@litlab/audx 0.0.1

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 (74) hide show
  1. package/README.md +86 -0
  2. package/dist/codegen/theme-codegen.d.ts +12 -0
  3. package/dist/codegen/theme-codegen.d.ts.map +1 -0
  4. package/dist/codegen/theme-codegen.js +153 -0
  5. package/dist/codegen/theme-codegen.js.map +1 -0
  6. package/dist/commands/add.d.ts +2 -0
  7. package/dist/commands/add.d.ts.map +1 -0
  8. package/dist/commands/add.js +120 -0
  9. package/dist/commands/add.js.map +1 -0
  10. package/dist/commands/diff.d.ts +2 -0
  11. package/dist/commands/diff.d.ts.map +1 -0
  12. package/dist/commands/diff.js +103 -0
  13. package/dist/commands/diff.js.map +1 -0
  14. package/dist/commands/generate.d.ts +12 -0
  15. package/dist/commands/generate.d.ts.map +1 -0
  16. package/dist/commands/generate.js +96 -0
  17. package/dist/commands/generate.js.map +1 -0
  18. package/dist/commands/init.d.ts +2 -0
  19. package/dist/commands/init.d.ts.map +1 -0
  20. package/dist/commands/init.js +79 -0
  21. package/dist/commands/init.js.map +1 -0
  22. package/dist/commands/list.d.ts +14 -0
  23. package/dist/commands/list.d.ts.map +1 -0
  24. package/dist/commands/list.js +93 -0
  25. package/dist/commands/list.js.map +1 -0
  26. package/dist/commands/remove.d.ts +2 -0
  27. package/dist/commands/remove.d.ts.map +1 -0
  28. package/dist/commands/remove.js +71 -0
  29. package/dist/commands/remove.js.map +1 -0
  30. package/dist/commands/theme.d.ts +31 -0
  31. package/dist/commands/theme.d.ts.map +1 -0
  32. package/dist/commands/theme.js +142 -0
  33. package/dist/commands/theme.js.map +1 -0
  34. package/dist/commands/update.d.ts +2 -0
  35. package/dist/commands/update.d.ts.map +1 -0
  36. package/dist/commands/update.js +123 -0
  37. package/dist/commands/update.js.map +1 -0
  38. package/dist/core/alias-resolver.d.ts +24 -0
  39. package/dist/core/alias-resolver.d.ts.map +1 -0
  40. package/dist/core/alias-resolver.js +87 -0
  41. package/dist/core/alias-resolver.js.map +1 -0
  42. package/dist/core/config.d.ts +21 -0
  43. package/dist/core/config.d.ts.map +1 -0
  44. package/dist/core/config.js +43 -0
  45. package/dist/core/config.js.map +1 -0
  46. package/dist/core/file-writer.d.ts +14 -0
  47. package/dist/core/file-writer.d.ts.map +1 -0
  48. package/dist/core/file-writer.js +90 -0
  49. package/dist/core/file-writer.js.map +1 -0
  50. package/dist/core/package-manager.d.ts +3 -0
  51. package/dist/core/package-manager.d.ts.map +1 -0
  52. package/dist/core/package-manager.js +17 -0
  53. package/dist/core/package-manager.js.map +1 -0
  54. package/dist/core/registry.d.ts +18 -0
  55. package/dist/core/registry.d.ts.map +1 -0
  56. package/dist/core/registry.js +69 -0
  57. package/dist/core/registry.js.map +1 -0
  58. package/dist/core/theme-manager.d.ts +35 -0
  59. package/dist/core/theme-manager.d.ts.map +1 -0
  60. package/dist/core/theme-manager.js +94 -0
  61. package/dist/core/theme-manager.js.map +1 -0
  62. package/dist/core/utils.d.ts +22 -0
  63. package/dist/core/utils.d.ts.map +1 -0
  64. package/dist/core/utils.js +44 -0
  65. package/dist/core/utils.js.map +1 -0
  66. package/dist/index.d.ts +3 -0
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +126 -0
  69. package/dist/index.js.map +1 -0
  70. package/dist/types.d.ts +116 -0
  71. package/dist/types.d.ts.map +1 -0
  72. package/dist/types.js +43 -0
  73. package/dist/types.js.map +1 -0
  74. package/package.json +54 -0
