claw-dashboard 2.1.1 → 2.2.0
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 +29 -1
- package/docs/API.md +1 -2
- package/index.js +31 -41
- package/package.json +22 -12
- package/src/auto-save.js +11 -5
- package/src/cli/export-snapshot.js +3 -1
- package/src/cli/import-snapshot.js +3 -1
- package/src/config.js +9 -15
- package/src/errors.js +0 -9
- package/src/security.js +6 -2
- package/src/snapshot.js +73 -26
- package/src/web-server.js +7 -10
- package/.c8rc.json +0 -38
- package/.dockerignore +0 -68
- package/.github/dependabot.yml +0 -45
- package/.github/pull_request_template.md +0 -39
- package/.github/workflows/ci.yml +0 -147
- package/.github/workflows/release.yml +0 -40
- package/.github/workflows/security.yml +0 -84
- package/.husky/pre-commit +0 -1
- package/.planning/codebase/ARCHITECTURE.md +0 -206
- package/.planning/codebase/INTEGRATIONS.md +0 -150
- package/.planning/codebase/STACK.md +0 -122
- package/.planning/codebase/STRUCTURE.md +0 -201
- package/CONTRIBUTING.md +0 -378
- package/Dockerfile +0 -54
- package/FEATURES.md +0 -307
- package/TODO.md +0 -28
- package/ai.openclaw.dashboard.plist +0 -35
- package/build-cjs.js +0 -127
- package/cjs-shim.js +0 -13
- package/dist/clawdash +0 -1729
- package/dist/clawdash.meta.json +0 -2236
- package/dist/widgets.cjs +0 -6511
- package/docker-compose.yml +0 -67
- package/esbuild.config.js +0 -158
- package/eslint.config.js +0 -56
- package/examples/plugins/README.md +0 -122
- package/examples/plugins/api-status/index.js +0 -294
- package/examples/plugins/api-status/plugin.json +0 -19
- package/examples/plugins/hello-world/index.js +0 -104
- package/examples/plugins/hello-world/plugin.json +0 -15
- package/examples/plugins/system-metrics-chart/index.js +0 -339
- package/examples/plugins/system-metrics-chart/plugin.json +0 -18
- package/examples/plugins/weather-widget/index.js +0 -136
- package/examples/plugins/weather-widget/plugin.json +0 -19
- package/index.cjs +0 -23005
- package/jest.config.js +0 -11
- package/scripts/release.js +0 -595
- package/src/database.js +0 -734
- package/tests/alerts.test.js +0 -437
- package/tests/auto-save.test.js +0 -529
- package/tests/cache.test.js +0 -317
- package/tests/cli.test.js +0 -351
- package/tests/command-palette.test.js +0 -320
- package/tests/config-processor.test.js +0 -452
- package/tests/config-validator.test.js +0 -710
- package/tests/config-watcher.test.js +0 -594
- package/tests/config.test.js +0 -755
- package/tests/database.test.js +0 -438
- package/tests/errors.test.js +0 -189
- package/tests/example-plugins.test.js +0 -624
- package/tests/integration.test.js +0 -1321
- package/tests/loading-states.test.js +0 -300
- package/tests/manifest-validation-on-load.test.js +0 -671
- package/tests/performance-monitor.test.js +0 -190
- package/tests/plugin-api-rate-limit.test.js +0 -302
- package/tests/plugin-errors.test.js +0 -311
- package/tests/plugin-lifecycle-e2e.test.js +0 -1036
- package/tests/plugin-reload.test.js +0 -764
- package/tests/rate-limiter.test.js +0 -539
- package/tests/removed-dependencies.test.js +0 -74
- package/tests/retry.test.js +0 -308
- package/tests/security.test.js +0 -411
- package/tests/settings-modal.test.js +0 -226
- package/tests/theme-selector.test.js +0 -57
- package/tests/utils.js +0 -242
- package/tests/utils.test.js +0 -317
- package/tests/validate-plugin-cli.test.js +0 -359
- package/tests/validation.test.js +0 -837
- package/tests/web-server.test.js +0 -646
- package/tests/widget-arrange-mode.test.js +0 -183
- package/tests/widget-config-hot-reload.test.js +0 -465
- package/tests/widget-dependency.test.js +0 -591
- package/tests/widget-error-boundary.test.js +0 -749
- package/tests/widget-error-isolation.test.js +0 -469
- package/tests/widget-integration.test.js +0 -1147
- package/tests/widget-refresh-intervals.test.js +0 -284
- package/tests/worker-pool.test.js +0 -522
package/jest.config.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
testEnvironment: 'node',
|
|
3
|
-
transform: {},
|
|
4
|
-
moduleFileExtensions: ['js', 'mjs'],
|
|
5
|
-
testMatch: ['**/tests/**/*.test.js'],
|
|
6
|
-
// c8 handles coverage - Jest coverage disabled
|
|
7
|
-
collectCoverage: false,
|
|
8
|
-
coverageProvider: 'v8',
|
|
9
|
-
verbose: true,
|
|
10
|
-
testTimeout: 10000,
|
|
11
|
-
};
|
package/scripts/release.js
DELETED
|
@@ -1,595 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Automated Release Script for claw-dashboard
|
|
5
|
-
*
|
|
6
|
-
* This script automates the release process:
|
|
7
|
-
* 1. Validates the working directory is clean
|
|
8
|
-
* 2. Bumps version in package.json (patch/minor/major)
|
|
9
|
-
* 3. Updates CHANGELOG.md with new version entry
|
|
10
|
-
* 4. Builds the project with ESBuild
|
|
11
|
-
* 5. Creates GPG-signed git tag
|
|
12
|
-
* 6. Optionally creates GitHub release
|
|
13
|
-
*
|
|
14
|
-
* Usage:
|
|
15
|
-
* node scripts/release.js [patch|minor|major] [--sign] [--github]
|
|
16
|
-
*
|
|
17
|
-
* Options:
|
|
18
|
-
* patch, minor, major - Version bump type (default: patch)
|
|
19
|
-
* --sign, -s - GPG sign the release tag and artifacts
|
|
20
|
-
* --github, -g - Create GitHub release (requires gh CLI)
|
|
21
|
-
* --dry-run, -d - Preview changes without executing
|
|
22
|
-
* --help, -h - Show help
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
import { execSync } from 'child_process';
|
|
26
|
-
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
27
|
-
import { join, dirname } from 'path';
|
|
28
|
-
import { fileURLToPath } from 'url';
|
|
29
|
-
|
|
30
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
31
|
-
const __dirname = dirname(__filename);
|
|
32
|
-
const ROOT = join(__dirname, '..');
|
|
33
|
-
|
|
34
|
-
// Colors for output
|
|
35
|
-
const colors = {
|
|
36
|
-
reset: '\x1b[0m',
|
|
37
|
-
bright: '\x1b[1m',
|
|
38
|
-
green: '\x1b[32m',
|
|
39
|
-
yellow: '\x1b[33m',
|
|
40
|
-
red: '\x1b[31m',
|
|
41
|
-
cyan: '\x1b[36m',
|
|
42
|
-
gray: '\x1b[90m',
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Print styled message
|
|
47
|
-
*/
|
|
48
|
-
function log(message, type = 'info') {
|
|
49
|
-
const prefix = {
|
|
50
|
-
info: `${colors.cyan}ℹ${colors.reset}`,
|
|
51
|
-
success: `${colors.green}✓${colors.reset}`,
|
|
52
|
-
warning: `${colors.yellow}⚠${colors.reset}`,
|
|
53
|
-
error: `${colors.red}✗${colors.reset}`,
|
|
54
|
-
step: `${colors.bright}→${colors.reset}`,
|
|
55
|
-
}[type] || 'ℹ';
|
|
56
|
-
|
|
57
|
-
console.log(`${prefix} ${message}`);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Execute command with error handling
|
|
62
|
-
*/
|
|
63
|
-
function exec(command, options = {}) {
|
|
64
|
-
try {
|
|
65
|
-
return execSync(command, {
|
|
66
|
-
encoding: 'utf8',
|
|
67
|
-
cwd: ROOT,
|
|
68
|
-
stdio: options.silent ? 'pipe' : 'inherit',
|
|
69
|
-
...options,
|
|
70
|
-
});
|
|
71
|
-
} catch (error) {
|
|
72
|
-
if (!options.ignoreErrors) {
|
|
73
|
-
throw new Error(`Command failed: ${command}\n${error.message}`);
|
|
74
|
-
}
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Parse command line arguments
|
|
81
|
-
*/
|
|
82
|
-
function parseArgs() {
|
|
83
|
-
const args = process.argv.slice(2);
|
|
84
|
-
const result = {
|
|
85
|
-
bumpType: 'patch',
|
|
86
|
-
sign: false,
|
|
87
|
-
github: false,
|
|
88
|
-
dryRun: false,
|
|
89
|
-
help: false,
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
for (const arg of args) {
|
|
93
|
-
switch (arg) {
|
|
94
|
-
case 'patch':
|
|
95
|
-
case 'minor':
|
|
96
|
-
case 'major':
|
|
97
|
-
result.bumpType = arg;
|
|
98
|
-
break;
|
|
99
|
-
case '--sign':
|
|
100
|
-
case '-s':
|
|
101
|
-
result.sign = true;
|
|
102
|
-
break;
|
|
103
|
-
case '--github':
|
|
104
|
-
case '-g':
|
|
105
|
-
result.github = true;
|
|
106
|
-
break;
|
|
107
|
-
case '--dry-run':
|
|
108
|
-
case '-d':
|
|
109
|
-
result.dryRun = true;
|
|
110
|
-
break;
|
|
111
|
-
case '--help':
|
|
112
|
-
case '-h':
|
|
113
|
-
result.help = true;
|
|
114
|
-
break;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return result;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Show help message
|
|
123
|
-
*/
|
|
124
|
-
function showHelp() {
|
|
125
|
-
console.log(`
|
|
126
|
-
${colors.bright}Release Script for claw-dashboard${colors.reset}
|
|
127
|
-
|
|
128
|
-
Automates the release process with version bumping, building, and signing.
|
|
129
|
-
|
|
130
|
-
${colors.bright}Usage:${colors.reset}
|
|
131
|
-
node scripts/release.js [patch|minor|major] [options]
|
|
132
|
-
|
|
133
|
-
${colors.bright}Version Types:${colors.reset}
|
|
134
|
-
patch Increment patch version (1.0.0 → 1.0.1) [default]
|
|
135
|
-
minor Increment minor version (1.0.0 → 1.1.0)
|
|
136
|
-
major Increment major version (1.0.0 → 2.0.0)
|
|
137
|
-
|
|
138
|
-
${colors.bright}Options:${colors.reset}
|
|
139
|
-
--sign, -s GPG sign the release tag and artifacts
|
|
140
|
-
--github, -g Create GitHub release (requires gh CLI)
|
|
141
|
-
--dry-run, -d Preview changes without executing
|
|
142
|
-
--help, -h Show this help message
|
|
143
|
-
|
|
144
|
-
${colors.bright}Examples:${colors.reset}
|
|
145
|
-
node scripts/release.js patch # Patch release
|
|
146
|
-
node scripts/release.js minor --sign # Minor release with GPG signing
|
|
147
|
-
node scripts/release.js major --github # Major release with GitHub release
|
|
148
|
-
node scripts/release.js --dry-run # Preview changes
|
|
149
|
-
|
|
150
|
-
${colors.bright}Requirements for signing:${colors.reset}
|
|
151
|
-
- GPG key configured: git config --global user.signingkey YOUR_KEY_ID
|
|
152
|
-
- GPG key added to GitHub: https://github.com/settings/gpg/new
|
|
153
|
-
`);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Check if working directory is clean
|
|
158
|
-
*/
|
|
159
|
-
function checkWorkingDirectory() {
|
|
160
|
-
log('Checking working directory status...', 'step');
|
|
161
|
-
|
|
162
|
-
try {
|
|
163
|
-
const status = exec('git status --porcelain', { silent: true });
|
|
164
|
-
if (status && status.trim()) {
|
|
165
|
-
throw new Error('Working directory is not clean. Please commit or stash changes first.');
|
|
166
|
-
}
|
|
167
|
-
log('Working directory is clean', 'success');
|
|
168
|
-
} catch (error) {
|
|
169
|
-
if (error.message.includes('not a git repository')) {
|
|
170
|
-
throw new Error('Not a git repository');
|
|
171
|
-
}
|
|
172
|
-
throw error;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Get current version from package.json
|
|
178
|
-
*/
|
|
179
|
-
function getCurrentVersion() {
|
|
180
|
-
const pkgPath = join(ROOT, 'package.json');
|
|
181
|
-
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
|
|
182
|
-
return pkg.version;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Bump version based on type
|
|
187
|
-
*/
|
|
188
|
-
function bumpVersion(currentVersion, bumpType) {
|
|
189
|
-
const parts = currentVersion.split('.').map(Number);
|
|
190
|
-
const [major, minor, patch] = parts;
|
|
191
|
-
|
|
192
|
-
switch (bumpType) {
|
|
193
|
-
case 'major':
|
|
194
|
-
return `${major + 1}.0.0`;
|
|
195
|
-
case 'minor':
|
|
196
|
-
return `${major}.${minor + 1}.0`;
|
|
197
|
-
case 'patch':
|
|
198
|
-
default:
|
|
199
|
-
return `${major}.${minor}.${patch + 1}`;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Update version in package.json
|
|
205
|
-
*/
|
|
206
|
-
function updatePackageVersion(newVersion, dryRun) {
|
|
207
|
-
log(`Updating package.json to v${newVersion}...`, 'step');
|
|
208
|
-
|
|
209
|
-
const pkgPath = join(ROOT, 'package.json');
|
|
210
|
-
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
|
|
211
|
-
const oldVersion = pkg.version;
|
|
212
|
-
pkg.version = newVersion;
|
|
213
|
-
|
|
214
|
-
if (dryRun) {
|
|
215
|
-
log(`[DRY-RUN] Would update version: ${oldVersion} → ${newVersion}`, 'warning');
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
|
|
220
|
-
log(`Version updated: ${oldVersion} → ${newVersion}`, 'success');
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Get latest changelog entry
|
|
225
|
-
*/
|
|
226
|
-
function getLatestChangelogEntry() {
|
|
227
|
-
const changelogPath = join(ROOT, 'CHANGELOG.md');
|
|
228
|
-
if (!existsSync(changelogPath)) {
|
|
229
|
-
return null;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const content = readFileSync(changelogPath, 'utf8');
|
|
233
|
-
const unreleasedMatch = content.match(/## \[Unreleased\]([\s\S]*?)(?=## \[|$)/);
|
|
234
|
-
|
|
235
|
-
if (unreleasedMatch) {
|
|
236
|
-
return unreleasedMatch[1].trim();
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
return null;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* Update CHANGELOG.md
|
|
244
|
-
*/
|
|
245
|
-
function updateChangelog(newVersion, dryRun) {
|
|
246
|
-
log('Updating CHANGELOG.md...', 'step');
|
|
247
|
-
|
|
248
|
-
const changelogPath = join(ROOT, 'CHANGELOG.md');
|
|
249
|
-
if (!existsSync(changelogPath)) {
|
|
250
|
-
log('CHANGELOG.md not found, skipping', 'warning');
|
|
251
|
-
return null;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
const today = new Date().toISOString().split('T')[0];
|
|
255
|
-
const unreleasedSection = getLatestChangelogEntry();
|
|
256
|
-
|
|
257
|
-
let content = readFileSync(changelogPath, 'utf8');
|
|
258
|
-
|
|
259
|
-
// Replace [Unreleased] link with new version
|
|
260
|
-
const unreleasedLink = `[Unreleased]: https://github.com/spleck/claw-dashboard/compare/v${newVersion}...HEAD`;
|
|
261
|
-
const newVersionLink = `[${newVersion}]: https://github.com/spleck/claw-dashboard/compare/v${getCurrentVersion()}...v${newVersion}`;
|
|
262
|
-
|
|
263
|
-
content = content.replace(
|
|
264
|
-
/## \[Unreleased\]/,
|
|
265
|
-
`## [Unreleased]\n\n## [${newVersion}] - ${today}`
|
|
266
|
-
);
|
|
267
|
-
|
|
268
|
-
// Update comparison links at the bottom
|
|
269
|
-
content = content.replace(
|
|
270
|
-
/\[Unreleased\]: .*/,
|
|
271
|
-
`${unreleasedLink}\n${newVersionLink}`
|
|
272
|
-
);
|
|
273
|
-
|
|
274
|
-
if (dryRun) {
|
|
275
|
-
log('[DRY-RUN] Would update CHANGELOG.md', 'warning');
|
|
276
|
-
return unreleasedSection;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
writeFileSync(changelogPath, content);
|
|
280
|
-
log('CHANGELOG.md updated', 'success');
|
|
281
|
-
|
|
282
|
-
return unreleasedSection;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Check if ESBuild is available
|
|
287
|
-
*/
|
|
288
|
-
function checkEsbuild() {
|
|
289
|
-
log('Checking ESBuild availability...', 'step');
|
|
290
|
-
|
|
291
|
-
try {
|
|
292
|
-
exec('npx esbuild --version', { silent: true });
|
|
293
|
-
log('ESBuild is available', 'success');
|
|
294
|
-
return true;
|
|
295
|
-
} catch {
|
|
296
|
-
log('ESBuild not found, installing...', 'warning');
|
|
297
|
-
try {
|
|
298
|
-
exec('npm install --save-dev esbuild');
|
|
299
|
-
log('ESBuild installed', 'success');
|
|
300
|
-
return true;
|
|
301
|
-
} catch (error) {
|
|
302
|
-
log('Failed to install ESBuild', 'error');
|
|
303
|
-
return false;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* Build the project
|
|
310
|
-
*/
|
|
311
|
-
function buildProject(dryRun) {
|
|
312
|
-
log('Building project...', 'step');
|
|
313
|
-
|
|
314
|
-
if (dryRun) {
|
|
315
|
-
log('[DRY-RUN] Would run: node esbuild.config.js', 'warning');
|
|
316
|
-
return;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
// Ensure dist directory exists
|
|
320
|
-
const distPath = join(ROOT, 'dist');
|
|
321
|
-
if (!existsSync(distPath)) {
|
|
322
|
-
mkdirSync(distPath, { recursive: true });
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
try {
|
|
326
|
-
exec('node esbuild.config.js');
|
|
327
|
-
log('Build successful', 'success');
|
|
328
|
-
} catch (error) {
|
|
329
|
-
throw new Error(`Build failed: ${error.message}`);
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* Check if GPG is configured
|
|
335
|
-
*/
|
|
336
|
-
function checkGpgConfig() {
|
|
337
|
-
try {
|
|
338
|
-
const signingKey = exec('git config --get user.signingkey', {
|
|
339
|
-
silent: true,
|
|
340
|
-
ignoreErrors: true,
|
|
341
|
-
});
|
|
342
|
-
return signingKey && signingKey.trim();
|
|
343
|
-
} catch {
|
|
344
|
-
return null;
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* Check GPG availability
|
|
350
|
-
*/
|
|
351
|
-
function checkGpg(sign) {
|
|
352
|
-
if (!sign) return true;
|
|
353
|
-
|
|
354
|
-
log('Checking GPG configuration...', 'step');
|
|
355
|
-
|
|
356
|
-
const signingKey = checkGpgConfig();
|
|
357
|
-
if (!signingKey) {
|
|
358
|
-
throw new Error(
|
|
359
|
-
'GPG signing requested but no signing key configured.\n' +
|
|
360
|
-
'Run: git config --global user.signingkey YOUR_KEY_ID'
|
|
361
|
-
);
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
try {
|
|
365
|
-
exec(`gpg --list-keys ${signingKey.trim()}`, { silent: true });
|
|
366
|
-
log(`GPG key found: ${signingKey.trim().substring(0, 16)}...`, 'success');
|
|
367
|
-
return true;
|
|
368
|
-
} catch {
|
|
369
|
-
throw new Error(`GPG key ${signingKey.trim()} not found in keyring`);
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
/**
|
|
374
|
-
* Create GPG signature for artifact
|
|
375
|
-
*/
|
|
376
|
-
function createGpgSignature(filePath, dryRun) {
|
|
377
|
-
if (dryRun) {
|
|
378
|
-
log(`[DRY-RUN] Would sign: ${filePath}`, 'warning');
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
try {
|
|
383
|
-
exec(`gpg --armor --detach-sign --output ${filePath}.asc ${filePath}`, {
|
|
384
|
-
silent: true,
|
|
385
|
-
});
|
|
386
|
-
log(`GPG signature created: ${filePath}.asc`, 'success');
|
|
387
|
-
} catch (error) {
|
|
388
|
-
log(`Failed to sign ${filePath}: ${error.message}`, 'warning');
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
/**
|
|
393
|
-
* Sign release artifacts
|
|
394
|
-
*/
|
|
395
|
-
function signArtifacts(version, dryRun) {
|
|
396
|
-
log('Signing release artifacts...', 'step');
|
|
397
|
-
|
|
398
|
-
const artifacts = [
|
|
399
|
-
join(ROOT, 'dist', 'clawdash'),
|
|
400
|
-
join(ROOT, 'package.json'),
|
|
401
|
-
];
|
|
402
|
-
|
|
403
|
-
for (const artifact of artifacts) {
|
|
404
|
-
if (existsSync(artifact)) {
|
|
405
|
-
createGpgSignature(artifact, dryRun);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
/**
|
|
411
|
-
* Create git commit and tag
|
|
412
|
-
*/
|
|
413
|
-
function createGitTag(version, sign, releaseNotes, dryRun) {
|
|
414
|
-
log('Creating git commit and tag...', 'step');
|
|
415
|
-
|
|
416
|
-
const tagMessage = releaseNotes
|
|
417
|
-
? `Release v${version}\n\n${releaseNotes}`
|
|
418
|
-
: `Release v${version}`;
|
|
419
|
-
|
|
420
|
-
if (dryRun) {
|
|
421
|
-
log('[DRY-RUN] Would create commit: chore: bump version to v' + version, 'warning');
|
|
422
|
-
log(`[DRY-RUN] Would create tag: v${version}${sign ? ' (GPG signed)' : ''}`, 'warning');
|
|
423
|
-
return;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
// Stage changes
|
|
427
|
-
exec('git add package.json CHANGELOG.md');
|
|
428
|
-
|
|
429
|
-
// Create commit
|
|
430
|
-
exec(`git commit -m "chore: bump version to v${version}"`);
|
|
431
|
-
log(`Created commit: chore: bump version to v${version}`, 'success');
|
|
432
|
-
|
|
433
|
-
// Create tag
|
|
434
|
-
const tagCmd = sign
|
|
435
|
-
? `git tag -s v${version} -m "${tagMessage}"`
|
|
436
|
-
: `git tag -a v${version} -m "${tagMessage}"`;
|
|
437
|
-
|
|
438
|
-
exec(tagCmd);
|
|
439
|
-
log(`Created tag: v${version}${sign ? ' (GPG signed)' : ''}`, 'success');
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
/**
|
|
443
|
-
* Check if GitHub CLI is available
|
|
444
|
-
*/
|
|
445
|
-
function checkGhCli() {
|
|
446
|
-
try {
|
|
447
|
-
exec('gh --version', { silent: true });
|
|
448
|
-
return true;
|
|
449
|
-
} catch {
|
|
450
|
-
return false;
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
/**
|
|
455
|
-
* Create GitHub release
|
|
456
|
-
*/
|
|
457
|
-
function createGithubRelease(version, releaseNotes, sign, dryRun) {
|
|
458
|
-
log('Creating GitHub release...', 'step');
|
|
459
|
-
|
|
460
|
-
if (!checkGhCli()) {
|
|
461
|
-
log('GitHub CLI (gh) not found, skipping GitHub release', 'warning');
|
|
462
|
-
log('Install from: https://cli.github.com/', 'info');
|
|
463
|
-
return;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
const title = `v${version}`;
|
|
467
|
-
const notes = releaseNotes || `Release ${title}`;
|
|
468
|
-
|
|
469
|
-
const cmd = [
|
|
470
|
-
'gh release create',
|
|
471
|
-
`v${version}`,
|
|
472
|
-
'--title', `"${title}"`,
|
|
473
|
-
'--notes', `"${notes}"`,
|
|
474
|
-
sign ? '--verify-tag' : '',
|
|
475
|
-
join(ROOT, 'dist', 'clawdash'),
|
|
476
|
-
].filter(Boolean).join(' ');
|
|
477
|
-
|
|
478
|
-
if (dryRun) {
|
|
479
|
-
log('[DRY-RUN] Would run: ' + cmd, 'warning');
|
|
480
|
-
return;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
try {
|
|
484
|
-
exec(cmd);
|
|
485
|
-
log(`GitHub release created: ${title}`, 'success');
|
|
486
|
-
} catch (error) {
|
|
487
|
-
log(`Failed to create GitHub release: ${error.message}`, 'warning');
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
/**
|
|
492
|
-
* Print summary
|
|
493
|
-
*/
|
|
494
|
-
function printSummary(version, bumpType, sign, github, dryRun) {
|
|
495
|
-
console.log(`
|
|
496
|
-
${colors.bright}╔══════════════════════════════════════════╗${colors.reset}
|
|
497
|
-
${colors.bright}║${colors.reset} ${colors.green}Release Summary${colors.reset} ${colors.bright}║${colors.reset}
|
|
498
|
-
${colors.bright}╠══════════════════════════════════════════╣${colors.reset}
|
|
499
|
-
Version: ${colors.cyan}v${version}${colors.reset}
|
|
500
|
-
Type: ${colors.yellow}${bumpType}${colors.reset}
|
|
501
|
-
GPG Sign: ${sign ? colors.green + 'Yes' : colors.gray + 'No'}${colors.reset}
|
|
502
|
-
GitHub: ${github ? colors.green + 'Yes' : colors.gray + 'No'}${colors.reset}
|
|
503
|
-
Mode: ${dryRun ? colors.yellow + 'DRY-RUN' : colors.green + 'LIVE'}${colors.reset}
|
|
504
|
-
${colors.bright}╚══════════════════════════════════════════╝${colors.reset}
|
|
505
|
-
`);
|
|
506
|
-
|
|
507
|
-
if (!dryRun) {
|
|
508
|
-
console.log(`
|
|
509
|
-
Next steps:
|
|
510
|
-
1. Review the changes: git show HEAD
|
|
511
|
-
2. Review the tag: git show v${version}
|
|
512
|
-
3. Push to remote: git push && git push origin v${version}
|
|
513
|
-
`);
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
/**
|
|
518
|
-
* Main execution
|
|
519
|
-
*/
|
|
520
|
-
async function main() {
|
|
521
|
-
const args = parseArgs();
|
|
522
|
-
|
|
523
|
-
if (args.help) {
|
|
524
|
-
showHelp();
|
|
525
|
-
process.exit(0);
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
console.log(`\n${colors.bright}🚀 Starting Release Process${colors.reset}\n`);
|
|
529
|
-
|
|
530
|
-
try {
|
|
531
|
-
// Pre-flight checks
|
|
532
|
-
checkWorkingDirectory();
|
|
533
|
-
|
|
534
|
-
const currentVersion = getCurrentVersion();
|
|
535
|
-
log(`Current version: ${currentVersion}`, 'info');
|
|
536
|
-
|
|
537
|
-
const newVersion = bumpVersion(currentVersion, args.bumpType);
|
|
538
|
-
log(`New version will be: ${newVersion}`, 'info');
|
|
539
|
-
|
|
540
|
-
// Check dependencies
|
|
541
|
-
if (!checkEsbuild()) {
|
|
542
|
-
process.exit(1);
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
if (args.sign && !checkGpg(args.sign)) {
|
|
546
|
-
process.exit(1);
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
if (args.github && !checkGhCli()) {
|
|
550
|
-
log('GitHub CLI not found, but continuing...', 'warning');
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
// Confirmation prompt in non-dry-run mode
|
|
554
|
-
if (!args.dryRun) {
|
|
555
|
-
console.log(`\n${colors.yellow}This will create a new release.${colors.reset}`);
|
|
556
|
-
console.log(`${colors.gray}Use --dry-run to preview changes.${colors.reset}\n`);
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
// Execute release steps
|
|
560
|
-
updatePackageVersion(newVersion, args.dryRun);
|
|
561
|
-
const releaseNotes = updateChangelog(newVersion, args.dryRun);
|
|
562
|
-
buildProject(args.dryRun);
|
|
563
|
-
|
|
564
|
-
if (args.sign) {
|
|
565
|
-
signArtifacts(newVersion, args.dryRun);
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
createGitTag(newVersion, args.sign, releaseNotes, args.dryRun);
|
|
569
|
-
|
|
570
|
-
if (args.github) {
|
|
571
|
-
createGithubRelease(newVersion, releaseNotes, args.sign, args.dryRun);
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
// Summary
|
|
575
|
-
printSummary(newVersion, args.bumpType, args.sign, args.github, args.dryRun);
|
|
576
|
-
|
|
577
|
-
process.exit(0);
|
|
578
|
-
} catch (error) {
|
|
579
|
-
console.error(`\n${colors.red}✗ Release failed:${colors.reset}`, error.message);
|
|
580
|
-
process.exit(1);
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
// Run if called directly
|
|
585
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
586
|
-
main();
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
export {
|
|
590
|
-
bumpVersion,
|
|
591
|
-
checkWorkingDirectory,
|
|
592
|
-
getCurrentVersion,
|
|
593
|
-
updatePackageVersion,
|
|
594
|
-
updateChangelog,
|
|
595
|
-
};
|