@hasna/skills 0.5.2 → 0.5.4

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/dist/index.js CHANGED
@@ -19,12 +19,14 @@ var __toESM = (mod, isNodeMode, target) => {
19
19
  }
20
20
  target = mod != null ? __create(__getProtoOf(mod)) : {};
21
21
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
22
- for (let key of __getOwnPropNames(mod))
23
- if (!__hasOwnProp.call(to, key))
24
- __defProp(to, key, {
25
- get: __accessProp.bind(mod, key),
26
- enumerable: true
27
- });
22
+ if (mod && typeof mod === "object" || typeof mod === "function") {
23
+ for (let key of __getOwnPropNames(mod))
24
+ if (!__hasOwnProp.call(to, key))
25
+ __defProp(to, key, {
26
+ get: __accessProp.bind(mod, key),
27
+ enumerable: true
28
+ });
29
+ }
28
30
  if (canCache)
29
31
  cache.set(mod, to);
30
32
  return to;
@@ -1463,8 +1465,45 @@ function validateRegistryConsistency(registry, skillsDir) {
1463
1465
  import { createHash } from "crypto";
1464
1466
  import { existsSync as existsSync5, readdirSync as readdirSync4, readFileSync as readFileSync4, statSync as statSync4 } from "fs";
1465
1467
  import { join as join5, sep } from "path";
1468
+
1469
+ // src/lib/skill-entry-path.ts
1470
+ class SkillEntryPaths {
1471
+ files = new Set;
1472
+ directories = new Set;
1473
+ add(path, maxBytes, invalid, limit) {
1474
+ if (path.length > maxBytes)
1475
+ limit();
1476
+ const encoded = new TextEncoder().encode(path);
1477
+ if (encoded.byteLength > maxBytes)
1478
+ limit();
1479
+ if (new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(encoded) !== path)
1480
+ invalid("Invalid UTF-8 entry path");
1481
+ if (!path || /[\\:\x00-\x1f\x7f]/u.test(path))
1482
+ invalid("Unsafe entry path");
1483
+ if (path.split("/").some((segment) => !segment || segment === "." || segment === ".."))
1484
+ invalid("Unsafe entry path segment");
1485
+ const key = path.normalize("NFC").toLowerCase().normalize("NFC");
1486
+ if (this.files.has(key) || this.directories.has(key))
1487
+ invalid("Duplicate or conflicting entry path");
1488
+ const parents = key.split("/");
1489
+ parents.pop();
1490
+ while (parents.length) {
1491
+ const parent = parents.join("/");
1492
+ if (this.files.has(parent))
1493
+ invalid("Conflicting entry file ancestor");
1494
+ this.directories.add(parent);
1495
+ parents.pop();
1496
+ }
1497
+ this.files.add(key);
1498
+ }
1499
+ }
1500
+
1501
+ // src/lib/skill-hash.ts
1466
1502
  var CONTENT_HASH_ALGORITHM = "sha256";
1467
1503
  var HASH_EXCLUDE_DIRS = new Set([".git", "node_modules", "dist", "build", ".turbo"]);
1504
+ function excludedHashEntry(name, directory) {
1505
+ return name.startsWith(".") || directory && HASH_EXCLUDE_DIRS.has(name);
1506
+ }
1468
1507
  var HASH_COVERAGE = [
1469
1508
  "SKILL.md",
1470
1509
  "skill.json",
@@ -1546,7 +1585,7 @@ function collectDirectory(files, dir, rel) {
1546
1585
  if (stats.isSymbolicLink())
1547
1586
  continue;
1548
1587
  if (stats.isDirectory()) {
1549
- if (HASH_EXCLUDE_DIRS.has(entry))
1588
+ if (excludedHashEntry(entry, true))
1550
1589
  continue;
1551
1590
  collectDirectory(files, absolute, childRel);
1552
1591
  } else if (stats.isFile()) {
@@ -1556,28 +1595,242 @@ function collectDirectory(files, dir, rel) {
1556
1595
  }
1557
1596
  function collectFile(files, absolute, rel) {
1558
1597
  const buffer = readFileSync4(absolute);
1598
+ files.push(normalizeBundleFile(rel.split(sep).join("/"), buffer));
1599
+ }
1600
+ function normalizeBundleFile(rel, buffer) {
1559
1601
  if (rel === "skill.json") {
1560
- files.push({ rel: rel.split(sep).join("/"), content: new TextEncoder().encode(canonicalizeManifest(new TextDecoder().decode(buffer))) });
1561
- return;
1602
+ return { rel, content: new TextEncoder().encode(canonicalizeManifest(new TextDecoder().decode(buffer))) };
1562
1603
  }
1563
1604
  if (looksLikeText(buffer)) {
1564
1605
  const normalized = normalizeLineEndings(new TextDecoder().decode(buffer));
1565
- files.push({ rel: rel.split(sep).join("/"), content: new TextEncoder().encode(normalized) });
1566
- return;
1606
+ return { rel, content: new TextEncoder().encode(normalized) };
1567
1607
  }
1568
- files.push({ rel: rel.split(sep).join("/"), content: buffer });
1608
+ return { rel, content: buffer };
1569
1609
  }
1570
1610
  function computeContentHash(skillPath) {
1611
+ return hashBundleFiles(collectBundleFiles(skillPath));
1612
+ }
1613
+ function* bundleHashParts(files) {
1614
+ for (const file of files) {
1615
+ yield new TextEncoder().encode(file.rel);
1616
+ yield new TextEncoder().encode(`\x00${file.content.length}\x00`);
1617
+ yield file.content;
1618
+ yield new TextEncoder().encode("\x00");
1619
+ }
1620
+ yield new TextEncoder().encode("\x00");
1621
+ }
1622
+ function hashBundleFiles(files) {
1623
+ const hash = createHash(CONTENT_HASH_ALGORITHM);
1624
+ for (const part of bundleHashParts(files))
1625
+ hash.update(part);
1626
+ return hash.digest("hex");
1627
+ }
1628
+ async function hashBundleFilesCooperatively(files, check) {
1571
1629
  const hash = createHash(CONTENT_HASH_ALGORITHM);
1572
- for (const file of collectBundleFiles(skillPath)) {
1573
- hash.update(new TextEncoder().encode(file.rel));
1574
- hash.update(new TextEncoder().encode(`\x00${file.content.length}\x00`));
1575
- hash.update(file.content);
1576
- hash.update(new TextEncoder().encode("\x00"));
1630
+ let bytesSinceYield = 0;
1631
+ for (const part of bundleHashParts(files)) {
1632
+ for (let offset = 0;offset < part.byteLength; offset += 64 * 1024) {
1633
+ check();
1634
+ const chunk = part.subarray(offset, offset + 64 * 1024);
1635
+ hash.update(chunk);
1636
+ bytesSinceYield += chunk.byteLength;
1637
+ if (bytesSinceYield >= 256 * 1024) {
1638
+ await new Promise((resolve2) => setImmediate(resolve2));
1639
+ bytesSinceYield = 0;
1640
+ }
1641
+ }
1577
1642
  }
1578
- hash.update(new TextEncoder().encode("\x00"));
1643
+ check();
1579
1644
  return hash.digest("hex");
1580
1645
  }
1646
+ var CONTENT_HASH_LIMITS = Object.freeze({
1647
+ entries: 1024,
1648
+ rawBytes: 64 * 1024 * 1024,
1649
+ normalizedBytes: 64 * 1024 * 1024,
1650
+ fileBytes: 16 * 1024 * 1024,
1651
+ normalizedFileBytes: 16 * 1024 * 1024,
1652
+ pathBytes: 100,
1653
+ manifestBytes: 16 * 1024,
1654
+ manifestDepth: 64,
1655
+ timeoutMs: 5000
1656
+ });
1657
+
1658
+ class ContentHashInputError extends Error {
1659
+ code;
1660
+ constructor(code, message) {
1661
+ super(message);
1662
+ this.code = code;
1663
+ this.name = "ContentHashInputError";
1664
+ }
1665
+ }
1666
+ function invalidContent(message = "Invalid content hash input") {
1667
+ throw new ContentHashInputError("CONTENT_HASH_INVALID", message);
1668
+ }
1669
+ function contentLimit(message) {
1670
+ throw new ContentHashInputError("CONTENT_HASH_LIMIT", message);
1671
+ }
1672
+ function contentRecord(value, allowed) {
1673
+ if (!value || typeof value !== "object" || ![Object.prototype, null].includes(Object.getPrototypeOf(value)))
1674
+ invalidContent();
1675
+ const result = Object.create(null);
1676
+ for (const key of Reflect.ownKeys(value)) {
1677
+ if (typeof key !== "string" || !allowed.includes(key))
1678
+ invalidContent();
1679
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
1680
+ if (!descriptor || !("value" in descriptor))
1681
+ invalidContent("Accessor content hash input is unsupported");
1682
+ result[key] = descriptor.value;
1683
+ }
1684
+ return result;
1685
+ }
1686
+ function contentOptions(options) {
1687
+ const record = contentRecord(options, ["limits", "signal"]);
1688
+ const limits = { ...CONTENT_HASH_LIMITS };
1689
+ if (record.limits !== undefined) {
1690
+ const supplied = contentRecord(record.limits, Object.keys(limits));
1691
+ for (const key of Object.keys(supplied)) {
1692
+ const value = supplied[key];
1693
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0 || value > limits[key])
1694
+ contentLimit("Invalid content hash limit");
1695
+ limits[key] = value;
1696
+ }
1697
+ }
1698
+ if (record.signal !== undefined && !(record.signal instanceof AbortSignal))
1699
+ invalidContent("Invalid content hash signal");
1700
+ return { limits, signal: record.signal };
1701
+ }
1702
+ var typedArrayPrototype = Object.getPrototypeOf(Uint8Array.prototype);
1703
+ var byteLengthOf = Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteLength").get;
1704
+ var bufferOf = Object.getOwnPropertyDescriptor(typedArrayPrototype, "buffer").get;
1705
+ function snapshotContentEntries(entries, limits, check) {
1706
+ if (!Array.isArray(entries))
1707
+ invalidContent("Content hash entries must be an array");
1708
+ if (entries.length > limits.entries)
1709
+ contentLimit("Content hash entry limit exceeded");
1710
+ if (Reflect.ownKeys(entries).length !== entries.length + 1)
1711
+ invalidContent("Invalid content hash entry array");
1712
+ const snapshot = [];
1713
+ const paths = new SkillEntryPaths;
1714
+ let rawBytes = 0;
1715
+ for (let index = 0;index < entries.length; index++) {
1716
+ check();
1717
+ const descriptor = Object.getOwnPropertyDescriptor(entries, String(index));
1718
+ if (!descriptor || !("value" in descriptor))
1719
+ invalidContent("Invalid content hash entry array");
1720
+ const entry = contentRecord(descriptor.value, ["path", "bytes", "mode"]);
1721
+ if (typeof entry.path !== "string" || typeof entry.mode !== "number" || !Number.isInteger(entry.mode) || entry.mode < 0 || entry.mode > 511)
1722
+ invalidContent("Invalid regular-file content hash entry");
1723
+ paths.add(entry.path, limits.pathBytes, invalidContent, () => contentLimit("Content hash path limit exceeded"));
1724
+ if (!(entry.bytes instanceof Uint8Array) || !ArrayBuffer.isView(entry.bytes))
1725
+ invalidContent("Content hash entry requires bytes");
1726
+ const size = byteLengthOf.call(entry.bytes);
1727
+ if (!(bufferOf.call(entry.bytes) instanceof ArrayBuffer))
1728
+ invalidContent("Shared content hash bytes are unsupported");
1729
+ if (size > limits.fileBytes || rawBytes + size > limits.rawBytes)
1730
+ contentLimit("Content hash raw byte limit exceeded");
1731
+ if (entry.path === "skill.json" && size > limits.manifestBytes)
1732
+ contentLimit("Content hash manifest byte limit exceeded");
1733
+ rawBytes += size;
1734
+ const bytes = new Uint8Array(new ArrayBuffer(size));
1735
+ bytes.set(entry.bytes);
1736
+ snapshot.push({ path: entry.path, bytes, mode: entry.mode });
1737
+ }
1738
+ check();
1739
+ return snapshot;
1740
+ }
1741
+ function coveredContentPath(path) {
1742
+ const segments = path.split("/");
1743
+ if (!HASH_COVERAGE.includes(segments[0]))
1744
+ return false;
1745
+ return !segments.slice(1).some((segment, index) => excludedHashEntry(segment, index < segments.length - 2));
1746
+ }
1747
+ function boundedManifest(raw, maxDepth) {
1748
+ let parsed;
1749
+ try {
1750
+ parsed = JSON.parse(raw);
1751
+ } catch {
1752
+ return;
1753
+ }
1754
+ const pending = [{ value: parsed, depth: 1 }];
1755
+ while (pending.length) {
1756
+ const { value, depth } = pending.pop();
1757
+ if (!value || typeof value !== "object")
1758
+ continue;
1759
+ if (depth > maxDepth)
1760
+ contentLimit("Content hash manifest depth limit exceeded");
1761
+ for (const child of Object.values(value))
1762
+ pending.push({ value: child, depth: depth + 1 });
1763
+ }
1764
+ return parsed;
1765
+ }
1766
+ async function hashContentEntries(entries, options) {
1767
+ const { limits, signal } = contentOptions(options);
1768
+ const deadline = performance.now() + limits.timeoutMs;
1769
+ let terminal;
1770
+ const abort = () => {
1771
+ terminal ??= new ContentHashInputError("CONTENT_HASH_ABORTED", "Content hashing aborted");
1772
+ };
1773
+ const timer = setTimeout(() => {
1774
+ terminal ??= new ContentHashInputError("CONTENT_HASH_TIMEOUT", "Content hashing deadline exceeded");
1775
+ }, limits.timeoutMs);
1776
+ const check = () => {
1777
+ if (signal?.aborted)
1778
+ abort();
1779
+ if (terminal)
1780
+ throw terminal;
1781
+ if (performance.now() >= deadline)
1782
+ throw new ContentHashInputError("CONTENT_HASH_TIMEOUT", "Content hashing deadline exceeded");
1783
+ };
1784
+ try {
1785
+ signal?.addEventListener("abort", abort, { once: true });
1786
+ check();
1787
+ const snapshot = snapshotContentEntries(entries, limits, check);
1788
+ const normalized = [];
1789
+ let normalizedBytes = 0;
1790
+ let manifest;
1791
+ await new Promise((resolve2) => setImmediate(resolve2));
1792
+ for (const entry of snapshot) {
1793
+ check();
1794
+ if (!coveredContentPath(entry.path))
1795
+ continue;
1796
+ if (entry.path === "skill.json")
1797
+ manifest = boundedManifest(new TextDecoder().decode(entry.bytes), limits.manifestDepth);
1798
+ const file = normalizeBundleFile(entry.path, entry.bytes);
1799
+ check();
1800
+ if (file.content.byteLength > limits.normalizedFileBytes || normalizedBytes + file.content.byteLength > limits.normalizedBytes)
1801
+ contentLimit("Content hash normalized byte limit exceeded");
1802
+ normalizedBytes += file.content.byteLength;
1803
+ normalized.push(file);
1804
+ await new Promise((resolve2) => setImmediate(resolve2));
1805
+ }
1806
+ normalized.sort((a, b) => a.rel < b.rel ? -1 : a.rel > b.rel ? 1 : 0);
1807
+ check();
1808
+ return { hash: await hashBundleFilesCooperatively(normalized, check), manifest };
1809
+ } catch (error) {
1810
+ if (error instanceof ContentHashInputError)
1811
+ throw error;
1812
+ throw new ContentHashInputError("CONTENT_HASH_INVALID", "Invalid content hash input");
1813
+ } finally {
1814
+ clearTimeout(timer);
1815
+ signal?.removeEventListener("abort", abort);
1816
+ }
1817
+ }
1818
+ async function computeContentHashFromEntries(entries, options = {}) {
1819
+ return (await hashContentEntries(entries, options)).hash;
1820
+ }
1821
+ async function verifyContentHashFromEntries(entries, options = {}) {
1822
+ const { hash, manifest } = await hashContentEntries(entries, options);
1823
+ const provenance = manifest && typeof manifest === "object" && !Array.isArray(manifest) ? manifest.provenance : undefined;
1824
+ const value = provenance && typeof provenance === "object" && !Array.isArray(provenance) ? provenance.content_hash : undefined;
1825
+ if (value !== undefined && typeof value !== "string")
1826
+ invalidContent("Invalid content hash declaration");
1827
+ const declaredHash = value?.trim() || undefined;
1828
+ if (!declaredHash)
1829
+ return { declared: false, valid: false };
1830
+ if (!/^[a-f0-9]{64}$/.test(declaredHash))
1831
+ return { declared: true, valid: false, declaredHash };
1832
+ return { declared: true, valid: hash === declaredHash, declaredHash, computedHash: hash };
1833
+ }
1581
1834
  function verifyContentHash(skillPath, manifest) {
1582
1835
  const declaredHash = manifest?.provenance?.content_hash?.trim() || undefined;
1583
1836
  if (!declaredHash)
@@ -4478,207 +4731,207 @@ function readIfExists(path) {
4478
4731
  // ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/external.js
4479
4732
  var exports_external = {};
4480
4733
  __export(exports_external, {
4481
- void: () => voidType,
4482
- util: () => util,
4483
- unknown: () => unknownType,
4484
- union: () => unionType,
4485
- undefined: () => undefinedType,
4486
- tuple: () => tupleType,
4487
- transformer: () => effectsType,
4488
- symbol: () => symbolType,
4489
- string: () => stringType,
4490
- strictObject: () => strictObjectType,
4491
- setErrorMap: () => setErrorMap,
4492
- set: () => setType,
4493
- record: () => recordType,
4494
- quotelessJson: () => quotelessJson,
4495
- promise: () => promiseType,
4496
- preprocess: () => preprocessType,
4497
- pipeline: () => pipelineType,
4498
- ostring: () => ostring,
4499
- optional: () => optionalType,
4500
- onumber: () => onumber,
4501
- oboolean: () => oboolean,
4502
- objectUtil: () => objectUtil,
4503
- object: () => objectType,
4504
- number: () => numberType,
4505
- nullable: () => nullableType,
4506
- null: () => nullType,
4507
- never: () => neverType,
4508
- nativeEnum: () => nativeEnumType,
4509
- nan: () => nanType,
4510
- map: () => mapType,
4511
- makeIssue: () => makeIssue,
4512
- literal: () => literalType,
4513
- lazy: () => lazyType,
4514
- late: () => late,
4515
- isValid: () => isValid,
4516
- isDirty: () => isDirty,
4517
- isAsync: () => isAsync,
4518
- isAborted: () => isAborted,
4519
- intersection: () => intersectionType,
4520
- instanceof: () => instanceOfType,
4521
- getParsedType: () => getParsedType,
4522
- getErrorMap: () => getErrorMap,
4523
- function: () => functionType,
4524
- enum: () => enumType,
4525
- effect: () => effectsType,
4526
- discriminatedUnion: () => discriminatedUnionType,
4527
- defaultErrorMap: () => en_default,
4528
- datetimeRegex: () => datetimeRegex,
4529
- date: () => dateType,
4530
- custom: () => custom,
4531
- coerce: () => coerce,
4532
- boolean: () => booleanType,
4533
- bigint: () => bigIntType,
4534
- array: () => arrayType,
4535
- any: () => anyType,
4536
- addIssueToContext: () => addIssueToContext,
4537
- ZodVoid: () => ZodVoid,
4538
- ZodUnknown: () => ZodUnknown,
4539
- ZodUnion: () => ZodUnion,
4540
- ZodUndefined: () => ZodUndefined,
4541
- ZodType: () => ZodType,
4542
- ZodTuple: () => ZodTuple,
4543
- ZodTransformer: () => ZodEffects,
4544
- ZodSymbol: () => ZodSymbol,
4545
- ZodString: () => ZodString,
4546
- ZodSet: () => ZodSet,
4547
- ZodSchema: () => ZodType,
4548
- ZodRecord: () => ZodRecord,
4549
- ZodReadonly: () => ZodReadonly,
4550
- ZodPromise: () => ZodPromise,
4551
- ZodPipeline: () => ZodPipeline,
4552
- ZodParsedType: () => ZodParsedType,
4553
- ZodOptional: () => ZodOptional,
4554
- ZodObject: () => ZodObject,
4555
- ZodNumber: () => ZodNumber,
4556
- ZodNullable: () => ZodNullable,
4557
- ZodNull: () => ZodNull,
4558
- ZodNever: () => ZodNever,
4559
- ZodNativeEnum: () => ZodNativeEnum,
4560
- ZodNaN: () => ZodNaN,
4561
- ZodMap: () => ZodMap,
4562
- ZodLiteral: () => ZodLiteral,
4563
- ZodLazy: () => ZodLazy,
4564
- ZodIssueCode: () => ZodIssueCode,
4565
- ZodIntersection: () => ZodIntersection,
4566
- ZodFunction: () => ZodFunction,
4567
- ZodFirstPartyTypeKind: () => ZodFirstPartyTypeKind,
4568
- ZodError: () => ZodError,
4569
- ZodEnum: () => ZodEnum,
4570
- ZodEffects: () => ZodEffects,
4571
- ZodDiscriminatedUnion: () => ZodDiscriminatedUnion,
4572
- ZodDefault: () => ZodDefault,
4573
- ZodDate: () => ZodDate,
4574
- ZodCatch: () => ZodCatch,
4575
- ZodBranded: () => ZodBranded,
4576
- ZodBoolean: () => ZodBoolean,
4577
- ZodBigInt: () => ZodBigInt,
4578
- ZodArray: () => ZodArray,
4579
- ZodAny: () => ZodAny,
4580
- Schema: () => ZodType,
4581
- ParseStatus: () => ParseStatus,
4582
- OK: () => OK,
4583
- NEVER: () => NEVER,
4584
- INVALID: () => INVALID,
4585
- EMPTY_PATH: () => EMPTY_PATH,
4734
+ BRAND: () => BRAND,
4586
4735
  DIRTY: () => DIRTY,
4587
- BRAND: () => BRAND
4588
- });
4589
-
4590
- // ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/util.js
4591
- var util;
4592
- (function(util2) {
4593
- util2.assertEqual = (_) => {};
4594
- function assertIs(_arg) {}
4595
- util2.assertIs = assertIs;
4596
- function assertNever(_x) {
4597
- throw new Error;
4598
- }
4599
- util2.assertNever = assertNever;
4600
- util2.arrayToEnum = (items) => {
4601
- const obj = {};
4602
- for (const item of items) {
4603
- obj[item] = item;
4604
- }
4605
- return obj;
4606
- };
4607
- util2.getValidEnumValues = (obj) => {
4608
- const validKeys2 = util2.objectKeys(obj).filter((k) => typeof obj[obj[k]] !== "number");
4609
- const filtered = {};
4610
- for (const k of validKeys2) {
4611
- filtered[k] = obj[k];
4612
- }
4613
- return util2.objectValues(filtered);
4614
- };
4615
- util2.objectValues = (obj) => {
4616
- return util2.objectKeys(obj).map(function(e) {
4617
- return obj[e];
4618
- });
4619
- };
4620
- util2.objectKeys = typeof Object.keys === "function" ? (obj) => Object.keys(obj) : (object) => {
4621
- const keys = [];
4622
- for (const key in object) {
4623
- if (Object.prototype.hasOwnProperty.call(object, key)) {
4624
- keys.push(key);
4625
- }
4626
- }
4627
- return keys;
4628
- };
4629
- util2.find = (arr, checker) => {
4630
- for (const item of arr) {
4631
- if (checker(item))
4632
- return item;
4633
- }
4634
- return;
4635
- };
4636
- util2.isInteger = typeof Number.isInteger === "function" ? (val) => Number.isInteger(val) : (val) => typeof val === "number" && Number.isFinite(val) && Math.floor(val) === val;
4637
- function joinValues(array, separator = " | ") {
4638
- return array.map((val) => typeof val === "string" ? `'${val}'` : val).join(separator);
4639
- }
4640
- util2.joinValues = joinValues;
4641
- util2.jsonStringifyReplacer = (_, value) => {
4642
- if (typeof value === "bigint") {
4643
- return value.toString();
4644
- }
4645
- return value;
4646
- };
4647
- })(util || (util = {}));
4648
- var objectUtil;
4649
- (function(objectUtil2) {
4650
- objectUtil2.mergeShapes = (first, second) => {
4651
- return {
4652
- ...first,
4653
- ...second
4654
- };
4655
- };
4656
- })(objectUtil || (objectUtil = {}));
4657
- var ZodParsedType = util.arrayToEnum([
4658
- "string",
4659
- "nan",
4660
- "number",
4661
- "integer",
4662
- "float",
4663
- "boolean",
4664
- "date",
4665
- "bigint",
4666
- "symbol",
4667
- "function",
4668
- "undefined",
4669
- "null",
4670
- "array",
4671
- "object",
4672
- "unknown",
4673
- "promise",
4674
- "void",
4675
- "never",
4676
- "map",
4677
- "set"
4678
- ]);
4679
- var getParsedType = (data) => {
4680
- const t = typeof data;
4681
- switch (t) {
4736
+ EMPTY_PATH: () => EMPTY_PATH,
4737
+ INVALID: () => INVALID,
4738
+ NEVER: () => NEVER,
4739
+ OK: () => OK,
4740
+ ParseStatus: () => ParseStatus,
4741
+ Schema: () => ZodType,
4742
+ ZodAny: () => ZodAny,
4743
+ ZodArray: () => ZodArray,
4744
+ ZodBigInt: () => ZodBigInt,
4745
+ ZodBoolean: () => ZodBoolean,
4746
+ ZodBranded: () => ZodBranded,
4747
+ ZodCatch: () => ZodCatch,
4748
+ ZodDate: () => ZodDate,
4749
+ ZodDefault: () => ZodDefault,
4750
+ ZodDiscriminatedUnion: () => ZodDiscriminatedUnion,
4751
+ ZodEffects: () => ZodEffects,
4752
+ ZodEnum: () => ZodEnum,
4753
+ ZodError: () => ZodError,
4754
+ ZodFirstPartyTypeKind: () => ZodFirstPartyTypeKind,
4755
+ ZodFunction: () => ZodFunction,
4756
+ ZodIntersection: () => ZodIntersection,
4757
+ ZodIssueCode: () => ZodIssueCode,
4758
+ ZodLazy: () => ZodLazy,
4759
+ ZodLiteral: () => ZodLiteral,
4760
+ ZodMap: () => ZodMap,
4761
+ ZodNaN: () => ZodNaN,
4762
+ ZodNativeEnum: () => ZodNativeEnum,
4763
+ ZodNever: () => ZodNever,
4764
+ ZodNull: () => ZodNull,
4765
+ ZodNullable: () => ZodNullable,
4766
+ ZodNumber: () => ZodNumber,
4767
+ ZodObject: () => ZodObject,
4768
+ ZodOptional: () => ZodOptional,
4769
+ ZodParsedType: () => ZodParsedType,
4770
+ ZodPipeline: () => ZodPipeline,
4771
+ ZodPromise: () => ZodPromise,
4772
+ ZodReadonly: () => ZodReadonly,
4773
+ ZodRecord: () => ZodRecord,
4774
+ ZodSchema: () => ZodType,
4775
+ ZodSet: () => ZodSet,
4776
+ ZodString: () => ZodString,
4777
+ ZodSymbol: () => ZodSymbol,
4778
+ ZodTransformer: () => ZodEffects,
4779
+ ZodTuple: () => ZodTuple,
4780
+ ZodType: () => ZodType,
4781
+ ZodUndefined: () => ZodUndefined,
4782
+ ZodUnion: () => ZodUnion,
4783
+ ZodUnknown: () => ZodUnknown,
4784
+ ZodVoid: () => ZodVoid,
4785
+ addIssueToContext: () => addIssueToContext,
4786
+ any: () => anyType,
4787
+ array: () => arrayType,
4788
+ bigint: () => bigIntType,
4789
+ boolean: () => booleanType,
4790
+ coerce: () => coerce,
4791
+ custom: () => custom,
4792
+ date: () => dateType,
4793
+ datetimeRegex: () => datetimeRegex,
4794
+ defaultErrorMap: () => en_default,
4795
+ discriminatedUnion: () => discriminatedUnionType,
4796
+ effect: () => effectsType,
4797
+ enum: () => enumType,
4798
+ function: () => functionType,
4799
+ getErrorMap: () => getErrorMap,
4800
+ getParsedType: () => getParsedType,
4801
+ instanceof: () => instanceOfType,
4802
+ intersection: () => intersectionType,
4803
+ isAborted: () => isAborted,
4804
+ isAsync: () => isAsync,
4805
+ isDirty: () => isDirty,
4806
+ isValid: () => isValid,
4807
+ late: () => late,
4808
+ lazy: () => lazyType,
4809
+ literal: () => literalType,
4810
+ makeIssue: () => makeIssue,
4811
+ map: () => mapType,
4812
+ nan: () => nanType,
4813
+ nativeEnum: () => nativeEnumType,
4814
+ never: () => neverType,
4815
+ null: () => nullType,
4816
+ nullable: () => nullableType,
4817
+ number: () => numberType,
4818
+ object: () => objectType,
4819
+ objectUtil: () => objectUtil,
4820
+ oboolean: () => oboolean,
4821
+ onumber: () => onumber,
4822
+ optional: () => optionalType,
4823
+ ostring: () => ostring,
4824
+ pipeline: () => pipelineType,
4825
+ preprocess: () => preprocessType,
4826
+ promise: () => promiseType,
4827
+ quotelessJson: () => quotelessJson,
4828
+ record: () => recordType,
4829
+ set: () => setType,
4830
+ setErrorMap: () => setErrorMap,
4831
+ strictObject: () => strictObjectType,
4832
+ string: () => stringType,
4833
+ symbol: () => symbolType,
4834
+ transformer: () => effectsType,
4835
+ tuple: () => tupleType,
4836
+ undefined: () => undefinedType,
4837
+ union: () => unionType,
4838
+ unknown: () => unknownType,
4839
+ util: () => util,
4840
+ void: () => voidType
4841
+ });
4842
+
4843
+ // ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/util.js
4844
+ var util;
4845
+ (function(util2) {
4846
+ util2.assertEqual = (_) => {};
4847
+ function assertIs(_arg) {}
4848
+ util2.assertIs = assertIs;
4849
+ function assertNever(_x) {
4850
+ throw new Error;
4851
+ }
4852
+ util2.assertNever = assertNever;
4853
+ util2.arrayToEnum = (items) => {
4854
+ const obj = {};
4855
+ for (const item of items) {
4856
+ obj[item] = item;
4857
+ }
4858
+ return obj;
4859
+ };
4860
+ util2.getValidEnumValues = (obj) => {
4861
+ const validKeys2 = util2.objectKeys(obj).filter((k) => typeof obj[obj[k]] !== "number");
4862
+ const filtered = {};
4863
+ for (const k of validKeys2) {
4864
+ filtered[k] = obj[k];
4865
+ }
4866
+ return util2.objectValues(filtered);
4867
+ };
4868
+ util2.objectValues = (obj) => {
4869
+ return util2.objectKeys(obj).map(function(e) {
4870
+ return obj[e];
4871
+ });
4872
+ };
4873
+ util2.objectKeys = typeof Object.keys === "function" ? (obj) => Object.keys(obj) : (object) => {
4874
+ const keys = [];
4875
+ for (const key in object) {
4876
+ if (Object.prototype.hasOwnProperty.call(object, key)) {
4877
+ keys.push(key);
4878
+ }
4879
+ }
4880
+ return keys;
4881
+ };
4882
+ util2.find = (arr, checker) => {
4883
+ for (const item of arr) {
4884
+ if (checker(item))
4885
+ return item;
4886
+ }
4887
+ return;
4888
+ };
4889
+ util2.isInteger = typeof Number.isInteger === "function" ? (val) => Number.isInteger(val) : (val) => typeof val === "number" && Number.isFinite(val) && Math.floor(val) === val;
4890
+ function joinValues(array, separator = " | ") {
4891
+ return array.map((val) => typeof val === "string" ? `'${val}'` : val).join(separator);
4892
+ }
4893
+ util2.joinValues = joinValues;
4894
+ util2.jsonStringifyReplacer = (_, value) => {
4895
+ if (typeof value === "bigint") {
4896
+ return value.toString();
4897
+ }
4898
+ return value;
4899
+ };
4900
+ })(util || (util = {}));
4901
+ var objectUtil;
4902
+ (function(objectUtil2) {
4903
+ objectUtil2.mergeShapes = (first, second) => {
4904
+ return {
4905
+ ...first,
4906
+ ...second
4907
+ };
4908
+ };
4909
+ })(objectUtil || (objectUtil = {}));
4910
+ var ZodParsedType = util.arrayToEnum([
4911
+ "string",
4912
+ "nan",
4913
+ "number",
4914
+ "integer",
4915
+ "float",
4916
+ "boolean",
4917
+ "date",
4918
+ "bigint",
4919
+ "symbol",
4920
+ "function",
4921
+ "undefined",
4922
+ "null",
4923
+ "array",
4924
+ "object",
4925
+ "unknown",
4926
+ "promise",
4927
+ "void",
4928
+ "never",
4929
+ "map",
4930
+ "set"
4931
+ ]);
4932
+ var getParsedType = (data) => {
4933
+ const t = typeof data;
4934
+ switch (t) {
4682
4935
  case "undefined":
4683
4936
  return ZodParsedType.undefined;
4684
4937
  case "string":
@@ -10254,11 +10507,174 @@ function primitiveHaystack(primitive) {
10254
10507
  function clone(value) {
10255
10508
  return value === undefined ? undefined : JSON.parse(JSON.stringify(value));
10256
10509
  }
10257
- // src/lib/remote-workspace-selection.ts
10510
+ // src/lib/remote-invitations.ts
10511
+ class WorkspaceInvitationInputError extends Error {
10512
+ code = "INVITATION_INPUT_INVALID";
10513
+ constructor() {
10514
+ super("Provide only the documented invitation fields, exact lowercase IDs, expected generation and explicit confirmation. Issue and resend require your stable idempotency key.");
10515
+ this.name = "WorkspaceInvitationInputError";
10516
+ }
10517
+ }
10518
+ var invitationFailures = {
10519
+ INVALID_REQUEST: [400, "Invitation parameters were refused."],
10520
+ ACCOUNT_UNAVAILABLE: [403, "Account is unavailable."],
10521
+ INTERACTIVE_SESSION_REQUIRED: [403, "Fresh interactive sign-in is required."],
10522
+ WORKSPACE_ADMIN_REQUIRED: [403, "A current workspace owner or admin is required."],
10523
+ INVITATION_FORBIDDEN: [403, "Your current role cannot manage this invitation."],
10524
+ INVITATION_UNAVAILABLE: [404, "Invitation is unavailable for this account."],
10525
+ INVITATION_CHANGED: [409, "Invitation changed. Read its current generation before another action."],
10526
+ INVITATION_EXISTS: [409, "A pending invitation already exists. Read current invitations."],
10527
+ ALREADY_MEMBER: [409, "An active membership already exists. An invitation cannot change its role."],
10528
+ IDEMPOTENCY_CONFLICT: [409, "This request key was used for different invitation parameters. Reconcile the original request."],
10529
+ INVITATION_LIMIT: [429, "Invitation limit reached. Wait before issuing or resending."],
10530
+ INVITATION_BUSY: [503, "Invitation is busy. Read its state before another action."],
10531
+ INVITATION_DELIVERY_UNAVAILABLE: [503, "Invitation email delivery is unavailable."]
10532
+ };
10533
+
10534
+ class RemoteWorkspaceInvitationError extends Error {
10535
+ code;
10536
+ status;
10537
+ constructor(code) {
10538
+ super(invitationFailures[code][1]);
10539
+ this.code = code;
10540
+ this.name = "RemoteWorkspaceInvitationError";
10541
+ this.status = invitationFailures[code][0];
10542
+ }
10543
+ }
10544
+
10545
+ class RemoteWorkspaceInvitationUnconfirmedError extends Error {
10546
+ code = "INVITATION_UNCONFIRMED";
10547
+ constructor() {
10548
+ 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.");
10549
+ this.name = "RemoteWorkspaceInvitationUnconfirmedError";
10550
+ }
10551
+ }
10552
+
10553
+ class RemoteWorkspaceInvitationReadError extends Error {
10554
+ code = "INVITATION_READ_FAILED";
10555
+ constructor() {
10556
+ super("Unable to read a valid invitation result. Check the selected server, account, current membership and permissions.");
10557
+ this.name = "RemoteWorkspaceInvitationReadError";
10558
+ }
10559
+ }
10560
+ function invitationFailure(value, status) {
10561
+ if (!record(value) || typeof value.code !== "string" || !Object.hasOwn(invitationFailures, value.code))
10562
+ return null;
10563
+ const code = value.code;
10564
+ return invitationFailures[code][0] === status ? code : null;
10565
+ }
10258
10566
  var record = (v) => !!v && typeof v === "object" && !Array.isArray(v);
10259
10567
  var uuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v);
10260
- var text = (v, max = 1024) => typeof v === "string" && !!v.trim() && v.length <= max && !/[\p{Cc}\p{Cs}\u2028\u2029]/u.test(v);
10261
10568
  var role = (v) => typeof v === "string" && ["owner", "admin", "member", "viewer"].includes(v);
10569
+ var email = (v) => typeof v === "string" && v.length <= 254 && !/[\p{Cc}\p{Cs}\u2028\u2029\s]/u.test(v) && /^[^@]+@[^@]+\.[^@]+$/.test(v);
10570
+ var 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));
10571
+ var inputFailure = () => {
10572
+ throw new WorkspaceInvitationInputError;
10573
+ };
10574
+ function invitationInput(action, input) {
10575
+ if (!record(input))
10576
+ return inputFailure();
10577
+ const keys = {
10578
+ list: ["after"],
10579
+ get: ["invitationId"],
10580
+ issue: ["email", "role", "idempotencyKey", "confirm"],
10581
+ resend: ["invitationId", "expectedGeneration", "idempotencyKey", "confirm"],
10582
+ revoke: ["invitationId", "expectedGeneration", "confirm"],
10583
+ accept: ["invitationId", "token", "confirm"]
10584
+ };
10585
+ if (Object.keys(input).some((key) => !keys[action].includes(key)) || action !== "list" && keys[action].some((key) => !Object.hasOwn(input, key)))
10586
+ return inputFailure();
10587
+ const value = { ...input };
10588
+ if (action === "list") {
10589
+ if (value.after !== undefined && !uuid(value.after))
10590
+ return inputFailure();
10591
+ }
10592
+ if (["get", "resend", "revoke", "accept"].includes(action) && !uuid(value.invitationId))
10593
+ return inputFailure();
10594
+ if (!["list", "get"].includes(action) && value.confirm !== true)
10595
+ return inputFailure();
10596
+ if (["issue", "resend"].includes(action) && !uuid(value.idempotencyKey))
10597
+ return inputFailure();
10598
+ if (action === "issue") {
10599
+ if (typeof value.email !== "string")
10600
+ return inputFailure();
10601
+ value.email = value.email.trim().toLowerCase();
10602
+ if (!email(value.email) || !role(value.role))
10603
+ return inputFailure();
10604
+ }
10605
+ if (["resend", "revoke"].includes(action) && (!Number.isInteger(value.expectedGeneration) || Number(value.expectedGeneration) < 1 || Number(value.expectedGeneration) > 10))
10606
+ return inputFailure();
10607
+ if (action === "accept" && (typeof value.token !== "string" || !/^[A-Za-z0-9_-]{43}$/.test(value.token)))
10608
+ return inputFailure();
10609
+ return value;
10610
+ }
10611
+ function invitationRequest(action, input) {
10612
+ const base = "/api/v1/workspace/invitations", value = input;
10613
+ const { confirm: _confirm, invitationId: id, ...body } = value;
10614
+ if (action === "list")
10615
+ return { path: base + (value.after ? `?after=${value.after}` : ""), method: "GET" };
10616
+ if (action === "get")
10617
+ return { path: `${base}/${id}`, method: "GET" };
10618
+ if (action === "accept")
10619
+ return { path: "/api/v1/account/invitations/accept", method: "POST", body: JSON.stringify({ invitationId: id, token: value.token }) };
10620
+ return { path: action === "issue" ? base : `${base}/${id}${action === "resend" ? "/resend" : ""}`, method: action === "revoke" ? "DELETE" : "POST", body: JSON.stringify(body) };
10621
+ }
10622
+ function invalid() {
10623
+ throw new RemoteWorkspaceInvitationReadError;
10624
+ }
10625
+ function projection(v, organizationId) {
10626
+ 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)
10627
+ return invalid();
10628
+ return {
10629
+ id: v.id,
10630
+ organizationId,
10631
+ email: v.email,
10632
+ role: v.role,
10633
+ generation: Number(v.generation),
10634
+ status: v.status,
10635
+ expiresAt: v.expiresAt,
10636
+ createdAt: v.createdAt,
10637
+ delivery: { state: v.delivery.state, attempts: Number(v.delivery.attempts) }
10638
+ };
10639
+ }
10640
+ function parseInvitationResult(action, value, input, organizationId) {
10641
+ if (!record(value))
10642
+ return invalid();
10643
+ const request = input;
10644
+ if (action === "accept") {
10645
+ if (!uuid(value.organizationId) || !uuid(value.membershipId) || value.accepted !== true || typeof value.changed !== "boolean")
10646
+ return invalid();
10647
+ return { organizationId: value.organizationId, membershipId: value.membershipId, accepted: true, changed: value.changed };
10648
+ }
10649
+ if (action === "list") {
10650
+ if (value.organizationId !== organizationId || !Array.isArray(value.invitations) || value.invitations.length > 50 || value.nextCursor !== null && !uuid(value.nextCursor))
10651
+ return invalid();
10652
+ const invitations = value.invitations.map((v) => projection(v, organizationId));
10653
+ 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))
10654
+ return invalid();
10655
+ return { organizationId, invitations, nextCursor: value.nextCursor };
10656
+ }
10657
+ const invitation = projection(value.invitation, organizationId);
10658
+ if (action !== "issue" && invitation.id !== request.invitationId)
10659
+ return invalid();
10660
+ if (action === "get")
10661
+ return { invitation };
10662
+ if (typeof value.changed !== "boolean")
10663
+ return invalid();
10664
+ if (action === "issue" && (invitation.email !== request.email || invitation.role !== request.role || value.changed && invitation.generation !== 1))
10665
+ return invalid();
10666
+ if (action === "resend" && (value.changed ? invitation.generation !== Number(request.expectedGeneration) + 1 : invitation.generation <= Number(request.expectedGeneration)))
10667
+ return invalid();
10668
+ if (action === "revoke" && (invitation.status !== "revoked" || invitation.generation < Number(request.expectedGeneration) || value.changed && invitation.generation !== request.expectedGeneration))
10669
+ return invalid();
10670
+ return { invitation, changed: value.changed };
10671
+ }
10672
+
10673
+ // src/lib/remote-workspace-selection.ts
10674
+ var record2 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
10675
+ var 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);
10676
+ var text = (v, max = 1024) => typeof v === "string" && !!v.trim() && v.length <= max && !/[\p{Cc}\p{Cs}\u2028\u2029]/u.test(v);
10677
+ var role2 = (v) => typeof v === "string" && ["owner", "admin", "member", "viewer"].includes(v);
10262
10678
  var invalidWorkspaceResult = "The server returned an invalid workspace selection result.";
10263
10679
 
10264
10680
  class WorkspaceContextInputError extends Error {
@@ -10275,48 +10691,48 @@ class WorkspaceIdentityMismatchError extends Error {
10275
10691
  }
10276
10692
  }
10277
10693
  function workspaceExpectedUserId(value) {
10278
- if (!uuid(value))
10694
+ if (!uuid2(value))
10279
10695
  throw new WorkspaceContextInputError;
10280
10696
  return value;
10281
10697
  }
10282
10698
  function workspaceContext(value) {
10283
- if (!record(value) || Object.keys(value).sort().join(",") !== "membershipId,userId" || !uuid(value.userId) || !uuid(value.membershipId))
10699
+ if (!record2(value) || Object.keys(value).sort().join(",") !== "membershipId,userId" || !uuid2(value.userId) || !uuid2(value.membershipId))
10284
10700
  throw new WorkspaceContextInputError;
10285
10701
  return { userId: value.userId, membershipId: value.membershipId };
10286
10702
  }
10287
- function invalid() {
10703
+ function invalid2() {
10288
10704
  throw new Error(invalidWorkspaceResult);
10289
10705
  }
10290
10706
  function organization(v) {
10291
- if (!record(v) || !uuid(v.id) || !text(v.slug) || !text(v.name))
10292
- return invalid();
10707
+ if (!record2(v) || !uuid2(v.id) || !text(v.slug) || !text(v.name))
10708
+ return invalid2();
10293
10709
  return { id: v.id, slug: v.slug, name: v.name };
10294
10710
  }
10295
10711
  function parseAccountWorkspaces(value) {
10296
- if (!record(value) || !Array.isArray(value.workspaces) || !value.workspaces.length || value.workspaces.length > 1000)
10297
- return invalid();
10712
+ if (!record2(value) || !Array.isArray(value.workspaces) || !value.workspaces.length || value.workspaces.length > 1000)
10713
+ return invalid2();
10298
10714
  const workspaces = value.workspaces.map((v) => {
10299
- if (!record(v) || !uuid(v.membershipId) || !role(v.role) || typeof v.current !== "boolean")
10300
- return invalid();
10715
+ if (!record2(v) || !uuid2(v.membershipId) || !role2(v.role) || typeof v.current !== "boolean")
10716
+ return invalid2();
10301
10717
  return { membershipId: v.membershipId, organization: organization(v.organization), role: v.role, current: v.current };
10302
10718
  });
10303
10719
  if (workspaces.filter((w) => w.current).length !== 1 || new Set(workspaces.map((w) => w.membershipId)).size !== workspaces.length || new Set(workspaces.map((w) => w.organization.id)).size !== workspaces.length)
10304
- return invalid();
10720
+ return invalid2();
10305
10721
  return { workspaces };
10306
10722
  }
10307
10723
  function parseWorkspaceIdentity(value, expectedUserId) {
10308
- if (!record(value))
10309
- return invalid();
10724
+ if (!record2(value))
10725
+ return invalid2();
10310
10726
  const user = value.user;
10311
- if (!record(user) || !uuid(user.id) || !uuid(user.membershipId) || !text(user.email, 320) || !(user.displayName === null || text(user.displayName)) || !role(user.role))
10312
- return invalid();
10727
+ if (!record2(user) || !uuid2(user.id) || !uuid2(user.membershipId) || !text(user.email, 320) || !(user.displayName === null || text(user.displayName)) || !role2(user.role))
10728
+ return invalid2();
10313
10729
  if (user.id !== expectedUserId)
10314
10730
  throw new WorkspaceIdentityMismatchError;
10315
10731
  return { user: { id: user.id, membershipId: user.membershipId, email: user.email, displayName: user.displayName, role: user.role }, organization: organization(value.organization) };
10316
10732
  }
10317
10733
  function sessionToken(value) {
10318
10734
  if (typeof value !== "string" || !value || value.length > 8192 || /[^\x21-\x7e]/.test(value) || value.startsWith("sk_"))
10319
- return invalid();
10735
+ return invalid2();
10320
10736
  return value;
10321
10737
  }
10322
10738
  function parseWorkspaceSession(value, expected) {
@@ -10326,9 +10742,9 @@ function parseWorkspaceSession(value, expected) {
10326
10742
  return { token: sessionToken(value.token), ...identity };
10327
10743
  }
10328
10744
  function parseWorkspaceLogin(value, expectedUserId) {
10329
- const user = record(value) && value.user;
10330
- if (!record(value) || !record(user) || !uuid(user.id))
10331
- return invalid();
10745
+ const user = record2(value) && value.user;
10746
+ if (!record2(value) || !record2(user) || !uuid2(user.id))
10747
+ return invalid2();
10332
10748
  if (expectedUserId !== undefined && user.id !== expectedUserId)
10333
10749
  throw new WorkspaceIdentityMismatchError;
10334
10750
  return { token: sessionToken(value.token), userId: user.id };
@@ -10342,18 +10758,18 @@ var workspaceSelectionFailures = {
10342
10758
  WORKSPACE_BUSY: [503, "Workspace is busy. Refresh before retrying."]
10343
10759
  };
10344
10760
  function workspaceSelectionFailure(value, status) {
10345
- if (!record(value) || typeof value.code !== "string" || !Object.hasOwn(workspaceSelectionFailures, value.code))
10761
+ if (!record2(value) || typeof value.code !== "string" || !Object.hasOwn(workspaceSelectionFailures, value.code))
10346
10762
  return null;
10347
10763
  const code = value.code;
10348
10764
  return workspaceSelectionFailures[code][0] === status ? code : null;
10349
10765
  }
10350
10766
 
10351
10767
  // src/lib/remote-workspace.ts
10352
- var record2 = (value) => !!value && typeof value === "object" && !Array.isArray(value);
10768
+ var record3 = (value) => !!value && typeof value === "object" && !Array.isArray(value);
10353
10769
  var cursor = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,512}$/.test(value);
10354
- var uuid2 = (value) => typeof value === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i.test(value);
10770
+ var 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);
10355
10771
  function workspaceMembersQuery(options = {}) {
10356
- if (!record2(options) || Object.keys(options).some((key) => key !== "limit" && key !== "cursor") || options.limit !== undefined && (!Number.isInteger(options.limit) || options.limit < 1 || options.limit > 100) || options.cursor !== undefined && !cursor(options.cursor))
10772
+ 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))
10357
10773
  throw new Error("Use a roster limit from 1 to 100 and an unchanged continuation cursor.");
10358
10774
  const query = new URLSearchParams;
10359
10775
  if (options.limit !== undefined)
@@ -10362,14 +10778,14 @@ function workspaceMembersQuery(options = {}) {
10362
10778
  query.set("cursor", options.cursor);
10363
10779
  return query.size ? `?${query}` : "";
10364
10780
  }
10365
- function timestamp(value) {
10781
+ function timestamp2(value) {
10366
10782
  if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}Z$/.test(value))
10367
10783
  return false;
10368
10784
  const time = Date.parse(value);
10369
10785
  return Number.isFinite(time) && new Date(time).toISOString().slice(0, 23) === value.slice(0, 23);
10370
10786
  }
10371
10787
  function parseMember(row, fail) {
10372
- if (!record2(row) || !uuid2(row.membershipId) || !uuid2(row.userId) || typeof row.email !== "string" || !row.email || !(row.displayName === null || typeof row.displayName === "string") || !isRole(row.role) || !timestamp(row.createdAt))
10788
+ 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))
10373
10789
  return fail();
