@morphist/aspects 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +74 -49
  2. package/dist/cli.js +2873 -704
  3. package/package.json +10 -4
package/dist/cli.js CHANGED
@@ -785,64 +785,6 @@ var init_prompt = __esm(() => {
785
785
  kCancel = Symbol.for("cancel");
786
786
  });
787
787
 
788
- // node_modules/sisteransi/src/index.js
789
- var require_src = __commonJS((exports, module) => {
790
- var ESC = "\x1B";
791
- var CSI = `${ESC}[`;
792
- var beep = "\x07";
793
- var cursor = {
794
- to(x2, y3) {
795
- if (!y3)
796
- return `${CSI}${x2 + 1}G`;
797
- return `${CSI}${y3 + 1};${x2 + 1}H`;
798
- },
799
- move(x2, y3) {
800
- let ret = "";
801
- if (x2 < 0)
802
- ret += `${CSI}${-x2}D`;
803
- else if (x2 > 0)
804
- ret += `${CSI}${x2}C`;
805
- if (y3 < 0)
806
- ret += `${CSI}${-y3}A`;
807
- else if (y3 > 0)
808
- ret += `${CSI}${y3}B`;
809
- return ret;
810
- },
811
- up: (count = 1) => `${CSI}${count}A`,
812
- down: (count = 1) => `${CSI}${count}B`,
813
- forward: (count = 1) => `${CSI}${count}C`,
814
- backward: (count = 1) => `${CSI}${count}D`,
815
- nextLine: (count = 1) => `${CSI}E`.repeat(count),
816
- prevLine: (count = 1) => `${CSI}F`.repeat(count),
817
- left: `${CSI}G`,
818
- hide: `${CSI}?25l`,
819
- show: `${CSI}?25h`,
820
- save: `${ESC}7`,
821
- restore: `${ESC}8`
822
- };
823
- var scroll = {
824
- up: (count = 1) => `${CSI}S`.repeat(count),
825
- down: (count = 1) => `${CSI}T`.repeat(count)
826
- };
827
- var erase = {
828
- screen: `${CSI}2J`,
829
- up: (count = 1) => `${CSI}1J`.repeat(count),
830
- down: (count = 1) => `${CSI}J`.repeat(count),
831
- line: `${CSI}2K`,
832
- lineEnd: `${CSI}K`,
833
- lineStart: `${CSI}1K`,
834
- lines(count) {
835
- let clear = "";
836
- for (let i2 = 0;i2 < count; i2++)
837
- clear += this.line + (i2 < count - 1 ? cursor.up() : "");
838
- if (count)
839
- clear += cursor.left;
840
- return clear;
841
- }
842
- };
843
- module.exports = { cursor, scroll, erase, beep };
844
- });
845
-
846
788
  // node_modules/picocolors/picocolors.js
