@trikhub/cli 0.2.0 → 0.3.1
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/README.md +103 -96
- package/dist/cli.js +12 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/install.d.ts +5 -3
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +78 -88
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/publish.d.ts +6 -1
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +120 -127
- package/dist/commands/publish.js.map +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +16 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/registry.d.ts +12 -4
- package/dist/lib/registry.d.ts.map +1 -1
- package/dist/lib/registry.js +54 -15
- package/dist/lib/registry.js.map +1 -1
- package/dist/types.d.ts +8 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -48,14 +48,15 @@ trik install @scope/trik-name --version 1.2.3
|
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
The install process:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
|
|
52
|
+
1. **Tries npm registry first** - If the package is published to npm, installs via your package manager (npm/pnpm/yarn)
|
|
53
|
+
2. **Falls back to TrikHub registry** - For GitHub-only packages, downloads the tarball from GitHub Releases
|
|
54
|
+
3. Adds the dependency to `package.json` (npm packages use version, TrikHub packages use tarball URL)
|
|
55
|
+
4. Extracts to `node_modules/`
|
|
55
56
|
5. **Validates** the trik (manifest structure, security rules)
|
|
56
|
-
6.
|
|
57
|
+
6. Registers the trik in `.trikhub/config.json`
|
|
57
58
|
|
|
58
|
-
|
|
59
|
+
This hybrid approach means triks work like regular npm packages while supporting GitHub-only distributions.
|
|
59
60
|
|
|
60
61
|
### `trik search <query>`
|
|
61
62
|
|
|
@@ -107,6 +108,23 @@ trik upgrade @acme/article-search
|
|
|
107
108
|
trik upgrade --force
|
|
108
109
|
```
|
|
109
110
|
|
|
111
|
+
### `trik sync`
|
|
112
|
+
|
|
113
|
+
Discover trik packages in `node_modules` and register them in `.trikhub/config.json`.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# Scan node_modules and add triks to config
|
|
117
|
+
trik sync
|
|
118
|
+
|
|
119
|
+
# Preview what would be synced
|
|
120
|
+
trik sync --dry-run
|
|
121
|
+
|
|
122
|
+
# Output as JSON
|
|
123
|
+
trik sync --json
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
This is useful when you manually add a trik to `package.json` and run `npm install`. The sync command will detect the trik and register it.
|
|
127
|
+
|
|
110
128
|
## Authentication
|
|
111
129
|
|
|
112
130
|
### `trik login`
|
|
@@ -168,16 +186,19 @@ trik publish --skip-release
|
|
|
168
186
|
|
|
169
187
|
The CLI will:
|
|
170
188
|
|
|
171
|
-
1. Validate your trik structure (manifest.json, trikhub.json, dist/)
|
|
172
|
-
2. Create
|
|
189
|
+
1. Validate your trik structure (manifest.json, trikhub.json, package.json, dist/)
|
|
190
|
+
2. Create an **npm-compatible tarball** with files inside a `package/` directory
|
|
173
191
|
3. Compute SHA-256 hash for integrity verification
|
|
174
192
|
4. Create a GitHub Release with the tarball attached
|
|
175
193
|
5. Register the trik with the TrikHub registry
|
|
176
194
|
|
|
195
|
+
The tarball format is compatible with npm, so users can install directly via the tarball URL.
|
|
196
|
+
|
|
177
197
|
### Required Files
|
|
178
198
|
|
|
179
199
|
```
|
|
180
200
|
your-trik/
|
|
201
|
+
├── package.json # npm package definition (required)
|
|
181
202
|
├── manifest.json # Trik manifest (required)
|
|
182
203
|
├── trikhub.json # Registry metadata (required)
|
|
183
204
|
├── dist/
|
|
@@ -210,102 +231,59 @@ Triks use scoped names similar to npm:
|
|
|
210
231
|
|
|
211
232
|
**Note:** All trik names are normalized to lowercase. `@Acme/Article-Search` becomes `@acme/article-search`.
|
|
212
233
|
|
|
213
|
-
##
|
|
214
|
-
|
|
215
|
-
The CLI supports both **local** (project-level) and **global** (user-level) configurations. This allows you to have project-specific trik installations or share triks across all projects.
|
|
216
|
-
|
|
217
|
-
### Configuration Resolution
|
|
218
|
-
|
|
219
|
-
When you run a command like `trik install`, the CLI resolves configuration in this order:
|
|
220
|
-
|
|
221
|
-
1. **Local config**: Checks for `.trikhub/config.json` in the current directory
|
|
222
|
-
2. **Global config**: Falls back to `~/.trikhub/config.json` in your home directory
|
|
223
|
-
3. **Setup prompt**: If neither exists, prompts you to choose where to set up
|
|
224
|
-
|
|
225
|
-
```
|
|
226
|
-
$ trik install @acme/article-search
|
|
227
|
-
|
|
228
|
-
No TrikHub configuration found.
|
|
229
|
-
Triks need a place to be installed.
|
|
230
|
-
|
|
231
|
-
? Where would you like to set up TrikHub?
|
|
232
|
-
❯ Global (~/.trikhub) - Available to all projects
|
|
233
|
-
Local (./.trikhub) - Project-specific configuration
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
### Global Configuration (Default)
|
|
237
|
-
|
|
238
|
-
Triks are installed in your home directory and available to all projects:
|
|
239
|
-
|
|
240
|
-
```
|
|
241
|
-
~/.trikhub/
|
|
242
|
-
├── config.json # CLI configuration
|
|
243
|
-
├── triks.lock # Lockfile tracking installed versions
|
|
244
|
-
└── triks/ # Installed triks
|
|
245
|
-
└── @scope/trik-name/
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
### Local Configuration
|
|
234
|
+
## How Triks Work with npm
|
|
249
235
|
|
|
250
|
-
Triks are installed in
|
|
236
|
+
Triks are installed as regular npm packages in your project's `node_modules/`. The CLI tracks which packages are triks in `.trikhub/config.json`.
|
|
251
237
|
|
|
252
|
-
|
|
253
|
-
- Sharing trik configurations with your team (commit `.trikhub/` to git)
|
|
254
|
-
- Isolated environments
|
|
238
|
+
### Project Structure
|
|
255
239
|
|
|
256
240
|
```
|
|
257
241
|
./your-project/
|
|
242
|
+
├── package.json # Trik dependencies listed here
|
|
243
|
+
├── node_modules/
|
|
244
|
+
│ └── @scope/trik-name/ # Trik installed like any npm package
|
|
258
245
|
└── .trikhub/
|
|
259
|
-
|
|
260
|
-
├── triks.lock # Project lockfile
|
|
261
|
-
└── triks/ # Project-specific triks
|
|
262
|
-
└── @scope/trik-name/
|
|
246
|
+
└── config.json # Lists which packages are triks
|
|
263
247
|
```
|
|
264
248
|
|
|
265
|
-
###
|
|
249
|
+
### The Config File
|
|
266
250
|
|
|
267
|
-
|
|
251
|
+
`.trikhub/config.json` tracks which npm packages are triks:
|
|
268
252
|
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
● @acme/article-search v1.0.0
|
|
274
|
-
|
|
275
|
-
# In a directory without local config (uses global)
|
|
276
|
-
$ cd ~
|
|
277
|
-
$ trik list
|
|
278
|
-
Installed triks (5) (global):
|
|
279
|
-
● @acme/other-trik v2.0.0
|
|
253
|
+
```json
|
|
254
|
+
{
|
|
255
|
+
"triks": ["@acme/article-search", "@acme/web-scraper"]
|
|
256
|
+
}
|
|
280
257
|
```
|
|
281
258
|
|
|
282
|
-
|
|
259
|
+
This file is used by the TrikHub Gateway to know which packages to load as triks.
|
|
283
260
|
|
|
284
|
-
|
|
261
|
+
### TrikHub Registry Packages
|
|
285
262
|
|
|
286
|
-
|
|
287
|
-
$ trik install @scope/some-trik
|
|
288
|
-
# When prompted "Use global configuration?", select "No"
|
|
289
|
-
# This will initialize a local .trikhub/ directory
|
|
290
|
-
```
|
|
263
|
+
For packages not published to npm (GitHub-only), the CLI:
|
|
291
264
|
|
|
292
|
-
|
|
265
|
+
1. Downloads the tarball from GitHub Releases
|
|
266
|
+
2. Extracts to `node_modules/`
|
|
267
|
+
3. Adds the tarball URL to `package.json`
|
|
293
268
|
|
|
294
|
-
|
|
269
|
+
```json
|
|
270
|
+
{
|
|
271
|
+
"dependencies": {
|
|
272
|
+
"@acme/article-search": "https://github.com/acme/article-search/releases/download/v1.0.0/article-search-1.0.0.tar.gz"
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
```
|
|
295
276
|
|
|
296
|
-
|
|
297
|
-
|------|-------------|
|
|
298
|
-
| `~/.trikhub/config.json` | CLI configuration |
|
|
299
|
-
| `~/.trikhub/triks.lock` | Lockfile tracking installed versions |
|
|
300
|
-
| `~/.trikhub/triks/` | Installed triks directory |
|
|
277
|
+
This means `npm install` works natively - npm fetches from the tarball URL.
|
|
301
278
|
|
|
302
|
-
|
|
279
|
+
## File Locations
|
|
303
280
|
|
|
304
281
|
| Path | Description |
|
|
305
282
|
|------|-------------|
|
|
306
|
-
|
|
|
307
|
-
| `./.trikhub/
|
|
308
|
-
|
|
|
283
|
+
| `~/.trikhub/config.json` | Global CLI configuration (auth tokens, registry URL) |
|
|
284
|
+
| `./.trikhub/config.json` | Project trik registry (list of trik package names) |
|
|
285
|
+
| `./package.json` | Trik dependencies (managed by npm) |
|
|
286
|
+
| `./node_modules/` | Installed triks (managed by npm) |
|
|
309
287
|
|
|
310
288
|
## Validation
|
|
311
289
|
|
|
@@ -322,26 +300,39 @@ Triks that fail validation are rejected to prevent prompt injection vulnerabilit
|
|
|
322
300
|
|
|
323
301
|
### Registry URL
|
|
324
302
|
|
|
325
|
-
|
|
303
|
+
The registry URL is determined by environment:
|
|
304
|
+
|
|
305
|
+
| Environment | Registry URL |
|
|
306
|
+
| ----------- | ------------ |
|
|
307
|
+
| Production (default) | `https://api.trikhub.com` |
|
|
308
|
+
| Development (`--dev` flag) | `http://localhost:3001` |
|
|
309
|
+
|
|
310
|
+
Use the `--dev` flag for local development:
|
|
326
311
|
|
|
327
312
|
```bash
|
|
328
|
-
|
|
329
|
-
|
|
313
|
+
trik --dev search article
|
|
314
|
+
trik --dev install @scope/name
|
|
315
|
+
```
|
|
330
316
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
317
|
+
Alternatively, set `NODE_ENV=development`:
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
export NODE_ENV=development
|
|
321
|
+
trik search article
|
|
335
322
|
```
|
|
336
323
|
|
|
337
|
-
|
|
324
|
+
You can also override the registry URL with an environment variable:
|
|
338
325
|
|
|
339
|
-
|
|
326
|
+
```bash
|
|
327
|
+
export TRIKHUB_REGISTRY=http://localhost:3000
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Global Config File (`~/.trikhub/config.json`)
|
|
331
|
+
|
|
332
|
+
Stores authentication and CLI settings:
|
|
340
333
|
|
|
341
334
|
```json
|
|
342
335
|
{
|
|
343
|
-
"registry": "https://api.trikhub.com",
|
|
344
|
-
"triksDirectory": ".trikhub/triks",
|
|
345
336
|
"analytics": true,
|
|
346
337
|
"authToken": "...",
|
|
347
338
|
"authExpiresAt": "2026-03-09T11:24:12.401Z",
|
|
@@ -351,13 +342,29 @@ The `config.json` file (either local `.trikhub/config.json` or global `~/.trikhu
|
|
|
351
342
|
|
|
352
343
|
| Field | Description |
|
|
353
344
|
| ----- | ----------- |
|
|
354
|
-
| `registry` | TrikHub registry URL |
|
|
355
|
-
| `triksDirectory` | Where triks are installed (relative to config location for local) |
|
|
356
345
|
| `analytics` | Whether to send anonymous download analytics |
|
|
357
346
|
| `authToken` | Authentication token (set by `trik login`) |
|
|
358
347
|
| `authExpiresAt` | Token expiration timestamp |
|
|
359
348
|
| `publisherUsername` | Authenticated GitHub username |
|
|
360
349
|
|
|
350
|
+
### Project Config File (`.trikhub/config.json`)
|
|
351
|
+
|
|
352
|
+
Tracks which npm packages are triks:
|
|
353
|
+
|
|
354
|
+
```json
|
|
355
|
+
{
|
|
356
|
+
"triks": ["@acme/article-search", "@acme/web-scraper"],
|
|
357
|
+
"trikhub": {
|
|
358
|
+
"@acme/article-search": "1.0.0"
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
| Field | Description |
|
|
364
|
+
| ----- | ----------- |
|
|
365
|
+
| `triks` | List of npm package names that are triks |
|
|
366
|
+
| `trikhub` | Packages installed from TrikHub registry (version tracking) |
|
|
367
|
+
|
|
361
368
|
## Development
|
|
362
369
|
|
|
363
370
|
```bash
|
package/dist/cli.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Command-line interface for managing AI triks.
|
|
6
6
|
*/
|
|
7
7
|
import { Command } from 'commander';
|
|
8
|
+
import { createRequire } from 'module';
|
|
8
9
|
import { installCommand } from './commands/install.js';
|
|
9
10
|
import { listCommand } from './commands/list.js';
|
|
10
11
|
import { searchCommand } from './commands/search.js';
|
|
@@ -14,11 +15,21 @@ import { loginCommand, logoutCommand, whoamiCommand } from './commands/login.js'
|
|
|
14
15
|
import { publishCommand } from './commands/publish.js';
|
|
15
16
|
import { upgradeCommand, upgradeAllCommand } from './commands/upgrade.js';
|
|
16
17
|
import { syncCommand } from './commands/sync.js';
|
|
18
|
+
// Read version from package.json
|
|
19
|
+
const require = createRequire(import.meta.url);
|
|
20
|
+
const pkg = require('../package.json');
|
|
17
21
|
const program = new Command();
|
|
18
22
|
program
|
|
19
23
|
.name('trik')
|
|
20
24
|
.description('TrikHub CLI - Teaching AI new triks')
|
|
21
|
-
.version(
|
|
25
|
+
.version(pkg.version)
|
|
26
|
+
.option('--dev', 'Use development registry (localhost:3001)')
|
|
27
|
+
.hook('preAction', () => {
|
|
28
|
+
// Set NODE_ENV before any command runs if --dev flag is passed
|
|
29
|
+
if (program.opts().dev) {
|
|
30
|
+
process.env.NODE_ENV = 'development';
|
|
31
|
+
}
|
|
32
|
+
});
|
|
22
33
|
// Install command
|
|
23
34
|
program
|
|
24
35
|
.command('install <trik>')
|
|
@@ -75,7 +86,6 @@ program
|
|
|
75
86
|
.description('Publish a trik to the registry')
|
|
76
87
|
.option('-d, --directory <path>', 'Trik directory to publish', '.')
|
|
77
88
|
.option('-t, --tag <version>', 'Version tag (default: from manifest)')
|
|
78
|
-
.option('--skip-release', 'Skip creating GitHub release (for manual upload)')
|
|
79
89
|
.action(publishCommand);
|
|
80
90
|
// Upgrade command
|
|
81
91
|
program
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,MAAM,CAAC;KACZ,WAAW,CAAC,qCAAqC,CAAC;KAClD,OAAO,CAAC,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,9 +5,11 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Workflow:
|
|
7
7
|
* 1. Try npm registry first
|
|
8
|
-
* 2. If not found, fall back to TrikHub registry (
|
|
9
|
-
* 3.
|
|
10
|
-
* 4.
|
|
8
|
+
* 2. If not found, fall back to TrikHub registry (uses git URLs)
|
|
9
|
+
* 3. Verify commit SHA for security
|
|
10
|
+
* 4. Add to package.json as github:owner/repo#tag
|
|
11
|
+
* 5. Run package manager install
|
|
12
|
+
* 6. Update .trikhub/config.json with the trik
|
|
11
13
|
*/
|
|
12
14
|
interface InstallOptions {
|
|
13
15
|
version?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAaH,UAAU,cAAc;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAiVD,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,IAAI,CAAC,CA2Ff"}
|
package/dist/commands/install.js
CHANGED
|
@@ -5,20 +5,19 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Workflow:
|
|
7
7
|
* 1. Try npm registry first
|
|
8
|
-
* 2. If not found, fall back to TrikHub registry (
|
|
9
|
-
* 3.
|
|
10
|
-
* 4.
|
|
8
|
+
* 2. If not found, fall back to TrikHub registry (uses git URLs)
|
|
9
|
+
* 3. Verify commit SHA for security
|
|
10
|
+
* 4. Add to package.json as github:owner/repo#tag
|
|
11
|
+
* 5. Run package manager install
|
|
12
|
+
* 6. Update .trikhub/config.json with the trik
|
|
11
13
|
*/
|
|
12
|
-
import { existsSync,
|
|
14
|
+
import { existsSync, mkdirSync } from 'node:fs';
|
|
13
15
|
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
14
16
|
import { join, dirname } from 'node:path';
|
|
15
17
|
import { spawn } from 'node:child_process';
|
|
16
|
-
import { pipeline } from 'node:stream/promises';
|
|
17
|
-
import { Readable } from 'node:stream';
|
|
18
18
|
import chalk from 'chalk';
|
|
19
19
|
import ora from 'ora';
|
|
20
20
|
import * as semver from 'semver';
|
|
21
|
-
import * as tar from 'tar';
|
|
22
21
|
import { validateManifest } from '@trikhub/manifest';
|
|
23
22
|
import { registry } from '../lib/registry.js';
|
|
24
23
|
const NPM_CONFIG_DIR = '.trikhub';
|
|
@@ -78,6 +77,7 @@ async function readNpmConfig(baseDir) {
|
|
|
78
77
|
const config = JSON.parse(content);
|
|
79
78
|
return {
|
|
80
79
|
triks: Array.isArray(config.triks) ? config.triks : [],
|
|
80
|
+
trikhub: config.trikhub ?? {},
|
|
81
81
|
};
|
|
82
82
|
}
|
|
83
83
|
catch {
|
|
@@ -115,44 +115,67 @@ async function isTrikPackage(packagePath) {
|
|
|
115
115
|
}
|
|
116
116
|
/**
|
|
117
117
|
* Add a trik to the config
|
|
118
|
+
* @param trikhubVersion - If provided, marks this as a TrikHub-only package (not on npm)
|
|
118
119
|
*/
|
|
119
|
-
async function addTrikToConfig(packageName, baseDir) {
|
|
120
|
+
async function addTrikToConfig(packageName, baseDir, trikhubVersion) {
|
|
120
121
|
const config = await readNpmConfig(baseDir);
|
|
121
122
|
if (!config.triks.includes(packageName)) {
|
|
122
123
|
config.triks = [...config.triks, packageName].sort();
|
|
123
|
-
await writeNpmConfig(config, baseDir);
|
|
124
124
|
}
|
|
125
|
+
// Track TrikHub source for reinstallation
|
|
126
|
+
if (trikhubVersion) {
|
|
127
|
+
if (!config.trikhub) {
|
|
128
|
+
config.trikhub = {};
|
|
129
|
+
}
|
|
130
|
+
config.trikhub[packageName] = trikhubVersion;
|
|
131
|
+
}
|
|
132
|
+
await writeNpmConfig(config, baseDir);
|
|
125
133
|
}
|
|
126
134
|
/**
|
|
127
|
-
*
|
|
135
|
+
* Verify that a GitHub tag points to the expected commit SHA
|
|
128
136
|
*/
|
|
129
|
-
async function
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
137
|
+
async function verifyGitHubTagSha(githubRepo, gitTag, expectedSha) {
|
|
138
|
+
try {
|
|
139
|
+
// Use GitHub API to get the tag reference
|
|
140
|
+
const response = await fetch(`https://api.github.com/repos/${githubRepo}/git/refs/tags/${gitTag}`);
|
|
141
|
+
if (!response.ok) {
|
|
142
|
+
if (response.status === 404) {
|
|
143
|
+
return { valid: false };
|
|
144
|
+
}
|
|
145
|
+
throw new Error(`GitHub API error: ${response.status}`);
|
|
146
|
+
}
|
|
147
|
+
const data = await response.json();
|
|
148
|
+
let currentSha = data.object.sha;
|
|
149
|
+
// If it's an annotated tag, we need to dereference it
|
|
150
|
+
if (data.object.type === 'tag') {
|
|
151
|
+
const tagResponse = await fetch(`https://api.github.com/repos/${githubRepo}/git/tags/${currentSha}`);
|
|
152
|
+
if (tagResponse.ok) {
|
|
153
|
+
const tagData = await tagResponse.json();
|
|
154
|
+
currentSha = tagData.object.sha;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
valid: currentSha === expectedSha,
|
|
159
|
+
currentSha,
|
|
160
|
+
};
|
|
136
161
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
162
|
+
catch {
|
|
163
|
+
// If we can't verify, proceed with caution
|
|
164
|
+
return { valid: true };
|
|
140
165
|
}
|
|
141
|
-
const fileStream = createWriteStream(destPath);
|
|
142
|
-
await pipeline(Readable.fromWeb(response.body), fileStream);
|
|
143
166
|
}
|
|
144
167
|
/**
|
|
145
|
-
* Add a dependency to package.json
|
|
168
|
+
* Add a dependency to package.json using git URL format
|
|
146
169
|
*/
|
|
147
|
-
async function addToPackageJson(packageName,
|
|
170
|
+
async function addToPackageJson(packageName, githubRepo, gitTag, baseDir) {
|
|
148
171
|
const packageJsonPath = join(baseDir, 'package.json');
|
|
149
172
|
const content = await readFile(packageJsonPath, 'utf-8');
|
|
150
173
|
const pkg = JSON.parse(content);
|
|
151
174
|
if (!pkg.dependencies) {
|
|
152
175
|
pkg.dependencies = {};
|
|
153
176
|
}
|
|
154
|
-
// Use
|
|
155
|
-
pkg.dependencies[packageName] = `
|
|
177
|
+
// Use GitHub shorthand format - clean and npm/pnpm compatible
|
|
178
|
+
pkg.dependencies[packageName] = `github:${githubRepo}#${gitTag}`;
|
|
156
179
|
await writeFile(packageJsonPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
|
|
157
180
|
}
|
|
158
181
|
/**
|
|
@@ -172,10 +195,9 @@ async function tryNpmInstall(pm, packageSpec, baseDir) {
|
|
|
172
195
|
return { success: false, notFound: isNotFound };
|
|
173
196
|
}
|
|
174
197
|
/**
|
|
175
|
-
* Install from TrikHub registry
|
|
176
|
-
* Extracts directly to node_modules since TrikHub tarballs may not be npm-compatible
|
|
198
|
+
* Install from TrikHub registry using git URLs
|
|
177
199
|
*/
|
|
178
|
-
async function installFromTrikhub(packageName, requestedVersion, baseDir, spinner) {
|
|
200
|
+
async function installFromTrikhub(packageName, requestedVersion, baseDir, pm, spinner) {
|
|
179
201
|
// Fetch trik info from TrikHub registry
|
|
180
202
|
spinner.text = `Fetching ${chalk.cyan(packageName)} from TrikHub registry...`;
|
|
181
203
|
const trikInfo = await registry.getTrik(packageName);
|
|
@@ -212,66 +234,33 @@ async function installFromTrikhub(packageName, requestedVersion, baseDir, spinne
|
|
|
212
234
|
spinner.fail(`Version ${chalk.red(versionToInstall)} not found for ${packageName}`);
|
|
213
235
|
return { success: false };
|
|
214
236
|
}
|
|
215
|
-
//
|
|
216
|
-
spinner.text = `
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const nodeModulesPath = join(baseDir, 'node_modules');
|
|
225
|
-
const packagePath = join(nodeModulesPath, ...packageName.split('/'));
|
|
226
|
-
// Ensure parent directories exist (for scoped packages)
|
|
227
|
-
if (packageName.startsWith('@')) {
|
|
228
|
-
const scopeDir = join(nodeModulesPath, packageName.split('/')[0]);
|
|
229
|
-
if (!existsSync(scopeDir)) {
|
|
230
|
-
mkdirSync(scopeDir, { recursive: true });
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
// Remove existing installation if present
|
|
234
|
-
if (existsSync(packagePath)) {
|
|
235
|
-
rmSync(packagePath, { recursive: true, force: true });
|
|
237
|
+
// Verify the commit SHA hasn't changed (security check)
|
|
238
|
+
spinner.text = `Verifying ${chalk.cyan(packageName)}@${versionToInstall}...`;
|
|
239
|
+
const verification = await verifyGitHubTagSha(trikInfo.githubRepo, versionInfo.gitTag, versionInfo.commitSha);
|
|
240
|
+
if (!verification.valid) {
|
|
241
|
+
spinner.fail(`Security warning: Tag ${versionInfo.gitTag} has been modified!`);
|
|
242
|
+
console.log(chalk.red('\nThe git tag no longer points to the same commit as when it was published.'));
|
|
243
|
+
console.log(chalk.dim(` Expected SHA: ${versionInfo.commitSha}`));
|
|
244
|
+
if (verification.currentSha) {
|
|
245
|
+
console.log(chalk.dim(` Current SHA: ${verification.currentSha}`));
|
|
236
246
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
// Extract tarball to the package directory
|
|
240
|
-
await tar.extract({
|
|
241
|
-
file: tarballPath,
|
|
242
|
-
cwd: packagePath,
|
|
243
|
-
});
|
|
244
|
-
// Create a minimal package.json if one doesn't exist
|
|
245
|
-
const pkgJsonPath = join(packagePath, 'package.json');
|
|
246
|
-
if (!existsSync(pkgJsonPath)) {
|
|
247
|
-
const minimalPkg = {
|
|
248
|
-
name: packageName,
|
|
249
|
-
version: versionToInstall,
|
|
250
|
-
description: trikInfo.description || `TrikHub package: ${packageName}`,
|
|
251
|
-
};
|
|
252
|
-
await writeFile(pkgJsonPath, JSON.stringify(minimalPkg, null, 2) + '\n', 'utf-8');
|
|
253
|
-
}
|
|
254
|
-
// Add to package.json dependencies
|
|
255
|
-
await addToPackageJson(packageName, versionToInstall, baseDir);
|
|
256
|
-
// Report download for analytics
|
|
257
|
-
registry.reportDownload(packageName, versionToInstall);
|
|
258
|
-
return { success: true, version: versionToInstall };
|
|
247
|
+
console.log(chalk.red('\nThis could indicate tampering. Aborting installation.'));
|
|
248
|
+
return { success: false };
|
|
259
249
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
catch {
|
|
271
|
-
// Ignore cleanup errors
|
|
272
|
-
}
|
|
273
|
-
}
|
|
250
|
+
// Add to package.json using git URL format
|
|
251
|
+
spinner.text = `Adding ${chalk.cyan(packageName)}@${versionToInstall} to package.json...`;
|
|
252
|
+
await addToPackageJson(packageName, trikInfo.githubRepo, versionInfo.gitTag, baseDir);
|
|
253
|
+
// Run package manager install
|
|
254
|
+
spinner.text = `Installing ${chalk.cyan(packageName)}@${versionToInstall}...`;
|
|
255
|
+
const installResult = await runCommand(pm, ['install'], baseDir, { silent: true });
|
|
256
|
+
if (installResult.code !== 0) {
|
|
257
|
+
spinner.fail(`Failed to install ${packageName}`);
|
|
258
|
+
console.log(chalk.dim(installResult.stderr));
|
|
259
|
+
return { success: false };
|
|
274
260
|
}
|
|
261
|
+
// Report download for analytics
|
|
262
|
+
registry.reportDownload(packageName, versionToInstall);
|
|
263
|
+
return { success: true, version: versionToInstall };
|
|
275
264
|
}
|
|
276
265
|
export async function installCommand(trikInput, options) {
|
|
277
266
|
const spinner = ora();
|
|
@@ -314,7 +303,7 @@ export async function installCommand(trikInput, options) {
|
|
|
314
303
|
else if (npmResult.notFound) {
|
|
315
304
|
// Not on npm, try TrikHub registry
|
|
316
305
|
spinner.text = `Not found on npm, checking TrikHub registry...`;
|
|
317
|
-
const trikhubResult = await installFromTrikhub(packageName, versionSpec, baseDir, spinner);
|
|
306
|
+
const trikhubResult = await installFromTrikhub(packageName, versionSpec, baseDir, pm, spinner);
|
|
318
307
|
if (trikhubResult.success) {
|
|
319
308
|
spinner.succeed(`Installed ${chalk.green(packageName)}@${trikhubResult.version} from TrikHub`);
|
|
320
309
|
installed = true;
|
|
@@ -334,7 +323,8 @@ export async function installCommand(trikInput, options) {
|
|
|
334
323
|
spinner.start('Checking if package is a trik...');
|
|
335
324
|
const packagePath = join(baseDir, 'node_modules', ...packageName.split('/'));
|
|
336
325
|
if (await isTrikPackage(packagePath)) {
|
|
337
|
-
|
|
326
|
+
// Pass version for TrikHub packages (for sync/upgrade tracking)
|
|
327
|
+
await addTrikToConfig(packageName, baseDir, installedVersion);
|
|
338
328
|
spinner.succeed(`Registered ${chalk.green(packageName)} as a trik`);
|
|
339
329
|
console.log();
|
|
340
330
|
console.log(chalk.dim(` Added to: package.json`));
|