10374
10790
  return {
10375
10791
  membershipId: row.membershipId,
@@ -10389,12 +10805,12 @@ class WorkspaceMemberInputError extends Error {
10389
10805
  }
10390
10806
  }
10391
10807
  function mutationInput(membershipId, input, roleChange) {
10392
- if (typeof membershipId !== "string" || !uuid2(membershipId) || membershipId !== membershipId.toLowerCase() || !record2(input) || Object.keys(input).sort().join(",") !== (roleChange ? "expectedRole,role" : "expectedRole"))
10808
+ if (typeof membershipId !== "string" || !uuid3(membershipId) || membershipId !== membershipId.toLowerCase() || !record3(input) || Object.keys(input).sort().join(",") !== (roleChange ? "expectedRole,role" : "expectedRole"))
10393
10809
  throw new WorkspaceMemberInputError;
10394
- const expectedRole = input.expectedRole, role2 = roleChange ? input.role : undefined;
10395
- if (!isRole(expectedRole) || roleChange && !isRole(role2))
10810
+ const expectedRole = input.expectedRole, role3 = roleChange ? input.role : undefined;
10811
+ if (!isRole(expectedRole) || roleChange && !isRole(role3))
10396
10812
  throw new WorkspaceMemberInputError;
10397
- return { membershipId, role: role2, expectedRole };
10813
+ return { membershipId, role: role3, expectedRole };
10398
10814
  }