package/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # audx
2
+
3
+ CLI tool for distributing and managing UI sounds from the [audx](https://audx.dev) registry.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g audx
9
+ ```
10
+
11
+ Or use directly with `npx`:
12
+
13
+ ```bash
14
+ npx audx <command>
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ ```bash
20
+ # Initialize audx in your project
21
+ audx init
22
+
23
+ # Browse available sounds
24
+ audx list
25
+
26
+ # Add a sound
27
+ audx add click-001
28
+
29
+ # Set up themes
30
+ audx theme init
31
+ audx theme map click click-001
32
+ audx theme generate
33
+ ```
34
+
35
+ ## Commands
36
+
37
+ | Command | Description |
38
+ |---|---|
39
+ | `audx init` | Initialize audx config in your project |
40
+ | `audx add <sounds...>` | Add sounds from the registry |
41
+ | `audx remove <sounds...>` | Remove installed sounds |
42
+ | `audx list` | List available sounds (`--tag`, `--search`) |
43
+ | `audx diff` | Check for updates to installed sounds |
44
+ | `audx update [sound]` | Update installed sounds from registry |
45
+ | `audx generate "<prompt>"` | Generate a sound from a text prompt (`--name`, `--duration`) |
46
+ | `audx theme init` | Create theme configuration |
47
+ | `audx theme set <name>` | Switch active theme |
48
+ | `audx theme map <semantic> <sound>` | Map a semantic name to a sound |
49
+ | `audx theme create <name>` | Create a new theme |
50
+ | `audx theme list` | List all themes |
51
+ | `audx theme generate` | Generate `sound-theme.ts` |
52
+
53
+ ## How It Works
54
+
55
+ audx manages UI sounds as TypeScript modules with base64-encoded audio data — no external files to serve. Sounds are fetched from the audx registry and written directly into your project.
56
+
57
+ The theme system lets you reference sounds by semantic purpose (`play("success")`) instead of file names, and swap entire sound palettes by switching themes.
58
+
59
+ ## Configuration
60
+
61
+ Running `audx init` creates `audx.config.json`:
62
+
63
+ ```json
64
+ {
65
+ "soundDir": "src/sounds",
66
+ "libDir": "src/lib",
67
+ "registryUrl": "https://audx.dev",
68
+ "packageManager": "pnpm",
69
+ "aliases": {
70
+ "lib": "@/lib",
71
+ "hooks": "@/hooks",
72
+ "sounds": "@/sounds"
73
+ },
74
+ "installedSounds": {}
75
+ }
76
+ ```
77
+
78
+ Path aliases are auto-detected from your `tsconfig.json`.
79
+
80
+ ## Requirements
81
+
82
+ - Node.js 18+
83
+
84
+ ## License
85
+
86
+ MIT
@@ -0,0 +1,12 @@
1
+ import type { AliasMap, AudxConfig, ThemeConfig } from "../types.js";
2
+ /**
3
+ * Generate the `sound-theme.ts` TypeScript source from a theme configuration.
4
+ *
5
+ * The generated file exports:
6
+ * - `SemanticSoundName` — union type of all semantic names present in the themes
7
+ * - `soundThemes` — object mapping theme names to their sound mappings
8
+ * - `play(name)` — plays the mapped sound in the active theme (no-ops for null)
9
+ * - `setSoundTheme(themeName)` — switches the active theme at runtime
10
+ */
11
+ export declare function generate(themeConfig: ThemeConfig, aliasMap: AliasMap, config: AudxConfig): string;
12
+ //# sourceMappingURL=theme-codegen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-codegen.d.ts","sourceRoot":"","sources":["../../src/codegen/theme-codegen.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAErE;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CACvB,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,UAAU,GAChB,MAAM,CAuER"}
@@ -0,0 +1,153 @@
1
+ import { resolveImport } from "../core/alias-resolver.js";
2
+ /**
3
+ * Generate the `sound-theme.ts` TypeScript source from a theme configuration.
4
+ *
5
+ * The generated file exports:
6
+ * - `SemanticSoundName` — union type of all semantic names present in the themes
7
+ * - `soundThemes` — object mapping theme names to their sound mappings
8
+ * - `play(name)` — plays the mapped sound in the active theme (no-ops for null)
9
+ * - `setSoundTheme(themeName)` — switches the active theme at runtime
10
+ */
11
+ export function generate(themeConfig, aliasMap, config) {
12
+ // The generated file lives in libDir (e.g. "src/lib/sound-theme.ts")
13
+ const generatedFilePath = `${config.libDir}/sound-theme.ts`;
14
+ // Collect all unique semantic names across all themes
15
+ const semanticNames = collectSemanticNames(themeConfig);
16
+ // Collect all unique non-null sound file paths across all themes
17
+ const soundPaths = collectSoundPaths(themeConfig);
18
+ // Build import statements for each sound module
19
+ const imports = buildImports(soundPaths, generatedFilePath, aliasMap);
20
+ // Resolve the audio-engine import path
21
+ const audioEngineImport = resolveImport(aliasMap, generatedFilePath, `${config.libDir}/audio-engine.ts`);
22
+ const lines = [];
23
+ // File header
24
+ lines.push("// This file is auto-generated by audx. Do not edit manually.");
25
+ lines.push("");
26
+ // Audio engine import
27
+ lines.push(`import { playAudio } from "${audioEngineImport}";`);
28
+ // Sound module imports
29
+ for (const { importName, importPath } of imports) {
30
+ lines.push(`import { default as ${importName} } from "${importPath}";`);
31
+ }
32
+ lines.push("");
33
+ // SemanticSoundName type union
34
+ lines.push(buildSemanticSoundNameType(semanticNames));
35
+ lines.push("");
36
+ // soundThemes object
37
+ lines.push(buildSoundThemesObject(themeConfig, soundPaths, generatedFilePath, aliasMap));
38
+ lines.push("");
39
+ // Runtime state
40
+ lines.push(`let activeTheme = "${themeConfig.activeTheme}";`);
41
+ lines.push("");
42
+ // setSoundTheme function
43
+ lines.push("export function setSoundTheme(themeName: string): void {");
44
+ lines.push(" activeTheme = themeName;");
45
+ lines.push("}");
46
+ lines.push("");
47
+ // play function
48
+ lines.push("export function play(name: SemanticSoundName): void {");
49
+ lines.push(" const theme = soundThemes[activeTheme];");
50
+ lines.push(" if (!theme) return;");
51
+ lines.push(" const asset = theme[name];");
52
+ lines.push(" if (!asset) return;");
53
+ lines.push(" playAudio(asset.dataUri);");
54
+ lines.push("}");
55
+ lines.push("");
56
+ return lines.join("\n");
57
+ }
58
+ /**
59
+ * Collect all unique semantic names across all themes.
60
+ */
61
+ function collectSemanticNames(themeConfig) {
62
+ const names = new Set();
63
+ for (const mappings of Object.values(themeConfig.themes)) {
64
+ for (const key of Object.keys(mappings)) {
65
+ names.add(key);
66
+ }
67
+ }
68
+ return Array.from(names).sort();
69
+ }
70
+ /**
71
+ * Collect all unique non-null sound file paths across all themes.
72
+ */
73
+ function collectSoundPaths(themeConfig) {
74
+ const paths = new Set();
75
+ for (const mappings of Object.values(themeConfig.themes)) {
76
+ for (const value of Object.values(mappings)) {
77
+ if (value !== null) {
78
+ paths.add(value);
79
+ }
80
+ }
81
+ }
82
+ return Array.from(paths).sort();
83
+ }
84
+ /**
85
+ * Derive a safe import variable name from a sound file path.
86
+ * e.g. "src/sounds/click-001.ts" → "click001Sound"
87
+ */
88
+ function deriveImportName(soundPath) {
89
+ const fileName = soundPath.split("/").pop() ?? soundPath;
90
+ const baseName = fileName.replace(/\.(tsx?|jsx?|mjs|cjs)$/, "");
91
+ // Convert kebab-case to camelCase and append "Sound"
92
+ const camel = baseName
93
+ .split("-")
94
+ .map((part, i) => i === 0
95
+ ? part.toLowerCase()
96
+ : part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())
97
+ .join("");
98
+ return `${camel}Sound`;
99
+ }
100
+ /**
101
+ * Build import statements for all sound modules.
102
+ */
103
+ function buildImports(soundPaths, generatedFilePath, aliasMap) {
104
+ return soundPaths.map((soundPath) => {
105
+ const importPath = resolveImport(aliasMap, generatedFilePath, soundPath);
106
+ const importName = deriveImportName(soundPath);
107
+ return { importName, importPath, originalPath: soundPath };
108
+ });
109
+ }
110
+ /**
111
+ * Build the `SemanticSoundName` type union string.
112
+ */
113
+ function buildSemanticSoundNameType(semanticNames) {
114
+ if (semanticNames.length === 0) {
115
+ return "export type SemanticSoundName = never;";
116
+ }
117
+ const members = semanticNames.map((n) => `"${n}"`).join(" | ");
118
+ return `export type SemanticSoundName = ${members};`;
119
+ }
120
+ /**
121
+ * Build the `soundThemes` object source code.
122
+ */
123
+ function buildSoundThemesObject(themeConfig, soundPaths, generatedFilePath, aliasMap) {
124
+ // Build a lookup from original path → import variable name
125
+ const pathToImportName = new Map();
126
+ for (const soundPath of soundPaths) {
127
+ pathToImportName.set(soundPath, deriveImportName(soundPath));
128
+ }
129
+ const lines = [];
130
+ lines.push("export const soundThemes: Record<string, Record<SemanticSoundName, { dataUri: string } | null>> = {");
131
+ for (const [themeName, mappings] of Object.entries(themeConfig.themes)) {
132
+ lines.push(` "${themeName}": {`);
133
+ const sortedEntries = Object.entries(mappings).sort(([a], [b]) => a.localeCompare(b));
134
+ for (const [semanticName, soundPath] of sortedEntries) {
135
+ if (soundPath === null) {
136
+ lines.push(` "${semanticName}": null,`);
137
+ }
138
+ else {
139
+ const importName = pathToImportName.get(soundPath);
140
+ if (importName) {
141
+ lines.push(` "${semanticName}": ${importName},`);
142
+ }
143
+ else {
144
+ lines.push(` "${semanticName}": null,`);
145
+ }
146
+ }
147
+ }
148
+ lines.push(" },");
149
+ }
150
+ lines.push("};");
151
+ return lines.join("\n");
152
+ }
153
+ //# sourceMappingURL=theme-codegen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-codegen.js","sourceRoot":"","sources":["../../src/codegen/theme-codegen.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function addCommand(sounds: string[], projectRoot: string): Promise<void>;
2
+ //# sourceMappingURL=add.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAiEA,wBAAsB,UAAU,CAC/B,MAAM,EAAE,MAAM,EAAE,EAChB,WAAW,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAwEf"}
@@ -0,0 +1,120 @@
1
+ import { existsSync } from "node:fs";
2
+ import { basename, dirname, join } from "node:path";
3
+ import { createInterface } from "node:readline";
4
+ import { loadFromTsConfig } from "../core/alias-resolver.js";
5
+ import * as ConfigManager from "../core/config.js";
6
+ import { writeRegistryFile } from "../core/file-writer.js";
7
+ import { fetchItem } from "../core/registry.js";
8
+ /**
9
+ * Prompt the user with a yes/no question via stdin/stdout.
10
+ * Returns `true` when the user answers y/yes (case-insensitive).
11
+ */
12
+ function confirm(question) {
13
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
14
+ return new Promise((resolve) => {
15
+ rl.question(question, (answer) => {
16
+ rl.close();
17
+ resolve(/^y(es)?$/i.test(answer.trim()));
18
+ });
19
+ });
20
+ }
21
+ /**
22
+ * Check whether a registry file would conflict with an existing file on disk.
23
+ * Returns the resolved target path if a conflict exists, otherwise null.
24
+ */
25
+ function getConflictPath(file, targetDir, config) {
26
+ const fileName = basename(file.path);
27
+ let targetPath;
28
+ if (file.type === "registry:hook") {
29
+ const hooksDir = join(dirname(config.libDir), "hooks");
30
+ targetPath = join(hooksDir, fileName);
31
+ }
32
+ else if (file.type === "registry:lib") {
33
+ const normalised = file.path.replace(/\\/g, "/");
34
+ if (normalised.includes("/sounds/")) {
35
+ targetPath = join(targetDir, fileName);
36
+ }
37
+ else {
38
+ targetPath = join(config.libDir, fileName);
39
+ }
40
+ }
41
+ else {
42
+ targetPath = join(targetDir, fileName);
43
+ }
44
+ return existsSync(targetPath) ? targetPath : null;
45
+ }
46
+ /**
47
+ * Determine whether a registry file is a shared dependency (lib or hook)
48
+ * rather than the primary sound module.
49
+ */
50
+ function isDependencyFile(file) {
51
+ if (file.type === "registry:hook")
52
+ return true;
53
+ if (file.type === "registry:lib") {
54
+ const normalised = file.path.replace(/\\/g, "/");
55
+ return !normalised.includes("/sounds/");
56
+ }
57
+ return false;
58
+ }
59
+ export async function addCommand(sounds, projectRoot) {
60
+ // Requirement 3.8 — config must exist
61
+ if (!ConfigManager.exists(projectRoot)) {
62
+ console.error("Configuration not found. Run 'audx init' first.");
63
+ process.exit(1);
64
+ }
65
+ const config = ConfigManager.read(projectRoot);
66
+ const aliasMap = loadFromTsConfig(projectRoot);
67
+ const updatedConfig = {
68
+ ...config,
69
+ installedSounds: { ...config.installedSounds },
70
+ };
71
+ for (const soundName of sounds) {
72
+ try {
73
+ // Requirement 3.1 — fetch registry item
74
+ const item = await fetchItem(config.registryUrl, soundName);
75
+ const targetDir = join(projectRoot, config.soundDir);
76
+ const writtenFiles = [];
77
+ for (const file of item.files) {
78
+ // Requirement 3.5 — skip dependency files that already exist
79
+ if (isDependencyFile(file)) {
80
+ const conflictPath = getConflictPath(file, targetDir, config);
81
+ if (conflictPath) {
82
+ writtenFiles.push(conflictPath);
83
+ continue;
84
+ }
85
+ }
86
+ else {
87
+ // Requirement 3.9 — prompt on file conflicts for non-dependency files
88
+ const conflictPath = getConflictPath(file, targetDir, config);
89
+ if (conflictPath) {
90
+ const overwrite = await confirm(`File '${conflictPath}' already exists. Overwrite? (y/N) `);
91
+ if (!overwrite) {
92
+ console.log(` Skipped ${conflictPath}`);
93
+ continue;
94
+ }
95
+ }
96
+ }
97
+ // Requirement 3.2, 3.3 — write file with import rewriting
98
+ const writtenPath = writeRegistryFile(file, targetDir, aliasMap, config);
99
+ if (writtenPath) {
100
+ writtenFiles.push(writtenPath);
101
+ }
102
+ }
103
+ // Requirement 3.6 — update installedSounds in config
104
+ updatedConfig.installedSounds[soundName] = {
105
+ files: writtenFiles,
106
+ installedAt: new Date().toISOString(),
107
+ };
108
+ console.log(`✔ Added ${soundName}`);
109
+ }
110
+ catch (error) {
111
+ // Requirement 3.7 — handle HTTP errors with sound name and status code
112
+ const message = error instanceof Error ? error.message : String(error);
113
+ console.error(`✘ ${message}`);
114
+ process.exit(2);
115
+ }
116
+ }
117
+ // Write updated config once after all sounds are processed
118
+ ConfigManager.write(projectRoot, updatedConfig);
119
+ }
120
+ //# sourceMappingURL=add.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function diffCommand(projectRoot: string): Promise<void>;
2
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/commands/diff.ts"],"names":[],"mappings":"AA+EA,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA2CpE"}
@@ -0,0 +1,103 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { basename, dirname, join } from "node:path";
3
+ import * as ConfigManager from "../core/config.js";
4
+ import { fetchItem } from "../core/registry.js";
5
+ /**
6
+ * Resolve the expected local file path for a registry file based on its type
7
+ * and the project config.
8
+ */
9
+ function resolveLocalPath(file, config, projectRoot) {
10
+ const fileName = basename(file.path);
11
+ if (file.type === "registry:hook") {
12
+ const hooksDir = join(dirname(config.libDir), "hooks");
13
+ return join(projectRoot, hooksDir, fileName);
14
+ }
15
+ if (file.type === "registry:lib") {
16
+ const normalised = file.path.replace(/\\/g, "/");
17
+ if (normalised.includes("/sounds/")) {
18
+ return join(projectRoot, config.soundDir, fileName);
19
+ }
20
+ return join(projectRoot, config.libDir, fileName);
21
+ }
22
+ return join(projectRoot, config.soundDir, fileName);
23
+ }
24
+ /**
25
+ * Read local file content, returning null if the file cannot be read.
26
+ */
27
+ function readLocalFile(filePath) {
28
+ try {
29
+ return readFileSync(filePath, "utf-8");
30
+ }
31
+ catch {
32
+ return null;
33
+ }
34
+ }
35
+ /**
36
+ * Compare registry file content against local file content.
37
+ * Returns true if the files differ (ignoring import path differences
38
+ * is not feasible here — we compare raw registry content against local).
39
+ *
40
+ * Since local files have rewritten imports, we only compare the sound
41
+ * module files (the primary files in /sounds/) by checking if the local
42
+ * file exists and has different content length or key data sections.
43
+ * For a pragmatic approach, we compare the full content of each registry
44
+ * file against the local file. Note: import-rewritten files will always
45
+ * show as different if aliases differ from registry defaults, but this
46
+ * is the expected behavior for detecting upstream changes.
47
+ */
48
+ function hasChanges(registryFiles, config, projectRoot) {
49
+ for (const file of registryFiles) {
50
+ const localPath = resolveLocalPath(file, config, projectRoot);
51
+ const localContent = readLocalFile(localPath);
52
+ if (localContent === null) {
53
+ // File missing locally — counts as a difference
54
+ return true;
55
+ }
56
+ // Compare registry content against local content
57
+ if (file.content !== localContent) {
58
+ return true;
59
+ }
60
+ }
61
+ return false;
62
+ }
63
+ export async function diffCommand(projectRoot) {
64
+ // Config must exist
65
+ if (!ConfigManager.exists(projectRoot)) {
66
+ console.error("Configuration not found. Run 'audx init' first.");
67
+ process.exit(1);
68
+ }
69
+ const config = ConfigManager.read(projectRoot);
70
+ const installedNames = Object.keys(config.installedSounds);
71
+ if (installedNames.length === 0) {
72
+ console.log("No sounds installed.");
73
+ return;
74
+ }
75
+ const changedSounds = [];
76
+ for (const soundName of installedNames) {
77
+ try {
78
+ // Requirement 10.1 — fetch current registry item for each installed sound
79
+ const item = await fetchItem(config.registryUrl, soundName);
80
+ // Compare fetched file content against local files
81
+ if (hasChanges(item.files, config, projectRoot)) {
82
+ changedSounds.push(soundName);
83
+ }
84
+ }
85
+ catch (error) {
86
+ // Requirement 10.7 — continue on individual fetch failures with warning
87
+ const message = error instanceof Error ? error.message : String(error);
88
+ console.warn(`⚠ Could not check '${soundName}': ${message}`);
89
+ }
90
+ }
91
+ // Requirement 10.2 — display changed sound names
92
+ if (changedSounds.length > 0) {
93
+ console.log("Sounds with available updates:");
94
+ for (const name of changedSounds) {
95
+ console.log(` • ${name}`);
96
+ }
97
+ }
98
+ else {
99
+ // Requirement 10.3 — all up to date message
100
+ console.log("All sounds are up to date.");
101
+ }
102
+ }
103
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/commands/diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * `audx generate "<prompt>"` command handler.
3
+ *
4
+ * Accepts a prompt string, optional --name and --duration flags.
5
+ * Generates a sound via the API, writes a Sound_Module file, and
6
+ * updates the config manifest.
7
+ */
8
+ export declare function generateCommand(prompt: string, options: {
9
+ name?: string;
10
+ duration?: string;
11
+ }, projectRoot: string): Promise<void>;
12
+ //# sourceMappingURL=generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AA+CA;;;;;;GAMG;AACH,wBAAsB,eAAe,CACpC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,EAC7C,WAAW,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAgEf"}
@@ -0,0 +1,96 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import * as ConfigManager from "../core/config.js";
4
+ import { generateSound } from "../core/registry.js";
5
+ import { deriveKebabName, encodeAudioToDataUri } from "../core/utils.js";
6
+ /**
7
+ * Convert a kebab-case name to a camelCase variable name suffixed with "Audio".
8
+ * e.g. "laser-blast" → "laserBlastAudio"
9
+ */
10
+ function toCamelCaseAudioVar(kebab) {
11
+ const camel = kebab.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
12
+ return `${camel}Audio`;
13
+ }
14
+ /**
15
+ * Build the Sound_Module TypeScript source for a generated sound.
16
+ */
17
+ function buildSoundModule(name, dataUri, duration) {
18
+ const varName = toCamelCaseAudioVar(name);
19
+ const dur = duration ?? 2;
20
+ const lines = [
21
+ `import type { AudioAsset } from "@/lib/audio-types";`,
22
+ ``,
23
+ `export const ${varName}: AudioAsset = {`,
24
+ ` name: "${name}",`,
25
+ ` dataUri:`,
26
+ ` "${dataUri}",`,
27
+ ` duration: ${dur},`,
28
+ ` format: "mp3",`,
29
+ ` license: "MIT",`,
30
+ ` author: "Generated",`,
31
+ `};`,
32
+ ``,
33
+ ];
34
+ return lines.join("\n");
35
+ }
36
+ /**
37
+ * `audx generate "<prompt>"` command handler.
38
+ *
39
+ * Accepts a prompt string, optional --name and --duration flags.
40
+ * Generates a sound via the API, writes a Sound_Module file, and
41
+ * updates the config manifest.
42
+ */
43
+ export async function generateCommand(prompt, options, projectRoot) {
44
+ // Requirement 8.8 — config must exist
45
+ if (!ConfigManager.exists(projectRoot)) {
46
+ console.error("Configuration not found. Run 'audx init' first.");
47
+ process.exit(1);
48
+ }
49
+ const config = ConfigManager.read(projectRoot);
50
+ // Requirement 8.2 / 8.3 — derive or use provided name
51
+ const soundName = options.name ?? deriveKebabName(prompt);
52
+ // Build API params
53
+ const params = { text: prompt };
54
+ // Requirement 8.4 — optional duration
55
+ if (options.duration !== undefined) {
56
+ const dur = Number(options.duration);
57
+ if (Number.isNaN(dur) || dur < 0.5 || dur > 22) {
58
+ console.error("Duration must be a number between 0.5 and 22.");
59
+ process.exit(1);
60
+ }
61
+ params.duration_seconds = dur;
62
+ }
63
+ try {
64
+ // Requirement 8.1 — POST to generation API
65
+ console.log(`Generating sound "${soundName}" from prompt: "${prompt}"...`);
66
+ const audioBuffer = await generateSound(config.registryUrl, params);
67
+ // Requirement 8.5 — encode as base64 data URI and create Sound_Module
68
+ const dataUri = encodeAudioToDataUri(audioBuffer);
69
+ const moduleContent = buildSoundModule(soundName, dataUri, params.duration_seconds);
70
+ // Write to soundDir
71
+ const targetDir = join(projectRoot, config.soundDir);
72
+ mkdirSync(targetDir, { recursive: true });
73
+ const filePath = join(targetDir, `${soundName}.ts`);
74
+ writeFileSync(filePath, moduleContent, "utf-8");
75
+ // Requirement 8.6 — update installedSounds in config
76
+ const updatedConfig = {
77
+ ...config,
78
+ installedSounds: {
79
+ ...config.installedSounds,
80
+ [soundName]: {
81
+ files: [filePath],
82
+ installedAt: new Date().toISOString(),
83
+ },
84
+ },
85
+ };
86
+ ConfigManager.write(projectRoot, updatedConfig);
87
+ console.log(`✔ Generated and installed ${soundName}`);
88
+ }
89
+ catch (error) {
90
+ // Requirement 8.7 — handle API errors
91
+ const message = error instanceof Error ? error.message : String(error);
92
+ console.error(`✘ ${message}`);
93
+ process.exit(2);
94
+ }
95
+ }
96
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function initCommand(projectRoot: string): Promise<void>;
2
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAoDA,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA8CpE"}