create-bl-theme 1.0.7 → 1.0.9

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.
@@ -1,7 +1,10 @@
1
1
  {
2
2
  "permissions": {
3
3
  "allow": [
4
- "Bash(cat:*)"
4
+ "Bash(cat:*)",
5
+ "Bash(node /Users/boidu/Developer/create-bl-theme/bin/cli.js bump:*)",
6
+ "Bash(npm:*)",
7
+ "Bash(node /Users/boidu/Developer/create-bl-theme/bin/cli.js:*)"
5
8
  ],
6
9
  "deny": [],
7
10
  "ask": []
package/CLAUDE.md ADDED
@@ -0,0 +1,73 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ **create-bl-theme** is a CLI tool for scaffolding and managing themes for the Better Lyrics browser extension. It provides commands to create new themes, validate their structure, manage versioning, and handle publishing to a theme registry.
8
+
9
+ ## Commands
10
+
11
+ ```bash
12
+ # Run the CLI locally during development
13
+ node bin/cli.js [command]
14
+
15
+ # Create a new theme (interactive prompts)
16
+ node bin/cli.js [theme-name]
17
+
18
+ # Validate a theme (supports local paths or GitHub URLs)
19
+ node bin/cli.js validate [dir|url]
20
+
21
+ # Check publishing status against the theme registry
22
+ node bin/cli.js publish [dir]
23
+
24
+ # Bump version (patch/minor/major)
25
+ node bin/cli.js bump [patch|minor|major] [dir]
26
+
27
+ # Show version/help
28
+ node bin/cli.js --version
29
+ node bin/cli.js --help
30
+ ```
31
+
32
+ ## Architecture
33
+
34
+ The entire CLI is implemented in a single file: `bin/cli.js` (ES6 module).
35
+
36
+ **Main routing pattern:**
37
+ - `main()` parses `process.argv` and routes to command handlers
38
+ - Commands: `create()`, `validate()`, `publish()`, `bump()`
39
+
40
+ **Key external dependencies:**
41
+ - `rics` - RICS CSS preprocessor for syntax validation via `compileWithDetails()`
42
+ - `prompts` - Interactive CLI prompts
43
+ - `image-size` - Image dimension validation
44
+ - `picocolors` - Terminal colors
45
+
46
+ **External API calls:**
47
+ - Theme registry: `https://raw.githubusercontent.com/better-lyrics/themes/master/index.json`
48
+ - Lock file: `https://raw.githubusercontent.com/better-lyrics/themes/master/index.lock.json`
49
+
50
+ ## Theme Structure Generated
51
+
52
+ ```
53
+ theme-name/
54
+ ├── metadata.json # Required: id, title, creators, minVersion, hasShaders, version, images
55
+ ├── style.rics # Required: styles using RICS preprocessor (plain CSS is valid)
56
+ ├── images/ # Required: at least one screenshot
57
+ ├── DESCRIPTION.md # Optional: rich markdown description
58
+ ├── shader.json # Required if hasShaders: true
59
+ └── README.md
60
+ ```
61
+
62
+ ## Validation Rules
63
+
64
+ - `metadata.json` requires fields: id, title, creators, minVersion, hasShaders, version, images
65
+ - Version must be strict semver (e.g., `1.0.0`)
66
+ - Image IDs: lowercase letters, numbers, hyphens only
67
+ - Images: PNG, JPG, GIF, WebP; warns if not 16:9 aspect ratio
68
+ - RICS syntax validated with detailed error reporting
69
+ - Shader.json required when `hasShaders: true`
70
+
71
+ ## RICS Notes
72
+
73
+ RICS is a lightweight CSS preprocessor with full CSS parity. Plain CSS is valid RICS. Supports variables, nesting, mixins. Documentation: https://github.com/better-lyrics/rics
package/README.md CHANGED
@@ -45,9 +45,41 @@ The validator checks:
45
45
  - Required files (metadata.json, style.rics or style.css, images/)
46
46
  - RICS syntax validation (for .rics files)
47
47
  - Valid JSON structure and required fields
48
+ - Semver version format
48
49
  - Image integrity (detects corrupted files)
49
50
  - Image dimensions (recommends 1280x720, but other sizes work fine)
50
51
 
52
+ ### Bump version
53
+
54
+ ```bash
55
+ # Bump patch version (1.0.0 → 1.0.1)
56
+ create-bl-theme bump patch
57
+
58
+ # Bump minor version (1.0.0 → 1.1.0)
59
+ create-bl-theme bump minor
60
+
61
+ # Bump major version (1.0.0 → 2.0.0)
62
+ create-bl-theme bump major
63
+
64
+ # Bump in a specific directory
65
+ create-bl-theme bump patch ./my-theme
66
+ ```
67
+
68
+ ### Check publishing status
69
+
70
+ ```bash
71
+ # Check if theme is registered and ready to publish
72
+ create-bl-theme publish
73
+
74
+ # Check a specific directory
75
+ create-bl-theme publish ./my-theme
76
+ ```
77
+
78
+ The publish command:
79
+ - Checks if your theme is registered in the theme store
80
+ - Shows your current version vs. the registry version
81
+ - Provides setup instructions for auto-publishing
82
+
51
83
  ## Generated Structure
52
84
 
53
85
  ```
@@ -130,6 +162,16 @@ Better Lyrics supports **GitHub Flavored Markdown (GFM)** in DESCRIPTION.md, so
130
162
  ```
131
163
  4. Open a pull request
132
164
 
165
+ ### Auto-Publishing
166
+
167
+ After your theme is registered, install the [Better Lyrics Themes](https://github.com/marketplace/better-lyrics-themes) GitHub App on your repo. This enables automatic updates:
168
+
169
+ 1. Bump your version: `create-bl-theme bump patch`
170
+ 2. Commit and push
171
+ 3. The registry automatically validates and publishes your update
172
+
173
+ Use `create-bl-theme publish` to check your publishing status.
174
+
133
175
  ## License
134
176
 
135
177
  MIT
package/bin/cli.js CHANGED
@@ -7,7 +7,7 @@ import path from "path";
7
7
  import os from "os";
8
8
  import { fileURLToPath } from "url";
9
9
  import { imageSize } from "image-size";
10
- import { execSync } from "child_process";
10
+ import { execSync, spawn } from "child_process";
11
11
  import { compileWithDetails } from "rics";
12
12
 
13
13
  const __filename = fileURLToPath(import.meta.url);
@@ -22,12 +22,95 @@ const RECOMMENDED_HEIGHT = 720;
22
22
  // GitHub URL patterns
23
23
  const GITHUB_URL_PATTERN = /^(?:https?:\/\/)?(?:www\.)?github\.com\/([^\/]+)\/([^\/]+)(?:\/)?(?:\.git)?$/;
24
24
 
25
+ // GitHub App URL for auto-updates
26
+ const GITHUB_APP_URL = "https://github.com/apps/better-lyrics-harmonizer/installations/new";
27
+
28
+ // Load package.json for version
29
+ const pkg = JSON.parse(
30
+ fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf-8")
31
+ );
32
+
33
+ // Cross-platform browser opener
34
+ function openBrowser(url) {
35
+ const platform = process.platform;
36
+ let command;
37
+ let args;
38
+
39
+ if (platform === "darwin") {
40
+ command = "open";
41
+ args = [url];
42
+ } else if (platform === "win32") {
43
+ command = "cmd";
44
+ args = ["/c", "start", "", url];
45
+ } else {
46
+ command = "xdg-open";
47
+ args = [url];
48
+ }
49
+
50
+ return new Promise((resolve, reject) => {
51
+ const child = spawn(command, args, {
52
+ detached: true,
53
+ stdio: "ignore",
54
+ });
55
+
56
+ child.on("error", (err) => {
57
+ reject(err);
58
+ });
59
+
60
+ child.unref();
61
+ resolve();
62
+ });
63
+ }
64
+
65
+ // Prompt to install GitHub App for auto-updates
66
+ async function promptGitHubAppInstall() {
67
+ console.log();
68
+ console.log(pc.bold("GitHub App Installation"));
69
+ console.log();
70
+ console.log("Install Better Lyrics Harmonizer for automatic theme publishing.");
71
+ console.log(pc.dim("This is a one-time setup. After installing, push changes with a bumped"));
72
+ console.log(pc.dim("version and they'll auto-publish to the theme store (with commit status)."));
73
+ console.log();
74
+
75
+ const response = await prompts({
76
+ type: "confirm",
77
+ name: "openBrowser",
78
+ message: "Open browser to install Better Lyrics Harmonizer?",
79
+ initial: true,
80
+ });
81
+
82
+ if (response.openBrowser) {
83
+ try {
84
+ await openBrowser(GITHUB_APP_URL);
85
+ console.log(pc.green(" Browser opened!"));
86
+ } catch (err) {
87
+ console.log(pc.yellow(" Could not open browser automatically."));
88
+ }
89
+ }
90
+
91
+ console.log();
92
+ console.log(pc.dim(" Install URL:"));
93
+ console.log(pc.cyan(` ${GITHUB_APP_URL}`));
94
+ console.log();
95
+ }
96
+
25
97
  async function main() {
26
98
  const args = process.argv.slice(2);
27
99
  const command = args[0];
28
100
 
101
+ // Handle flags first (no banner)
102
+ if (command === "--version" || command === "-v" || command === "version") {
103
+ console.log(pkg.version);
104
+ return;
105
+ }
106
+
107
+ if (command === "--help" || command === "-h" || command === "help") {
108
+ showHelp();
109
+ return;
110
+ }
111
+
29
112
  console.log();
30
- console.log(pc.bold(pc.cyan(" Better Lyrics Theme Creator")));
113
+ console.log(pc.bold(pc.cyan(" Better Lyrics Theme Creator")) + pc.dim(` v${pkg.version}`));
31
114
  console.log(pc.dim(" Create themes for Better Lyrics extension"));
32
115
  console.log();
33
116
 
@@ -41,8 +124,8 @@ async function main() {
41
124
  return;
42
125
  }
43
126
 
44
- if (command === "help" || command === "--help" || command === "-h") {
45
- showHelp();
127
+ if (command === "bump") {
128
+ await bump(args[1], args[2]);
46
129
  return;
47
130
  }
48
131
 
@@ -50,16 +133,27 @@ async function main() {
50
133
  }
51
134
 
52
135
  function showHelp() {
53
- console.log(`${pc.bold("Usage:")}
136
+ console.log(`
137
+ ${pc.bold(pc.cyan("create-bl-theme"))} ${pc.dim(`v${pkg.version}`)}
138
+ CLI for Better Lyrics themes
139
+
140
+ ${pc.bold("Usage:")}
54
141
  ${pc.cyan("create-bl-theme")} [name] Create a new theme
55
142
  ${pc.cyan("create-bl-theme")} validate [dir|url] Validate a theme (local or GitHub)
56
143
  ${pc.cyan("create-bl-theme")} publish [dir] Check publishing status
144
+ ${pc.cyan("create-bl-theme")} bump [type] [dir] Bump version (patch, minor, major)
145
+
146
+ ${pc.bold("Options:")}
147
+ ${pc.cyan("-v, --version")} Show version number
148
+ ${pc.cyan("-h, --help")} Show this help message
57
149
 
58
150
  ${pc.bold("Examples:")}
59
151
  ${pc.dim("$")} create-bl-theme my-awesome-theme
60
152
  ${pc.dim("$")} create-bl-theme validate ./my-theme
61
153
  ${pc.dim("$")} create-bl-theme validate https://github.com/user/theme-repo
62
154
  ${pc.dim("$")} create-bl-theme publish
155
+ ${pc.dim("$")} create-bl-theme bump patch
156
+ ${pc.dim("$")} create-bl-theme bump minor ./my-theme
63
157
 
64
158
  ${pc.bold("Theme Structure:")}
65
159
  my-theme/
@@ -590,6 +684,11 @@ async function validate(dir) {
590
684
 
591
685
  console.log();
592
686
 
687
+ // Prompt to install GitHub App if validation passed
688
+ if (errors.length === 0) {
689
+ await promptGitHubAppInstall();
690
+ }
691
+
593
692
  // Cleanup temp directory if we cloned from GitHub
594
693
  if (tempDir) {
595
694
  try {
@@ -674,30 +773,23 @@ async function publish(dir) {
674
773
  console.log(` 2. Add { "repo": "${repo}" } to index.json`);
675
774
  console.log(" 3. Open a pull request");
676
775
  console.log();
677
- console.log("After your PR is merged, install the GitHub App for auto-updates:");
678
- console.log(pc.cyan(" https://github.com/marketplace/better-lyrics-themes"));
776
+ console.log(pc.dim("After your PR is merged, install the GitHub App for auto-updates:"));
777
+ await promptGitHubAppInstall();
679
778
  process.exit(0);
680
779
  }
681
780
 
682
781
  // 7. Theme is registered
683
782
  console.log(pc.green("Theme is registered in the theme store."));
684
783
  console.log();
685
- console.log(pc.bold("Auto-publishing Setup:"));
686
- console.log();
687
- console.log("To enable automatic updates when you push:");
688
- console.log(" 1. Install the GitHub App on your repo:");
689
- console.log(pc.cyan(" https://github.com/marketplace/better-lyrics-themes"));
690
- console.log();
691
- console.log(" 2. Push changes to your repo:");
692
- console.log(pc.dim(" git add ."));
693
- console.log(pc.dim(' git commit -m "feat: update theme"'));
694
- console.log(pc.dim(" git push"));
784
+ console.log(pc.bold("To publish updates:"));
785
+ console.log(pc.dim(" git add ."));
786
+ console.log(pc.dim(' git commit -m "feat: update theme"'));
787
+ console.log(pc.dim(" git push"));
695
788
  console.log();
696
789
  console.log("The registry will automatically:");
697
790
  console.log(" - Validate your theme");
698
791
  console.log(" - Update the lockfile");
699
792
  console.log(" - Vendor your theme files");
700
- console.log(" - Show a commit status on your push");
701
793
  console.log();
702
794
 
703
795
  // 8. Check current lockfile status
@@ -739,7 +831,8 @@ async function publish(dir) {
739
831
  }
740
832
  }
741
833
 
742
- console.log();
834
+ // Prompt to install GitHub App for auto-updates
835
+ await promptGitHubAppInstall();
743
836
  }
744
837
 
745
838
  function checkIsGitRepo(themePath) {
@@ -788,6 +881,90 @@ async function checkLockStatus(repo) {
788
881
  }
789
882
  }
790
883
 
884
+ async function bump(typeOrDir, dirArg) {
885
+ // Handle flexible argument order: bump [type] [dir] or bump [dir]
886
+ let type = "patch";
887
+ let dir = ".";
888
+
889
+ const validTypes = ["patch", "minor", "major"];
890
+
891
+ if (typeOrDir) {
892
+ if (validTypes.includes(typeOrDir)) {
893
+ type = typeOrDir;
894
+ dir = dirArg || ".";
895
+ } else {
896
+ // Assume it's a directory
897
+ dir = typeOrDir;
898
+ }
899
+ }
900
+
901
+ const fullPath = path.resolve(process.cwd(), dir);
902
+ const metadataPath = path.join(fullPath, "metadata.json");
903
+
904
+ // Check metadata.json exists
905
+ if (!fs.existsSync(metadataPath)) {
906
+ console.log(pc.red("Error: metadata.json not found."));
907
+ process.exit(1);
908
+ }
909
+
910
+ let metadata;
911
+ try {
912
+ metadata = JSON.parse(fs.readFileSync(metadataPath, "utf-8"));
913
+ } catch (e) {
914
+ console.log(pc.red(`Error: Invalid metadata.json - ${e.message}`));
915
+ process.exit(1);
916
+ }
917
+
918
+ const currentVersion = metadata.version;
919
+ if (!currentVersion) {
920
+ console.log(pc.red("Error: No version field in metadata.json"));
921
+ process.exit(1);
922
+ }
923
+
924
+ // Parse current version
925
+ const match = currentVersion.match(/^(\d+)\.(\d+)\.(\d+)(.*)$/);
926
+ if (!match) {
927
+ console.log(pc.red(`Error: Invalid version format "${currentVersion}"`));
928
+ process.exit(1);
929
+ }
930
+
931
+ let [, major, minor, patch, prerelease] = match;
932
+ major = parseInt(major, 10);
933
+ minor = parseInt(minor, 10);
934
+ patch = parseInt(patch, 10);
935
+
936
+ // Bump version
937
+ switch (type) {
938
+ case "major":
939
+ major++;
940
+ minor = 0;
941
+ patch = 0;
942
+ prerelease = "";
943
+ break;
944
+ case "minor":
945
+ minor++;
946
+ patch = 0;
947
+ prerelease = "";
948
+ break;
949
+ case "patch":
950
+ default:
951
+ patch++;
952
+ prerelease = "";
953
+ break;
954
+ }
955
+
956
+ const newVersion = `${major}.${minor}.${patch}`;
957
+ metadata.version = newVersion;
958
+
959
+ // Write back
960
+ fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2) + "\n");
961
+
962
+ console.log(pc.green(` ${currentVersion} → ${newVersion}`));
963
+ console.log();
964
+ console.log(pc.dim(` Updated ${metadataPath}`));
965
+ console.log();
966
+ }
967
+
791
968
  main().catch((err) => {
792
969
  console.error(pc.red(err.message));
793
970
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-bl-theme",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "CLI tool to scaffold Better Lyrics themes",
5
5
  "type": "module",
6
6
  "bin": {