1 # Scripts 2 3 ## `ci/classify-changes.mjs` 4 5 CI change classifier — the single source of truth for path-based CI gating. 6 Maps changed files to categories, collects unmatched files as `unknown` , and 7 derives the expected job set from the category union. Consumed by the triage 8 job in `.github/workflows/ci.yml` and `.github/workflows/packaging.yml` . 9 10 - **Input:** newline-delimited filenames (
`--files`
) or JSON array (
`--json`
),
11 plus event type ( `--event pull_request|push|workflow_dispatch` )
12 - **Output:** JSON to stdout; `GITHUB_OUTPUT` entries ( `expected-jobs` ,
13 `run_<job>` booleans, `unknown-files` , `categories` ) and
14 `GITHUB_STEP_SUMMARY` markdown table when those env vars are set
15 - **Pure function:** no network or filesystem access beyond stdin — testable
16 locally without GitHub API access
17 - **Contract tests:** `tests/ci/classify-changes.test.ts`
18 - **Drift tests:** `tests/ci/ci-workflow-contract.test.ts`
19 - **Run:** `node scripts/ci/classify-changes.mjs --files <paths> --event pull_request`
20
21 ## `generate-mock-songs.mjs`
22
23 Regenerates the shared mock/preview song catalog used by both the website
24 embedded preview and the Playwright E2E Tauri mock from a local playlist of
25 m4a files.
26
27 - **Input:** m4a files in `~/Music/OpenKara/media` (override with
28 `--media-dir <path>` )
29 - **Output:** `src/mock/preview-songs.ts` (self-contained: base64 cover art +
30 synced lyrics + MBIDs) and `src/mock/covers/*.jpg` (300×300 downscaled
31 JPEGs for human/git inspection)
32 - **Lyrics source:** fetched from lrclib.net ( `/api/get` ) using the embedded
33 title/artist/album/duration tags. Synced lyrics (LRC with real
34 `[mm:ss.xx]` timestamps) are used when available; otherwise the embedded
35 m4a `lyrics` tag is used with pseudo-LRC timestamps as a fallback
36 - **Run:** `node scripts/generate-mock-songs.mjs [--media-dir <path>] [--cover-size 300]`
37 - **When to run:** after changing the preview playlist
38 - **Idempotent:** two consecutive runs produce zero diff in the output files
39 for the same input media and cover size (assuming lrclib returns the same
40 synced lyrics)
41 - **Why a shared module:** the website preview ( `website/src/mock-app.ts` )
42 and the E2E Tauri mock ( `tests/e2e/fixtures/tauri-mock.ts` ) both serialize
43 from `src/mock/preview-songs.ts` so the two surfaces cannot drift apart
44
45 ## `generate-db-schema.mjs`
46
47 Regenerates `docs/references/generated/db-schema.md` from
48 `src-tauri/migrations/*.sql` .
49
50 - **Input:** none (reads migration files directly)
51 - **Output:** `docs/references/generated/db-schema.md`
52 - **Run:** `node scripts/generate-db-schema.mjs` or `pnpm generate:db-schema`
53 - **When to run:** after any migration PR or manual schema change
54 - **Idempotent:** two consecutive runs produce zero diff in the output file
55
56 ## `setup.sh`
57
58 Bootstraps the local Demucs ONNX model required by later separation work.
59
60 - **Input:** none
61 - **Prerequisites:** `curl` , `shasum`
62 - **Output:** `src-tauri/models/htdemucs.onnx`
63 - **Success:** downloads the model, verifies SHA-256, and stores it in the models directory
64 - **Repeat runs:** exit immediately if the existing model already matches the pinned checksum
65 - **Failure:** exits non-zero with a readable error if a required tool is missing, the download fails, or checksum verification fails
66
67 Run it from the repository root:
68
69 ```bash
70 ./scripts/setup.sh
71 ```
72
73 ## `run-local-smoke.sh`
74
75 Runs a local backend smoke pass against real audio files in a directory and
76 writes JSON + Markdown reports into an output directory.
77
78 - **Input:** optional input directory, defaults to `./test`
79 - **Prerequisites:** Rust toolchain, local dependencies installed, optional
80 model downloaded via `./scripts/setup.sh` if separation should run
81 - **Output:** `output/local-audio-smoke-report.json` ,
82 `output/local-audio-smoke-report.md` , and separation cache under
83 `output/cache/`
84 - **Success:** imports supported audio files, profiles playback load/seek, and
85 runs separation when a verified model is available
86 - **Repeat runs:** overwrite the smoke DB/report files while reusing any cached
87 stems under the selected output directory
88 - **Failure:** exits non-zero with readable stderr when the input directory is
89 missing, no readable audio files are found, or a backend step fatally fails
90
91 Run it from the repository root:
92
93 ```bash
94 ./scripts/run-local-smoke.sh
95 ```
96
97 Optional custom paths:
98
99 ```bash
100 ./scripts/run-local-smoke.sh ./test ./output
101 ```
102
103 ## `generate-macos-liquid-glass-icon.mjs`
104
105 Compiles the Icon Composer project into macOS 26 Liquid Glass assets.
106
107 - **Input:** `src-tauri/icons/OpenKara.icon/` plus `src-tauri/icons/app-icon.png`
108 (extracts the microphone foreground into `OpenKara Mic.png` before compiling;
109 the `.icon` fill owns the macOS 26 background shape)
110 - **Prerequisites:** macOS host with Xcode `actool` ( `xcrun actool` )
111 - **Output:** `src-tauri/icons/Assets.car` , `src-tauri/icons/OpenKara.icns`
112 - **Run:** `node scripts/generate-macos-liquid-glass-icon.mjs` or `pnpm icons:generate` (chained after `tauri icon` )
113 - **Non-macOS hosts:** exits successfully without writing files
114 - **When to run:** after changing `app-icon.png` or `OpenKara.icon/icon.json`
115 - **Bundle:** `Assets.car` is copied into the app via `tauri.conf.json` `bundle.resources` ; `Info.plist` sets `CFBundleIconName` to `OpenKara`
116
117 ## `generate-flatpak-node-sources.mjs`
118
119 Regenerates Flatpak offline pnpm dependency sources from `pnpm-lock.yaml` .
120
121 - **Input:** `pnpm-lock.yaml` plus existing
122 `packaging/flatpak/generated/node-sources.0.json` scaffold entries
123 - **Output:** `packaging/flatpak/generated/node-sources.0.json`
124 - **Run:** `node scripts/generate-flatpak-node-sources.mjs` or
125 `pnpm generate:flatpak-node-sources`
126 - **When to run:** after changing JavaScript dependencies or lockfile entries
127 used by Flatpak packaging
128
129 ## `flatpak/populate_pnpm_store.mjs`
130
131 Seeds the Flatpak offline pnpm 11 store from downloaded tarballs. Canonical
132 copy also lives inline in `node-sources.0.json` as
133 `flatpak-node/populate_pnpm_store.mjs` and is invoked from the Flatpak
134 manifest **after** the pnpm tarball is installed.
135
136 - **Why:** pnpm 11 indexes packages in `store-dir/v11/index.db` (SQLite +
137 msgpackr). Legacy JSON `index/` entries are ignored, which previously
138 produced `ERR_PNPM_NO_OFFLINE_TARBALL` despite intact CAFS blobs.
139 - **How:** replays each lockfile tarball through pnpm's own
140 `dist/worker.js` extract path so the store matches a normal install.
141 - **Run (inside Flatpak build):**
142 `node flatpak-node/populate_pnpm_store.mjs <manifest.json> <tarball-dir> <store-dir>`
143
144 ## `flatpak/rewrite_lockfile_local_tarballs.mjs`
145
146 Rewrites `pnpm-lock.yaml` package resolutions in the Flatpak build directory
147 so each entry has `tarball: file:flatpak-node/pnpm-tarballs/<name>.tgz` .
148
149 - **Why:** even with a pre-seeded store, offline install must never hit
150 `registry.npmjs.org` inside the Flatpak sandbox (DNS fails with EAI_AGAIN).
151 The `file:` resolution uses pnpm's localTarball fetcher, which works offline.
152 - **Run (inside Flatpak build, before install):**
153 `node flatpak-node/rewrite_lockfile_local_tarballs.mjs`
154
155 ## `generate-flatpak-cargo-sources.mjs`
156
157 Regenerates Flatpak offline Cargo dependency sources from `src-tauri/Cargo.lock` .
158
159 - **Input:** `src-tauri/Cargo.lock`
160 - **Output:** `packaging/flatpak/generated/cargo-sources.json`
161 - **Run:** `node scripts/generate-flatpak-cargo-sources.mjs [lockfile] [output]` or
162 `pnpm generate:flatpak-cargo-sources`
163 - **Optional args:** `lockfile` and `output` override the default input/output
164 paths (used by tests to render into a temp directory without touching the
165 checkout)
166 - **Exports:** `parseCargoLockfile` , `generateCargoSources` , and
167 `renderCargoSources` (pure rendering for non-destructive tests)
168 - **When to run:** after changing Rust dependencies or `Cargo.lock` entries
169 used by Flatpak packaging
170 - **Idempotent:** two consecutive runs produce zero diff in the output file
171