@litlab/audx 0.0.1 → 0.5.5

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 (81) hide show
  1. package/README.md +96 -53
  2. package/dist/bin.js +1212 -0
  3. package/dist/cc-DgCkkqq8.js +13 -0
  4. package/dist/cc-he3fHS3P.js +12 -0
  5. package/dist/index.d.ts +723 -3
  6. package/dist/index.js +1534 -126
  7. package/dist/react.d.ts +583 -0
  8. package/dist/react.js +1556 -0
  9. package/package.json +64 -39
  10. package/schemas/pack.schema.json +4 -0
  11. package/schemas/patch.schema.json +857 -0
  12. package/dist/codegen/theme-codegen.d.ts +0 -12
  13. package/dist/codegen/theme-codegen.d.ts.map +0 -1
  14. package/dist/codegen/theme-codegen.js +0 -153
  15. package/dist/codegen/theme-codegen.js.map +0 -1
  16. package/dist/commands/add.d.ts +0 -2
  17. package/dist/commands/add.d.ts.map +0 -1
  18. package/dist/commands/add.js +0 -120
  19. package/dist/commands/add.js.map +0 -1
  20. package/dist/commands/diff.d.ts +0 -2
  21. package/dist/commands/diff.d.ts.map +0 -1
  22. package/dist/commands/diff.js +0 -103
  23. package/dist/commands/diff.js.map +0 -1
  24. package/dist/commands/generate.d.ts +0 -12
  25. package/dist/commands/generate.d.ts.map +0 -1
  26. package/dist/commands/generate.js +0 -96
  27. package/dist/commands/generate.js.map +0 -1
  28. package/dist/commands/init.d.ts +0 -2
  29. package/dist/commands/init.d.ts.map +0 -1
  30. package/dist/commands/init.js +0 -79
  31. package/dist/commands/init.js.map +0 -1
  32. package/dist/commands/list.d.ts +0 -14
  33. package/dist/commands/list.d.ts.map +0 -1
  34. package/dist/commands/list.js +0 -93
  35. package/dist/commands/list.js.map +0 -1
  36. package/dist/commands/remove.d.ts +0 -2
  37. package/dist/commands/remove.d.ts.map +0 -1
  38. package/dist/commands/remove.js +0 -71
  39. package/dist/commands/remove.js.map +0 -1
  40. package/dist/commands/theme.d.ts +0 -31
  41. package/dist/commands/theme.d.ts.map +0 -1
  42. package/dist/commands/theme.js +0 -142
  43. package/dist/commands/theme.js.map +0 -1
  44. package/dist/commands/update.d.ts +0 -2
  45. package/dist/commands/update.d.ts.map +0 -1
  46. package/dist/commands/update.js +0 -123
  47. package/dist/commands/update.js.map +0 -1
  48. package/dist/core/alias-resolver.d.ts +0 -24
  49. package/dist/core/alias-resolver.d.ts.map +0 -1
  50. package/dist/core/alias-resolver.js +0 -87
  51. package/dist/core/alias-resolver.js.map +0 -1
  52. package/dist/core/config.d.ts +0 -21
  53. package/dist/core/config.d.ts.map +0 -1
  54. package/dist/core/config.js +0 -43
  55. package/dist/core/config.js.map +0 -1
  56. package/dist/core/file-writer.d.ts +0 -14
  57. package/dist/core/file-writer.d.ts.map +0 -1
  58. package/dist/core/file-writer.js +0 -90
  59. package/dist/core/file-writer.js.map +0 -1
  60. package/dist/core/package-manager.d.ts +0 -3
  61. package/dist/core/package-manager.d.ts.map +0 -1
  62. package/dist/core/package-manager.js +0 -17
  63. package/dist/core/package-manager.js.map +0 -1
  64. package/dist/core/registry.d.ts +0 -18
  65. package/dist/core/registry.d.ts.map +0 -1
  66. package/dist/core/registry.js +0 -69
  67. package/dist/core/registry.js.map +0 -1
  68. package/dist/core/theme-manager.d.ts +0 -35
  69. package/dist/core/theme-manager.d.ts.map +0 -1
  70. package/dist/core/theme-manager.js +0 -94
  71. package/dist/core/theme-manager.js.map +0 -1
  72. package/dist/core/utils.d.ts +0 -22
  73. package/dist/core/utils.d.ts.map +0 -1
  74. package/dist/core/utils.js +0 -44
  75. package/dist/core/utils.js.map +0 -1
  76. package/dist/index.d.ts.map +0 -1
  77. package/dist/index.js.map +0 -1
  78. package/dist/types.d.ts +0 -116
  79. package/dist/types.d.ts.map +0 -1
  80. package/dist/types.js +0 -43
  81. package/dist/types.js.map +0 -1