847
789
  var require_picocolors = __commonJS((exports, module) => {
848
790
  var p = process || {};
@@ -913,6 +855,64 @@ var require_picocolors = __commonJS((exports, module) => {
913
855
  module.exports.createColors = createColors2;
914
856
  });
915
857
 
858
+ // node_modules/sisteransi/src/index.js
859
+ var require_src = __commonJS((exports, module) => {
860
+ var ESC = "\x1B";
861
+ var CSI = `${ESC}[`;
862
+ var beep = "\x07";
863
+ var cursor = {
864
+ to(x2, y3) {
865
+ if (!y3)
866
+ return `${CSI}${x2 + 1}G`;
867
+ return `${CSI}${y3 + 1};${x2 + 1}H`;
868
+ },
869
+ move(x2, y3) {
870
+ let ret = "";
871
+ if (x2 < 0)
872
+ ret += `${CSI}${-x2}D`;
873
+ else if (x2 > 0)
874
+ ret += `${CSI}${x2}C`;
875
+ if (y3 < 0)
876
+ ret += `${CSI}${-y3}A`;
877
+ else if (y3 > 0)
878
+ ret += `${CSI}${y3}B`;
879
+ return ret;
880
+ },
881
+ up: (count = 1) => `${CSI}${count}A`,
882
+ down: (count = 1) => `${CSI}${count}B`,
883
+ forward: (count = 1) => `${CSI}${count}C`,
884
+ backward: (count = 1) => `${CSI}${count}D`,
885
+ nextLine: (count = 1) => `${CSI}E`.repeat(count),
886
+ prevLine: (count = 1) => `${CSI}F`.repeat(count),
887
+ left: `${CSI}G`,
888
+ hide: `${CSI}?25l`,
889
+ show: `${CSI}?25h`,
890
+ save: `${ESC}7`,
891
+ restore: `${ESC}8`
892
+ };
893
+ var scroll = {
894
+ up: (count = 1) => `${CSI}S`.repeat(count),
895
+ down: (count = 1) => `${CSI}T`.repeat(count)
896
+ };
897
+ var erase = {
898
+ screen: `${CSI}2J`,
899
+ up: (count = 1) => `${CSI}1J`.repeat(count),
900
+ down: (count = 1) => `${CSI}J`.repeat(count),
901
+ line: `${CSI}2K`,
902
+ lineEnd: `${CSI}K`,
903
+ lineStart: `${CSI}1K`,
904
+ lines(count) {
905
+ let clear = "";
906
+ for (let i2 = 0;i2 < count; i2++)
907
+ clear += this.line + (i2 < count - 1 ? cursor.up() : "");
908
+ if (count)
909
+ clear += cursor.left;
910
+ return clear;
911
+ }
912
+ };
913
+ module.exports = { cursor, scroll, erase, beep };
914
+ });
915
+
916
916
  // node_modules/node-fetch-native/dist/shared/node-fetch-native.DfbY2q-x.mjs
917
917
  function f3(e3) {
918
918
  return e3 && e3.__esModule && Object.prototype.hasOwnProperty.call(e3, "default") ? e3.default : e3;
@@ -6284,6 +6284,9 @@ async function runMain(cmd, opts = {}) {
6284
6284
  }
6285
6285
  }
6286
6286
 
6287
+ // src/cli.ts
6288
+ var import_picocolors5 = __toESM(require_picocolors(), 1);
6289
+
6287
6290
  // scripts/lib/output.ts
6288
6291
  var rgb = (r3, g3, b2) => (text) => `\x1B[38;2;${r3};${g3};${b2}m${text}\x1B[0m`;
6289
6292
  var colors2 = {
@@ -6326,8 +6329,8 @@ function morphistBanner() {
6326
6329
  }
6327
6330
 
6328
6331
  // src/commands/create.ts
6329
- import { writeFile as writeFile4, readFile as readFile5, stat as stat2, mkdir as mkdir4 } from "node:fs/promises";
6330
- import { join as join4 } from "node:path";
6332
+ import { writeFile as writeFile4, readFile as readFile5, stat as stat3, mkdir as mkdir4 } from "node:fs/promises";
6333
+ import { join as join5 } from "node:path";
6331
6334
  import { execSync } from "node:child_process";
6332
6335
 
6333
6336
  // node_modules/@clack/core/dist/index.mjs
@@ -20682,7 +20685,7 @@ var aspectSchema = exports_external.object({
20682
20685
 
20683
20686
  // src/commands/set.ts
20684
20687
  import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile3, readdir } from "node:fs/promises";
20685
- import { join as join3 } from "node:path";
20688
+ import { join as join4 } from "node:path";
20686
20689
 
20687
20690
  // src/utils/colors.ts
20688
20691
  var import_picocolors3 = __toESM(require_picocolors(), 1);
@@ -20713,32 +20716,77 @@ var icons2 = {
20713
20716
  sparkle: "✨",
20714
20717
  package: "\uD83D\uDCE6",
20715
20718
  search: "\uD83D\uDD0D",
20716
- wizard: "\uD83E\uDDD9"
20719
+ wizard: "\uD83E\uDDD9",
20720
+ share: "\uD83D\uDD17"
20717
20721
  };
20718
20722
 
20719
20723
  // src/utils/paths.ts
20720
20724
  import { homedir } from "node:os";
20721
20725
  import { join } from "node:path";
20722
- import { mkdir } from "node:fs/promises";
20726
+ import { mkdir, stat } from "node:fs/promises";
20723
20727
  var ASPECTS_HOME = join(homedir(), ".aspects");
20728
+ var PROJECT_ASPECTS_DIR_NAME = ".aspects";
20724
20729
  var ASPECTS_DIR = join(ASPECTS_HOME, "aspects");
20725
20730
  var SETS_DIR = join(ASPECTS_HOME, "sets");
20726
20731
  var CONFIG_PATH = join(ASPECTS_HOME, "config.json");
20727
- async function ensureAspectsDir() {
20728
- await mkdir(ASPECTS_DIR, { recursive: true });
20732
+ var cachedProjectRoot = null;
20733
+ async function findProjectRoot() {
20734
+ if (cachedProjectRoot !== null)
20735
+ return cachedProjectRoot || null;
20736
+ let dir = process.cwd();
20737
+ const root = "/";
20738
+ while (dir !== root) {
20739
+ try {
20740
+ await stat(join(dir, PROJECT_ASPECTS_DIR_NAME));
20741
+ cachedProjectRoot = dir;
20742
+ return dir;
20743
+ } catch {
20744
+ try {
20745
+ await stat(join(dir, "aspects.json"));
20746
+ cachedProjectRoot = dir;
20747
+ return dir;
20748
+ } catch {}
20749
+ }
20750
+ dir = join(dir, "..");
20751
+ }
20752
+ cachedProjectRoot = "";
20753
+ return null;
20754
+ }
20755
+ function getAspectsHome(scope, projectRoot) {
20756
+ if (scope === "global") {
20757
+ return ASPECTS_HOME;
20758
+ }
20759
+ return join(projectRoot || process.cwd(), PROJECT_ASPECTS_DIR_NAME);
20760
+ }
20761
+ function getConfigPath(scope, projectRoot) {
20762
+ return join(getAspectsHome(scope, projectRoot), "config.json");
20729
20763
  }
20730
- async function ensureSetsDir() {
20731
- await mkdir(SETS_DIR, { recursive: true });
20764
+ async function ensureAspectsDir(scope = "global", projectRoot) {
20765
+ const aspectsDir = join(getAspectsHome(scope, projectRoot), "aspects");
20766
+ await mkdir(aspectsDir, { recursive: true });
20732
20767
  }
20733
- function getSetsDir() {
20734
- return SETS_DIR;
20768
+ async function ensureSetsDir(scope = "global", projectRoot) {
20769
+ const setsDir = join(getAspectsHome(scope, projectRoot), "sets");
20770
+ await mkdir(setsDir, { recursive: true });
20735
20771
  }
20736
- function getAspectPath(name) {
20737
- return join(ASPECTS_DIR, name);
20772
+ function getSetsDir(scope = "global", projectRoot) {
20773
+ return join(getAspectsHome(scope, projectRoot), "sets");
20774
+ }
20775
+ function getAspectPath(name, scope = "global", projectRoot) {
20776
+ const aspectsDir = join(getAspectsHome(scope, projectRoot), "aspects");
20777
+ return join(aspectsDir, name);
20738
20778
  }
20739
20779
 
20740
20780
  // src/lib/config.ts
20741
20781
  import { readFile, writeFile } from "node:fs/promises";
20782
+ var DEFAULT_REGISTRY_API_URL = "https://aspects.sh/api/v1";
20783
+ function resolveRegistryUrl(envUrl, configUrl) {
20784
+ if (envUrl)
20785
+ return envUrl;
20786
+ if (configUrl)
20787
+ return configUrl;
20788
+ return DEFAULT_REGISTRY_API_URL;
20789
+ }
20742
20790
  function createDefaultConfig() {
20743
20791
  return {
20744
20792
  version: 1,
@@ -20746,54 +20794,96 @@ function createDefaultConfig() {
20746
20794
  settings: {}
20747
20795
  };
20748
20796
  }
20749
- async function readConfig() {
20750
- await ensureAspectsDir();
20797
+ async function readConfig(scope = "global", projectRoot) {
20798
+ await ensureAspectsDir(scope, projectRoot);
20799
+ const configPath = scope === "global" ? CONFIG_PATH : getConfigPath(scope, projectRoot);
20751
20800
  try {
20752
- const content = await readFile(CONFIG_PATH, "utf-8");
20801
+ const content = await readFile(configPath, "utf-8");
20753
20802
  return JSON.parse(content);
20754
20803
  } catch (err) {
20755
20804
  if (err.code === "ENOENT") {
20756
20805
  const config2 = createDefaultConfig();
20757
- await writeConfig(config2);
20806
+ await writeConfig(config2, scope, projectRoot);
20758
20807
  return config2;
20759
20808
  }
20760
20809
  throw err;
20761
20810
  }
20762
20811
  }
20763
- async function writeConfig(config2) {
20764
- await ensureAspectsDir();
20765
- await writeFile(CONFIG_PATH, JSON.stringify(config2, null, 2) + `
20812
+ async function writeConfig(config2, scope = "global", projectRoot) {
20813
+ await ensureAspectsDir(scope, projectRoot);
20814
+ const configPath = scope === "global" ? CONFIG_PATH : getConfigPath(scope, projectRoot);
20815
+ await writeFile(configPath, JSON.stringify(config2, null, 2) + `
20766
20816
  `);
20767
20817
  }
20768
- async function addInstalledAspect(name, info) {
20769
- const config2 = await readConfig();
20818
+ async function addInstalledAspect(name, info, scope = "global", projectRoot) {
20819
+ const config2 = await readConfig(scope, projectRoot);
20770
20820
  config2.installed[name] = info;
20771
- await writeConfig(config2);
20821
+ await writeConfig(config2, scope, projectRoot);
20772
20822
  }
20773
- async function removeInstalledAspect(name) {
20774
- const config2 = await readConfig();
20823
+ async function removeInstalledAspect(name, scope = "global", projectRoot) {
20824
+ const config2 = await readConfig(scope, projectRoot);
20775
20825
  if (!(name in config2.installed)) {
20776
20826
  return false;
20777
20827
  }
20778
20828
  delete config2.installed[name];
20779
- await writeConfig(config2);
20829
+ await writeConfig(config2, scope, projectRoot);
20780
20830
  return true;
20781
20831
  }
20782
- async function getInstalledAspect(name) {
20783
- const config2 = await readConfig();
20832
+ async function getInstalledAspect(name, scope = "global", projectRoot) {
20833
+ const config2 = await readConfig(scope, projectRoot);
20784
20834
  return config2.installed[name] ?? null;
20785
20835
  }
20786
- async function listInstalledAspects() {
20787
- const config2 = await readConfig();
20836
+ async function listInstalledAspects(scope = "global", projectRoot) {
20837
+ const config2 = await readConfig(scope, projectRoot);
20788
20838
  return Object.entries(config2.installed).map(([name, info]) => ({
20789
20839
  name,
20840
+ scope,
20790
20841
  ...info
20791
20842
  }));
20792
20843
  }
20844
+ async function listAllInstalledAspects(projectRoot) {
20845
+ const globalAspects = await listInstalledAspects("global");
20846
+ try {
20847
+ const projectAspects = await listInstalledAspects("project", projectRoot);
20848
+ return [...projectAspects, ...globalAspects];
20849
+ } catch {
20850
+ return globalAspects;
20851
+ }
20852
+ }
20853
+ async function getRegistryUrl() {
20854
+ const config2 = await readConfig();
20855
+ return resolveRegistryUrl(process.env.ASPECTS_REGISTRY_URL, config2.settings.registryUrl);
20856
+ }
20857
+ async function getAuthToken() {
20858
+ const config2 = await readConfig();
20859
+ if (!config2.auth?.accessToken)
20860
+ return null;
20861
+ if (config2.auth.expiresAt && new Date(config2.auth.expiresAt) < new Date) {
20862
+ return null;
20863
+ }
20864
+ return config2.auth.accessToken;
20865
+ }
20866
+ async function getAuth() {
20867
+ const config2 = await readConfig();
20868
+ return config2.auth ?? null;
20869
+ }
20870
+ async function isLoggedIn() {
20871
+ return await getAuthToken() !== null;
20872
+ }
20873
+ async function setAuthTokens(tokens) {
20874
+ const config2 = await readConfig();
20875
+ config2.auth = tokens;
20876
+ await writeConfig(config2);
20877
+ }
20878
+ async function clearAuth() {
20879
+ const config2 = await readConfig();
20880
+ delete config2.auth;
20881
+ await writeConfig(config2);
20882
+ }
20793
20883
 
20794
20884
  // src/lib/installer.ts
20795
- import { mkdir as mkdir2, writeFile as writeFile2, readFile as readFile3, stat } from "node:fs/promises";
20796
- import { join as join2, dirname } from "node:path";
20885
+ import { mkdir as mkdir2, writeFile as writeFile2, readFile as readFile3, stat as stat2, access } from "node:fs/promises";
20886
+ import { join as join3, dirname } from "node:path";
20797
20887
 
20798
20888
  // node_modules/ofetch/dist/node.mjs
20799
20889
  import http from "node:http";
@@ -21474,103 +21564,1755 @@ function formatZodErrors(error48) {
21474
21564
  });
21475
21565
  }
21476
21566
 
21567
+ // src/lib/api-client.ts
21568
+ var cache = new Map;
21569
+ function getCached(key) {
21570
+ const entry = cache.get(key);
21571
+ if (!entry)
21572
+ return null;
21573
+ if (Date.now() - entry.timestamp > entry.ttl) {
21574
+ cache.delete(key);
21575
+ return null;
21576
+ }
21577
+ return entry.data;
21578
+ }
21579
+ function setCache(key, data, ttlMs) {
21580
+ cache.set(key, { data, timestamp: Date.now(), ttl: ttlMs });
21581
+ }
21582
+ class ApiClientError extends Error {
21583
+ statusCode;
21584
+ errorCode;
21585
+ constructor(message, statusCode, errorCode) {
21586
+ super(message);
21587
+ this.statusCode = statusCode;
21588
+ this.errorCode = errorCode;
21589
+ this.name = "ApiClientError";
21590
+ }
21591
+ }
21592
+ function parseApiError(err) {
21593
+ const fetchErr = err;
21594
+ const status = fetchErr?.statusCode ?? fetchErr?.status ?? 0;
21595
+ const body = fetchErr?.data;
21596
+ if (body && typeof body === "object" && "message" in body) {
21597
+ return new ApiClientError(body.message, status, body.error);
21598
+ }
21599
+ if (status === 0 || !status) {
21600
+ return new ApiClientError("Network error. Check your connection and try again.", 0, "network_error");
21601
+ }
21602
+ return new ApiClientError(`Request failed with status ${status}`, status);
21603
+ }
21604
+ var MAX_RETRIES = 3;
21605
+ var TIMEOUT_MS = 30000;
21606
+ async function apiFetch(path, options = {}) {
21607
+ const baseUrl = options.baseUrl ?? await getRegistryUrl();
21608
+ const url2 = `${baseUrl}${path}`;
21609
+ const headers = {
21610
+ Accept: "application/json"
21611
+ };
21612
+ if (options.auth) {
21613
+ const token = await getAuthToken();
21614
+ if (!token) {
21615
+ throw new ApiClientError('Not logged in. Run "aspects login" first.', 401, "unauthorized");
21616
+ }
21617
+ headers["Authorization"] = `Bearer ${token}`;
21618
+ }
21619
+ if (options.body) {
21620
+ headers["Content-Type"] = "application/json";
21621
+ }
21622
+ let lastError;
21623
+ for (let attempt = 1;attempt <= MAX_RETRIES; attempt++) {
21624
+ try {
21625
+ return await ofetch(url2, {
21626
+ method: options.method ?? "GET",
21627
+ headers,
21628
+ body: options.body ? JSON.stringify(options.body) : undefined,
21629
+ timeout: TIMEOUT_MS,
21630
+ parseResponse: JSON.parse
21631
+ });
21632
+ } catch (err) {
21633
+ lastError = err;
21634
+ const fetchErr = err;
21635
+ const status = fetchErr?.statusCode ?? fetchErr?.status ?? 0;
21636
+ if (status >= 400 && status < 500 && status !== 429) {
21637
+ throw parseApiError(err);
21638
+ }
21639
+ if (attempt < MAX_RETRIES && (status === 429 || status >= 500 || status === 0)) {
21640
+ const delay = Math.pow(2, attempt - 1) * 1000;
21641
+ await new Promise((r6) => setTimeout(r6, delay));
21642
+ continue;
21643
+ }
21644
+ }
21645
+ }
21646
+ throw parseApiError(lastError);
21647
+ }
21648
+ async function getRegistry(baseUrl) {
21649
+ const cacheKey = `registry:${baseUrl ?? "default"}`;
21650
+ const cached2 = getCached(cacheKey);
21651
+ if (cached2)
21652
+ return cached2;
21653
+ const data = await apiFetch("/registry", { baseUrl });
21654
+ setCache(cacheKey, data, 5 * 60 * 1000);
21655
+ return data;
21656
+ }
21657
+ async function getAspect(name) {
21658
+ return apiFetch(`/aspects/${encodeURIComponent(name)}`);
21659
+ }
21660
+ async function getAspectVersion(name, version2) {
21661
+ return apiFetch(`/aspects/${encodeURIComponent(name)}/${encodeURIComponent(version2)}`);
21662
+ }
21663
+ async function searchAspects(params) {
21664
+ const searchParams = new URLSearchParams;
21665
+ if (params.q)
21666
+ searchParams.set("q", params.q);
21667
+ if (params.category)
21668
+ searchParams.set("category", params.category);
21669
+ if (params.trust)
21670
+ searchParams.set("trust", params.trust);
21671
+ if (params.limit)
21672
+ searchParams.set("limit", String(params.limit));
21673
+ if (params.offset)
21674
+ searchParams.set("offset", String(params.offset));
21675
+ const query = searchParams.toString();
21676
+ return apiFetch(`/search${query ? `?${query}` : ""}`);
21677
+ }
21678
+ async function publishAspect(aspect) {
21679
+ return apiFetch("/aspects", {
21680
+ method: "POST",
21681
+ body: { aspect },
21682
+ auth: true
21683
+ });
21684
+ }
21685
+ async function publishAnonymous(aspect) {
21686
+ return apiFetch("/aspects/blob", {
21687
+ method: "POST",
21688
+ body: aspect,
21689
+ auth: false
21690
+ });
21691
+ }
21692
+ async function getAspectByHash(hash2) {
21693
+ return apiFetch(`/aspects/blob/${encodeURIComponent(hash2)}`);
21694
+ }
21695
+ async function unpublishAspect(name, version2) {
21696
+ return apiFetch(`/aspects/${encodeURIComponent(name)}/${encodeURIComponent(version2)}`, { method: "DELETE", auth: true });
21697
+ }
21698
+ async function initiateDeviceAuth() {
21699
+ return apiFetch("/auth/device", { method: "POST" });
21700
+ }
21701
+ async function pollDeviceAuth(deviceCode, codeVerifier) {
21702
+ const baseUrl = await getRegistryUrl();
21703
+ const url2 = `${baseUrl}/auth/device/poll`;
21704
+ return ofetch(url2, {
21705
+ method: "POST",
21706
+ headers: {
21707
+ "Content-Type": "application/json",
21708
+ Accept: "application/json"
21709
+ },
21710
+ body: JSON.stringify({ device_code: deviceCode, code_verifier: codeVerifier }),
21711
+ timeout: TIMEOUT_MS,
21712
+ parseResponse: JSON.parse
21713
+ });
21714
+ }
21715
+
21477
21716
  // src/lib/registry.ts
21478
- var DEFAULT_REGISTRY_URL = "https://raw.githubusercontent.com/aimorphist/aspects/main/registry/index.json";
21717
+ var FALLBACK_REGISTRY_URL = "https://raw.githubusercontent.com/aimorphist/aspects/main/registry/index.json";
21479
21718
  var cachedIndex = null;
21480
- async function fetchRegistryIndex(registryUrl) {
21719
+ async function fetchRegistryIndex() {
21481
21720
  if (cachedIndex)
21482
21721
  return cachedIndex;
21483
- const url2 = registryUrl ?? DEFAULT_REGISTRY_URL;
21484
21722
  try {
21485
- const result = await ofetch(url2, { parseResponse: JSON.parse });
21486
- if (!result) {
21487
- throw new Error("Registry returned empty response");
21488
- }
21489
- cachedIndex = result;
21723
+ cachedIndex = await getRegistry();
21490
21724
  return cachedIndex;
21491
- } catch (err) {
21492
- throw new Error(`Failed to fetch registry from ${url2}: ${err.message}`);
21725
+ } catch {
21726
+ try {
21727
+ const result = await ofetch(FALLBACK_REGISTRY_URL, { parseResponse: JSON.parse });
21728
+ if (!result)
21729
+ throw new Error("Registry returned empty response");
21730
+ cachedIndex = result;
21731
+ return cachedIndex;
21732
+ } catch (err) {
21733
+ throw new Error(`Failed to fetch registry: ${err.message}`);
21734
+ }
21493
21735
  }
21494
21736
  }
21495
21737
  async function getRegistryAspect(name) {
21496
- const index = await fetchRegistryIndex();
21497
- return index.aspects[name] ?? null;
21738
+ try {
21739
+ const detail = await getAspect(name);
21740
+ return apiDetailToRegistryAspect(detail);
21741
+ } catch (err) {
21742
+ if (err instanceof ApiClientError && err.statusCode === 404) {
21743
+ return null;
21744
+ }
21745
+ try {
21746
+ const index = await fetchRegistryIndex();
21747
+ return index.aspects[name] ?? null;
21748
+ } catch {
21749
+ throw err;
21750
+ }
21751
+ }
21498
21752
  }
21499
- async function fetchAspectYaml(url2) {
21500
- return await ofetch(url2, { responseType: "text" });
21753
+ async function fetchAspectVersion(name, version2) {
21754
+ return getAspectVersion(name, version2);
21501
21755
  }
21502
-
21503
- // src/utils/hash.ts
21504
- import { createHash } from "node:crypto";
21505
- function sha256(content) {
21506
- return createHash("sha256").update(content, "utf-8").digest("hex");
21756
+ async function fetchAspectContent(url2) {
21757
+ return await ofetch(url2, { responseType: "text" });
21507
21758
  }
21508
-
21509
- // src/utils/logger.ts
21510
- var logger = consola.create({
21511
- formatOptions: {
21512
- date: false
21513
- }
21514
- });
21515
- var log = {
21516
- info: logger.info.bind(logger),
21517
- success: logger.success.bind(logger),
21518
- warn: logger.warn.bind(logger),
21519
- error: logger.error.bind(logger),
21520
- box: logger.box.bind(logger),
21521
- start: logger.start.bind(logger)
21522
- };
21523
-
21524
- // src/lib/installer.ts
21525
- async function installAspect(spec) {
21526
- switch (spec.type) {
21527
- case "registry":
21528
- return installFromRegistry(spec.name, spec.version);
21529
- case "local":
21530
- return installFromLocal(spec.path);
21531
- case "github":
21532
- return installFromGitHub(spec.owner, spec.repo, spec.ref);
21533
- }
21759
+ async function searchRegistry(params) {
21760
+ return searchAspects(params);
21534
21761
  }
21535
- async function installFromRegistry(name, version2) {
21536
- let registryAspect;
21762
+ async function getAspectDetail(name) {
21537
21763
  try {
21538
- registryAspect = await getRegistryAspect(name);
21764
+ return await getAspect(name);
21539
21765
  } catch (err) {
21540
- return {
21541
- success: false,
21542
- error: `Unable to reach registry: ${err.message}. Make sure you have network connectivity or try installing from a local path.`
21543
- };
21544
- }
21545
- if (!registryAspect) {
21546
- return { success: false, error: `Aspect "${name}" not found in registry` };
21766
+ if (err instanceof ApiClientError && err.statusCode === 404) {
21767
+ return null;
21768
+ }
21769
+ throw err;
21547
21770
  }
21548
- const targetVersion = version2 ?? registryAspect.latest;
21549
- const versionInfo = registryAspect.versions[targetVersion];
21550
- if (!versionInfo) {
21551
- const available = Object.keys(registryAspect.versions).join(", ");
21552
- return {
21553
- success: false,
21554
- error: `Version "${targetVersion}" not found. Available: ${available}`
21771
+ }
21772
+ async function fetchAspectByHash(hash2) {
21773
+ return getAspectByHash(hash2);
21774
+ }
21775
+ function apiDetailToRegistryAspect(detail) {
21776
+ const versions2 = {};
21777
+ for (const [ver, info] of Object.entries(detail.versions)) {
21778
+ versions2[ver] = {
21779
+ published: info.published,
21780
+ url: "",
21781
+ blake3: info.blake3,
21782
+ size: info.size
21555
21783
  };
21556
21784
  }
21557
- const existing = await getInstalledAspect(name);
21558
- if (existing && existing.version === targetVersion) {
21559
- const aspect2 = await loadAspectFromPath(getAspectPath(name));
21560
- if (aspect2) {
21561
- return { success: true, aspect: aspect2, source: "registry", alreadyInstalled: true };
21785
+ return {
21786
+ latest: detail.latest,
21787
+ versions: versions2,
21788
+ metadata: {
21789
+ displayName: detail.versions[detail.latest]?.aspect?.displayName ?? detail.name,
21790
+ tagline: detail.versions[detail.latest]?.aspect?.tagline ?? "",
21791
+ category: detail.versions[detail.latest]?.aspect?.category,
21792
+ tags: detail.versions[detail.latest]?.aspect?.tags,
21793
+ publisher: detail.publisher,
21794
+ trust: detail.trust
21562
21795
  }
21563
- }
21796
+ };
21797
+ }
21798
+
21799
+ // node_modules/@noble/hashes/utils.js
21800
+ /*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
21801
+ function isBytes(a2) {
21802
+ return a2 instanceof Uint8Array || ArrayBuffer.isView(a2) && a2.constructor.name === "Uint8Array";
21803
+ }
21804
+ function anumber(n5, title = "") {
21805
+ if (!Number.isSafeInteger(n5) || n5 < 0) {
21806
+ const prefix = title && `"${title}" `;
21807
+ throw new Error(`${prefix}expected integer >= 0, got ${n5}`);
21808
+ }
21809
+ }
21810
+ function abytes(value, length, title = "") {
21811
+ const bytes = isBytes(value);
21812
+ const len = value?.length;
21813
+ const needsLen = length !== undefined;
21814
+ if (!bytes || needsLen && len !== length) {
21815
+ const prefix = title && `"${title}" `;
21816
+ const ofLen = needsLen ? ` of length ${length}` : "";
21817
+ const got = bytes ? `length=${len}` : `type=${typeof value}`;
21818
+ throw new Error(prefix + "expected Uint8Array" + ofLen + ", got " + got);
21819
+ }
21820
+ return value;
21821
+ }
21822
+ function aexists(instance, checkFinished = true) {
21823
+ if (instance.destroyed)
21824
+ throw new Error("Hash instance has been destroyed");
21825
+ if (checkFinished && instance.finished)
21826
+ throw new Error("Hash#digest() has already been called");
21827
+ }
21828
+ function aoutput(out, instance) {
21829
+ abytes(out, undefined, "digestInto() output");
21830
+ const min = instance.outputLen;
21831
+ if (out.length < min) {
21832
+ throw new Error('"digestInto() output" expected to be of length >=' + min);
21833
+ }
21834
+ }
21835
+ function u8(arr) {
21836
+ return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
21837
+ }
21838
+ function u32(arr) {
21839
+ return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
21840
+ }
21841
+ function clean(...arrays) {
21842
+ for (let i2 = 0;i2 < arrays.length; i2++) {
21843
+ arrays[i2].fill(0);
21844
+ }
21845
+ }
21846
+ function rotr(word, shift) {
21847
+ return word << 32 - shift | word >>> shift;
21848
+ }
21849
+ var isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)();
21850
+ function byteSwap(word) {
21851
+ return word << 24 & 4278190080 | word << 8 & 16711680 | word >>> 8 & 65280 | word >>> 24 & 255;
21852
+ }
21853
+ var swap8IfBE = isLE ? (n5) => n5 : (n5) => byteSwap(n5);
21854
+ function byteSwap32(arr) {
21855
+ for (let i2 = 0;i2 < arr.length; i2++) {
21856
+ arr[i2] = byteSwap(arr[i2]);
21857
+ }
21858
+ return arr;
21859
+ }
21860
+ var swap32IfBE = isLE ? (u4) => u4 : byteSwap32;
21861
+ function createHasher(hashCons, info = {}) {
21862
+ const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
21863
+ const tmp = hashCons(undefined);
21864
+ hashC.outputLen = tmp.outputLen;
21865
+ hashC.blockLen = tmp.blockLen;
21866
+ hashC.create = (opts) => hashCons(opts);
21867
+ Object.assign(hashC, info);
21868
+ return Object.freeze(hashC);
21869
+ }
21870
+
21871
+ // node_modules/@noble/hashes/_md.js
21872
+ var SHA256_IV = /* @__PURE__ */ Uint32Array.from([
21873
+ 1779033703,
21874
+ 3144134277,
21875
+ 1013904242,
21876
+ 2773480762,
21877
+ 1359893119,
21878
+ 2600822924,
21879
+ 528734635,
21880
+ 1541459225
21881
+ ]);
21882
+
21883
+ // node_modules/@noble/hashes/_u64.js
21884
+ var U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
21885
+ var _32n = /* @__PURE__ */ BigInt(32);
21886
+ function fromBig(n5, le4 = false) {
21887
+ if (le4)
21888
+ return { h: Number(n5 & U32_MASK64), l: Number(n5 >> _32n & U32_MASK64) };
21889
+ return { h: Number(n5 >> _32n & U32_MASK64) | 0, l: Number(n5 & U32_MASK64) | 0 };
21890
+ }
21891
+ var rotrSH = (h4, l3, s2) => h4 >>> s2 | l3 << 32 - s2;
21892
+ var rotrSL = (h4, l3, s2) => h4 << 32 - s2 | l3 >>> s2;
21893
+ var rotrBH = (h4, l3, s2) => h4 << 64 - s2 | l3 >>> s2 - 32;
21894
+ var rotrBL = (h4, l3, s2) => h4 >>> s2 - 32 | l3 << 64 - s2;
21895
+ var rotr32H = (_h, l3) => l3;
21896
+ var rotr32L = (h4, _l2) => h4;
21897
+ function add(Ah, Al2, Bh, Bl2) {
21898
+ const l3 = (Al2 >>> 0) + (Bl2 >>> 0);
21899
+ return { h: Ah + Bh + (l3 / 2 ** 32 | 0) | 0, l: l3 | 0 };
21900
+ }
21901
+ var add3L = (Al2, Bl2, Cl2) => (Al2 >>> 0) + (Bl2 >>> 0) + (Cl2 >>> 0);
21902
+ var add3H = (low, Ah, Bh, Ch) => Ah + Bh + Ch + (low / 2 ** 32 | 0) | 0;
21903
+
21904
+ // node_modules/@noble/hashes/_blake.js
21905
+ var BSIGMA = /* @__PURE__ */ Uint8Array.from([
21906
+ 0,
21907
+ 1,
21908
+ 2,
21909
+ 3,
21910
+ 4,
21911
+ 5,
21912
+ 6,
21913
+ 7,
21914
+ 8,
21915
+ 9,
21916
+ 10,
21917
+ 11,
21918
+ 12,
21919
+ 13,
21920
+ 14,
21921
+ 15,
21922
+ 14,
21923
+ 10,
21924
+ 4,
21925
+ 8,
21926
+ 9,
21927
+ 15,
21928
+ 13,
21929
+ 6,
21930
+ 1,
21931
+ 12,
21932
+ 0,
21933
+ 2,
21934
+ 11,
21935
+ 7,
21936
+ 5,
21937
+ 3,
21938
+ 11,
21939
+ 8,
21940
+ 12,
21941
+ 0,
21942
+ 5,
21943
+ 2,
21944
+ 15,
21945
+ 13,
21946
+ 10,
21947
+ 14,
21948
+ 3,
21949
+ 6,
21950
+ 7,
21951
+ 1,
21952
+ 9,
21953
+ 4,
21954
+ 7,
21955
+ 9,
21956
+ 3,
21957
+ 1,
21958
+ 13,
21959
+ 12,
21960
+ 11,
21961
+ 14,
21962
+ 2,
21963
+ 6,
21964
+ 5,
21965
+ 10,
21966
+ 4,
21967
+ 0,
21968
+ 15,
21969
+ 8,
21970
+ 9,
21971
+ 0,
21972
+ 5,
21973
+ 7,
21974
+ 2,
21975
+ 4,
21976
+ 10,
21977
+ 15,
21978
+ 14,
21979
+ 1,
21980
+ 11,
21981
+ 12,
21982
+ 6,
21983
+ 8,
21984
+ 3,
21985
+ 13,
21986
+ 2,
21987
+ 12,
21988
+ 6,
21989
+ 10,
21990
+ 0,
21991
+ 11,
21992
+ 8,
21993
+ 3,
21994
+ 4,
21995
+ 13,
21996
+ 7,
21997
+ 5,
21998
+ 15,
21999
+ 14,
22000
+ 1,
22001
+ 9,
22002
+ 12,
22003
+ 5,
22004
+ 1,
22005
+ 15,
22006
+ 14,
22007
+ 13,
22008
+ 4,
22009
+ 10,
22010
+ 0,
22011
+ 7,
22012
+ 6,
22013
+ 3,
22014
+ 9,
22015
+ 2,
22016
+ 8,
22017
+ 11,
22018
+ 13,
22019
+ 11,
22020
+ 7,
22021
+ 14,
22022
+ 12,
22023
+ 1,
22024
+ 3,
22025
+ 9,
22026
+ 5,
22027
+ 0,
22028
+ 15,
22029
+ 4,
22030
+ 8,
22031
+ 6,
22032
+ 2,
22033
+ 10,
22034
+ 6,
22035
+ 15,
22036
+ 14,
22037
+ 9,
22038
+ 11,
22039
+ 3,
22040
+ 0,
22041
+ 8,
22042
+ 12,
22043
+ 2,
22044
+ 13,
22045
+ 7,
22046
+ 1,
22047
+ 4,
22048
+ 10,
22049
+ 5,
22050
+ 10,
22051
+ 2,
22052
+ 8,
22053
+ 4,
22054
+ 7,
22055
+ 6,
22056
+ 1,
22057
+ 5,
22058
+ 15,
22059
+ 11,
22060
+ 9,
22061
+ 14,
22062
+ 3,
22063
+ 12,
22064
+ 13,
22065
+ 0,
22066
+ 0,
22067
+ 1,
22068
+ 2,
22069
+ 3,
22070
+ 4,
22071
+ 5,
22072
+ 6,
22073
+ 7,
22074
+ 8,
22075
+ 9,
22076
+ 10,
22077
+ 11,
22078
+ 12,
22079
+ 13,
22080
+ 14,
22081
+ 15,
22082
+ 14,
22083
+ 10,
22084
+ 4,
22085
+ 8,
22086
+ 9,
22087
+ 15,
22088
+ 13,
22089
+ 6,
22090
+ 1,
22091
+ 12,
22092
+ 0,
22093
+ 2,
22094
+ 11,
22095
+ 7,
22096
+ 5,
22097
+ 3,
22098
+ 11,
22099
+ 8,
22100
+ 12,
22101
+ 0,
22102
+ 5,
22103
+ 2,
22104
+ 15,
22105
+ 13,
22106
+ 10,
22107
+ 14,
22108
+ 3,
22109
+ 6,
22110
+ 7,
22111
+ 1,
22112
+ 9,
22113
+ 4,
22114
+ 7,
22115
+ 9,
22116
+ 3,
22117
+ 1,
22118
+ 13,
22119
+ 12,
22120
+ 11,
22121
+ 14,
22122
+ 2,
22123
+ 6,
22124
+ 5,
22125
+ 10,
22126
+ 4,
22127
+ 0,
22128
+ 15,
22129
+ 8,
22130
+ 9,
22131
+ 0,
22132
+ 5,
22133
+ 7,
22134
+ 2,
22135
+ 4,
22136
+ 10,
22137
+ 15,
22138
+ 14,
22139
+ 1,
22140
+ 11,
22141
+ 12,
22142
+ 6,
22143
+ 8,
22144
+ 3,
22145
+ 13,
22146
+ 2,
22147
+ 12,
22148
+ 6,
22149
+ 10,
22150
+ 0,
22151
+ 11,
22152
+ 8,
22153
+ 3,
22154
+ 4,
22155
+ 13,
22156
+ 7,
22157
+ 5,
22158
+ 15,
22159
+ 14,
22160
+ 1,
22161
+ 9
22162
+ ]);
22163
+ function G1s(a2, b4, c5, d4, x4) {
22164
+ a2 = a2 + b4 + x4 | 0;
22165
+ d4 = rotr(d4 ^ a2, 16);
22166
+ c5 = c5 + d4 | 0;
22167
+ b4 = rotr(b4 ^ c5, 12);
22168
+ return { a: a2, b: b4, c: c5, d: d4 };
22169
+ }
22170
+ function G2s(a2, b4, c5, d4, x4) {
22171
+ a2 = a2 + b4 + x4 | 0;
22172
+ d4 = rotr(d4 ^ a2, 8);
22173
+ c5 = c5 + d4 | 0;
22174
+ b4 = rotr(b4 ^ c5, 7);
22175
+ return { a: a2, b: b4, c: c5, d: d4 };
22176
+ }
22177
+
22178
+ // node_modules/@noble/hashes/blake2.js
22179
+ var B2B_IV = /* @__PURE__ */ Uint32Array.from([
22180
+ 4089235720,
22181
+ 1779033703,
22182
+ 2227873595,
22183
+ 3144134277,
22184
+ 4271175723,
22185
+ 1013904242,
22186
+ 1595750129,
22187
+ 2773480762,
22188
+ 2917565137,
22189
+ 1359893119,
22190
+ 725511199,
22191
+ 2600822924,
22192
+ 4215389547,
22193
+ 528734635,
22194
+ 327033209,
22195
+ 1541459225
22196
+ ]);
22197
+ var BBUF = /* @__PURE__ */ new Uint32Array(32);
22198
+ function G1b(a2, b4, c5, d4, msg, x4) {
22199
+ const Xl = msg[x4], Xh = msg[x4 + 1];
22200
+ let Al2 = BBUF[2 * a2], Ah = BBUF[2 * a2 + 1];
22201
+ let Bl2 = BBUF[2 * b4], Bh = BBUF[2 * b4 + 1];
22202
+ let Cl2 = BBUF[2 * c5], Ch = BBUF[2 * c5 + 1];
22203
+ let Dl = BBUF[2 * d4], Dh = BBUF[2 * d4 + 1];
22204
+ let ll2 = add3L(Al2, Bl2, Xl);
22205
+ Ah = add3H(ll2, Ah, Bh, Xh);
22206
+ Al2 = ll2 | 0;
22207
+ ({ Dh, Dl } = { Dh: Dh ^ Ah, Dl: Dl ^ Al2 });
22208
+ ({ Dh, Dl } = { Dh: rotr32H(Dh, Dl), Dl: rotr32L(Dh, Dl) });
22209
+ ({ h: Ch, l: Cl2 } = add(Ch, Cl2, Dh, Dl));
22210
+ ({ Bh, Bl: Bl2 } = { Bh: Bh ^ Ch, Bl: Bl2 ^ Cl2 });
22211
+ ({ Bh, Bl: Bl2 } = { Bh: rotrSH(Bh, Bl2, 24), Bl: rotrSL(Bh, Bl2, 24) });
22212
+ BBUF[2 * a2] = Al2, BBUF[2 * a2 + 1] = Ah;
22213
+ BBUF[2 * b4] = Bl2, BBUF[2 * b4 + 1] = Bh;
22214
+ BBUF[2 * c5] = Cl2, BBUF[2 * c5 + 1] = Ch;
22215
+ BBUF[2 * d4] = Dl, BBUF[2 * d4 + 1] = Dh;
22216
+ }
22217
+ function G2b(a2, b4, c5, d4, msg, x4) {
22218
+ const Xl = msg[x4], Xh = msg[x4 + 1];
22219
+ let Al2 = BBUF[2 * a2], Ah = BBUF[2 * a2 + 1];
22220
+ let Bl2 = BBUF[2 * b4], Bh = BBUF[2 * b4 + 1];
22221
+ let Cl2 = BBUF[2 * c5], Ch = BBUF[2 * c5 + 1];
22222
+ let Dl = BBUF[2 * d4], Dh = BBUF[2 * d4 + 1];
22223
+ let ll2 = add3L(Al2, Bl2, Xl);
22224
+ Ah = add3H(ll2, Ah, Bh, Xh);
22225
+ Al2 = ll2 | 0;
22226
+ ({ Dh, Dl } = { Dh: Dh ^ Ah, Dl: Dl ^ Al2 });
22227
+ ({ Dh, Dl } = { Dh: rotrSH(Dh, Dl, 16), Dl: rotrSL(Dh, Dl, 16) });
22228
+ ({ h: Ch, l: Cl2 } = add(Ch, Cl2, Dh, Dl));
22229
+ ({ Bh, Bl: Bl2 } = { Bh: Bh ^ Ch, Bl: Bl2 ^ Cl2 });
22230
+ ({ Bh, Bl: Bl2 } = { Bh: rotrBH(Bh, Bl2, 63), Bl: rotrBL(Bh, Bl2, 63) });
22231
+ BBUF[2 * a2] = Al2, BBUF[2 * a2 + 1] = Ah;
22232
+ BBUF[2 * b4] = Bl2, BBUF[2 * b4 + 1] = Bh;
22233
+ BBUF[2 * c5] = Cl2, BBUF[2 * c5 + 1] = Ch;
22234
+ BBUF[2 * d4] = Dl, BBUF[2 * d4 + 1] = Dh;
22235
+ }
22236
+ function checkBlake2Opts(outputLen, opts = {}, keyLen, saltLen, persLen) {
22237
+ anumber(keyLen);
22238
+ if (outputLen < 0 || outputLen > keyLen)
22239
+ throw new Error("outputLen bigger than keyLen");
22240
+ const { key, salt, personalization } = opts;
22241
+ if (key !== undefined && (key.length < 1 || key.length > keyLen))
22242
+ throw new Error('"key" expected to be undefined or of length=1..' + keyLen);
22243
+ if (salt !== undefined)
22244
+ abytes(salt, saltLen, "salt");
22245
+ if (personalization !== undefined)
22246
+ abytes(personalization, persLen, "personalization");
22247
+ }
22248
+
22249
+ class _BLAKE2 {
22250
+ buffer;
22251
+ buffer32;
22252
+ finished = false;
22253
+ destroyed = false;
22254
+ length = 0;
22255
+ pos = 0;
22256
+ blockLen;
22257
+ outputLen;
22258
+ constructor(blockLen, outputLen) {
22259
+ anumber(blockLen);
22260
+ anumber(outputLen);
22261
+ this.blockLen = blockLen;
22262
+ this.outputLen = outputLen;
22263
+ this.buffer = new Uint8Array(blockLen);
22264
+ this.buffer32 = u32(this.buffer);
22265
+ }
22266
+ update(data) {
22267
+ aexists(this);
22268
+ abytes(data);
22269
+ const { blockLen, buffer, buffer32 } = this;
22270
+ const len = data.length;
22271
+ const offset = data.byteOffset;
22272
+ const buf = data.buffer;
22273
+ for (let pos = 0;pos < len; ) {
22274
+ if (this.pos === blockLen) {
22275
+ swap32IfBE(buffer32);
22276
+ this.compress(buffer32, 0, false);
22277
+ swap32IfBE(buffer32);
22278
+ this.pos = 0;
22279
+ }
22280
+ const take = Math.min(blockLen - this.pos, len - pos);
22281
+ const dataOffset = offset + pos;
22282
+ if (take === blockLen && !(dataOffset % 4) && pos + take < len) {
22283
+ const data32 = new Uint32Array(buf, dataOffset, Math.floor((len - pos) / 4));
22284
+ swap32IfBE(data32);
22285
+ for (let pos32 = 0;pos + blockLen < len; pos32 += buffer32.length, pos += blockLen) {
22286
+ this.length += blockLen;
22287
+ this.compress(data32, pos32, false);
22288
+ }
22289
+ swap32IfBE(data32);
22290
+ continue;
22291
+ }
22292
+ buffer.set(data.subarray(pos, pos + take), this.pos);
22293
+ this.pos += take;
22294
+ this.length += take;
22295
+ pos += take;
22296
+ }
22297
+ return this;
22298
+ }
22299
+ digestInto(out) {
22300
+ aexists(this);
22301
+ aoutput(out, this);
22302
+ const { pos, buffer32 } = this;
22303
+ this.finished = true;
22304
+ clean(this.buffer.subarray(pos));
22305
+ swap32IfBE(buffer32);
22306
+ this.compress(buffer32, 0, true);
22307
+ swap32IfBE(buffer32);
22308
+ const out32 = u32(out);
22309
+ this.get().forEach((v4, i2) => out32[i2] = swap8IfBE(v4));
22310
+ }
22311
+ digest() {
22312
+ const { buffer, outputLen } = this;
22313
+ this.digestInto(buffer);
22314
+ const res = buffer.slice(0, outputLen);
22315
+ this.destroy();
22316
+ return res;
22317
+ }
22318
+ _cloneInto(to) {
22319
+ const { buffer, length, finished, destroyed, outputLen, pos } = this;
22320
+ to ||= new this.constructor({ dkLen: outputLen });
22321
+ to.set(...this.get());
22322
+ to.buffer.set(buffer);
22323
+ to.destroyed = destroyed;
22324
+ to.finished = finished;
22325
+ to.length = length;
22326
+ to.pos = pos;
22327
+ to.outputLen = outputLen;
22328
+ return to;
22329
+ }
22330
+ clone() {
22331
+ return this._cloneInto();
22332
+ }
22333
+ }
22334
+
22335
+ class _BLAKE2b extends _BLAKE2 {
22336
+ v0l = B2B_IV[0] | 0;
22337
+ v0h = B2B_IV[1] | 0;
22338
+ v1l = B2B_IV[2] | 0;
22339
+ v1h = B2B_IV[3] | 0;
22340
+ v2l = B2B_IV[4] | 0;
22341
+ v2h = B2B_IV[5] | 0;
22342
+ v3l = B2B_IV[6] | 0;
22343
+ v3h = B2B_IV[7] | 0;
22344
+ v4l = B2B_IV[8] | 0;
22345
+ v4h = B2B_IV[9] | 0;
22346
+ v5l = B2B_IV[10] | 0;
22347
+ v5h = B2B_IV[11] | 0;
22348
+ v6l = B2B_IV[12] | 0;
22349
+ v6h = B2B_IV[13] | 0;
22350
+ v7l = B2B_IV[14] | 0;
22351
+ v7h = B2B_IV[15] | 0;
22352
+ constructor(opts = {}) {
22353
+ const olen = opts.dkLen === undefined ? 64 : opts.dkLen;
22354
+ super(128, olen);
22355
+ checkBlake2Opts(olen, opts, 64, 16, 16);
22356
+ let { key, personalization, salt } = opts;
22357
+ let keyLength = 0;
22358
+ if (key !== undefined) {
22359
+ abytes(key, undefined, "key");
22360
+ keyLength = key.length;
22361
+ }
22362
+ this.v0l ^= this.outputLen | keyLength << 8 | 1 << 16 | 1 << 24;
22363
+ if (salt !== undefined) {
22364
+ abytes(salt, undefined, "salt");
22365
+ const slt = u32(salt);
22366
+ this.v4l ^= swap8IfBE(slt[0]);
22367
+ this.v4h ^= swap8IfBE(slt[1]);
22368
+ this.v5l ^= swap8IfBE(slt[2]);
22369
+ this.v5h ^= swap8IfBE(slt[3]);
22370
+ }
22371
+ if (personalization !== undefined) {
22372
+ abytes(personalization, undefined, "personalization");
22373
+ const pers = u32(personalization);
22374
+ this.v6l ^= swap8IfBE(pers[0]);
22375
+ this.v6h ^= swap8IfBE(pers[1]);
22376
+ this.v7l ^= swap8IfBE(pers[2]);
22377
+ this.v7h ^= swap8IfBE(pers[3]);
22378
+ }
22379
+ if (key !== undefined) {
22380
+ const tmp = new Uint8Array(this.blockLen);
22381
+ tmp.set(key);
22382
+ this.update(tmp);
22383
+ }
22384
+ }
22385
+ get() {
22386
+ let { v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h } = this;
22387
+ return [v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h];
22388
+ }
22389
+ set(v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h) {
22390
+ this.v0l = v0l | 0;
22391
+ this.v0h = v0h | 0;
22392
+ this.v1l = v1l | 0;
22393
+ this.v1h = v1h | 0;
22394
+ this.v2l = v2l | 0;
22395
+ this.v2h = v2h | 0;
22396
+ this.v3l = v3l | 0;
22397
+ this.v3h = v3h | 0;
22398
+ this.v4l = v4l | 0;
22399
+ this.v4h = v4h | 0;
22400
+ this.v5l = v5l | 0;
22401
+ this.v5h = v5h | 0;
22402
+ this.v6l = v6l | 0;
22403
+ this.v6h = v6h | 0;
22404
+ this.v7l = v7l | 0;
22405
+ this.v7h = v7h | 0;
22406
+ }
22407
+ compress(msg, offset, isLast) {
22408
+ this.get().forEach((v4, i2) => BBUF[i2] = v4);
22409
+ BBUF.set(B2B_IV, 16);
22410
+ let { h: h4, l: l3 } = fromBig(BigInt(this.length));
22411
+ BBUF[24] = B2B_IV[8] ^ l3;
22412
+ BBUF[25] = B2B_IV[9] ^ h4;
22413
+ if (isLast) {
22414
+ BBUF[28] = ~BBUF[28];
22415
+ BBUF[29] = ~BBUF[29];
22416
+ }
22417
+ let j2 = 0;
22418
+ const s2 = BSIGMA;
22419
+ for (let i2 = 0;i2 < 12; i2++) {
22420
+ G1b(0, 4, 8, 12, msg, offset + 2 * s2[j2++]);
22421
+ G2b(0, 4, 8, 12, msg, offset + 2 * s2[j2++]);
22422
+ G1b(1, 5, 9, 13, msg, offset + 2 * s2[j2++]);
22423
+ G2b(1, 5, 9, 13, msg, offset + 2 * s2[j2++]);
22424
+ G1b(2, 6, 10, 14, msg, offset + 2 * s2[j2++]);
22425
+ G2b(2, 6, 10, 14, msg, offset + 2 * s2[j2++]);
22426
+ G1b(3, 7, 11, 15, msg, offset + 2 * s2[j2++]);
22427
+ G2b(3, 7, 11, 15, msg, offset + 2 * s2[j2++]);
22428
+ G1b(0, 5, 10, 15, msg, offset + 2 * s2[j2++]);
22429
+ G2b(0, 5, 10, 15, msg, offset + 2 * s2[j2++]);
22430
+ G1b(1, 6, 11, 12, msg, offset + 2 * s2[j2++]);
22431
+ G2b(1, 6, 11, 12, msg, offset + 2 * s2[j2++]);
22432
+ G1b(2, 7, 8, 13, msg, offset + 2 * s2[j2++]);
22433
+ G2b(2, 7, 8, 13, msg, offset + 2 * s2[j2++]);
22434
+ G1b(3, 4, 9, 14, msg, offset + 2 * s2[j2++]);
22435
+ G2b(3, 4, 9, 14, msg, offset + 2 * s2[j2++]);
22436
+ }
22437
+ this.v0l ^= BBUF[0] ^ BBUF[16];
22438
+ this.v0h ^= BBUF[1] ^ BBUF[17];
22439
+ this.v1l ^= BBUF[2] ^ BBUF[18];
22440
+ this.v1h ^= BBUF[3] ^ BBUF[19];
22441
+ this.v2l ^= BBUF[4] ^ BBUF[20];
22442
+ this.v2h ^= BBUF[5] ^ BBUF[21];
22443
+ this.v3l ^= BBUF[6] ^ BBUF[22];
22444
+ this.v3h ^= BBUF[7] ^ BBUF[23];
22445
+ this.v4l ^= BBUF[8] ^ BBUF[24];
22446
+ this.v4h ^= BBUF[9] ^ BBUF[25];
22447
+ this.v5l ^= BBUF[10] ^ BBUF[26];
22448
+ this.v5h ^= BBUF[11] ^ BBUF[27];
22449
+ this.v6l ^= BBUF[12] ^ BBUF[28];
22450
+ this.v6h ^= BBUF[13] ^ BBUF[29];
22451
+ this.v7l ^= BBUF[14] ^ BBUF[30];
22452
+ this.v7h ^= BBUF[15] ^ BBUF[31];
22453
+ clean(BBUF);
22454
+ }
22455
+ destroy() {
22456
+ this.destroyed = true;
22457
+ clean(this.buffer32);
22458
+ this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
22459
+ }
22460
+ }
22461
+ function compress(s2, offset, msg, rounds, v0, v1, v22, v32, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) {
22462
+ let j2 = 0;
22463
+ for (let i2 = 0;i2 < rounds; i2++) {
22464
+ ({ a: v0, b: v4, c: v8, d: v12 } = G1s(v0, v4, v8, v12, msg[offset + s2[j2++]]));
22465
+ ({ a: v0, b: v4, c: v8, d: v12 } = G2s(v0, v4, v8, v12, msg[offset + s2[j2++]]));
22466
+ ({ a: v1, b: v5, c: v9, d: v13 } = G1s(v1, v5, v9, v13, msg[offset + s2[j2++]]));
22467
+ ({ a: v1, b: v5, c: v9, d: v13 } = G2s(v1, v5, v9, v13, msg[offset + s2[j2++]]));
22468
+ ({ a: v22, b: v6, c: v10, d: v14 } = G1s(v22, v6, v10, v14, msg[offset + s2[j2++]]));
22469
+ ({ a: v22, b: v6, c: v10, d: v14 } = G2s(v22, v6, v10, v14, msg[offset + s2[j2++]]));
22470
+ ({ a: v32, b: v7, c: v11, d: v15 } = G1s(v32, v7, v11, v15, msg[offset + s2[j2++]]));
22471
+ ({ a: v32, b: v7, c: v11, d: v15 } = G2s(v32, v7, v11, v15, msg[offset + s2[j2++]]));
22472
+ ({ a: v0, b: v5, c: v10, d: v15 } = G1s(v0, v5, v10, v15, msg[offset + s2[j2++]]));
22473
+ ({ a: v0, b: v5, c: v10, d: v15 } = G2s(v0, v5, v10, v15, msg[offset + s2[j2++]]));
22474
+ ({ a: v1, b: v6, c: v11, d: v12 } = G1s(v1, v6, v11, v12, msg[offset + s2[j2++]]));
22475
+ ({ a: v1, b: v6, c: v11, d: v12 } = G2s(v1, v6, v11, v12, msg[offset + s2[j2++]]));
22476
+ ({ a: v22, b: v7, c: v8, d: v13 } = G1s(v22, v7, v8, v13, msg[offset + s2[j2++]]));
22477
+ ({ a: v22, b: v7, c: v8, d: v13 } = G2s(v22, v7, v8, v13, msg[offset + s2[j2++]]));
22478
+ ({ a: v32, b: v4, c: v9, d: v14 } = G1s(v32, v4, v9, v14, msg[offset + s2[j2++]]));
22479
+ ({ a: v32, b: v4, c: v9, d: v14 } = G2s(v32, v4, v9, v14, msg[offset + s2[j2++]]));
22480
+ }
22481
+ return { v0, v1, v2: v22, v3: v32, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 };
22482
+ }
22483
+ var B2S_IV = /* @__PURE__ */ SHA256_IV.slice();
22484
+
22485
+ class _BLAKE2s extends _BLAKE2 {
22486
+ v0 = B2S_IV[0] | 0;
22487
+ v1 = B2S_IV[1] | 0;
22488
+ v2 = B2S_IV[2] | 0;
22489
+ v3 = B2S_IV[3] | 0;
22490
+ v4 = B2S_IV[4] | 0;
22491
+ v5 = B2S_IV[5] | 0;
22492
+ v6 = B2S_IV[6] | 0;
22493
+ v7 = B2S_IV[7] | 0;
22494
+ constructor(opts = {}) {
22495
+ const olen = opts.dkLen === undefined ? 32 : opts.dkLen;
22496
+ super(64, olen);
22497
+ checkBlake2Opts(olen, opts, 32, 8, 8);
22498
+ let { key, personalization, salt } = opts;
22499
+ let keyLength = 0;
22500
+ if (key !== undefined) {
22501
+ abytes(key, undefined, "key");
22502
+ keyLength = key.length;
22503
+ }
22504
+ this.v0 ^= this.outputLen | keyLength << 8 | 1 << 16 | 1 << 24;
22505
+ if (salt !== undefined) {
22506
+ abytes(salt, undefined, "salt");
22507
+ const slt = u32(salt);
22508
+ this.v4 ^= swap8IfBE(slt[0]);
22509
+ this.v5 ^= swap8IfBE(slt[1]);
22510
+ }
22511
+ if (personalization !== undefined) {
22512
+ abytes(personalization, undefined, "personalization");
22513
+ const pers = u32(personalization);
22514
+ this.v6 ^= swap8IfBE(pers[0]);
22515
+ this.v7 ^= swap8IfBE(pers[1]);
22516
+ }
22517
+ if (key !== undefined) {
22518
+ const tmp = new Uint8Array(this.blockLen);
22519
+ tmp.set(key);
22520
+ this.update(tmp);
22521
+ }
22522
+ }
22523
+ get() {
22524
+ const { v0, v1, v2: v22, v3: v32, v4, v5, v6, v7 } = this;
22525
+ return [v0, v1, v22, v32, v4, v5, v6, v7];
22526
+ }
22527
+ set(v0, v1, v22, v32, v4, v5, v6, v7) {
22528
+ this.v0 = v0 | 0;
22529
+ this.v1 = v1 | 0;
22530
+ this.v2 = v22 | 0;
22531
+ this.v3 = v32 | 0;
22532
+ this.v4 = v4 | 0;
22533
+ this.v5 = v5 | 0;
22534
+ this.v6 = v6 | 0;
22535
+ this.v7 = v7 | 0;
22536
+ }
22537
+ compress(msg, offset, isLast) {
22538
+ const { h: h4, l: l3 } = fromBig(BigInt(this.length));
22539
+ const { v0, v1, v2: v22, v3: v32, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 } = compress(BSIGMA, offset, msg, 10, this.v0, this.v1, this.v2, this.v3, this.v4, this.v5, this.v6, this.v7, B2S_IV[0], B2S_IV[1], B2S_IV[2], B2S_IV[3], l3 ^ B2S_IV[4], h4 ^ B2S_IV[5], isLast ? ~B2S_IV[6] : B2S_IV[6], B2S_IV[7]);
22540
+ this.v0 ^= v0 ^ v8;
22541
+ this.v1 ^= v1 ^ v9;
22542
+ this.v2 ^= v22 ^ v10;
22543
+ this.v3 ^= v32 ^ v11;
22544
+ this.v4 ^= v4 ^ v12;
22545
+ this.v5 ^= v5 ^ v13;
22546
+ this.v6 ^= v6 ^ v14;
22547
+ this.v7 ^= v7 ^ v15;
22548
+ }
22549
+ destroy() {
22550
+ this.destroyed = true;
22551
+ clean(this.buffer32);
22552
+ this.set(0, 0, 0, 0, 0, 0, 0, 0);
22553
+ }
22554
+ }
22555
+
22556
+ // node_modules/@noble/hashes/blake3.js
22557
+ var B3_Flags = {
22558
+ CHUNK_START: 1,
22559
+ CHUNK_END: 2,
22560
+ PARENT: 4,
22561
+ ROOT: 8,
22562
+ KEYED_HASH: 16,
22563
+ DERIVE_KEY_CONTEXT: 32,
22564
+ DERIVE_KEY_MATERIAL: 64
22565
+ };
22566
+ var B3_IV = /* @__PURE__ */ SHA256_IV.slice();
22567
+ var B3_SIGMA = /* @__PURE__ */ (() => {
22568
+ const Id = Array.from({ length: 16 }, (_5, i2) => i2);
22569
+ const permute = (arr) => [2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8].map((i2) => arr[i2]);
22570
+ const res = [];
22571
+ for (let i2 = 0, v4 = Id;i2 < 7; i2++, v4 = permute(v4))
22572
+ res.push(...v4);
22573
+ return Uint8Array.from(res);
22574
+ })();
22575
+
22576
+ class _BLAKE3 extends _BLAKE2 {
22577
+ chunkPos = 0;
22578
+ chunksDone = 0;
22579
+ flags = 0 | 0;
22580
+ IV;
22581
+ state;
22582
+ stack = [];
22583
+ posOut = 0;
22584
+ bufferOut32 = new Uint32Array(16);
22585
+ bufferOut;
22586
+ chunkOut = 0;
22587
+ enableXOF = true;
22588
+ constructor(opts = {}, flags = 0) {
22589
+ super(64, opts.dkLen === undefined ? 32 : opts.dkLen);
22590
+ const { key, context } = opts;
22591
+ const hasContext = context !== undefined;
22592
+ if (key !== undefined) {
22593
+ if (hasContext)
22594
+ throw new Error('Only "key" or "context" can be specified at same time');
22595
+ abytes(key, 32, "key");
22596
+ const k5 = key.slice();
22597
+ this.IV = u32(k5);
22598
+ swap32IfBE(this.IV);
22599
+ this.flags = flags | B3_Flags.KEYED_HASH;
22600
+ } else if (hasContext) {
22601
+ abytes(context, undefined, "context");
22602
+ const ctx = context;
22603
+ const contextKey = new _BLAKE3({ dkLen: 32 }, B3_Flags.DERIVE_KEY_CONTEXT).update(ctx).digest();
22604
+ this.IV = u32(contextKey);
22605
+ swap32IfBE(this.IV);
22606
+ this.flags = flags | B3_Flags.DERIVE_KEY_MATERIAL;
22607
+ } else {
22608
+ this.IV = B3_IV.slice();
22609
+ this.flags = flags;
22610
+ }
22611
+ this.state = this.IV.slice();
22612
+ this.bufferOut = u8(this.bufferOut32);
22613
+ }
22614
+ get() {
22615
+ return [];
22616
+ }
22617
+ set() {}
22618
+ b2Compress(counter, flags, buf, bufPos = 0) {
22619
+ const { state: s2, pos } = this;
22620
+ const { h: h4, l: l3 } = fromBig(BigInt(counter), true);
22621
+ const { v0, v1, v2: v22, v3: v32, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 } = compress(B3_SIGMA, bufPos, buf, 7, s2[0], s2[1], s2[2], s2[3], s2[4], s2[5], s2[6], s2[7], B3_IV[0], B3_IV[1], B3_IV[2], B3_IV[3], h4, l3, pos, flags);
22622
+ s2[0] = v0 ^ v8;
22623
+ s2[1] = v1 ^ v9;
22624
+ s2[2] = v22 ^ v10;
22625
+ s2[3] = v32 ^ v11;
22626
+ s2[4] = v4 ^ v12;
22627
+ s2[5] = v5 ^ v13;
22628
+ s2[6] = v6 ^ v14;
22629
+ s2[7] = v7 ^ v15;
22630
+ }
22631
+ compress(buf, bufPos = 0, isLast = false) {
22632
+ let flags = this.flags;
22633
+ if (!this.chunkPos)
22634
+ flags |= B3_Flags.CHUNK_START;
22635
+ if (this.chunkPos === 15 || isLast)
22636
+ flags |= B3_Flags.CHUNK_END;
22637
+ if (!isLast)
22638
+ this.pos = this.blockLen;
22639
+ this.b2Compress(this.chunksDone, flags, buf, bufPos);
22640
+ this.chunkPos += 1;
22641
+ if (this.chunkPos === 16 || isLast) {
22642
+ let chunk = this.state;
22643
+ this.state = this.IV.slice();
22644
+ for (let last, chunks = this.chunksDone + 1;isLast || !(chunks & 1); chunks >>= 1) {
22645
+ if (!(last = this.stack.pop()))
22646
+ break;
22647
+ this.buffer32.set(last, 0);
22648
+ this.buffer32.set(chunk, 8);
22649
+ this.pos = this.blockLen;
22650
+ this.b2Compress(0, this.flags | B3_Flags.PARENT, this.buffer32, 0);
22651
+ chunk = this.state;
22652
+ this.state = this.IV.slice();
22653
+ }
22654
+ this.chunksDone++;
22655
+ this.chunkPos = 0;
22656
+ this.stack.push(chunk);
22657
+ }
22658
+ this.pos = 0;
22659
+ }
22660
+ _cloneInto(to) {
22661
+ to = super._cloneInto(to);
22662
+ const { IV, flags, state, chunkPos, posOut, chunkOut, stack, chunksDone } = this;
22663
+ to.state.set(state.slice());
22664
+ to.stack = stack.map((i2) => Uint32Array.from(i2));
22665
+ to.IV.set(IV);
22666
+ to.flags = flags;
22667
+ to.chunkPos = chunkPos;
22668
+ to.chunksDone = chunksDone;
22669
+ to.posOut = posOut;
22670
+ to.chunkOut = chunkOut;
22671
+ to.enableXOF = this.enableXOF;
22672
+ to.bufferOut32.set(this.bufferOut32);
22673
+ return to;
22674
+ }
22675
+ destroy() {
22676
+ this.destroyed = true;
22677
+ clean(this.state, this.buffer32, this.IV, this.bufferOut32);
22678
+ clean(...this.stack);
22679
+ }
22680
+ b2CompressOut() {
22681
+ const { state: s2, pos, flags, buffer32, bufferOut32: out32 } = this;
22682
+ const { h: h4, l: l3 } = fromBig(BigInt(this.chunkOut++));
22683
+ swap32IfBE(buffer32);
22684
+ const { v0, v1, v2: v22, v3: v32, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 } = compress(B3_SIGMA, 0, buffer32, 7, s2[0], s2[1], s2[2], s2[3], s2[4], s2[5], s2[6], s2[7], B3_IV[0], B3_IV[1], B3_IV[2], B3_IV[3], l3, h4, pos, flags);
22685
+ out32[0] = v0 ^ v8;
22686
+ out32[1] = v1 ^ v9;
22687
+ out32[2] = v22 ^ v10;
22688
+ out32[3] = v32 ^ v11;
22689
+ out32[4] = v4 ^ v12;
22690
+ out32[5] = v5 ^ v13;
22691
+ out32[6] = v6 ^ v14;
22692
+ out32[7] = v7 ^ v15;
22693
+ out32[8] = s2[0] ^ v8;
22694
+ out32[9] = s2[1] ^ v9;
22695
+ out32[10] = s2[2] ^ v10;
22696
+ out32[11] = s2[3] ^ v11;
22697
+ out32[12] = s2[4] ^ v12;
22698
+ out32[13] = s2[5] ^ v13;
22699
+ out32[14] = s2[6] ^ v14;
22700
+ out32[15] = s2[7] ^ v15;
22701
+ swap32IfBE(buffer32);
22702
+ swap32IfBE(out32);
22703
+ this.posOut = 0;
22704
+ }
22705
+ finish() {
22706
+ if (this.finished)
22707
+ return;
22708
+ this.finished = true;
22709
+ clean(this.buffer.subarray(this.pos));
22710
+ let flags = this.flags | B3_Flags.ROOT;
22711
+ if (this.stack.length) {
22712
+ flags |= B3_Flags.PARENT;
22713
+ swap32IfBE(this.buffer32);
22714
+ this.compress(this.buffer32, 0, true);
22715
+ swap32IfBE(this.buffer32);
22716
+ this.chunksDone = 0;
22717
+ this.pos = this.blockLen;
22718
+ } else {
22719
+ flags |= (!this.chunkPos ? B3_Flags.CHUNK_START : 0) | B3_Flags.CHUNK_END;
22720
+ }
22721
+ this.flags = flags;
22722
+ this.b2CompressOut();
22723
+ }
22724
+ writeInto(out) {
22725
+ aexists(this, false);
22726
+ abytes(out);
22727
+ this.finish();
22728
+ const { blockLen, bufferOut } = this;
22729
+ for (let pos = 0, len = out.length;pos < len; ) {
22730
+ if (this.posOut >= blockLen)
22731
+ this.b2CompressOut();
22732
+ const take = Math.min(blockLen - this.posOut, len - pos);
22733
+ out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos);
22734
+ this.posOut += take;
22735
+ pos += take;
22736
+ }
22737
+ return out;
22738
+ }
22739
+ xofInto(out) {
22740
+ if (!this.enableXOF)
22741
+ throw new Error("XOF is not possible after digest call");
22742
+ return this.writeInto(out);
22743
+ }
22744
+ xof(bytes) {
22745
+ anumber(bytes);
22746
+ return this.xofInto(new Uint8Array(bytes));
22747
+ }
22748
+ digestInto(out) {
22749
+ aoutput(out, this);
22750
+ if (this.finished)
22751
+ throw new Error("digest() was already called");
22752
+ this.enableXOF = false;
22753
+ this.writeInto(out);
22754
+ this.destroy();
22755
+ return out;
22756
+ }
22757
+ digest() {
22758
+ return this.digestInto(new Uint8Array(this.outputLen));
22759
+ }
22760
+ }
22761
+ var blake3 = /* @__PURE__ */ createHasher((opts = {}) => new _BLAKE3(opts));
22762
+
22763
+ // node_modules/@scure/base/index.js
22764
+ /*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) */
22765
+ function isBytes2(a2) {
22766
+ return a2 instanceof Uint8Array || ArrayBuffer.isView(a2) && a2.constructor.name === "Uint8Array";
22767
+ }
22768
+ function abytes2(b4) {
22769
+ if (!isBytes2(b4))
22770
+ throw new Error("Uint8Array expected");
22771
+ }
22772
+ function isArrayOf(isString, arr) {
22773
+ if (!Array.isArray(arr))
22774
+ return false;
22775
+ if (arr.length === 0)
22776
+ return true;
22777
+ if (isString) {
22778
+ return arr.every((item) => typeof item === "string");
22779
+ } else {
22780
+ return arr.every((item) => Number.isSafeInteger(item));
22781
+ }
22782
+ }
22783
+ function afn(input) {
22784
+ if (typeof input !== "function")
22785
+ throw new Error("function expected");
22786
+ return true;
22787
+ }
22788
+ function astr(label, input) {
22789
+ if (typeof input !== "string")
22790
+ throw new Error(`${label}: string expected`);
22791
+ return true;
22792
+ }
22793
+ function anumber2(n5) {
22794
+ if (!Number.isSafeInteger(n5))
22795
+ throw new Error(`invalid integer: ${n5}`);
22796
+ }
22797
+ function aArr(input) {
22798
+ if (!Array.isArray(input))
22799
+ throw new Error("array expected");
22800
+ }
22801
+ function astrArr(label, input) {
22802
+ if (!isArrayOf(true, input))
22803
+ throw new Error(`${label}: array of strings expected`);
22804
+ }
22805
+ function anumArr(label, input) {
22806
+ if (!isArrayOf(false, input))
22807
+ throw new Error(`${label}: array of numbers expected`);
22808
+ }
22809
+ function chain(...args) {
22810
+ const id = (a2) => a2;
22811
+ const wrap = (a2, b4) => (c5) => a2(b4(c5));
22812
+ const encode4 = args.map((x4) => x4.encode).reduceRight(wrap, id);
22813
+ const decode4 = args.map((x4) => x4.decode).reduce(wrap, id);
22814
+ return { encode: encode4, decode: decode4 };
22815
+ }
22816
+ function alphabet(letters) {
22817
+ const lettersA = typeof letters === "string" ? letters.split("") : letters;
22818
+ const len = lettersA.length;
22819
+ astrArr("alphabet", lettersA);
22820
+ const indexes = new Map(lettersA.map((l3, i2) => [l3, i2]));
22821
+ return {
22822
+ encode: (digits) => {
22823
+ aArr(digits);
22824
+ return digits.map((i2) => {
22825
+ if (!Number.isSafeInteger(i2) || i2 < 0 || i2 >= len)
22826
+ throw new Error(`alphabet.encode: digit index outside alphabet "${i2}". Allowed: ${letters}`);
22827
+ return lettersA[i2];
22828
+ });
22829
+ },
22830
+ decode: (input) => {
22831
+ aArr(input);
22832
+ return input.map((letter) => {
22833
+ astr("alphabet.decode", letter);
22834
+ const i2 = indexes.get(letter);
22835
+ if (i2 === undefined)
22836
+ throw new Error(`Unknown letter: "${letter}". Allowed: ${letters}`);
22837
+ return i2;
22838
+ });
22839
+ }
22840
+ };
22841
+ }
22842
+ function join2(separator = "") {
22843
+ astr("join", separator);
22844
+ return {
22845
+ encode: (from) => {
22846
+ astrArr("join.decode", from);
22847
+ return from.join(separator);
22848
+ },
22849
+ decode: (to) => {
22850
+ astr("join.decode", to);
22851
+ return to.split(separator);
22852
+ }
22853
+ };
22854
+ }
22855
+ function padding(bits, chr = "=") {
22856
+ anumber2(bits);
22857
+ astr("padding", chr);
22858
+ return {
22859
+ encode(data) {
22860
+ astrArr("padding.encode", data);
22861
+ while (data.length * bits % 8)
22862
+ data.push(chr);
22863
+ return data;
22864
+ },
22865
+ decode(input) {
22866
+ astrArr("padding.decode", input);
22867
+ let end = input.length;
22868
+ if (end * bits % 8)
22869
+ throw new Error("padding: invalid, string should have whole number of bytes");
22870
+ for (;end > 0 && input[end - 1] === chr; end--) {
22871
+ const last = end - 1;
22872
+ const byte = last * bits;
22873
+ if (byte % 8 === 0)
22874
+ throw new Error("padding: invalid, string has too much padding");
22875
+ }
22876
+ return input.slice(0, end);
22877
+ }
22878
+ };
22879
+ }
22880
+ function normalize(fn) {
22881
+ afn(fn);
22882
+ return { encode: (from) => from, decode: (to) => fn(to) };
22883
+ }
22884
+ function convertRadix(data, from, to) {
22885
+ if (from < 2)
22886
+ throw new Error(`convertRadix: invalid from=${from}, base cannot be less than 2`);
22887
+ if (to < 2)
22888
+ throw new Error(`convertRadix: invalid to=${to}, base cannot be less than 2`);
22889
+ aArr(data);
22890
+ if (!data.length)
22891
+ return [];
22892
+ let pos = 0;
22893
+ const res = [];
22894
+ const digits = Array.from(data, (d4) => {
22895
+ anumber2(d4);
22896
+ if (d4 < 0 || d4 >= from)
22897
+ throw new Error(`invalid integer: ${d4}`);
22898
+ return d4;
22899
+ });
22900
+ const dlen = digits.length;
22901
+ while (true) {
22902
+ let carry = 0;
22903
+ let done = true;
22904
+ for (let i2 = pos;i2 < dlen; i2++) {
22905
+ const digit = digits[i2];
22906
+ const fromCarry = from * carry;
22907
+ const digitBase = fromCarry + digit;
22908
+ if (!Number.isSafeInteger(digitBase) || fromCarry / from !== carry || digitBase - digit !== fromCarry) {
22909
+ throw new Error("convertRadix: carry overflow");
22910
+ }
22911
+ const div = digitBase / to;
22912
+ carry = digitBase % to;
22913
+ const rounded = Math.floor(div);
22914
+ digits[i2] = rounded;
22915
+ if (!Number.isSafeInteger(rounded) || rounded * to + carry !== digitBase)
22916
+ throw new Error("convertRadix: carry overflow");
22917
+ if (!done)
22918
+ continue;
22919
+ else if (!rounded)
22920
+ pos = i2;
22921
+ else
22922
+ done = false;
22923
+ }
22924
+ res.push(carry);
22925
+ if (done)
22926
+ break;
22927
+ }
22928
+ for (let i2 = 0;i2 < data.length - 1 && data[i2] === 0; i2++)
22929
+ res.push(0);
22930
+ return res.reverse();
22931
+ }
22932
+ var gcd = (a2, b4) => b4 === 0 ? a2 : gcd(b4, a2 % b4);
22933
+ var radix2carry = (from, to) => from + (to - gcd(from, to));
22934
+ var powers = /* @__PURE__ */ (() => {
22935
+ let res = [];
22936
+ for (let i2 = 0;i2 < 40; i2++)
22937
+ res.push(2 ** i2);
22938
+ return res;
22939
+ })();
22940
+ function convertRadix2(data, from, to, padding2) {
22941
+ aArr(data);
22942
+ if (from <= 0 || from > 32)
22943
+ throw new Error(`convertRadix2: wrong from=${from}`);
22944
+ if (to <= 0 || to > 32)
22945
+ throw new Error(`convertRadix2: wrong to=${to}`);
22946
+ if (radix2carry(from, to) > 32) {
22947
+ throw new Error(`convertRadix2: carry overflow from=${from} to=${to} carryBits=${radix2carry(from, to)}`);
22948
+ }
22949
+ let carry = 0;
22950
+ let pos = 0;
22951
+ const max = powers[from];
22952
+ const mask = powers[to] - 1;
22953
+ const res = [];
22954
+ for (const n5 of data) {
22955
+ anumber2(n5);
22956
+ if (n5 >= max)
22957
+ throw new Error(`convertRadix2: invalid data word=${n5} from=${from}`);
22958
+ carry = carry << from | n5;
22959
+ if (pos + from > 32)
22960
+ throw new Error(`convertRadix2: carry overflow pos=${pos} from=${from}`);
22961
+ pos += from;
22962
+ for (;pos >= to; pos -= to)
22963
+ res.push((carry >> pos - to & mask) >>> 0);
22964
+ const pow = powers[pos];
22965
+ if (pow === undefined)
22966
+ throw new Error("invalid carry");
22967
+ carry &= pow - 1;
22968
+ }
22969
+ carry = carry << to - pos & mask;
22970
+ if (!padding2 && pos >= from)
22971
+ throw new Error("Excess padding");
22972
+ if (!padding2 && carry > 0)
22973
+ throw new Error(`Non-zero padding: ${carry}`);
22974
+ if (padding2 && pos > 0)
22975
+ res.push(carry >>> 0);
22976
+ return res;
22977
+ }
22978
+ function radix(num) {
22979
+ anumber2(num);
22980
+ const _256 = 2 ** 8;
22981
+ return {
22982
+ encode: (bytes) => {
22983
+ if (!isBytes2(bytes))
22984
+ throw new Error("radix.encode input should be Uint8Array");
22985
+ return convertRadix(Array.from(bytes), _256, num);
22986
+ },
22987
+ decode: (digits) => {
22988
+ anumArr("radix.decode", digits);
22989
+ return Uint8Array.from(convertRadix(digits, num, _256));
22990
+ }
22991
+ };
22992
+ }
22993
+ function radix2(bits, revPadding = false) {
22994
+ anumber2(bits);
22995
+ if (bits <= 0 || bits > 32)
22996
+ throw new Error("radix2: bits should be in (0..32]");
22997
+ if (radix2carry(8, bits) > 32 || radix2carry(bits, 8) > 32)
22998
+ throw new Error("radix2: carry overflow");
22999
+ return {
23000
+ encode: (bytes) => {
23001
+ if (!isBytes2(bytes))
23002
+ throw new Error("radix2.encode input should be Uint8Array");
23003
+ return convertRadix2(Array.from(bytes), 8, bits, !revPadding);
23004
+ },
23005
+ decode: (digits) => {
23006
+ anumArr("radix2.decode", digits);
23007
+ return Uint8Array.from(convertRadix2(digits, bits, 8, revPadding));
23008
+ }
23009
+ };
23010
+ }
23011
+ function unsafeWrapper(fn) {
23012
+ afn(fn);
23013
+ return function(...args) {
23014
+ try {
23015
+ return fn.apply(null, args);
23016
+ } catch (e3) {}
23017
+ };
23018
+ }
23019
+ var base16 = chain(radix2(4), alphabet("0123456789ABCDEF"), join2(""));
23020
+ var base32 = chain(radix2(5), alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"), padding(5), join2(""));
23021
+ var base32nopad = chain(radix2(5), alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"), join2(""));
23022
+ var base32hex = chain(radix2(5), alphabet("0123456789ABCDEFGHIJKLMNOPQRSTUV"), padding(5), join2(""));
23023
+ var base32hexnopad = chain(radix2(5), alphabet("0123456789ABCDEFGHIJKLMNOPQRSTUV"), join2(""));
23024
+ var base32crockford = chain(radix2(5), alphabet("0123456789ABCDEFGHJKMNPQRSTVWXYZ"), join2(""), normalize((s2) => s2.toUpperCase().replace(/O/g, "0").replace(/[IL]/g, "1")));
23025
+ var hasBase64Builtin = /* @__PURE__ */ (() => typeof Uint8Array.from([]).toBase64 === "function" && typeof Uint8Array.fromBase64 === "function")();
23026
+ var decodeBase64Builtin = (s2, isUrl) => {
23027
+ astr("base64", s2);
23028
+ const re = isUrl ? /^[A-Za-z0-9=_-]+$/ : /^[A-Za-z0-9=+/]+$/;
23029
+ const alphabet2 = isUrl ? "base64url" : "base64";
23030
+ if (s2.length > 0 && !re.test(s2))
23031
+ throw new Error("invalid base64");
23032
+ return Uint8Array.fromBase64(s2, { alphabet: alphabet2, lastChunkHandling: "strict" });
23033
+ };
23034
+ var base643 = hasBase64Builtin ? {
23035
+ encode(b4) {
23036
+ abytes2(b4);
23037
+ return b4.toBase64();
23038
+ },
23039
+ decode(s2) {
23040
+ return decodeBase64Builtin(s2, false);
23041
+ }
23042
+ } : chain(radix2(6), alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), padding(6), join2(""));
23043
+ var base64nopad = chain(radix2(6), alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), join2(""));
23044
+ var base64url3 = hasBase64Builtin ? {
23045
+ encode(b4) {
23046
+ abytes2(b4);
23047
+ return b4.toBase64({ alphabet: "base64url" });
23048
+ },
23049
+ decode(s2) {
23050
+ return decodeBase64Builtin(s2, true);
23051
+ }
23052
+ } : chain(radix2(6), alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"), padding(6), join2(""));
23053
+ var base64urlnopad = chain(radix2(6), alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"), join2(""));
23054
+ var genBase58 = (abc) => chain(radix(58), alphabet(abc), join2(""));
23055
+ var base58 = genBase58("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz");
23056
+ var base58flickr = genBase58("123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ");
23057
+ var base58xrp = genBase58("rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz");
23058
+ var BECH_ALPHABET = chain(alphabet("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), join2(""));
23059
+ var POLYMOD_GENERATORS = [996825010, 642813549, 513874426, 1027748829, 705979059];
23060
+ function bech32Polymod(pre) {
23061
+ const b4 = pre >> 25;
23062
+ let chk = (pre & 33554431) << 5;
23063
+ for (let i2 = 0;i2 < POLYMOD_GENERATORS.length; i2++) {
23064
+ if ((b4 >> i2 & 1) === 1)
23065
+ chk ^= POLYMOD_GENERATORS[i2];
23066
+ }
23067
+ return chk;
23068
+ }
23069
+ function bechChecksum(prefix, words, encodingConst = 1) {
23070
+ const len = prefix.length;
23071
+ let chk = 1;
23072
+ for (let i2 = 0;i2 < len; i2++) {
23073
+ const c5 = prefix.charCodeAt(i2);
23074
+ if (c5 < 33 || c5 > 126)
23075
+ throw new Error(`Invalid prefix (${prefix})`);
23076
+ chk = bech32Polymod(chk) ^ c5 >> 5;
23077
+ }
23078
+ chk = bech32Polymod(chk);
23079
+ for (let i2 = 0;i2 < len; i2++)
23080
+ chk = bech32Polymod(chk) ^ prefix.charCodeAt(i2) & 31;
23081
+ for (let v4 of words)
23082
+ chk = bech32Polymod(chk) ^ v4;
23083
+ for (let i2 = 0;i2 < 6; i2++)
23084
+ chk = bech32Polymod(chk);
23085
+ chk ^= encodingConst;
23086
+ return BECH_ALPHABET.encode(convertRadix2([chk % powers[30]], 30, 5, false));
23087
+ }
23088
+ function genBech32(encoding) {
23089
+ const ENCODING_CONST = encoding === "bech32" ? 1 : 734539939;
23090
+ const _words = radix2(5);
23091
+ const fromWords = _words.decode;
23092
+ const toWords = _words.encode;
23093
+ const fromWordsUnsafe = unsafeWrapper(fromWords);
23094
+ function encode4(prefix, words, limit = 90) {
23095
+ astr("bech32.encode prefix", prefix);
23096
+ if (isBytes2(words))
23097
+ words = Array.from(words);
23098
+ anumArr("bech32.encode", words);
23099
+ const plen = prefix.length;
23100
+ if (plen === 0)
23101
+ throw new TypeError(`Invalid prefix length ${plen}`);
23102
+ const actualLength = plen + 7 + words.length;
23103
+ if (limit !== false && actualLength > limit)
23104
+ throw new TypeError(`Length ${actualLength} exceeds limit ${limit}`);
23105
+ const lowered = prefix.toLowerCase();
23106
+ const sum = bechChecksum(lowered, words, ENCODING_CONST);
23107
+ return `${lowered}1${BECH_ALPHABET.encode(words)}${sum}`;
23108
+ }
23109
+ function decode4(str, limit = 90) {
23110
+ astr("bech32.decode input", str);
23111
+ const slen = str.length;
23112
+ if (slen < 8 || limit !== false && slen > limit)
23113
+ throw new TypeError(`invalid string length: ${slen} (${str}). Expected (8..${limit})`);
23114
+ const lowered = str.toLowerCase();
23115
+ if (str !== lowered && str !== str.toUpperCase())
23116
+ throw new Error(`String must be lowercase or uppercase`);
23117
+ const sepIndex = lowered.lastIndexOf("1");
23118
+ if (sepIndex === 0 || sepIndex === -1)
23119
+ throw new Error(`Letter "1" must be present between prefix and data only`);
23120
+ const prefix = lowered.slice(0, sepIndex);
23121
+ const data = lowered.slice(sepIndex + 1);
23122
+ if (data.length < 6)
23123
+ throw new Error("Data must be at least 6 characters long");
23124
+ const words = BECH_ALPHABET.decode(data).slice(0, -6);
23125
+ const sum = bechChecksum(prefix, words, ENCODING_CONST);
23126
+ if (!data.endsWith(sum))
23127
+ throw new Error(`Invalid checksum in ${str}: expected "${sum}"`);
23128
+ return { prefix, words };
23129
+ }
23130
+ const decodeUnsafe = unsafeWrapper(decode4);
23131
+ function decodeToBytes(str) {
23132
+ const { prefix, words } = decode4(str, false);
23133
+ return { prefix, words, bytes: fromWords(words) };
23134
+ }
23135
+ function encodeFromBytes(prefix, bytes) {
23136
+ return encode4(prefix, toWords(bytes));
23137
+ }
23138
+ return {
23139
+ encode: encode4,
23140
+ decode: decode4,
23141
+ encodeFromBytes,
23142
+ decodeToBytes,
23143
+ decodeUnsafe,
23144
+ fromWords,
23145
+ fromWordsUnsafe,
23146
+ toWords
23147
+ };
23148
+ }
23149
+ var bech32 = genBech32("bech32");
23150
+ var bech32m = genBech32("bech32m");
23151
+ var hasHexBuiltin = /* @__PURE__ */ (() => typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function")();
23152
+ var hexBuiltin = {
23153
+ encode(data) {
23154
+ abytes2(data);
23155
+ return data.toHex();
23156
+ },
23157
+ decode(s2) {
23158
+ astr("hex", s2);
23159
+ return Uint8Array.fromHex(s2);
23160
+ }
23161
+ };
23162
+ var hex3 = hasHexBuiltin ? hexBuiltin : chain(radix2(4), alphabet("0123456789abcdef"), join2(""), normalize((s2) => {
23163
+ if (typeof s2 !== "string" || s2.length % 2 !== 0)
23164
+ throw new TypeError(`hex.decode: expected string, got ${typeof s2} with length ${s2.length}`);
23165
+ return s2.toLowerCase();
23166
+ }));
23167
+
23168
+ // src/utils/hash.ts
23169
+ function blake3Hash(content) {
23170
+ const hash2 = blake3(new TextEncoder().encode(content));
23171
+ return base58.encode(hash2);
23172
+ }
23173
+ function canonicalizeAspect(obj) {
23174
+ return JSON.stringify(obj, (_5, value) => {
23175
+ if (value && typeof value === "object" && !Array.isArray(value)) {
23176
+ return Object.keys(value).sort().reduce((sorted, key) => {
23177
+ sorted[key] = value[key];
23178
+ return sorted;
23179
+ }, {});
23180
+ }
23181
+ return value;
23182
+ });
23183
+ }
23184
+ function blake3HashAspect(aspect) {
23185
+ return blake3Hash(canonicalizeAspect(aspect));
23186
+ }
23187
+
23188
+ // src/utils/logger.ts
23189
+ var logger = consola.create({
23190
+ formatOptions: {
23191
+ date: false
23192
+ }
23193
+ });
23194
+ var log = {
23195
+ info: logger.info.bind(logger),
23196
+ success: logger.success.bind(logger),
23197
+ warn: logger.warn.bind(logger),
23198
+ error: logger.error.bind(logger),
23199
+ box: logger.box.bind(logger),
23200
+ start: logger.start.bind(logger)
23201
+ };
23202
+
23203
+ // src/lib/installer.ts
23204
+ var ASPECT_FILENAME = "aspect.json";
23205
+ var LEGACY_FILENAME = "aspect.yaml";
23206
+ async function installAspect(spec, options) {
23207
+ switch (spec.type) {
23208
+ case "registry":
23209
+ return installFromRegistry(spec.name, spec.version, options);
23210
+ case "local":
23211
+ return installFromLocal(spec.path, options);
23212
+ case "github":
23213
+ return installFromGitHub(spec.owner, spec.repo, spec.ref, options);
23214
+ case "hash":
23215
+ return installFromHash(spec.hash, options);
23216
+ }
23217
+ }
23218
+ async function installFromRegistry(name, version2, options) {
23219
+ try {
23220
+ return await installFromRegistryApi(name, version2, options);
23221
+ } catch {
23222
+ return installFromRegistryLegacy(name, version2, options);
23223
+ }
23224
+ }
23225
+ async function installFromRegistryApi(name, version2, options) {
23226
+ const targetVersion = version2 ?? "latest";
23227
+ const scope = options?.scope ?? "global";
23228
+ const projectRoot = options?.projectRoot;
23229
+ if (!options?.force) {
23230
+ const existing = await getInstalledAspect(name, scope, projectRoot);
23231
+ if (existing && (version2 ? existing.version === version2 : true)) {
23232
+ const aspect2 = await loadAspectFromPath(getAspectPath(name, scope, projectRoot));
23233
+ if (aspect2) {
23234
+ return { success: true, aspect: aspect2, source: "registry", alreadyInstalled: true };
23235
+ }
23236
+ }
23237
+ }
23238
+ log.start(`Fetching ${name}@${targetVersion}...`);
23239
+ let versionData;
23240
+ try {
23241
+ versionData = await fetchAspectVersion(name, targetVersion);
23242
+ } catch (err) {
23243
+ const message = err.message;
23244
+ if (message.includes("not_found") || message.includes("404") || message.includes("not found")) {
23245
+ return { success: false, error: `Aspect "${name}@${targetVersion}" not found in registry` };
23246
+ }
23247
+ throw err;
23248
+ }
23249
+ const aspect = versionData.content;
23250
+ if (aspect.name !== name) {
23251
+ return {
23252
+ success: false,
23253
+ error: `Aspect name mismatch: expected "${name}", got "${aspect.name}"`
23254
+ };
23255
+ }
23256
+ await ensureAspectsDir(scope, projectRoot);
23257
+ const aspectDir = getAspectPath(name, scope, projectRoot);
23258
+ await mkdir2(aspectDir, { recursive: true });
23259
+ const content = JSON.stringify(aspect, null, 2);
23260
+ await writeFile2(join3(aspectDir, ASPECT_FILENAME), content);
23261
+ const hash2 = versionData.blake3 || blake3Hash(content);
23262
+ await addInstalledAspect(name, {
23263
+ version: aspect.version,
23264
+ source: "registry",
23265
+ installedAt: new Date().toISOString(),
23266
+ blake3: hash2
23267
+ }, scope, projectRoot);
23268
+ return { success: true, aspect, source: "registry" };
23269
+ }
23270
+ async function installFromRegistryLegacy(name, version2, options) {
23271
+ const scope = options?.scope ?? "global";
23272
+ const projectRoot = options?.projectRoot;
23273
+ let registryAspect;
23274
+ try {
23275
+ registryAspect = await getRegistryAspect(name);
23276
+ } catch (err) {
23277
+ return {
23278
+ success: false,
23279
+ error: `Unable to reach registry: ${err.message}. Make sure you have network connectivity or try installing from a local path.`
23280
+ };
23281
+ }
23282
+ if (!registryAspect) {
23283
+ return { success: false, error: `Aspect "${name}" not found in registry` };
23284
+ }
23285
+ const targetVersion = version2 ?? registryAspect.latest;
23286
+ const versionInfo = registryAspect.versions[targetVersion];
23287
+ if (!versionInfo) {
23288
+ const available = Object.keys(registryAspect.versions).join(", ");
23289
+ return {
23290
+ success: false,
23291
+ error: `Version "${targetVersion}" not found. Available: ${available}`
23292
+ };
23293
+ }
23294
+ if (!options?.force) {
23295
+ const existing = await getInstalledAspect(name, scope, projectRoot);
23296
+ if (existing && existing.version === targetVersion) {
23297
+ const aspect2 = await loadAspectFromPath(getAspectPath(name, scope, projectRoot));
23298
+ if (aspect2) {
23299
+ return { success: true, aspect: aspect2, source: "registry", alreadyInstalled: true };
23300
+ }
23301
+ }
23302
+ }
23303
+ if (!versionInfo.url) {
23304
+ return { success: false, error: `No download URL for ${name}@${targetVersion}` };
23305
+ }
21564
23306
  log.start(`Fetching ${name}@${targetVersion}...`);
21565
- let yamlContent;
23307
+ let content;
21566
23308
  try {
21567
- yamlContent = await fetchAspectYaml(versionInfo.url);
23309
+ content = await ofetch(versionInfo.url, { responseType: "text" });
21568
23310
  } catch (err) {
21569
23311
  return { success: false, error: `Failed to fetch aspect: ${err.message}` };
21570
23312
  }
21571
- const parseResult = parseAspectJson(yamlContent);
23313
+ const parseResult = parseAspectJson(content);
21572
23314
  if (!parseResult.success) {
21573
- return { success: false, error: `Invalid aspect.yaml: ${parseResult.errors.join(", ")}` };
23315
+ return { success: false, error: `Invalid aspect data: ${parseResult.errors.join(", ")}` };
21574
23316
  }
21575
23317
  if (parseResult.warnings.length > 0) {
21576
23318
  parseResult.warnings.forEach((w4) => log.warn(w4));
@@ -21582,82 +23324,98 @@ async function installFromRegistry(name, version2) {
21582
23324
  error: `Aspect name mismatch: expected "${name}", got "${aspect.name}"`
21583
23325
  };
21584
23326
  }
21585
- await ensureAspectsDir();
21586
- const aspectDir = getAspectPath(name);
23327
+ await ensureAspectsDir(scope, projectRoot);
23328
+ const aspectDir = getAspectPath(name, scope, projectRoot);
21587
23329
  await mkdir2(aspectDir, { recursive: true });
21588
- await writeFile2(join2(aspectDir, "aspect.yaml"), yamlContent);
21589
- const hash2 = sha256(yamlContent);
23330
+ await writeFile2(join3(aspectDir, ASPECT_FILENAME), content);
23331
+ const hash2 = blake3Hash(content);
21590
23332
  await addInstalledAspect(name, {
21591
23333
  version: aspect.version,
21592
23334
  source: "registry",
21593
23335
  installedAt: new Date().toISOString(),
21594
- sha256: hash2
21595
- });
23336
+ blake3: hash2
23337
+ }, scope, projectRoot);
21596
23338
  return { success: true, aspect, source: "registry" };
21597
23339
  }
21598
23340
  var DEFAULT_GITHUB_REF = "main";
21599
- async function installFromGitHub(owner, repo, ref) {
23341
+ async function installFromGitHub(owner, repo, ref, options) {
21600
23342
  const targetRef = ref ?? DEFAULT_GITHUB_REF;
21601
- const url2 = `https://raw.githubusercontent.com/${owner}/${repo}/${targetRef}/aspect.yaml`;
21602
- log.start(`Fetching from github:${owner}/${repo}@${targetRef}...`);
21603
- let yamlContent;
21604
- try {
21605
- yamlContent = await ofetch(url2, { responseType: "text" });
21606
- } catch (err) {
21607
- const message = err.message;
21608
- if (message.includes("404")) {
21609
- return {
21610
- success: false,
21611
- error: `No aspect.yaml found at github:${owner}/${repo}@${targetRef}. Make sure the repo exists and has an aspect.yaml in the root.`
21612
- };
23343
+ const scope = options?.scope ?? "global";
23344
+ const projectRoot = options?.projectRoot;
23345
+ let content = null;
23346
+ for (const filename of [ASPECT_FILENAME, LEGACY_FILENAME]) {
23347
+ const url2 = `https://raw.githubusercontent.com/${owner}/${repo}/${targetRef}/${filename}`;
23348
+ log.start(`Fetching from github:${owner}/${repo}@${targetRef}...`);
23349
+ try {
23350
+ content = await ofetch(url2, { responseType: "text" });
23351
+ break;
23352
+ } catch (err) {
23353
+ const message = err.message;
23354
+ if (!message.includes("404")) {
23355
+ return { success: false, error: `Failed to fetch from GitHub: ${message}` };
23356
+ }
21613
23357
  }
21614
- return { success: false, error: `Failed to fetch from GitHub: ${message}` };
21615
23358
  }
21616
- const parseResult = parseAspectJson(yamlContent);
23359
+ if (!content) {
23360
+ return {
23361
+ success: false,
23362
+ error: `No aspect.json found at github:${owner}/${repo}@${targetRef}. Make sure the repo exists and has an aspect.json in the root.`
23363
+ };
23364
+ }
23365
+ const parseResult = parseAspectJson(content);
21617
23366
  if (!parseResult.success) {
21618
- return { success: false, error: `Invalid aspect.yaml: ${parseResult.errors.join(", ")}` };
23367
+ return { success: false, error: `Invalid aspect data: ${parseResult.errors.join(", ")}` };
21619
23368
  }
21620
23369
  if (parseResult.warnings.length > 0) {
21621
23370
  parseResult.warnings.forEach((w4) => log.warn(w4));
21622
23371
  }
21623
23372
  const aspect = parseResult.aspect;
21624
- const existing = await getInstalledAspect(aspect.name);
21625
- if (existing && existing.source === "github" && existing.githubRef === targetRef) {
21626
- const existingAspect = await loadAspectFromPath(getAspectPath(aspect.name));
21627
- if (existingAspect && existing.sha256 === sha256(yamlContent)) {
21628
- return { success: true, aspect: existingAspect, source: "github", alreadyInstalled: true };
23373
+ if (!options?.force) {
23374
+ const existing = await getInstalledAspect(aspect.name, scope, projectRoot);
23375
+ if (existing && existing.source === "github" && existing.githubRef === targetRef) {
23376
+ const existingAspect = await loadAspectFromPath(getAspectPath(aspect.name, scope, projectRoot));
23377
+ if (existingAspect && existing.blake3 === blake3Hash(content)) {
23378
+ return { success: true, aspect: existingAspect, source: "github", alreadyInstalled: true };
23379
+ }
21629
23380
  }
21630
23381
  }
21631
- await ensureAspectsDir();
21632
- const aspectDir = getAspectPath(aspect.name);
23382
+ await ensureAspectsDir(scope, projectRoot);
23383
+ const aspectDir = getAspectPath(aspect.name, scope, projectRoot);
21633
23384
  await mkdir2(aspectDir, { recursive: true });
21634
- await writeFile2(join2(aspectDir, "aspect.yaml"), yamlContent);
21635
- const hash2 = sha256(yamlContent);
23385
+ await writeFile2(join3(aspectDir, ASPECT_FILENAME), content);
23386
+ const hash2 = blake3Hash(content);
21636
23387
  await addInstalledAspect(aspect.name, {
21637
23388
  version: aspect.version,
21638
23389
  source: "github",
21639
23390
  installedAt: new Date().toISOString(),
21640
- sha256: hash2,
23391
+ blake3: hash2,
21641
23392
  githubRef: targetRef
21642
- });
23393
+ }, scope, projectRoot);
21643
23394
  return { success: true, aspect, source: "github" };
21644
23395
  }
21645
- async function installFromLocal(path) {
21646
- let yamlPath;
23396
+ async function installFromLocal(path, options) {
23397
+ let filePath;
21647
23398
  let aspectDir;
21648
23399
  try {
21649
- const stats = await stat(path);
23400
+ const stats = await stat2(path);
21650
23401
  if (stats.isDirectory()) {
21651
23402
  aspectDir = path;
21652
- yamlPath = join2(path, "aspect.yaml");
23403
+ const jsonPath = join3(path, ASPECT_FILENAME);
23404
+ const yamlPath = join3(path, LEGACY_FILENAME);
23405
+ try {
23406
+ await access(jsonPath);
23407
+ filePath = jsonPath;
23408
+ } catch {
23409
+ filePath = yamlPath;
23410
+ }
21653
23411
  } else {
21654
- yamlPath = path;
23412
+ filePath = path;
21655
23413
  aspectDir = dirname(path);
21656
23414
  }
21657
23415
  } catch {
21658
23416
  return { success: false, error: `Path not found: ${path}` };
21659
23417
  }
21660
- const parseResult = await parseAspectFile(yamlPath);
23418
+ const parseResult = await parseAspectFile(filePath);
21661
23419
  if (!parseResult.success) {
21662
23420
  return { success: false, error: parseResult.errors.join(", ") };
21663
23421
  }
@@ -21665,29 +23423,80 @@ async function installFromLocal(path) {
21665
23423
  parseResult.warnings.forEach((w4) => log.warn(w4));
21666
23424
  }
21667
23425
  const aspect = parseResult.aspect;
21668
- const yamlContent = await readFile3(yamlPath, "utf-8");
21669
- const hash2 = sha256(yamlContent);
21670
- const existing = await getInstalledAspect(aspect.name);
21671
- if (existing && existing.path === aspectDir && existing.sha256 === hash2) {
21672
- return { success: true, aspect, source: "local", alreadyInstalled: true };
23426
+ const content = await readFile3(filePath, "utf-8");
23427
+ const hash2 = blake3Hash(content);
23428
+ const scope = options?.scope ?? "global";
23429
+ const projectRoot = options?.projectRoot;
23430
+ if (!options?.force) {
23431
+ const existing = await getInstalledAspect(aspect.name, scope, projectRoot);
23432
+ if (existing && existing.path === aspectDir && existing.blake3 === hash2) {
23433
+ return { success: true, aspect, source: "local", alreadyInstalled: true };
23434
+ }
21673
23435
  }
21674
23436
  await addInstalledAspect(aspect.name, {
21675
23437
  version: aspect.version,
21676
23438
  source: "local",
21677
23439
  installedAt: new Date().toISOString(),
21678
- sha256: hash2,
23440
+ blake3: hash2,
21679
23441
  path: aspectDir
21680
- });
23442
+ }, scope, projectRoot);
21681
23443
  return { success: true, aspect, source: "local" };
21682
23444
  }
23445
+ async function installFromHash(hash2, options) {
23446
+ const scope = options?.scope ?? "global";
23447
+ const projectRoot = options?.projectRoot;
23448
+ log.start(`Fetching aspect by hash ${hash2.slice(0, 12)}...`);
23449
+ let versionData;
23450
+ try {
23451
+ versionData = await fetchAspectByHash(hash2);
23452
+ } catch (err) {
23453
+ const message = err.message;
23454
+ if (message.includes("not_found") || message.includes("404") || message.includes("not found")) {
23455
+ return { success: false, error: `No aspect found for hash "${hash2}"` };
23456
+ }
23457
+ return { success: false, error: `Failed to fetch aspect by hash: ${message}` };
23458
+ }
23459
+ const aspect = versionData.content;
23460
+ if (!options?.force) {
23461
+ const existing = await getInstalledAspect(aspect.name, scope, projectRoot);
23462
+ if (existing && existing.blake3 === hash2) {
23463
+ const existingAspect = await loadAspectFromPath(getAspectPath(aspect.name, scope, projectRoot));
23464
+ if (existingAspect) {
23465
+ return { success: true, aspect: existingAspect, source: "registry", alreadyInstalled: true };
23466
+ }
23467
+ }
23468
+ }
23469
+ await ensureAspectsDir(scope, projectRoot);
23470
+ const aspectDir = getAspectPath(aspect.name, scope, projectRoot);
23471
+ await mkdir2(aspectDir, { recursive: true });
23472
+ const content = JSON.stringify(aspect, null, 2);
23473
+ await writeFile2(join3(aspectDir, ASPECT_FILENAME), content);
23474
+ await addInstalledAspect(aspect.name, {
23475
+ version: aspect.version,
23476
+ source: "registry",
23477
+ installedAt: new Date().toISOString(),
23478
+ blake3: versionData.blake3 || blake3Hash(content)
23479
+ }, scope, projectRoot);
23480
+ return { success: true, aspect, source: "registry" };
23481
+ }
21683
23482
  async function loadAspectFromPath(aspectDir) {
21684
- const result = await parseAspectFile(join2(aspectDir, "aspect.yaml"));
21685
- return result.success ? result.aspect : null;
23483
+ const jsonResult = await parseAspectFile(join3(aspectDir, ASPECT_FILENAME));
23484
+ if (jsonResult.success)
23485
+ return jsonResult.aspect;
23486
+ const yamlResult = await parseAspectFile(join3(aspectDir, LEGACY_FILENAME));
23487
+ return yamlResult.success ? yamlResult.aspect : null;
21686
23488
  }
21687
23489
 
21688
23490
  // src/lib/resolver.ts
21689
23491
  import { resolve, isAbsolute } from "node:path";
21690
23492
  function parseInstallSpec(spec) {
23493
+ if (spec.startsWith("hash:")) {
23494
+ const hash2 = spec.slice(5);
23495
+ if (hash2.length < 16) {
23496
+ throw new Error(`Invalid hash spec: ${spec}. Hash must be at least 16 characters.`);
23497
+ }
23498
+ return { type: "hash", hash: hash2 };
23499
+ }
21691
23500
  if (spec.startsWith("github:")) {
21692
23501
  const rest = spec.slice(7);
21693
23502
  const parts = rest.split("@");
@@ -21731,7 +23540,7 @@ function parseInstallSpec(spec) {
21731
23540
  // src/commands/set.ts
21732
23541
  async function loadSet(name) {
21733
23542
  try {
21734
- const setPath = join3(getSetsDir(), name, "set.json");
23543
+ const setPath = join4(getSetsDir(), name, "set.json");
21735
23544
  const content = await readFile4(setPath, "utf-8");
21736
23545
  return JSON.parse(content);
21737
23546
  } catch {
@@ -21740,10 +23549,10 @@ async function loadSet(name) {
21740
23549
  }
21741
23550
  async function saveSet(set2) {
21742
23551
  await ensureSetsDir();
21743
- const setDir = join3(getSetsDir(), set2.name);
23552
+ const setDir = join4(getSetsDir(), set2.name);
21744
23553
  await mkdir3(setDir, { recursive: true });
21745
23554
  set2.updatedAt = new Date().toISOString();
21746
- await writeFile3(join3(setDir, "set.json"), JSON.stringify(set2, null, 2) + `
23555
+ await writeFile3(join4(setDir, "set.json"), JSON.stringify(set2, null, 2) + `
21747
23556
  `);
21748
23557
  }
21749
23558
  async function listAllSets() {
@@ -22197,14 +24006,14 @@ var create_default = defineCommand({
22197
24006
  let inRegistry = false;
22198
24007
  let repoRoot = cwd;
22199
24008
  try {
22200
- await stat2(join4(cwd, INDEX_PATH));
24009
+ await stat3(join5(cwd, INDEX_PATH));
22201
24010
  inRegistry = true;
22202
24011
  } catch {
22203
24012
  try {
22204
24013
  const gitRoot = execSync("git rev-parse --show-toplevel", {
22205
24014
  encoding: "utf-8"
22206
24015
  }).trim();
22207
- await stat2(join4(gitRoot, INDEX_PATH));
24016
+ await stat3(join5(gitRoot, INDEX_PATH));
22208
24017
  inRegistry = true;
22209
24018
  repoRoot = gitRoot;
22210
24019
  } catch {}
@@ -22212,8 +24021,25 @@ var create_default = defineCommand({
22212
24021
  if (inRegistry) {
22213
24022
  M2.info(`Detected aspects registry at ${repoRoot}`);
22214
24023
  }
22215
- const answers = await Ce({
22216
- name: () => he2({
24024
+ const aspectExistsAt = async (name) => {
24025
+ let checkPath;
24026
+ if (inRegistry) {
24027
+ checkPath = join5(repoRoot, REGISTRY_DIR, name, "aspect.json");
24028
+ } else if (args.path) {
24029
+ checkPath = join5(args.path, "aspect.json");
24030
+ } else {
24031
+ checkPath = join5(cwd, "aspect.json");
24032
+ }
24033
+ try {
24034
+ await stat3(checkPath);
24035
+ return checkPath;
24036
+ } catch {
24037
+ return null;
24038
+ }
24039
+ };
24040
+ let aspectName;
24041
+ while (!aspectName) {
24042
+ const nameInput = await he2({
22217
24043
  message: "Aspect name (slug)",
22218
24044
  placeholder: "my-wizard",
22219
24045
  validate: (value) => {
@@ -22223,7 +24049,34 @@ var create_default = defineCommand({
22223
24049
  return "Name must be lowercase letters, numbers, and hyphens only";
22224
24050
  }
22225
24051
  }
22226
- }),
24052
+ });
24053
+ if (pD2(nameInput)) {
24054
+ xe("Cancelled");
24055
+ process.exit(0);
24056
+ }
24057
+ const existingPath = await aspectExistsAt(nameInput);
24058
+ if (existingPath) {
24059
+ M2.warn(`An aspect already exists at ${existingPath}`);
24060
+ const action = await ve2({
24061
+ message: "What would you like to do?",
24062
+ options: [
24063
+ { value: "rename", label: "Choose a different name" },
24064
+ { value: "overwrite", label: "Overwrite the existing aspect" },
24065
+ { value: "cancel", label: "Cancel" }
24066
+ ]
24067
+ });
24068
+ if (pD2(action) || action === "cancel") {
24069
+ xe("Cancelled");
24070
+ process.exit(0);
24071
+ }
24072
+ if (action === "overwrite") {
24073
+ aspectName = nameInput;
24074
+ }
24075
+ } else {
24076
+ aspectName = nameInput;
24077
+ }
24078
+ }
24079
+ const answers = await Ce({
22227
24080
  displayName: () => he2({
22228
24081
  message: "Display name",
22229
24082
  placeholder: "My Wizard",
@@ -22323,9 +24176,20 @@ Keep it light! A few well-crafted rules beat many vague ones.
22323
24176
  const action = await ve2({
22324
24177
  message: "What would you like to add?",
22325
24178
  options: [
22326
- { value: "directive", label: "Add a directive (strict rule)", hint: "MUST-follow, emphasized across models" },
22327
- { value: "instruction", label: "Add an instruction (general guidance)", hint: "Softer preference" },
22328
- { value: "done", label: hasAny ? "Done finish creating aspect" : "Skip — finish without adding any" }
24179
+ {
24180
+ value: "directive",
24181
+ label: "Add a directive (strict rule)",
24182
+ hint: "MUST-follow, emphasized across models"
24183
+ },
24184
+ {
24185
+ value: "instruction",
24186
+ label: "Add an instruction (general guidance)",
24187
+ hint: "Softer preference"
24188
+ },
24189
+ {
24190
+ value: "done",
24191
+ label: hasAny ? "Done — finish creating aspect" : "Skip — finish without adding any"
24192
+ }
22329
24193
  ]
22330
24194
  });
22331
24195
  if (pD2(action) || action === "done") {
@@ -22353,8 +24217,16 @@ Keep it light! A few well-crafted rules beat many vague ones.
22353
24217
  const priority = await ve2({
22354
24218
  message: "Priority level:",
22355
24219
  options: [
22356
- { value: "high", label: "High", hint: "Critical, always emphasized" },
22357
- { value: "medium", label: "Medium", hint: "Important but flexible" },
24220
+ {
24221
+ value: "high",
24222
+ label: "High",
24223
+ hint: "Critical, always emphasized"
24224
+ },
24225
+ {
24226
+ value: "medium",
24227
+ label: "Medium",
24228
+ hint: "Important but flexible"
24229
+ },
22358
24230
  { value: "low", label: "Low", hint: "Nice-to-have preference" }
22359
24231
  ],
22360
24232
  initialValue: "high"
@@ -22394,7 +24266,7 @@ Keep it light! A few well-crafted rules beat many vague ones.
22394
24266
  }
22395
24267
  const aspect = {
22396
24268
  schemaVersion: 1,
22397
- name: answers.name,
24269
+ name: aspectName,
22398
24270
  publisher: answers.author || "community",
22399
24271
  version: "1.0.0",
22400
24272
  displayName: answers.displayName,
@@ -22425,20 +24297,15 @@ Keep it light! A few well-crafted rules beat many vague ones.
22425
24297
  let outputDir;
22426
24298
  let outputPath;
22427
24299
  if (inRegistry) {
22428
- outputDir = join4(repoRoot, REGISTRY_DIR, answers.name);
22429
- outputPath = join4(outputDir, "aspect.json");
24300
+ outputDir = join5(repoRoot, REGISTRY_DIR, aspectName);
24301
+ outputPath = join5(outputDir, "aspect.json");
22430
24302
  } else if (args.path) {
22431
24303
  outputDir = args.path;
22432
- outputPath = join4(outputDir, "aspect.json");
24304
+ outputPath = join5(outputDir, "aspect.json");
22433
24305
  } else {
22434
24306
  outputDir = cwd;
22435
- outputPath = join4(cwd, "aspect.json");
24307
+ outputPath = join5(cwd, "aspect.json");
22436
24308
  }
22437
- try {
22438
- await stat2(outputPath);
22439
- M2.error(`aspect.json already exists at ${outputPath}`);
22440
- process.exit(1);
22441
- } catch {}
22442
24309
  await mkdir4(outputDir, { recursive: true });
22443
24310
  const jsonContent = JSON.stringify(aspect, null, 2);
22444
24311
  await writeFile4(outputPath, jsonContent);
@@ -22450,7 +24317,7 @@ Keep it light! A few well-crafted rules beat many vague ones.
22450
24317
  });
22451
24318
  if (updateIndex) {
22452
24319
  try {
22453
- await addToRegistryIndex(repoRoot, answers.name, answers.displayName, answers.tagline, answers.category, answers.author || "community");
24320
+ await addToRegistryIndex(repoRoot, aspectName, answers.displayName, answers.tagline, answers.category, answers.author || "community");
22454
24321
  M2.success("Updated registry/index.json");
22455
24322
  } catch (err) {
22456
24323
  M2.error(`Failed to update index.json: ${err}`);
@@ -22463,11 +24330,11 @@ Keep it light! A few well-crafted rules beat many vague ones.
22463
24330
  if (gitCommit) {
22464
24331
  try {
22465
24332
  execSync(`git add .`, { cwd: repoRoot, stdio: "pipe" });
22466
- execSync(`git commit -m "Add ${answers.name} aspect"`, {
24333
+ execSync(`git commit -m "Add ${aspectName} aspect"`, {
22467
24334
  cwd: repoRoot,
22468
24335
  stdio: "pipe"
22469
24336
  });
22470
- M2.success(`Committed: "Add ${answers.name} aspect"`);
24337
+ M2.success(`Committed: "Add ${aspectName} aspect"`);
22471
24338
  const gitPush = await ye2({
22472
24339
  message: "Push to origin?",
22473
24340
  initialValue: true
@@ -22491,7 +24358,7 @@ Next: Open a PR at https://github.com/${GITHUB_REPO}/compare`);
22491
24358
  To submit to the registry:`);
22492
24359
  M2.info("1. Fork https://github.com/" + GITHUB_REPO);
22493
24360
  M2.info("2. Clone your fork and run this command inside it");
22494
- M2.info("3. Or visit https://getaspects.com/create");
24361
+ M2.info("3. Or visit https://aspects.sh/create");
22495
24362
  }
22496
24363
  const sets = await listAllSets();
22497
24364
  if (sets.length > 0) {
@@ -22508,8 +24375,8 @@ To submit to the registry:`);
22508
24375
  });
22509
24376
  if (!pD2(addToSet) && addToSet !== "__none__") {
22510
24377
  const set2 = await loadSet(addToSet);
22511
- if (set2 && !set2.aspects.includes(answers.name)) {
22512
- set2.aspects.push(answers.name);
24378
+ if (set2 && !set2.aspects.includes(aspectName)) {
24379
+ set2.aspects.push(aspectName);
22513
24380
  await saveSet(set2);
22514
24381
  M2.success(`Added to set: ${set2.displayName}`);
22515
24382
  }
@@ -22519,7 +24386,7 @@ To submit to the registry:`);
22519
24386
  }
22520
24387
  });
22521
24388
  async function addToRegistryIndex(repoRoot, name, displayName, tagline, category, publisher) {
22522
- const indexPath = join4(repoRoot, INDEX_PATH);
24389
+ const indexPath = join5(repoRoot, INDEX_PATH);
22523
24390
  const indexContent = await readFile5(indexPath, "utf-8");
22524
24391
  const index = JSON.parse(indexContent);
22525
24392
  const now = new Date().toISOString();
@@ -22604,12 +24471,28 @@ var add_default = defineCommand({
22604
24471
  force: {
22605
24472
  type: "boolean",
22606
24473
  description: "Overwrite existing installation"
24474
+ },
24475
+ global: {
24476
+ type: "boolean",
24477
+ alias: "g",
24478
+ description: "Install to global scope (~/.aspects) instead of project"
22607
24479
  }
22608
24480
  },
22609
24481
  async run({ args }) {
22610
24482
  const specs = Array.isArray(args.specs) ? args.specs : [args.specs];
22611
- const results = [];
22612
- for (const specStr of specs) {
24483
+ let scope;
24484
+ let projectRoot;
24485
+ if (args.global) {
24486
+ scope = "global";
24487
+ } else {
24488
+ projectRoot = await findProjectRoot() || undefined;
24489
+ scope = projectRoot ? "project" : "global";
24490
+ }
24491
+ const scopeLabel = scope === "global" ? "~/.aspects" : "./.aspects";
24492
+ console.log();
24493
+ console.log(c3.muted(`Installing to ${scopeLabel}`));
24494
+ const results = [];
24495
+ for (const specStr of specs) {
22613
24496
  let spec;
22614
24497
  try {
22615
24498
  spec = parseInstallSpec(specStr);
@@ -22617,7 +24500,7 @@ var add_default = defineCommand({
22617
24500
  results.push({ spec: specStr, success: false, error: err.message });
22618
24501
  continue;
22619
24502
  }
22620
- const result = await installAspect(spec);
24503
+ const result = await installAspect(spec, { force: !!args.force, scope, projectRoot });
22621
24504
  if (!result.success) {
22622
24505
  results.push({ spec: specStr, success: false, error: result.error });
22623
24506
  continue;
@@ -22666,15 +24549,19 @@ var add_default = defineCommand({
22666
24549
  });
22667
24550
 
22668
24551
  // src/lib/aspect-loader.ts
22669
- import { join as join5 } from "node:path";
22670
- async function loadInstalledAspect(name) {
22671
- const installed = await getInstalledAspect(name);
24552
+ import { join as join6 } from "node:path";
24553
+ var ASPECT_FILENAME2 = "aspect.json";
24554
+ var LEGACY_FILENAME2 = "aspect.yaml";
24555
+ async function loadInstalledAspect(name, scope = "global", projectRoot) {
24556
+ const installed = await getInstalledAspect(name, scope, projectRoot);
22672
24557
  if (!installed)
22673
24558
  return null;
22674
- const aspectDir = installed.path ?? getAspectPath(name);
22675
- const yamlPath = join5(aspectDir, "aspect.yaml");
22676
- const result = await parseAspectFile(yamlPath);
22677
- return result.success ? result.aspect : null;
24559
+ const aspectDir = installed.path ?? getAspectPath(name, scope, projectRoot);
24560
+ const jsonResult = await parseAspectFile(join6(aspectDir, ASPECT_FILENAME2));
24561
+ if (jsonResult.success)
24562
+ return jsonResult.aspect;
24563
+ const yamlResult = await parseAspectFile(join6(aspectDir, LEGACY_FILENAME2));
24564
+ return yamlResult.success ? yamlResult.aspect : null;
22678
24565
  }
22679
24566
 
22680
24567
  // src/commands/list.ts
@@ -22683,9 +24570,28 @@ var list_default = defineCommand({
22683
24570
  name: "list",
22684
24571
  description: "List installed aspects"
22685
24572
  },
22686
- args: {},
22687
- async run() {
22688
- const installed = await listInstalledAspects();
24573
+ args: {
24574
+ global: {
24575
+ type: "boolean",
24576
+ alias: "g",
24577
+ description: "List only global aspects (~/.aspects)"
24578
+ },
24579
+ project: {
24580
+ type: "boolean",
24581
+ alias: "p",
24582
+ description: "List only project aspects (./.aspects)"
24583
+ }
24584
+ },
24585
+ async run({ args }) {
24586
+ const projectRoot = await findProjectRoot() || undefined;
24587
+ let installed;
24588
+ if (args.global) {
24589
+ installed = await listInstalledAspects("global");
24590
+ } else if (args.project) {
24591
+ installed = await listInstalledAspects("project", projectRoot);
24592
+ } else {
24593
+ installed = await listAllInstalledAspects(projectRoot);
24594
+ }
22689
24595
  if (installed.length === 0) {
22690
24596
  console.log();
22691
24597
  console.log(c3.muted(" No aspects installed."));
@@ -22696,13 +24602,14 @@ var list_default = defineCommand({
22696
24602
  console.log();
22697
24603
  console.log(c3.bold(`${icons2.package} Installed aspects`));
22698
24604
  console.log();
22699
- for (const installed2 of await listInstalledAspects()) {
22700
- const aspect = await loadInstalledAspect(installed2.name);
22701
- const sourceLabel = installed2.source === "local" ? c3.dim(" (local)") : installed2.source === "github" ? c3.dim(" (github)") : "";
22702
- const name = c3.aspect(installed2.name);
22703
- const version2 = c3.version(`@${installed2.version}`);
24605
+ for (const item of installed) {
24606
+ const aspect = await loadInstalledAspect(item.name, item.scope, projectRoot);
24607
+ const scopeLabel = item.scope === "project" ? c3.dim(" [project]") : c3.dim(" [global]");
24608
+ const sourceLabel = item.source === "local" ? c3.dim(" (local)") : item.source === "github" ? c3.dim(" (github)") : "";
24609
+ const name = c3.aspect(item.name);
24610
+ const version2 = c3.version(`@${item.version}`);
22704
24611
  const tagline = aspect?.tagline ? c3.muted(` — ${aspect.tagline}`) : "";
22705
- console.log(` ${name}${version2}${sourceLabel}${tagline}`);
24612
+ console.log(` ${name}${version2}${scopeLabel}${sourceLabel}${tagline}`);
22706
24613
  }
22707
24614
  console.log();
22708
24615
  }
@@ -22719,9 +24626,57 @@ var search_default = defineCommand({
22719
24626
  type: "positional",
22720
24627
  description: "Search query (optional, lists all if omitted)",
22721
24628
  required: false
24629
+ },
24630
+ category: {
24631
+ type: "string",
24632
+ description: "Filter by category (assistant, roleplay, creative, etc.)"
24633
+ },
24634
+ trust: {
24635
+ type: "string",
24636
+ description: "Filter by trust level (verified, community)"
24637
+ },
24638
+ limit: {
24639
+ type: "string",
24640
+ description: "Max results (default 20, max 100)"
24641
+ },
24642
+ offset: {
24643
+ type: "string",
24644
+ description: "Pagination offset"
22722
24645
  }
22723
24646
  },
22724
24647
  async run({ args }) {
24648
+ const query = args.query;
24649
+ const category = args.category;
24650
+ const trust = args.trust;
24651
+ const limit = args.limit ? parseInt(args.limit, 10) : undefined;
24652
+ const offset = args.offset ? parseInt(args.offset, 10) : undefined;
24653
+ try {
24654
+ const result = await searchRegistry({ q: query, category, trust, limit, offset });
24655
+ if (result.results.length === 0) {
24656
+ console.log();
24657
+ if (query) {
24658
+ console.log(c3.muted(` No aspects found matching "${query}"`));
24659
+ } else {
24660
+ console.log(c3.muted(" No aspects found"));
24661
+ }
24662
+ console.log();
24663
+ return;
24664
+ }
24665
+ console.log();
24666
+ console.log(c3.bold(`${icons2.search} ${query ? `Aspects matching "${query}"` : "Available aspects"}`));
24667
+ if (result.total > result.results.length) {
24668
+ console.log(c3.muted(` Showing ${result.results.length} of ${result.total} results`));
24669
+ }
24670
+ console.log();
24671
+ for (const item of result.results) {
24672
+ const verified = item.trust === "verified" ? ` ${icons2.success}` : "";
24673
+ const downloads = formatDownloads(item.downloads);
24674
+ console.log(` ${c3.aspect(item.name)}${c3.version(`@${item.version}`)}${verified} ${downloads}`);
24675
+ console.log(` ${c3.muted(item.tagline)}`);
24676
+ console.log();
24677
+ }
24678
+ return;
24679
+ } catch {}
22725
24680
  let index;
22726
24681
  try {
22727
24682
  index = await fetchRegistryIndex();
@@ -22729,13 +24684,19 @@ var search_default = defineCommand({
22729
24684
  log.error(err.message);
22730
24685
  process.exit(1);
22731
24686
  }
22732
- const query = args.query?.toLowerCase();
24687
+ const queryLower = query?.toLowerCase();
22733
24688
  const aspects = Object.entries(index.aspects);
22734
- const matches = query ? aspects.filter(([name, info]) => name.toLowerCase().includes(query) || info.metadata.displayName.toLowerCase().includes(query) || info.metadata.tagline.toLowerCase().includes(query)) : aspects;
24689
+ let matches = queryLower ? aspects.filter(([name, info]) => name.toLowerCase().includes(queryLower) || info.metadata.displayName.toLowerCase().includes(queryLower) || info.metadata.tagline.toLowerCase().includes(queryLower)) : aspects;
24690
+ if (category) {
24691
+ matches = matches.filter(([, info]) => info.metadata.category === category);
24692
+ }
24693
+ if (trust) {
24694
+ matches = matches.filter(([, info]) => info.metadata.trust === trust);
24695
+ }
22735
24696
  if (matches.length === 0) {
22736
24697
  console.log();
22737
24698
  if (query) {
22738
- console.log(c3.muted(` No aspects found matching "${args.query}"`));
24699
+ console.log(c3.muted(` No aspects found matching "${query}"`));
22739
24700
  } else {
22740
24701
  console.log(c3.muted(" Registry is empty"));
22741
24702
  }
@@ -22743,7 +24704,7 @@ var search_default = defineCommand({
22743
24704
  return;
22744
24705
  }
22745
24706
  console.log();
22746
- console.log(c3.bold(`${icons2.search} ${query ? `Aspects matching "${args.query}"` : "Available aspects"}`));
24707
+ console.log(c3.bold(`${icons2.search} ${query ? `Aspects matching "${query}"` : "Available aspects"}`));
22747
24708
  console.log();
22748
24709
  for (const [name, info] of matches) {
22749
24710
  const verified = info.metadata.trust === "verified" ? ` ${icons2.success}` : "";
@@ -22753,6 +24714,12 @@ var search_default = defineCommand({
22753
24714
  }
22754
24715
  }
22755
24716
  });
24717
+ function formatDownloads(count) {
24718
+ if (count >= 1000) {
24719
+ return c3.muted(`${(count / 1000).toFixed(1)}k dl`);
24720
+ }
24721
+ return c3.muted(`${count} dl`);
24722
+ }
22756
24723
 
22757
24724
  // src/commands/find.ts
22758
24725
  function matchesFilter(aspect, filters, deep = false) {
@@ -22986,7 +24953,7 @@ var find_default = defineCommand({
22986
24953
  continue;
22987
24954
  }
22988
24955
  const aspectPath = aspectInfo.path || getAspectPath(name);
22989
- const parseResult = await parseAspectFile(`${aspectPath}/aspect.yaml`);
24956
+ const parseResult = await parseAspectFile(`${aspectPath}/aspect.json`);
22990
24957
  if (!parseResult.success)
22991
24958
  continue;
22992
24959
  const aspect = parseResult.aspect;
@@ -23050,7 +25017,7 @@ var find_default = defineCommand({
23050
25017
  var info_default = defineCommand({
23051
25018
  meta: {
23052
25019
  name: "info",
23053
- description: "Show details about an installed aspect"
25020
+ description: "Show details about an aspect (installed or from registry)"
23054
25021
  },
23055
25022
  args: {
23056
25023
  name: {
@@ -23061,56 +25028,122 @@ var info_default = defineCommand({
23061
25028
  },
23062
25029
  async run({ args }) {
23063
25030
  const installed = await getInstalledAspect(args.name);
23064
- if (!installed) {
23065
- log.error(`Aspect "${args.name}" is not installed`);
23066
- process.exit(1);
23067
- }
23068
- const aspect = await loadInstalledAspect(args.name);
23069
- if (!aspect) {
23070
- log.error(`Failed to load aspect "${args.name}" — aspect.yaml may be corrupted`);
23071
- process.exit(1);
23072
- }
23073
- console.log();
23074
- console.log(`${c3.bold(aspect.displayName)} ${c3.muted("(")}${c3.aspect(aspect.name)}${c3.version(`@${aspect.version}`)}${c3.muted(")")}`);
23075
- console.log();
23076
- console.log(` ${c3.italic(aspect.tagline)}`);
23077
- console.log();
23078
- const meta3 = [];
23079
- if (aspect.publisher)
23080
- meta3.push(["Publisher", aspect.publisher]);
23081
- if (aspect.author)
23082
- meta3.push(["Author", aspect.author]);
23083
- if (aspect.license)
23084
- meta3.push(["License", aspect.license]);
23085
- meta3.push(["Source", installed.source]);
23086
- if (meta3.length > 0) {
23087
- for (const [label, value] of meta3) {
23088
- console.log(` ${c3.label(label.padEnd(10))} ${c3.value(value)}`);
25031
+ if (installed) {
25032
+ const aspect = await loadInstalledAspect(args.name);
25033
+ if (!aspect) {
25034
+ log.error(`Failed to load aspect "${args.name}" — aspect.json may be corrupted`);
25035
+ process.exit(1);
23089
25036
  }
23090
- }
23091
- if (aspect.voiceHints) {
23092
25037
  console.log();
23093
- console.log(` ${c3.bold("Voice")}`);
23094
- if (aspect.voiceHints.speed) {
23095
- console.log(` ${c3.label("Speed")} ${aspect.voiceHints.speed}`);
23096
- }
23097
- if (aspect.voiceHints.emotions?.length) {
23098
- console.log(` ${c3.label("Emotions")} ${aspect.voiceHints.emotions.join(", ")}`);
25038
+ console.log(`${c3.bold(aspect.displayName)} ${c3.muted("(")}${c3.aspect(aspect.name)}${c3.version(`@${aspect.version}`)}${c3.muted(")")}`);
25039
+ console.log();
25040
+ console.log(` ${c3.italic(aspect.tagline)}`);
25041
+ console.log();
25042
+ const meta3 = [];
25043
+ if (aspect.publisher)
25044
+ meta3.push(["Publisher", aspect.publisher]);
25045
+ if (aspect.author)
25046
+ meta3.push(["Author", aspect.author]);
25047
+ if (aspect.license)
25048
+ meta3.push(["License", aspect.license]);
25049
+ meta3.push(["Source", installed.source]);
25050
+ if (meta3.length > 0) {
25051
+ for (const [label, value] of meta3) {
25052
+ console.log(` ${c3.label(label.padEnd(10))} ${c3.value(value)}`);
25053
+ }
25054
+ }
25055
+ if (aspect.voiceHints) {
25056
+ console.log();
25057
+ console.log(` ${c3.bold("Voice")}`);
25058
+ if (aspect.voiceHints.speed) {
25059
+ console.log(` ${c3.label("Speed")} ${aspect.voiceHints.speed}`);
25060
+ }
25061
+ if (aspect.voiceHints.emotions?.length) {
25062
+ console.log(` ${c3.label("Emotions")} ${aspect.voiceHints.emotions.join(", ")}`);
25063
+ }
25064
+ if (aspect.voiceHints.styleHints) {
25065
+ console.log(` ${c3.label("Style")} ${c3.muted(aspect.voiceHints.styleHints)}`);
25066
+ }
23099
25067
  }
23100
- if (aspect.voiceHints.styleHints) {
23101
- console.log(` ${c3.label("Style")} ${c3.muted(aspect.voiceHints.styleHints)}`);
25068
+ if (aspect.modes && Object.keys(aspect.modes).length > 0) {
25069
+ console.log();
25070
+ console.log(` ${c3.bold("Modes")}`);
25071
+ for (const [modeName, mode] of Object.entries(aspect.modes)) {
25072
+ console.log(` ${c3.highlight(modeName)} ${icons2.arrow} ${c3.muted(mode.description)}`);
25073
+ }
23102
25074
  }
25075
+ console.log();
25076
+ return;
23103
25077
  }
23104
- if (aspect.modes && Object.keys(aspect.modes).length > 0) {
25078
+ try {
25079
+ const detail = await getAspectDetail(args.name);
25080
+ if (!detail) {
25081
+ log.error(`Aspect "${args.name}" not found (not installed or in registry)`);
25082
+ console.log(c3.muted(` Try "aspects search ${args.name}" to find similar aspects`));
25083
+ process.exit(1);
25084
+ }
25085
+ const latestVersion = detail.versions[detail.latest];
25086
+ const latestAspect = latestVersion?.aspect;
25087
+ console.log();
25088
+ console.log(`${c3.bold(latestAspect?.displayName ?? detail.name)} ${c3.muted("(")}${c3.aspect(detail.name)}${c3.version(`@${detail.latest}`)}${c3.muted(")")}`);
25089
+ console.log();
25090
+ if (latestAspect?.tagline) {
25091
+ console.log(` ${c3.italic(latestAspect.tagline)}`);
25092
+ console.log();
25093
+ }
25094
+ const meta3 = [];
25095
+ meta3.push(["Publisher", detail.publisher]);
25096
+ if (latestAspect?.category)
25097
+ meta3.push(["Category", latestAspect.category]);
25098
+ meta3.push(["Trust", detail.trust]);
25099
+ meta3.push(["Latest", detail.latest]);
25100
+ meta3.push(["Published", formatDate(detail.modified)]);
25101
+ for (const [label, value] of meta3) {
25102
+ console.log(` ${c3.label(label.padEnd(10))} ${c3.value(value)}`);
25103
+ }
23105
25104
  console.log();
23106
- console.log(` ${c3.bold("Modes")}`);
23107
- for (const [modeName, mode] of Object.entries(aspect.modes)) {
23108
- console.log(` ${c3.highlight(modeName)} ${icons2.arrow} ${c3.muted(mode.description)}`);
25105
+ console.log(` ${c3.bold("Stats")}`);
25106
+ console.log(` ${c3.label("Downloads")} ${formatNumber(detail.stats.downloads.total)} total / ${formatNumber(detail.stats.downloads.weekly)} weekly`);
25107
+ const versions2 = Object.keys(detail.versions);
25108
+ if (versions2.length > 0) {
25109
+ console.log();
25110
+ console.log(` ${c3.bold("Versions")}`);
25111
+ for (const ver of versions2) {
25112
+ const vInfo = detail.versions[ver];
25113
+ const deprecated = vInfo?.deprecated ? c3.warn(` (deprecated: ${vInfo.deprecated})`) : "";
25114
+ const current = ver === detail.latest ? ` ${c3.success("← latest")}` : "";
25115
+ console.log(` ${c3.version(ver)} ${c3.muted(formatDate(vInfo?.published ?? ""))}${current}${deprecated}`);
25116
+ }
23109
25117
  }
25118
+ console.log();
25119
+ console.log(c3.muted(` Install: aspects install ${detail.name}`));
25120
+ console.log();
25121
+ } catch (err) {
25122
+ log.error(`Aspect "${args.name}" is not installed`);
25123
+ console.log(c3.muted(` Try "aspects search ${args.name}" to find aspects in the registry`));
25124
+ process.exit(1);
23110
25125
  }
23111
- console.log();
23112
25126
  }
23113
25127
  });
25128
+ function formatNumber(n5) {
25129
+ if (n5 >= 1000) {
25130
+ return `${(n5 / 1000).toFixed(1)}k`;
25131
+ }
25132
+ return String(n5);
25133
+ }
25134
+ function formatDate(isoDate) {
25135
+ if (!isoDate)
25136
+ return "unknown";
25137
+ try {
25138
+ return new Date(isoDate).toLocaleDateString("en-US", {
25139
+ year: "numeric",
25140
+ month: "short",
25141
+ day: "numeric"
25142
+ });
25143
+ } catch {
25144
+ return isoDate;
25145
+ }
25146
+ }
23114
25147
 
23115
25148
  // src/commands/remove.ts
23116
25149
  import { rm } from "node:fs/promises";
@@ -23124,17 +25157,30 @@ var remove_default = defineCommand({
23124
25157
  type: "positional",
23125
25158
  description: "Aspect name to remove",
23126
25159
  required: true
25160
+ },
25161
+ global: {
25162
+ type: "boolean",
25163
+ alias: "g",
25164
+ description: "Remove from global scope (~/.aspects) instead of project"
23127
25165
  }
23128
25166
  },
23129
25167
  async run({ args }) {
23130
- const installed = await getInstalledAspect(args.name);
25168
+ let scope;
25169
+ let projectRoot;
25170
+ if (args.global) {
25171
+ scope = "global";
25172
+ } else {
25173
+ projectRoot = await findProjectRoot() || undefined;
25174
+ scope = projectRoot ? "project" : "global";
25175
+ }
25176
+ const installed = await getInstalledAspect(args.name, scope, projectRoot);
23131
25177
  if (!installed) {
23132
25178
  log.error(`Aspect "${args.name}" is not installed`);
23133
25179
  process.exit(1);
23134
25180
  }
23135
- await removeInstalledAspect(args.name);
25181
+ await removeInstalledAspect(args.name, scope, projectRoot);
23136
25182
  if (installed.source === "registry" || installed.source === "github") {
23137
- const aspectDir = getAspectPath(args.name);
25183
+ const aspectDir = getAspectPath(args.name, scope, projectRoot);
23138
25184
  try {
23139
25185
  await rm(aspectDir, { recursive: true });
23140
25186
  } catch {}
@@ -23250,8 +25296,8 @@ var update_default = defineCommand({
23250
25296
  });
23251
25297
 
23252
25298
  // src/commands/validate.ts
23253
- import { readFile as readFile6, stat as stat3 } from "node:fs/promises";
23254
- import { join as join6 } from "node:path";
25299
+ import { readFile as readFile6, stat as stat4 } from "node:fs/promises";
25300
+ import { join as join7 } from "node:path";
23255
25301
  var validate_default = defineCommand({
23256
25302
  meta: {
23257
25303
  name: "validate",
@@ -23278,9 +25324,9 @@ var validate_default = defineCommand({
23278
25324
  Ie("\uD83D\uDD0D Validate aspect");
23279
25325
  let aspectPath = args.path || process.cwd();
23280
25326
  try {
23281
- const stats = await stat3(aspectPath);
25327
+ const stats = await stat4(aspectPath);
23282
25328
  if (stats.isDirectory()) {
23283
- aspectPath = join6(aspectPath, "aspect.json");
25329
+ aspectPath = join7(aspectPath, "aspect.json");
23284
25330
  }
23285
25331
  } catch {
23286
25332
  M2.error(`Path not found: ${aspectPath}`);
@@ -23391,8 +25437,8 @@ var validate_default = defineCommand({
23391
25437
  });
23392
25438
 
23393
25439
  // src/commands/compile.ts
23394
- import { readFile as readFile7, writeFile as writeFile5, stat as stat4 } from "node:fs/promises";
23395
- import { join as join7 } from "node:path";
25440
+ import { readFile as readFile7, writeFile as writeFile5, stat as stat5 } from "node:fs/promises";
25441
+ import { join as join8 } from "node:path";
23396
25442
  function detectModelFamily(model) {
23397
25443
  const lower = model.toLowerCase();
23398
25444
  if (lower.includes("claude")) {
@@ -23477,16 +25523,16 @@ var compile_default = defineCommand({
23477
25523
  let aspectPath;
23478
25524
  let aspectContent;
23479
25525
  try {
23480
- const stats = await stat4(args.name);
25526
+ const stats = await stat5(args.name);
23481
25527
  if (stats.isDirectory()) {
23482
- aspectPath = join7(args.name, "aspect.json");
25528
+ aspectPath = join8(args.name, "aspect.json");
23483
25529
  } else {
23484
25530
  aspectPath = args.name;
23485
25531
  }
23486
25532
  aspectContent = await readFile7(aspectPath, "utf-8");
23487
25533
  } catch {
23488
25534
  try {
23489
- aspectPath = join7(ASPECTS_DIR, args.name, "aspect.json");
25535
+ aspectPath = join8(ASPECTS_DIR, args.name, "aspect.json");
23490
25536
  aspectContent = await readFile7(aspectPath, "utf-8");
23491
25537
  } catch {
23492
25538
  M2.error(`Aspect not found: ${args.name}`);
@@ -23585,81 +25631,47 @@ ${modeInfo.critical}
23585
25631
  });
23586
25632
 
23587
25633
  // src/commands/publish.ts
23588
- import { readFile as readFile8, writeFile as writeFile6, stat as stat5, mkdir as mkdir5, readdir as readdir2 } from "node:fs/promises";
23589
- import { join as join8, dirname as dirname3 } from "node:path";
23590
- import { execSync as execSync2 } from "node:child_process";
23591
- import { homedir as homedir2 } from "node:os";
23592
- var GITHUB_REPO2 = "aimorphist/aspects";
23593
- var REGISTRY_DIR2 = "registry/aspects";
23594
- var INDEX_PATH2 = "registry/index.json";
23595
- var ISSUE_TEMPLATE_URL = `https://github.com/${GITHUB_REPO2}/issues/new?template=new-aspect.yml`;
25634
+ import { readFile as readFile8, stat as stat6, readdir as readdir2 } from "node:fs/promises";
25635
+ import { join as join9, dirname as dirname3 } from "node:path";
25636
+ var MAX_ASPECT_SIZE = 51200;
23596
25637
  var publish_default = defineCommand({
23597
25638
  meta: {
23598
25639
  name: "publish",
23599
- description: "Publish an aspect to the Morphist registry"
25640
+ description: "Publish an aspect to the registry"
23600
25641
  },
23601
25642
  args: {
23602
25643
  path: {
23603
25644
  type: "positional",
23604
25645
  description: "Path to aspect directory or aspect.json (optional)",
23605
25646
  required: false
25647
+ },
25648
+ "dry-run": {
25649
+ type: "boolean",
25650
+ description: "Validate without publishing"
23606
25651
  }
23607
25652
  },
23608
25653
  async run({ args }) {
23609
- Ie("\uD83D\uDCE4 Publish an aspect to the Morphist registry");
23610
- M2.info("");
23611
- M2.info("Publishing options:");
23612
- M2.info(" 1. GitHub PR Automated fork, branch, and PR creation (requires gh CLI)");
23613
- M2.info(" 2. Issue Template — Submit via GitHub issue form (no CLI needed)");
23614
- M2.info(" 3. Manual Get instructions for manual submission");
23615
- M2.info("");
23616
- M2.info(`\uD83D\uDCA1 You can also submit directly at: ${ISSUE_TEMPLATE_URL}`);
23617
- M2.info("");
23618
- const publishMethod = await ve2({
23619
- message: "How would you like to publish?",
23620
- options: [
23621
- { value: "pr", label: "GitHub PR (automated)", hint: "Requires GitHub CLI" },
23622
- { value: "issue", label: "Issue Template (web form)", hint: "Opens in browser" },
23623
- { value: "manual", label: "Manual Instructions", hint: "Copy-paste steps" }
23624
- ]
23625
- });
23626
- if (pD2(publishMethod)) {
23627
- xe("Cancelled");
23628
- process.exit(0);
23629
- }
23630
- if (publishMethod === "issue") {
23631
- await handleIssueTemplate(args.path);
23632
- return;
23633
- }
23634
- if (publishMethod === "manual") {
23635
- await handleManualInstructions(args.path);
23636
- return;
23637
- }
23638
- const hasGhCli = checkGitHubCli();
23639
- if (!hasGhCli) {
23640
- M2.error("GitHub CLI (gh) is required for automated PR publishing.");
23641
- M2.info("Install it from: https://cli.github.com/");
23642
- M2.info("Then run: gh auth login");
23643
- M2.info("");
23644
- M2.info("Alternatively, use the Issue Template option to submit without CLI.");
23645
- process.exit(1);
23646
- }
23647
- const ghUser = getGitHubUsername();
23648
- if (!ghUser) {
23649
- M2.error("Not authenticated with GitHub CLI.");
23650
- M2.info("Run: gh auth login");
23651
- process.exit(1);
25654
+ const dryRun = args["dry-run"];
25655
+ Ie(`${icons2.package} ${dryRun ? "Validate" : "Publish"} an aspect`);
25656
+ if (!dryRun) {
25657
+ const loggedIn = await isLoggedIn();
25658
+ if (!loggedIn) {
25659
+ M2.error("Login required to publish with a name.");
25660
+ console.log();
25661
+ M2.info(`Run ${c3.highlight("aspects login")} to create an account and claim aspect names.`);
25662
+ console.log();
25663
+ M2.info(`Or use ${c3.highlight("aspects share")} to publish anonymously via hash (no account needed).`);
25664
+ process.exit(1);
25665
+ }
23652
25666
  }
23653
- M2.info(`Authenticated as: ${ghUser}`);
23654
- let aspectInfo;
23655
25667
  let aspectPath;
23656
25668
  if (args.path) {
23657
25669
  aspectPath = args.path;
23658
25670
  } else {
23659
- const spinner3 = Y3();
23660
- spinner3.start("Scanning for aspects...");
25671
+ const spinner = Y3();
25672
+ spinner.start("Scanning for aspects...");
23661
25673
  const aspects = await findLocalAspects();
23662
- spinner3.stop("Found aspects");
25674
+ spinner.stop("Found aspects");
23663
25675
  if (aspects.length === 0) {
23664
25676
  M2.error("No aspects found.");
23665
25677
  M2.info("Create one with: aspects create my-aspect");
@@ -23688,97 +25700,93 @@ var publish_default = defineCommand({
23688
25700
  const spinner2 = Y3();
23689
25701
  spinner2.start("Validating aspect...");
23690
25702
  const validation = await validateAspect(aspectPath);
23691
- if (!validation.valid || !validation.aspect) {
25703
+ if (!validation.valid || !validation.aspect || !validation.content) {
23692
25704
  spinner2.stop("Validation failed");
23693
- M2.error(" Aspect validation failed:");
25705
+ M2.error("Invalid aspect.json:");
23694
25706
  for (const err of validation.errors || []) {
23695
- M2.error(` ${err}`);
25707
+ M2.error(` ${icons2.bullet} ${err}`);
23696
25708
  }
23697
25709
  M2.info("");
23698
25710
  M2.info("Fix these issues before publishing.");
23699
25711
  process.exit(1);
23700
25712
  }
23701
- spinner2.stop("Validation passed ✓");
23702
- aspectInfo = validation.aspect;
23703
- M2.info("");
23704
- M2.info(` Name: ${aspectInfo.name}@${aspectInfo.version}`);
23705
- M2.info(` Display: ${aspectInfo.displayName}`);
23706
- M2.info(` Tagline: ${aspectInfo.tagline}`);
23707
- if (aspectInfo.author) {
23708
- M2.info(` Author: ${aspectInfo.author}`);
25713
+ const sizeBytes = Buffer.byteLength(validation.content);
25714
+ if (sizeBytes > MAX_ASPECT_SIZE) {
25715
+ spinner2.stop("Validation failed");
25716
+ M2.error(`Aspect too large: ${sizeBytes} bytes (${MAX_ASPECT_SIZE} byte limit)`);
25717
+ process.exit(1);
25718
+ }
25719
+ if (!dryRun) {
25720
+ const auth = await getAuth();
25721
+ if (validation.aspect.publisher && auth && validation.aspect.publisher !== auth.username) {
25722
+ spinner2.stop("Validation failed");
25723
+ M2.error(`Publisher mismatch: aspect.json has "${validation.aspect.publisher}" but you are "@${auth.username}"`);
25724
+ M2.info("Update the publisher field in aspect.json or log in with the correct account.");
25725
+ process.exit(1);
25726
+ }
25727
+ }
25728
+ spinner2.stop("Validation passed");
25729
+ console.log();
25730
+ console.log(` ${c3.label("Schema")} valid`);
25731
+ console.log(` ${c3.label("Size")} ${(sizeBytes / 1024).toFixed(1)} KB / ${(MAX_ASPECT_SIZE / 1024).toFixed(0)} KB`);
25732
+ if (!dryRun) {
25733
+ console.log(` ${c3.label("Publisher")} ${validation.aspect.publisher || "not set"}`);
25734
+ }
25735
+ console.log();
25736
+ console.log(` ${c3.bold(validation.aspect.displayName)} ${c3.muted(`(${validation.aspect.name}@${validation.aspect.version})`)}`);
25737
+ console.log(` ${c3.italic(validation.aspect.tagline)}`);
25738
+ console.log();
25739
+ if (dryRun) {
25740
+ M2.success("Would publish successfully");
25741
+ Se("(No changes made)");
25742
+ return;
23709
25743
  }
23710
- M2.info(` Path: ${aspectInfo.path}`);
23711
- M2.info("");
23712
25744
  const confirmPublish = await ye2({
23713
- message: "Publish this aspect to the Morphist registry?",
25745
+ message: "Publish this aspect to the registry?",
23714
25746
  initialValue: true
23715
25747
  });
23716
25748
  if (pD2(confirmPublish) || !confirmPublish) {
23717
25749
  xe("Cancelled");
23718
25750
  process.exit(0);
23719
25751
  }
23720
- const spinner = Y3();
23721
- spinner.start("Checking for fork...");
23722
- const hasFork = await ensureFork(ghUser);
23723
- if (hasFork) {
23724
- spinner.stop("Fork ready");
23725
- } else {
23726
- spinner.stop("Fork created");
23727
- }
23728
- spinner.start("Preparing local copy...");
23729
- const forkDir = await prepareLocalFork(ghUser);
23730
- spinner.stop("Local copy ready");
23731
- const branchName = `add-${aspectInfo.name}`;
23732
- spinner.start(`Creating branch: ${branchName}...`);
23733
- await createBranch(forkDir, branchName);
23734
- spinner.stop("Branch created");
23735
- spinner.start("Adding aspect to registry...");
23736
- await copyAspectToRegistry(forkDir, aspectInfo);
23737
- spinner.stop("Aspect added");
23738
- spinner.start("Updating registry index...");
23739
- await updateRegistryIndex(forkDir, aspectInfo, ghUser);
23740
- spinner.stop("Index updated");
23741
- spinner.start("Committing changes...");
23742
- await commitAndPush(forkDir, aspectInfo.name, branchName);
23743
- spinner.stop("Changes pushed");
23744
- spinner.start("Creating pull request...");
23745
- const prUrl = await createPullRequest(forkDir, aspectInfo, branchName);
23746
- spinner.stop("Pull request created");
23747
- M2.success("");
23748
- M2.success("✓ Pull request created!");
23749
- M2.info("");
23750
- M2.info(` PR: ${prUrl}`);
23751
- M2.info(` Aspect: https://github.com/${ghUser}/aspects/tree/${branchName}/${REGISTRY_DIR2}/${aspectInfo.name}`);
23752
- M2.info("");
23753
- M2.info("Your aspect will be available after review and merge.");
23754
- Se("Thanks for contributing! \uD83C\uDF89");
25752
+ const spinner3 = Y3();
25753
+ spinner3.start(`Publishing ${validation.aspect.name}@${validation.aspect.version}...`);
25754
+ try {
25755
+ const parsed = JSON.parse(validation.content);
25756
+ const result = await publishAspect(parsed);
25757
+ spinner3.stop("Published");
25758
+ console.log();
25759
+ console.log(`${icons2.success} Published ${c3.bold(`${result.name}@${result.version}`)}`);
25760
+ console.log();
25761
+ console.log(` ${c3.label("View at")} ${result.url}`);
25762
+ console.log();
25763
+ } catch (err) {
25764
+ spinner3.stop("Publish failed");
25765
+ if (err instanceof ApiClientError) {
25766
+ M2.error(err.message);
25767
+ if (err.errorCode === "version_exists") {
25768
+ M2.info("");
25769
+ M2.info("Tip: Bump the version in aspect.json and try again");
25770
+ } else if (err.errorCode === "name_taken") {
25771
+ M2.info("");
25772
+ M2.info("Tip: Choose a different name in aspect.json");
25773
+ } else if (err.errorCode === "unauthorized") {
25774
+ M2.info("");
25775
+ M2.info('Run "aspects login" to authenticate');
25776
+ }
25777
+ } else {
25778
+ M2.error(`Publish failed: ${err.message}`);
25779
+ }
25780
+ process.exit(1);
25781
+ }
23755
25782
  }
23756
25783
  });
23757
- function checkGitHubCli() {
23758
- try {
23759
- execSync2("gh --version", { stdio: "pipe" });
23760
- return true;
23761
- } catch {
23762
- return false;
23763
- }
23764
- }
23765
- function getGitHubUsername() {
23766
- try {
23767
- const result = execSync2("gh api user --jq .login", {
23768
- encoding: "utf-8",
23769
- stdio: ["pipe", "pipe", "pipe"]
23770
- }).trim();
23771
- return result || null;
23772
- } catch {
23773
- return null;
23774
- }
23775
- }
23776
25784
  async function loadAspectFromPath2(inputPath) {
23777
25785
  let aspectPath = inputPath;
23778
25786
  try {
23779
- const stats = await stat5(inputPath);
25787
+ const stats = await stat6(inputPath);
23780
25788
  if (stats.isDirectory()) {
23781
- aspectPath = join8(inputPath, "aspect.json");
25789
+ aspectPath = join9(inputPath, "aspect.json");
23782
25790
  }
23783
25791
  } catch {
23784
25792
  return null;
@@ -23793,6 +25801,7 @@ async function loadAspectFromPath2(inputPath) {
23793
25801
  tagline: aspect.tagline,
23794
25802
  version: aspect.version || "1.0.0",
23795
25803
  category: aspect.category,
25804
+ publisher: aspect.publisher,
23796
25805
  author: aspect.author
23797
25806
  };
23798
25807
  } catch {
@@ -23809,7 +25818,7 @@ async function findLocalAspects() {
23809
25818
  const entries = await readdir2(process.cwd(), { withFileTypes: true });
23810
25819
  for (const entry of entries) {
23811
25820
  if (entry.isDirectory() && !entry.name.startsWith(".")) {
23812
- const subAspect = await loadAspectFromPath2(join8(process.cwd(), entry.name));
25821
+ const subAspect = await loadAspectFromPath2(join9(process.cwd(), entry.name));
23813
25822
  if (subAspect && !aspects.find((a2) => a2.path === subAspect.path)) {
23814
25823
  aspects.push(subAspect);
23815
25824
  }
@@ -23820,7 +25829,7 @@ async function findLocalAspects() {
23820
25829
  const entries = await readdir2(ASPECTS_DIR, { withFileTypes: true });
23821
25830
  for (const entry of entries) {
23822
25831
  if (entry.isDirectory()) {
23823
- const installedAspect = await loadAspectFromPath2(join8(ASPECTS_DIR, entry.name));
25832
+ const installedAspect = await loadAspectFromPath2(join9(ASPECTS_DIR, entry.name));
23824
25833
  if (installedAspect && !aspects.find((a2) => a2.path === installedAspect.path)) {
23825
25834
  aspects.push(installedAspect);
23826
25835
  }
@@ -23829,119 +25838,12 @@ async function findLocalAspects() {
23829
25838
  } catch {}
23830
25839
  return aspects;
23831
25840
  }
23832
- async function ensureFork(ghUser) {
23833
- try {
23834
- execSync2(`gh repo view ${ghUser}/aspects`, { stdio: "pipe" });
23835
- return true;
23836
- } catch {
23837
- execSync2(`gh repo fork ${GITHUB_REPO2} --clone=false`, { stdio: "pipe" });
23838
- return false;
23839
- }
23840
- }
23841
- async function prepareLocalFork(ghUser) {
23842
- const forkDir = join8(homedir2(), ".aspects", ".publish-cache", "aspects");
23843
- try {
23844
- await stat5(join8(forkDir, ".git"));
23845
- execSync2("git fetch origin", { cwd: forkDir, stdio: "pipe" });
23846
- execSync2("git checkout main", { cwd: forkDir, stdio: "pipe" });
23847
- execSync2("git pull origin main", { cwd: forkDir, stdio: "pipe" });
23848
- } catch {
23849
- await mkdir5(dirname3(forkDir), { recursive: true });
23850
- execSync2(`gh repo clone ${ghUser}/aspects ${forkDir}`, { stdio: "pipe" });
23851
- try {
23852
- execSync2(`git remote add upstream https://github.com/${GITHUB_REPO2}.git`, {
23853
- cwd: forkDir,
23854
- stdio: "pipe"
23855
- });
23856
- } catch {}
23857
- }
23858
- try {
23859
- execSync2("git fetch upstream", { cwd: forkDir, stdio: "pipe" });
23860
- execSync2("git merge upstream/main --no-edit", {
23861
- cwd: forkDir,
23862
- stdio: "pipe"
23863
- });
23864
- } catch {}
23865
- return forkDir;
23866
- }
23867
- async function createBranch(forkDir, branchName) {
23868
- try {
23869
- execSync2(`git branch -D ${branchName}`, { cwd: forkDir, stdio: "pipe" });
23870
- } catch {}
23871
- execSync2(`git checkout -b ${branchName}`, { cwd: forkDir, stdio: "pipe" });
23872
- }
23873
- async function copyAspectToRegistry(forkDir, aspectInfo) {
23874
- const targetDir = join8(forkDir, REGISTRY_DIR2, aspectInfo.name);
23875
- await mkdir5(targetDir, { recursive: true });
23876
- const sourceFile = join8(aspectInfo.path, "aspect.json");
23877
- const targetFile = join8(targetDir, "aspect.json");
23878
- const content = await readFile8(sourceFile, "utf-8");
23879
- await writeFile6(targetFile, content);
23880
- }
23881
- async function updateRegistryIndex(forkDir, aspectInfo, ghUser) {
23882
- const indexPath = join8(forkDir, INDEX_PATH2);
23883
- const indexContent = await readFile8(indexPath, "utf-8");
23884
- const index = JSON.parse(indexContent);
23885
- const now = new Date().toISOString();
23886
- index.aspects[aspectInfo.name] = {
23887
- latest: aspectInfo.version,
23888
- versions: {
23889
- [aspectInfo.version]: {
23890
- published: now,
23891
- url: `https://raw.githubusercontent.com/${GITHUB_REPO2}/main/${REGISTRY_DIR2}/${aspectInfo.name}/aspect.json`
23892
- }
23893
- },
23894
- metadata: {
23895
- displayName: aspectInfo.displayName,
23896
- tagline: aspectInfo.tagline,
23897
- category: aspectInfo.category || "assistant",
23898
- publisher: ghUser,
23899
- githubUrl: `https://github.com/${ghUser}/aspects/tree/main/${REGISTRY_DIR2}/${aspectInfo.name}`,
23900
- trust: "community"
23901
- }
23902
- };
23903
- index.updated = now;
23904
- await writeFile6(indexPath, JSON.stringify(index, null, 2) + `
23905
- `);
23906
- }
23907
- async function commitAndPush(forkDir, aspectName, branchName) {
23908
- execSync2("git add .", { cwd: forkDir, stdio: "pipe" });
23909
- execSync2(`git commit -m "Add ${aspectName} aspect"`, {
23910
- cwd: forkDir,
23911
- stdio: "pipe"
23912
- });
23913
- execSync2(`git push -u origin ${branchName} --force`, {
23914
- cwd: forkDir,
23915
- stdio: "pipe"
23916
- });
23917
- }
23918
- async function createPullRequest(forkDir, aspectInfo, branchName) {
23919
- const title = `Add ${aspectInfo.displayName} aspect`;
23920
- const body = `## New Aspect: ${aspectInfo.displayName}
23921
-
23922
- **Name:** \`${aspectInfo.name}\`
23923
- **Version:** ${aspectInfo.version}
23924
- **Tagline:** ${aspectInfo.tagline}
23925
- ${aspectInfo.category ? `**Category:** ${aspectInfo.category}` : ""}
23926
- ${aspectInfo.author ? `**Author:** ${aspectInfo.author}` : ""}
23927
-
23928
- ---
23929
-
23930
- *Submitted via \`aspects publish\`*
23931
- `;
23932
- const result = execSync2(`gh pr create --repo ${GITHUB_REPO2} --title "${title}" --body "${body.replace(/"/g, "\\\"")}" --head ${branchName}`, {
23933
- cwd: forkDir,
23934
- encoding: "utf-8",
23935
- stdio: ["pipe", "pipe", "pipe"]
23936
- });
23937
- return result.trim();
23938
- }
23939
25841
  async function validateAspect(aspectPath) {
23940
25842
  let filePath = aspectPath;
23941
25843
  try {
23942
- const stats = await stat5(aspectPath);
25844
+ const stats = await stat6(aspectPath);
23943
25845
  if (stats.isDirectory()) {
23944
- filePath = join8(aspectPath, "aspect.json");
25846
+ filePath = join9(aspectPath, "aspect.json");
23945
25847
  }
23946
25848
  } catch {
23947
25849
  return { valid: false, errors: [`Path not found: ${aspectPath}`] };
@@ -23956,7 +25858,12 @@ async function validateAspect(aspectPath) {
23956
25858
  try {
23957
25859
  data = JSON.parse(content);
23958
25860
  } catch (err) {
23959
- return { valid: false, errors: [`Invalid JSON: ${err instanceof Error ? err.message : "parse error"}`] };
25861
+ return {
25862
+ valid: false,
25863
+ errors: [
25864
+ `Invalid JSON: ${err instanceof Error ? err.message : "parse error"}`
25865
+ ]
25866
+ };
23960
25867
  }
23961
25868
  const result = aspectSchema.safeParse(data);
23962
25869
  if (!result.success) {
@@ -23977,118 +25884,15 @@ async function validateAspect(aspectPath) {
23977
25884
  tagline: aspect.tagline,
23978
25885
  version: aspect.version || "1.0.0",
23979
25886
  category: aspect.category,
25887
+ publisher: aspect.publisher,
23980
25888
  author: aspect.author
23981
25889
  }
23982
25890
  };
23983
25891
  }
23984
- async function handleIssueTemplate(inputPath) {
23985
- M2.info("");
23986
- M2.info("\uD83D\uDCDD Issue Template Submission");
23987
- M2.info("");
23988
- if (inputPath) {
23989
- const validation = await validateAspect(inputPath);
23990
- if (validation.valid && validation.aspect) {
23991
- M2.success(`✓ Aspect validated: ${validation.aspect.displayName}`);
23992
- M2.info("");
23993
- M2.info("Your aspect.json content (copy this to the issue form):");
23994
- M2.info("─".repeat(50));
23995
- console.log(validation.content);
23996
- M2.info("─".repeat(50));
23997
- M2.info("");
23998
- } else if (validation.errors) {
23999
- M2.warn("⚠️ Validation issues found:");
24000
- for (const err of validation.errors) {
24001
- M2.error(` • ${err}`);
24002
- }
24003
- M2.info("");
24004
- M2.info("Fix these issues before submitting.");
24005
- M2.info("");
24006
- }
24007
- }
24008
- M2.info("\uD83D\uDCCF Field Limits:");
24009
- M2.info(` • name: ${FIELD_LIMITS.name} chars (lowercase, hyphens only)`);
24010
- M2.info(` • displayName: ${FIELD_LIMITS.displayName} chars`);
24011
- M2.info(` • tagline: ${FIELD_LIMITS.tagline} chars`);
24012
- M2.info(` • prompt: ${FIELD_LIMITS.prompt} chars`);
24013
- M2.info(` • tags: max ${FIELD_LIMITS.maxTags} tags, ${FIELD_LIMITS.tag} chars each`);
24014
- M2.info("");
24015
- const openBrowser = await ye2({
24016
- message: "Open issue template in browser?",
24017
- initialValue: true
24018
- });
24019
- if (pD2(openBrowser)) {
24020
- xe("Cancelled");
24021
- process.exit(0);
24022
- }
24023
- if (openBrowser) {
24024
- try {
24025
- execSync2(`open "${ISSUE_TEMPLATE_URL}"`, { stdio: "pipe" });
24026
- M2.success("Opened in browser!");
24027
- } catch {
24028
- try {
24029
- execSync2(`xdg-open "${ISSUE_TEMPLATE_URL}"`, { stdio: "pipe" });
24030
- M2.success("Opened in browser!");
24031
- } catch {
24032
- M2.info(`Open this URL manually: ${ISSUE_TEMPLATE_URL}`);
24033
- }
24034
- }
24035
- } else {
24036
- M2.info(`Submit at: ${ISSUE_TEMPLATE_URL}`);
24037
- }
24038
- Se("Thanks for contributing! \uD83C\uDF89");
24039
- }
24040
- async function handleManualInstructions(inputPath) {
24041
- M2.info("");
24042
- M2.info("\uD83D\uDCCB Manual Submission Instructions");
24043
- M2.info("");
24044
- if (inputPath) {
24045
- const validation = await validateAspect(inputPath);
24046
- if (validation.valid && validation.aspect) {
24047
- M2.success(`✓ Aspect validated: ${validation.aspect.displayName}`);
24048
- } else if (validation.errors) {
24049
- M2.warn("⚠️ Validation issues found:");
24050
- for (const err of validation.errors) {
24051
- M2.error(` • ${err}`);
24052
- }
24053
- M2.info("");
24054
- }
24055
- }
24056
- M2.info("Option 1: Submit via Issue Template (Easiest)");
24057
- M2.info("─".repeat(50));
24058
- M2.info(` 1. Go to: ${ISSUE_TEMPLATE_URL}`);
24059
- M2.info(" 2. Fill out the form with your aspect details");
24060
- M2.info(" 3. Paste your aspect.json content");
24061
- M2.info(" 4. Submit the issue");
24062
- M2.info(" 5. A maintainer will review and add your aspect");
24063
- M2.info("");
24064
- M2.info("Option 2: Fork & Pull Request");
24065
- M2.info("─".repeat(50));
24066
- M2.info(` 1. Fork https://github.com/${GITHUB_REPO2}`);
24067
- M2.info(" 2. Clone your fork locally");
24068
- M2.info(" 3. Create a new branch: git checkout -b add-your-aspect");
24069
- M2.info(" 4. Create directory: registry/aspects/your-aspect-name/");
24070
- M2.info(" 5. Add your aspect.json file to that directory");
24071
- M2.info(" 6. Update registry/index.json with your aspect metadata");
24072
- M2.info(" 7. Commit and push your changes");
24073
- M2.info(` 8. Open a PR to ${GITHUB_REPO2}`);
24074
- M2.info("");
24075
- M2.info("\uD83D\uDCCF Field Limits:");
24076
- M2.info(` • name: ${FIELD_LIMITS.name} chars (lowercase, hyphens only)`);
24077
- M2.info(` • displayName: ${FIELD_LIMITS.displayName} chars`);
24078
- M2.info(` • tagline: ${FIELD_LIMITS.tagline} chars`);
24079
- M2.info(` • prompt: ${FIELD_LIMITS.prompt} chars`);
24080
- M2.info(` • tags: max ${FIELD_LIMITS.maxTags} tags, ${FIELD_LIMITS.tag} chars each`);
24081
- M2.info("");
24082
- M2.info("\uD83D\uDCDA Documentation:");
24083
- M2.info(` • Schema: https://github.com/${GITHUB_REPO2}/blob/main/docs/CLI.md#aspect-schema-v2`);
24084
- M2.info(` • Examples: https://github.com/${GITHUB_REPO2}/tree/main/registry/aspects`);
24085
- M2.info("");
24086
- Se("Good luck with your submission! \uD83C\uDF89");
24087
- }
24088
25892
 
24089
25893
  // src/commands/edit.ts
24090
- import { readFile as readFile9, writeFile as writeFile7 } from "node:fs/promises";
24091
- import { join as join9 } from "node:path";
25894
+ import { readFile as readFile9, writeFile as writeFile6 } from "node:fs/promises";
25895
+ import { join as join10 } from "node:path";
24092
25896
  var CATEGORIES = [
24093
25897
  "assistant",
24094
25898
  "roleplay",
@@ -24105,7 +25909,7 @@ async function listLocalAspects() {
24105
25909
  const results = [];
24106
25910
  for (const [name, info] of Object.entries(config2.installed)) {
24107
25911
  const aspectPath = info.path || getAspectPath(name);
24108
- const parseResult = await parseAspectFile(join9(aspectPath, "aspect.yaml"));
25912
+ const parseResult = await parseAspectFile(join10(aspectPath, "aspect.json"));
24109
25913
  if (parseResult.success) {
24110
25914
  results.push({ name, path: aspectPath, aspect: parseResult.aspect });
24111
25915
  }
@@ -24261,7 +26065,7 @@ var edit_default = defineCommand({
24261
26065
  xe("Cancelled");
24262
26066
  return;
24263
26067
  }
24264
- const aspectPath = join9(selectedAspect.path, "aspect.yaml");
26068
+ const aspectPath = join10(selectedAspect.path, "aspect.json");
24265
26069
  const content = await readFile9(aspectPath, "utf-8");
24266
26070
  let updatedContent = content;
24267
26071
  if (changes.includes("displayName")) {
@@ -24290,17 +26094,17 @@ ${updatedAspect.tags.map((t4) => ` - ${t4}`).join(`
24290
26094
  `);
24291
26095
  }
24292
26096
  }
24293
- await writeFile7(aspectPath, updatedContent);
26097
+ await writeFile6(aspectPath, updatedContent);
24294
26098
  console.log();
24295
- console.log(`${icons2.success} Updated ${c3.bold(selectedAspect.name)}/aspect.yaml`);
26099
+ console.log(`${icons2.success} Updated ${c3.bold(selectedAspect.name)}/aspect.json`);
24296
26100
  console.log(` ${c3.muted(`Changed: ${changes.join(", ")}`)}`);
24297
26101
  console.log();
24298
26102
  }
24299
26103
  });
24300
26104
 
24301
26105
  // src/commands/bundle.ts
24302
- import { readFile as readFile10, writeFile as writeFile8 } from "node:fs/promises";
24303
- import { join as join10 } from "node:path";
26106
+ import { readFile as readFile10, writeFile as writeFile7 } from "node:fs/promises";
26107
+ import { join as join11 } from "node:path";
24304
26108
  var import_picocolors4 = __toESM(require_picocolors(), 1);
24305
26109
  function parseQuery2(query) {
24306
26110
  const filters = [];
@@ -24380,7 +26184,7 @@ async function loadLocalAspects() {
24380
26184
  const aspects = [];
24381
26185
  for (const name of Object.keys(config2.installed || {})) {
24382
26186
  try {
24383
- const aspectPath = join10(getAspectPath(name), "aspect.json");
26187
+ const aspectPath = join11(getAspectPath(name), "aspect.json");
24384
26188
  const content = await readFile10(aspectPath, "utf-8");
24385
26189
  aspects.push(JSON.parse(content));
24386
26190
  } catch {}
@@ -24394,7 +26198,7 @@ async function loadRegistryAspects() {
24394
26198
  try {
24395
26199
  const versionInfo = entry.versions[entry.latest];
24396
26200
  if (versionInfo?.url) {
24397
- const yamlContent = await fetchAspectYaml(versionInfo.url);
26201
+ const yamlContent = await fetchAspectContent(versionInfo.url);
24398
26202
  const aspect = JSON.parse(yamlContent);
24399
26203
  aspects.push(aspect);
24400
26204
  }
@@ -24458,13 +26262,13 @@ var bundle_default = defineCommand({
24458
26262
  if (entry) {
24459
26263
  const versionInfo = entry.versions[entry.latest];
24460
26264
  if (versionInfo?.url) {
24461
- const content = await fetchAspectYaml(versionInfo.url);
26265
+ const content = await fetchAspectContent(versionInfo.url);
24462
26266
  const aspect = JSON.parse(content);
24463
26267
  aspectsToBundle.push(aspect);
24464
26268
  }
24465
26269
  }
24466
26270
  } else {
24467
- const aspectPath = join10(getAspectPath(name), "aspect.json");
26271
+ const aspectPath = join11(getAspectPath(name), "aspect.json");
24468
26272
  const content = await readFile10(aspectPath, "utf-8");
24469
26273
  aspectsToBundle.push(JSON.parse(content));
24470
26274
  }
@@ -24506,7 +26310,7 @@ var bundle_default = defineCommand({
24506
26310
  if (entry) {
24507
26311
  const versionInfo = entry.versions[entry.latest];
24508
26312
  if (versionInfo?.url) {
24509
- const content = await fetchAspectYaml(versionInfo.url);
26313
+ const content = await fetchAspectContent(versionInfo.url);
24510
26314
  const aspect = JSON.parse(content);
24511
26315
  if (!aspectsToBundle.some((a2) => a2.name === aspect.name)) {
24512
26316
  aspectsToBundle.push(aspect);
@@ -24514,7 +26318,7 @@ var bundle_default = defineCommand({
24514
26318
  }
24515
26319
  }
24516
26320
  } else {
24517
- const aspectPath = join10(getAspectPath(aspectName), "aspect.json");
26321
+ const aspectPath = join11(getAspectPath(aspectName), "aspect.json");
24518
26322
  const content = await readFile10(aspectPath, "utf-8");
24519
26323
  const aspect = JSON.parse(content);
24520
26324
  if (!aspectsToBundle.some((a2) => a2.name === aspect.name)) {
@@ -24547,7 +26351,7 @@ var bundle_default = defineCommand({
24547
26351
  aspects: aspectsToBundle
24548
26352
  };
24549
26353
  const outputPath = args.output;
24550
- await writeFile8(outputPath, JSON.stringify(bundle, null, 2) + `
26354
+ await writeFile7(outputPath, JSON.stringify(bundle, null, 2) + `
24551
26355
  `);
24552
26356
  console.log();
24553
26357
  console.log(`${c3.dim("Bundled aspects:")}`);
@@ -24560,7 +26364,7 @@ var bundle_default = defineCommand({
24560
26364
  });
24561
26365
  async function loadSet2(name) {
24562
26366
  try {
24563
- const setPath = join10(getSetsDir(), name, "set.json");
26367
+ const setPath = join11(getSetsDir(), name, "set.json");
24564
26368
  const content = await readFile10(setPath, "utf-8");
24565
26369
  return JSON.parse(content);
24566
26370
  } catch {
@@ -24568,41 +26372,406 @@ async function loadSet2(name) {
24568
26372
  }
24569
26373
  }
24570
26374
 
26375
+ // src/commands/login.ts
26376
+ var login_default = defineCommand({
26377
+ meta: {
26378
+ name: "login",
26379
+ description: "Authenticate with the aspects registry"
26380
+ },
26381
+ async run() {
26382
+ const auth = await getAuth();
26383
+ if (auth && await isLoggedIn()) {
26384
+ console.log();
26385
+ console.log(`${icons2.info} Already logged in as ${c3.bold(`@${auth.username}`)}`);
26386
+ console.log(c3.muted(' Run "aspects logout" to sign out first.'));
26387
+ console.log();
26388
+ return;
26389
+ }
26390
+ console.log();
26391
+ log.start("Requesting authorization...");
26392
+ let deviceCode;
26393
+ try {
26394
+ deviceCode = await initiateDeviceAuth();
26395
+ } catch (err) {
26396
+ log.error(`Failed to initiate login: ${err.message}`);
26397
+ process.exit(1);
26398
+ }
26399
+ console.log();
26400
+ console.log(` ${c3.bold("Please visit this URL and enter the code:")}`);
26401
+ console.log(` ${c3.highlight(deviceCode.verification_uri_complete)}`);
26402
+ console.log();
26403
+ console.log(` Code: ${c3.bold(deviceCode.user_code)}`);
26404
+ console.log();
26405
+ try {
26406
+ const { exec } = await import("node:child_process");
26407
+ const platform2 = process.platform;
26408
+ const openCmd = platform2 === "darwin" ? "open" : platform2 === "win32" ? "start" : "xdg-open";
26409
+ exec(`${openCmd} "${deviceCode.verification_uri_complete}"`);
26410
+ } catch {}
26411
+ console.log(c3.muted(" Waiting for authorization... (Press Ctrl+C to cancel)"));
26412
+ console.log();
26413
+ let interval = deviceCode.interval * 1000;
26414
+ const expiresAt = Date.now() + deviceCode.expires_in * 1000;
26415
+ while (Date.now() < expiresAt) {
26416
+ await new Promise((r6) => setTimeout(r6, interval));
26417
+ try {
26418
+ const result = await pollDeviceAuth(deviceCode.device_code, deviceCode.code_verifier);
26419
+ if (result.ok && result.access_token) {
26420
+ const expiresIn = result.expires_in ?? 3600;
26421
+ const expiresAtDate = new Date(Date.now() + expiresIn * 1000).toISOString();
26422
+ const username = extractUsernameFromToken(result.access_token) ?? "user";
26423
+ await setAuthTokens({
26424
+ accessToken: result.access_token,
26425
+ refreshToken: result.refresh_token,
26426
+ expiresAt: expiresAtDate,
26427
+ username
26428
+ });
26429
+ console.log(`${icons2.success} Authorized as ${c3.bold(`@${username}`)}`);
26430
+ console.log(c3.muted(" Access token stored in ~/.aspects/config.json"));
26431
+ console.log();
26432
+ return;
26433
+ }
26434
+ if (!result.ok) {
26435
+ switch (result.status) {
26436
+ case "pending":
26437
+ continue;
26438
+ case "slow_down":
26439
+ interval *= 2;
26440
+ continue;
26441
+ case "expired":
26442
+ log.error('Authorization code expired. Please run "aspects login" again.');
26443
+ process.exit(1);
26444
+ break;
26445
+ case "denied":
26446
+ log.error("Authorization denied.");
26447
+ process.exit(1);
26448
+ break;
26449
+ default:
26450
+ log.error(`Unexpected status: ${result.status}`);
26451
+ process.exit(1);
26452
+ }
26453
+ }
26454
+ } catch (err) {
26455
+ continue;
26456
+ }
26457
+ }
26458
+ log.error('Authorization timed out. Please run "aspects login" again.');
26459
+ process.exit(1);
26460
+ }
26461
+ });
26462
+ function extractUsernameFromToken(token) {
26463
+ try {
26464
+ const parts = token.split(".");
26465
+ if (parts.length !== 3)
26466
+ return null;
26467
+ const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
26468
+ return payload.username ?? payload.sub ?? payload.preferred_username ?? null;
26469
+ } catch {
26470
+ return null;
26471
+ }
26472
+ }
26473
+
26474
+ // src/commands/logout.ts
26475
+ var logout_default = defineCommand({
26476
+ meta: {
26477
+ name: "logout",
26478
+ description: "Clear stored authentication tokens"
26479
+ },
26480
+ async run() {
26481
+ const auth = await getAuth();
26482
+ if (!auth) {
26483
+ console.log();
26484
+ console.log(`${icons2.info} Not logged in.`);
26485
+ console.log();
26486
+ return;
26487
+ }
26488
+ const username = auth.username;
26489
+ await clearAuth();
26490
+ console.log();
26491
+ console.log(`${icons2.success} Logged out${username ? ` from @${username}` : ""}`);
26492
+ console.log(c3.muted(" Auth tokens removed from ~/.aspects/config.json"));
26493
+ console.log();
26494
+ }
26495
+ });
26496
+
26497
+ // src/commands/share.ts
26498
+ import { stat as stat7 } from "node:fs/promises";
26499
+ import { join as join12 } from "node:path";
26500
+ var MAX_ASPECT_SIZE2 = 51200;
26501
+ var share_default = defineCommand({
26502
+ meta: {
26503
+ name: "share",
26504
+ description: "Share an aspect anonymously via content hash (no account required)"
26505
+ },
26506
+ args: {
26507
+ target: {
26508
+ type: "positional",
26509
+ description: "Aspect name (if installed) or path to aspect.json",
26510
+ required: false
26511
+ },
26512
+ "dry-run": {
26513
+ type: "boolean",
26514
+ description: "Compute hash without uploading"
26515
+ }
26516
+ },
26517
+ async run({ args }) {
26518
+ const dryRun = args["dry-run"];
26519
+ Ie(`${icons2.share} ${dryRun ? "Preview" : "Share"} an aspect`);
26520
+ const target = args.target;
26521
+ if (!target) {
26522
+ M2.error("Please specify an aspect to share.");
26523
+ console.log();
26524
+ M2.info("Usage:");
26525
+ console.log(` ${c3.cmd("aspects share <name>")} Share an installed aspect`);
26526
+ console.log(` ${c3.cmd("aspects share ./path")} Share from a local path`);
26527
+ console.log();
26528
+ const installed = await listInstalledAspects();
26529
+ if (installed.length > 0) {
26530
+ M2.info("Installed aspects you can share:");
26531
+ for (const item of installed.slice(0, 10)) {
26532
+ console.log(` ${icons2.bullet} ${c3.aspect(item.name)}`);
26533
+ }
26534
+ if (installed.length > 10) {
26535
+ console.log(` ${c3.muted(`...and ${installed.length - 10} more`)}`);
26536
+ }
26537
+ }
26538
+ process.exit(1);
26539
+ }
26540
+ let aspect;
26541
+ if (target.startsWith(".") || target.startsWith("/")) {
26542
+ let filePath = target;
26543
+ try {
26544
+ const stats = await stat7(target);
26545
+ if (stats.isDirectory()) {
26546
+ const jsonPath = join12(target, "aspect.json");
26547
+ const yamlPath = join12(target, "aspect.yaml");
26548
+ try {
26549
+ await stat7(jsonPath);
26550
+ filePath = jsonPath;
26551
+ } catch {
26552
+ filePath = yamlPath;
26553
+ }
26554
+ }
26555
+ } catch {
26556
+ M2.error(`Path not found: ${target}`);
26557
+ process.exit(1);
26558
+ }
26559
+ const result = await parseAspectFile(filePath);
26560
+ if (!result.success) {
26561
+ M2.error(`Invalid aspect: ${result.errors.join(", ")}`);
26562
+ process.exit(1);
26563
+ }
26564
+ aspect = result.aspect;
26565
+ } else {
26566
+ const loaded = await loadInstalledAspect(target);
26567
+ if (!loaded) {
26568
+ M2.error(`Aspect "${target}" is not installed or cannot be read`);
26569
+ M2.info("To share from a path, use: aspects share ./path/to/aspect.json");
26570
+ process.exit(1);
26571
+ }
26572
+ aspect = loaded;
26573
+ }
26574
+ const content = canonicalizeAspect(aspect);
26575
+ const sizeBytes = Buffer.byteLength(content);
26576
+ if (sizeBytes > MAX_ASPECT_SIZE2) {
26577
+ M2.error(`Aspect too large: ${sizeBytes} bytes (${MAX_ASPECT_SIZE2} byte limit)`);
26578
+ process.exit(1);
26579
+ }
26580
+ const hash2 = blake3HashAspect(aspect);
26581
+ console.log();
26582
+ console.log(` ${c3.bold(aspect.displayName)} ${c3.muted(`(${aspect.name}@${aspect.version})`)}`);
26583
+ console.log(` ${c3.italic(aspect.tagline)}`);
26584
+ console.log();
26585
+ console.log(` ${c3.label("Size")} ${(sizeBytes / 1024).toFixed(1)} KB`);
26586
+ console.log(` ${c3.label("Hash")} ${hash2}`);
26587
+ console.log();
26588
+ if (dryRun) {
26589
+ M2.info("Dry run — not uploading");
26590
+ console.log();
26591
+ console.log(` ${c3.label("Install")} aspects add hash:${hash2}`);
26592
+ console.log();
26593
+ Se("(No upload performed)");
26594
+ return;
26595
+ }
26596
+ const spinner = Y3();
26597
+ spinner.start("Uploading...");
26598
+ try {
26599
+ const response = await publishAnonymous(aspect);
26600
+ spinner.stop("Uploaded");
26601
+ if (response.blake3 !== hash2) {
26602
+ M2.warn("Hash mismatch: client and server computed different hashes.");
26603
+ console.log(` ${c3.muted("Client:")} ${hash2}`);
26604
+ console.log(` ${c3.muted("Server:")} ${response.blake3}`);
26605
+ console.log(` ${c3.muted("Using server hash (authoritative).")}`);
26606
+ console.log();
26607
+ }
26608
+ console.log();
26609
+ console.log(`${icons2.success} ${c3.bold("Shared successfully!")}`);
26610
+ console.log();
26611
+ console.log(` ${c3.label("Hash")} ${response.blake3}`);
26612
+ console.log(` ${c3.label("Install")} ${c3.highlight(`aspects add blake3:${response.blake3}`)}`);
26613
+ if (response.existing) {
26614
+ console.log(` ${c3.muted("(Already existed on registry)")}`);
26615
+ }
26616
+ console.log();
26617
+ Se("Share this hash with anyone to let them install your aspect!");
26618
+ } catch (err) {
26619
+ spinner.stop("Upload failed");
26620
+ if (err instanceof ApiClientError) {
26621
+ M2.error(err.message);
26622
+ if (err.errorCode === "already_exists") {
26623
+ console.log();
26624
+ console.log(`${icons2.info} This aspect is already available on the registry.`);
26625
+ console.log();
26626
+ console.log(` ${c3.label("Hash")} ${hash2}`);
26627
+ console.log(` ${c3.label("Install")} ${c3.highlight(`aspects add hash:${hash2}`)}`);
26628
+ console.log();
26629
+ return;
26630
+ }
26631
+ } else {
26632
+ M2.error(`Upload failed: ${err.message}`);
26633
+ }
26634
+ process.exit(1);
26635
+ }
26636
+ }
26637
+ });
26638
+
26639
+ // src/commands/unpublish.ts
26640
+ var unpublish_default = defineCommand({
26641
+ meta: {
26642
+ name: "unpublish",
26643
+ description: "Unpublish a version from the registry"
26644
+ },
26645
+ args: {
26646
+ target: {
26647
+ type: "positional",
26648
+ description: "Aspect to unpublish (name@version)",
26649
+ required: true
26650
+ }
26651
+ },
26652
+ async run({ args }) {
26653
+ const target = args.target;
26654
+ const atIndex = target.lastIndexOf("@");
26655
+ if (atIndex <= 0) {
26656
+ M2.error("Please specify name@version (e.g. my-aspect@1.0.0)");
26657
+ process.exit(1);
26658
+ }
26659
+ const name = target.slice(0, atIndex);
26660
+ const version2 = target.slice(atIndex + 1);
26661
+ Ie(`${icons2.package} Unpublish ${c3.bold(`${name}@${version2}`)}`);
26662
+ const loggedIn = await isLoggedIn();
26663
+ if (!loggedIn) {
26664
+ M2.error('Not logged in. Run "aspects login" first.');
26665
+ process.exit(1);
26666
+ }
26667
+ const confirmed = await ye2({
26668
+ message: `Are you sure you want to unpublish ${name}@${version2}? This cannot be undone.`,
26669
+ initialValue: false
26670
+ });
26671
+ if (pD2(confirmed) || !confirmed) {
26672
+ xe("Cancelled");
26673
+ process.exit(0);
26674
+ }
26675
+ const spinner = Y3();
26676
+ spinner.start(`Unpublishing ${name}@${version2}...`);
26677
+ try {
26678
+ const result = await unpublishAspect(name, version2);
26679
+ spinner.stop("Done");
26680
+ console.log();
26681
+ console.log(`${icons2.success} ${result.message}`);
26682
+ console.log();
26683
+ } catch (err) {
26684
+ spinner.stop("Failed");
26685
+ if (err instanceof ApiClientError) {
26686
+ M2.error(err.message);
26687
+ if (err.errorCode === "forbidden") {
26688
+ M2.info("Unpublish is only allowed within 72 hours of publishing.");
26689
+ } else if (err.errorCode === "not_found") {
26690
+ M2.info("That version does not exist in the registry.");
26691
+ } else if (err.errorCode === "unauthorized") {
26692
+ M2.info('Run "aspects login" to authenticate.');
26693
+ }
26694
+ } else {
26695
+ M2.error(`Unpublish failed: ${err.message}`);
26696
+ }
26697
+ process.exit(1);
26698
+ }
26699
+ }
26700
+ });
26701
+
24571
26702
  // src/cli.ts
26703
+ var ALIASES = {
26704
+ c: "create",
26705
+ new: "create",
26706
+ n: "create",
26707
+ install: "add",
26708
+ get: "add",
26709
+ a: "add",
26710
+ i: "add",
26711
+ g: "add"
26712
+ };
26713
+ var ALIAS_HINTS = {};
26714
+ for (const [alias, canonical] of Object.entries(ALIASES)) {
26715
+ (ALIAS_HINTS[canonical] ??= []).push(alias);
26716
+ }
26717
+ var cmdArg = process.argv[2];
26718
+ if (cmdArg && ALIASES[cmdArg]) {
26719
+ process.argv[2] = ALIASES[cmdArg];
26720
+ }
26721
+ var COMMANDS = [
26722
+ { name: "create", cmd: create_default, desc: "Create a new aspect interactively", aliases: ["c", "new", "n"] },
26723
+ { name: "add", cmd: add_default, desc: "Install aspect(s) to your local library", aliases: ["install", "get", "a", "i", "g"] },
26724
+ { name: "list", cmd: list_default, desc: "List installed aspects" },
26725
+ { name: "search", cmd: search_default, desc: "Search the aspect registry" },
26726
+ { name: "find", cmd: find_default, desc: "Search aspects with filters and operators" },
26727
+ { name: "info", cmd: info_default, desc: "Show details about an aspect" },
26728
+ { name: "remove", cmd: remove_default, desc: "Remove an installed aspect" },
26729
+ { name: "update", cmd: update_default, desc: "Update installed aspect(s) to latest version" },
26730
+ { name: "validate", cmd: validate_default, desc: "Validate an aspect.json file" },
26731
+ { name: "compile", cmd: compile_default, desc: "Compile an aspect's prompt for a model" },
26732
+ { name: "publish", cmd: publish_default, desc: "Publish an aspect to the registry" },
26733
+ { name: "set", cmd: set_default, desc: "Manage aspect sets (collections)" },
26734
+ { name: "edit", cmd: edit_default, desc: "Edit an existing aspect" },
26735
+ { name: "bundle", cmd: bundle_default, desc: "Bundle multiple aspects into one file" },
26736
+ { name: "share", cmd: share_default, desc: "Share an aspect via content hash" },
26737
+ { name: "unpublish", cmd: unpublish_default, desc: "Unpublish a version from the registry" },
26738
+ { name: "login", cmd: login_default, desc: "Authenticate with the registry" },
26739
+ { name: "logout", cmd: logout_default, desc: "Clear stored authentication tokens" }
26740
+ ];
26741
+ function showCustomHelp() {
26742
+ morphistBanner();
26743
+ console.log(import_picocolors5.default.dim(`Package manager for AI personality aspects (v0.1.0)`));
26744
+ console.log();
26745
+ console.log(`${import_picocolors5.default.bold(import_picocolors5.default.underline("USAGE"))} ${import_picocolors5.default.cyan("aspects")} ${import_picocolors5.default.dim("<command>")} ${import_picocolors5.default.dim("[options]")}`);
26746
+ console.log();
26747
+ console.log(import_picocolors5.default.bold(import_picocolors5.default.underline("COMMANDS")));
26748
+ console.log();
26749
+ const maxNameLen = Math.max(...COMMANDS.map((c5) => c5.name.length));
26750
+ for (const { name, desc, aliases } of COMMANDS) {
26751
+ const paddedName = name.padStart(maxNameLen);
26752
+ const aliasPart = aliases?.length ? ` ${import_picocolors5.default.dim("also:")} ${aliases.map((a2) => import_picocolors5.default.cyan(a2)).join(import_picocolors5.default.dim(", "))}` : "";
26753
+ console.log(` ${import_picocolors5.default.cyan(paddedName)} ${desc}${aliasPart}`);
26754
+ }
26755
+ console.log();
26756
+ console.log(`Use ${import_picocolors5.default.cyan("aspects <command> --help")} for more info.`);
26757
+ console.log();
26758
+ }
26759
+ var showingHelp = process.argv.length === 2 || process.argv.length === 3 && (process.argv[2] === "--help" || process.argv[2] === "-h");
26760
+ if (showingHelp) {
26761
+ showCustomHelp();
26762
+ process.exit(0);
26763
+ }
26764
+ var subCommands = {};
26765
+ for (const { name, cmd } of COMMANDS) {
26766
+ subCommands[name] = cmd;
26767
+ }
24572
26768
  var main = defineCommand({
24573
26769
  meta: {
24574
26770
  name: "aspects",
24575
26771
  version: "0.1.0",
24576
26772
  description: "Package manager for AI personality aspects"
24577
26773
  },
24578
- subCommands: {
24579
- create: create_default,
24580
- c: create_default,
24581
- new: create_default,
24582
- n: create_default,
24583
- add: add_default,
24584
- install: add_default,
24585
- get: add_default,
24586
- a: add_default,
24587
- i: add_default,
24588
- g: add_default,
24589
- list: list_default,
24590
- search: search_default,
24591
- find: find_default,
24592
- info: info_default,
24593
- remove: remove_default,
24594
- update: update_default,
24595
- validate: validate_default,
24596
- compile: compile_default,
24597
- publish: publish_default,
24598
- set: set_default,
24599
- edit: edit_default,
24600
- bundle: bundle_default
24601
- }
26774
+ subCommands
24602
26775
  });
24603
26776
  morphistBanner();
24604
- var args = process.argv.slice(2);
24605
- if (args.length === 0 || args[0] && args[0].startsWith("-") && args[0] !== "--help" && args[0] !== "-h") {
24606
- process.argv.splice(2, 0, "create");
24607
- }
24608
26777
  runMain(main);