10399
10815
  function workspaceMemberRoleInput(membershipId, input) {
10400
10816
  const value = mutationInput(membershipId, input, true);
@@ -10405,19 +10821,19 @@ function workspaceMemberRemovalInput(membershipId, input) {
10405
10821
  return { membershipId: value.membershipId, body: { expectedRole: value.expectedRole } };
10406
10822
  }
10407
10823
  var invalidMemberResult = "The server returned an invalid workspace member result. Refresh the roster before another action.";
10408
- function parseWorkspaceMemberRoleResult(value, membershipId, role2) {
10824
+ function parseWorkspaceMemberRoleResult(value, membershipId, role3) {
10409
10825
  const fail = () => {
10410
10826
  throw new Error(invalidMemberResult);
10411
10827
  };
10412
- if (!record2(value) || !uuid2(value.organizationId) || typeof value.changed !== "boolean")
10828
+ if (!record3(value) || !uuid3(value.organizationId) || typeof value.changed !== "boolean")
10413
10829
  return fail();
10414
10830
  const member = parseMember(value.member, fail);
10415
- if (member.membershipId !== membershipId || member.role !== role2)
10831
+ if (member.membershipId !== membershipId || member.role !== role3)
10416
10832
  return fail();
10417
10833
  return { organizationId: value.organizationId, member, changed: value.changed };
10418
10834
  }
10419
10835
  function parseWorkspaceMemberRemovalResult(value, membershipId) {
10420
- if (!record2(value) || !uuid2(value.organizationId) || value.membershipId !== membershipId || value.removed !== true || typeof value.alreadyRemoved !== "boolean")
10836
+ if (!record3(value) || !uuid3(value.organizationId) || value.membershipId !== membershipId || value.removed !== true || typeof value.alreadyRemoved !== "boolean")
10421
10837
  throw new Error(invalidMemberResult);
10422
10838
  return { organizationId: value.organizationId, membershipId, removed: true, alreadyRemoved: value.alreadyRemoved };
10423
10839
  }
@@ -10434,7 +10850,7 @@ var workspaceMemberFailures = {
10434
10850
  MEMBERSHIP_BUSY: [503, "Membership is busy. Refresh the roster before another action."]
10435
10851
  };
10436
10852
  function workspaceMemberFailure(value, status) {
10437
- if (!record2(value) || typeof value.code !== "string" || !Object.hasOwn(workspaceMemberFailures, value.code))
10853
+ if (!record3(value) || typeof value.code !== "string" || !Object.hasOwn(workspaceMemberFailures, value.code))
10438
10854
  return null;
10439
10855
  const code = value.code;
10440
10856
  return workspaceMemberFailures[code][0] === status ? code : null;
@@ -10443,7 +10859,7 @@ function parseWorkspaceMembersPage(value) {
10443
10859
  const fail = () => {
10444
10860
  throw new Error("The server returned an invalid workspace roster.");
10445
10861
  };
10446
- if (!record2(value) || !uuid2(value.organizationId) || !Array.isArray(value.members) || value.members.length > 100 || !(value.nextCursor === null || cursor(value.nextCursor)) || !value.members.length && value.nextCursor !== null)
10862
+ 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)
10447
10863
  return fail();
10448
10864
  const members = value.members.map((row) => parseMember(row, fail));
10449
10865
  if (new Set(members.map((row) => row.membershipId)).size !== members.length)
@@ -10517,44 +10933,44 @@ function getApiUrl(action, env = process.env, options = {}) {
10517
10933
  // src/lib/remote-run-contract.ts
10518
10934
  var REMOTE_SKILL_RUN_CONTRACT_VERSION = 1;
10519
10935
  function normalizeRemoteSkillRunContract(payload, fallbackSkill) {
10520
- const record3 = isRecord3(payload) ? payload : {};
10936
+ const record4 = isRecord3(payload) ? payload : {};
10521
10937
  return {
10522
10938
  contractVersion: REMOTE_SKILL_RUN_CONTRACT_VERSION,
10523
- ...pickString(record3, "id"),
10524
- skill: pickStringValue(record3, "skill") ?? fallbackSkill,
10525
- ...pickString(record3, "requestedSlug"),
10526
- ...pickString(record3, "status"),
10527
- ...pickNumber(record3, "exitCode"),
10528
- ...pickString(record3, "correlationId"),
10529
- ...pickString(record3, "createdAt"),
10530
- ...pickString(record3, "startedAt"),
10531
- ...pickString(record3, "completedAt"),
10532
- ...pickNumber(record3, "durationMs"),
10533
- ...pickString(record3, "outputType"),
10534
- ...hasOwn(record3, "outputPreview") ? { outputPreview: record3.outputPreview } : {},
10535
- ...pickString(record3, "errorCode"),
10536
- ...pickString(record3, "errorMessage"),
10537
- ...pickString(record3, "error"),
10538
- ...pickString(record3, "code"),
10539
- ...hasOwn(record3, "details") ? { details: record3.details } : {}
10939
+ ...pickString(record4, "id"),
10940
+ skill: pickStringValue(record4, "skill") ?? fallbackSkill,
10941
+ ...pickString(record4, "requestedSlug"),
10942
+ ...pickString(record4, "status"),
10943
+ ...pickNumber(record4, "exitCode"),
10944
+ ...pickString(record4, "correlationId"),
10945
+ ...pickString(record4, "createdAt"),
10946
+ ...pickString(record4, "startedAt"),
10947
+ ...pickString(record4, "completedAt"),
10948
+ ...pickNumber(record4, "durationMs"),
10949
+ ...pickString(record4, "outputType"),
10950
+ ...hasOwn(record4, "outputPreview") ? { outputPreview: record4.outputPreview } : {},
10951
+ ...pickString(record4, "errorCode"),
10952
+ ...pickString(record4, "errorMessage"),
10953
+ ...pickString(record4, "error"),
10954
+ ...pickString(record4, "code"),
10955
+ ...hasOwn(record4, "details") ? { details: record4.details } : {}
10540
10956
  };
10541
10957
  }
10542
10958
  function isRecord3(value) {
10543
10959
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
10544
10960
  }
10545
- function hasOwn(record3, key) {
10546
- return Object.prototype.hasOwnProperty.call(record3, key);
10961
+ function hasOwn(record4, key) {
10962
+ return Object.prototype.hasOwnProperty.call(record4, key);
10547
10963
  }
10548
- function pickString(record3, key) {
10549
- const value = pickStringValue(record3, key);
10964
+ function pickString(record4, key) {
10965
+ const value = pickStringValue(record4, key);
10550
10966
  return value === undefined ? {} : { [key]: value };
10551
10967
  }
10552
- function pickStringValue(record3, key) {
10553
- const value = record3[key];
10968
+ function pickStringValue(record4, key) {
10969
+ const value = record4[key];
10554
10970
  return typeof value === "string" ? value : undefined;
10555
10971
  }
10556
- function pickNumber(record3, key) {
10557
- const value = record3[key];
10972
+ function pickNumber(record4, key) {
10973
+ const value = record4[key];
10558
10974
  return typeof value === "number" && Number.isFinite(value) ? { [key]: value } : {};
10559
10975
  }
10560
10976
 
@@ -10724,6 +11140,69 @@ function parseUpdatedWorkspace(value) {
10724
11140
  return { organization: { id: organization2.id, slug: organization2.slug, name: organization2.name } };
10725
11141
  }
10726
11142
 
11143
+ // src/lib/remote-quote-errors.ts
11144
+ var quoteUnavailableMessages = Object.freeze({
11145
+ HOSTED_PROVIDER_UNAVAILABLE: "Hosted execution is temporarily unavailable on this Skills instance.",
11146
+ HOSTED_CONNECTORS_UNAVAILABLE: "Hosted connector execution is unavailable on this Skills instance.",
11147
+ SKILL_IMPLEMENTATION_UNAVAILABLE: "This skill has no hosted execution implementation.",
11148
+ HOSTED_PRICING_UNAVAILABLE: "Hosted execution is unavailable while this skill's pricing is reviewed.",
11149
+ RUNTIME_ALLOWLIST_REQUIRED: "Hosted execution is unavailable until this Skills instance enables its skill catalog.",
11150
+ RUNTIME_SKILL_NOT_ALLOWED: "This skill is not enabled for hosted execution on this Skills instance."
11151
+ });
11152
+ async function readQuoteUnavailableCode(response) {
11153
+ const maximum = 16 * 1024;
11154
+ const length = response.headers.get("content-length");
11155
+ if (response.status !== 503 || response.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase() !== "application/json" || length !== null && (!/^\d+$/.test(length) || Number(length) > maximum)) {
11156
+ response.body?.cancel().catch(() => {});
11157
+ return null;
11158
+ }
11159
+ const reader = response.body?.getReader();
11160
+ if (!reader)
11161
+ return null;
11162
+ let timer;
11163
+ let deadlineExceeded = false;
11164
+ const expired = Symbol("quote body deadline");
11165
+ const deadline = new Promise((resolve2) => {
11166
+ timer = setTimeout(() => {
11167
+ deadlineExceeded = true;
11168
+ resolve2(expired);
11169
+ reader.cancel().catch(() => {});
11170
+ }, 1500);
11171
+ });
11172
+ const chunks = [];
11173
+ let size = 0;
11174
+ try {
11175
+ while (true) {
11176
+ const next = await Promise.race([reader.read(), deadline]);
11177
+ if (next === expired || deadlineExceeded)
11178
+ return null;
11179
+ if (next.done)
11180
+ break;
11181
+ size += next.value.byteLength;
11182
+ if (size > maximum)
11183
+ return null;
11184
+ chunks.push(next.value);
11185
+ }
11186
+ const bytes = new Uint8Array(size);
11187
+ let offset = 0;
11188
+ for (const chunk of chunks) {
11189
+ bytes.set(chunk, offset);
11190
+ offset += chunk.byteLength;
11191
+ }
11192
+ const value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
11193
+ if (!value || typeof value !== "object" || Array.isArray(value))
11194
+ return null;
11195
+ const code = value.code;
11196
+ return typeof code === "string" && Object.hasOwn(quoteUnavailableMessages, code) ? code : null;
11197
+ } catch {
11198
+ return null;
11199
+ } finally {
11200
+ clearTimeout(timer);
11201
+ reader.cancel().catch(() => {});
11202
+ reader.releaseLock();
11203
+ }
11204
+ }
11205
+
10727
11206
  // src/lib/remote-client.ts
10728
11207
  class RemoteRouteUnsupportedError extends Error {
10729
11208
  path;
@@ -10749,6 +11228,18 @@ class RemoteRequestError extends Error {
10749
11228
  }
10750
11229
  }
10751
11230
 
11231
+ class RemoteQuoteUnavailableError extends RemoteRequestError {
11232
+ code;
11233
+ constructor(path, code) {
11234
+ super(path, 503);
11235
+ this.code = code;
11236
+ if (!Object.hasOwn(quoteUnavailableMessages, code))
11237
+ throw new Error("Unknown quote refusal code");
11238
+ this.name = "RemoteQuoteUnavailableError";
11239
+ this.message = quoteUnavailableMessages[code];
11240
+ }
11241
+ }
11242
+
10752
11243
  class RemoteWorkspaceMemberError extends RemoteRequestError {
10753
11244
  code;
10754
11245
  constructor(path, code) {
@@ -10810,6 +11301,11 @@ class RemoteSkillsClient {
10810
11301
  throw new RemoteRouteUnsupportedError(routePath, response.status, this.apiUrl);
10811
11302
  }
10812
11303
  if (!response.ok) {
11304
+ if (opts.quoteRefusal && options?.method === "POST" && /^\/api\/v1\/skills\/[^/?#]+\/quote$/.test(routePath) && response.status === 503) {
11305
+ const code = await readQuoteUnavailableCode(response);
11306
+ if (code)
11307
+ throw new RemoteQuoteUnavailableError(routePath, code);
11308
+ }
10813
11309
  if (path === "/api/v1/billing/checkout" && options?.method === "POST" && response.status === 503 && await responseBodyCarriesCode(response, ["SUBSCRIPTION_CHECKOUT_UNAVAILABLE"])) {
10814
11310
  throw new RemoteCapabilityUnavailableError;
10815
11311
  }
@@ -10867,7 +11363,7 @@ class RemoteSkillsClient {
10867
11363
  const response = await this.requestNewRoute(`/api/v1/skills/${encodeURIComponent(slug)}/quote`, {
10868
11364
  method: "POST",
10869
11365
  body: JSON.stringify({ input, args })
10870
- });
11366
+ }, { quoteRefusal: true });
10871
11367
  return parseRemoteRunQuote(await response.json());
10872
11368
  }
10873
11369
  getCapabilities() {
@@ -11032,6 +11528,53 @@ class RemoteSkillsClient {
11032
11528
  }
11033
11529
  return parseWorkspaceLeaveResult(body, captured.context.membershipId, identity.organization.id);
11034
11530
  }
11531
+ listWorkspaceInvitations(context, options = {}) {
11532
+ return this.requestWorkspaceInvitation(context, "list", options);
11533
+ }
11534
+ getWorkspaceInvitation(context, invitationId) {
11535
+ return this.requestWorkspaceInvitation(context, "get", { invitationId });
11536
+ }
11537
+ issueWorkspaceInvitation(context, input) {
11538
+ return this.requestWorkspaceInvitation(context, "issue", input);
11539
+ }
11540
+ resendWorkspaceInvitation(context, invitationId, input) {
11541
+ return this.requestWorkspaceInvitation(context, "resend", { ...input, invitationId });
11542
+ }
11543
+ revokeWorkspaceInvitation(context, invitationId, input) {
11544
+ return this.requestWorkspaceInvitation(context, "revoke", { ...input, invitationId });
11545
+ }
11546
+ acceptWorkspaceInvitation(context, invitationId, input) {
11547
+ return this.requestWorkspaceInvitation(context, "accept", { ...input, invitationId });
11548
+ }
11549
+ async requestWorkspaceInvitation(context, action, input) {
11550
+ const target = workspaceContext(context), captured = invitationInput(action, input);
11551
+ const connection = new RemoteSkillsClient(this.apiKey, this.apiUrl);
11552
+ const identityValue = await connection.requestWorkspaceSelection("/api/auth/whoami");
11553
+ if (!identityValue || typeof identityValue !== "object" || identityValue.authMethod !== "jwt")
11554
+ throw new RemoteWorkspaceInvitationError("INTERACTIVE_SESSION_REQUIRED");
11555
+ const identity = parseWorkspaceIdentity(identityValue, target.userId);
11556
+ if (identity.user.membershipId !== target.membershipId)
11557
+ throw new WorkspaceIdentityMismatchError;
11558
+ const request = invitationRequest(action, captured), read = action === "list" || action === "get";
11559
+ let response, value;
11560
+ try {
11561
+ response = await connection.request(request.path, { method: request.method, ...request.body ? { body: request.body } : {}, credentials: "omit" });
11562
+ value = JSON.parse(new TextDecoder().decode(await readBoundedResponse(response, response.ok ? 64 * 1024 : 4096)));
11563
+ } catch {
11564
+ throw read ? new RemoteWorkspaceInvitationReadError : new RemoteWorkspaceInvitationUnconfirmedError;
11565
+ }
11566
+ if (!response.ok) {
11567
+ const code = invitationFailure(value, response.status);
11568
+ if (code)
11569
+ throw new RemoteWorkspaceInvitationError(code);
11570
+ throw read ? new RemoteWorkspaceInvitationReadError : new RemoteWorkspaceInvitationUnconfirmedError;
11571
+ }
11572
+ try {
11573
+ return parseInvitationResult(action, value, captured, identity.organization.id);
11574
+ } catch {
11575
+ throw read ? new RemoteWorkspaceInvitationReadError : new RemoteWorkspaceInvitationUnconfirmedError;
11576
+ }
11577
+ }
11035
11578
  async listApiKeys() {
11036
11579
  return this.arrayResponse("/api/auth/keys");
11037
11580
  }
@@ -11282,13 +11825,13 @@ class RemoteSkillsClient {
11282
11825
  return normalizeUpdatedSincePage(await response.json());
11283
11826
  }
11284
11827
  }
11285
- function requireOptionalString(record3, field) {
11286
- if (record3[field] === undefined)
11828
+ function requireOptionalString(record4, field) {
11829
+ if (record4[field] === undefined)
11287
11830
  return;
11288
- if (typeof record3[field] !== "string") {
11831
+ if (typeof record4[field] !== "string") {
11289
11832
  throw new Error(`Remote payload did not match the expected contract (${field} must be a string when present)`);
11290
11833
  }
11291
- return record3[field];
11834
+ return record4[field];
11292
11835
  }
11293
11836
  var INVALID_SKILL_VERSION_RESPONSE = "Remote skill version payload did not match the expected contract.";
11294
11837
  function isVersionRecord(value) {
@@ -11311,19 +11854,19 @@ function normalizePin(entry) {
11311
11854
  if (!entry || typeof entry !== "object") {
11312
11855
  throw new Error("Remote pin payload did not match the expected contract (expected an object)");
11313
11856
  }
11314
- const record3 = entry;
11315
- const slug = typeof record3.slug === "string" && record3.slug.trim() ? record3.slug.trim() : undefined;
11857
+ const record4 = entry;
11858
+ const slug = typeof record4.slug === "string" && record4.slug.trim() ? record4.slug.trim() : undefined;
11316
11859
  if (!slug) {
11317
11860
  throw new Error("Remote pin payload did not match the expected contract (missing slug)");
11318
11861
  }
11319
11862
  let metadata;
11320
- if (record3.metadata !== undefined) {
11321
- if (!record3.metadata || typeof record3.metadata !== "object" || Array.isArray(record3.metadata)) {
11863
+ if (record4.metadata !== undefined) {
11864
+ if (!record4.metadata || typeof record4.metadata !== "object" || Array.isArray(record4.metadata)) {
11322
11865
  throw new Error("Remote pin payload did not match the expected contract (metadata must be a JSON object when present)");
11323
11866
  }
11324
- metadata = record3.metadata;
11867
+ metadata = record4.metadata;
11325
11868
  }
11326
- const pinnedAt = requireOptionalString(record3, "pinnedAt");
11869
+ const pinnedAt = requireOptionalString(record4, "pinnedAt");
11327
11870
  return {
11328
11871
  slug,
11329
11872
  ...pinnedAt !== undefined ? { pinnedAt } : {},
@@ -11340,16 +11883,16 @@ function normalizeSkillSummary(entry) {
11340
11883
  if (!entry || typeof entry !== "object") {
11341
11884
  throw new Error("Remote skill payload did not match the expected contract (expected an object)");
11342
11885
  }
11343
- const record3 = entry;
11344
- const slug = typeof record3.slug === "string" && record3.slug.trim() ? record3.slug.trim() : undefined;
11886
+ const record4 = entry;
11887
+ const slug = typeof record4.slug === "string" && record4.slug.trim() ? record4.slug.trim() : undefined;
11345
11888
  if (!slug) {
11346
11889
  throw new Error("Remote skill payload did not match the expected contract (missing slug)");
11347
11890
  }
11348
11891
  return {
11349
11892
  slug,
11350
- ...requireOptionalString(record3, "name") !== undefined ? { name: requireOptionalString(record3, "name") } : {},
11351
- ...requireOptionalString(record3, "version") !== undefined ? { version: requireOptionalString(record3, "version") } : {},
11352
- ...requireOptionalString(record3, "updatedAt") !== undefined ? { updatedAt: requireOptionalString(record3, "updatedAt") } : {}
11893
+ ...requireOptionalString(record4, "name") !== undefined ? { name: requireOptionalString(record4, "name") } : {},
11894
+ ...requireOptionalString(record4, "version") !== undefined ? { version: requireOptionalString(record4, "version") } : {},
11895
+ ...requireOptionalString(record4, "updatedAt") !== undefined ? { updatedAt: requireOptionalString(record4, "updatedAt") } : {}
11353
11896
  };
11354
11897
  }
11355
11898
  function normalizeSkillSummaryList(payload) {
@@ -11402,12 +11945,12 @@ function normalizeUpdatedSincePage(payload) {
11402
11945
  if (!payload || typeof payload !== "object") {
11403
11946
  throw new Error("Updated-since payload did not match the expected contract (expected an object)");
11404
11947
  }
11405
- const record3 = payload;
11406
- if (!Array.isArray(record3.skills)) {
11948
+ const record4 = payload;
11949
+ if (!Array.isArray(record4.skills)) {
11407
11950
  throw new Error("Updated-since payload did not match the expected contract (missing skills array)");
11408
11951
  }
11409
- const skills = record3.skills.map(normalizeSkillSummary);
11410
- const nextCursor = record3.nextCursor === undefined || record3.nextCursor === null ? null : record3.nextCursor;
11952
+ const skills = record4.skills.map(normalizeSkillSummary);
11953
+ const nextCursor = record4.nextCursor === undefined || record4.nextCursor === null ? null : record4.nextCursor;
11411
11954
  if (nextCursor !== null && typeof nextCursor !== "string") {
11412
11955
  throw new Error("Updated-since payload did not match the expected contract (nextCursor must be a string or absent)");
11413
11956
  }
@@ -11621,10 +12164,6 @@ function recordScheduleRun(id, status, targetDir) {
11621
12164
  schedule.nextRun = getNextRun(schedule.cron, now)?.toISOString();
11622
12165
  saveSchedules(data, targetDir);
11623
12166
  }
11624
- // src/lib/pull.ts
11625
- import { existsSync as existsSync15, mkdirSync as mkdirSync8, mkdtempSync as mkdtempSync3, readFileSync as readFileSync15, renameSync as renameSync3, rmSync as rmSync4, writeFileSync as writeFileSync8 } from "fs";
11626
- import { dirname as dirname6, join as join17 } from "path";
11627
-
11628
12167
  // src/lib/revision.ts
11629
12168
  import { createHash as createHash4 } from "crypto";
11630
12169
  var REVISION_ID_PATTERN = /^[0-9a-f]{64}$/;
@@ -11644,14 +12183,18 @@ function revisionIdOf(content) {
11644
12183
  });
11645
12184
  return createHash4("sha256").update(canonical).digest("hex");
11646
12185
  }
11647
- function revisionIdOfRecord(record3) {
11648
- return revisionIdOf(record3);
12186
+ function revisionIdOfRecord(record4) {
12187
+ return revisionIdOf(record4);
11649
12188
  }
12189
+ // src/lib/pull.ts
12190
+ import { existsSync as existsSync15, mkdirSync as mkdirSync8, mkdtempSync as mkdtempSync3, readFileSync as readFileSync15, renameSync as renameSync3, rmSync as rmSync4, writeFileSync as writeFileSync8 } from "fs";
12191
+ import { dirname as dirname6, join as join17 } from "path";
11650
12192
 
11651
12193
  // src/lib/skill-bundle.ts
11652
12194
  import { createHash as createHash5 } from "crypto";
11653
12195
  import { readFileSync as readFileSync14, readdirSync as readdirSync9, statSync as statSync9 } from "fs";
11654
12196
  import { join as join16, relative as relative3 } from "path";
12197
+ import { createGunzip } from "zlib";
11655
12198
  var BLOCK = 512;
11656
12199
  var ANY_SEGMENT_EXCLUDES = new Set([
11657
12200
  ".git",
@@ -11974,6 +12517,227 @@ function concat(chunks) {
11974
12517
  }
11975
12518
  return merged;
11976
12519
  }
12520
+ var SKILL_BUNDLE_INSPECTION_LIMITS = Object.freeze({
12521
+ compressedBytes: 16 * 1024 * 1024,
12522
+ decompressedBytes: 64 * 1024 * 1024,
12523
+ entries: 1024,
12524
+ fileBytes: 16 * 1024 * 1024,
12525
+ pathBytes: 100,
12526
+ timeoutMs: 5000
12527
+ });
12528
+
12529
+ class SkillBundleInspectionError extends Error {
12530
+ code;
12531
+ constructor(code, message) {
12532
+ super(message);
12533
+ this.code = code;
12534
+ this.name = "SkillBundleInspectionError";
12535
+ }
12536
+ }
12537
+ function invalidBundle(message) {
12538
+ throw new SkillBundleInspectionError("BUNDLE_INVALID", message);
12539
+ }
12540
+ function inspectionLimits(options) {
12541
+ const limits = { ...SKILL_BUNDLE_INSPECTION_LIMITS };
12542
+ for (const key of Object.keys(options.limits ?? {})) {
12543
+ if (!Object.hasOwn(limits, key))
12544
+ throw new SkillBundleInspectionError("BUNDLE_LIMIT", "Unknown bundle limit");
12545
+ const field = key;
12546
+ const value = options.limits[field];
12547
+ if (!Number.isSafeInteger(value) || value <= 0 || value > limits[field]) {
12548
+ throw new SkillBundleInspectionError("BUNDLE_LIMIT", "Bundle limits must be positive integers within the hard ceilings");
12549
+ }
12550
+ limits[field] = value;
12551
+ }
12552
+ return limits;
12553
+ }
12554
+ async function inspectSkillBundle(bundle, options = {}) {
12555
+ const signal = options.signal;
12556
+ const limits = inspectionLimits(options);
12557
+ const deadline = performance.now() + limits.timeoutMs;
12558
+ const check = () => {
12559
+ if (signal?.aborted)
12560
+ throw new SkillBundleInspectionError("BUNDLE_ABORTED", "Bundle inspection aborted");
12561
+ if (performance.now() >= deadline)
12562
+ throw new SkillBundleInspectionError("BUNDLE_TIMEOUT", "Bundle inspection deadline exceeded");
12563
+ };
12564
+ check();
12565
+ if (bundle.byteLength > limits.compressedBytes)
12566
+ throw new SkillBundleInspectionError("BUNDLE_LIMIT", "Compressed bundle exceeds byte limit");
12567
+ const snapshot = ownBytes(bundle);
12568
+ check();
12569
+ const sha2562 = sha256Hex(snapshot);
12570
+ check();
12571
+ const parser = new BoundedTarReader(limits, check);
12572
+ const streamOptions = { chunkSize: 16 * 1024, highWaterMark: 16 * 1024 };
12573
+ const decoder = createGunzip(streamOptions);
12574
+ let terminalError;
12575
+ const stop = (code) => {
12576
+ terminalError ??= new SkillBundleInspectionError(code, code === "BUNDLE_ABORTED" ? "Bundle inspection aborted" : "Bundle inspection deadline exceeded");
12577
+ decoder.destroy(terminalError);
12578
+ };
12579
+ const onAbort = () => stop("BUNDLE_ABORTED");
12580
+ const timer = setTimeout(() => stop("BUNDLE_TIMEOUT"), Math.max(1, deadline - performance.now()));
12581
+ signal?.addEventListener("abort", onAbort, { once: true });
12582
+ let decompressedByteSize = 0;
12583
+ let bytesSinceYield = 0;
12584
+ try {
12585
+ check();
12586
+ decoder.end(snapshot);
12587
+ for await (const chunk of decoder) {
12588
+ check();
12589
+ decompressedByteSize += chunk.byteLength;
12590
+ if (decompressedByteSize > limits.decompressedBytes)
12591
+ throw new SkillBundleInspectionError("BUNDLE_LIMIT", "Decompressed bundle exceeds byte limit");
12592
+ parser.push(chunk);
12593
+ bytesSinceYield += chunk.byteLength;
12594
+ if (bytesSinceYield >= 256 * 1024) {
12595
+ await new Promise((resolve2) => setTimeout(resolve2, 0));
12596
+ bytesSinceYield = 0;
12597
+ check();
12598
+ }
12599
+ }
12600
+ check();
12601
+ const entries = parser.finish();
12602
+ return {
12603
+ entries,
12604
+ sha256: sha2562,
12605
+ compressedByteSize: snapshot.byteLength,
12606
+ decompressedByteSize,
12607
+ unpackedByteSize: parser.fileBytes,
12608
+ fileCount: entries.length
12609
+ };
12610
+ } catch (error) {
12611
+ if (terminalError)
12612
+ throw terminalError;
12613
+ if (error instanceof SkillBundleInspectionError)
12614
+ throw error;
12615
+ throw new SkillBundleInspectionError("BUNDLE_INVALID", "Invalid or truncated gzip bundle");
12616
+ } finally {
12617
+ clearTimeout(timer);
12618
+ signal?.removeEventListener("abort", onAbort);
12619
+ decoder.destroy();
12620
+ }
12621
+ }
12622
+
12623
+ class BoundedTarReader {
12624
+ limits;
12625
+ check;
12626
+ header = new Uint8Array(BLOCK);
12627
+ headerOffset = 0;
12628
+ pending;
12629
+ bodyOffset = 0;
12630
+ padding = 0;
12631
+ zeroBlocks = 0;
12632
+ entries = [];
12633
+ paths = new SkillEntryPaths;
12634
+ fileBytes = 0;
12635
+ constructor(limits, check) {
12636
+ this.limits = limits;
12637
+ this.check = check;
12638
+ }
12639
+ push(chunk) {
12640
+ let offset = 0;
12641
+ while (offset < chunk.byteLength) {
12642
+ this.check();
12643
+ if (this.pending) {
12644
+ const count = Math.min(this.pending.bytes.byteLength - this.bodyOffset, chunk.byteLength - offset);
12645
+ this.pending.bytes.set(chunk.subarray(offset, offset + count), this.bodyOffset);
12646
+ offset += count;
12647
+ this.bodyOffset += count;
12648
+ if (this.bodyOffset === this.pending.bytes.byteLength) {
12649
+ this.entries.push(this.pending);
12650
+ this.pending = undefined;
12651
+ }
12652
+ } else if (this.padding) {
12653
+ const count = Math.min(this.padding, chunk.byteLength - offset);
12654
+ if (chunk.subarray(offset, offset + count).some((byte) => byte !== 0))
12655
+ invalidBundle("Nonzero tar body padding");
12656
+ offset += count;
12657
+ this.padding -= count;
12658
+ } else {
12659
+ const count = Math.min(BLOCK - this.headerOffset, chunk.byteLength - offset);
12660
+ this.header.set(chunk.subarray(offset, offset + count), this.headerOffset);
12661
+ offset += count;
12662
+ this.headerOffset += count;
12663
+ if (this.headerOffset === BLOCK) {
12664
+ this.readHeader();
12665
+ this.headerOffset = 0;
12666
+ }
12667
+ }
12668
+ }
12669
+ }
12670
+ finish() {
12671
+ this.check();
12672
+ if (this.pending || this.padding || this.headerOffset || this.zeroBlocks < 2)
12673
+ invalidBundle("Truncated tar bundle");
12674
+ return this.entries;
12675
+ }
12676
+ readHeader() {
12677
+ this.check();
12678
+ const h = this.header;
12679
+ if (h.every((byte) => byte === 0)) {
12680
+ this.zeroBlocks++;
12681
+ return;
12682
+ }
12683
+ if (this.zeroBlocks)
12684
+ invalidBundle("Nonzero tar data after terminator");
12685
+ if (this.entries.length >= this.limits.entries)
12686
+ throw new SkillBundleInspectionError("BUNDLE_LIMIT", "Bundle entry limit exceeded");
12687
+ let checksum = 0;
12688
+ for (let i = 0;i < BLOCK; i++)
12689
+ checksum += i >= 148 && i < 156 ? 32 : h[i];
12690
+ if (tarOctal(h.subarray(148, 156)) !== checksum)
12691
+ invalidBundle("Invalid tar header checksum");
12692
+ if (new TextDecoder().decode(h.subarray(257, 265)) !== "ustar\x00" + "00")
12693
+ invalidBundle("Unsupported tar format");
12694
+ if (h[156] !== 48 && h[156] !== 0 || h.subarray(157, 257).some((b) => b !== 0) || h.subarray(345).some((b) => b !== 0))
12695
+ invalidBundle("Unsupported tar entry or path prefix");
12696
+ const mode = tarOctal(h.subarray(100, 108));
12697
+ if (mode > 511)
12698
+ invalidBundle("Unsupported tar permission bits");
12699
+ tarOctal(h.subarray(108, 116));
12700
+ tarOctal(h.subarray(116, 124));
12701
+ tarOctal(h.subarray(136, 148));
12702
+ const size = tarOctal(h.subarray(124, 136));
12703
+ if (size > this.limits.fileBytes || this.fileBytes + size > this.limits.decompressedBytes) {
12704
+ throw new SkillBundleInspectionError("BUNDLE_LIMIT", "Bundle file byte limit exceeded");
12705
+ }
12706
+ const name = h.subarray(0, 100);
12707
+ const end = name.indexOf(0);
12708
+ if (end !== -1 && name.subarray(end).some((b) => b !== 0))
12709
+ invalidBundle("Invalid tar path padding");
12710
+ const raw = end === -1 ? name : name.subarray(0, end);
12711
+ if (raw.byteLength > this.limits.pathBytes)
12712
+ throw new SkillBundleInspectionError("BUNDLE_LIMIT", "Bundle path byte limit exceeded");
12713
+ let path;
12714
+ try {
12715
+ path = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(raw);
12716
+ } catch {
12717
+ return invalidBundle("Invalid UTF-8 bundle path");
12718
+ }
12719
+ this.paths.add(path, this.limits.pathBytes, invalidBundle, () => {
12720
+ throw new SkillBundleInspectionError("BUNDLE_LIMIT", "Bundle path byte limit exceeded");
12721
+ });
12722
+ this.fileBytes += size;
12723
+ this.pending = { path, mode, bytes: new Uint8Array(new ArrayBuffer(size)) };
12724
+ this.bodyOffset = 0;
12725
+ this.padding = (BLOCK - size % BLOCK) % BLOCK;
12726
+ if (!size) {
12727
+ this.entries.push(this.pending);
12728
+ this.pending = undefined;
12729
+ }
12730
+ }
12731
+ }
12732
+ function tarOctal(field) {
12733
+ const text2 = new TextDecoder().decode(field);
12734
+ if (!/^[0-7]+[\0 ]*$/.test(text2))
12735
+ invalidBundle("Invalid tar octal field");
12736
+ const value = Number.parseInt(text2, 8);
12737
+ if (!Number.isSafeInteger(value))
12738
+ invalidBundle("Tar integer is out of range");
12739
+ return value;
12740
+ }
11977
12741
 
11978
12742
  // src/lib/skill-version.ts
11979
12743
  var SKILL_VERSION_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/;
@@ -12352,16 +13116,16 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
12352
13116
  }
12353
13117
  return { path: target, created };
12354
13118
  }
12355
- function writePullMarker(dir, record3) {
13119
+ function writePullMarker(dir, record4) {
12356
13120
  const marker = {
12357
13121
  managedBy: "@hasna/skills",
12358
- skill: record3.skill,
12359
- source: record3.source ?? "pull",
12360
- ...record3.version ? { version: record3.version } : {},
12361
- ...record3.contentHash ? { contentHash: record3.contentHash } : {},
12362
- ...record3.sourceCommit ? { sourceCommit: record3.sourceCommit } : {},
12363
- ...record3.signature ? { signature: record3.signature } : {},
12364
- ...record3.revisionId ? { revisionId: record3.revisionId } : {},
13122
+ skill: record4.skill,
13123
+ source: record4.source ?? "pull",
13124
+ ...record4.version ? { version: record4.version } : {},
13125
+ ...record4.contentHash ? { contentHash: record4.contentHash } : {},
13126
+ ...record4.sourceCommit ? { sourceCommit: record4.sourceCommit } : {},
13127
+ ...record4.signature ? { signature: record4.signature } : {},
13128
+ ...record4.revisionId ? { revisionId: record4.revisionId } : {},
12365
13129
  syncedAt: new Date().toISOString()
12366
13130
  };
12367
13131
  writeFileSync8(join17(dir, PULL_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
@@ -12376,19 +13140,19 @@ async function safeMeta(client, slug) {
12376
13140
  }
12377
13141
  if (!raw || typeof raw !== "object")
12378
13142
  return null;
12379
- const record3 = raw;
12380
- const kind = record3.kind === "instruction" || record3.kind === "executable" ? record3.kind : undefined;
12381
- const tags = Array.isArray(record3.tags) ? record3.tags.filter((tag) => typeof tag === "string" && tag.trim().length > 0) : undefined;
13143
+ const record4 = raw;
13144
+ const kind = record4.kind === "instruction" || record4.kind === "executable" ? record4.kind : undefined;
13145
+ const tags = Array.isArray(record4.tags) ? record4.tags.filter((tag) => typeof tag === "string" && tag.trim().length > 0) : undefined;
12382
13146
  return {
12383
- ...str(record3.displayName) ? { displayName: str(record3.displayName) } : {},
12384
- ...str(record3.description) ? { description: str(record3.description) } : {},
12385
- ...str(record3.category) ? { category: str(record3.category) } : {},
13147
+ ...str(record4.displayName) ? { displayName: str(record4.displayName) } : {},
13148
+ ...str(record4.description) ? { description: str(record4.description) } : {},
13149
+ ...str(record4.category) ? { category: str(record4.category) } : {},
12386
13150
  ...tags && tags.length ? { tags } : {},
12387
- ...str(record3.version) ? { version: str(record3.version) } : {},
13151
+ ...str(record4.version) ? { version: str(record4.version) } : {},
12388
13152
  ...kind ? { kind } : {},
12389
- ...REVISION_ID_PATTERN.test(str(record3.revisionId) ?? "") ? { revisionId: str(record3.revisionId) } : {},
12390
- ...typeof record3.skillMd === "string" && record3.skillMd.length > 0 ? { skillMd: record3.skillMd } : {},
12391
- ...str(record3.publishedSource) ? { publishedSource: str(record3.publishedSource) } : {}
13153
+ ...REVISION_ID_PATTERN.test(str(record4.revisionId) ?? "") ? { revisionId: str(record4.revisionId) } : {},
13154
+ ...typeof record4.skillMd === "string" && record4.skillMd.length > 0 ? { skillMd: record4.skillMd } : {},
13155
+ ...str(record4.publishedSource) ? { publishedSource: str(record4.publishedSource) } : {}
12392
13156
  };
12393
13157
  }
12394
13158
  function pickCorpusOptions(options) {
@@ -12397,8 +13161,8 @@ function pickCorpusOptions(options) {
12397
13161
  function extractSlug(entry) {
12398
13162
  if (!entry || typeof entry !== "object")
12399
13163
  return;
12400
- const record3 = entry;
12401
- return str(record3.slug) ?? str(record3.name);
13164
+ const record4 = entry;
13165
+ return str(record4.slug) ?? str(record4.name);
12402
13166
  }
12403
13167
  function dedupe(values) {
12404
13168
  return [...new Set(values)];
@@ -12524,7 +13288,7 @@ import { dirname as dirname7, relative as relative4 } from "path";
12524
13288
  // package.json
12525
13289
  var package_default = {
12526
13290
  name: "@hasna/skills",
12527
- version: "0.5.2",
13291
+ version: "0.5.4",
12528
13292
  description: "Skills library for AI coding agents",
12529
13293
  type: "module",
12530
13294
  bin: {
@@ -14035,7 +14799,7 @@ class SkillsPostgresSyncStore {
14035
14799
  }
14036
14800
  async upsertRecords(records) {
14037
14801
  let count = 0;
14038
- for (const record3 of records) {
14802
+ for (const record4 of records) {
14039
14803
  await this.client.query([
14040
14804
  "INSERT INTO skills_sync_records",
14041
14805
  "(scope, kind, id, updated_at, deleted_at, source, payload)",
@@ -14046,13 +14810,13 @@ class SkillsPostgresSyncStore {
14046
14810
  "source = EXCLUDED.source,",
14047
14811
  "payload = EXCLUDED.payload"
14048
14812
  ].join(" "), [
14049
- record3.scope,
14050
- record3.kind,
14051
- record3.id,
14052
- record3.updatedAt,
14053
- record3.deletedAt ?? null,
14054
- record3.source ?? null,
14055
- JSON.stringify(record3.payload)
14813
+ record4.scope,
14814
+ record4.kind,
14815
+ record4.id,
14816
+ record4.updatedAt,
14817
+ record4.deletedAt ?? null,
14818
+ record4.source ?? null,
14819
+ JSON.stringify(record4.payload)
14056
14820
  ]);
14057
14821
  count += 1;
14058
14822
  }
@@ -14994,6 +15758,101 @@ function writeStationHydration(options) {
14994
15758
  manifestPath: hydrationManifestPath
14995
15759
  };
14996
15760
  }
15761
+ // src/lib/remote-invitation-recovery.ts
15762
+ class InvitationEmailInputError extends Error {
15763
+ code = "INVITATION_EMAIL_INPUT_INVALID";
15764
+ constructor() {
15765
+ super("Use an explicit Skills API URL, exact invitation and retained challenge IDs, secret input, and deliberate confirmation.");
15766
+ this.name = "InvitationEmailInputError";
15767
+ }
15768
+ }
15769
+ var refusals = {
15770
+ INVALID_REQUEST: [400, "Invitation recovery parameters were refused."],
15771
+ ORIGIN_REQUIRED: [403, "Invitation recovery requires the configured site origin."],
15772
+ INVITATION_PROOF_UNAVAILABLE: [401, "Invitation proof is unavailable. Sign in or explicitly request another recovery code."],
15773
+ RATE_LIMITED: [429, "Invitation verification is rate limited. Wait before another deliberate action."],
15774
+ INVITATION_BUSY: [503, "Invitation is busy. Sign in to check membership before another deliberate action."],
15775
+ INVITATION_DELIVERY_UNAVAILABLE: [503, "Invitation recovery is unavailable on this service."]
15776
+ };
15777
+
15778
+ class RemoteInvitationEmailError extends Error {
15779
+ code;
15780
+ status;
15781
+ constructor(code) {
15782
+ super(refusals[code][1]);
15783
+ this.code = code;
15784
+ this.name = "RemoteInvitationEmailError";
15785
+ this.status = refusals[code][0];
15786
+ }
15787
+ }
15788
+
15789
+ class RemoteInvitationEmailUnconfirmedError extends Error {
15790
+ action;
15791
+ code = "INVITATION_EMAIL_UNCONFIRMED";
15792
+ constructor(action) {
15793
+ 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.");
15794
+ this.action = action;
15795
+ this.name = "RemoteInvitationEmailUnconfirmedError";
15796
+ }
15797
+ }
15798
+ var record4 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
15799
+ var uuid4 = (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);
15800
+ function invitationEmailIds(invitationId, challengeId) {
15801
+ if (!uuid4(invitationId) || !uuid4(challengeId))
15802
+ throw new InvitationEmailInputError;
15803
+ return { invitationId, challengeId };
15804
+ }
15805
+ function invitationEmailInput(action, input) {
15806
+ const keys = ["invitationId", "token", "challengeId", "confirm", ...action === "accept" ? ["code"] : []];
15807
+ if (!record4(input) || Object.keys(input).length !== keys.length || keys.some((key) => !Object.hasOwn(input, key)))
15808
+ throw new InvitationEmailInputError;
15809
+ const value = { ...input };
15810
+ const ids = invitationEmailIds(value.invitationId, value.challengeId);
15811
+ 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)))
15812
+ throw new InvitationEmailInputError;
15813
+ return { ...ids, token: value.token, confirm: true, ...action === "accept" ? { code: value.code } : {} };
15814
+ }
15815
+ async function requestInvitationEmail(origin, action, input) {
15816
+ const value = invitationEmailInput(action, input);
15817
+ let target;
15818
+ try {
15819
+ target = normalizeSkillsApiOrigin(origin);
15820
+ } catch {
15821
+ throw new InvitationEmailInputError;
15822
+ }
15823
+ const body = JSON.stringify({ invitationId: value.invitationId, token: value.token, challengeId: value.challengeId, ...action === "accept" ? { code: value.code } : {} });
15824
+ try {
15825
+ const response = await fetch(`${target}/api/v1/account/invitations/email-${action}`, {
15826
+ method: "POST",
15827
+ headers: { "Content-Type": "application/json" },
15828
+ body,
15829
+ credentials: "omit",
15830
+ redirect: "error",
15831
+ cache: "no-store",
15832
+ referrerPolicy: "no-referrer",
15833
+ signal: AbortSignal.timeout(15000)
15834
+ });
15835
+ const parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(await readBoundedResponse(response, 4096)));
15836
+ if (!response.ok && record4(parsed) && typeof parsed.code === "string" && Object.hasOwn(refusals, parsed.code)) {
15837
+ const code = parsed.code;
15838
+ if (response.status === refusals[code][0])
15839
+ throw new RemoteInvitationEmailError(code);
15840
+ }
15841
+ if (!record4(parsed))
15842
+ throw new RemoteInvitationEmailUnconfirmedError(action);
15843
+ if (action === "challenge" && response.status === 202 && parsed.challengeId === value.challengeId && parsed.expiresIn === 600 && typeof parsed.message === "string" && parsed.message.length <= 256) {
15844
+ return { challengeId: value.challengeId, message: "If this invitation is eligible, a verification code will arrive. Delivery is not confirmed.", expiresIn: 600 };
15845
+ }
15846
+ if (action === "accept" && response.status === 200 && uuid4(parsed.organizationId) && uuid4(parsed.membershipId) && parsed.accepted === true && parsed.changed === true && parsed.signInRequired === true) {
15847
+ return { organizationId: parsed.organizationId, membershipId: parsed.membershipId, accepted: true, changed: true, signInRequired: true };
15848
+ }
15849
+ } catch (error) {
15850
+ if (error instanceof RemoteInvitationEmailError)
15851
+ throw error;
15852
+ }
15853
+ throw new RemoteInvitationEmailUnconfirmedError(action);
15854
+ }
15855
+
14997
15856
  // src/lib/remote-auth.ts
14998
15857
  var MAX_ERROR_DETAIL_LENGTH = 200;
14999
15858
 
@@ -15034,10 +15893,10 @@ async function requestAuthApi(instance, path, options) {
15034
15893
  const text2 = await res.text();
15035
15894
  const body = text2 ? parseJsonBody(text2) : {};
15036
15895
  if (!res.ok) {
15037
- const record3 = isRecord5(body) ? body : {};
15038
- const detail = typeof record3.detail === "string" ? record3.detail : undefined;
15039
- const error = typeof record3.error === "string" ? record3.error : undefined;
15040
- const code = typeof record3.code === "string" ? record3.code : undefined;
15896
+ const record5 = isRecord5(body) ? body : {};
15897
+ const detail = typeof record5.detail === "string" ? record5.detail : undefined;
15898
+ const error = typeof record5.error === "string" ? record5.error : undefined;
15899
+ const code = typeof record5.code === "string" ? record5.code : undefined;
15041
15900
  throw new HostedApiError(detail || error || `${res.status} ${res.statusText}`, {
15042
15901
  status: res.status,
15043
15902
  code,
@@ -15071,11 +15930,17 @@ class RemoteSkillsAuthClient {
15071
15930
  constructor(apiUrl) {
15072
15931
  this.apiOrigin = normalizeSkillsApiOrigin(apiUrl);
15073
15932
  }
15074
- requestCode(email) {
15075
- return this.request("/api/auth/login", { method: "POST", body: JSON.stringify({ email }) });
15933
+ requestInvitationEmailChallenge(input) {
15934
+ return requestInvitationEmail(this.apiOrigin, "challenge", input);
15935
+ }
15936
+ acceptInvitationEmailChallenge(input) {
15937
+ return requestInvitationEmail(this.apiOrigin, "accept", input);
15076
15938
  }
15077
- verifyCode(email, code) {
15078
- return this.request("/api/auth/verify", { method: "POST", body: JSON.stringify({ email, code }) });
15939
+ requestCode(email2) {
15940
+ return this.request("/api/auth/login", { method: "POST", body: JSON.stringify({ email: email2 }) });
15941
+ }
15942
+ verifyCode(email2, code) {
15943
+ return this.request("/api/auth/verify", { method: "POST", body: JSON.stringify({ email: email2, code }) });
15079
15944
  }
15080
15945
  startDevice() {
15081
15946
  return this.request("/api/auth/device/start", { method: "POST", body: JSON.stringify({ client: "skills-sdk" }) });
@@ -15083,34 +15948,34 @@ class RemoteSkillsAuthClient {
15083
15948
  pollDevice(deviceCode) {
15084
15949
  return this.request("/api/auth/device/token", { method: "POST", body: JSON.stringify({ deviceCode }) });
15085
15950
  }
15086
- async sessionClient(email, code, context) {
15951
+ async sessionClient(email2, code, context) {
15087
15952
  if (context !== undefined) {
15088
15953
  const target = workspaceContext(context), apiOrigin2 = this.apiOrigin;
15089
- const session = await this.switchWorkspace(email, code, target);
15954
+ const session = await this.switchWorkspace(email2, code, target);
15090
15955
  return new RemoteSkillsClient(session.token, apiOrigin2);
15091
15956
  }
15092
15957
  const apiOrigin = this.apiOrigin;
15093
- if (!email.includes("@") || !/^\d{6}$/.test(code))
15958
+ if (!email2.includes("@") || !/^\d{6}$/.test(code))
15094
15959
  throw new Error("Fresh email and six-digit verification code are required to manage this account");
15095
- const login = await this.verifyCode(email, code);
15960
+ const login = await this.verifyCode(email2, code);
15096
15961
  if (!login || typeof login.token !== "string" || !login.token)
15097
15962
  throw new Error("The server did not return an authorized account session");
15098
15963
  return new RemoteSkillsClient(login.token, apiOrigin);
15099
15964
  }
15100
- async listAccountWorkspaces(email, code, expectedUserId) {
15101
- const login = await this.workspaceLogin(email, code, expectedUserId);
15965
+ async listAccountWorkspaces(email2, code, expectedUserId) {
15966
+ const login = await this.workspaceLogin(email2, code, expectedUserId);
15102
15967
  const result = await new RemoteSkillsClient(login.token, login.apiOrigin).listAccountWorkspaces(login.userId);
15103
15968
  return { userId: login.userId, ...result };
15104
15969
  }
15105
- async switchWorkspace(email, code, context) {
15970
+ async switchWorkspace(email2, code, context) {
15106
15971
  const target = workspaceContext(context);
15107
- const login = await this.workspaceLogin(email, code, target.userId);
15972
+ const login = await this.workspaceLogin(email2, code, target.userId);
15108
15973
  return new RemoteSkillsClient(login.token, login.apiOrigin).switchWorkspace(target);
15109
15974
  }
15110
- async workspaceLogin(email, code, expectedUserId) {
15975
+ async workspaceLogin(email2, code, expectedUserId) {
15111
15976
  const expected = expectedUserId === undefined ? undefined : workspaceExpectedUserId(expectedUserId);
15112
15977
  const apiOrigin = this.apiOrigin;
15113
- if (typeof email !== "string" || !email.includes("@") || typeof code !== "string" || !/^\d{6}$/.test(code))
15978
+ if (typeof email2 !== "string" || !email2.includes("@") || typeof code !== "string" || !/^\d{6}$/.test(code))
15114
15979
  throw new Error("Fresh email and six-digit verification code are required to manage this account");
15115
15980
  let response;
15116
15981
  try {
@@ -15120,7 +15985,7 @@ class RemoteSkillsAuthClient {
15120
15985
  credentials: "omit",
15121
15986
  signal: AbortSignal.timeout(15000),
15122
15987
  headers: { "Content-Type": "application/json" },
15123
- body: JSON.stringify({ email, code })
15988
+ body: JSON.stringify({ email: email2, code })
15124
15989
  });
15125
15990
  } catch {
15126
15991
  throw new HostedApiError("Unable to verify the Skills account.");
@@ -15137,40 +16002,67 @@ class RemoteSkillsAuthClient {
15137
16002
  }
15138
16003
  return { ...parseWorkspaceLogin(value, expected), apiOrigin };
15139
16004
  }
15140
- async createApiKey(email, code, name, scopes, context) {
16005
+ async listWorkspaceInvitations(email2, code, context, options = {}) {
16006
+ const target = workspaceContext(context), captured = invitationInput("list", options);
16007
+ return (await this.sessionClient(email2, code, target)).listWorkspaceInvitations(target, captured);
16008
+ }
16009
+ async getWorkspaceInvitation(email2, code, context, invitationId) {
16010
+ const target = workspaceContext(context), captured = invitationInput("get", { invitationId });
16011
+ return (await this.sessionClient(email2, code, target)).getWorkspaceInvitation(target, captured.invitationId);
16012
+ }
16013
+ async issueWorkspaceInvitation(email2, code, context, input) {
16014
+ const target = workspaceContext(context), captured = invitationInput("issue", input);
16015
+ return (await this.sessionClient(email2, code, target)).issueWorkspaceInvitation(target, captured);
16016
+ }
16017
+ async resendWorkspaceInvitation(email2, code, context, invitationId, input) {
16018
+ const target = workspaceContext(context), captured = invitationInput("resend", { ...input, invitationId });
16019
+ const { invitationId: id, ...options } = captured;
16020
+ return (await this.sessionClient(email2, code, target)).resendWorkspaceInvitation(target, id, options);
16021
+ }
16022
+ async revokeWorkspaceInvitation(email2, code, context, invitationId, input) {
16023
+ const target = workspaceContext(context), captured = invitationInput("revoke", { ...input, invitationId });
16024
+ const { invitationId: id, ...options } = captured;
16025
+ return (await this.sessionClient(email2, code, target)).revokeWorkspaceInvitation(target, id, options);
16026
+ }
16027
+ async acceptWorkspaceInvitation(email2, code, context, invitationId, input) {
16028
+ const target = workspaceContext(context), captured = invitationInput("accept", { ...input, invitationId });
16029
+ const { invitationId: id, ...options } = captured;
16030
+ return (await this.sessionClient(email2, code, target)).acceptWorkspaceInvitation(target, id, options);
16031
+ }
16032
+ async createApiKey(email2, code, name, scopes, context) {
15141
16033
  const capturedScopes = scopes === undefined ? undefined : [...scopes];
15142
- return (await this.sessionClient(email, code, context)).createApiKey(name, capturedScopes);
16034
+ return (await this.sessionClient(email2, code, context)).createApiKey(name, capturedScopes);
15143
16035
  }
15144
- async listApiKeys(email, code, context) {
15145
- return (await this.sessionClient(email, code, context)).listApiKeys();
16036
+ async listApiKeys(email2, code, context) {
16037
+ return (await this.sessionClient(email2, code, context)).listApiKeys();
15146
16038
  }
15147
- async revokeApiKey(email, code, keyId, context) {
15148
- return (await this.sessionClient(email, code, context)).revokeApiKey(keyId);
16039
+ async revokeApiKey(email2, code, keyId, context) {
16040
+ return (await this.sessionClient(email2, code, context)).revokeApiKey(keyId);
15149
16041
  }
15150
- async updateProfile(email, code, input, context) {
16042
+ async updateProfile(email2, code, input, context) {
15151
16043
  const body = customerNamePatch(input, "displayName");
15152
- return (await this.sessionClient(email, code, context)).updateProfile({ displayName: body.displayName });
16044
+ return (await this.sessionClient(email2, code, context)).updateProfile({ displayName: body.displayName });
15153
16045
  }
15154
- async updateCurrentWorkspace(email, code, input, context) {
16046
+ async updateCurrentWorkspace(email2, code, input, context) {
15155
16047
  const body = customerNamePatch(input, "name");
15156
- return (await this.sessionClient(email, code, context)).updateCurrentWorkspace({ name: body.name });
16048
+ return (await this.sessionClient(email2, code, context)).updateCurrentWorkspace({ name: body.name });
15157
16049
  }
15158
- async listWorkspaceMembers(email, code, options = {}, context) {
16050
+ async listWorkspaceMembers(email2, code, options = {}, context) {
15159
16051
  workspaceMembersQuery(options);
15160
16052
  const captured = { ...options };
15161
- return (await this.sessionClient(email, code, context)).listWorkspaceMembers(captured);
16053
+ return (await this.sessionClient(email2, code, context)).listWorkspaceMembers(captured);
15162
16054
  }
15163
- async setWorkspaceMemberRole(email, code, membershipId, input, context) {
16055
+ async setWorkspaceMemberRole(email2, code, membershipId, input, context) {
15164
16056
  const captured = workspaceMemberRoleInput(membershipId, input);
15165
- return (await this.sessionClient(email, code, context)).setWorkspaceMemberRole(captured.membershipId, captured.body);
16057
+ return (await this.sessionClient(email2, code, context)).setWorkspaceMemberRole(captured.membershipId, captured.body);
15166
16058
  }
15167
- async leaveWorkspace(email, code, context, input) {
16059
+ async leaveWorkspace(email2, code, context, input) {
15168
16060
  const captured = workspaceLeaveInput(context, input);
15169
- return (await this.sessionClient(email, code, captured.context)).leaveWorkspace(captured.context, captured.input);
16061
+ return (await this.sessionClient(email2, code, captured.context)).leaveWorkspace(captured.context, captured.input);
15170
16062
  }
15171
- async removeWorkspaceMember(email, code, membershipId, input, context) {
16063
+ async removeWorkspaceMember(email2, code, membershipId, input, context) {
15172
16064
  const captured = workspaceMemberRemovalInput(membershipId, input);
15173
- return (await this.sessionClient(email, code, context)).removeWorkspaceMember(captured.membershipId, captured.body);
16065
+ return (await this.sessionClient(email2, code, context)).removeWorkspaceMember(captured.membershipId, captured.body);
15174
16066
  }
15175
16067
  request(path, options) {
15176
16068
  if (!["/api/auth/login", "/api/auth/verify", "/api/auth/device/start", "/api/auth/device/token", "/api/auth/keys", "/api/auth/whoami"].includes(path))
@@ -15179,244 +16071,257 @@ class RemoteSkillsAuthClient {
15179
16071
  }
15180
16072
  }
15181
16073
  export {
15182
- writeStationSnapshot,
15183
- writeStationHydration,
15184
- writeRunLogs,
15185
- writeRegistrySyncArtifact,
15186
- writeManagedSkillDir,
15187
- writeManagedAgentSkill,
15188
- writeCorpusSkill,
15189
- walkEntries,
15190
- verifyContentHash,
15191
- validateToolPrimitiveCoverage,
15192
- validateStationId,
15193
- validateSkillsCliMcpParity,
15194
- validateSkillDirectory,
15195
- validateRegistryConsistency,
15196
- validatePortableSkillDirectory,
15197
- validatePortableManifestContract,
15198
- validateCron,
15199
- validateBlogArticleRunOptions,
15200
- uploadSkillsSnapshotFilesToS3,
15201
- updateSkillRun,
15202
- unsetConfig,
15203
- unpinSkill,
15204
- unpinProjectSkill,
15205
- syncSkillsToAgents,
15206
- summarizeMcpToolContract,
15207
- storageCapabilities,
15208
- skillsPostgresSyncSchemaSql,
15209
- skillsCredentialOrReason,
15210
- skillsCredentialFiles,
15211
- skillsCredentialFilePath,
15212
- skillExists,
15213
- signSkillsAwsV4Request,
15214
- sha256File,
15215
- setSkillDisabled,
15216
- setScheduleEnabled,
15217
- selectsSkillsLocalMode,
15218
- searchSkills,
15219
- scaffoldPortableSkill,
15220
- saveProjectConfig,
15221
- saveFeedback,
15222
- saveConfig,
15223
- sanitizePublicDiscoveryText,
15224
- runSkill,
15225
- runPortableSkill,
15226
- resolveSyncAgents,
15227
- resolveStorageConfig,
15228
- resolveSkillsNativeStorageConfig,
15229
- resolveSkillsFleet,
15230
- resolveSkillsApiOrigin,
15231
- resolveSkillsApiKey,
15232
- resolveSkillAlias,
15233
- requireSkillsFleet,
15234
- requireSkillsApiOrigin,
15235
- requireSkillsApiKey,
15236
- removeSkillForAgent,
15237
- removeSkill,
15238
- removeSchedule,
15239
- removeManagedAgentSkill,
15240
- recordScheduleRun,
15241
- readPortableSkillManifest,
15242
- pullSkills,
15243
- publicDiscoveryEnvVars,
15244
- publicDiscoveryDocumentation,
15245
- publicDiscoveryDependencies,
15246
- portPortableSkillDirectory,
15247
- portPortableSkill,
15248
- pointerSkillMd,
15249
- planStationSnapshot,
15250
- planStationHydration,
15251
- planSkillsS3SnapshotUpload,
15252
- pinSkill,
15253
- pinProjectSkill,
15254
- parseSkillFrontmatter,
15255
- parseRemoteSkillPayload,
15256
- parseRemoteRegistryPayload,
15257
- noticeLocalSkillsMode,
15258
- normalizeSkillsApiOrigin,
15259
- normalizeSkillSlug,
15260
- normalizeRemoteSkillRunContract,
15261
- normalizePortableSkillName,
15262
- normalizeLineEndings,
15263
- loadRemoteSkill,
15264
- loadRemoteRegistry,
15265
- loadRegistryProfile,
15266
- loadRegistry,
15267
- loadProjectConfig,
15268
- loadConfig,
15269
- loadBasicRegistry,
15270
- listToolPrimitives,
15271
- listSkillRuns,
15272
- listSchedules,
15273
- listPortableSkills,
15274
- listPortableSkillMetas,
15275
- listPinnedSkills,
15276
- listMcpToolContracts,
15277
- isSyncAgent,
15278
- isSkillsLocalOptIn,
15279
- isRegularFile,
15280
- isPortableWithinSkill,
15281
- isGatewayBackedSkill,
15282
- isExcludedSkillFileName,
15283
- isBasicSkillName,
15284
- installSkills,
15285
- installSkillSource,
15286
- installSkillManifest,
15287
- installSkillForAgent,
15288
- installSkill,
15289
- importSkillsLocalSnapshot,
15290
- homePathFor,
15291
- getToolPrimitive,
15292
- getStorageStatus,
15293
- getStorageDatabaseUrl,
15294
- getStorageDatabaseEnv,
15295
- getSkillsStorageStatus,
15296
- getSkillsStorageDatabaseUrl,
15297
- getSkillsStorageDatabaseEnv,
15298
- getSkillsNativeStorageStatus,
15299
- getSkillsByTag,
15300
- getSkillsByCategory,
15301
- getSkillToolDependencies,
15302
- getSkillRequirements,
15303
- getSkillPath,
15304
- getSkillDocs,
15305
- getSkillBestDoc,
15306
- getSkill,
15307
- getRunExportDir,
15308
- getPublicSkillDiscovery,
15309
- getProjectStateDir,
15310
- getProjectConfigPath,
15311
- getPortableSkillsRoot,
15312
- getPortableSkillPath,
15313
- getPinnedSkills,
15314
- getNextRun,
15315
- getMcpToolDescriptions,
15316
- getMcpResourceContracts,
15317
- getInstalledSkills,
15318
- getInstallMeta,
15319
- getFeedbackDbPath,
15320
- getDueSchedules,
15321
- getDisabledSkills,
15322
- getDisabledProjectSkills,
15323
- getConfiguredApiUrl,
15324
- getConfigPath,
15325
- getCompactSkillDiscovery,
15326
- getAllTags,
15327
- getAgentSkillsDir,
15328
- getAgentSkillPath,
15329
- generateSkillMd,
15330
- generateEnvExample,
15331
- findSkillsParityForMcpTool,
15332
- findSkillsParityForCliCommand,
15333
- findSkillRun,
15334
- findSimilarSkills,
15335
- findPortableSkill,
15336
- exportSkillsLocalSnapshot,
15337
- ensureProjectConfig,
15338
- enableSkill,
15339
- disableSkill,
15340
- destinationFor,
15341
- describeMcpToolContracts,
15342
- createSkillsSnapshotSyncRecord,
15343
- createSkillsS3ObjectStore,
15344
- createSkillsPostgresSyncStore,
15345
- createSkillToolDependencies,
15346
- createSkillRun,
15347
- createSkillMcpMetadata,
15348
- createRemoteSkillsClient,
15349
- createRegistrySyncArtifact,
15350
- createMcpContractManifest,
15351
- createLocalSkillManifest,
15352
- configuredSkillsApiUrl,
15353
- computeContentHash,
15354
- completeSkillRun,
15355
- clearRegistryCache,
15356
- canonicalizeManifest,
15357
- buildSkillsS3ObjectUrl,
15358
- buildSkillsApiUrl,
15359
- appendRunEvent,
15360
- agentGlobalSkillsDir,
15361
- addSchedule,
15362
- adaptSkillMdForAgent,
15363
- WorkspaceLeaveInputError,
15364
- WorkspaceIdentityMismatchError,
15365
- WorkspaceContextInputError,
15366
- TOOL_PRIMITIVE_SCHEMA_VERSION,
15367
- TOOL_PRIMITIVES,
15368
- StationSnapshotError,
15369
- SkillsS3ObjectStore,
15370
- SkillsPostgresSyncStore,
15371
- SkillsFleetCredentialError,
15372
- SYNC_MARKER_MANAGED_BY,
15373
- SYNC_MARKER_FILE,
15374
- SYNC_HOMES,
15375
- SYNC_AGENTS,
15376
- STORAGE_TABLES,
15377
- STATION_SYNC_MANIFEST_SCHEMA,
15378
- STATION_HYDRATION_MANIFEST_SCHEMA,
15379
- SKILL_SYSTEM_DEPS_ALLOWLIST,
15380
- SKILL_SANDBOX_MODES,
15381
- SKILL_RUNTIMES,
15382
- SKILL_ALIASES,
15383
- SKILLS_STORAGE_TABLES,
15384
- SKILLS_STORAGE_FALLBACK_ENV,
15385
- SKILLS_STORAGE_ENV,
15386
- SKILLS_PROJECT_DIR,
15387
- SKILLS_NATIVE_STORAGE_FALLBACK_ENV,
15388
- SKILLS_NATIVE_STORAGE_ENV,
15389
- SKILLS_LOCAL_OPT_IN_ENV_KEYS,
15390
- SKILLS_CLI_MCP_PARITY,
15391
- SKILLS_APP,
15392
- SKILLS_API_URL_ENV_KEYS,
15393
- SKILLS_API_URL_ENV,
15394
- SKILLS_API_KEY_ENV_KEYS,
15395
- SKILLS_API_KEY_ENV,
15396
- SKILLS,
15397
- RemoteWorkspaceSelectionError,
15398
- RemoteWorkspaceMemberError,
15399
- RemoteWorkspaceLeaveUnconfirmedError,
15400
- RemoteWorkspaceLeaveError,
15401
- RemoteSkillsClient,
15402
- RemoteSkillsAuthClient,
15403
- RemoteRouteUnsupportedError,
15404
- RemoteRequestError,
15405
- RemoteCreditApprovalError,
15406
- RemoteCapabilityUnavailableError,
15407
- REMOTE_SKILL_RUN_CONTRACT_VERSION,
15408
- REFUSED_SCANNER_FLAGGED,
15409
- PullSkillError,
15410
- PROJECT_CONFIG_FILE,
15411
- PORTABLE_SKILL_STANDARD,
15412
- PORTABLE_SKILL_SCHEMA,
15413
- PORTABLE_SKILL_DEFAULT_VERSION,
15414
- MissingSkillsFleetError,
15415
- MCP_CONTRACT_SCHEMA_VERSION,
15416
- HostedApiError,
15417
- DEFAULT_EXPORT_DIR,
15418
- CATEGORIES,
15419
- BASIC_SKILL_NAMES,
16074
+ AGENT_TARGETS,
15420
16075
  ARTICLE_GENERATION_SLUG,
15421
- AGENT_TARGETS
16076
+ BASIC_SKILL_NAMES,
16077
+ CATEGORIES,
16078
+ CONTENT_HASH_LIMITS,
16079
+ ContentHashInputError,
16080
+ DEFAULT_EXPORT_DIR,
16081
+ HostedApiError,
16082
+ InvitationEmailInputError,
16083
+ MCP_CONTRACT_SCHEMA_VERSION,
16084
+ MissingSkillsFleetError,
16085
+ PORTABLE_SKILL_DEFAULT_VERSION,
16086
+ PORTABLE_SKILL_SCHEMA,
16087
+ PORTABLE_SKILL_STANDARD,
16088
+ PROJECT_CONFIG_FILE,
16089
+ PullSkillError,
16090
+ REFUSED_SCANNER_FLAGGED,
16091
+ REMOTE_SKILL_RUN_CONTRACT_VERSION,
16092
+ RemoteCapabilityUnavailableError,
16093
+ RemoteCreditApprovalError,
16094
+ RemoteInvitationEmailError,
16095
+ RemoteInvitationEmailUnconfirmedError,
16096
+ RemoteQuoteUnavailableError,
16097
+ RemoteRequestError,
16098
+ RemoteRouteUnsupportedError,
16099
+ RemoteSkillsAuthClient,
16100
+ RemoteSkillsClient,
16101
+ RemoteWorkspaceInvitationError,
16102
+ RemoteWorkspaceInvitationReadError,
16103
+ RemoteWorkspaceInvitationUnconfirmedError,
16104
+ RemoteWorkspaceLeaveError,
16105
+ RemoteWorkspaceLeaveUnconfirmedError,
16106
+ RemoteWorkspaceMemberError,
16107
+ RemoteWorkspaceSelectionError,
16108
+ SKILLS,
16109
+ SKILLS_API_KEY_ENV,
16110
+ SKILLS_API_KEY_ENV_KEYS,
16111
+ SKILLS_API_URL_ENV,
16112
+ SKILLS_API_URL_ENV_KEYS,
16113
+ SKILLS_APP,
16114
+ SKILLS_CLI_MCP_PARITY,
16115
+ SKILLS_LOCAL_OPT_IN_ENV_KEYS,
16116
+ SKILLS_NATIVE_STORAGE_ENV,
16117
+ SKILLS_NATIVE_STORAGE_FALLBACK_ENV,
16118
+ SKILLS_PROJECT_DIR,
16119
+ SKILLS_STORAGE_ENV,
16120
+ SKILLS_STORAGE_FALLBACK_ENV,
16121
+ SKILLS_STORAGE_TABLES,
16122
+ SKILL_ALIASES,
16123
+ SKILL_RUNTIMES,
16124
+ SKILL_SANDBOX_MODES,
16125
+ SKILL_SYSTEM_DEPS_ALLOWLIST,
16126
+ STATION_HYDRATION_MANIFEST_SCHEMA,
16127
+ STATION_SYNC_MANIFEST_SCHEMA,
16128
+ STORAGE_TABLES,
16129
+ SYNC_AGENTS,
16130
+ SYNC_HOMES,
16131
+ SYNC_MARKER_FILE,
16132
+ SYNC_MARKER_MANAGED_BY,
16133
+ SkillsFleetCredentialError,
16134
+ SkillsPostgresSyncStore,
16135
+ SkillsS3ObjectStore,
16136
+ StationSnapshotError,
16137
+ TOOL_PRIMITIVES,
16138
+ TOOL_PRIMITIVE_SCHEMA_VERSION,
16139
+ WorkspaceContextInputError,
16140
+ WorkspaceIdentityMismatchError,
16141
+ WorkspaceInvitationInputError,
16142
+ WorkspaceLeaveInputError,
16143
+ adaptSkillMdForAgent,
16144
+ addSchedule,
16145
+ agentGlobalSkillsDir,
16146
+ appendRunEvent,
16147
+ buildSkillsApiUrl,
16148
+ buildSkillsS3ObjectUrl,
16149
+ canonicalizeManifest,
16150
+ clearRegistryCache,
16151
+ completeSkillRun,
16152
+ computeContentHash,
16153
+ computeContentHashFromEntries,
16154
+ configuredSkillsApiUrl,
16155
+ createLocalSkillManifest,
16156
+ createMcpContractManifest,
16157
+ createRegistrySyncArtifact,
16158
+ createRemoteSkillsClient,
16159
+ createSkillMcpMetadata,
16160
+ createSkillRun,
16161
+ createSkillToolDependencies,
16162
+ createSkillsPostgresSyncStore,
16163
+ createSkillsS3ObjectStore,
16164
+ createSkillsSnapshotSyncRecord,
16165
+ describeMcpToolContracts,
16166
+ destinationFor,
16167
+ disableSkill,
16168
+ enableSkill,
16169
+ ensureProjectConfig,
16170
+ exportSkillsLocalSnapshot,
16171
+ findPortableSkill,
16172
+ findSimilarSkills,
16173
+ findSkillRun,
16174
+ findSkillsParityForCliCommand,
16175
+ findSkillsParityForMcpTool,
16176
+ generateEnvExample,
16177
+ generateSkillMd,
16178
+ getAgentSkillPath,
16179
+ getAgentSkillsDir,
16180
+ getAllTags,
16181
+ getCompactSkillDiscovery,
16182
+ getConfigPath,
16183
+ getConfiguredApiUrl,
16184
+ getDisabledProjectSkills,
16185
+ getDisabledSkills,
16186
+ getDueSchedules,
16187
+ getFeedbackDbPath,
16188
+ getInstallMeta,
16189
+ getInstalledSkills,
16190
+ getMcpResourceContracts,
16191
+ getMcpToolDescriptions,
16192
+ getNextRun,
16193
+ getPinnedSkills,
16194
+ getPortableSkillPath,
16195
+ getPortableSkillsRoot,
16196
+ getProjectConfigPath,
16197
+ getProjectStateDir,
16198
+ getPublicSkillDiscovery,
16199
+ getRunExportDir,
16200
+ getSkill,
16201
+ getSkillBestDoc,
16202
+ getSkillDocs,
16203
+ getSkillPath,
16204
+ getSkillRequirements,
16205
+ getSkillToolDependencies,
16206
+ getSkillsByCategory,
16207
+ getSkillsByTag,
16208
+ getSkillsNativeStorageStatus,
16209
+ getSkillsStorageDatabaseEnv,
16210
+ getSkillsStorageDatabaseUrl,
16211
+ getSkillsStorageStatus,
16212
+ getStorageDatabaseEnv,
16213
+ getStorageDatabaseUrl,
16214
+ getStorageStatus,
16215
+ getToolPrimitive,
16216
+ homePathFor,
16217
+ importSkillsLocalSnapshot,
16218
+ installSkill,
16219
+ installSkillForAgent,
16220
+ installSkillManifest,
16221
+ installSkillSource,
16222
+ installSkills,
16223
+ isBasicSkillName,
16224
+ isExcludedSkillFileName,
16225
+ isGatewayBackedSkill,
16226
+ isPortableWithinSkill,
16227
+ isRegularFile,
16228
+ isSkillsLocalOptIn,
16229
+ isSyncAgent,
16230
+ listMcpToolContracts,
16231
+ listPinnedSkills,
16232
+ listPortableSkillMetas,
16233
+ listPortableSkills,
16234
+ listSchedules,
16235
+ listSkillRuns,
16236
+ listToolPrimitives,
16237
+ loadBasicRegistry,
16238
+ loadConfig,
16239
+ loadProjectConfig,
16240
+ loadRegistry,
16241
+ loadRegistryProfile,
16242
+ loadRemoteRegistry,
16243
+ loadRemoteSkill,
16244
+ normalizeLineEndings,
16245
+ normalizePortableSkillName,
16246
+ normalizeRemoteSkillRunContract,
16247
+ normalizeSkillSlug,
16248
+ normalizeSkillsApiOrigin,
16249
+ noticeLocalSkillsMode,
16250
+ parseRemoteRegistryPayload,
16251
+ parseRemoteSkillPayload,
16252
+ parseSkillFrontmatter,
16253
+ pinProjectSkill,
16254
+ pinSkill,
16255
+ planSkillsS3SnapshotUpload,
16256
+ planStationHydration,
16257
+ planStationSnapshot,
16258
+ pointerSkillMd,
16259
+ portPortableSkill,
16260
+ portPortableSkillDirectory,
16261
+ publicDiscoveryDependencies,
16262
+ publicDiscoveryDocumentation,
16263
+ publicDiscoveryEnvVars,
16264
+ pullSkills,
16265
+ readPortableSkillManifest,
16266
+ recordScheduleRun,
16267
+ removeManagedAgentSkill,
16268
+ removeSchedule,
16269
+ removeSkill,
16270
+ removeSkillForAgent,
16271
+ requireSkillsApiKey,
16272
+ requireSkillsApiOrigin,
16273
+ requireSkillsFleet,
16274
+ resolveSkillAlias,
16275
+ resolveSkillsApiKey,
16276
+ resolveSkillsApiOrigin,
16277
+ resolveSkillsFleet,
16278
+ resolveSkillsNativeStorageConfig,
16279
+ resolveStorageConfig,
16280
+ resolveSyncAgents,
16281
+ revisionIdOf,
16282
+ runPortableSkill,
16283
+ runSkill,
16284
+ sanitizePublicDiscoveryText,
16285
+ saveConfig,
16286
+ saveFeedback,
16287
+ saveProjectConfig,
16288
+ scaffoldPortableSkill,
16289
+ searchSkills,
16290
+ selectsSkillsLocalMode,
16291
+ setScheduleEnabled,
16292
+ setSkillDisabled,
16293
+ sha256File,
16294
+ signSkillsAwsV4Request,
16295
+ skillExists,
16296
+ skillsCredentialFilePath,
16297
+ skillsCredentialFiles,
16298
+ skillsCredentialOrReason,
16299
+ skillsPostgresSyncSchemaSql,
16300
+ storageCapabilities,
16301
+ summarizeMcpToolContract,
16302
+ syncSkillsToAgents,
16303
+ unpinProjectSkill,
16304
+ unpinSkill,
16305
+ unsetConfig,
16306
+ updateSkillRun,
16307
+ uploadSkillsSnapshotFilesToS3,
16308
+ validateBlogArticleRunOptions,
16309
+ validateCron,
16310
+ validatePortableManifestContract,
16311
+ validatePortableSkillDirectory,
16312
+ validateRegistryConsistency,
16313
+ validateSkillDirectory,
16314
+ validateSkillsCliMcpParity,
16315
+ validateStationId,
16316
+ validateToolPrimitiveCoverage,
16317
+ verifyContentHash,
16318
+ verifyContentHashFromEntries,
16319
+ walkEntries,
16320
+ writeCorpusSkill,
16321
+ writeManagedAgentSkill,
16322
+ writeManagedSkillDir,
16323
+ writeRegistrySyncArtifact,
16324
+ writeRunLogs,
16325
+ writeStationHydration,
16326
+ writeStationSnapshot
15422
16327
  };