@hasna/skills 0.5.2 → 0.5.3

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/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.2",
36863
+ version: "0.5.3",
36864
36864
  description: "Skills library for AI coding agents",
36865
36865
  type: "module",
36866
36866
  bin: {
@@ -39323,10 +39323,45 @@ var init_skill_validation = __esm(() => {
39323
39323
  VALID_BIN_COMMAND = /^[a-z0-9][a-z0-9._-]*$/;
39324
39324
  });
39325
39325
 
39326
+ // src/lib/skill-entry-path.ts
39327
+ class SkillEntryPaths {
39328
+ files = new Set;
39329
+ directories = new Set;
39330
+ add(path, maxBytes, invalid, limit) {
39331
+ if (path.length > maxBytes)
39332
+ limit();
39333
+ const encoded = new TextEncoder().encode(path);
39334
+ if (encoded.byteLength > maxBytes)
39335
+ limit();
39336
+ if (new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(encoded) !== path)
39337
+ invalid("Invalid UTF-8 entry path");
39338
+ if (!path || /[\\:\x00-\x1f\x7f]/u.test(path))
39339
+ invalid("Unsafe entry path");
39340
+ if (path.split("/").some((segment) => !segment || segment === "." || segment === ".."))
39341
+ invalid("Unsafe entry path segment");
39342
+ const key = path.normalize("NFC").toLowerCase().normalize("NFC");
39343
+ if (this.files.has(key) || this.directories.has(key))
39344
+ invalid("Duplicate or conflicting entry path");
39345
+ const parents = key.split("/");
39346
+ parents.pop();
39347
+ while (parents.length) {
39348
+ const parent = parents.join("/");
39349
+ if (this.files.has(parent))
39350
+ invalid("Conflicting entry file ancestor");
39351
+ this.directories.add(parent);
39352
+ parents.pop();
39353
+ }
39354
+ this.files.add(key);
39355
+ }
39356
+ }
39357
+
39326
39358
  // src/lib/skill-hash.ts
39327
39359
  import { createHash } from "crypto";
39328
39360
  import { existsSync as existsSync9, readdirSync as readdirSync4, readFileSync as readFileSync5, statSync as statSync4 } from "fs";
39329
39361
  import { join as join9, sep } from "path";
39362
+ function excludedHashEntry(name, directory) {
39363
+ return name.startsWith(".") || directory && HASH_EXCLUDE_DIRS.has(name);
39364
+ }
39330
39365
  function normalizeLineEndings(content) {
39331
39366
  return content.replace(/\r\n/g, `
39332
39367
  `).replace(/\r/g, `
@@ -39397,7 +39432,7 @@ function collectDirectory(files, dir, rel) {
39397
39432
  if (stats.isSymbolicLink())
39398
39433
  continue;
39399
39434
  if (stats.isDirectory()) {
39400
- if (HASH_EXCLUDE_DIRS.has(entry))
39435
+ if (excludedHashEntry(entry, true))
39401
39436
  continue;
39402
39437
  collectDirectory(files, absolute, childRel);
39403
39438
  } else if (stats.isFile()) {
@@ -39407,26 +39442,34 @@ function collectDirectory(files, dir, rel) {
39407
39442
  }
39408
39443
  function collectFile(files, absolute, rel) {
39409
39444
  const buffer = readFileSync5(absolute);
39445
+ files.push(normalizeBundleFile(rel.split(sep).join("/"), buffer));
39446
+ }
39447
+ function normalizeBundleFile(rel, buffer) {
39410
39448
  if (rel === "skill.json") {
39411
- files.push({ rel: rel.split(sep).join("/"), content: new TextEncoder().encode(canonicalizeManifest(new TextDecoder().decode(buffer))) });
39412
- return;
39449
+ return { rel, content: new TextEncoder().encode(canonicalizeManifest(new TextDecoder().decode(buffer))) };
39413
39450
  }
39414
39451
  if (looksLikeText(buffer)) {
39415
39452
  const normalized = normalizeLineEndings(new TextDecoder().decode(buffer));
39416
- files.push({ rel: rel.split(sep).join("/"), content: new TextEncoder().encode(normalized) });
39417
- return;
39453
+ return { rel, content: new TextEncoder().encode(normalized) };
39418
39454
  }
39419
- files.push({ rel: rel.split(sep).join("/"), content: buffer });
39455
+ return { rel, content: buffer };
39420
39456
  }
39421
39457
  function computeContentHash(skillPath) {
39422
- const hash = createHash(CONTENT_HASH_ALGORITHM);
39423
- for (const file of collectBundleFiles(skillPath)) {
39424
- hash.update(new TextEncoder().encode(file.rel));
39425
- hash.update(new TextEncoder().encode(`\x00${file.content.length}\x00`));
39426
- hash.update(file.content);
39427
- hash.update(new TextEncoder().encode("\x00"));
39458
+ return hashBundleFiles(collectBundleFiles(skillPath));
39459
+ }
39460
+ function* bundleHashParts(files) {
39461
+ for (const file of files) {
39462
+ yield new TextEncoder().encode(file.rel);
39463
+ yield new TextEncoder().encode(`\x00${file.content.length}\x00`);
39464
+ yield file.content;
39465
+ yield new TextEncoder().encode("\x00");
39428
39466
  }
39429
- hash.update(new TextEncoder().encode("\x00"));
39467
+ yield new TextEncoder().encode("\x00");
39468
+ }
39469
+ function hashBundleFiles(files) {
39470
+ const hash = createHash(CONTENT_HASH_ALGORITHM);
39471
+ for (const part of bundleHashParts(files))
39472
+ hash.update(part);
39430
39473
  return hash.digest("hex");
39431
39474
  }
39432
39475
  function verifyContentHash(skillPath, manifest) {
@@ -39463,7 +39506,7 @@ function hashSkillMarkdown(content) {
39463
39506
  function hashSkillMarkdownFile(path) {
39464
39507
  return hashSkillMarkdown(readFileSync5(path, "utf-8"));
39465
39508
  }
39466
- var CONTENT_HASH_ALGORITHM = "sha256", HASH_EXCLUDE_DIRS, HASH_COVERAGE;
39509
+ var CONTENT_HASH_ALGORITHM = "sha256", HASH_EXCLUDE_DIRS, HASH_COVERAGE, CONTENT_HASH_LIMITS, typedArrayPrototype, byteLengthOf, bufferOf;
39467
39510
  var init_skill_hash = __esm(() => {
39468
39511
  HASH_EXCLUDE_DIRS = new Set([".git", "node_modules", "dist", "build", ".turbo"]);
39469
39512
  HASH_COVERAGE = [
@@ -39477,6 +39520,20 @@ var init_skill_hash = __esm(() => {
39477
39520
  "assets",
39478
39521
  "references"
39479
39522
  ];
39523
+ CONTENT_HASH_LIMITS = Object.freeze({
39524
+ entries: 1024,
39525
+ rawBytes: 64 * 1024 * 1024,
39526
+ normalizedBytes: 64 * 1024 * 1024,
39527
+ fileBytes: 16 * 1024 * 1024,
39528
+ normalizedFileBytes: 16 * 1024 * 1024,
39529
+ pathBytes: 100,
39530
+ manifestBytes: 16 * 1024,
39531
+ manifestDepth: 64,
39532
+ timeoutMs: 5000
39533
+ });
39534
+ typedArrayPrototype = Object.getPrototypeOf(Uint8Array.prototype);
39535
+ byteLengthOf = Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteLength").get;
39536
+ bufferOf = Object.getOwnPropertyDescriptor(typedArrayPrototype, "buffer").get;
39480
39537
  });
39481
39538
 
39482
39539
  // src/lib/portable-skills-types.ts
@@ -49045,50 +49102,210 @@ var init_read_access = __esm(() => {
49045
49102
  init_remote_registry();
49046
49103
  });
49047
49104
 
49105
+ // src/lib/remote-invitations.ts
49106
+ function invitationFailure(value, status) {
49107
+ if (!record(value) || typeof value.code !== "string" || !Object.hasOwn(invitationFailures, value.code))
49108
+ return null;
49109
+ const code = value.code;
49110
+ return invitationFailures[code][0] === status ? code : null;
49111
+ }
49112
+ function invitationId(value) {
49113
+ return uuid(value) ? value : inputFailure();
49114
+ }
49115
+ function invitationInput(action, input) {
49116
+ if (!record(input))
49117
+ return inputFailure();
49118
+ const keys2 = {
49119
+ list: ["after"],
49120
+ get: ["invitationId"],
49121
+ issue: ["email", "role", "idempotencyKey", "confirm"],
49122
+ resend: ["invitationId", "expectedGeneration", "idempotencyKey", "confirm"],
49123
+ revoke: ["invitationId", "expectedGeneration", "confirm"],
49124
+ accept: ["invitationId", "token", "confirm"]
49125
+ };
49126
+ if (Object.keys(input).some((key) => !keys2[action].includes(key)) || action !== "list" && keys2[action].some((key) => !Object.hasOwn(input, key)))
49127
+ return inputFailure();
49128
+ const value = { ...input };
49129
+ if (action === "list") {
49130
+ if (value.after !== undefined && !uuid(value.after))
49131
+ return inputFailure();
49132
+ }
49133
+ if (["get", "resend", "revoke", "accept"].includes(action) && !uuid(value.invitationId))
49134
+ return inputFailure();
49135
+ if (!["list", "get"].includes(action) && value.confirm !== true)
49136
+ return inputFailure();
49137
+ if (["issue", "resend"].includes(action) && !uuid(value.idempotencyKey))
49138
+ return inputFailure();
49139
+ if (action === "issue") {
49140
+ if (typeof value.email !== "string")
49141
+ return inputFailure();
49142
+ value.email = value.email.trim().toLowerCase();
49143
+ if (!email(value.email) || !role(value.role))
49144
+ return inputFailure();
49145
+ }
49146
+ if (["resend", "revoke"].includes(action) && (!Number.isInteger(value.expectedGeneration) || Number(value.expectedGeneration) < 1 || Number(value.expectedGeneration) > 10))
49147
+ return inputFailure();
49148
+ if (action === "accept" && (typeof value.token !== "string" || !/^[A-Za-z0-9_-]{43}$/.test(value.token)))
49149
+ return inputFailure();
49150
+ return value;
49151
+ }
49152
+ function invitationRequest(action, input) {
49153
+ const base2 = "/api/v1/workspace/invitations", value = input;
49154
+ const { confirm: _confirm, invitationId: id, ...body } = value;
49155
+ if (action === "list")
49156
+ return { path: base2 + (value.after ? `?after=${value.after}` : ""), method: "GET" };
49157
+ if (action === "get")
49158
+ return { path: `${base2}/${id}`, method: "GET" };
49159
+ if (action === "accept")
49160
+ return { path: "/api/v1/account/invitations/accept", method: "POST", body: JSON.stringify({ invitationId: id, token: value.token }) };
49161
+ return { path: action === "issue" ? base2 : `${base2}/${id}${action === "resend" ? "/resend" : ""}`, method: action === "revoke" ? "DELETE" : "POST", body: JSON.stringify(body) };
49162
+ }
49163
+ function invalid() {
49164
+ throw new RemoteWorkspaceInvitationReadError;
49165
+ }
49166
+ function projection(v, organizationId) {
49167
+ if (!record(v) || !uuid(v.id) || v.organizationId !== organizationId || !email(v.email) || v.email !== v.email.trim().toLowerCase() || !role(v.role) || !Number.isInteger(v.generation) || Number(v.generation) < 1 || Number(v.generation) > 10 || typeof v.status !== "string" || !["pending", "expired", "accepted", "revoked"].includes(v.status) || !timestamp(v.expiresAt) || !timestamp(v.createdAt) || !record(v.delivery) || typeof v.delivery.state !== "string" || !["queued", "sending", "uncertain", "provider_accepted", "failed", "cancelled"].includes(v.delivery.state) || !Number.isInteger(v.delivery.attempts) || Number(v.delivery.attempts) < 0 || Number(v.delivery.attempts) > 5)
49168
+ return invalid();
49169
+ return {
49170
+ id: v.id,
49171
+ organizationId,
49172
+ email: v.email,
49173
+ role: v.role,
49174
+ generation: Number(v.generation),
49175
+ status: v.status,
49176
+ expiresAt: v.expiresAt,
49177
+ createdAt: v.createdAt,
49178
+ delivery: { state: v.delivery.state, attempts: Number(v.delivery.attempts) }
49179
+ };
49180
+ }
49181
+ function parseInvitationResult(action, value, input, organizationId) {
49182
+ if (!record(value))
49183
+ return invalid();
49184
+ const request = input;
49185
+ if (action === "accept") {
49186
+ if (!uuid(value.organizationId) || !uuid(value.membershipId) || value.accepted !== true || typeof value.changed !== "boolean")
49187
+ return invalid();
49188
+ return { organizationId: value.organizationId, membershipId: value.membershipId, accepted: true, changed: value.changed };
49189
+ }
49190
+ if (action === "list") {
49191
+ if (value.organizationId !== organizationId || !Array.isArray(value.invitations) || value.invitations.length > 50 || value.nextCursor !== null && !uuid(value.nextCursor))
49192
+ return invalid();
49193
+ const invitations = value.invitations.map((v) => projection(v, organizationId));
49194
+ if (invitations.some((v, n) => v.id <= String(n ? invitations[n - 1].id : request.after ?? "")) || value.nextCursor !== null && (invitations.length !== 50 || value.nextCursor !== invitations.at(-1)?.id))
49195
+ return invalid();
49196
+ return { organizationId, invitations, nextCursor: value.nextCursor };
49197
+ }
49198
+ const invitation = projection(value.invitation, organizationId);
49199
+ if (action !== "issue" && invitation.id !== request.invitationId)
49200
+ return invalid();
49201
+ if (action === "get")
49202
+ return { invitation };
49203
+ if (typeof value.changed !== "boolean")
49204
+ return invalid();
49205
+ if (action === "issue" && (invitation.email !== request.email || invitation.role !== request.role || value.changed && invitation.generation !== 1))
49206
+ return invalid();
49207
+ if (action === "resend" && (value.changed ? invitation.generation !== Number(request.expectedGeneration) + 1 : invitation.generation <= Number(request.expectedGeneration)))
49208
+ return invalid();
49209
+ if (action === "revoke" && (invitation.status !== "revoked" || invitation.generation < Number(request.expectedGeneration) || value.changed && invitation.generation !== request.expectedGeneration))
49210
+ return invalid();
49211
+ return { invitation, changed: value.changed };
49212
+ }
49213
+ var WorkspaceInvitationInputError, invitationFailures, RemoteWorkspaceInvitationError, RemoteWorkspaceInvitationUnconfirmedError, RemoteWorkspaceInvitationReadError, 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), role = (v) => typeof v === "string" && ["owner", "admin", "member", "viewer"].includes(v), email = (v) => typeof v === "string" && v.length <= 254 && !/[\p{Cc}\p{Cs}\u2028\u2029\s]/u.test(v) && /^[^@]+@[^@]+\.[^@]+$/.test(v), timestamp = (v) => typeof v === "string" && v.length <= 40 && /^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(?:\.\d{1,6})?(?:Z|[+-]\d\d:\d\d)$/.test(v) && Number.isFinite(Date.parse(v)), inputFailure = () => {
49214
+ throw new WorkspaceInvitationInputError;
49215
+ };
49216
+ var init_remote_invitations = __esm(() => {
49217
+ WorkspaceInvitationInputError = class WorkspaceInvitationInputError extends Error {
49218
+ code = "INVITATION_INPUT_INVALID";
49219
+ constructor() {
49220
+ super("Provide only the documented invitation fields, exact lowercase IDs, expected generation and explicit confirmation. Issue and resend require your stable idempotency key.");
49221
+ this.name = "WorkspaceInvitationInputError";
49222
+ }
49223
+ };
49224
+ invitationFailures = {
49225
+ INVALID_REQUEST: [400, "Invitation parameters were refused."],
49226
+ ACCOUNT_UNAVAILABLE: [403, "Account is unavailable."],
49227
+ INTERACTIVE_SESSION_REQUIRED: [403, "Fresh interactive sign-in is required."],
49228
+ WORKSPACE_ADMIN_REQUIRED: [403, "A current workspace owner or admin is required."],
49229
+ INVITATION_FORBIDDEN: [403, "Your current role cannot manage this invitation."],
49230
+ INVITATION_UNAVAILABLE: [404, "Invitation is unavailable for this account."],
49231
+ INVITATION_CHANGED: [409, "Invitation changed. Read its current generation before another action."],
49232
+ INVITATION_EXISTS: [409, "A pending invitation already exists. Read current invitations."],
49233
+ ALREADY_MEMBER: [409, "An active membership already exists. An invitation cannot change its role."],
49234
+ IDEMPOTENCY_CONFLICT: [409, "This request key was used for different invitation parameters. Reconcile the original request."],
49235
+ INVITATION_LIMIT: [429, "Invitation limit reached. Wait before issuing or resending."],
49236
+ INVITATION_BUSY: [503, "Invitation is busy. Read its state before another action."],
49237
+ INVITATION_DELIVERY_UNAVAILABLE: [503, "Invitation email delivery is unavailable."]
49238
+ };
49239
+ RemoteWorkspaceInvitationError = class RemoteWorkspaceInvitationError extends Error {
49240
+ code;
49241
+ status;
49242
+ constructor(code) {
49243
+ super(invitationFailures[code][1]);
49244
+ this.code = code;
49245
+ this.name = "RemoteWorkspaceInvitationError";
49246
+ this.status = invitationFailures[code][0];
49247
+ }
49248
+ };
49249
+ RemoteWorkspaceInvitationUnconfirmedError = class RemoteWorkspaceInvitationUnconfirmedError extends Error {
49250
+ code = "INVITATION_UNCONFIRMED";
49251
+ constructor() {
49252
+ super("The invitation outcome is unconfirmed. Read current invitations or memberships. Reconcile issue/resend only with the same request key, parameters, server and membership; never generate a new key or retry automatically. Saved credentials are unchanged.");
49253
+ this.name = "RemoteWorkspaceInvitationUnconfirmedError";
49254
+ }
49255
+ };
49256
+ RemoteWorkspaceInvitationReadError = class RemoteWorkspaceInvitationReadError extends Error {
49257
+ code = "INVITATION_READ_FAILED";
49258
+ constructor() {
49259
+ super("Unable to read a valid invitation result. Check the selected server, account, current membership and permissions.");
49260
+ this.name = "RemoteWorkspaceInvitationReadError";
49261
+ }
49262
+ };
49263
+ });
49264
+
49048
49265
  // src/lib/remote-workspace-selection.ts
49049
49266
  function workspaceExpectedUserId(value) {
49050
- if (!uuid(value))
49267
+ if (!uuid2(value))
49051
49268
  throw new WorkspaceContextInputError;
49052
49269
  return value;
49053
49270
  }
49054
49271
  function workspaceContext(value) {
49055
- if (!record(value) || Object.keys(value).sort().join(",") !== "membershipId,userId" || !uuid(value.userId) || !uuid(value.membershipId))
49272
+ if (!record2(value) || Object.keys(value).sort().join(",") !== "membershipId,userId" || !uuid2(value.userId) || !uuid2(value.membershipId))
49056
49273
  throw new WorkspaceContextInputError;
49057
49274
  return { userId: value.userId, membershipId: value.membershipId };
49058
49275
  }
49059
- function invalid() {
49276
+ function invalid2() {
49060
49277
  throw new Error(invalidWorkspaceResult);
49061
49278
  }
49062
49279
  function organization(v) {
49063
- if (!record(v) || !uuid(v.id) || !text(v.slug) || !text(v.name))
49064
- return invalid();
49280
+ if (!record2(v) || !uuid2(v.id) || !text(v.slug) || !text(v.name))
49281
+ return invalid2();
49065
49282
  return { id: v.id, slug: v.slug, name: v.name };
49066
49283
  }
49067
49284
  function parseAccountWorkspaces(value) {
49068
- if (!record(value) || !Array.isArray(value.workspaces) || !value.workspaces.length || value.workspaces.length > 1000)
49069
- return invalid();
49285
+ if (!record2(value) || !Array.isArray(value.workspaces) || !value.workspaces.length || value.workspaces.length > 1000)
49286
+ return invalid2();
49070
49287
  const workspaces = value.workspaces.map((v) => {
49071
- if (!record(v) || !uuid(v.membershipId) || !role(v.role) || typeof v.current !== "boolean")
49072
- return invalid();
49288
+ if (!record2(v) || !uuid2(v.membershipId) || !role2(v.role) || typeof v.current !== "boolean")
49289
+ return invalid2();
49073
49290
  return { membershipId: v.membershipId, organization: organization(v.organization), role: v.role, current: v.current };
49074
49291
  });
49075
49292
  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();
49293
+ return invalid2();
49077
49294
  return { workspaces };
49078
49295
  }
49079
49296
  function parseWorkspaceIdentity(value, expectedUserId) {
49080
- if (!record(value))
49081
- return invalid();
49297
+ if (!record2(value))
49298
+ return invalid2();
49082
49299
  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();
49300
+ if (!record2(user) || !uuid2(user.id) || !uuid2(user.membershipId) || !text(user.email, 320) || !(user.displayName === null || text(user.displayName)) || !role2(user.role))
49301
+ return invalid2();
49085
49302
  if (user.id !== expectedUserId)
49086
49303
  throw new WorkspaceIdentityMismatchError;
49087
49304
  return { user: { id: user.id, membershipId: user.membershipId, email: user.email, displayName: user.displayName, role: user.role }, organization: organization(value.organization) };
49088
49305
  }
49089
49306
  function sessionToken(value) {
49090
49307
  if (typeof value !== "string" || !value || value.length > 8192 || /[^\x21-\x7e]/.test(value) || value.startsWith("sk_"))
49091
- return invalid();
49308
+ return invalid2();
49092
49309
  return value;
49093
49310
  }
49094
49311
  function parseWorkspaceSession(value, expected) {
@@ -49098,20 +49315,20 @@ function parseWorkspaceSession(value, expected) {
49098
49315
  return { token: sessionToken(value.token), ...identity2 };
49099
49316
  }
49100
49317
  function parseWorkspaceLogin(value, expectedUserId) {
49101
- const user = record(value) && value.user;
49102
- if (!record(value) || !record(user) || !uuid(user.id))
49103
- return invalid();
49318
+ const user = record2(value) && value.user;
49319
+ if (!record2(value) || !record2(user) || !uuid2(user.id))
49320
+ return invalid2();
49104
49321
  if (expectedUserId !== undefined && user.id !== expectedUserId)
49105
49322
  throw new WorkspaceIdentityMismatchError;
49106
49323
  return { token: sessionToken(value.token), userId: user.id };
49107
49324
  }
49108
49325
  function workspaceSelectionFailure(value, status) {
49109
- if (!record(value) || typeof value.code !== "string" || !Object.hasOwn(workspaceSelectionFailures, value.code))
49326
+ if (!record2(value) || typeof value.code !== "string" || !Object.hasOwn(workspaceSelectionFailures, value.code))
49110
49327
  return null;
49111
49328
  const code = value.code;
49112
49329
  return workspaceSelectionFailures[code][0] === status ? code : null;
49113
49330
  }
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;
49331
+ var record2 = (v) => !!v && typeof v === "object" && !Array.isArray(v), uuid2 = (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), role2 = (v) => typeof v === "string" && ["owner", "admin", "member", "viewer"].includes(v), invalidWorkspaceResult = "The server returned an invalid workspace selection result.", WorkspaceContextInputError, WorkspaceIdentityMismatchError, workspaceSelectionFailures;
49115
49332
  var init_remote_workspace_selection = __esm(() => {
49116
49333
  WorkspaceContextInputError = class WorkspaceContextInputError extends Error {
49117
49334
  constructor() {
@@ -49137,7 +49354,7 @@ var init_remote_workspace_selection = __esm(() => {
49137
49354
 
49138
49355
  // src/lib/remote-workspace.ts
49139
49356
  function workspaceMembersQuery(options = {}) {
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))
49357
+ if (!record3(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))
49141
49358
  throw new Error("Use a roster limit from 1 to 100 and an unchanged continuation cursor.");
49142
49359
  const query = new URLSearchParams;
49143
49360
  if (options.limit !== undefined)
@@ -49146,14 +49363,14 @@ function workspaceMembersQuery(options = {}) {
49146
49363
  query.set("cursor", options.cursor);
49147
49364
  return query.size ? `?${query}` : "";
49148
49365
  }
49149
- function timestamp(value) {
49366
+ function timestamp2(value) {
49150
49367
  if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}Z$/.test(value))
49151
49368
  return false;
49152
49369
  const time = Date.parse(value);
49153
49370
  return Number.isFinite(time) && new Date(time).toISOString().slice(0, 23) === value.slice(0, 23);
49154
49371
  }
49155
49372
  function parseMember(row, fail2) {
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))
49373
+ if (!record3(row) || !uuid3(row.membershipId) || !uuid3(row.userId) || typeof row.email !== "string" || !row.email || !(row.displayName === null || typeof row.displayName === "string") || !isRole(row.role) || !timestamp2(row.createdAt))
49157
49374
  return fail2();
49158
49375
  return {
49159
49376
  membershipId: row.membershipId,
@@ -49165,12 +49382,12 @@ function parseMember(row, fail2) {
49165
49382
  };
49166
49383
  }
49167
49384
  function mutationInput(membershipId, input, roleChange) {
49168
- if (typeof membershipId !== "string" || !uuid2(membershipId) || membershipId !== membershipId.toLowerCase() || !record2(input) || Object.keys(input).sort().join(",") !== (roleChange ? "expectedRole,role" : "expectedRole"))
49385
+ if (typeof membershipId !== "string" || !uuid3(membershipId) || membershipId !== membershipId.toLowerCase() || !record3(input) || Object.keys(input).sort().join(",") !== (roleChange ? "expectedRole,role" : "expectedRole"))
49169
49386
  throw new WorkspaceMemberInputError;
49170
- const expectedRole = input.expectedRole, role2 = roleChange ? input.role : undefined;
49171
- if (!isRole(expectedRole) || roleChange && !isRole(role2))
49387
+ const expectedRole = input.expectedRole, role3 = roleChange ? input.role : undefined;
49388
+ if (!isRole(expectedRole) || roleChange && !isRole(role3))
49172
49389
  throw new WorkspaceMemberInputError;
49173
- return { membershipId, role: role2, expectedRole };
49390
+ return { membershipId, role: role3, expectedRole };
49174
49391
  }
49175
49392
  function workspaceMemberRoleInput(membershipId, input) {
49176
49393
  const value = mutationInput(membershipId, input, true);
@@ -49180,24 +49397,24 @@ function workspaceMemberRemovalInput(membershipId, input) {
49180
49397
  const value = mutationInput(membershipId, input, false);
49181
49398
  return { membershipId: value.membershipId, body: { expectedRole: value.expectedRole } };
49182
49399
  }
49183
- function parseWorkspaceMemberRoleResult(value, membershipId, role2) {
49400
+ function parseWorkspaceMemberRoleResult(value, membershipId, role3) {
49184
49401
  const fail2 = () => {
49185
49402
  throw new Error(invalidMemberResult);
49186
49403
  };
49187
- if (!record2(value) || !uuid2(value.organizationId) || typeof value.changed !== "boolean")
49404
+ if (!record3(value) || !uuid3(value.organizationId) || typeof value.changed !== "boolean")
49188
49405
  return fail2();
49189
49406
  const member = parseMember(value.member, fail2);
49190
- if (member.membershipId !== membershipId || member.role !== role2)
49407
+ if (member.membershipId !== membershipId || member.role !== role3)
49191
49408
  return fail2();
49192
49409
  return { organizationId: value.organizationId, member, changed: value.changed };
49193
49410
  }
49194
49411
  function parseWorkspaceMemberRemovalResult(value, membershipId) {
49195
- if (!record2(value) || !uuid2(value.organizationId) || value.membershipId !== membershipId || value.removed !== true || typeof value.alreadyRemoved !== "boolean")
49412
+ if (!record3(value) || !uuid3(value.organizationId) || value.membershipId !== membershipId || value.removed !== true || typeof value.alreadyRemoved !== "boolean")
49196
49413
  throw new Error(invalidMemberResult);
49197
49414
  return { organizationId: value.organizationId, membershipId, removed: true, alreadyRemoved: value.alreadyRemoved };
49198
49415
  }
49199
49416
  function workspaceMemberFailure(value, status) {
49200
- if (!record2(value) || typeof value.code !== "string" || !Object.hasOwn(workspaceMemberFailures, value.code))
49417
+ if (!record3(value) || typeof value.code !== "string" || !Object.hasOwn(workspaceMemberFailures, value.code))
49201
49418
  return null;
49202
49419
  const code = value.code;
49203
49420
  return workspaceMemberFailures[code][0] === status ? code : null;
@@ -49206,14 +49423,14 @@ function parseWorkspaceMembersPage(value) {
49206
49423
  const fail2 = () => {
49207
49424
  throw new Error("The server returned an invalid workspace roster.");
49208
49425
  };
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)
49426
+ if (!record3(value) || !uuid3(value.organizationId) || !Array.isArray(value.members) || value.members.length > 100 || !(value.nextCursor === null || cursor(value.nextCursor)) || !value.members.length && value.nextCursor !== null)
49210
49427
  return fail2();
49211
49428
  const members = value.members.map((row) => parseMember(row, fail2));
49212
49429
  if (new Set(members.map((row) => row.membershipId)).size !== members.length)
49213
49430
  return fail2();
49214
49431
  return { organizationId: value.organizationId, members, nextCursor: value.nextCursor };
49215
49432
  }
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;
49433
+ var record3 = (value) => !!value && typeof value === "object" && !Array.isArray(value), cursor = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,512}$/.test(value), uuid3 = (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;
49217
49434
  var init_remote_workspace = __esm(() => {
49218
49435
  WorkspaceMemberInputError = class WorkspaceMemberInputError extends Error {
49219
49436
  constructor() {
@@ -49322,14 +49539,14 @@ function readIdentity(env3 = process.env) {
49322
49539
  const parsed = JSON.parse(readFileSync12(getIdentityFilePath(env3), "utf-8"));
49323
49540
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
49324
49541
  return {};
49325
- const record3 = parsed;
49542
+ const record4 = parsed;
49326
49543
  const selected = resolveSkillsApiOrigin(env3)?.origin;
49327
- const bound = typeof record3.apiUrl === "string" ? record3.apiUrl : readCredentialValue(SKILLS_BOUND_API_URL, env3) ?? readStoredApiUrl(env3) ?? defaultFleetGatewayBaseUrl("skills");
49544
+ const bound = typeof record4.apiUrl === "string" ? record4.apiUrl : readCredentialValue(SKILLS_BOUND_API_URL, env3) ?? readStoredApiUrl(env3) ?? defaultFleetGatewayBaseUrl("skills");
49328
49545
  if (selected && normalizeSkillsApiOrigin(bound) !== selected)
49329
49546
  return {};
49330
49547
  const identity2 = {};
49331
49548
  for (const field of ["email", "orgId", "orgSlug", "userId"]) {
49332
- const value = record3[field];
49549
+ const value = record4[field];
49333
49550
  if (typeof value === "string" && value.length > 0)
49334
49551
  identity2[field] = value;
49335
49552
  }
@@ -49478,44 +49695,44 @@ var init_auth_store = __esm(() => {
49478
49695
 
49479
49696
  // src/lib/remote-run-contract.ts
49480
49697
  function normalizeRemoteSkillRunContract(payload, fallbackSkill) {
49481
- const record3 = isRecord3(payload) ? payload : {};
49698
+ const record4 = isRecord3(payload) ? payload : {};
49482
49699
  return {
49483
49700
  contractVersion: REMOTE_SKILL_RUN_CONTRACT_VERSION,
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 } : {}
49701
+ ...pickString(record4, "id"),
49702
+ skill: pickStringValue(record4, "skill") ?? fallbackSkill,
49703
+ ...pickString(record4, "requestedSlug"),
49704
+ ...pickString(record4, "status"),
49705
+ ...pickNumber(record4, "exitCode"),
49706
+ ...pickString(record4, "correlationId"),
49707
+ ...pickString(record4, "createdAt"),
49708
+ ...pickString(record4, "startedAt"),
49709
+ ...pickString(record4, "completedAt"),
49710
+ ...pickNumber(record4, "durationMs"),
49711
+ ...pickString(record4, "outputType"),
49712
+ ...hasOwn(record4, "outputPreview") ? { outputPreview: record4.outputPreview } : {},
49713
+ ...pickString(record4, "errorCode"),
49714
+ ...pickString(record4, "errorMessage"),
49715
+ ...pickString(record4, "error"),
49716
+ ...pickString(record4, "code"),
49717
+ ...hasOwn(record4, "details") ? { details: record4.details } : {}
49501
49718
  };
49502
49719
  }
49503
49720
  function isRecord3(value) {
49504
49721
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
49505
49722
  }
49506
- function hasOwn(record3, key) {
49507
- return Object.prototype.hasOwnProperty.call(record3, key);
49723
+ function hasOwn(record4, key) {
49724
+ return Object.prototype.hasOwnProperty.call(record4, key);
49508
49725
  }
49509
- function pickString(record3, key) {
49510
- const value = pickStringValue(record3, key);
49726
+ function pickString(record4, key) {
49727
+ const value = pickStringValue(record4, key);
49511
49728
  return value === undefined ? {} : { [key]: value };
49512
49729
  }
49513
- function pickStringValue(record3, key) {
49514
- const value = record3[key];
49730
+ function pickStringValue(record4, key) {
49731
+ const value = record4[key];
49515
49732
  return typeof value === "string" ? value : undefined;
49516
49733
  }
49517
- function pickNumber(record3, key) {
49518
- const value = record3[key];
49734
+ function pickNumber(record4, key) {
49735
+ const value = record4[key];
49519
49736
  return typeof value === "number" && Number.isFinite(value) ? { [key]: value } : {};
49520
49737
  }
49521
49738
  var REMOTE_SKILL_RUN_CONTRACT_VERSION = 1;
@@ -49981,6 +50198,53 @@ class RemoteSkillsClient {
49981
50198
  }
49982
50199
  return parseWorkspaceLeaveResult(body, captured.context.membershipId, identity2.organization.id);
49983
50200
  }
50201
+ listWorkspaceInvitations(context, options = {}) {
50202
+ return this.requestWorkspaceInvitation(context, "list", options);
50203
+ }
50204
+ getWorkspaceInvitation(context, invitationId2) {
50205
+ return this.requestWorkspaceInvitation(context, "get", { invitationId: invitationId2 });
50206
+ }
50207
+ issueWorkspaceInvitation(context, input) {
50208
+ return this.requestWorkspaceInvitation(context, "issue", input);
50209
+ }
50210
+ resendWorkspaceInvitation(context, invitationId2, input) {
50211
+ return this.requestWorkspaceInvitation(context, "resend", { ...input, invitationId: invitationId2 });
50212
+ }
50213
+ revokeWorkspaceInvitation(context, invitationId2, input) {
50214
+ return this.requestWorkspaceInvitation(context, "revoke", { ...input, invitationId: invitationId2 });
50215
+ }
50216
+ acceptWorkspaceInvitation(context, invitationId2, input) {
50217
+ return this.requestWorkspaceInvitation(context, "accept", { ...input, invitationId: invitationId2 });
50218
+ }
50219
+ async requestWorkspaceInvitation(context, action, input) {
50220
+ const target = workspaceContext(context), captured = invitationInput(action, input);
50221
+ const connection = new RemoteSkillsClient(this.apiKey, this.apiUrl);
50222
+ const identityValue = await connection.requestWorkspaceSelection("/api/auth/whoami");
50223
+ if (!identityValue || typeof identityValue !== "object" || identityValue.authMethod !== "jwt")
50224
+ throw new RemoteWorkspaceInvitationError("INTERACTIVE_SESSION_REQUIRED");
50225
+ const identity2 = parseWorkspaceIdentity(identityValue, target.userId);
50226
+ if (identity2.user.membershipId !== target.membershipId)
50227
+ throw new WorkspaceIdentityMismatchError;
50228
+ const request = invitationRequest(action, captured), read = action === "list" || action === "get";
50229
+ let response, value;
50230
+ try {
50231
+ response = await connection.request(request.path, { method: request.method, ...request.body ? { body: request.body } : {}, credentials: "omit" });
50232
+ value = JSON.parse(new TextDecoder().decode(await readBoundedResponse(response, response.ok ? 64 * 1024 : 4096)));
50233
+ } catch {
50234
+ throw read ? new RemoteWorkspaceInvitationReadError : new RemoteWorkspaceInvitationUnconfirmedError;
50235
+ }
50236
+ if (!response.ok) {
50237
+ const code = invitationFailure(value, response.status);
50238
+ if (code)
50239
+ throw new RemoteWorkspaceInvitationError(code);
50240
+ throw read ? new RemoteWorkspaceInvitationReadError : new RemoteWorkspaceInvitationUnconfirmedError;
50241
+ }
50242
+ try {
50243
+ return parseInvitationResult(action, value, captured, identity2.organization.id);
50244
+ } catch {
50245
+ throw read ? new RemoteWorkspaceInvitationReadError : new RemoteWorkspaceInvitationUnconfirmedError;
50246
+ }
50247
+ }
49984
50248
  async listApiKeys() {
49985
50249
  return this.arrayResponse("/api/auth/keys");
49986
50250
  }
@@ -50231,13 +50495,13 @@ class RemoteSkillsClient {
50231
50495
  return normalizeUpdatedSincePage(await response.json());
50232
50496
  }
50233
50497
  }
50234
- function requireOptionalString(record3, field) {
50235
- if (record3[field] === undefined)
50498
+ function requireOptionalString(record4, field) {
50499
+ if (record4[field] === undefined)
50236
50500
  return;
50237
- if (typeof record3[field] !== "string") {
50501
+ if (typeof record4[field] !== "string") {
50238
50502
  throw new Error(`Remote payload did not match the expected contract (${field} must be a string when present)`);
50239
50503
  }
50240
- return record3[field];
50504
+ return record4[field];
50241
50505
  }
50242
50506
  function isVersionRecord(value) {
50243
50507
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -50259,19 +50523,19 @@ function normalizePin(entry) {
50259
50523
  if (!entry || typeof entry !== "object") {
50260
50524
  throw new Error("Remote pin payload did not match the expected contract (expected an object)");
50261
50525
  }
50262
- const record3 = entry;
50263
- const slug = typeof record3.slug === "string" && record3.slug.trim() ? record3.slug.trim() : undefined;
50526
+ const record4 = entry;
50527
+ const slug = typeof record4.slug === "string" && record4.slug.trim() ? record4.slug.trim() : undefined;
50264
50528
  if (!slug) {
50265
50529
  throw new Error("Remote pin payload did not match the expected contract (missing slug)");
50266
50530
  }
50267
50531
  let metadata;
50268
- if (record3.metadata !== undefined) {
50269
- if (!record3.metadata || typeof record3.metadata !== "object" || Array.isArray(record3.metadata)) {
50532
+ if (record4.metadata !== undefined) {
50533
+ if (!record4.metadata || typeof record4.metadata !== "object" || Array.isArray(record4.metadata)) {
50270
50534
  throw new Error("Remote pin payload did not match the expected contract (metadata must be a JSON object when present)");
50271
50535
  }
50272
- metadata = record3.metadata;
50536
+ metadata = record4.metadata;
50273
50537
  }
50274
- const pinnedAt = requireOptionalString(record3, "pinnedAt");
50538
+ const pinnedAt = requireOptionalString(record4, "pinnedAt");
50275
50539
  return {
50276
50540
  slug,
50277
50541
  ...pinnedAt !== undefined ? { pinnedAt } : {},
@@ -50288,16 +50552,16 @@ function normalizeSkillSummary(entry) {
50288
50552
  if (!entry || typeof entry !== "object") {
50289
50553
  throw new Error("Remote skill payload did not match the expected contract (expected an object)");
50290
50554
  }
50291
- const record3 = entry;
50292
- const slug = typeof record3.slug === "string" && record3.slug.trim() ? record3.slug.trim() : undefined;
50555
+ const record4 = entry;
50556
+ const slug = typeof record4.slug === "string" && record4.slug.trim() ? record4.slug.trim() : undefined;
50293
50557
  if (!slug) {
50294
50558
  throw new Error("Remote skill payload did not match the expected contract (missing slug)");
50295
50559
  }
50296
50560
  return {
50297
50561
  slug,
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") } : {}
50562
+ ...requireOptionalString(record4, "name") !== undefined ? { name: requireOptionalString(record4, "name") } : {},
50563
+ ...requireOptionalString(record4, "version") !== undefined ? { version: requireOptionalString(record4, "version") } : {},
50564
+ ...requireOptionalString(record4, "updatedAt") !== undefined ? { updatedAt: requireOptionalString(record4, "updatedAt") } : {}
50301
50565
  };
50302
50566
  }
50303
50567
  function normalizeSkillSummaryList(payload) {
@@ -50350,12 +50614,12 @@ function normalizeUpdatedSincePage(payload) {
50350
50614
  if (!payload || typeof payload !== "object") {
50351
50615
  throw new Error("Updated-since payload did not match the expected contract (expected an object)");
50352
50616
  }
50353
- const record3 = payload;
50354
- if (!Array.isArray(record3.skills)) {
50617
+ const record4 = payload;
50618
+ if (!Array.isArray(record4.skills)) {
50355
50619
  throw new Error("Updated-since payload did not match the expected contract (missing skills array)");
50356
50620
  }
50357
- const skills = record3.skills.map(normalizeSkillSummary);
50358
- const nextCursor = record3.nextCursor === undefined || record3.nextCursor === null ? null : record3.nextCursor;
50621
+ const skills = record4.skills.map(normalizeSkillSummary);
50622
+ const nextCursor = record4.nextCursor === undefined || record4.nextCursor === null ? null : record4.nextCursor;
50359
50623
  if (nextCursor !== null && typeof nextCursor !== "string") {
50360
50624
  throw new Error("Updated-since payload did not match the expected contract (nextCursor must be a string or absent)");
50361
50625
  }
@@ -50370,6 +50634,7 @@ function createRemoteSkillsClientReadOnly(env3 = process.env) {
50370
50634
  }
50371
50635
  var RemoteRouteUnsupportedError, RemoteRequestError, RemoteWorkspaceMemberError, RemoteWorkspaceSelectionError, RemoteCapabilityUnavailableError, INVALID_SKILL_VERSION_RESPONSE = "Remote skill version payload did not match the expected contract.";
50372
50636
  var init_remote_client = __esm(() => {
50637
+ init_remote_invitations();
50373
50638
  init_remote_workspace_leave();
50374
50639
  init_remote_workspace_selection();
50375
50640
  init_remote_workspace();
@@ -50654,7 +50919,129 @@ function concat2(chunks) {
50654
50919
  }
50655
50920
  return merged;
50656
50921
  }
50657
- var BLOCK = 512, ANY_SEGMENT_EXCLUDES, ROOT_EXCLUDES, TOOL_SIDECAR_FILENAMES, CREDENTIAL_FILENAMES, CREDENTIAL_EXTENSIONS, ENV_TEMPLATE_NAMES, NON_DOTENV_EXTENSIONS;
50922
+ function invalidBundle(message) {
50923
+ throw new SkillBundleInspectionError("BUNDLE_INVALID", message);
50924
+ }
50925
+
50926
+ class BoundedTarReader {
50927
+ limits;
50928
+ check;
50929
+ header = new Uint8Array(BLOCK);
50930
+ headerOffset = 0;
50931
+ pending;
50932
+ bodyOffset = 0;
50933
+ padding = 0;
50934
+ zeroBlocks = 0;
50935
+ entries = [];
50936
+ paths = new SkillEntryPaths;
50937
+ fileBytes = 0;
50938
+ constructor(limits, check) {
50939
+ this.limits = limits;
50940
+ this.check = check;
50941
+ }
50942
+ push(chunk2) {
50943
+ let offset = 0;
50944
+ while (offset < chunk2.byteLength) {
50945
+ this.check();
50946
+ if (this.pending) {
50947
+ const count = Math.min(this.pending.bytes.byteLength - this.bodyOffset, chunk2.byteLength - offset);
50948
+ this.pending.bytes.set(chunk2.subarray(offset, offset + count), this.bodyOffset);
50949
+ offset += count;
50950
+ this.bodyOffset += count;
50951
+ if (this.bodyOffset === this.pending.bytes.byteLength) {
50952
+ this.entries.push(this.pending);
50953
+ this.pending = undefined;
50954
+ }
50955
+ } else if (this.padding) {
50956
+ const count = Math.min(this.padding, chunk2.byteLength - offset);
50957
+ if (chunk2.subarray(offset, offset + count).some((byte) => byte !== 0))
50958
+ invalidBundle("Nonzero tar body padding");
50959
+ offset += count;
50960
+ this.padding -= count;
50961
+ } else {
50962
+ const count = Math.min(BLOCK - this.headerOffset, chunk2.byteLength - offset);
50963
+ this.header.set(chunk2.subarray(offset, offset + count), this.headerOffset);
50964
+ offset += count;
50965
+ this.headerOffset += count;
50966
+ if (this.headerOffset === BLOCK) {
50967
+ this.readHeader();
50968
+ this.headerOffset = 0;
50969
+ }
50970
+ }
50971
+ }
50972
+ }
50973
+ finish() {
50974
+ this.check();
50975
+ if (this.pending || this.padding || this.headerOffset || this.zeroBlocks < 2)
50976
+ invalidBundle("Truncated tar bundle");
50977
+ return this.entries;
50978
+ }
50979
+ readHeader() {
50980
+ this.check();
50981
+ const h = this.header;
50982
+ if (h.every((byte) => byte === 0)) {
50983
+ this.zeroBlocks++;
50984
+ return;
50985
+ }
50986
+ if (this.zeroBlocks)
50987
+ invalidBundle("Nonzero tar data after terminator");
50988
+ if (this.entries.length >= this.limits.entries)
50989
+ throw new SkillBundleInspectionError("BUNDLE_LIMIT", "Bundle entry limit exceeded");
50990
+ let checksum = 0;
50991
+ for (let i = 0;i < BLOCK; i++)
50992
+ checksum += i >= 148 && i < 156 ? 32 : h[i];
50993
+ if (tarOctal(h.subarray(148, 156)) !== checksum)
50994
+ invalidBundle("Invalid tar header checksum");
50995
+ if (new TextDecoder().decode(h.subarray(257, 265)) !== "ustar\x00" + "00")
50996
+ invalidBundle("Unsupported tar format");
50997
+ if (h[156] !== 48 && h[156] !== 0 || h.subarray(157, 257).some((b) => b !== 0) || h.subarray(345).some((b) => b !== 0))
50998
+ invalidBundle("Unsupported tar entry or path prefix");
50999
+ const mode = tarOctal(h.subarray(100, 108));
51000
+ if (mode > 511)
51001
+ invalidBundle("Unsupported tar permission bits");
51002
+ tarOctal(h.subarray(108, 116));
51003
+ tarOctal(h.subarray(116, 124));
51004
+ tarOctal(h.subarray(136, 148));
51005
+ const size2 = tarOctal(h.subarray(124, 136));
51006
+ if (size2 > this.limits.fileBytes || this.fileBytes + size2 > this.limits.decompressedBytes) {
51007
+ throw new SkillBundleInspectionError("BUNDLE_LIMIT", "Bundle file byte limit exceeded");
51008
+ }
51009
+ const name = h.subarray(0, 100);
51010
+ const end = name.indexOf(0);
51011
+ if (end !== -1 && name.subarray(end).some((b) => b !== 0))
51012
+ invalidBundle("Invalid tar path padding");
51013
+ const raw = end === -1 ? name : name.subarray(0, end);
51014
+ if (raw.byteLength > this.limits.pathBytes)
51015
+ throw new SkillBundleInspectionError("BUNDLE_LIMIT", "Bundle path byte limit exceeded");
51016
+ let path;
51017
+ try {
51018
+ path = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(raw);
51019
+ } catch {
51020
+ return invalidBundle("Invalid UTF-8 bundle path");
51021
+ }
51022
+ this.paths.add(path, this.limits.pathBytes, invalidBundle, () => {
51023
+ throw new SkillBundleInspectionError("BUNDLE_LIMIT", "Bundle path byte limit exceeded");
51024
+ });
51025
+ this.fileBytes += size2;
51026
+ this.pending = { path, mode, bytes: new Uint8Array(new ArrayBuffer(size2)) };
51027
+ this.bodyOffset = 0;
51028
+ this.padding = (BLOCK - size2 % BLOCK) % BLOCK;
51029
+ if (!size2) {
51030
+ this.entries.push(this.pending);
51031
+ this.pending = undefined;
51032
+ }
51033
+ }
51034
+ }
51035
+ function tarOctal(field) {
51036
+ const text2 = new TextDecoder().decode(field);
51037
+ if (!/^[0-7]+[\0 ]*$/.test(text2))
51038
+ invalidBundle("Invalid tar octal field");
51039
+ const value = Number.parseInt(text2, 8);
51040
+ if (!Number.isSafeInteger(value))
51041
+ invalidBundle("Tar integer is out of range");
51042
+ return value;
51043
+ }
51044
+ var BLOCK = 512, ANY_SEGMENT_EXCLUDES, ROOT_EXCLUDES, TOOL_SIDECAR_FILENAMES, CREDENTIAL_FILENAMES, CREDENTIAL_EXTENSIONS, ENV_TEMPLATE_NAMES, NON_DOTENV_EXTENSIONS, SKILL_BUNDLE_INSPECTION_LIMITS, SkillBundleInspectionError;
50658
51045
  var init_skill_bundle = __esm(() => {
50659
51046
  ANY_SEGMENT_EXCLUDES = new Set([
50660
51047
  ".git",
@@ -50778,6 +51165,22 @@ var init_skill_bundle = __esm(() => {
50778
51165
  "tar",
50779
51166
  "wasm"
50780
51167
  ]);
51168
+ SKILL_BUNDLE_INSPECTION_LIMITS = Object.freeze({
51169
+ compressedBytes: 16 * 1024 * 1024,
51170
+ decompressedBytes: 64 * 1024 * 1024,
51171
+ entries: 1024,
51172
+ fileBytes: 16 * 1024 * 1024,
51173
+ pathBytes: 100,
51174
+ timeoutMs: 5000
51175
+ });
51176
+ SkillBundleInspectionError = class SkillBundleInspectionError extends Error {
51177
+ code;
51178
+ constructor(code, message) {
51179
+ super(message);
51180
+ this.code = code;
51181
+ this.name = "SkillBundleInspectionError";
51182
+ }
51183
+ };
50781
51184
  });
50782
51185
 
50783
51186
  // src/lib/skill-version.ts
@@ -51146,16 +51549,16 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
51146
51549
  }
51147
51550
  return { path: target, created };
51148
51551
  }
51149
- function writePullMarker(dir, record3) {
51552
+ function writePullMarker(dir, record4) {
51150
51553
  const marker = {
51151
51554
  managedBy: "@hasna/skills",
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 } : {},
51555
+ skill: record4.skill,
51556
+ source: record4.source ?? "pull",
51557
+ ...record4.version ? { version: record4.version } : {},
51558
+ ...record4.contentHash ? { contentHash: record4.contentHash } : {},
51559
+ ...record4.sourceCommit ? { sourceCommit: record4.sourceCommit } : {},
51560
+ ...record4.signature ? { signature: record4.signature } : {},
51561
+ ...record4.revisionId ? { revisionId: record4.revisionId } : {},
51159
51562
  syncedAt: new Date().toISOString()
51160
51563
  };
51161
51564
  writeFileSync8(join20(dir, PULL_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
@@ -51170,19 +51573,19 @@ async function safeMeta(client, slug) {
51170
51573
  }
51171
51574
  if (!raw || typeof raw !== "object")
51172
51575
  return null;
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;
51576
+ const record4 = raw;
51577
+ const kind = record4.kind === "instruction" || record4.kind === "executable" ? record4.kind : undefined;
51578
+ const tags = Array.isArray(record4.tags) ? record4.tags.filter((tag) => typeof tag === "string" && tag.trim().length > 0) : undefined;
51176
51579
  return {
51177
- ...str(record3.displayName) ? { displayName: str(record3.displayName) } : {},
51178
- ...str(record3.description) ? { description: str(record3.description) } : {},
51179
- ...str(record3.category) ? { category: str(record3.category) } : {},
51580
+ ...str(record4.displayName) ? { displayName: str(record4.displayName) } : {},
51581
+ ...str(record4.description) ? { description: str(record4.description) } : {},
51582
+ ...str(record4.category) ? { category: str(record4.category) } : {},
51180
51583
  ...tags && tags.length ? { tags } : {},
51181
- ...str(record3.version) ? { version: str(record3.version) } : {},
51584
+ ...str(record4.version) ? { version: str(record4.version) } : {},
51182
51585
  ...kind ? { kind } : {},
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) } : {}
51586
+ ...REVISION_ID_PATTERN.test(str(record4.revisionId) ?? "") ? { revisionId: str(record4.revisionId) } : {},
51587
+ ...typeof record4.skillMd === "string" && record4.skillMd.length > 0 ? { skillMd: record4.skillMd } : {},
51588
+ ...str(record4.publishedSource) ? { publishedSource: str(record4.publishedSource) } : {}
51186
51589
  };
51187
51590
  }
51188
51591
  function pickCorpusOptions(options) {
@@ -51191,8 +51594,8 @@ function pickCorpusOptions(options) {
51191
51594
  function extractSlug(entry) {
51192
51595
  if (!entry || typeof entry !== "object")
51193
51596
  return;
51194
- const record3 = entry;
51195
- return str(record3.slug) ?? str(record3.name);
51597
+ const record4 = entry;
51598
+ return str(record4.slug) ?? str(record4.name);
51196
51599
  }
51197
51600
  function dedupe(values2) {
51198
51601
  return [...new Set(values2)];
@@ -53515,8 +53918,8 @@ function writeRollbackRecord(mode, entries, appDir = getDataDir()) {
53515
53918
  const dir = join24(appDir, ROLLBACK_DIRNAME);
53516
53919
  mkdirSync9(dir, { recursive: true });
53517
53920
  const file = join24(dir, `${mode}-${Date.now()}.json`);
53518
- const record3 = { version: 1, mode, timestamp: new Date().toISOString(), entries };
53519
- writeFileSync10(file, `${JSON.stringify(record3, null, 2)}
53921
+ const record4 = { version: 1, mode, timestamp: new Date().toISOString(), entries };
53922
+ writeFileSync10(file, `${JSON.stringify(record4, null, 2)}
53520
53923
  `);
53521
53924
  return file;
53522
53925
  }
@@ -54394,7 +54797,7 @@ function createSkillRun(params, targetDir = process.cwd()) {
54394
54797
  mkdirSync10(logsDir, { recursive: true });
54395
54798
  mkdirSync10(exportDir, { recursive: true });
54396
54799
  mkdirSync10(join27(root, "tmp"), { recursive: true });
54397
- const record3 = {
54800
+ const record4 = {
54398
54801
  id,
54399
54802
  skill: skillName,
54400
54803
  status: params.status ?? "running",
@@ -54412,10 +54815,10 @@ function createSkillRun(params, targetDir = process.cwd()) {
54412
54815
  logsDir: toProjectRelative(targetDir, logsDir)
54413
54816
  }
54414
54817
  };
54415
- const context = { targetDir, runDir, exportDir, logsDir, record: record3 };
54818
+ const context = { targetDir, runDir, exportDir, logsDir, record: record4 };
54416
54819
  writeRunRecord(context);
54417
54820
  writeArtifactsManifest(context, []);
54418
- appendRunEvent(context, "created", { status: record3.status });
54821
+ appendRunEvent(context, "created", { status: record4.status });
54419
54822
  return context;
54420
54823
  }
54421
54824
  function completeSkillRun(context, patch) {
@@ -54465,9 +54868,9 @@ function listSkillRuns(targetDir = process.cwd(), limit = 50) {
54465
54868
  if (!statSync14(dayDir).isDirectory())
54466
54869
  continue;
54467
54870
  for (const runId of readdirSync13(dayDir).sort().reverse()) {
54468
- const record3 = readRunRecord(join27(dayDir, runId));
54469
- if (record3)
54470
- records.push(record3);
54871
+ const record4 = readRunRecord(join27(dayDir, runId));
54872
+ if (record4)
54873
+ records.push(record4);
54471
54874
  if (records.length >= limit)
54472
54875
  return records;
54473
54876
  }
@@ -54479,9 +54882,9 @@ function findSkillRun(runId, targetDir = process.cwd()) {
54479
54882
  if (!existsSync25(runsRoot))
54480
54883
  return null;
54481
54884
  for (const day of readdirSync13(runsRoot)) {
54482
- const record3 = readRunRecord(join27(runsRoot, day, runId));
54483
- if (record3)
54484
- return record3;
54885
+ const record4 = readRunRecord(join27(runsRoot, day, runId));
54886
+ if (record4)
54887
+ return record4;
54485
54888
  }
54486
54889
  return null;
54487
54890
  }
@@ -55317,11 +55720,11 @@ function datetime(args) {
55317
55720
  const timeRegex2 = `${time2}(?:${opts.join("|")})`;
55318
55721
  return new RegExp(`^${dateSource}T(?:${timeRegex2})$`);
55319
55722
  }
55320
- var cuid, cuid2, ulid, xid, ksuid, nanoid, duration, guid, uuid3 = (version) => {
55723
+ var cuid, cuid2, ulid, xid, ksuid, nanoid, duration, guid, uuid4 = (version) => {
55321
55724
  if (!version)
55322
55725
  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)$/;
55323
55726
  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})$`);
55324
- }, email, _emoji = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`, ipv4, ipv6, cidrv4, cidrv6, base64, base64url, hostname, e164, dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`, date, string2 = (params) => {
55727
+ }, email2, _emoji = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`, ipv4, ipv6, cidrv4, cidrv6, base64, base64url, hostname, e164, dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`, date, string2 = (params) => {
55325
55728
  const regex2 = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`;
55326
55729
  return new RegExp(`^${regex2}$`);
55327
55730
  }, integer, number, boolean, _null, lowercase, uppercase;
@@ -55334,7 +55737,7 @@ var init_regexes = __esm(() => {
55334
55737
  nanoid = /^[a-zA-Z0-9_-]{21}$/;
55335
55738
  duration = /^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/;
55336
55739
  guid = /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/;
55337
- email = /^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/;
55740
+ email2 = /^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/;
55338
55741
  ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
55339
55742
  ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})$/;
55340
55743
  cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/;
@@ -56111,13 +56514,13 @@ var init_schemas = __esm(() => {
56111
56514
  const v = versionMap[def.version];
56112
56515
  if (v === undefined)
56113
56516
  throw new Error(`Invalid UUID version: "${def.version}"`);
56114
- def.pattern ?? (def.pattern = uuid3(v));
56517
+ def.pattern ?? (def.pattern = uuid4(v));
56115
56518
  } else
56116
- def.pattern ?? (def.pattern = uuid3());
56519
+ def.pattern ?? (def.pattern = uuid4());
56117
56520
  $ZodStringFormat.init(inst, def);
56118
56521
  });
56119
56522
  $ZodEmail = /* @__PURE__ */ $constructor("$ZodEmail", (inst, def) => {
56120
- def.pattern ?? (def.pattern = email);
56523
+ def.pattern ?? (def.pattern = email2);
56121
56524
  $ZodStringFormat.init(inst, def);
56122
56525
  });
56123
56526
  $ZodURL = /* @__PURE__ */ $constructor("$ZodURL", (inst, def) => {
@@ -58593,7 +58996,7 @@ function intersection2(left, right) {
58593
58996
  right
58594
58997
  });
58595
58998
  }
58596
- function record3(keyType, valueType, params) {
58999
+ function record4(keyType, valueType, params) {
58597
59000
  return new ZodRecord2({
58598
59001
  type: "record",
58599
59002
  keyType,
@@ -59294,7 +59697,7 @@ var init_types2 = __esm(() => {
59294
59697
  });
59295
59698
  FormElicitationCapabilitySchema = intersection2(object2({
59296
59699
  applyDefaults: boolean2().optional()
59297
- }), record3(string3(), unknown()));
59700
+ }), record4(string3(), unknown()));
59298
59701
  ElicitationCapabilitySchema = preprocess((value) => {
59299
59702
  if (value && typeof value === "object" && !Array.isArray(value)) {
59300
59703
  if (Object.keys(value).length === 0) {
@@ -59305,7 +59708,7 @@ var init_types2 = __esm(() => {
59305
59708
  }, intersection2(object2({
59306
59709
  form: FormElicitationCapabilitySchema.optional(),
59307
59710
  url: AssertObjectSchema.optional()
59308
- }), record3(string3(), unknown()).optional()));
59711
+ }), record4(string3(), unknown()).optional()));
59309
59712
  ClientTasksCapabilitySchema = looseObject({
59310
59713
  list: AssertObjectSchema.optional(),
59311
59714
  cancel: AssertObjectSchema.optional(),
@@ -59328,7 +59731,7 @@ var init_types2 = __esm(() => {
59328
59731
  }).optional()
59329
59732
  });
59330
59733
  ClientCapabilitiesSchema = object2({
59331
- experimental: record3(string3(), AssertObjectSchema).optional(),
59734
+ experimental: record4(string3(), AssertObjectSchema).optional(),
59332
59735
  sampling: object2({
59333
59736
  context: AssertObjectSchema.optional(),
59334
59737
  tools: AssertObjectSchema.optional()
@@ -59338,7 +59741,7 @@ var init_types2 = __esm(() => {
59338
59741
  listChanged: boolean2().optional()
59339
59742
  }).optional(),
59340
59743
  tasks: ClientTasksCapabilitySchema.optional(),
59341
- extensions: record3(string3(), AssertObjectSchema).optional()
59744
+ extensions: record4(string3(), AssertObjectSchema).optional()
59342
59745
  });
59343
59746
  InitializeRequestParamsSchema = BaseRequestParamsSchema.extend({
59344
59747
  protocolVersion: string3(),
@@ -59350,7 +59753,7 @@ var init_types2 = __esm(() => {
59350
59753
  params: InitializeRequestParamsSchema
59351
59754
  });
59352
59755
  ServerCapabilitiesSchema = object2({
59353
- experimental: record3(string3(), AssertObjectSchema).optional(),
59756
+ experimental: record4(string3(), AssertObjectSchema).optional(),
59354
59757
  logging: AssertObjectSchema.optional(),
59355
59758
  completions: AssertObjectSchema.optional(),
59356
59759
  prompts: object2({
@@ -59364,7 +59767,7 @@ var init_types2 = __esm(() => {
59364
59767
  listChanged: boolean2().optional()
59365
59768
  }).optional(),
59366
59769
  tasks: ServerTasksCapabilitySchema.optional(),
59367
- extensions: record3(string3(), AssertObjectSchema).optional()
59770
+ extensions: record4(string3(), AssertObjectSchema).optional()
59368
59771
  });
59369
59772
  InitializeResultSchema = ResultSchema.extend({
59370
59773
  protocolVersion: string3(),
@@ -59451,7 +59854,7 @@ var init_types2 = __esm(() => {
59451
59854
  ResourceContentsSchema = object2({
59452
59855
  uri: string3(),
59453
59856
  mimeType: optional(string3()),
59454
- _meta: record3(string3(), unknown()).optional()
59857
+ _meta: record4(string3(), unknown()).optional()
59455
59858
  });
59456
59859
  TextResourceContentsSchema = ResourceContentsSchema.extend({
59457
59860
  text: string3()
@@ -59556,7 +59959,7 @@ var init_types2 = __esm(() => {
59556
59959
  });
59557
59960
  GetPromptRequestParamsSchema = BaseRequestParamsSchema.extend({
59558
59961
  name: string3(),
59559
- arguments: record3(string3(), string3()).optional()
59962
+ arguments: record4(string3(), string3()).optional()
59560
59963
  });
59561
59964
  GetPromptRequestSchema = RequestSchema.extend({
59562
59965
  method: literal("prompts/get"),
@@ -59566,34 +59969,34 @@ var init_types2 = __esm(() => {
59566
59969
  type: literal("text"),
59567
59970
  text: string3(),
59568
59971
  annotations: AnnotationsSchema.optional(),
59569
- _meta: record3(string3(), unknown()).optional()
59972
+ _meta: record4(string3(), unknown()).optional()
59570
59973
  });
59571
59974
  ImageContentSchema = object2({
59572
59975
  type: literal("image"),
59573
59976
  data: Base64Schema,
59574
59977
  mimeType: string3(),
59575
59978
  annotations: AnnotationsSchema.optional(),
59576
- _meta: record3(string3(), unknown()).optional()
59979
+ _meta: record4(string3(), unknown()).optional()
59577
59980
  });
59578
59981
  AudioContentSchema = object2({
59579
59982
  type: literal("audio"),
59580
59983
  data: Base64Schema,
59581
59984
  mimeType: string3(),
59582
59985
  annotations: AnnotationsSchema.optional(),
59583
- _meta: record3(string3(), unknown()).optional()
59986
+ _meta: record4(string3(), unknown()).optional()
59584
59987
  });
59585
59988
  ToolUseContentSchema = object2({
59586
59989
  type: literal("tool_use"),
59587
59990
  name: string3(),
59588
59991
  id: string3(),
59589
- input: record3(string3(), unknown()),
59590
- _meta: record3(string3(), unknown()).optional()
59992
+ input: record4(string3(), unknown()),
59993
+ _meta: record4(string3(), unknown()).optional()
59591
59994
  });
59592
59995
  EmbeddedResourceSchema = object2({
59593
59996
  type: literal("resource"),
59594
59997
  resource: union2([TextResourceContentsSchema, BlobResourceContentsSchema]),
59595
59998
  annotations: AnnotationsSchema.optional(),
59596
- _meta: record3(string3(), unknown()).optional()
59999
+ _meta: record4(string3(), unknown()).optional()
59597
60000
  });
59598
60001
  ResourceLinkSchema = ResourceSchema.extend({
59599
60002
  type: literal("resource_link")
@@ -59633,17 +60036,17 @@ var init_types2 = __esm(() => {
59633
60036
  description: string3().optional(),
59634
60037
  inputSchema: object2({
59635
60038
  type: literal("object"),
59636
- properties: record3(string3(), AssertObjectSchema).optional(),
60039
+ properties: record4(string3(), AssertObjectSchema).optional(),
59637
60040
  required: array(string3()).optional()
59638
60041
  }).catchall(unknown()),
59639
60042
  outputSchema: object2({
59640
60043
  type: literal("object"),
59641
- properties: record3(string3(), AssertObjectSchema).optional(),
60044
+ properties: record4(string3(), AssertObjectSchema).optional(),
59642
60045
  required: array(string3()).optional()
59643
60046
  }).catchall(unknown()).optional(),
59644
60047
  annotations: ToolAnnotationsSchema.optional(),
59645
60048
  execution: ToolExecutionSchema.optional(),
59646
- _meta: record3(string3(), unknown()).optional()
60049
+ _meta: record4(string3(), unknown()).optional()
59647
60050
  });
59648
60051
  ListToolsRequestSchema = PaginatedRequestSchema.extend({
59649
60052
  method: literal("tools/list")
@@ -59653,7 +60056,7 @@ var init_types2 = __esm(() => {
59653
60056
  });
59654
60057
  CallToolResultSchema = ResultSchema.extend({
59655
60058
  content: array(ContentBlockSchema).default([]),
59656
- structuredContent: record3(string3(), unknown()).optional(),
60059
+ structuredContent: record4(string3(), unknown()).optional(),
59657
60060
  isError: boolean2().optional()
59658
60061
  });
59659
60062
  CompatibilityCallToolResultSchema = CallToolResultSchema.or(ResultSchema.extend({
@@ -59661,7 +60064,7 @@ var init_types2 = __esm(() => {
59661
60064
  }));
59662
60065
  CallToolRequestParamsSchema = TaskAugmentedRequestParamsSchema.extend({
59663
60066
  name: string3(),
59664
- arguments: record3(string3(), unknown()).optional()
60067
+ arguments: record4(string3(), unknown()).optional()
59665
60068
  });
59666
60069
  CallToolRequestSchema = RequestSchema.extend({
59667
60070
  method: literal("tools/call"),
@@ -59710,7 +60113,7 @@ var init_types2 = __esm(() => {
59710
60113
  content: array(ContentBlockSchema).default([]),
59711
60114
  structuredContent: object2({}).loose().optional(),
59712
60115
  isError: boolean2().optional(),
59713
- _meta: record3(string3(), unknown()).optional()
60116
+ _meta: record4(string3(), unknown()).optional()
59714
60117
  });
59715
60118
  SamplingContentSchema = discriminatedUnion("type", [TextContentSchema, ImageContentSchema, AudioContentSchema]);
59716
60119
  SamplingMessageContentBlockSchema = discriminatedUnion("type", [
@@ -59723,7 +60126,7 @@ var init_types2 = __esm(() => {
59723
60126
  SamplingMessageSchema = object2({
59724
60127
  role: RoleSchema,
59725
60128
  content: union2([SamplingMessageContentBlockSchema, array(SamplingMessageContentBlockSchema)]),
59726
- _meta: record3(string3(), unknown()).optional()
60129
+ _meta: record4(string3(), unknown()).optional()
59727
60130
  });
59728
60131
  CreateMessageRequestParamsSchema = TaskAugmentedRequestParamsSchema.extend({
59729
60132
  messages: array(SamplingMessageSchema),
@@ -59836,7 +60239,7 @@ var init_types2 = __esm(() => {
59836
60239
  message: string3(),
59837
60240
  requestedSchema: object2({
59838
60241
  type: literal("object"),
59839
- properties: record3(string3(), PrimitiveSchemaDefinitionSchema),
60242
+ properties: record4(string3(), PrimitiveSchemaDefinitionSchema),
59840
60243
  required: array(string3()).optional()
59841
60244
  })
59842
60245
  });
@@ -59860,7 +60263,7 @@ var init_types2 = __esm(() => {
59860
60263
  });
59861
60264
  ElicitResultSchema = ResultSchema.extend({
59862
60265
  action: _enum(["accept", "decline", "cancel"]),
59863
- content: preprocess((val) => val === null ? undefined : val, record3(string3(), union2([string3(), number2(), boolean2(), array(string3())])).optional())
60266
+ content: preprocess((val) => val === null ? undefined : val, record4(string3(), union2([string3(), number2(), boolean2(), array(string3())])).optional())
59864
60267
  });
59865
60268
  ResourceTemplateReferenceSchema = object2({
59866
60269
  type: literal("ref/resource"),
@@ -59877,7 +60280,7 @@ var init_types2 = __esm(() => {
59877
60280
  value: string3()
59878
60281
  }),
59879
60282
  context: object2({
59880
- arguments: record3(string3(), string3()).optional()
60283
+ arguments: record4(string3(), string3()).optional()
59881
60284
  }).optional()
59882
60285
  });
59883
60286
  CompleteRequestSchema = RequestSchema.extend({
@@ -59894,7 +60297,7 @@ var init_types2 = __esm(() => {
59894
60297
  RootSchema = object2({
59895
60298
  uri: string3().startsWith("file://"),
59896
60299
  name: string3().optional(),
59897
- _meta: record3(string3(), unknown()).optional()
60300
+ _meta: record4(string3(), unknown()).optional()
59898
60301
  });
59899
60302
  ListRootsRequestSchema = RequestSchema.extend({
59900
60303
  method: literal("roots/list"),
@@ -67558,8 +67961,8 @@ var require_multipleOf = __commonJS((exports) => {
67558
67961
  const { gen, data, schemaCode, it } = cxt;
67559
67962
  const prec = it.opts.multipleOfPrecision;
67560
67963
  const res = gen.let("res");
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}))`);
67964
+ const invalid3 = prec ? (0, codegen_1._)`Math.abs(Math.round(${res}) - ${res}) > 1e-${prec}` : (0, codegen_1._)`${res} !== parseInt(${res})`;
67965
+ cxt.fail$data((0, codegen_1._)`(${schemaCode} === 0 || (${res} = ${data}/${schemaCode}, ${invalid3}))`);
67563
67966
  }
67564
67967
  };
67565
67968
  exports.default = def;
@@ -73636,6 +74039,107 @@ var init_storage_tools = __esm(() => {
73636
74039
  init_helpers();
73637
74040
  });
73638
74041
 
74042
+ // src/lib/remote-invitation-recovery.ts
74043
+ function invitationEmailIds(invitationId2, challengeId) {
74044
+ if (!uuid5(invitationId2) || !uuid5(challengeId))
74045
+ throw new InvitationEmailInputError;
74046
+ return { invitationId: invitationId2, challengeId };
74047
+ }
74048
+ function invitationEmailInput(action, input) {
74049
+ const keys2 = ["invitationId", "token", "challengeId", "confirm", ...action === "accept" ? ["code"] : []];
74050
+ if (!record6(input) || Object.keys(input).length !== keys2.length || keys2.some((key) => !Object.hasOwn(input, key)))
74051
+ throw new InvitationEmailInputError;
74052
+ const value = { ...input };
74053
+ const ids = invitationEmailIds(value.invitationId, value.challengeId);
74054
+ if (value.confirm !== true || typeof value.token !== "string" || !/^[A-Za-z0-9_-]{43}$/.test(value.token) || action === "accept" && (typeof value.code !== "string" || !/^\d{6}$/.test(value.code)))
74055
+ throw new InvitationEmailInputError;
74056
+ return { ...ids, token: value.token, confirm: true, ...action === "accept" ? { code: value.code } : {} };
74057
+ }
74058
+ async function requestInvitationEmail(origin, action, input) {
74059
+ const value = invitationEmailInput(action, input);
74060
+ let target;
74061
+ try {
74062
+ target = normalizeSkillsApiOrigin(origin);
74063
+ } catch {
74064
+ throw new InvitationEmailInputError;
74065
+ }
74066
+ const body = JSON.stringify({ invitationId: value.invitationId, token: value.token, challengeId: value.challengeId, ...action === "accept" ? { code: value.code } : {} });
74067
+ try {
74068
+ const response = await fetch(`${target}/api/v1/account/invitations/email-${action}`, {
74069
+ method: "POST",
74070
+ headers: { "Content-Type": "application/json" },
74071
+ body,
74072
+ credentials: "omit",
74073
+ redirect: "error",
74074
+ cache: "no-store",
74075
+ referrerPolicy: "no-referrer",
74076
+ signal: AbortSignal.timeout(15000)
74077
+ });
74078
+ const parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(await readBoundedResponse(response, 4096)));
74079
+ if (!response.ok && record6(parsed) && typeof parsed.code === "string" && Object.hasOwn(refusals, parsed.code)) {
74080
+ const code = parsed.code;
74081
+ if (response.status === refusals[code][0])
74082
+ throw new RemoteInvitationEmailError(code);
74083
+ }
74084
+ if (!record6(parsed))
74085
+ throw new RemoteInvitationEmailUnconfirmedError(action);
74086
+ if (action === "challenge" && response.status === 202 && parsed.challengeId === value.challengeId && parsed.expiresIn === 600 && typeof parsed.message === "string" && parsed.message.length <= 256) {
74087
+ return { challengeId: value.challengeId, message: "If this invitation is eligible, a verification code will arrive. Delivery is not confirmed.", expiresIn: 600 };
74088
+ }
74089
+ if (action === "accept" && response.status === 200 && uuid5(parsed.organizationId) && uuid5(parsed.membershipId) && parsed.accepted === true && parsed.changed === true && parsed.signInRequired === true) {
74090
+ return { organizationId: parsed.organizationId, membershipId: parsed.membershipId, accepted: true, changed: true, signInRequired: true };
74091
+ }
74092
+ } catch (error2) {
74093
+ if (error2 instanceof RemoteInvitationEmailError)
74094
+ throw error2;
74095
+ }
74096
+ throw new RemoteInvitationEmailUnconfirmedError(action);
74097
+ }
74098
+ function invitationEmailCustomerError(error2) {
74099
+ if (error2 instanceof InvitationEmailInputError || error2 instanceof RemoteInvitationEmailError || error2 instanceof RemoteInvitationEmailUnconfirmedError)
74100
+ return { code: error2.code, error: error2.message };
74101
+ return { code: "INVITATION_EMAIL_UNAVAILABLE", error: "Unable to prepare this recovery action. Check the explicit server and stable profile. No credential was saved." };
74102
+ }
74103
+ var InvitationEmailInputError, refusals, RemoteInvitationEmailError, RemoteInvitationEmailUnconfirmedError, record6 = (v) => !!v && typeof v === "object" && !Array.isArray(v), uuid5 = (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);
74104
+ var init_remote_invitation_recovery = __esm(() => {
74105
+ init_fleet_credentials();
74106
+ init_remote_files();
74107
+ InvitationEmailInputError = class InvitationEmailInputError extends Error {
74108
+ code = "INVITATION_EMAIL_INPUT_INVALID";
74109
+ constructor() {
74110
+ super("Use an explicit Skills API URL, exact invitation and retained challenge IDs, secret input, and deliberate confirmation.");
74111
+ this.name = "InvitationEmailInputError";
74112
+ }
74113
+ };
74114
+ refusals = {
74115
+ INVALID_REQUEST: [400, "Invitation recovery parameters were refused."],
74116
+ ORIGIN_REQUIRED: [403, "Invitation recovery requires the configured site origin."],
74117
+ INVITATION_PROOF_UNAVAILABLE: [401, "Invitation proof is unavailable. Sign in or explicitly request another recovery code."],
74118
+ RATE_LIMITED: [429, "Invitation verification is rate limited. Wait before another deliberate action."],
74119
+ INVITATION_BUSY: [503, "Invitation is busy. Sign in to check membership before another deliberate action."],
74120
+ INVITATION_DELIVERY_UNAVAILABLE: [503, "Invitation recovery is unavailable on this service."]
74121
+ };
74122
+ RemoteInvitationEmailError = class RemoteInvitationEmailError extends Error {
74123
+ code;
74124
+ status;
74125
+ constructor(code) {
74126
+ super(refusals[code][1]);
74127
+ this.code = code;
74128
+ this.name = "RemoteInvitationEmailError";
74129
+ this.status = refusals[code][0];
74130
+ }
74131
+ };
74132
+ RemoteInvitationEmailUnconfirmedError = class RemoteInvitationEmailUnconfirmedError extends Error {
74133
+ action;
74134
+ code = "INVITATION_EMAIL_UNCONFIRMED";
74135
+ constructor(action) {
74136
+ super(action === "challenge" ? "The recovery challenge outcome is unconfirmed. Retain the same invitation, challenge ID and server. Check your inbox; never rotate the challenge or retry automatically. No delivery is confirmed." : "Invitation acceptance is unconfirmed. Use fresh ordinary sign-in to inspect available memberships. Do not retry acceptance automatically; explicitly request another recovery code only if needed. Saved credentials are unchanged.");
74137
+ this.action = action;
74138
+ this.name = "RemoteInvitationEmailUnconfirmedError";
74139
+ }
74140
+ };
74141
+ });
74142
+
73639
74143
  // src/lib/remote-auth.ts
73640
74144
  async function requestAuthApi(instance, path, options) {
73641
74145
  const url = normalizeSkillsApiOrigin(instance);
@@ -73658,10 +74162,10 @@ async function requestAuthApi(instance, path, options) {
73658
74162
  const text2 = await res.text();
73659
74163
  const body = text2 ? parseJsonBody(text2) : {};
73660
74164
  if (!res.ok) {
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;
74165
+ const record7 = isRecord5(body) ? body : {};
74166
+ const detail = typeof record7.detail === "string" ? record7.detail : undefined;
74167
+ const error2 = typeof record7.error === "string" ? record7.error : undefined;
74168
+ const code = typeof record7.code === "string" ? record7.code : undefined;
73665
74169
  throw new HostedApiError(detail || error2 || `${res.status} ${res.statusText}`, {
73666
74170
  status: res.status,
73667
74171
  code,
@@ -73695,11 +74199,17 @@ class RemoteSkillsAuthClient {
73695
74199
  constructor(apiUrl) {
73696
74200
  this.apiOrigin = normalizeSkillsApiOrigin(apiUrl);
73697
74201
  }
73698
- requestCode(email2) {
73699
- return this.request("/api/auth/login", { method: "POST", body: JSON.stringify({ email: email2 }) });
74202
+ requestInvitationEmailChallenge(input) {
74203
+ return requestInvitationEmail(this.apiOrigin, "challenge", input);
74204
+ }
74205
+ acceptInvitationEmailChallenge(input) {
74206
+ return requestInvitationEmail(this.apiOrigin, "accept", input);
74207
+ }
74208
+ requestCode(email3) {
74209
+ return this.request("/api/auth/login", { method: "POST", body: JSON.stringify({ email: email3 }) });
73700
74210
  }
73701
- verifyCode(email2, code) {
73702
- return this.request("/api/auth/verify", { method: "POST", body: JSON.stringify({ email: email2, code }) });
74211
+ verifyCode(email3, code) {
74212
+ return this.request("/api/auth/verify", { method: "POST", body: JSON.stringify({ email: email3, code }) });
73703
74213
  }
73704
74214
  startDevice() {
73705
74215
  return this.request("/api/auth/device/start", { method: "POST", body: JSON.stringify({ client: "skills-sdk" }) });
@@ -73707,34 +74217,34 @@ class RemoteSkillsAuthClient {
73707
74217
  pollDevice(deviceCode) {
73708
74218
  return this.request("/api/auth/device/token", { method: "POST", body: JSON.stringify({ deviceCode }) });
73709
74219
  }
73710
- async sessionClient(email2, code, context) {
74220
+ async sessionClient(email3, code, context) {
73711
74221
  if (context !== undefined) {
73712
74222
  const target = workspaceContext(context), apiOrigin2 = this.apiOrigin;
73713
- const session = await this.switchWorkspace(email2, code, target);
74223
+ const session = await this.switchWorkspace(email3, code, target);
73714
74224
  return new RemoteSkillsClient(session.token, apiOrigin2);
73715
74225
  }
73716
74226
  const apiOrigin = this.apiOrigin;
73717
- if (!email2.includes("@") || !/^\d{6}$/.test(code))
74227
+ if (!email3.includes("@") || !/^\d{6}$/.test(code))
73718
74228
  throw new Error("Fresh email and six-digit verification code are required to manage this account");
73719
- const login = await this.verifyCode(email2, code);
74229
+ const login = await this.verifyCode(email3, code);
73720
74230
  if (!login || typeof login.token !== "string" || !login.token)
73721
74231
  throw new Error("The server did not return an authorized account session");
73722
74232
  return new RemoteSkillsClient(login.token, apiOrigin);
73723
74233
  }
73724
- async listAccountWorkspaces(email2, code, expectedUserId) {
73725
- const login = await this.workspaceLogin(email2, code, expectedUserId);
74234
+ async listAccountWorkspaces(email3, code, expectedUserId) {
74235
+ const login = await this.workspaceLogin(email3, code, expectedUserId);
73726
74236
  const result2 = await new RemoteSkillsClient(login.token, login.apiOrigin).listAccountWorkspaces(login.userId);
73727
74237
  return { userId: login.userId, ...result2 };
73728
74238
  }
73729
- async switchWorkspace(email2, code, context) {
74239
+ async switchWorkspace(email3, code, context) {
73730
74240
  const target = workspaceContext(context);
73731
- const login = await this.workspaceLogin(email2, code, target.userId);
74241
+ const login = await this.workspaceLogin(email3, code, target.userId);
73732
74242
  return new RemoteSkillsClient(login.token, login.apiOrigin).switchWorkspace(target);
73733
74243
  }
73734
- async workspaceLogin(email2, code, expectedUserId) {
74244
+ async workspaceLogin(email3, code, expectedUserId) {
73735
74245
  const expected = expectedUserId === undefined ? undefined : workspaceExpectedUserId(expectedUserId);
73736
74246
  const apiOrigin = this.apiOrigin;
73737
- if (typeof email2 !== "string" || !email2.includes("@") || typeof code !== "string" || !/^\d{6}$/.test(code))
74247
+ if (typeof email3 !== "string" || !email3.includes("@") || typeof code !== "string" || !/^\d{6}$/.test(code))
73738
74248
  throw new Error("Fresh email and six-digit verification code are required to manage this account");
73739
74249
  let response;
73740
74250
  try {
@@ -73744,7 +74254,7 @@ class RemoteSkillsAuthClient {
73744
74254
  credentials: "omit",
73745
74255
  signal: AbortSignal.timeout(15000),
73746
74256
  headers: { "Content-Type": "application/json" },
73747
- body: JSON.stringify({ email: email2, code })
74257
+ body: JSON.stringify({ email: email3, code })
73748
74258
  });
73749
74259
  } catch {
73750
74260
  throw new HostedApiError("Unable to verify the Skills account.");
@@ -73761,40 +74271,67 @@ class RemoteSkillsAuthClient {
73761
74271
  }
73762
74272
  return { ...parseWorkspaceLogin(value, expected), apiOrigin };
73763
74273
  }
73764
- async createApiKey(email2, code, name, scopes, context) {
74274
+ async listWorkspaceInvitations(email3, code, context, options = {}) {
74275
+ const target = workspaceContext(context), captured = invitationInput("list", options);
74276
+ return (await this.sessionClient(email3, code, target)).listWorkspaceInvitations(target, captured);
74277
+ }
74278
+ async getWorkspaceInvitation(email3, code, context, invitationId2) {
74279
+ const target = workspaceContext(context), captured = invitationInput("get", { invitationId: invitationId2 });
74280
+ return (await this.sessionClient(email3, code, target)).getWorkspaceInvitation(target, captured.invitationId);
74281
+ }
74282
+ async issueWorkspaceInvitation(email3, code, context, input) {
74283
+ const target = workspaceContext(context), captured = invitationInput("issue", input);
74284
+ return (await this.sessionClient(email3, code, target)).issueWorkspaceInvitation(target, captured);
74285
+ }
74286
+ async resendWorkspaceInvitation(email3, code, context, invitationId2, input) {
74287
+ const target = workspaceContext(context), captured = invitationInput("resend", { ...input, invitationId: invitationId2 });
74288
+ const { invitationId: id, ...options } = captured;
74289
+ return (await this.sessionClient(email3, code, target)).resendWorkspaceInvitation(target, id, options);
74290
+ }
74291
+ async revokeWorkspaceInvitation(email3, code, context, invitationId2, input) {
74292
+ const target = workspaceContext(context), captured = invitationInput("revoke", { ...input, invitationId: invitationId2 });
74293
+ const { invitationId: id, ...options } = captured;
74294
+ return (await this.sessionClient(email3, code, target)).revokeWorkspaceInvitation(target, id, options);
74295
+ }
74296
+ async acceptWorkspaceInvitation(email3, code, context, invitationId2, input) {
74297
+ const target = workspaceContext(context), captured = invitationInput("accept", { ...input, invitationId: invitationId2 });
74298
+ const { invitationId: id, ...options } = captured;
74299
+ return (await this.sessionClient(email3, code, target)).acceptWorkspaceInvitation(target, id, options);
74300
+ }
74301
+ async createApiKey(email3, code, name, scopes, context) {
73765
74302
  const capturedScopes = scopes === undefined ? undefined : [...scopes];
73766
- return (await this.sessionClient(email2, code, context)).createApiKey(name, capturedScopes);
74303
+ return (await this.sessionClient(email3, code, context)).createApiKey(name, capturedScopes);
73767
74304
  }
73768
- async listApiKeys(email2, code, context) {
73769
- return (await this.sessionClient(email2, code, context)).listApiKeys();
74305
+ async listApiKeys(email3, code, context) {
74306
+ return (await this.sessionClient(email3, code, context)).listApiKeys();
73770
74307
  }
73771
- async revokeApiKey(email2, code, keyId, context) {
73772
- return (await this.sessionClient(email2, code, context)).revokeApiKey(keyId);
74308
+ async revokeApiKey(email3, code, keyId, context) {
74309
+ return (await this.sessionClient(email3, code, context)).revokeApiKey(keyId);
73773
74310
  }
73774
- async updateProfile(email2, code, input, context) {
74311
+ async updateProfile(email3, code, input, context) {
73775
74312
  const body = customerNamePatch(input, "displayName");
73776
- return (await this.sessionClient(email2, code, context)).updateProfile({ displayName: body.displayName });
74313
+ return (await this.sessionClient(email3, code, context)).updateProfile({ displayName: body.displayName });
73777
74314
  }
73778
- async updateCurrentWorkspace(email2, code, input, context) {
74315
+ async updateCurrentWorkspace(email3, code, input, context) {
73779
74316
  const body = customerNamePatch(input, "name");
73780
- return (await this.sessionClient(email2, code, context)).updateCurrentWorkspace({ name: body.name });
74317
+ return (await this.sessionClient(email3, code, context)).updateCurrentWorkspace({ name: body.name });
73781
74318
  }
73782
- async listWorkspaceMembers(email2, code, options = {}, context) {
74319
+ async listWorkspaceMembers(email3, code, options = {}, context) {
73783
74320
  workspaceMembersQuery(options);
73784
74321
  const captured = { ...options };
73785
- return (await this.sessionClient(email2, code, context)).listWorkspaceMembers(captured);
74322
+ return (await this.sessionClient(email3, code, context)).listWorkspaceMembers(captured);
73786
74323
  }
73787
- async setWorkspaceMemberRole(email2, code, membershipId, input, context) {
74324
+ async setWorkspaceMemberRole(email3, code, membershipId, input, context) {
73788
74325
  const captured = workspaceMemberRoleInput(membershipId, input);
73789
- return (await this.sessionClient(email2, code, context)).setWorkspaceMemberRole(captured.membershipId, captured.body);
74326
+ return (await this.sessionClient(email3, code, context)).setWorkspaceMemberRole(captured.membershipId, captured.body);
73790
74327
  }
73791
- async leaveWorkspace(email2, code, context, input) {
74328
+ async leaveWorkspace(email3, code, context, input) {
73792
74329
  const captured = workspaceLeaveInput(context, input);
73793
- return (await this.sessionClient(email2, code, captured.context)).leaveWorkspace(captured.context, captured.input);
74330
+ return (await this.sessionClient(email3, code, captured.context)).leaveWorkspace(captured.context, captured.input);
73794
74331
  }
73795
- async removeWorkspaceMember(email2, code, membershipId, input, context) {
74332
+ async removeWorkspaceMember(email3, code, membershipId, input, context) {
73796
74333
  const captured = workspaceMemberRemovalInput(membershipId, input);
73797
- return (await this.sessionClient(email2, code, context)).removeWorkspaceMember(captured.membershipId, captured.body);
74334
+ return (await this.sessionClient(email3, code, context)).removeWorkspaceMember(captured.membershipId, captured.body);
73798
74335
  }
73799
74336
  request(path, options) {
73800
74337
  if (!["/api/auth/login", "/api/auth/verify", "/api/auth/device/start", "/api/auth/device/token", "/api/auth/keys", "/api/auth/whoami"].includes(path))
@@ -73804,6 +74341,8 @@ class RemoteSkillsAuthClient {
73804
74341
  }
73805
74342
  var MAX_ERROR_DETAIL_LENGTH = 200, HostedApiError;
73806
74343
  var init_remote_auth = __esm(() => {
74344
+ init_remote_invitation_recovery();
74345
+ init_remote_invitations();
73807
74346
  init_remote_workspace_leave();
73808
74347
  init_remote_workspace_selection();
73809
74348
  init_remote_files();
@@ -73950,20 +74489,20 @@ async function prepareWorkspaceEnrollment(membershipId, source = process.env) {
73950
74489
  return {
73951
74490
  profile,
73952
74491
  origin,
73953
- async complete(email2, code) {
74492
+ async complete(email3, code) {
73954
74493
  unchanged2();
73955
- if (!email2.includes("@") || !/^\d{6}$/.test(code))
74494
+ if (!email3.includes("@") || !/^\d{6}$/.test(code))
73956
74495
  return fail2("A fresh email and six-digit verification code are required.");
73957
- if (expected && expected.user.email.toLowerCase() !== email2.toLowerCase())
74496
+ if (expected && expected.user.email.toLowerCase() !== email3.toLowerCase())
73958
74497
  return fail2("This profile belongs to another account. Use a different profile or ordinary replacement login.");
73959
74498
  let issued = false;
73960
74499
  try {
73961
- const result2 = await new RemoteSkillsAuthClient(origin).verifyCode(email2, code);
74500
+ const result2 = await new RemoteSkillsAuthClient(origin).verifyCode(email3, code);
73962
74501
  const login = parseWorkspaceLogin(result2, expected?.user.id);
73963
74502
  if (result2.firstLogin === true)
73964
74503
  return fail2("This sign-in created a new account using the server signup policy. Finish ordinary account login before enrolling a workspace profile.");
73965
74504
  const session = await new RemoteSkillsClient(login.token, origin).switchWorkspace({ userId: login.userId, membershipId });
73966
- if (session.user.email.toLowerCase() !== email2.toLowerCase())
74505
+ if (session.user.email.toLowerCase() !== email3.toLowerCase())
73967
74506
  return fail2("The verified account does not match the requested email.");
73968
74507
  if (session.user.role === "viewer")
73969
74508
  return fail2("Viewer memberships cannot enroll API keys.");
@@ -74047,8 +74586,103 @@ var init_workspace_profile = __esm(() => {
74047
74586
  };
74048
74587
  });
74049
74588
 
74589
+ // src/lib/invitation-customer-action.ts
74590
+ function invitationProfileContext(userId, membershipId, profile) {
74591
+ const target = workspaceContext({ userId, membershipId });
74592
+ if (profile && (profile.userId !== target.userId || profile.membershipId !== target.membershipId))
74593
+ throw new WorkspaceIdentityMismatchError;
74594
+ return target;
74595
+ }
74596
+ async function invokeFreshInvitation(client, email3, code, context, action, input) {
74597
+ const target = workspaceContext(context), captured = invitationInput(action, input);
74598
+ let result2;
74599
+ switch (action) {
74600
+ case "list":
74601
+ result2 = await client.listWorkspaceInvitations(email3, code, target, captured);
74602
+ break;
74603
+ case "get":
74604
+ result2 = await client.getWorkspaceInvitation(email3, code, target, captured.invitationId);
74605
+ break;
74606
+ case "issue":
74607
+ result2 = await client.issueWorkspaceInvitation(email3, code, target, captured);
74608
+ break;
74609
+ case "resend": {
74610
+ const { invitationId: invitationId2, ...options } = captured;
74611
+ result2 = await client.resendWorkspaceInvitation(email3, code, target, invitationId2, options);
74612
+ break;
74613
+ }
74614
+ case "revoke": {
74615
+ const { invitationId: invitationId2, ...options } = captured;
74616
+ result2 = await client.revokeWorkspaceInvitation(email3, code, target, invitationId2, options);
74617
+ break;
74618
+ }
74619
+ case "accept": {
74620
+ const { invitationId: invitationId2, ...options } = captured;
74621
+ result2 = await client.acceptWorkspaceInvitation(email3, code, target, invitationId2, options);
74622
+ break;
74623
+ }
74624
+ default:
74625
+ throw new WorkspaceInvitationInputError;
74626
+ }
74627
+ return result2;
74628
+ }
74629
+ function invitationCustomerError(error2) {
74630
+ if (error2 instanceof WorkspaceInvitationInputError || error2 instanceof RemoteWorkspaceInvitationError || error2 instanceof RemoteWorkspaceInvitationUnconfirmedError || error2 instanceof RemoteWorkspaceInvitationReadError)
74631
+ return { code: error2.code, error: error2.message };
74632
+ return { code: "INVITATION_VERIFICATION_FAILED", error: "Invitation verification failed. Check the selected server, profile, exact user and current membership, then obtain a fresh code. No invitation result was confirmed; saved credentials are unchanged." };
74633
+ }
74634
+ var init_invitation_customer_action = __esm(() => {
74635
+ init_remote_workspace_selection();
74636
+ init_remote_invitations();
74637
+ });
74638
+
74639
+ // src/mcp/remote-invitation-tools.ts
74640
+ function registerRemoteInvitationTools(server) {
74641
+ const uuid6 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
74642
+ const verification = { userId: uuid6, membershipId: uuid6, email: exports_external.string().email().max(254), code: exports_external.string().regex(/^\d{6}$/) };
74643
+ const schemas4 = {
74644
+ list: exports_external.object({ ...verification, after: uuid6.optional() }).strict(),
74645
+ get: exports_external.object({ ...verification, invitationId: uuid6 }).strict(),
74646
+ issue: exports_external.object({ ...verification, recipient: exports_external.string().email().max(254), role: exports_external.enum(["owner", "admin", "member", "viewer"]), idempotencyKey: uuid6, confirm: exports_external.literal(true) }).strict(),
74647
+ resend: exports_external.object({ ...verification, invitationId: uuid6, expectedGeneration: exports_external.number().int().min(1).max(10), idempotencyKey: uuid6, confirm: exports_external.literal(true) }).strict(),
74648
+ revoke: exports_external.object({ ...verification, invitationId: uuid6, expectedGeneration: exports_external.number().int().min(1).max(10), confirm: exports_external.literal(true) }).strict(),
74649
+ accept: exports_external.object({ ...verification, invitationId: uuid6, token: exports_external.string().regex(/^[A-Za-z0-9_-]{43}$/).describe("Secret from the invitation email; supplied only in the MCP request, never returned or saved."), confirm: exports_external.literal(true) }).strict()
74650
+ };
74651
+ for (const action of ["list", "get", "issue", "resend", "revoke", "accept"]) {
74652
+ const read = action === "list" || action === "get";
74653
+ server.registerTool(action === "list" ? "list_workspace_invitations" : `${action}_workspace_invitation`, {
74654
+ title: `${action[0].toUpperCase() + action.slice(1)} Workspace Invitation${action === "list" ? "s" : ""}`,
74655
+ description: "Use fresh verification bound to the exact observed user/current membership and any selected profile. Mutations require confirm=true; issue/resend require a stable caller request key. Never retry uncertain outcomes automatically. Acceptance does not switch workspace or create credentials. Zero-membership account recovery is not supported by this flow.",
74656
+ annotations: { destructiveHint: !read, idempotentHint: true, readOnlyHint: read },
74657
+ inputSchema: schemas4[action]
74658
+ }, async (value) => {
74659
+ try {
74660
+ const { userId, membershipId, email: email3, code, recipient, ...rest2 } = value;
74661
+ const input = invitationInput(action, action === "issue" ? { ...rest2, email: recipient } : rest2);
74662
+ const context = invitationProfileContext(String(userId), String(membershipId));
74663
+ const target = await captureProfileWorkspace("Manage invitations");
74664
+ invitationProfileContext(context.userId, context.membershipId, target.context);
74665
+ target.unchanged();
74666
+ return mcpJson(await invokeFreshInvitation(new RemoteSkillsAuthClient(target.origin), String(email3), String(code), context, action, input));
74667
+ } catch (error2) {
74668
+ const result2 = invitationCustomerError(error2);
74669
+ return mcpError(result2.code, result2.error);
74670
+ }
74671
+ });
74672
+ }
74673
+ }
74674
+ var init_remote_invitation_tools = __esm(() => {
74675
+ init_zod();
74676
+ init_remote_auth();
74677
+ init_workspace_profile();
74678
+ init_invitation_customer_action();
74679
+ init_remote_invitations();
74680
+ init_helpers();
74681
+ });
74682
+
74050
74683
  // src/mcp/remote-customer-tools.ts
74051
74684
  function registerRemoteCustomerTools(server) {
74685
+ registerRemoteInvitationTools(server);
74052
74686
  const memberRole = exports_external.enum(["owner", "admin", "member", "viewer"]);
74053
74687
  const memberInput = {
74054
74688
  membershipId: exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/),
@@ -74061,9 +74695,9 @@ function registerRemoteCustomerTools(server) {
74061
74695
  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
74696
  annotations: { destructiveHint: true, idempotentHint: false, readOnlyHint: false },
74063
74697
  inputSchema: exports_external.object({ ...memberInput, userId: memberInput.membershipId, confirm: exports_external.literal(true) }).strict()
74064
- }, async ({ membershipId, userId, expectedRole, email: email2, code, confirm }) => {
74698
+ }, async ({ membershipId, userId, expectedRole, email: email3, code, confirm }) => {
74065
74699
  try {
74066
- return mcpJson(await freshAccount("Leave workspace", (client, context) => client.leaveWorkspace(email2, code, workspaceLeaveProfileContext(membershipId, userId, context), { expectedRole, confirm })));
74700
+ return mcpJson(await freshAccount("Leave workspace", (client, context) => client.leaveWorkspace(email3, code, workspaceLeaveProfileContext(membershipId, userId, context), { expectedRole, confirm })));
74067
74701
  } catch (error2) {
74068
74702
  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
74703
  }
@@ -74072,9 +74706,9 @@ function registerRemoteCustomerTools(server) {
74072
74706
  title: "Set Current Workspace Member Role",
74073
74707
  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.",
74074
74708
  inputSchema: exports_external.object({ ...memberInput, role: memberRole }).strict()
74075
- }, async ({ membershipId, role: role2, expectedRole, email: email2, code }) => {
74709
+ }, async ({ membershipId, role: role3, expectedRole, email: email3, code }) => {
74076
74710
  try {
74077
- return mcpJson(await freshAccount("Set workspace member role", (client, context) => client.setWorkspaceMemberRole(email2, code, membershipId, { role: role2, expectedRole }, context)));
74711
+ return mcpJson(await freshAccount("Set workspace member role", (client, context) => client.setWorkspaceMemberRole(email3, code, membershipId, { role: role3, expectedRole }, context)));
74078
74712
  } catch (error2) {
74079
74713
  return memberError(error2);
74080
74714
  }
@@ -74083,9 +74717,9 @@ function registerRemoteCustomerTools(server) {
74083
74717
  title: "Remove Current Workspace Member",
74084
74718
  description: "Remove exactly this membership incarnation using its observed expectedRole and fresh verification. Self-removal is unavailable. A retry cannot remove a later replacement membership; saved credentials stay unchanged.",
74085
74719
  inputSchema: exports_external.object(memberInput).strict()
74086
- }, async ({ membershipId, expectedRole, email: email2, code }) => {
74720
+ }, async ({ membershipId, expectedRole, email: email3, code }) => {
74087
74721
  try {
74088
- return mcpJson(await freshAccount("Remove workspace member", (client, context) => client.removeWorkspaceMember(email2, code, membershipId, { expectedRole }, context)));
74722
+ return mcpJson(await freshAccount("Remove workspace member", (client, context) => client.removeWorkspaceMember(email3, code, membershipId, { expectedRole }, context)));
74089
74723
  } catch (error2) {
74090
74724
  return memberError(error2);
74091
74725
  }
@@ -74099,9 +74733,9 @@ function registerRemoteCustomerTools(server) {
74099
74733
  limit: exports_external.number().int().min(1).max(100).optional(),
74100
74734
  cursor: exports_external.string().regex(/^[A-Za-z0-9_-]{1,512}$/).optional()
74101
74735
  }).strict()
74102
- }, async ({ email: email2, code, limit, cursor: cursor2 }) => {
74736
+ }, async ({ email: email3, code, limit, cursor: cursor2 }) => {
74103
74737
  try {
74104
- return mcpJson(await freshAccount("List workspace members", (client, context) => client.listWorkspaceMembers(email2, code, { limit, cursor: cursor2 }, context)));
74738
+ return mcpJson(await freshAccount("List workspace members", (client, context) => client.listWorkspaceMembers(email3, code, { limit, cursor: cursor2 }, context)));
74105
74739
  } catch {
74106
74740
  return mcpError("WORKSPACE_MEMBERS_FAILED", "Unable to list workspace members. Check the selected server, owner/admin permissions, pagination and fresh verification code.");
74107
74741
  }
@@ -74111,9 +74745,9 @@ function registerRemoteCustomerTools(server) {
74111
74745
  title: kind === "profile" ? "Update Account Display Name" : "Update Workspace Name",
74112
74746
  description: "Update only the name on the explicitly selected Skills server using fresh email OTP. Workspace changes require an owner/admin. Saved credentials are unchanged.",
74113
74747
  inputSchema: exports_external.object({ name: exports_external.string().min(1), email: exports_external.string().email(), code: exports_external.string().regex(/^\d{6}$/) }).strict()
74114
- }, async ({ name, email: email2, code }) => {
74748
+ }, async ({ name, email: email3, code }) => {
74115
74749
  try {
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)));
74750
+ return mcpJson(await freshAccount("Update customer name", async (client, context) => kind === "profile" ? client.updateProfile(email3, code, { displayName: name }, context) : client.updateCurrentWorkspace(email3, code, { name }, context)));
74117
74751
  } catch {
74118
74752
  return mcpError("NAME_UPDATE_FAILED", "Unable to update the name. Check the selected server, name, permissions and fresh verification code.");
74119
74753
  }
@@ -74133,9 +74767,9 @@ function registerRemoteCustomerTools(server) {
74133
74767
  title: "List API Keys",
74134
74768
  description: "List account API keys using fresh email OTP reauthentication.",
74135
74769
  inputSchema: { email: exports_external.string().email(), code: exports_external.string().regex(/^\d{6}$/) }
74136
- }, async ({ email: email2, code }) => {
74770
+ }, async ({ email: email3, code }) => {
74137
74771
  try {
74138
- return mcpJson(await freshAccount("List API keys", (client, context) => client.listApiKeys(email2, code, context)));
74772
+ return mcpJson(await freshAccount("List API keys", (client, context) => client.listApiKeys(email3, code, context)));
74139
74773
  } catch {
74140
74774
  return mcpError("KEY_LIST_FAILED", "Unable to list API keys. Check the selected profile, server, account and fresh verification code.");
74141
74775
  }
@@ -74144,9 +74778,9 @@ function registerRemoteCustomerTools(server) {
74144
74778
  title: "Revoke API Key",
74145
74779
  description: "Revoke an account API key using fresh email OTP reauthentication.",
74146
74780
  inputSchema: { key_id: exports_external.string().min(1), email: exports_external.string().email(), code: exports_external.string().regex(/^\d{6}$/) }
74147
- }, async ({ key_id, email: email2, code }) => {
74781
+ }, async ({ key_id, email: email3, code }) => {
74148
74782
  try {
74149
- return mcpJson(await freshAccount("Revoke API key", (client, context) => client.revokeApiKey(email2, code, key_id, context)));
74783
+ return mcpJson(await freshAccount("Revoke API key", (client, context) => client.revokeApiKey(email3, code, key_id, context)));
74150
74784
  } catch {
74151
74785
  return mcpError("KEY_REVOKE_FAILED", "Unable to revoke this API key. Check the selected profile, key, account and fresh verification code.");
74152
74786
  }
@@ -74155,10 +74789,10 @@ function registerRemoteCustomerTools(server) {
74155
74789
  title: "Create API Key",
74156
74790
  description: "Create an API key using fresh email OTP reauthentication; returns its secret once. A stored API key cannot grant this authority.",
74157
74791
  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() }
74158
- }, async ({ name, email: email2, code, scopes }) => {
74792
+ }, async ({ name, email: email3, code, scopes }) => {
74159
74793
  const capturedScopes = scopes === undefined ? undefined : [...scopes];
74160
74794
  try {
74161
- return mcpJson(await freshAccount("Create API key", (client, context) => client.createApiKey(email2, code, name, capturedScopes, context)));
74795
+ return mcpJson(await freshAccount("Create API key", (client, context) => client.createApiKey(email3, code, name, capturedScopes, context)));
74162
74796
  } catch {
74163
74797
  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.");
74164
74798
  }
@@ -74200,6 +74834,7 @@ async function freshAccount(action, operation) {
74200
74834
  return operation(new RemoteSkillsAuthClient(target.origin), target.context);
74201
74835
  }
74202
74836
  var init_remote_customer_tools = __esm(() => {
74837
+ init_remote_invitation_tools();
74203
74838
  init_zod();
74204
74839
  init_remote_auth();
74205
74840
  init_workspace_profile();
@@ -74210,6 +74845,11 @@ var init_remote_customer_tools = __esm(() => {
74210
74845
  });
74211
74846
 
74212
74847
  // src/mcp/server.ts
74848
+ var exports_server = {};
74849
+ __export(exports_server, {
74850
+ server: () => server,
74851
+ buildServer: () => buildServer
74852
+ });
74213
74853
  function buildServer() {
74214
74854
  const server = new McpServer({
74215
74855
  name: "skills",
@@ -74236,371 +74876,10 @@ var init_server3 = __esm(() => {
74236
74876
  server = buildServer();
74237
74877
  });
74238
74878
 
74239
- // ../../node_modules/.bun/@hono+node-server@1.19.17+2145b681a064c8e9/node_modules/@hono/node-server/dist/index.mjs
74240
- import { Readable } from "stream";
74241
- import crypto2 from "crypto";
74242
- var GlobalRequest, Request, newHeadersFromIncoming = (incoming) => {
74243
- const headerRecord = [];
74244
- const rawHeaders = incoming.rawHeaders;
74245
- for (let i = 0;i < rawHeaders.length; i += 2) {
74246
- const { [i]: key, [i + 1]: value } = rawHeaders;
74247
- if (key.charCodeAt(0) !== 58) {
74248
- headerRecord.push([key, value]);
74249
- }
74250
- }
74251
- return new Headers(headerRecord);
74252
- }, wrapBodyStream, newRequestFromIncoming = (method2, url, headers, incoming, abortController) => {
74253
- const init = {
74254
- method: method2,
74255
- headers,
74256
- signal: abortController.signal
74257
- };
74258
- if (method2 === "TRACE") {
74259
- init.method = "GET";
74260
- const req = new Request(url, init);
74261
- Object.defineProperty(req, "method", {
74262
- get() {
74263
- return "TRACE";
74264
- }
74265
- });
74266
- return req;
74267
- }
74268
- if (!(method2 === "GET" || method2 === "HEAD")) {
74269
- if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) {
74270
- init.body = new ReadableStream({
74271
- start(controller) {
74272
- controller.enqueue(incoming.rawBody);
74273
- controller.close();
74274
- }
74275
- });
74276
- } else if (incoming[wrapBodyStream]) {
74277
- let reader;
74278
- init.body = new ReadableStream({
74279
- async pull(controller) {
74280
- try {
74281
- reader ||= Readable.toWeb(incoming).getReader();
74282
- const { done, value } = await reader.read();
74283
- if (done) {
74284
- controller.close();
74285
- } else {
74286
- controller.enqueue(value);
74287
- }
74288
- } catch (error2) {
74289
- controller.error(error2);
74290
- }
74291
- }
74292
- });
74293
- } else {
74294
- init.body = Readable.toWeb(incoming);
74295
- }
74296
- }
74297
- return new Request(url, init);
74298
- }, getRequestCache, requestCache, incomingKey, urlKey, headersKey, abortControllerKey, getAbortController, requestPrototype, responseCache, getResponseCache, cacheKey, GlobalResponse, Response2, outgoingEnded, incomingDraining, MAX_DRAIN_BYTES;
74299
- var init_dist = __esm(() => {
74300
- GlobalRequest = global.Request;
74301
- Request = class extends GlobalRequest {
74302
- constructor(input, options) {
74303
- if (typeof input === "object" && getRequestCache in input) {
74304
- input = input[getRequestCache]();
74305
- }
74306
- if (typeof options?.body?.getReader !== "undefined") {
74307
- options.duplex ??= "half";
74308
- }
74309
- super(input, options);
74310
- }
74311
- };
74312
- wrapBodyStream = Symbol("wrapBodyStream");
74313
- getRequestCache = Symbol("getRequestCache");
74314
- requestCache = Symbol("requestCache");
74315
- incomingKey = Symbol("incomingKey");
74316
- urlKey = Symbol("urlKey");
74317
- headersKey = Symbol("headersKey");
74318
- abortControllerKey = Symbol("abortControllerKey");
74319
- getAbortController = Symbol("getAbortController");
74320
- requestPrototype = {
74321
- get method() {
74322
- return this[incomingKey].method || "GET";
74323
- },
74324
- get url() {
74325
- return this[urlKey];
74326
- },
74327
- get headers() {
74328
- return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);
74329
- },
74330
- [getAbortController]() {
74331
- this[getRequestCache]();
74332
- return this[abortControllerKey];
74333
- },
74334
- [getRequestCache]() {
74335
- this[abortControllerKey] ||= new AbortController;
74336
- return this[requestCache] ||= newRequestFromIncoming(this.method, this[urlKey], this.headers, this[incomingKey], this[abortControllerKey]);
74337
- }
74338
- };
74339
- [
74340
- "body",
74341
- "bodyUsed",
74342
- "cache",
74343
- "credentials",
74344
- "destination",
74345
- "integrity",
74346
- "mode",
74347
- "redirect",
74348
- "referrer",
74349
- "referrerPolicy",
74350
- "signal",
74351
- "keepalive"
74352
- ].forEach((k) => {
74353
- Object.defineProperty(requestPrototype, k, {
74354
- get() {
74355
- return this[getRequestCache]()[k];
74356
- }
74357
- });
74358
- });
74359
- ["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
74360
- Object.defineProperty(requestPrototype, k, {
74361
- value: function() {
74362
- return this[getRequestCache]()[k]();
74363
- }
74364
- });
74365
- });
74366
- Object.defineProperty(requestPrototype, Symbol.for("nodejs.util.inspect.custom"), {
74367
- value: function(depth, options, inspectFn) {
74368
- const props = {
74369
- method: this.method,
74370
- url: this.url,
74371
- headers: this.headers,
74372
- nativeRequest: this[requestCache]
74373
- };
74374
- return `Request (lightweight) ${inspectFn(props, { ...options, depth: depth == null ? null : depth - 1 })}`;
74375
- }
74376
- });
74377
- Object.setPrototypeOf(requestPrototype, Request.prototype);
74378
- responseCache = Symbol("responseCache");
74379
- getResponseCache = Symbol("getResponseCache");
74380
- cacheKey = Symbol("cache");
74381
- GlobalResponse = global.Response;
74382
- Response2 = class _Response {
74383
- #body;
74384
- #init;
74385
- [getResponseCache]() {
74386
- delete this[cacheKey];
74387
- return this[responseCache] ||= new GlobalResponse(this.#body, this.#init);
74388
- }
74389
- constructor(body, init) {
74390
- let headers;
74391
- this.#body = body;
74392
- if (init instanceof _Response) {
74393
- const cachedGlobalResponse = init[responseCache];
74394
- if (cachedGlobalResponse) {
74395
- this.#init = cachedGlobalResponse;
74396
- this[getResponseCache]();
74397
- return;
74398
- } else {
74399
- this.#init = init.#init;
74400
- headers = new Headers(init.#init.headers);
74401
- }
74402
- } else {
74403
- this.#init = init;
74404
- }
74405
- if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) {
74406
- this[cacheKey] = [init?.status || 200, body, headers || init?.headers];
74407
- }
74408
- }
74409
- get headers() {
74410
- const cache3 = this[cacheKey];
74411
- if (cache3) {
74412
- if (!(cache3[2] instanceof Headers)) {
74413
- cache3[2] = new Headers(cache3[2] || { "content-type": "text/plain; charset=UTF-8" });
74414
- }
74415
- return cache3[2];
74416
- }
74417
- return this[getResponseCache]().headers;
74418
- }
74419
- get status() {
74420
- return this[cacheKey]?.[0] ?? this[getResponseCache]().status;
74421
- }
74422
- get ok() {
74423
- const status = this.status;
74424
- return status >= 200 && status < 300;
74425
- }
74426
- };
74427
- ["body", "bodyUsed", "redirected", "statusText", "trailers", "type", "url"].forEach((k) => {
74428
- Object.defineProperty(Response2.prototype, k, {
74429
- get() {
74430
- return this[getResponseCache]()[k];
74431
- }
74432
- });
74433
- });
74434
- ["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
74435
- Object.defineProperty(Response2.prototype, k, {
74436
- value: function() {
74437
- return this[getResponseCache]()[k]();
74438
- }
74439
- });
74440
- });
74441
- Object.defineProperty(Response2.prototype, Symbol.for("nodejs.util.inspect.custom"), {
74442
- value: function(depth, options, inspectFn) {
74443
- const props = {
74444
- status: this.status,
74445
- headers: this.headers,
74446
- ok: this.ok,
74447
- nativeResponse: this[responseCache]
74448
- };
74449
- return `Response (lightweight) ${inspectFn(props, { ...options, depth: depth == null ? null : depth - 1 })}`;
74450
- }
74451
- });
74452
- Object.setPrototypeOf(Response2, GlobalResponse);
74453
- Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype);
74454
- if (typeof global.crypto === "undefined") {
74455
- global.crypto = crypto2;
74456
- }
74457
- outgoingEnded = Symbol("outgoingEnded");
74458
- incomingDraining = Symbol("incomingDraining");
74459
- MAX_DRAIN_BYTES = 64 * 1024 * 1024;
74460
- });
74461
-
74462
- // ../../node_modules/.bun/content-type@1.0.5/node_modules/content-type/index.js
74463
- var require_content_type = __commonJS((exports) => {
74464
- /*!
74465
- * content-type
74466
- * Copyright(c) 2015 Douglas Christopher Wilson
74467
- * MIT Licensed
74468
- */
74469
- var PARAM_REGEXP = /; *([!#$%&'*+.^_`|~0-9A-Za-z-]+) *= *("(?:[\u000b\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u000b\u0020-\u00ff])*"|[!#$%&'*+.^_`|~0-9A-Za-z-]+) */g;
74470
- var TEXT_REGEXP = /^[\u000b\u0020-\u007e\u0080-\u00ff]+$/;
74471
- var TOKEN_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
74472
- var QESC_REGEXP = /\\([\u000b\u0020-\u00ff])/g;
74473
- var QUOTE_REGEXP = /([\\"])/g;
74474
- var TYPE_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\/[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
74475
- exports.format = format;
74476
- exports.parse = parse6;
74477
- function format(obj) {
74478
- if (!obj || typeof obj !== "object") {
74479
- throw new TypeError("argument obj is required");
74480
- }
74481
- var parameters = obj.parameters;
74482
- var type = obj.type;
74483
- if (!type || !TYPE_REGEXP.test(type)) {
74484
- throw new TypeError("invalid type");
74485
- }
74486
- var string5 = type;
74487
- if (parameters && typeof parameters === "object") {
74488
- var param;
74489
- var params = Object.keys(parameters).sort();
74490
- for (var i = 0;i < params.length; i++) {
74491
- param = params[i];
74492
- if (!TOKEN_REGEXP.test(param)) {
74493
- throw new TypeError("invalid parameter name");
74494
- }
74495
- string5 += "; " + param + "=" + qstring(parameters[param]);
74496
- }
74497
- }
74498
- return string5;
74499
- }
74500
- function parse6(string5) {
74501
- if (!string5) {
74502
- throw new TypeError("argument string is required");
74503
- }
74504
- var header = typeof string5 === "object" ? getcontenttype(string5) : string5;
74505
- if (typeof header !== "string") {
74506
- throw new TypeError("argument string is required to be a string");
74507
- }
74508
- var index = header.indexOf(";");
74509
- var type = index !== -1 ? header.slice(0, index).trim() : header.trim();
74510
- if (!TYPE_REGEXP.test(type)) {
74511
- throw new TypeError("invalid media type");
74512
- }
74513
- var obj = new ContentType(type.toLowerCase());
74514
- if (index !== -1) {
74515
- var key;
74516
- var match;
74517
- var value;
74518
- PARAM_REGEXP.lastIndex = index;
74519
- while (match = PARAM_REGEXP.exec(header)) {
74520
- if (match.index !== index) {
74521
- throw new TypeError("invalid parameter format");
74522
- }
74523
- index += match[0].length;
74524
- key = match[1].toLowerCase();
74525
- value = match[2];
74526
- if (value.charCodeAt(0) === 34) {
74527
- value = value.slice(1, -1);
74528
- if (value.indexOf("\\") !== -1) {
74529
- value = value.replace(QESC_REGEXP, "$1");
74530
- }
74531
- }
74532
- obj.parameters[key] = value;
74533
- }
74534
- if (index !== header.length) {
74535
- throw new TypeError("invalid parameter format");
74536
- }
74537
- }
74538
- return obj;
74539
- }
74540
- function getcontenttype(obj) {
74541
- var header;
74542
- if (typeof obj.getHeader === "function") {
74543
- header = obj.getHeader("content-type");
74544
- } else if (typeof obj.headers === "object") {
74545
- header = obj.headers && obj.headers["content-type"];
74546
- }
74547
- if (typeof header !== "string") {
74548
- throw new TypeError("content-type header is missing from object");
74549
- }
74550
- return header;
74551
- }
74552
- function qstring(val) {
74553
- var str2 = String(val);
74554
- if (TOKEN_REGEXP.test(str2)) {
74555
- return str2;
74556
- }
74557
- if (str2.length > 0 && !TEXT_REGEXP.test(str2)) {
74558
- throw new TypeError("invalid parameter value");
74559
- }
74560
- return '"' + str2.replace(QUOTE_REGEXP, "\\$1") + '"';
74561
- }
74562
- function ContentType(type) {
74563
- this.parameters = Object.create(null);
74564
- this.type = type;
74565
- }
74566
- });
74567
-
74568
- // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/mediaType.js
74569
- var import_content_type;
74570
- var init_mediaType = __esm(() => {
74571
- import_content_type = __toESM(require_content_type(), 1);
74572
- });
74573
-
74574
- // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/server/sseKeepAlive.js
74575
- var MAX_TIMER_DELAY_MS;
74576
- var init_sseKeepAlive = __esm(() => {
74577
- MAX_TIMER_DELAY_MS = 2 ** 31 - 1;
74578
- });
74579
-
74580
- // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/server/webStandardStreamableHttp.js
74581
- var init_webStandardStreamableHttp = __esm(() => {
74582
- init_mediaType();
74583
- init_sseKeepAlive();
74584
- init_types2();
74585
- });
74586
-
74587
- // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0+2b91fc17bf64bdfd/node_modules/@modelcontextprotocol/sdk/dist/esm/server/streamableHttp.js
74588
- var init_streamableHttp = __esm(() => {
74589
- init_dist();
74590
- init_webStandardStreamableHttp();
74591
- });
74592
-
74593
- // src/mcp/http.ts
74594
- var init_http = __esm(() => {
74595
- init_streamableHttp();
74596
- init_server3();
74597
- });
74598
-
74599
74879
  // src/mcp/index.ts
74600
74880
  var exports_mcp = {};
74601
74881
  __export(exports_mcp, {
74602
74882
  startMcpStdio: () => startMcpStdio,
74603
- buildServer: () => buildServer,
74604
74883
  assertSkillsMcpConfigured: () => assertSkillsMcpConfigured
74605
74884
  });
74606
74885
  function printHelp() {
@@ -74611,6 +74890,7 @@ MCP server for ${package_default.name}
74611
74890
  Options:
74612
74891
  -V, --version output the version number
74613
74892
  -h, --help display help for command
74893
+ --invitation-recovery --stdio expose only anonymous invitation recovery tools
74614
74894
  --stdio run newline-delimited JSON-RPC for agent hosts
74615
74895
  --http run Streamable HTTP transport on 127.0.0.1 (default; port 8836)
74616
74896
  --port <n> HTTP port (--http or MCP_HTTP=1)`);
@@ -74627,23 +74907,21 @@ function assertSkillsMcpConfigured(env3 = process.env) {
74627
74907
  }
74628
74908
  async function startMcpStdio() {
74629
74909
  assertSkillsMcpConfigured();
74630
- const server2 = buildServer();
74910
+ const { buildServer: buildServer2 } = await Promise.resolve().then(() => (init_server3(), exports_server));
74911
+ const server2 = buildServer2();
74631
74912
  await server2.connect(new StdioServerTransport);
74632
74913
  }
74633
74914
  var args;
74634
74915
  var init_mcp2 = __esm(() => {
74635
74916
  init_stdio2();
74636
74917
  init_package();
74637
- init_server3();
74638
- init_http();
74639
74918
  init_fleet_credentials();
74640
- init_server3();
74641
74919
  args = process.argv.slice(2);
74642
- if (args.includes("--help") || args.includes("-h")) {
74920
+ if (!args.some((value) => value.startsWith("--invitation-recovery")) && (args.includes("--help") || args.includes("-h"))) {
74643
74921
  printHelp();
74644
74922
  process.exit(0);
74645
74923
  }
74646
- if (args.includes("--version") || args.includes("-V")) {
74924
+ if (!args.some((value) => value.startsWith("--invitation-recovery")) && (args.includes("--version") || args.includes("-V"))) {
74647
74925
  console.log(package_default.version);
74648
74926
  process.exit(0);
74649
74927
  }
@@ -77515,10 +77793,10 @@ async function handleRegistrySync(options) {
77515
77793
  await writeJson2(artifact, 2);
77516
77794
  return;
77517
77795
  }
77518
- const invalid2 = artifact.summary.invalidSkillCount ?? "not checked";
77796
+ const invalid3 = artifact.summary.invalidSkillCount ?? "not checked";
77519
77797
  console.log(source_default.green(`Registry sync artifact written to ${options.output}`));
77520
77798
  console.log(source_default.dim(` Skills: ${artifact.summary.skillCount}`));
77521
- console.log(source_default.dim(` Invalid: ${invalid2}`));
77799
+ console.log(source_default.dim(` Invalid: ${invalid3}`));
77522
77800
  }
77523
77801
  function registerPull(parent) {
77524
77802
  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) => {
@@ -77738,21 +78016,21 @@ async function readPublishRevision(client, slug) {
77738
78016
  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."]);
77739
78017
  }
77740
78018
  const body = lookup.body;
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;
78019
+ const record7 = body !== null && typeof body === "object" && !Array.isArray(body) ? body : undefined;
78020
+ const nestedError = record7?.error;
78021
+ const code = typeof record7?.code === "string" ? record7.code : nestedError !== null && typeof nestedError === "object" && !Array.isArray(nestedError) ? nestedError.code : undefined;
77744
78022
  if (lookup.status === 404 && code === "SKILL_NOT_FOUND")
77745
78023
  return;
77746
78024
  if (lookup.status < 200 || lookup.status >= 300) {
77747
78025
  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."]);
77748
78026
  }
77749
- const revision = record5?.revisionId;
77750
- if (record5?.publicationState === "catalogue-only") {
77751
- if (record5.name === slug && (record5.slug === undefined || record5.slug === slug) && revision === null)
78027
+ const revision = record7?.revisionId;
78028
+ if (record7?.publicationState === "catalogue-only") {
78029
+ if (record7.name === slug && (record7.slug === undefined || record7.slug === slug) && revision === null)
77752
78030
  return;
77753
78031
  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."]);
77754
78032
  }
77755
- if (record5?.slug !== slug || typeof revision !== "string" || revision.length === 0 || revision !== revision.trim() || !/^[\x21-\x7e]+$/.test(revision)) {
78033
+ if (record7?.slug !== slug || typeof revision !== "string" || revision.length === 0 || revision !== revision.trim() || !/^[\x21-\x7e]+$/.test(revision)) {
77756
78034
  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."]);
77757
78035
  }
77758
78036
  return revision;
@@ -78126,22 +78404,22 @@ function authIdentityPayload(authSource, live, cached2, offline = false) {
78126
78404
  const data = recordField(root.data);
78127
78405
  const user = recordField(root.user) ?? recordField(data?.user);
78128
78406
  const organization2 = recordField(root.organization) ?? recordField(root.org) ?? recordField(data?.organization);
78129
- const email2 = stringField2(user?.email) ?? cached2?.email;
78407
+ const email3 = stringField2(user?.email) ?? cached2?.email;
78130
78408
  const orgSlug = stringField2(organization2?.slug) ?? cached2?.orgSlug;
78131
78409
  const orgName = stringField2(organization2?.name);
78132
78410
  const userId = stringField2(user?.id) ?? cached2?.userId;
78133
78411
  const orgId = stringField2(organization2?.id) ?? cached2?.orgId;
78134
- const role2 = stringField2(user?.role);
78412
+ const role3 = stringField2(user?.role);
78135
78413
  return {
78136
78414
  status: "authenticated",
78137
78415
  authSource,
78138
78416
  ...offline ? { offline: true } : {},
78139
- ...email2 ? { email: email2 } : {},
78417
+ ...email3 ? { email: email3 } : {},
78140
78418
  ...orgSlug ? { organization: orgSlug } : {},
78141
78419
  ...orgName ? { organizationName: orgName } : {},
78142
78420
  ...userId ? { userId } : {},
78143
78421
  ...orgId ? { orgId } : {},
78144
- ...role2 ? { role: role2 } : {}
78422
+ ...role3 ? { role: role3 } : {}
78145
78423
  };
78146
78424
  }
78147
78425
  function printWhoami(payload) {
@@ -78218,7 +78496,7 @@ function printLoginSuccess(loginResult, json) {
78218
78496
  console.log(source_default.dim(` API key saved to ${getAuthFilePath()}`));
78219
78497
  }
78220
78498
  }
78221
- async function doLogin(email2, code, json) {
78499
+ async function doLogin(email3, code, json) {
78222
78500
  const env3 = { ...process.env };
78223
78501
  let origin;
78224
78502
  try {
@@ -78227,7 +78505,7 @@ async function doLogin(email2, code, json) {
78227
78505
  writeCommandError(error2, "Configure a Skills API before signing in", json);
78228
78506
  return;
78229
78507
  }
78230
- if (!email2 || !email2.includes("@")) {
78508
+ if (!email3 || !email3.includes("@")) {
78231
78509
  writeCommandError(new Error("Invalid email"), "Invalid email", json);
78232
78510
  process.exitCode = 1;
78233
78511
  return;
@@ -78239,7 +78517,7 @@ async function doLogin(email2, code, json) {
78239
78517
  try {
78240
78518
  sendRes = await apiRequest("/api/auth/login", {
78241
78519
  method: "POST",
78242
- body: JSON.stringify({ email: email2 })
78520
+ body: JSON.stringify({ email: email3 })
78243
78521
  }, origin);
78244
78522
  } catch (err) {
78245
78523
  writeCommandError(err, "Failed to request login code", json);
@@ -78250,9 +78528,9 @@ async function doLogin(email2, code, json) {
78250
78528
  return;
78251
78529
  }
78252
78530
  if (!json)
78253
- console.log(source_default.green("\u2713 Code sent to " + email2));
78531
+ console.log(source_default.green("\u2713 Code sent to " + email3));
78254
78532
  if (json || !isTTY) {
78255
- console.log(JSON.stringify({ status: "code_sent", email: email2, message: "Check email for 6-digit code, then run: skills auth login --email " + email2 + " --code <CODE>" }));
78533
+ console.log(JSON.stringify({ status: "code_sent", email: email3, message: "Check email for 6-digit code, then run: skills auth login --email " + email3 + " --code <CODE>" }));
78256
78534
  return;
78257
78535
  }
78258
78536
  const answer = await prompt(source_default.bold("Code: "));
@@ -78264,7 +78542,7 @@ async function doLogin(email2, code, json) {
78264
78542
  try {
78265
78543
  verifyRes = await apiRequest("/api/auth/verify", {
78266
78544
  method: "POST",
78267
- body: JSON.stringify({ email: email2, code })
78545
+ body: JSON.stringify({ email: email3, code })
78268
78546
  }, origin);
78269
78547
  } catch (err) {
78270
78548
  writeCommandError(err, "Failed to verify login code", json);
@@ -78311,13 +78589,13 @@ async function doApiKeyLogin(apiKey, json) {
78311
78589
  return;
78312
78590
  }
78313
78591
  const identity2 = authIdentityPayload("stored", whoami);
78314
- const email2 = stringField2(identity2.email);
78592
+ const email3 = stringField2(identity2.email);
78315
78593
  const orgId = stringField2(identity2.orgId);
78316
78594
  const orgSlug = stringField2(identity2.organization);
78317
78595
  const userId = stringField2(identity2.userId);
78318
78596
  saveAuthConfig({
78319
78597
  apiKey: trimmed,
78320
- ...email2 ? { email: email2 } : {},
78598
+ ...email3 ? { email: email3 } : {},
78321
78599
  ...orgId ? { orgId } : {},
78322
78600
  ...orgSlug ? { orgSlug } : {},
78323
78601
  ...userId ? { userId } : {}
@@ -78487,8 +78765,8 @@ function registerAuth(parent) {
78487
78765
  await doDeviceLogin(options);
78488
78766
  return;
78489
78767
  }
78490
- let email2 = options.email;
78491
- if (!email2 && isTTY && !options.json) {
78768
+ let email3 = options.email;
78769
+ if (!email3 && isTTY && !options.json) {
78492
78770
  const existing = authForPrompt();
78493
78771
  if (existing) {
78494
78772
  console.log(source_default.dim(`Already signed in as ${existing.email}`));
@@ -78499,17 +78777,17 @@ function registerAuth(parent) {
78499
78777
  const answer = await prompt(source_default.bold("Email: "));
78500
78778
  if (answer === null)
78501
78779
  return;
78502
- email2 = answer;
78780
+ email3 = answer;
78503
78781
  }
78504
- if (!email2) {
78782
+ if (!email3) {
78505
78783
  writeCommandError(new Error("Email required. Use: skills auth login --email you@example.com"), "Email required", options.json);
78506
78784
  return;
78507
78785
  }
78508
- await doLogin(email2, options.code, options.json);
78786
+ await doLogin(email3, options.code, options.json);
78509
78787
  });
78510
78788
  auth.command("signup").description("Create or sign in with your email (passwordless)").option("--email <email>", "Email address (non-interactive)").option("--code <code>", "Verification code (non-interactive)").option("--json", "Output result as JSON without prompting", false).action(async (options) => {
78511
- let email2 = options.email;
78512
- if (!email2 && isTTY && !options.json) {
78789
+ let email3 = options.email;
78790
+ if (!email3 && isTTY && !options.json) {
78513
78791
  const existing = authForPrompt();
78514
78792
  if (existing) {
78515
78793
  console.log(source_default.dim(`Already signed in as ${existing.email}`));
@@ -78520,9 +78798,9 @@ function registerAuth(parent) {
78520
78798
  const answer = await prompt(source_default.bold("Email: "));
78521
78799
  if (answer === null)
78522
78800
  return;
78523
- email2 = answer;
78801
+ email3 = answer;
78524
78802
  }
78525
- if (!email2) {
78803
+ if (!email3) {
78526
78804
  const error2 = "Email required. Use: skills auth signup --email you@example.com";
78527
78805
  if (options.json)
78528
78806
  console.log(JSON.stringify({ error: error2 }));
@@ -78531,7 +78809,7 @@ function registerAuth(parent) {
78531
78809
  process.exitCode = 1;
78532
78810
  return;
78533
78811
  }
78534
- await doLogin(email2, options.code, options.json);
78812
+ await doLogin(email3, options.code, options.json);
78535
78813
  });
78536
78814
  auth.command("logout").description("Remove this profile's stored credentials; injected keys remain configured").option("--json", "Output as JSON", false).action((options) => {
78537
78815
  const { stillResolves } = clearAuthConfig();
@@ -78597,6 +78875,285 @@ var init_auth = __esm(() => {
78597
78875
  CONFIG_HINT_STATUSES = new Set([401, 403, 404, 405, 501]);
78598
78876
  });
78599
78877
 
78878
+ // src/lib/invitation-recovery-target.ts
78879
+ function prepareInvitationRecoveryTarget(source = process.env) {
78880
+ const env3 = { ...source }, names = ["HASNA_SKILLS_API_URL", "SKILLS_API_URL"];
78881
+ const urls = names.map((name) => env3[name]?.trim()).filter((value) => !!value);
78882
+ if (!urls.length)
78883
+ throw new InvitationEmailInputError;
78884
+ let origin;
78885
+ try {
78886
+ const normalized = urls.map(normalizeSkillsApiOrigin);
78887
+ if (normalized.some((value) => value !== normalized[0]))
78888
+ throw new InvitationEmailInputError;
78889
+ origin = normalized[0];
78890
+ } catch {
78891
+ throw new InvitationEmailInputError;
78892
+ }
78893
+ const unchangedFiles = captureSkillsCredentialFiles(skillsProfileCredentialFiles(env3));
78894
+ return { origin, unchanged() {
78895
+ unchangedFiles();
78896
+ if ([...names, "HASNA_PROFILE", "HASNA_HOME", "HOME"].some((name) => source[name] !== env3[name]))
78897
+ throw new InvitationEmailInputError;
78898
+ } };
78899
+ }
78900
+ var init_invitation_recovery_target = __esm(() => {
78901
+ init_fleet_credentials();
78902
+ init_instance_credentials();
78903
+ init_remote_invitation_recovery();
78904
+ });
78905
+
78906
+ // src/cli/commands/invitation-verification.ts
78907
+ import { emitKeypressEvents as emitKeypressEvents2 } from "readline";
78908
+ async function readInvitationSecrets() {
78909
+ if (process.stdin.isTTY)
78910
+ throw new NameInputError("Pipe the six-digit code and invitation token on two separate lines with --secrets-stdin.");
78911
+ let text2 = "";
78912
+ for await (const chunk2 of process.stdin) {
78913
+ text2 += chunk2.toString();
78914
+ if (text2.length > 64)
78915
+ throw new NameInputError("Supply only the code and invitation token on two separate lines.");
78916
+ }
78917
+ const matched = /^(\d{6})\r?\n([A-Za-z0-9_-]{43})(?:\r?\n)?$/.exec(text2);
78918
+ if (!matched)
78919
+ throw new NameInputError("Supply only the code and invitation token on two separate lines.");
78920
+ return { code: matched[1], token: matched[2] };
78921
+ }
78922
+ function promptInvitationToken() {
78923
+ return promptInvitationProof("token");
78924
+ }
78925
+ function promptInvitationRecoveryCode() {
78926
+ return promptInvitationProof("code");
78927
+ }
78928
+ function promptInvitationProof(kind) {
78929
+ const length = kind === "token" ? 43 : 6;
78930
+ const label = kind === "token" ? "invitation token" : "recovery code";
78931
+ const character = kind === "token" ? /^[A-Za-z0-9_-]$/ : /^\d$/;
78932
+ const { stdin, stderr: output } = process, wasRaw = stdin.isRaw, wasFlowing = stdin.readableFlowing;
78933
+ return new Promise((resolve5) => {
78934
+ let value = "", settled = false, overflow = false;
78935
+ const finish = (answer) => {
78936
+ if (settled)
78937
+ return;
78938
+ settled = true;
78939
+ clearTimeout(timer);
78940
+ stdin.off("keypress", keypress);
78941
+ stdin.off("end", cancel);
78942
+ process.off("SIGINT", cancel);
78943
+ stdin.setRawMode(wasRaw);
78944
+ if (wasFlowing !== true)
78945
+ stdin.pause();
78946
+ output.write(`
78947
+ `);
78948
+ if (answer === null)
78949
+ process.exitCode = 130;
78950
+ resolve5(answer);
78951
+ };
78952
+ const cancel = () => finish(null);
78953
+ const keypress = (text2, key) => {
78954
+ if (key.ctrl && ["c", "d"].includes(key.name ?? "") || key.name === "escape")
78955
+ return cancel();
78956
+ if (key.name === "return" || key.name === "enter") {
78957
+ if (overflow) {
78958
+ value = "";
78959
+ overflow = false;
78960
+ output.write(`
78961
+ Enter exactly ${length} ${label} characters: `);
78962
+ return;
78963
+ }
78964
+ if (value.length === length)
78965
+ return finish(value);
78966
+ output.write(`
78967
+ Enter the complete ${label}: `);
78968
+ value = "";
78969
+ return;
78970
+ }
78971
+ if (overflow)
78972
+ return;
78973
+ if (key.name === "backspace") {
78974
+ if (value) {
78975
+ value = value.slice(0, -1);
78976
+ output.write("\b \b");
78977
+ }
78978
+ } else if (character.test(text2)) {
78979
+ if (value.length === length) {
78980
+ overflow = true;
78981
+ output.write(`
78982
+ The ${label} is too long. Press Enter to start again.`);
78983
+ } else {
78984
+ value += text2;
78985
+ output.write("*");
78986
+ }
78987
+ } else if (text2 && !key.ctrl && !key.meta) {
78988
+ overflow = true;
78989
+ output.write(`
78990
+ The ${label} contains invalid characters. Press Enter to start again.`);
78991
+ }
78992
+ };
78993
+ const timer = setTimeout(cancel, 5 * 60 * 1000);
78994
+ emitKeypressEvents2(stdin);
78995
+ stdin.setRawMode(true);
78996
+ stdin.on("keypress", keypress);
78997
+ stdin.once("end", cancel);
78998
+ process.once("SIGINT", cancel);
78999
+ output.write(kind === "token" ? "Enter the invitation token from your email: " : "Enter the six-digit recovery code from your email: ");
79000
+ stdin.resume();
79001
+ });
79002
+ }
79003
+ var init_invitation_verification = __esm(() => {
79004
+ init_customer_verification();
79005
+ });
79006
+
79007
+ // src/cli/commands/invitation-recovery.ts
79008
+ async function readToken() {
79009
+ if (process.stdin.isTTY)
79010
+ throw new InvitationEmailInputError;
79011
+ let value = "";
79012
+ for await (const chunk2 of process.stdin) {
79013
+ value += chunk2.toString();
79014
+ if (value.length > 45)
79015
+ throw new InvitationEmailInputError;
79016
+ }
79017
+ const matched = /^([A-Za-z0-9_-]{43})(?:\r?\n)?$/.exec(value);
79018
+ if (!matched)
79019
+ throw new InvitationEmailInputError;
79020
+ return matched[1];
79021
+ }
79022
+ function registerInvitationRecoveryCommands(invitations) {
79023
+ for (const action of ["challenge", "accept"]) {
79024
+ const command = invitations.createCommand(`email-${action}`).argument("<invitation-id>").allowExcessArguments(false).enablePositionalOptions().configureOutput({ writeErr: () => {
79025
+ process.stderr.write(`Invitation recovery arguments were refused. Supply proof only through masked input or the documented stdin flags.
79026
+ `);
79027
+ } }).description(action === "challenge" ? "Request an eligibility-neutral recovery code; does not confirm delivery" : "Accept with invitation proof; requires ordinary sign-in afterward").requiredOption("--challenge-id <id>", "Your retained challenge UUID; generate it before the request and keep the same exact context").requiredOption("--confirm", "Confirm this exact invitation recovery action").option(action === "challenge" ? "--token-stdin" : "--secrets-stdin", action === "challenge" ? "Read the invitation token from one stdin line" : "Read the recovery code then invitation token from two stdin lines").option("--json", "Output only validated results").action(async (invitationId2, options) => {
79028
+ try {
79029
+ if (options.confirm !== true)
79030
+ throw new InvitationEmailInputError;
79031
+ const ids = invitationEmailIds(invitationId2, options.challengeId), target = prepareInvitationRecoveryTarget();
79032
+ const piped = action === "challenge" ? options.tokenStdin : options.secretsStdin;
79033
+ if (!piped && (options.json || !process.stdin.isTTY || !process.stderr.isTTY))
79034
+ throw new InvitationEmailInputError;
79035
+ let token, code = null;
79036
+ if (piped && action === "accept")
79037
+ ({ token, code } = await readInvitationSecrets());
79038
+ else if (piped)
79039
+ token = await readToken();
79040
+ else {
79041
+ token = await promptInvitationToken();
79042
+ if (token === null)
79043
+ return;
79044
+ if (action === "accept") {
79045
+ code = await promptInvitationRecoveryCode();
79046
+ if (code === null)
79047
+ return;
79048
+ }
79049
+ }
79050
+ target.unchanged();
79051
+ const client = new RemoteSkillsAuthClient(target.origin);
79052
+ const result2 = action === "challenge" ? await client.requestInvitationEmailChallenge({ ...ids, token, confirm: true }) : await client.acceptInvitationEmailChallenge({ ...ids, token, code, confirm: true });
79053
+ console.log(JSON.stringify(result2, null, options.json ? undefined : 2));
79054
+ } catch (error2) {
79055
+ const result2 = invitationEmailCustomerError(error2);
79056
+ if (options.json)
79057
+ console.log(JSON.stringify(result2));
79058
+ else
79059
+ console.error(result2.error);
79060
+ process.exitCode = 1;
79061
+ }
79062
+ });
79063
+ invitations.addCommand(command);
79064
+ }
79065
+ }
79066
+ var init_invitation_recovery = __esm(() => {
79067
+ init_remote_auth();
79068
+ init_invitation_recovery_target();
79069
+ init_remote_invitation_recovery();
79070
+ init_invitation_verification();
79071
+ });
79072
+
79073
+ // src/cli/commands/workspace-invitations.ts
79074
+ function registerWorkspaceInvitationCommands(workspace) {
79075
+ const invitations = workspace.command("invitations").description("Manage workspace invitations with fresh verification and unchanged saved credentials");
79076
+ registerInvitationRecoveryCommands(invitations);
79077
+ for (const action of ["list", "get", "issue", "resend", "revoke", "accept"]) {
79078
+ const targeted = ["get", "resend", "revoke", "accept"].includes(action), mutation = !["list", "get"].includes(action);
79079
+ const command = invitations.command(action + (targeted ? " <invitation-id>" : "")).allowExcessArguments(false).description(action === "accept" ? "Accept a received invitation; does not switch workspace or create credentials" : `${action} invitations in the exact observed workspace`).requiredOption("--user-id <id>", "Observed account ID from workspace list").requiredOption("--membership-id <id>", "Exact observed current membership; must match any selected profile").requiredOption("--email <email>", "Account email for fresh verification").option("--json", "Output the validated result as JSON");
79080
+ if (mutation)
79081
+ command.requiredOption("--confirm", "Confirm this exact invitation action");
79082
+ if (action === "list")
79083
+ command.option("--after <id>", "Exact nextCursor from the previous page");
79084
+ if (action === "issue")
79085
+ command.requiredOption("--recipient <email>", "Invitation recipient").requiredOption("--role <role>", "owner, admin, member or viewer");
79086
+ if (action === "issue" || action === "resend")
79087
+ command.requiredOption("--idempotency-key <id>", "Your stable request UUID; reuse only with the same original context and parameters");
79088
+ if (action === "resend" || action === "revoke")
79089
+ command.requiredOption("--expected-generation <number>", "Generation you observed before confirming");
79090
+ if (action === "accept")
79091
+ command.option("--secrets-stdin", "Read a fresh six-digit code and invitation token on two separate stdin lines");
79092
+ else
79093
+ command.option("--code-stdin", "Read a previously requested six-digit verification code from stdin");
79094
+ command.action(async (...args2) => {
79095
+ const id = targeted ? String(args2[0]) : undefined, options = args2[targeted ? 1 : 0];
79096
+ try {
79097
+ if (mutation && options.confirm !== true)
79098
+ throw new WorkspaceInvitationInputError;
79099
+ let input = action === "list" ? { ...options.after === undefined ? {} : { after: options.after } } : action === "get" ? { invitationId: id } : action === "issue" ? { email: options.recipient, role: options.role, idempotencyKey: options.idempotencyKey, confirm: true } : action === "resend" ? { invitationId: id, expectedGeneration: Number(options.expectedGeneration), idempotencyKey: options.idempotencyKey, confirm: true } : action === "revoke" ? { invitationId: id, expectedGeneration: Number(options.expectedGeneration), confirm: true } : { invitationId: id, token: "", confirm: true };
79100
+ if (action === "accept")
79101
+ invitationId(id);
79102
+ else
79103
+ input = invitationInput(action, input);
79104
+ const context = invitationProfileContext(options.userId, options.membershipId);
79105
+ if (!options.email.includes("@"))
79106
+ throw new NameInputError("Provide the verified account email.");
79107
+ const stdin = action === "accept" ? options.secretsStdin : options.codeStdin;
79108
+ if (!stdin && (options.json || !process.stdin.isTTY || !process.stderr.isTTY))
79109
+ throw new NameInputError(action === "accept" ? "Use --secrets-stdin with a fresh code and invitation token on two separate lines." : "Use --code-stdin with a fresh verification code.");
79110
+ const target = await prepareProfileWorkspace("Manage invitations").resolve();
79111
+ invitationProfileContext(context.userId, context.membershipId, target.context);
79112
+ const client = new RemoteSkillsAuthClient(target.origin);
79113
+ let code, token = null;
79114
+ if (action === "accept" && stdin)
79115
+ ({ code, token } = await readInvitationSecrets());
79116
+ else {
79117
+ if (action === "accept") {
79118
+ token = await promptInvitationToken();
79119
+ if (token === null)
79120
+ return;
79121
+ }
79122
+ if (stdin)
79123
+ code = await readCode();
79124
+ else {
79125
+ await client.requestCode(options.email);
79126
+ code = await promptCode();
79127
+ }
79128
+ }
79129
+ if (code === null)
79130
+ return;
79131
+ if (action === "accept")
79132
+ input = invitationInput("accept", { invitationId: id, token, confirm: true });
79133
+ target.unchanged();
79134
+ const result2 = await invokeFreshInvitation(client, options.email, code, context, action, input);
79135
+ console.log(JSON.stringify(result2, null, options.json ? undefined : 2));
79136
+ } catch (error2) {
79137
+ const result2 = error2 instanceof NameInputError ? { code: "INVITATION_INPUT_INVALID", error: error2.message } : invitationCustomerError(error2);
79138
+ if (options.json)
79139
+ console.log(JSON.stringify(result2));
79140
+ else
79141
+ console.error(result2.error);
79142
+ process.exitCode = 1;
79143
+ }
79144
+ });
79145
+ }
79146
+ }
79147
+ var init_workspace_invitations = __esm(() => {
79148
+ init_invitation_recovery();
79149
+ init_workspace_profile();
79150
+ init_remote_auth();
79151
+ init_invitation_customer_action();
79152
+ init_remote_invitations();
79153
+ init_customer_verification();
79154
+ init_invitation_verification();
79155
+ });
79156
+
78600
79157
  // src/cli/commands/workspace-leave.ts
78601
79158
  function registerWorkspaceLeaveCommand(workspace) {
78602
79159
  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) => {
@@ -78769,6 +79326,7 @@ function registerCustomerProfileCommands(program2) {
78769
79326
  registerWorkspaceMembersCommand(workspace);
78770
79327
  registerWorkspaceMemberMutationCommands(workspace);
78771
79328
  registerWorkspaceLeaveCommand(workspace);
79329
+ registerWorkspaceInvitationCommands(workspace);
78772
79330
  const commands = [
78773
79331
  { kind: "account", command: account.command("update") },
78774
79332
  { kind: "workspace", command: workspace.command("update") }
@@ -78811,6 +79369,7 @@ function registerCustomerProfileCommands(program2) {
78811
79369
  }
78812
79370
  }
78813
79371
  var init_customer_profile = __esm(() => {
79372
+ init_workspace_invitations();
78814
79373
  init_workspace_profile();
78815
79374
  init_workspace_selection();
78816
79375
  init_remote_auth();
@@ -79012,14 +79571,14 @@ function resolveCorpusRootReadOnly(options) {
79012
79571
  }
79013
79572
  return { root: join39(appDir, INSTALLED_SKILLS_DIRNAME), migrationPending: true };
79014
79573
  }
79015
- function remoteRowToSkill(record5) {
79016
- const slug = typeof record5.slug === "string" ? record5.slug : typeof record5.name === "string" ? record5.name : undefined;
79574
+ function remoteRowToSkill(record7) {
79575
+ const slug = typeof record7.slug === "string" ? record7.slug : typeof record7.name === "string" ? record7.name : undefined;
79017
79576
  if (!slug)
79018
79577
  return;
79019
79578
  return {
79020
79579
  slug,
79021
- version: typeof record5.version === "string" ? record5.version : undefined,
79022
- sha256: typeof record5.bundleSha256 === "string" && record5.bundleSha256 ? record5.bundleSha256 : undefined
79580
+ version: typeof record7.version === "string" ? record7.version : undefined,
79581
+ sha256: typeof record7.bundleSha256 === "string" && record7.bundleSha256 ? record7.bundleSha256 : undefined
79023
79582
  };
79024
79583
  }
79025
79584
  function recheckLocalSide(plannedLocal, localDir, ops = {