@traceletdev/cli 0.5.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/LICENSE +21 -0
- package/README.md +244 -0
- package/bin/tracelet.js +60 -0
- package/binaries/darwin-arm64/tracelet +0 -0
- package/binaries/darwin-x64/tracelet +0 -0
- package/binaries/linux-arm64/tracelet +0 -0
- package/binaries/linux-x64/tracelet +0 -0
- package/binaries/win32-arm64/tracelet.exe +0 -0
- package/binaries/win32-x64/tracelet.exe +0 -0
- package/package.json +66 -0
- package/scripts/pack-binaries.js +132 -0
- package/scripts/postinstall.js +66 -0
- package/scripts/publish-all.js +116 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Moiz Imran
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# Tracelet
|
|
2
|
+
|
|
3
|
+
> **Small traces. Big clarity.**
|
|
4
|
+
|
|
5
|
+
Tracelet is a modern performance toolkit that brings **Lighthouse-level insight** and **ESLint-level ergonomics** into one seamless workflow.
|
|
6
|
+
|
|
7
|
+
[](https://golang.org/)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- **š Fast** - Every operation completes in seconds
|
|
13
|
+
- **šÆ Deterministic** - Reproducible metrics regardless of environment
|
|
14
|
+
- **š§ Integrated** - Fits into your dev loop, editor, and CI
|
|
15
|
+
- **šļø Transparent** - See what's happening, not just summaries
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
### Install via npm (Recommended)
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Install tracelet CLI
|
|
23
|
+
npm install -D @traceletdev/cli
|
|
24
|
+
|
|
25
|
+
# Install framework plugin (choose one)
|
|
26
|
+
npm install -D @traceletdev/next # for Next.js
|
|
27
|
+
npm install -D @traceletdev/vite # for Vite
|
|
28
|
+
|
|
29
|
+
# Initialize config
|
|
30
|
+
npx tracelet init
|
|
31
|
+
|
|
32
|
+
# Lint
|
|
33
|
+
npx tracelet lint
|
|
34
|
+
|
|
35
|
+
# Probe
|
|
36
|
+
npx tracelet probe http://localhost:3000
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
See [Framework Integration](#framework-integration) below for setup details.
|
|
40
|
+
|
|
41
|
+
### Build from source
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Build
|
|
45
|
+
go build -o tracelet ./cmd/tracelet
|
|
46
|
+
|
|
47
|
+
# Initialize
|
|
48
|
+
./tracelet init
|
|
49
|
+
|
|
50
|
+
# Lint
|
|
51
|
+
./tracelet lint
|
|
52
|
+
|
|
53
|
+
# Probe
|
|
54
|
+
./tracelet probe http://localhost:3000
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## What's Included
|
|
58
|
+
|
|
59
|
+
### š Lint
|
|
60
|
+
|
|
61
|
+
Performance budgets as code. Enforce route-level JavaScript limits with ESLint-style rules.
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
tracelet lint
|
|
65
|
+
# Route JS(gzip) Verdict
|
|
66
|
+
# / 9KB ā
|
|
67
|
+
# /product 47KB ā over budget
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### š Probe
|
|
71
|
+
|
|
72
|
+
Chrome-based performance audits in 2-3 seconds. Collect TTFB, FCP, LCP, CLS, TBT-Lite, FSI.
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
tracelet probe http://localhost:3000 --profile mobile
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### š„ļø HUD
|
|
79
|
+
|
|
80
|
+
Real-time overlay for development. See live performance feedback in your browser.
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
tracelet hud
|
|
84
|
+
# Then add <script src="http://localhost:3111/overlay.js"></script> to your app
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The overlay shows a **Routes** tab (lint budgets), a **Metrics** tab (live Web Vitals), and a
|
|
88
|
+
**Components** tab (React re-render counts). React tracking needs its hook loaded *before* React ā
|
|
89
|
+
add this to `<head>`, before your app bundle:
|
|
90
|
+
|
|
91
|
+
```html
|
|
92
|
+
<script src="http://localhost:3111/hook.js"></script>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
See [`@traceletdev/react`](./packages/tracelet-react/README.md) for the bundled-app (`import`) setup.
|
|
96
|
+
|
|
97
|
+
### š CI
|
|
98
|
+
|
|
99
|
+
Automated checks with baseline comparison. GitHub Action ready.
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
tracelet ci --compare .tracelet/baseline.json --format markdown
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### š VS Code
|
|
106
|
+
|
|
107
|
+
In-editor diagnostics with quick fixes. See issues as you code.
|
|
108
|
+
|
|
109
|
+
Install the extension and get instant feedback on save.
|
|
110
|
+
|
|
111
|
+
## Documentation
|
|
112
|
+
|
|
113
|
+
- [Overview](./docs/overview.md) - Philosophy and features
|
|
114
|
+
- [Configuration](./docs/config.md) - Config reference
|
|
115
|
+
- [Rules](./docs/rules.md) - Rule catalog
|
|
116
|
+
- [API Reference](./docs/api.md) - CLI and programmatic APIs
|
|
117
|
+
- [Framework Adapters](./docs/adapters.md) - Next.js and Vite integration
|
|
118
|
+
|
|
119
|
+
## Framework Integration
|
|
120
|
+
|
|
121
|
+
### Next.js
|
|
122
|
+
|
|
123
|
+
1. Install packages:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npm install -D @traceletdev/cli @traceletdev/next
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
2. Add postbuild script to `package.json`:
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"scripts": {
|
|
134
|
+
"postbuild": "node node_modules/@traceletdev/next/collect.js"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
3. Build your app:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
npm run build
|
|
143
|
+
# Stats automatically collected
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
4. Lint with tracelet:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
npx tracelet lint
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Vite
|
|
153
|
+
|
|
154
|
+
1. Install packages:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
npm install -D @traceletdev/cli @traceletdev/vite
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
2. Add plugin to `vite.config.js`:
|
|
161
|
+
|
|
162
|
+
```js
|
|
163
|
+
import { defineConfig } from 'vite';
|
|
164
|
+
import tracelet from '@traceletdev/vite';
|
|
165
|
+
|
|
166
|
+
export default defineConfig({
|
|
167
|
+
plugins: [
|
|
168
|
+
tracelet(),
|
|
169
|
+
// your other plugins
|
|
170
|
+
],
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
3. Build your app:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
npm run build
|
|
178
|
+
# Stats automatically collected during build
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
4. Lint with tracelet:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
npx tracelet lint
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Adapters (Legacy)
|
|
188
|
+
|
|
189
|
+
For projects not using npm packages, see adapter files in `adapters/` directory:
|
|
190
|
+
|
|
191
|
+
- **Next.js** - `node adapters/next-collect.js` after build
|
|
192
|
+
- **Vite** - Use `adapters/vite-plugin-tracelet.cjs` in `vite.config.js`
|
|
193
|
+
|
|
194
|
+
## Examples
|
|
195
|
+
|
|
196
|
+
See [`examples/`](./examples) ā drop-in [config examples](./examples/config-examples)
|
|
197
|
+
(basic, strict, CI) and pointers to the runnable Next.js/Vite fixture apps.
|
|
198
|
+
|
|
199
|
+
## Development
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
# Run tests
|
|
203
|
+
go test ./tests/integration -v
|
|
204
|
+
|
|
205
|
+
# Build CLI
|
|
206
|
+
go build -o tracelet ./cmd/tracelet
|
|
207
|
+
|
|
208
|
+
# Build VS Code extension
|
|
209
|
+
cd ui/vscode-extension
|
|
210
|
+
npm install
|
|
211
|
+
npm run compile
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Project Structure
|
|
215
|
+
|
|
216
|
+
```
|
|
217
|
+
tracelet/
|
|
218
|
+
āā cmd/tracelet/ # CLI entrypoint
|
|
219
|
+
āā internal/ # Core packages
|
|
220
|
+
ā āā config/ # Config loader
|
|
221
|
+
ā āā lint/ # Linting engine
|
|
222
|
+
ā āā probe/ # Chrome probe
|
|
223
|
+
ā āā hud/ # HUD server
|
|
224
|
+
ā āā ci/ # CI helpers
|
|
225
|
+
ā āā reporters/ # Output formatters
|
|
226
|
+
āā adapters/ # Framework adapters
|
|
227
|
+
āā ui/vscode-extension/ # VS Code extension
|
|
228
|
+
āā tests/ # Tests and fixtures
|
|
229
|
+
āā docs/ # Documentation
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## License
|
|
233
|
+
|
|
234
|
+
MIT
|
|
235
|
+
|
|
236
|
+
## Contributing
|
|
237
|
+
|
|
238
|
+
Contributions welcome! See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines and
|
|
239
|
+
our [Code of Conduct](./CODE_OF_CONDUCT.md). Release history is in
|
|
240
|
+
[CHANGELOG.md](./CHANGELOG.md).
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
**Tracelet** ā performance you can lint.
|
package/bin/tracelet.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
const { spawn } = require('child_process');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
|
|
9
|
+
// Platform detection
|
|
10
|
+
const platform = process.platform;
|
|
11
|
+
const arch = process.arch;
|
|
12
|
+
|
|
13
|
+
// Map Node.js platform/arch to our binary names
|
|
14
|
+
const platformMap = {
|
|
15
|
+
'darwin': platform === 'darwin' ? (arch === 'arm64' ? 'darwin-arm64' : 'darwin-x64') : null,
|
|
16
|
+
'linux': platform === 'linux' ? (arch === 'arm64' ? 'linux-arm64' : 'linux-x64') : null,
|
|
17
|
+
'win32': platform === 'win32' ? (arch === 'arm64' ? 'win32-arm64' : 'win32-x64') : null,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const binaryDir = platformMap[platform] || platformMap[process.platform];
|
|
21
|
+
if (!binaryDir) {
|
|
22
|
+
console.error(`[tracelet] Unsupported platform: ${platform}-${arch}`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const binaryName = platform === 'win32' ? 'tracelet.exe' : 'tracelet';
|
|
27
|
+
const binaryPath = path.join(__dirname, '..', 'binaries', binaryDir, binaryName);
|
|
28
|
+
|
|
29
|
+
// Check if binary exists
|
|
30
|
+
if (!fs.existsSync(binaryPath)) {
|
|
31
|
+
console.error(`[tracelet] Binary not found at ${binaryPath}`);
|
|
32
|
+
console.error(`[tracelet] Please run 'npm run postinstall' or reinstall the package`);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Make binary executable on Unix-like systems
|
|
37
|
+
if (platform !== 'win32') {
|
|
38
|
+
try {
|
|
39
|
+
fs.chmodSync(binaryPath, '755');
|
|
40
|
+
} catch (e) {
|
|
41
|
+
// Ignore if chmod fails
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Spawn binary with forwarded args
|
|
46
|
+
const args = process.argv.slice(2);
|
|
47
|
+
const child = spawn(binaryPath, args, {
|
|
48
|
+
stdio: 'inherit',
|
|
49
|
+
cwd: process.cwd(),
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
child.on('error', (err) => {
|
|
53
|
+
console.error(`[tracelet] Failed to spawn binary:`, err.message);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
child.on('exit', (code) => {
|
|
58
|
+
process.exit(code || 0);
|
|
59
|
+
});
|
|
60
|
+
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@traceletdev/cli",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Performance toolkit that brings Lighthouse-level insight and ESLint-level ergonomics",
|
|
5
|
+
"type": "commonjs",
|
|
6
|
+
"main": "bin/tracelet.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"tracelet": "bin/tracelet.js"
|
|
9
|
+
},
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"postinstall": "node scripts/postinstall.js",
|
|
15
|
+
"build:bin": "echo 'Run: goreleaser release --snapshot to build binaries, or use go build'",
|
|
16
|
+
"pack:bin": "node scripts/pack-binaries.js",
|
|
17
|
+
"prepare:publish": "npm run pack:bin && npm run test:packages",
|
|
18
|
+
"test:packages": "echo 'Package structure tests would go here'",
|
|
19
|
+
"publish:all": "node scripts/publish-all.js",
|
|
20
|
+
"publish:dry": "node scripts/publish-all.js --dry-run",
|
|
21
|
+
"format": "prettier --write \"{adapters,packages,scripts,examples}/**/*.{js,cjs,mjs,json}\" \"ui/vscode-extension/src/**/*.ts\" \"*.json\"",
|
|
22
|
+
"format:check": "prettier --check \"{adapters,packages,scripts,examples}/**/*.{js,cjs,mjs,json}\" \"ui/vscode-extension/src/**/*.ts\" \"*.json\"",
|
|
23
|
+
"lint": "eslint .",
|
|
24
|
+
"lint:fix": "eslint . --fix",
|
|
25
|
+
"prepare": "husky"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=18.0.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@eslint/js": "^9.39.4",
|
|
32
|
+
"eslint": "^9.39.4",
|
|
33
|
+
"eslint-config-prettier": "^10.1.8",
|
|
34
|
+
"globals": "^16.5.0",
|
|
35
|
+
"husky": "^9.1.7",
|
|
36
|
+
"prettier": "^3.6.2",
|
|
37
|
+
"typescript": "^5.9.3",
|
|
38
|
+
"typescript-eslint": "^8.62.1"
|
|
39
|
+
},
|
|
40
|
+
"workspaces": [
|
|
41
|
+
"packages/*"
|
|
42
|
+
],
|
|
43
|
+
"keywords": [
|
|
44
|
+
"performance",
|
|
45
|
+
"budgets",
|
|
46
|
+
"linting",
|
|
47
|
+
"monitoring",
|
|
48
|
+
"nextjs",
|
|
49
|
+
"vite",
|
|
50
|
+
"web-vitals"
|
|
51
|
+
],
|
|
52
|
+
"author": "Moiz Imran <moizwasti@gmail.com>",
|
|
53
|
+
"license": "MIT",
|
|
54
|
+
"repository": {
|
|
55
|
+
"type": "git",
|
|
56
|
+
"url": "git+https://github.com/traceletdev/tracelet.git"
|
|
57
|
+
},
|
|
58
|
+
"files": [
|
|
59
|
+
"bin/",
|
|
60
|
+
"binaries/",
|
|
61
|
+
"scripts/",
|
|
62
|
+
"README.md",
|
|
63
|
+
"LICENSE",
|
|
64
|
+
"package.json"
|
|
65
|
+
]
|
|
66
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Pack Go binaries into npm package structure
|
|
10
|
+
*
|
|
11
|
+
* Expects binaries to be built and placed in dist/ directory
|
|
12
|
+
* (by GoReleaser or manual build)
|
|
13
|
+
*
|
|
14
|
+
* Structure:
|
|
15
|
+
* dist/
|
|
16
|
+
* tracelet_darwin_amd64/tracelet
|
|
17
|
+
* tracelet_darwin_arm64/tracelet
|
|
18
|
+
* tracelet_linux_amd64/tracelet
|
|
19
|
+
* tracelet_linux_arm64/tracelet
|
|
20
|
+
* tracelet_windows_amd64/tracelet.exe
|
|
21
|
+
* tracelet_windows_arm64/tracelet.exe
|
|
22
|
+
*
|
|
23
|
+
* Output:
|
|
24
|
+
* binaries/
|
|
25
|
+
* darwin-x64/tracelet
|
|
26
|
+
* darwin-arm64/tracelet
|
|
27
|
+
* linux-x64/tracelet
|
|
28
|
+
* linux-arm64/tracelet
|
|
29
|
+
* win32-x64/tracelet.exe
|
|
30
|
+
* win32-arm64/tracelet.exe
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
const distDir = path.join(__dirname, '..', 'dist');
|
|
34
|
+
const binariesDir = path.join(__dirname, '..', 'binaries');
|
|
35
|
+
|
|
36
|
+
// Map from GoReleaser naming to npm naming
|
|
37
|
+
const platformMap = {
|
|
38
|
+
darwin: {
|
|
39
|
+
amd64: { dir: 'darwin-x64', name: 'tracelet' },
|
|
40
|
+
arm64: { dir: 'darwin-arm64', name: 'tracelet' },
|
|
41
|
+
},
|
|
42
|
+
linux: {
|
|
43
|
+
amd64: { dir: 'linux-x64', name: 'tracelet' },
|
|
44
|
+
arm64: { dir: 'linux-arm64', name: 'tracelet' },
|
|
45
|
+
},
|
|
46
|
+
windows: {
|
|
47
|
+
amd64: { dir: 'win32-x64', name: 'tracelet.exe' },
|
|
48
|
+
arm64: { dir: 'win32-arm64', name: 'tracelet.exe' },
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
function packBinaries() {
|
|
53
|
+
if (!fs.existsSync(distDir)) {
|
|
54
|
+
console.error('dist/ directory not found. Run GoReleaser or build binaries first.');
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Create binaries directory structure
|
|
59
|
+
if (!fs.existsSync(binariesDir)) {
|
|
60
|
+
fs.mkdirSync(binariesDir, { recursive: true });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
let packed = 0;
|
|
64
|
+
let skipped = 0;
|
|
65
|
+
|
|
66
|
+
// Find all directories in dist/
|
|
67
|
+
const entries = fs.readdirSync(distDir, { withFileTypes: true });
|
|
68
|
+
|
|
69
|
+
for (const entry of entries) {
|
|
70
|
+
if (!entry.isDirectory()) continue;
|
|
71
|
+
|
|
72
|
+
const dirName = entry.name;
|
|
73
|
+
// Expected format: tracelet_<os>_<arch> or tracelet_<os>_<arch>v7
|
|
74
|
+
const match = dirName.match(/^tracelet_(darwin|linux|windows)_(amd64|arm64)(?:v\d+)?$/);
|
|
75
|
+
if (!match) {
|
|
76
|
+
console.warn(`Skipping unknown directory: ${dirName}`);
|
|
77
|
+
skipped++;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const [, goos, goarch] = match;
|
|
82
|
+
const mapping = platformMap[goos]?.[goarch];
|
|
83
|
+
if (!mapping) {
|
|
84
|
+
console.warn(`No mapping for ${goos}/${goarch}`);
|
|
85
|
+
skipped++;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const sourceDir = path.join(distDir, dirName);
|
|
90
|
+
const sourceBinary = path.join(sourceDir, mapping.name);
|
|
91
|
+
const targetDir = path.join(binariesDir, mapping.dir);
|
|
92
|
+
const targetBinary = path.join(targetDir, mapping.name);
|
|
93
|
+
|
|
94
|
+
if (!fs.existsSync(sourceBinary)) {
|
|
95
|
+
console.warn(`Binary not found: ${sourceBinary}`);
|
|
96
|
+
skipped++;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Create target directory
|
|
101
|
+
if (!fs.existsSync(targetDir)) {
|
|
102
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Copy binary
|
|
106
|
+
fs.copyFileSync(sourceBinary, targetBinary);
|
|
107
|
+
|
|
108
|
+
// Make executable on Unix
|
|
109
|
+
if (goos !== 'windows') {
|
|
110
|
+
fs.chmodSync(targetBinary, '755');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
console.log(`ā Packed ${goos}/${goarch} ā ${mapping.dir}/${mapping.name}`);
|
|
114
|
+
packed++;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (packed === 0 && skipped > 0) {
|
|
118
|
+
console.error('No binaries were packed. Check that dist/ contains built binaries.');
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
console.log(`\nā Packed ${packed} binaries to binaries/`);
|
|
123
|
+
if (skipped > 0) {
|
|
124
|
+
console.warn(`ā Skipped ${skipped} entries`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (require.main === module) {
|
|
129
|
+
packBinaries();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
module.exports = packBinaries;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
// Platform detection
|
|
9
|
+
const platform = process.platform;
|
|
10
|
+
const arch = process.arch;
|
|
11
|
+
|
|
12
|
+
// Map Node.js platform/arch to our binary names
|
|
13
|
+
let binaryDir;
|
|
14
|
+
if (platform === 'darwin') {
|
|
15
|
+
binaryDir = arch === 'arm64' ? 'darwin-arm64' : 'darwin-x64';
|
|
16
|
+
} else if (platform === 'linux') {
|
|
17
|
+
binaryDir = arch === 'arm64' ? 'linux-arm64' : 'linux-x64';
|
|
18
|
+
} else if (platform === 'win32') {
|
|
19
|
+
binaryDir = arch === 'arm64' ? 'win32-arm64' : 'win32-x64';
|
|
20
|
+
} else {
|
|
21
|
+
console.warn(`[tracelet] Unsupported platform: ${platform}-${arch}`);
|
|
22
|
+
process.exit(0);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const binaryName = platform === 'win32' ? 'tracelet.exe' : 'tracelet';
|
|
26
|
+
const sourcePath = path.join(__dirname, '..', 'binaries', binaryDir, binaryName);
|
|
27
|
+
const targetPath = path.join(__dirname, '..', 'node_modules', '.bin', binaryName);
|
|
28
|
+
|
|
29
|
+
// Check if source binary exists
|
|
30
|
+
if (!fs.existsSync(sourcePath)) {
|
|
31
|
+
console.warn(`[tracelet] Binary not found for ${platform}-${arch}, skipping postinstall`);
|
|
32
|
+
console.warn(`[tracelet] You may need to build binaries first`);
|
|
33
|
+
process.exit(0);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Ensure .bin directory exists
|
|
37
|
+
const binDir = path.dirname(targetPath);
|
|
38
|
+
if (!fs.existsSync(binDir)) {
|
|
39
|
+
fs.mkdirSync(binDir, { recursive: true });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Copy or symlink binary
|
|
43
|
+
try {
|
|
44
|
+
// Try symlink first (works on Unix and Windows with proper permissions)
|
|
45
|
+
if (fs.existsSync(targetPath)) {
|
|
46
|
+
fs.unlinkSync(targetPath);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (platform === 'win32') {
|
|
50
|
+
// Windows: copy instead of symlink for better compatibility
|
|
51
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
52
|
+
} else {
|
|
53
|
+
// Unix: use symlink
|
|
54
|
+
fs.symlinkSync(path.relative(binDir, sourcePath), targetPath);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Make executable on Unix
|
|
58
|
+
if (platform !== 'win32') {
|
|
59
|
+
fs.chmodSync(targetPath, '755');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
console.log(`[tracelet] Binary linked successfully for ${platform}-${arch}`);
|
|
63
|
+
} catch (err) {
|
|
64
|
+
console.warn(`[tracelet] Failed to link binary:`, err.message);
|
|
65
|
+
console.warn(`[tracelet] You can still use 'npx tracelet' or the full path`);
|
|
66
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Publish all packages to npm
|
|
7
|
+
*
|
|
8
|
+
* Ensures version sync across packages and publishes:
|
|
9
|
+
* - @traceletdev/cli (main package)
|
|
10
|
+
* - packages/tracelet-next -> @traceletdev/next
|
|
11
|
+
* - packages/tracelet-vite -> @traceletdev/vite
|
|
12
|
+
* - packages/tracelet-react -> @traceletdev/react
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* node scripts/publish-all.js [version]
|
|
16
|
+
*
|
|
17
|
+
* If version is provided, updates all package.json files
|
|
18
|
+
* If not, publishes current versions
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const fs = require('fs');
|
|
22
|
+
const path = require('path');
|
|
23
|
+
const { execSync } = require('child_process');
|
|
24
|
+
|
|
25
|
+
const packages = [
|
|
26
|
+
{ name: '@traceletdev/cli', path: '.' },
|
|
27
|
+
{ name: '@traceletdev/next', path: 'packages/tracelet-next' },
|
|
28
|
+
{ name: '@traceletdev/vite', path: 'packages/tracelet-vite' },
|
|
29
|
+
{ name: '@traceletdev/react', path: 'packages/tracelet-react' },
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
function getVersion(pkgPath) {
|
|
33
|
+
const pkgJsonPath = path.join(pkgPath, 'package.json');
|
|
34
|
+
if (!fs.existsSync(pkgJsonPath)) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8'));
|
|
38
|
+
return pkg.version;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function setVersion(pkgPath, version) {
|
|
42
|
+
const pkgJsonPath = path.join(pkgPath, 'package.json');
|
|
43
|
+
const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8'));
|
|
44
|
+
pkg.version = version;
|
|
45
|
+
fs.writeFileSync(pkgJsonPath, JSON.stringify(pkg, null, 2) + '\n');
|
|
46
|
+
console.log(`ā Updated ${pkg.name} to ${version}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function publishPackage(pkgPath, dryRun = false) {
|
|
50
|
+
const cmd = dryRun ? 'npm publish --dry-run' : 'npm publish';
|
|
51
|
+
console.log(`\nš¦ Publishing ${path.basename(pkgPath)}...`);
|
|
52
|
+
try {
|
|
53
|
+
execSync(cmd, { cwd: pkgPath, stdio: 'inherit' });
|
|
54
|
+
console.log(`ā Published ${path.basename(pkgPath)}`);
|
|
55
|
+
} catch (err) {
|
|
56
|
+
console.error(`ā Failed to publish ${path.basename(pkgPath)}`);
|
|
57
|
+
throw err;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function main() {
|
|
62
|
+
const args = process.argv.slice(2);
|
|
63
|
+
const dryRun = args.includes('--dry-run');
|
|
64
|
+
let newVersion = args.find(arg => !arg.startsWith('--'));
|
|
65
|
+
|
|
66
|
+
// Check if binaries are built
|
|
67
|
+
const binariesDir = path.join(process.cwd(), 'binaries');
|
|
68
|
+
if (!fs.existsSync(binariesDir)) {
|
|
69
|
+
console.warn('ā binaries/ directory not found. Run "npm run pack:bin" first.');
|
|
70
|
+
console.warn('ā Publishing without binaries will result in broken package.');
|
|
71
|
+
if (!dryRun) {
|
|
72
|
+
console.error('ā Aborting publish. Build binaries first.');
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Get current versions
|
|
78
|
+
const versions = packages
|
|
79
|
+
.map(pkg => ({
|
|
80
|
+
...pkg,
|
|
81
|
+
version: getVersion(pkg.path),
|
|
82
|
+
}))
|
|
83
|
+
.filter(pkg => pkg.version !== null);
|
|
84
|
+
|
|
85
|
+
if (versions.length === 0) {
|
|
86
|
+
console.error('No packages found with package.json');
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const currentVersion = versions[0].version;
|
|
91
|
+
console.log(`Current version: ${currentVersion}`);
|
|
92
|
+
|
|
93
|
+
// Update versions if new version provided
|
|
94
|
+
if (newVersion) {
|
|
95
|
+
if (!/^\d+\.\d+\.\d+/.test(newVersion)) {
|
|
96
|
+
console.error('Invalid version format. Use semantic versioning (e.g., 0.5.0)');
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
console.log(`\nš Updating all packages to ${newVersion}...`);
|
|
100
|
+
versions.forEach(pkg => setVersion(pkg.path, newVersion));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Publish packages
|
|
104
|
+
console.log(`\nš Publishing packages${dryRun ? ' (dry run)' : ''}...`);
|
|
105
|
+
versions.forEach(pkg => {
|
|
106
|
+
publishPackage(pkg.path, dryRun);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
console.log('\nā
All packages published successfully!');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (require.main === module) {
|
|
113
|
+
main();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
module.exports = { getVersion, setVersion, publishPackage };
|