@programinglive/commiter 1.1.8 → 1.1.10

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [1.1.10](https://github.com/programinglive/commiter/compare/v1.1.9...v1.1.10) (2025-11-26)
6
+
7
+
8
+ ### ✨ Features
9
+
10
+ * **website:** add professional landing page and release tools ([ec53e2d](https://github.com/programinglive/commiter/commit/ec53e2d5d2d1d61d899ba0349cb6771bb9e57385))
11
+
12
+ ### [1.1.9](https://github.com/programinglive/commiter/compare/v1.1.8...v1.1.9) (2025-11-24)
13
+
14
+
15
+ ### 🐛 Bug Fixes
16
+
17
+ * convert release scripts to CJS to support ESM projects ([842da02](https://github.com/programinglive/commiter/commit/842da0298f1c4df7aa93b43ca8698e3669ef6450))
18
+
5
19
  ### [1.1.8](https://github.com/programinglive/commiter/compare/v1.1.7...v1.1.8) (2025-11-22)
6
20
 
7
21
 
@@ -0,0 +1,103 @@
1
+ # Creating GitHub Releases
2
+
3
+ This guide explains how to populate your GitHub releases page with releases from your tags.
4
+
5
+ ## Problem
6
+
7
+ You have tags in your repository (v1.0.0, v1.1.9, etc.) but the GitHub releases page is empty. GitHub doesn't automatically create releases from tags - you need to create them manually.
8
+
9
+ ## Solution Options
10
+
11
+ ### Option 1: Use the Automated Script (Recommended)
12
+
13
+ We've created a script that will automatically create releases for all your tags using the content from CHANGELOG.md.
14
+
15
+ #### Prerequisites
16
+ 1. Create a GitHub Personal Access Token:
17
+ - Go to https://github.com/settings/tokens
18
+ - Click "Generate new token" → "Generate new token (classic)"
19
+ - Give it a name like "Commiter Releases"
20
+ - Select scope: `repo` (Full control of private repositories)
21
+ - Click "Generate token"
22
+ - **Copy the token immediately** (you won't see it again!)
23
+
24
+ #### Steps
25
+ 1. Set your GitHub token as an environment variable:
26
+ ```powershell
27
+ # Windows PowerShell
28
+ $env:GITHUB_TOKEN="your_token_here"
29
+ ```
30
+
31
+ 2. Run the script:
32
+ ```bash
33
+ node scripts/create-releases.js
34
+ ```
35
+
36
+ 3. The script will:
37
+ - Read all your local tags
38
+ - Parse CHANGELOG.md for release notes
39
+ - Create GitHub releases for each tag
40
+ - Skip tags that already have releases
41
+
42
+ ### Option 2: Create Releases Manually
43
+
44
+ If you prefer to create releases manually or just want to create the latest release:
45
+
46
+ 1. Go to https://github.com/programinglive/commiter/releases
47
+ 2. Click "Draft a new release"
48
+ 3. Click "Choose a tag" and select `v1.1.9`
49
+ 4. Set the release title to `v1.1.9`
50
+ 5. Copy the release notes from CHANGELOG.md (lines 5-10):
51
+ ```markdown
52
+ ### 🐛 Bug Fixes
53
+
54
+ * convert release scripts to CJS to support ESM projects ([842da02](https://github.com/programinglive/commiter/commit/842da0298f1c4df7aa93b43ca8698e3669ef6450))
55
+ ```
56
+ 6. Click "Publish release"
57
+ 7. Repeat for other versions if needed
58
+
59
+ ### Option 3: Use GitHub CLI (if installed)
60
+
61
+ If you have GitHub CLI installed (`gh`):
62
+
63
+ ```bash
64
+ # Create release for v1.1.9
65
+ gh release create v1.1.9 \
66
+ --title "v1.1.9" \
67
+ --notes "### 🐛 Bug Fixes
68
+
69
+ * convert release scripts to CJS to support ESM projects"
70
+
71
+ # Or create from CHANGELOG
72
+ gh release create v1.1.9 --notes-file CHANGELOG.md
73
+ ```
74
+
75
+ ## After Creating Releases
76
+
77
+ Once releases are created, they will appear on:
78
+ - https://github.com/programinglive/commiter/releases
79
+ - The right sidebar of your repository
80
+ - In the repository's release feed
81
+
82
+ ## Automating Future Releases
83
+
84
+ To automatically create GitHub releases during your release process, you can:
85
+
86
+ 1. **Add to your release script** - Modify `scripts/release.cjs` to create GitHub releases
87
+ 2. **Use GitHub Actions** - Set up a workflow that creates releases when tags are pushed
88
+ 3. **Use the script** - Run `scripts/create-releases.js` after each release
89
+
90
+ ## Troubleshooting
91
+
92
+ ### "GITHUB_TOKEN not set"
93
+ Make sure you've set the environment variable in your current terminal session.
94
+
95
+ ### "API rate limit exceeded"
96
+ GitHub API has rate limits. The script waits 1 second between requests to avoid this. If you hit the limit, wait an hour and try again.
97
+
98
+ ### "Resource not accessible by integration"
99
+ Your token doesn't have the right permissions. Make sure you selected the `repo` scope when creating the token.
100
+
101
+ ## Security Note
102
+
103
+ **Never commit your GitHub token to the repository!** Always use environment variables or secure secret management.
@@ -0,0 +1,101 @@
1
+ # Quick Guide: Create GitHub Release for v1.1.9
2
+
3
+ Follow these simple steps to create your first GitHub release:
4
+
5
+ ## Step 1: Navigate to New Release Page
6
+ 1. Make sure you're logged into GitHub
7
+ 2. Go to: https://github.com/programinglive/commiter/releases/new
8
+
9
+ ## Step 2: Fill in the Form
10
+
11
+ ### Choose a tag
12
+ - Click "Choose a tag"
13
+ - Type: `v1.1.9`
14
+ - Click "Create new tag: v1.1.9 on publish"
15
+
16
+ ### Release title
17
+ - Type: `v1.1.9`
18
+
19
+ ### Describe this release
20
+ Copy and paste this content:
21
+
22
+ ```markdown
23
+ ### 🐛 Bug Fixes
24
+
25
+ * convert release scripts to CJS to support ESM projects ([842da02](https://github.com/programinglive/commiter/commit/842da0298f1c4df7aa93b43ca8698e3669ef6450))
26
+ ```
27
+
28
+ ## Step 3: Publish
29
+ - Click the green "Publish release" button
30
+
31
+ ## Done! ✅
32
+
33
+ Your release will now appear at: https://github.com/programinglive/commiter/releases
34
+
35
+ ---
36
+
37
+ ## Create More Releases (Optional)
38
+
39
+ If you want to create releases for older versions, here's the content for each:
40
+
41
+ ### v1.1.8
42
+ **Title:** `v1.1.8`
43
+ **Description:**
44
+ ```markdown
45
+ ### 🐛 Bug Fixes
46
+
47
+ * update installation script to copy missing files and update gitignore ([5d56259](https://github.com/programinglive/commiter/commit/5d562592fe35b684fa12bd89748b24551ae28a66))
48
+ ```
49
+
50
+ ### v1.1.7
51
+ **Title:** `v1.1.7`
52
+ **Description:**
53
+ ```markdown
54
+ ### 📝 Documentation
55
+
56
+ * recommend dev workflow mcp server ([58a5054](https://github.com/programinglive/commiter/commit/58a5054fafd627ef23c448fd93b1383518590ad2))
57
+ ```
58
+
59
+ ### v1.1.6
60
+ **Title:** `v1.1.6`
61
+ **Description:**
62
+ ```markdown
63
+ ### 🐛 Bug Fixes
64
+
65
+ * revert to simple release notes staging to avoid git ref conflicts ([2f6a40e](https://github.com/programinglive/commiter/commit/2f6a40ed7259cffdb0b1de1633af3e43df475044))
66
+ ```
67
+
68
+ ### v1.1.5
69
+ **Title:** `v1.1.5`
70
+ **Description:**
71
+ ```markdown
72
+ ### ✨ Features
73
+
74
+ * include release notes in release commit via amendment ([3f2afa8](https://github.com/programinglive/commiter/commit/3f2afa8bd0bd264d047df06ae791384e74dc827e))
75
+
76
+ ### 📝 Documentation
77
+
78
+ * update release notes for v1.1.5 ([cb3dbe6](https://github.com/programinglive/commiter/commit/cb3dbe62a85a174bfb074e3d2526a005fc83d0d7))
79
+ ```
80
+
81
+ ### v1.1.1
82
+ **Title:** `v1.1.1`
83
+ **Description:**
84
+ ```markdown
85
+ ### 🐛 Bug Fixes
86
+
87
+ * remove fs.F_OK deprecation warning ([1b0652b](https://github.com/programinglive/commiter/commit/1b0652b88d1b095e1045994948f75ce8194f9d3a))
88
+ ```
89
+
90
+ ### v1.0.12
91
+ **Title:** `v1.0.12`
92
+ **Description:**
93
+ ```markdown
94
+ ### ✨ Features
95
+
96
+ * auto-detect test command during release ([602e30e](https://github.com/programinglive/commiter/commit/602e30e94ff7c58b35f8c54bd495c0334352c72c))
97
+ ```
98
+
99
+ ---
100
+
101
+ **Tip:** You only need to create releases for the major versions (1.1.9, 1.1.8, 1.1.7, etc.). You can skip the older patch versions if you want to save time.
@@ -4,6 +4,8 @@ This document summarizes every published version of `@programinglive/commiter`.
4
4
 
5
5
  | Version | Date | Highlights |
6
6
  |---------|------|------------|
7
+ | 1.1.10 | 2025-11-26 | **website:** add professional landing page and release tools (ec53e2d) |
8
+ | 1.1.9 | 2025-11-24 | convert release scripts to CJS to support ESM projects (842da02) |
7
9
  | 1.1.8 | 2025-11-22 | update installation script to copy missing files and update gitignore (5d56259) |
8
10
  | 1.1.7 | 2025-11-11 | recommend dev workflow mcp server (58a5054) |
9
11
  | 1.1.6 | 2025-11-05 | revert to simple release notes staging to avoid git ref conflicts (2f6a40e) |
@@ -34,6 +36,20 @@ This document summarizes every published version of `@programinglive/commiter`.
34
36
 
35
37
 
36
38
 
39
+
40
+
41
+ ## 1.1.10 – ✨ Features
42
+
43
+ Released on **2025-11-26**.
44
+
45
+ - **website:** add professional landing page and release tools (ec53e2d)
46
+
47
+ ## 1.1.9 – 🐛 Bug Fixes
48
+
49
+ Released on **2025-11-24**.
50
+
51
+ - convert release scripts to CJS to support ESM projects (842da02)
52
+
37
53
  ## 1.1.8 – 🐛 Bug Fixes
38
54
 
39
55
  Released on **2025-11-22**.
package/index.js CHANGED
@@ -59,10 +59,10 @@ function setupCommiter() {
59
59
  packageJson.scripts = ensureSafeTestScript(packageJson.scripts || {});
60
60
  // Add scripts
61
61
  packageJson.scripts.prepare = 'husky';
62
- packageJson.scripts.release = 'node scripts/release.js';
63
- packageJson.scripts['release:major'] = 'node scripts/release.js major';
64
- packageJson.scripts['release:minor'] = 'node scripts/release.js minor';
65
- packageJson.scripts['release:patch'] = 'node scripts/release.js patch';
62
+ packageJson.scripts.release = 'node scripts/release.cjs';
63
+ packageJson.scripts['release:major'] = 'node scripts/release.cjs major';
64
+ packageJson.scripts['release:minor'] = 'node scripts/release.cjs minor';
65
+ packageJson.scripts['release:patch'] = 'node scripts/release.cjs patch';
66
66
 
67
67
  // Add standard-version config
68
68
  packageJson['standard-version'] = {
@@ -92,22 +92,22 @@ function setupCommiter() {
92
92
  fs.mkdirSync(releaseScriptDir, { recursive: true });
93
93
  }
94
94
 
95
- const releaseScriptPath = path.join(releaseScriptDir, 'release.js');
96
- const releaseScriptSource = path.join(__dirname, 'scripts', 'release.js');
95
+ const releaseScriptPath = path.join(releaseScriptDir, 'release.cjs');
96
+ const releaseScriptSource = path.join(__dirname, 'scripts', 'release.cjs');
97
97
  fs.copyFileSync(releaseScriptSource, releaseScriptPath);
98
98
 
99
99
  // Copy update-release-notes.js
100
- const updateNotesSource = path.join(__dirname, 'scripts', 'update-release-notes.js');
101
- const updateNotesDest = path.join(releaseScriptDir, 'update-release-notes.js');
100
+ const updateNotesSource = path.join(__dirname, 'scripts', 'update-release-notes.cjs');
101
+ const updateNotesDest = path.join(releaseScriptDir, 'update-release-notes.cjs');
102
102
  if (fs.existsSync(updateNotesSource)) {
103
- fs.copyFileSync(updateNotesSource, updateNotesDest);
103
+ fs.copyFileSync(updateNotesSource, updateNotesDest);
104
104
  }
105
105
 
106
106
  // Copy preload directory
107
107
  const preloadSource = path.join(__dirname, 'scripts', 'preload');
108
108
  const preloadDest = path.join(releaseScriptDir, 'preload');
109
109
  if (fs.existsSync(preloadSource)) {
110
- copyRecursiveSync(preloadSource, preloadDest);
110
+ copyRecursiveSync(preloadSource, preloadDest);
111
111
  }
112
112
  try {
113
113
  fs.chmodSync(releaseScriptPath, 0o755);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@programinglive/commiter",
3
- "version": "1.1.8",
3
+ "version": "1.1.10",
4
4
  "description": "Commiter keeps repositories release-ready by enforcing conventional commits, generating icon-rich changelog entries, and orchestrating semantic version bumps without manual toil. It bootstraps Husky hooks, commitlint rules, and release scripts that inspect history, detect framework-specific test commands, run them automatically, tag git releases, coordinate npm publishing, surface release metrics, enforce project-specific checks, and give maintainers observability across distributed teams. Plus!",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -9,10 +9,10 @@
9
9
  "scripts": {
10
10
  "test": "node --test",
11
11
  "prepare": "husky",
12
- "release": "node scripts/release.js",
13
- "release:major": "node scripts/release.js major",
14
- "release:minor": "node scripts/release.js minor",
15
- "release:patch": "node scripts/release.js patch"
12
+ "release": "node scripts/release.cjs",
13
+ "release:major": "node scripts/release.cjs major",
14
+ "release:minor": "node scripts/release.cjs minor",
15
+ "release:patch": "node scripts/release.cjs patch"
16
16
  },
17
17
  "keywords": [
18
18
  "commit",
@@ -0,0 +1,219 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Create GitHub Releases from Tags and CHANGELOG
5
+ *
6
+ * This script reads the CHANGELOG.md file and creates GitHub releases
7
+ * for all tags that don't have releases yet.
8
+ *
9
+ * Prerequisites:
10
+ * - GitHub Personal Access Token with 'repo' scope
11
+ * - Set as environment variable: GITHUB_TOKEN
12
+ *
13
+ * Usage:
14
+ * GITHUB_TOKEN=your_token node scripts/create-releases.js
15
+ */
16
+
17
+ const fs = require('fs');
18
+ const https = require('https');
19
+ const { execSync } = require('child_process');
20
+
21
+ // Configuration
22
+ const REPO_OWNER = 'programinglive';
23
+ const REPO_NAME = 'commiter';
24
+ const CHANGELOG_PATH = './CHANGELOG.md';
25
+
26
+ // GitHub API helper
27
+ function githubRequest(method, path, data = null) {
28
+ const token = process.env.GITHUB_TOKEN;
29
+
30
+ if (!token) {
31
+ console.error('❌ Error: GITHUB_TOKEN environment variable not set');
32
+ console.error('Please set it with: set GITHUB_TOKEN=your_token_here');
33
+ process.exit(1);
34
+ }
35
+
36
+ return new Promise((resolve, reject) => {
37
+ const options = {
38
+ hostname: 'api.github.com',
39
+ port: 443,
40
+ path: path,
41
+ method: method,
42
+ headers: {
43
+ 'User-Agent': 'Commiter-Release-Script',
44
+ 'Authorization': `token ${token}`,
45
+ 'Accept': 'application/vnd.github.v3+json',
46
+ 'Content-Type': 'application/json'
47
+ }
48
+ };
49
+
50
+ const req = https.request(options, (res) => {
51
+ let body = '';
52
+ res.on('data', (chunk) => body += chunk);
53
+ res.on('end', () => {
54
+ if (res.statusCode >= 200 && res.statusCode < 300) {
55
+ resolve(JSON.parse(body || '{}'));
56
+ } else {
57
+ reject(new Error(`GitHub API error: ${res.statusCode} - ${body}`));
58
+ }
59
+ });
60
+ });
61
+
62
+ req.on('error', reject);
63
+
64
+ if (data) {
65
+ req.write(JSON.stringify(data));
66
+ }
67
+
68
+ req.end();
69
+ });
70
+ }
71
+
72
+ // Parse CHANGELOG.md to extract release notes
73
+ function parseChangelog() {
74
+ const content = fs.readFileSync(CHANGELOG_PATH, 'utf-8');
75
+ const releases = {};
76
+
77
+ // Match version headers like: ### [1.1.9](link) (2025-11-24)
78
+ const versionRegex = /### \[(\d+\.\d+\.\d+)\]\([^)]+\) \(([^)]+)\)/g;
79
+ const sections = content.split(versionRegex);
80
+
81
+ // Process matches
82
+ let match;
83
+ const matches = [];
84
+ while ((match = versionRegex.exec(content)) !== null) {
85
+ matches.push({
86
+ version: match[1],
87
+ date: match[2],
88
+ index: match.index
89
+ });
90
+ }
91
+
92
+ // Extract content for each version
93
+ for (let i = 0; i < matches.length; i++) {
94
+ const current = matches[i];
95
+ const next = matches[i + 1];
96
+
97
+ const startIndex = current.index;
98
+ const endIndex = next ? next.index : content.length;
99
+
100
+ let releaseContent = content.substring(startIndex, endIndex).trim();
101
+
102
+ // Remove the version header line
103
+ releaseContent = releaseContent.split('\n').slice(1).join('\n').trim();
104
+
105
+ // Clean up the content
106
+ releaseContent = releaseContent
107
+ .replace(/###\s+\[(\d+\.\d+\.\d+)\].*$/m, '') // Remove next version header if present
108
+ .trim();
109
+
110
+ releases[current.version] = {
111
+ version: current.version,
112
+ date: current.date,
113
+ body: releaseContent || 'See CHANGELOG.md for details.'
114
+ };
115
+ }
116
+
117
+ return releases;
118
+ }
119
+
120
+ // Get all local tags
121
+ function getLocalTags() {
122
+ try {
123
+ const output = execSync('git tag -l', { encoding: 'utf-8' });
124
+ return output.trim().split('\n').filter(Boolean);
125
+ } catch (error) {
126
+ console.error('❌ Error getting local tags:', error.message);
127
+ return [];
128
+ }
129
+ }
130
+
131
+ // Get existing GitHub releases
132
+ async function getExistingReleases() {
133
+ try {
134
+ const releases = await githubRequest('GET', `/repos/${REPO_OWNER}/${REPO_NAME}/releases`);
135
+ return new Set(releases.map(r => r.tag_name));
136
+ } catch (error) {
137
+ console.error('❌ Error fetching existing releases:', error.message);
138
+ return new Set();
139
+ }
140
+ }
141
+
142
+ // Create a GitHub release
143
+ async function createRelease(tag, releaseData) {
144
+ const data = {
145
+ tag_name: tag,
146
+ name: `${tag}`,
147
+ body: releaseData.body,
148
+ draft: false,
149
+ prerelease: false
150
+ };
151
+
152
+ try {
153
+ await githubRequest('POST', `/repos/${REPO_OWNER}/${REPO_NAME}/releases`, data);
154
+ console.log(`✅ Created release for ${tag}`);
155
+ return true;
156
+ } catch (error) {
157
+ console.error(`❌ Failed to create release for ${tag}:`, error.message);
158
+ return false;
159
+ }
160
+ }
161
+
162
+ // Main function
163
+ async function main() {
164
+ console.log('🚀 Creating GitHub Releases from CHANGELOG...\n');
165
+
166
+ // Parse changelog
167
+ console.log('📝 Parsing CHANGELOG.md...');
168
+ const releases = parseChangelog();
169
+ console.log(`Found ${Object.keys(releases).length} releases in CHANGELOG\n`);
170
+
171
+ // Get local tags
172
+ console.log('🏷️ Getting local tags...');
173
+ const localTags = getLocalTags();
174
+ console.log(`Found ${localTags.length} local tags\n`);
175
+
176
+ // Get existing GitHub releases
177
+ console.log('🔍 Checking existing GitHub releases...');
178
+ const existingReleases = await getExistingReleases();
179
+ console.log(`Found ${existingReleases.size} existing releases on GitHub\n`);
180
+
181
+ // Create releases for tags that don't have them
182
+ console.log('📦 Creating missing releases...\n');
183
+ let created = 0;
184
+ let skipped = 0;
185
+
186
+ for (const tag of localTags) {
187
+ const version = tag.replace(/^v/, '');
188
+
189
+ if (existingReleases.has(tag)) {
190
+ console.log(`⏭️ Skipping ${tag} (already exists)`);
191
+ skipped++;
192
+ continue;
193
+ }
194
+
195
+ const releaseData = releases[version];
196
+ if (!releaseData) {
197
+ console.log(`⚠️ No changelog entry found for ${tag}, using default message`);
198
+ await createRelease(tag, { body: 'See [CHANGELOG.md](CHANGELOG.md) for details.' });
199
+ created++;
200
+ } else {
201
+ await createRelease(tag, releaseData);
202
+ created++;
203
+ }
204
+
205
+ // Rate limiting: wait 1 second between requests
206
+ await new Promise(resolve => setTimeout(resolve, 1000));
207
+ }
208
+
209
+ console.log(`\n✨ Done!`);
210
+ console.log(` Created: ${created}`);
211
+ console.log(` Skipped: ${skipped}`);
212
+ console.log(`\n🔗 View releases at: https://github.com/${REPO_OWNER}/${REPO_NAME}/releases`);
213
+ }
214
+
215
+ // Run the script
216
+ main().catch(error => {
217
+ console.error('\n❌ Script failed:', error.message);
218
+ process.exit(1);
219
+ });
@@ -4,7 +4,7 @@ const { spawnSync } = require('child_process');
4
4
  const fs = require('fs');
5
5
  const path = require('path');
6
6
 
7
- const { updateReleaseNotes } = require('./update-release-notes');
7
+ const { updateReleaseNotes } = require('./update-release-notes.cjs');
8
8
 
9
9
  const fsFokPreloadPath = path.join(__dirname, 'preload', 'fs-f-ok.cjs');
10
10
  const FS_FOK_PRELOAD_FLAG = buildPreloadFlag(fsFokPreloadPath);
package/web/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # Commiter Website
2
+
3
+ This is the static website for the Commiter project. It can be deployed to any web server or hosting platform.
4
+
5
+ ## 📁 Structure
6
+
7
+ ```
8
+ web/
9
+ ├── index.html # Main landing page
10
+ ├── css/
11
+ │ └── style.css # Styles with modern dark theme
12
+ ├── js/
13
+ │ └── script.js # Interactive features
14
+ └── README.md # This file
15
+ ```
16
+
17
+ ## 🚀 Deployment Options
18
+
19
+ ### Option 1: Plesk / cPanel
20
+ 1. Compress the `web` folder contents into a ZIP file
21
+ 2. Upload to your Plesk/cPanel file manager
22
+ 3. Extract in your public_html or desired directory
23
+ 4. Access via your domain
24
+
25
+ ### Option 2: Static Hosting (Netlify, Vercel, GitHub Pages)
26
+ 1. Push the `web` folder to a Git repository
27
+ 2. Connect to your hosting platform
28
+ 3. Set the build directory to `web`
29
+ 4. Deploy
30
+
31
+ ### Option 3: Simple HTTP Server (Testing)
32
+ ```bash
33
+ # Navigate to the web directory
34
+ cd web
35
+
36
+ # Python 3
37
+ python -m http.server 8000
38
+
39
+ # Node.js (if you have http-server installed)
40
+ npx http-server -p 8000
41
+
42
+ # PHP
43
+ php -S localhost:8000
44
+ ```
45
+
46
+ Then open http://localhost:8000 in your browser.
47
+
48
+ ## 🎨 Features
49
+
50
+ - **Modern Design**: Dark theme with glassmorphism effects
51
+ - **Fully Responsive**: Works on desktop, tablet, and mobile
52
+ - **Smooth Animations**: Scroll animations and transitions
53
+ - **Interactive Elements**: Copy-to-clipboard, smooth scrolling
54
+ - **SEO Optimized**: Meta tags and semantic HTML
55
+ - **Fast Loading**: Optimized CSS and JavaScript
56
+
57
+ ## 🛠️ Customization
58
+
59
+ ### Colors
60
+ Edit CSS variables in `css/style.css`:
61
+ ```css
62
+ :root {
63
+ --primary: #6366f1;
64
+ --secondary: #8b5cf6;
65
+ --accent: #ec4899;
66
+ /* ... more variables */
67
+ }
68
+ ```
69
+
70
+ ### Content
71
+ Edit `index.html` to update:
72
+ - Version numbers
73
+ - Release information
74
+ - Links and URLs
75
+ - Text content
76
+
77
+ ## 📝 License
78
+
79
+ This website is part of the Commiter project and is released under the MIT License.