package/dist/bin.js ADDED
@@ -0,0 +1,1212 @@
1
+ #!/usr/bin/env node
2
+ import * as p from '@clack/prompts';
3
+ import { existsSync, mkdirSync } from 'node:fs';
4
+ import { readdir, readFile, writeFile, unlink } from 'node:fs/promises';
5
+ import __node_cjsPath, { resolve, join, basename, isAbsolute } from 'node:path';
6
+ import pc from 'picocolors';
7
+ import { _ as _object_without_properties_loose } from './cc-DgCkkqq8.js';
8
+ import __node_cjsModule from 'node:module';
9
+ import __node_cjsUrl from 'node:url';
10
+
11
+ const require$1 = __node_cjsModule.createRequire(import.meta.url);
12
+
13
+ const REGISTRY_BASE = "https://audx.site/api";
14
+ const CONFIG_DIR = ".themes";
15
+ const CONFIG_FILE = "config.json";
16
+ function configPath() {
17
+ return resolve(process.cwd(), CONFIG_DIR, CONFIG_FILE);
18
+ }
19
+ function getConfig() {
20
+ const p = configPath();
21
+ if (!existsSync(p)) return null;
22
+ try {
23
+ const raw = JSON.parse(require$1("node:fs").readFileSync(p, "utf-8"));
24
+ if (typeof raw.output === "string") return {
25
+ output: raw.output
26
+ };
27
+ } catch (unused) {}
28
+ return null;
29
+ }
30
+ async function ensureConfig(context = "setup") {
31
+ const existing = getConfig();
32
+ if (existing) return existing;
33
+ const isThemeContext = context === "themes";
34
+ const output = await p.select({
35
+ message: isThemeContext ? "Where should themes be installed?" : "Where should AudX be set up?",
36
+ options: isThemeContext ? [
37
+ {
38
+ value: "src/audio",
39
+ label: "src/audio/themes",
40
+ hint: "default"
41
+ },
42
+ {
43
+ value: "lib/audio",
44
+ label: "lib/audio/themes"
45
+ },
46
+ {
47
+ value: "__custom__",
48
+ label: "Custom path..."
49
+ }
50
+ ] : [
51
+ {
52
+ value: "src/audio",
53
+ label: "src/audio",
54
+ hint: "default"
55
+ },
56
+ {
57
+ value: "lib/audio",
58
+ label: "lib/audio"
59
+ },
60
+ {
61
+ value: "__custom__",
62
+ label: "Custom path..."
63
+ }
64
+ ]
65
+ });
66
+ if (p.isCancel(output)) {
67
+ p.cancel("Cancelled.");
68
+ process.exit(0);
69
+ }
70
+ let outputDir = output;
71
+ if (outputDir === "__custom__") {
72
+ const custom = await p.text({
73
+ message: "Enter output path",
74
+ placeholder: isThemeContext ? "src/audio/themes" : "src/audio",
75
+ validate: (v)=>v.length === 0 ? "Path is required" : undefined
76
+ });
77
+ if (p.isCancel(custom)) {
78
+ p.cancel("Cancelled.");
79
+ process.exit(0);
80
+ }
81
+ outputDir = normalizeConfigOutput(custom, context);
82
+ }
83
+ const config = {
84
+ output: outputDir
85
+ };
86
+ const dir = resolve(process.cwd(), CONFIG_DIR);
87
+ if (!existsSync(dir)) mkdirSync(dir, {
88
+ recursive: true
89
+ });
90
+ require$1("node:fs").writeFileSync(configPath(), `${JSON.stringify(config, null, 2)}\n`, "utf-8");
91
+ return config;
92
+ }
93
+ function normalizeConfigOutput(output, context) {
94
+ const normalized = output.replace(/\/+$/, "");
95
+ if (context === "themes" && normalized.endsWith("/themes")) {
96
+ return normalized.slice(0, -"/themes".length);
97
+ }
98
+ return normalized;
99
+ }
100
+ function getPatchesDir() {
101
+ var _ref;
102
+ const config = getConfig();
103
+ const output = (_ref = config == null ? void 0 : config.output) != null ? _ref : "src/audio";
104
+ return resolve(process.cwd(), output, "themes");
105
+ }
106
+ function getSoundsDir() {
107
+ var _ref;
108
+ const config = getConfig();
109
+ const output = (_ref = config == null ? void 0 : config.output) != null ? _ref : "src/audio";
110
+ return resolve(process.cwd(), output, "a");
111
+ }
112
+ function parseGitHubSource(source) {
113
+ const normalizedSource = source.replace(/\/+$/, "").replace(/\.git$/, "");
114
+ const ghUrlMatch = normalizedSource.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\/tree\/([^/]+)(?:\/(.+))?)?$/);
115
+ if (ghUrlMatch) {
116
+ var _ghUrlMatch_, _ghUrlMatch_1;
117
+ return {
118
+ owner: ghUrlMatch[1],
119
+ repo: ghUrlMatch[2],
120
+ branch: (_ghUrlMatch_ = ghUrlMatch[3]) != null ? _ghUrlMatch_ : "main",
121
+ path: (_ghUrlMatch_1 = ghUrlMatch[4]) != null ? _ghUrlMatch_1 : ""
122
+ };
123
+ }
124
+ const shorthand = normalizedSource.match(/^([^/]+)\/([^/]+)$/);
125
+ if (shorthand) {
126
+ return {
127
+ owner: shorthand[1],
128
+ repo: shorthand[2],
129
+ branch: "main",
130
+ path: ""
131
+ };
132
+ }
133
+ return null;
134
+ }
135
+ async function discoverPatchesFromGitHub(source) {
136
+ const parsed = parseGitHubSource(source);
137
+ if (!parsed) {
138
+ throw new Error(`Invalid source: ${source}. Use owner/repo or a GitHub URL.`);
139
+ }
140
+ const { owner, repo, branch, path: subPath } = parsed;
141
+ const treeUrl = `https://api.github.com/repos/${owner}/${repo}/git/trees/${branch}?recursive=1`;
142
+ const res = await fetch(treeUrl, {
143
+ headers: {
144
+ Accept: "application/vnd.github.v3+json"
145
+ }
146
+ });
147
+ if (!res.ok) {
148
+ throw new Error(`Failed to fetch repo tree: ${res.status}`);
149
+ }
150
+ const tree = await res.json();
151
+ const jsonFiles = tree.tree.filter((item)=>{
152
+ if (item.type !== "blob" || !item.path.endsWith(".json")) return false;
153
+ if (subPath && !item.path.startsWith(subPath)) return false;
154
+ if (item.path.includes("node_modules/")) return false;
155
+ if (item.path.includes("package.json")) return false;
156
+ if (item.path.includes("tsconfig")) return false;
157
+ if (item.path.includes(".changeset/")) return false;
158
+ return true;
159
+ });
160
+ const patches = [];
161
+ for (const file of jsonFiles){
162
+ const rawUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${branch}/${file.path}`;
163
+ try {
164
+ const r = await fetch(rawUrl);
165
+ if (!r.ok) continue;
166
+ const data = await r.json();
167
+ if (!validatePatch(data)) continue;
168
+ patches.push({
169
+ name: data.name,
170
+ path: file.path,
171
+ downloadUrl: rawUrl,
172
+ description: data.description,
173
+ soundCount: Object.keys(data.sounds).length
174
+ });
175
+ } catch (unused) {}
176
+ }
177
+ return patches;
178
+ }
179
+ function isGitHubSource(source) {
180
+ return parseGitHubSource(source) !== null;
181
+ }
182
+ function isLocalSource(source) {
183
+ if (source.startsWith("http://") || source.startsWith("https://")) {
184
+ return false;
185
+ }
186
+ const abs = isAbsolute(source) ? source : resolve(process.cwd(), source);
187
+ return existsSync(abs);
188
+ }
189
+ async function discoverPatchesFromLocal(source) {
190
+ const abs = isAbsolute(source) ? source : resolve(process.cwd(), source);
191
+ if (abs.endsWith(".json")) {
192
+ const raw = await readFile(abs, "utf-8");
193
+ const data = JSON.parse(raw);
194
+ if (!validatePatch(data)) {
195
+ throw new Error(`${source} is not a valid sound patch.`);
196
+ }
197
+ return [
198
+ {
199
+ name: data.name,
200
+ path: abs,
201
+ downloadUrl: abs,
202
+ description: data.description,
203
+ soundCount: Object.keys(data.sounds).length
204
+ }
205
+ ];
206
+ }
207
+ const files = await readdir(abs);
208
+ const patches = [];
209
+ for (const file of files){
210
+ if (!file.endsWith(".json") || file === "index.json") continue;
211
+ try {
212
+ const filePath = join(abs, file);
213
+ const raw = await readFile(filePath, "utf-8");
214
+ const data = JSON.parse(raw);
215
+ if (!validatePatch(data)) continue;
216
+ patches.push({
217
+ name: data.name,
218
+ path: filePath,
219
+ downloadUrl: filePath,
220
+ description: data.description,
221
+ soundCount: Object.keys(data.sounds).length
222
+ });
223
+ } catch (unused) {}
224
+ }
225
+ return patches;
226
+ }
227
+ async function fetchPatchIndex() {
228
+ const res = await fetch(`${REGISTRY_BASE}/patches`);
229
+ if (!res.ok) {
230
+ throw new Error(`Failed to fetch patch index: ${res.status}`);
231
+ }
232
+ return res.json();
233
+ }
234
+ async function fetchPatchJson(nameOrUrl) {
235
+ const url = nameOrUrl.startsWith("http") ? nameOrUrl : `${REGISTRY_BASE}/patch/${nameOrUrl}`;
236
+ const res = await fetch(url);
237
+ if (!res.ok) {
238
+ throw new Error(`Failed to fetch patch: ${res.status}`);
239
+ }
240
+ return res.json();
241
+ }
242
+ async function registerPatch(url) {
243
+ try {
244
+ await fetch(`${REGISTRY_BASE}/patches`, {
245
+ method: "POST",
246
+ headers: {
247
+ "Content-Type": "application/json"
248
+ },
249
+ body: JSON.stringify({
250
+ url
251
+ })
252
+ });
253
+ } catch (unused) {}
254
+ }
255
+ function validatePatch(data) {
256
+ return typeof data.name === "string" && typeof data.sounds === "object" && data.sounds !== null;
257
+ }
258
+ async function getInstalledPatches() {
259
+ const dir = getPatchesDir();
260
+ if (!existsSync(dir)) return [];
261
+ const files = await readdir(dir);
262
+ const patches = [];
263
+ for (const file of files){
264
+ if (!file.endsWith(".ts") || file === "index.ts") continue;
265
+ try {
266
+ var _raw_match, _ref;
267
+ const raw = await readFile(join(dir, file), "utf-8");
268
+ const nameMatch = raw.match(/^\/\/ patch: (.+)$/m);
269
+ const exportCount = ((_raw_match = raw.match(/^export const /gm)) != null ? _raw_match : []).length;
270
+ const name = (_ref = nameMatch == null ? void 0 : nameMatch[1]) != null ? _ref : basename(file, ".ts");
271
+ patches.push({
272
+ file,
273
+ name,
274
+ soundCount: Math.max(0, exportCount - 1)
275
+ });
276
+ } catch (unused) {}
277
+ }
278
+ return patches;
279
+ }
280
+ const RESERVED = new Set([
281
+ "break",
282
+ "case",
283
+ "catch",
284
+ "continue",
285
+ "debugger",
286
+ "default",
287
+ "delete",
288
+ "do",
289
+ "else",
290
+ "finally",
291
+ "for",
292
+ "function",
293
+ "if",
294
+ "in",
295
+ "instanceof",
296
+ "new",
297
+ "return",
298
+ "switch",
299
+ "this",
300
+ "throw",
301
+ "try",
302
+ "typeof",
303
+ "var",
304
+ "void",
305
+ "while",
306
+ "with",
307
+ "class",
308
+ "const",
309
+ "enum",
310
+ "export",
311
+ "extends",
312
+ "import",
313
+ "super",
314
+ "implements",
315
+ "interface",
316
+ "let",
317
+ "package",
318
+ "private",
319
+ "protected",
320
+ "public",
321
+ "static",
322
+ "yield",
323
+ "await"
324
+ ]);
325
+ function toCamelCase(s) {
326
+ let id = s.replace(/[^a-zA-Z0-9]+(.)/g, (_, c)=>c.toUpperCase()).replace(/^[^a-zA-Z_$]/, "_$&");
327
+ if (RESERVED.has(id)) id = `_${id}`;
328
+ return id;
329
+ }
330
+ function toIdentifier(s) {
331
+ return toCamelCase(s);
332
+ }
333
+ function generateModule(data) {
334
+ const entries = Object.entries(data.sounds);
335
+ const ids = entries.map(([key])=>toCamelCase(key));
336
+ const lines = [
337
+ `// ${data.name} — generated by @litlab/audx (do not edit)`,
338
+ `// patch: ${data.name}`,
339
+ `import type { SoundDefinition, SoundPatch } from "@litlab/audx";`,
340
+ ""
341
+ ];
342
+ for(let i = 0; i < entries.length; i++){
343
+ const [, def] = entries[i];
344
+ lines.push(`export const ${ids[i]}: SoundDefinition = ${JSON.stringify(def)};`);
345
+ }
346
+ const { sounds: _, $schema: _s } = data, meta = _object_without_properties_loose(data, [
347
+ "sounds",
348
+ "$schema"
349
+ ]);
350
+ const soundsObj = ids.map((id, i)=>{
351
+ const key = entries[i][0];
352
+ return id === key ? id : `${JSON.stringify(key)}: ${id}`;
353
+ });
354
+ lines.push("", `export const _patch: SoundPatch = {`, ` ...${JSON.stringify(meta)},`, ` sounds: { ${soundsObj.join(", ")} },`, `};`, "");
355
+ return lines.join("\n");
356
+ }
357
+ function generateSoundModule(name, definition) {
358
+ const id = toCamelCase(name);
359
+ return [
360
+ `import { defineSound } from "@litlab/audx";`,
361
+ "",
362
+ `export const ${id} = defineSound(${JSON.stringify(definition, null, 2)});`,
363
+ ""
364
+ ].join("\n");
365
+ }
366
+ async function regenerateIndex(dir) {
367
+ if (!existsSync(dir)) return;
368
+ const files = await readdir(dir);
369
+ const modules = files.filter((f)=>f.endsWith(".ts") && f !== "index.ts").map((f)=>basename(f, ".ts")).sort();
370
+ const lines = [
371
+ "// generated by @litlab/audx (do not edit)",
372
+ ...modules.map((m)=>`export * as ${toCamelCase(m)} from "./${m}";`),
373
+ ""
374
+ ];
375
+ await writeFile(join(dir, "index.ts"), lines.join("\n"), "utf-8");
376
+ }
377
+
378
+ function parseAddOptions(args) {
379
+ const options = {};
380
+ let source;
381
+ for(let i = 0; i < args.length; i++){
382
+ const arg = args[i];
383
+ if (arg === "-y" || arg === "--yes") {
384
+ options.yes = true;
385
+ } else if (arg === "-l" || arg === "--list") {
386
+ options.list = true;
387
+ } else if (arg === "--patch") {
388
+ options.patch = args[++i];
389
+ } else if (arg && !arg.startsWith("-")) {
390
+ source = arg;
391
+ }
392
+ }
393
+ return {
394
+ source,
395
+ options
396
+ };
397
+ }
398
+ async function add(args) {
399
+ const { source, options } = parseAddOptions(args);
400
+ p.intro("@litlab/audx add");
401
+ if (!source) {
402
+ await addFromRegistry(options);
403
+ return;
404
+ }
405
+ if (isLocalSource(source)) {
406
+ await addFromLocal(source, options);
407
+ return;
408
+ }
409
+ if (source.startsWith("http") && source.endsWith(".json")) {
410
+ await addFromUrl(source, options);
411
+ return;
412
+ }
413
+ if (isGitHubSource(source)) {
414
+ await addFromGitHub(source, options);
415
+ return;
416
+ }
417
+ await addSoundFromRegistry(source, options);
418
+ }
419
+ async function addFromLocal(source, options) {
420
+ const s = p.spinner();
421
+ s.start("Scanning local path for patches...");
422
+ let discovered;
423
+ try {
424
+ discovered = await discoverPatchesFromLocal(source);
425
+ s.stop(`Found ${discovered.length} patch(es)`);
426
+ } catch (err) {
427
+ s.stop("Failed to scan local path.");
428
+ p.log.error(String(err));
429
+ process.exit(1);
430
+ }
431
+ if (discovered.length === 0) {
432
+ p.log.warn("No valid sound patches found at this path.");
433
+ p.outro("Patches must be JSON files with a name and sounds object.");
434
+ return;
435
+ }
436
+ if (options.list) {
437
+ printPatchList(discovered);
438
+ return;
439
+ }
440
+ const toInstall = selectPatches(discovered, options);
441
+ if (!toInstall || toInstall.length === 0) return;
442
+ const installed = await getInstalledPatches();
443
+ const installedNames = new Set(installed.map((p)=>p.name));
444
+ const final = options.yes ? toInstall : await confirmOverwrites(toInstall, installedNames);
445
+ if (!final || final.length === 0) return;
446
+ const dl = p.spinner();
447
+ dl.start(`Installing ${final.length} patch(es)...`);
448
+ const results = [];
449
+ for (const patch of final){
450
+ try {
451
+ const raw = await readFile(patch.downloadUrl, "utf-8");
452
+ const data = JSON.parse(raw);
453
+ if (!validatePatch(data)) {
454
+ p.log.warn(`Skipping ${patch.name}: invalid patch format`);
455
+ continue;
456
+ }
457
+ await writePatch(patch.name, data);
458
+ results.push(data.name);
459
+ } catch (err) {
460
+ p.log.warn(`Failed to install ${patch.name}: ${err}`);
461
+ }
462
+ }
463
+ dl.stop(`Installed ${results.length} patch(es)`);
464
+ p.note(results.map((n)=>` - ${n}`).join("\n"), "Installed patches");
465
+ p.outro("Done!");
466
+ }
467
+ async function addFromGitHub(source, options) {
468
+ const s = p.spinner();
469
+ s.start("Scanning repository for patches...");
470
+ let discovered;
471
+ try {
472
+ discovered = await discoverPatchesFromGitHub(source);
473
+ s.stop(`Found ${discovered.length} patch(es)`);
474
+ } catch (err) {
475
+ s.stop("Failed to scan repository.");
476
+ p.log.error(String(err));
477
+ process.exit(1);
478
+ }
479
+ if (discovered.length === 0) {
480
+ p.log.warn("No valid sound patches found in this repository.");
481
+ p.outro("Patches must be JSON files with a name and sounds object.");
482
+ return;
483
+ }
484
+ if (options.list) {
485
+ printPatchList(discovered);
486
+ return;
487
+ }
488
+ const installed = await getInstalledPatches();
489
+ const installedNames = new Set(installed.map((p)=>p.name));
490
+ const toInstall = await resolvePatchSelection(discovered, installedNames, options);
491
+ if (!toInstall || toInstall.length === 0) return;
492
+ const dl = p.spinner();
493
+ dl.start(`Installing ${toInstall.length} patch(es)...`);
494
+ const results = [];
495
+ for (const patch of toInstall){
496
+ try {
497
+ const data = await fetchPatchJson(patch.downloadUrl);
498
+ if (!validatePatch(data)) {
499
+ p.log.warn(`Skipping ${patch.name}: invalid patch format`);
500
+ continue;
501
+ }
502
+ await writePatch(patch.name, data);
503
+ registerPatch(patch.downloadUrl);
504
+ results.push(data.name);
505
+ } catch (err) {
506
+ p.log.warn(`Failed to install ${patch.name}: ${err}`);
507
+ }
508
+ }
509
+ dl.stop(`Installed ${results.length} patch(es)`);
510
+ p.note(results.map((n)=>` - ${n}`).join("\n"), "Installed patches");
511
+ p.outro("Done!");
512
+ }
513
+ async function addFromUrl(url, options) {
514
+ const s = p.spinner();
515
+ s.start("Fetching patch...");
516
+ try {
517
+ const data = await fetchPatchJson(url);
518
+ if (!validatePatch(data)) {
519
+ s.stop("Invalid patch format.");
520
+ p.log.error("The fetched JSON is not a valid sound patch (missing name or sounds).");
521
+ process.exit(1);
522
+ }
523
+ s.stop(`Fetched "${data.name}"`);
524
+ if (options.list) {
525
+ console.log(` ${pc.bold(data.name)} ${pc.dim(`${Object.keys(data.sounds).length} sounds`)}`);
526
+ console.log();
527
+ return;
528
+ }
529
+ await writePatch(data.name, data);
530
+ registerPatch(url);
531
+ } catch (err) {
532
+ s.stop("Failed to fetch patch.");
533
+ p.log.error(String(err));
534
+ process.exit(1);
535
+ }
536
+ }
537
+ async function addFromRegistry(options) {
538
+ const s = p.spinner();
539
+ s.start("Fetching available patches...");
540
+ let index;
541
+ try {
542
+ index = await fetchPatchIndex();
543
+ s.stop(`Found ${index.length} patches`);
544
+ } catch (err) {
545
+ s.stop("Failed to fetch patch index.");
546
+ p.log.error(String(err));
547
+ process.exit(1);
548
+ }
549
+ if (options.list) {
550
+ console.log();
551
+ for (const entry of index){
552
+ console.log(` ${pc.bold(entry.name)} ${pc.dim(entry.description)}`);
553
+ }
554
+ console.log();
555
+ return;
556
+ }
557
+ const installed = await getInstalledPatches();
558
+ const installedNames = new Set(installed.map((p)=>p.name));
559
+ let names;
560
+ if (options.patch) {
561
+ const patchName = options.patch;
562
+ names = [
563
+ patchName
564
+ ];
565
+ const match = index.find((e)=>e.name.toLowerCase() === patchName.toLowerCase());
566
+ if (!match) {
567
+ p.log.error(`Patch "${patchName}" not found in registry.`);
568
+ process.exit(1);
569
+ }
570
+ } else if (options.yes) {
571
+ names = index.map((e)=>e.name);
572
+ } else {
573
+ const selected = await p.multiselect({
574
+ message: "Select patches to install",
575
+ options: index.map((entry)=>({
576
+ value: entry.name,
577
+ label: `${entry.name}${installedNames.has(entry.name) ? " (installed)" : ""}`,
578
+ hint: entry.description
579
+ }))
580
+ });
581
+ if (p.isCancel(selected)) {
582
+ p.cancel("Cancelled.");
583
+ process.exit(0);
584
+ }
585
+ names = selected;
586
+ if (names.length === 0) {
587
+ p.outro("No patches selected.");
588
+ return;
589
+ }
590
+ }
591
+ if (!options.yes) {
592
+ const existing = names.filter((n)=>installedNames.has(n));
593
+ if (existing.length > 0) {
594
+ const overwrite = await p.confirm({
595
+ message: `${existing.length} patch(es) already installed. Overwrite?`
596
+ });
597
+ if (p.isCancel(overwrite) || !overwrite) {
598
+ p.cancel("Cancelled.");
599
+ process.exit(0);
600
+ }
601
+ }
602
+ }
603
+ const dl = p.spinner();
604
+ dl.start(`Downloading ${names.length} patch(es)...`);
605
+ const results = [];
606
+ for (const name of names){
607
+ try {
608
+ const data = await fetchPatchJson(name);
609
+ if (!validatePatch(data)) {
610
+ p.log.warn(`Skipping ${name}: invalid patch format`);
611
+ continue;
612
+ }
613
+ await writePatch(name, data);
614
+ results.push(data.name);
615
+ } catch (err) {
616
+ p.log.warn(`Failed to download ${name}: ${err}`);
617
+ }
618
+ }
619
+ dl.stop(`Downloaded ${results.length} patch(es)`);
620
+ p.note(results.map((n)=>` - ${n}`).join("\n"), "Installed patches");
621
+ p.outro("Done!");
622
+ }
623
+ async function addSoundFromRegistry(soundName, options) {
624
+ if (options.list) {
625
+ p.log.error("--list is only available when browsing themes.");
626
+ process.exit(1);
627
+ }
628
+ const s = p.spinner();
629
+ s.start(`Finding "${soundName}"...`);
630
+ let index;
631
+ try {
632
+ index = await fetchPatchIndex();
633
+ } catch (err) {
634
+ s.stop("Failed to fetch theme index.");
635
+ p.log.error(String(err));
636
+ process.exit(1);
637
+ }
638
+ let found;
639
+ for (const entry of index){
640
+ try {
641
+ const data = await fetchPatchJson(entry.name);
642
+ if (!validatePatch(data)) continue;
643
+ const match = Object.entries(data.sounds).find(([name])=>name.toLowerCase() === soundName.toLowerCase());
644
+ if (match) {
645
+ found = {
646
+ theme: data.name,
647
+ definition: match[1]
648
+ };
649
+ break;
650
+ }
651
+ } catch (unused) {}
652
+ }
653
+ if (!found) {
654
+ s.stop(`Sound "${soundName}" not found.`);
655
+ p.log.error("Run `@litlab/audx add` to browse available themes.");
656
+ process.exit(1);
657
+ }
658
+ s.stop(`Found "${soundName}" in ${found.theme}`);
659
+ await writeSound(soundName, found.definition, options);
660
+ p.note(` - ${soundName}`, "Installed sound");
661
+ p.outro("Done!");
662
+ }
663
+ function printPatchList(patches) {
664
+ console.log();
665
+ for (const patch of patches){
666
+ const desc = patch.description ? ` ${pc.dim(patch.description)}` : "";
667
+ console.log(` ${pc.bold(patch.name)} ${pc.dim(`${patch.soundCount} sounds`)}${desc}`);
668
+ }
669
+ console.log();
670
+ }
671
+ function selectPatches(discovered, options) {
672
+ if (options.patch) {
673
+ const patchName = options.patch;
674
+ const match = discovered.filter((d)=>d.name.toLowerCase() === patchName.toLowerCase());
675
+ if (match.length === 0) {
676
+ p.log.error(`Patch "${patchName}" not found.`);
677
+ process.exit(1);
678
+ }
679
+ return match;
680
+ }
681
+ if (options.yes) return discovered;
682
+ return discovered;
683
+ }
684
+ async function resolvePatchSelection(discovered, installedNames, options) {
685
+ if (options.patch) {
686
+ const patchName = options.patch;
687
+ const match = discovered.filter((d)=>d.name.toLowerCase() === patchName.toLowerCase());
688
+ if (match.length === 0) {
689
+ p.log.error(`Patch "${patchName}" not found.`);
690
+ process.exit(1);
691
+ }
692
+ return match;
693
+ }
694
+ if (options.yes) return discovered;
695
+ if (discovered.length === 1) return discovered;
696
+ return await promptPatchSelection(discovered, installedNames);
697
+ }
698
+ async function promptPatchSelection(discovered, installedNames) {
699
+ const selected = await p.multiselect({
700
+ message: "Select patches to install",
701
+ options: discovered.map((patch)=>({
702
+ value: patch.name,
703
+ label: `${patch.name}${installedNames.has(patch.name) ? " (installed)" : ""}`,
704
+ hint: patch.description ? `${patch.soundCount} sounds — ${patch.description}` : `${patch.soundCount} sounds`
705
+ }))
706
+ });
707
+ if (p.isCancel(selected)) {
708
+ p.cancel("Cancelled.");
709
+ process.exit(0);
710
+ }
711
+ const names = new Set(selected);
712
+ return discovered.filter((d)=>names.has(d.name));
713
+ }
714
+ async function confirmOverwrites(patches, installedNames) {
715
+ const existing = patches.filter((patch)=>installedNames.has(patch.name));
716
+ if (existing.length === 0) return patches;
717
+ const overwrite = await p.confirm({
718
+ message: `${existing.length} patch(es) already installed. Overwrite?`
719
+ });
720
+ if (p.isCancel(overwrite) || !overwrite) {
721
+ p.cancel("Cancelled.");
722
+ process.exit(0);
723
+ }
724
+ return patches;
725
+ }
726
+ async function writePatch(filename, data) {
727
+ await ensureConfig("themes");
728
+ const dir = getPatchesDir();
729
+ if (!existsSync(dir)) {
730
+ mkdirSync(dir, {
731
+ recursive: true
732
+ });
733
+ }
734
+ const slug = filename.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
735
+ const moduleSource = generateModule(data);
736
+ const target = join(dir, `${slug}.ts`);
737
+ await writeFile(target, moduleSource, "utf-8");
738
+ await regenerateIndex(dir);
739
+ }
740
+ async function writeSound(name, definition, options) {
741
+ await ensureConfig("setup");
742
+ const dir = getSoundsDir();
743
+ if (!existsSync(dir)) {
744
+ mkdirSync(dir, {
745
+ recursive: true
746
+ });
747
+ }
748
+ const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
749
+ const target = join(dir, `${slug}.ts`);
750
+ if (existsSync(target) && !options.yes) {
751
+ const overwrite = await p.confirm({
752
+ message: `${slug}.ts already exists. Overwrite?`
753
+ });
754
+ if (p.isCancel(overwrite) || !overwrite) {
755
+ p.cancel("Cancelled.");
756
+ process.exit(0);
757
+ }
758
+ }
759
+ await writeFile(target, generateSoundModule(toIdentifier(name), definition), "utf-8");
760
+ }
761
+
762
+ async function check(_args) {
763
+ p.intro("@litlab/audx check");
764
+ const installed = await getInstalledPatches();
765
+ if (installed.length === 0) {
766
+ p.log.warn("No patches installed.");
767
+ p.outro("Install patches with npx @litlab/audx add");
768
+ return;
769
+ }
770
+ const s = p.spinner();
771
+ s.start("Checking for updates...");
772
+ let registry;
773
+ try {
774
+ registry = await fetchPatchIndex();
775
+ s.stop(`Checked ${registry.length} registry patch(es)`);
776
+ } catch (err) {
777
+ s.stop("Failed to fetch registry.");
778
+ p.log.error(String(err));
779
+ process.exit(1);
780
+ }
781
+ const registryMap = new Map(registry.map((e)=>[
782
+ e.name.toLowerCase(),
783
+ e
784
+ ]));
785
+ const available = [];
786
+ const notInRegistry = [];
787
+ for (const entry of installed){
788
+ const regEntry = registryMap.get(entry.name.toLowerCase());
789
+ if (regEntry) {
790
+ available.push(entry.name);
791
+ } else {
792
+ notInRegistry.push(entry.name);
793
+ }
794
+ }
795
+ if (available.length === 0) {
796
+ p.log.warn("No installed patches found in the registry.");
797
+ p.outro("");
798
+ return;
799
+ }
800
+ p.note(available.map((name)=>` ↑ ${name}`).join("\n"), `${available.length} patch(es) available`);
801
+ if (notInRegistry.length > 0) {
802
+ p.log.warn([
803
+ `${notInRegistry.length} patch(es) not found in registry:`,
804
+ ...notInRegistry.map((name)=>` • ${name}`)
805
+ ].join("\n"));
806
+ }
807
+ p.outro("Run npx @litlab/audx update to re-download latest versions");
808
+ }
809
+
810
+ async function find(args) {
811
+ const query = args.join(" ").toLowerCase();
812
+ p.intro("@litlab/audx find");
813
+ const s = p.spinner();
814
+ s.start("Fetching registry...");
815
+ let index;
816
+ try {
817
+ index = await fetchPatchIndex();
818
+ s.stop(`Found ${index.length} patch(es) in registry`);
819
+ } catch (err) {
820
+ s.stop("Failed to fetch registry.");
821
+ p.log.error(String(err));
822
+ process.exit(1);
823
+ }
824
+ if (index.length === 0) {
825
+ p.log.warn("No patches available in the registry.");
826
+ p.outro("");
827
+ return;
828
+ }
829
+ const matches = query ? index.filter((entry)=>{
830
+ var _entry_tags;
831
+ const haystack = `${entry.name} ${entry.description} ${((_entry_tags = entry.tags) != null ? _entry_tags : []).join(" ")}`.toLowerCase();
832
+ return haystack.includes(query);
833
+ }) : index;
834
+ if (matches.length === 0) {
835
+ p.log.warn(`No patches found for "${query}"`);
836
+ p.outro("");
837
+ return;
838
+ }
839
+ p.log.info("Install with npx @litlab/audx add --patch <name>");
840
+ for (const entry of matches){
841
+ const tags = entry.tags && entry.tags.length > 0 ? ` ${entry.tags.join(", ")}` : "";
842
+ const desc = entry.description ? `\n ${entry.description}` : "";
843
+ p.log.step(`${entry.name}${tags}${desc}`);
844
+ }
845
+ p.outro(`${matches.length} result(s)`);
846
+ }
847
+
848
+ async function init(args) {
849
+ if (args[0] === "theme") {
850
+ await themeInit(args.slice(1));
851
+ return;
852
+ }
853
+ p.intro("@litlab/audx init");
854
+ await ensureConfig();
855
+ await add([]);
856
+ }
857
+ async function themeInit(_args) {
858
+ p.intro("@litlab/audx theme init");
859
+ const name = await p.text({
860
+ message: "Patch name",
861
+ placeholder: "my-patch",
862
+ validate: (v)=>v.length === 0 ? "Name is required" : undefined
863
+ });
864
+ if (p.isCancel(name)) {
865
+ p.cancel("Cancelled.");
866
+ process.exit(0);
867
+ }
868
+ const author = await p.text({
869
+ message: "Author",
870
+ placeholder: "Your name"
871
+ });
872
+ if (p.isCancel(author)) {
873
+ p.cancel("Cancelled.");
874
+ process.exit(0);
875
+ }
876
+ const description = await p.text({
877
+ message: "Description",
878
+ placeholder: "What does this patch sound like?"
879
+ });
880
+ if (p.isCancel(description)) {
881
+ p.cancel("Cancelled.");
882
+ process.exit(0);
883
+ }
884
+ const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
885
+ const filename = `${slug}.json`;
886
+ const dir = resolve(process.cwd(), ".audx", "themes");
887
+ if (!existsSync(dir)) {
888
+ mkdirSync(dir, {
889
+ recursive: true
890
+ });
891
+ }
892
+ const target = resolve(dir, filename);
893
+ if (existsSync(target)) {
894
+ const overwrite = await p.confirm({
895
+ message: `${filename} already exists. Overwrite?`
896
+ });
897
+ if (p.isCancel(overwrite) || !overwrite) {
898
+ p.cancel("Cancelled.");
899
+ process.exit(0);
900
+ }
901
+ }
902
+ const patch = {
903
+ $schema: "../../node_modules/@litlab/audx/schemas/patch.schema.json",
904
+ name: name,
905
+ author: author || undefined,
906
+ version: "1.0.0",
907
+ description: description || undefined,
908
+ tags: [],
909
+ sounds: {}
910
+ };
911
+ await writeFile(target, `${JSON.stringify(patch, null, 2)}\n`, "utf-8");
912
+ p.log.success(`Created .audx/themes/${filename}`);
913
+ p.outro("Add sounds to the `sounds` object to get started.");
914
+ }
915
+
916
+ async function list(_args) {
917
+ p.intro("@litlab/audx list");
918
+ const patches = await getInstalledPatches();
919
+ if (patches.length === 0) {
920
+ p.log.warn(`No patches found in ${getPatchesDir()}`);
921
+ p.outro("Run `@litlab/audx add` to install patches.");
922
+ return;
923
+ }
924
+ const rows = patches.map((patch)=>{
925
+ var _patch_description;
926
+ return ` ${patch.name.padEnd(16)} ${String(patch.soundCount).padStart(3)} sounds ${(_patch_description = patch.description) != null ? _patch_description : ""}`;
927
+ });
928
+ p.note(rows.join("\n"), `${patches.length} patch(es) installed`);
929
+ p.outro(getPatchesDir());
930
+ }
931
+
932
+ function parseRemoveOptions(args) {
933
+ const options = {};
934
+ const patches = [];
935
+ for(let i = 0; i < args.length; i++){
936
+ const arg = args[i];
937
+ if (arg === "-y" || arg === "--yes") {
938
+ options.yes = true;
939
+ } else if (arg && !arg.startsWith("-")) {
940
+ patches.push(arg);
941
+ }
942
+ }
943
+ return {
944
+ patches,
945
+ options
946
+ };
947
+ }
948
+ async function remove(args) {
949
+ const { patches: patchNames, options } = parseRemoveOptions(args);
950
+ p.intro("@litlab/audx remove");
951
+ const patches = await getInstalledPatches();
952
+ if (patches.length === 0) {
953
+ p.log.warn("No patches installed.");
954
+ p.outro("Nothing to remove.");
955
+ return;
956
+ }
957
+ let files;
958
+ if (patchNames.length > 0) {
959
+ const matched = patches.filter((pk)=>patchNames.some((n)=>n.toLowerCase() === pk.name.toLowerCase()));
960
+ if (matched.length === 0) {
961
+ p.log.error(`No matching patches found for: ${patchNames.join(", ")}`);
962
+ return;
963
+ }
964
+ files = matched.map((pk)=>pk.file);
965
+ } else {
966
+ const selected = await p.multiselect({
967
+ message: "Select patches to remove",
968
+ options: patches.map((pk)=>({
969
+ value: pk.file,
970
+ label: pk.name,
971
+ hint: `${pk.soundCount} sounds`
972
+ }))
973
+ });
974
+ if (p.isCancel(selected)) {
975
+ p.cancel("Cancelled.");
976
+ process.exit(0);
977
+ }
978
+ files = selected;
979
+ if (files.length === 0) {
980
+ p.outro("No patches selected.");
981
+ return;
982
+ }
983
+ }
984
+ if (!options.yes) {
985
+ const confirmed = await p.confirm({
986
+ message: `Remove ${files.length} patch(es)?`
987
+ });
988
+ if (p.isCancel(confirmed) || !confirmed) {
989
+ p.cancel("Cancelled.");
990
+ process.exit(0);
991
+ }
992
+ }
993
+ const dir = getPatchesDir();
994
+ const removed = [];
995
+ for (const file of files){
996
+ try {
997
+ var _ref;
998
+ await unlink(join(dir, file));
999
+ const pk = patches.find((item)=>item.file === file);
1000
+ removed.push((_ref = pk == null ? void 0 : pk.name) != null ? _ref : file);
1001
+ } catch (err) {
1002
+ p.log.warn(`Failed to remove ${file}: ${err}`);
1003
+ }
1004
+ }
1005
+ await regenerateIndex(dir);
1006
+ p.note(removed.map((n)=>` - ${n}`).join("\n"), "Removed patches");
1007
+ p.outro("Done!");
1008
+ }
1009
+
1010
+ async function update(_args) {
1011
+ p.intro("@litlab/audx update");
1012
+ const installed = await getInstalledPatches();
1013
+ if (installed.length === 0) {
1014
+ p.log.warn("No patches installed.");
1015
+ p.outro("Install patches with npx @litlab/audx add");
1016
+ return;
1017
+ }
1018
+ const s = p.spinner();
1019
+ s.start("Fetching registry...");
1020
+ let registry;
1021
+ try {
1022
+ registry = await fetchPatchIndex();
1023
+ s.stop(`Found ${registry.length} registry patch(es)`);
1024
+ } catch (err) {
1025
+ s.stop("Failed to fetch registry.");
1026
+ p.log.error(String(err));
1027
+ process.exit(1);
1028
+ }
1029
+ const registryMap = new Map(registry.map((e)=>[
1030
+ e.name.toLowerCase(),
1031
+ e
1032
+ ]));
1033
+ const toUpdate = installed.filter((pk)=>registryMap.has(pk.name.toLowerCase()));
1034
+ if (toUpdate.length === 0) {
1035
+ p.log.warn("No installed patches found in the registry.");
1036
+ p.outro("");
1037
+ return;
1038
+ }
1039
+ const dl = p.spinner();
1040
+ dl.start(`Updating ${toUpdate.length} patch(es)...`);
1041
+ let successCount = 0;
1042
+ let failCount = 0;
1043
+ const dir = getPatchesDir();
1044
+ if (!existsSync(dir)) {
1045
+ mkdirSync(dir, {
1046
+ recursive: true
1047
+ });
1048
+ }
1049
+ for (const entry of toUpdate){
1050
+ try {
1051
+ const data = await fetchPatchJson(entry.name);
1052
+ if (!validatePatch(data)) {
1053
+ failCount++;
1054
+ continue;
1055
+ }
1056
+ const slug = entry.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
1057
+ const moduleSource = generateModule(data);
1058
+ const target = join(dir, `${slug}.ts`);
1059
+ await writeFile(target, moduleSource, "utf-8");
1060
+ successCount++;
1061
+ } catch (unused) {
1062
+ failCount++;
1063
+ }
1064
+ }
1065
+ await regenerateIndex(dir);
1066
+ dl.stop(`Updated ${successCount} patch(es)`);
1067
+ if (failCount > 0) {
1068
+ p.log.warn(`Failed to update ${failCount} patch(es)`);
1069
+ }
1070
+ p.outro("Done!");
1071
+ }
1072
+
1073
+ const __filename$1 = __node_cjsUrl.fileURLToPath(import.meta.url);
1074
+ __node_cjsPath.dirname(__filename$1);
1075
+
1076
+ const COMMANDS = {
1077
+ add,
1078
+ a: add,
1079
+ find,
1080
+ search: find,
1081
+ f: find,
1082
+ s: find,
1083
+ list,
1084
+ ls: list,
1085
+ remove,
1086
+ rm: remove,
1087
+ check,
1088
+ update,
1089
+ upgrade: update,
1090
+ init,
1091
+ theme: async (args)=>{
1092
+ if (args[0] !== "init") {
1093
+ var _args_;
1094
+ p.log.error(`Unknown theme command: ${(_args_ = args[0]) != null ? _args_ : ""}`);
1095
+ p.log.message("Run @litlab/audx theme init to create a new theme.");
1096
+ process.exit(1);
1097
+ }
1098
+ await themeInit(args.slice(1));
1099
+ }
1100
+ };
1101
+ function showBanner() {
1102
+ p.intro("@litlab/audx");
1103
+ p.log.message("Manage sound patches for your project.");
1104
+ p.log.message([
1105
+ "Patches",
1106
+ " add [sound] Install an individual sound",
1107
+ " add Browse and install themes",
1108
+ " find [query] Search for patches",
1109
+ " list List installed patches",
1110
+ " remove Remove installed patches"
1111
+ ].join("\n"));
1112
+ p.log.message([
1113
+ "Updates",
1114
+ " check Check for updates",
1115
+ " update Update installed patches"
1116
+ ].join("\n"));
1117
+ p.log.message([
1118
+ "Project",
1119
+ " init Set up AudX and install themes",
1120
+ " theme init Create a new local theme JSON"
1121
+ ].join("\n"));
1122
+ p.outro("try: npx @litlab/audx add ommgh/audio");
1123
+ }
1124
+ function showHelp() {
1125
+ p.intro("@litlab/audx");
1126
+ p.log.message([
1127
+ "Usage: @litlab/audx <command> [options]",
1128
+ "",
1129
+ "Manage Patches:",
1130
+ " add [sound] Install an individual sound",
1131
+ " add Browse and install themes",
1132
+ " add <source> Install themes from a source",
1133
+ " find [query] Search for patches in the registry",
1134
+ " list, ls List installed patches",
1135
+ " remove, rm Remove installed patches",
1136
+ "",
1137
+ "Updates:",
1138
+ " check Check for available updates",
1139
+ " update Update all installed patches",
1140
+ "",
1141
+ "Project:",
1142
+ " init Set up AudX and install themes",
1143
+ " theme init Create a new local theme JSON"
1144
+ ].join("\n"));
1145
+ p.log.message([
1146
+ "Add Options:",
1147
+ " -l, --list Preview available patches without installing",
1148
+ " -y, --yes Skip confirmation prompts",
1149
+ " --patch <name> Install a specific patch by name",
1150
+ "",
1151
+ "Remove Options:",
1152
+ " -y, --yes Skip confirmation prompts"
1153
+ ].join("\n"));
1154
+ p.log.message([
1155
+ "Source Formats:",
1156
+ " ./local/path Local file or directory",
1157
+ " owner/repo GitHub shorthand",
1158
+ " https://github.com/user/repo Full GitHub URL",
1159
+ " https://...patch.json Direct URL to a patch file",
1160
+ " (no argument) Browse the registry"
1161
+ ].join("\n"));
1162
+ p.log.message([
1163
+ "Options:",
1164
+ " --help, -h Show this help message",
1165
+ " --version, -v Show version number"
1166
+ ].join("\n"));
1167
+ p.note([
1168
+ " @litlab/audx add ommgh/audio",
1169
+ " @litlab/audx add ./.themes/",
1170
+ " @litlab/audx add ommgh/audio --list",
1171
+ " @litlab/audx add --patch core -y",
1172
+ " @litlab/audx remove core -y",
1173
+ " @litlab/audx find ambient",
1174
+ " @litlab/audx check",
1175
+ " @litlab/audx update"
1176
+ ].join("\n"), "Examples");
1177
+ p.outro("");
1178
+ }
1179
+ async function run() {
1180
+ const args = process.argv.slice(2);
1181
+ const command = args[0];
1182
+ if (!command) {
1183
+ showBanner();
1184
+ return;
1185
+ }
1186
+ if (command === "--help" || command === "-h") {
1187
+ showHelp();
1188
+ return;
1189
+ }
1190
+ if (command === "--version" || command === "-v") {
1191
+ try {
1192
+ const { readFileSync } = await import('node:fs');
1193
+ const { join, dirname } = await import('node:path');
1194
+ const { fileURLToPath } = await import('node:url');
1195
+ const __dirname = dirname(fileURLToPath(import.meta.url));
1196
+ const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
1197
+ console.log(pkg.version);
1198
+ } catch (unused) {
1199
+ console.log("0.0.0");
1200
+ }
1201
+ return;
1202
+ }
1203
+ const handler = COMMANDS[command];
1204
+ if (!handler) {
1205
+ p.log.error(`Unknown command: ${command}`);
1206
+ p.log.message("Run @litlab/audx --help for usage information.");
1207
+ process.exit(1);
1208
+ }
1209
+ await handler(args.slice(1));
1210
+ }
1211
+
1212
+ run();