ancoder-skill-cli 0.13.27 → 0.13.29
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 +145 -1
- package/bin/targets/skill-cli-darwin-arm64 +0 -0
- package/bin/targets/skill-cli-darwin-x64 +0 -0
- package/bin/targets/skill-cli-linux-arm64 +0 -0
- package/bin/targets/skill-cli-linux-x64 +0 -0
- package/bin/targets/skill-cli-win32-x64.exe +0 -0
- package/package.json +7 -2
- package/scripts/check-bin.js +54 -0
- package/scripts/check-install-host.js +153 -0
- package/scripts/install.ps1 +150 -0
- package/scripts/install.sh +217 -0
- package/scripts/make-install-bundle.js +167 -0
package/README.md
CHANGED
|
@@ -22,6 +22,140 @@ The npm package is self-contained and includes prebuilt binaries for:
|
|
|
22
22
|
|
|
23
23
|
After install, the wrapper selects the correct bundled binary for the current platform automatically.
|
|
24
24
|
|
|
25
|
+
## One-line install (Gitee or intranet)
|
|
26
|
+
|
|
27
|
+
For users who cannot access GitHub, publish the release-only bundle to Gitee or copy these files to an intranet static file server:
|
|
28
|
+
|
|
29
|
+
- `scripts/install.ps1`
|
|
30
|
+
- `scripts/install.sh`
|
|
31
|
+
- `bin/targets/skill-cli-win32-x64.exe`
|
|
32
|
+
- `bin/targets/skill-cli-linux-x64`
|
|
33
|
+
- `bin/targets/skill-cli-linux-arm64`
|
|
34
|
+
- `bin/targets/skill-cli-darwin-arm64`
|
|
35
|
+
- `bin/targets/skill-cli-darwin-x64`
|
|
36
|
+
|
|
37
|
+
Windows users can install the latest Gitee release with PowerShell:
|
|
38
|
+
|
|
39
|
+
```powershell
|
|
40
|
+
irm https://gitee.com/marvin-dev/skill-cli-release/raw/main/scripts/install.ps1 | iex
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
macOS/Linux users can install the latest Gitee release with curl:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
curl -fsSL https://gitee.com/marvin-dev/skill-cli-release/raw/main/scripts/install.sh | bash
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The installer downloads the matching prebuilt binary, installs it as `skill-cli`, runs `skill-cli install`, then runs a lite `doctor` check. No Go toolchain is required.
|
|
50
|
+
|
|
51
|
+
The `raw/main` URL is the moving latest channel. Each GitHub release updates Gitee `main` with the newest install bundle. If you need a reproducible install, pin a specific release tag instead:
|
|
52
|
+
|
|
53
|
+
```powershell
|
|
54
|
+
irm https://gitee.com/marvin-dev/skill-cli-release/raw/v0.13.29/scripts/install.ps1 | iex
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
curl -fsSL https://gitee.com/marvin-dev/skill-cli-release/raw/v0.13.29/scripts/install.sh | bash
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Before sharing the Gitee command externally, make sure both the Gitee `main` branch and the release tag have been updated. The installer in `main` is generated from the latest release bundle.
|
|
62
|
+
|
|
63
|
+
Gitee release checklist:
|
|
64
|
+
|
|
65
|
+
1. Run `go test ./...`, `bash scripts/build-all.sh`, `node scripts/check-bin.js`, and `npm pack --dry-run`.
|
|
66
|
+
2. Commit `bin/targets/`, `scripts/install.ps1`, `scripts/install.sh`, `scripts/make-install-bundle.js`, `scripts/check-install-host.js`, `scripts/check-bin.js`, `scripts/build-all.sh`, `package.json`, `package-lock.json`, `.gitattributes`, and `README.md`.
|
|
67
|
+
3. Push the release tag to GitHub. The GitHub Actions release workflow builds the binaries and syncs a dist-only bundle to `git@gitee.com:marvin-dev/skill-cli-release.git`.
|
|
68
|
+
4. Verify these URLs return `200` before sending the install command:
|
|
69
|
+
- `https://gitee.com/marvin-dev/skill-cli-release/raw/main/scripts/install.ps1`
|
|
70
|
+
- `https://gitee.com/marvin-dev/skill-cli-release/raw/main/scripts/install.sh`
|
|
71
|
+
- `https://gitee.com/marvin-dev/skill-cli-release/raw/main/bin/targets/skill-cli-win32-x64.exe`
|
|
72
|
+
- `https://gitee.com/marvin-dev/skill-cli-release/raw/v0.13.29/scripts/install.ps1`
|
|
73
|
+
- `https://gitee.com/marvin-dev/skill-cli-release/raw/v0.13.29/bin/targets/skill-cli-win32-x64.exe`
|
|
74
|
+
Or run:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
node scripts/check-install-host.js \
|
|
78
|
+
--script-root https://gitee.com/marvin-dev/skill-cli-release/raw/main \
|
|
79
|
+
--base-url https://gitee.com/marvin-dev/skill-cli-release/raw/main/bin/targets
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
5. Share the `raw/main` install command only after the check above passes.
|
|
83
|
+
|
|
84
|
+
GitHub Actions Gitee sync setup:
|
|
85
|
+
|
|
86
|
+
1. Create a dedicated SSH key for the Gitee release-only repo:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
ssh-keygen -t ed25519 -C "github-actions skill-cli-release" -f ~/.ssh/skill-cli-release-gitee
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
2. Add the public key `~/.ssh/skill-cli-release-gitee.pub` to Gitee with write access to `git@gitee.com:marvin-dev/skill-cli-release.git`.
|
|
93
|
+
3. Add the private key content from `~/.ssh/skill-cli-release-gitee` to the GitHub repository secret `GITEE_SSH_PRIVATE_KEY`.
|
|
94
|
+
|
|
95
|
+
The workflow only pushes the generated `dist/install/` bundle to Gitee, so the source repository remains GitHub-only.
|
|
96
|
+
|
|
97
|
+
For private intranet hosting, generate a static install bundle and upload the generated `dist/install/` directory as-is:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npm run install-bundle -- --root https://intranet.example.com/skill-cli
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
That directory contains:
|
|
104
|
+
|
|
105
|
+
- `scripts/install.ps1`
|
|
106
|
+
- `scripts/install.sh`
|
|
107
|
+
- `bin/targets/skill-cli-*`
|
|
108
|
+
- `manifest.json`
|
|
109
|
+
- `README.txt`
|
|
110
|
+
|
|
111
|
+
After uploading `dist/install/` to `https://intranet.example.com/skill-cli/`, users can run:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
node scripts/check-install-host.js --root https://intranet.example.com/skill-cli --all-binaries
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
```powershell
|
|
118
|
+
irm https://intranet.example.com/skill-cli/scripts/install.ps1 | iex
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
curl -fsSL https://intranet.example.com/skill-cli/scripts/install.sh | bash
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
If binaries are hosted somewhere else, point the installer at the directory containing the `skill-cli-*` files:
|
|
126
|
+
|
|
127
|
+
```powershell
|
|
128
|
+
$env:SKILL_CLI_BASE_URL = "https://intranet.example.com/skill-cli/bin/targets"
|
|
129
|
+
irm https://intranet.example.com/skill-cli/scripts/install.ps1 | iex
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
curl -fsSL https://intranet.example.com/skill-cli/scripts/install.sh | \
|
|
134
|
+
bash -s -- --base-url https://intranet.example.com/skill-cli/bin/targets
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Useful options:
|
|
138
|
+
|
|
139
|
+
```powershell
|
|
140
|
+
# Install the binary only, without writing ~/.claude components
|
|
141
|
+
$env:SKILL_CLI_NO_INSTALL = "1"
|
|
142
|
+
irm https://gitee.com/marvin-dev/skill-cli-release/raw/main/scripts/install.ps1 | iex
|
|
143
|
+
|
|
144
|
+
# For a clean smoke test against a temporary Claude directory
|
|
145
|
+
$env:SKILL_CLI_NO_INSTALL = $null
|
|
146
|
+
$env:SKILL_CLI_CLAUDE_DIR = "$PWD\.skill-cli-test-claude"
|
|
147
|
+
irm https://gitee.com/marvin-dev/skill-cli-release/raw/main/scripts/install.ps1 | iex
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
# Install the binary only, without writing ~/.claude components
|
|
152
|
+
curl -fsSL https://gitee.com/marvin-dev/skill-cli-release/raw/main/scripts/install.sh | bash -s -- --no-install
|
|
153
|
+
|
|
154
|
+
# For a clean smoke test against a temporary Claude directory
|
|
155
|
+
curl -fsSL https://gitee.com/marvin-dev/skill-cli-release/raw/main/scripts/install.sh | \
|
|
156
|
+
bash -s -- --claude-dir "$PWD/.skill-cli-test-claude"
|
|
157
|
+
```
|
|
158
|
+
|
|
25
159
|
## Build from source (Go)
|
|
26
160
|
|
|
27
161
|
```bash
|
|
@@ -82,9 +216,19 @@ The evaluator fails the run when critical issues are found or the score is below
|
|
|
82
216
|
|
|
83
217
|
Use `--no-adversarial` if you want the older OMC-only generation behavior.
|
|
84
218
|
|
|
219
|
+
### Generation failure logs
|
|
220
|
+
|
|
221
|
+
Every `skill-cli generate` run writes a local JSONL session log under:
|
|
222
|
+
|
|
223
|
+
```text
|
|
224
|
+
<skills-dir>/.skill-cli/logs/generate/<skill-name>-<timestamp>.jsonl
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
When generation fails, the CLI prints the exact log path. The log records major stages such as Claude binary resolution, scaffold creation, brainstorm probe, loop start/ticks, deterministic gates, repair attempts, and adversarial review failures, including captured command output and error tails for troubleshooting.
|
|
228
|
+
|
|
85
229
|
## Publish to npm
|
|
86
230
|
|
|
87
|
-
Releases are published by GitHub Actions, not by running `npm publish` from a developer machine. The workflow in `.github/workflows/release.yml` runs when a `v*` tag is pushed; it builds the release binaries, creates the GitHub Release, prepares `bin/targets/` for the npm package, and publishes with the repository `NPM_TOKEN` secret.
|
|
231
|
+
Releases are published by GitHub Actions, not by running `npm publish` from a developer machine. The workflow in `.github/workflows/release.yml` runs when a `v*` tag is pushed; it builds the release binaries, creates the GitHub Release, syncs a release-only install bundle to Gitee, prepares `bin/targets/` for the npm package, and publishes with the repository `NPM_TOKEN` secret.
|
|
88
232
|
|
|
89
233
|
1. Bump `package.json` and `package-lock.json` to the intended version.
|
|
90
234
|
2. Run local verification:
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ancoder-skill-cli",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.29",
|
|
4
4
|
"description": "CLI for managing everything-claude-code (ECC) components — agents, skills, commands, rules, hooks, MCP configs. Single binary, all assets embedded.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"skill-cli": "bin/skill-cli.js"
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"scripts": {
|
|
9
9
|
"postinstall": "node scripts/postinstall.js",
|
|
10
10
|
"prepublishOnly": "node scripts/check-bin.js",
|
|
11
|
-
"build": "bash scripts/build-all.sh"
|
|
11
|
+
"build": "bash scripts/build-all.sh",
|
|
12
|
+
"install-bundle": "node scripts/make-install-bundle.js"
|
|
12
13
|
},
|
|
13
14
|
"repository": {
|
|
14
15
|
"type": "git",
|
|
@@ -38,6 +39,10 @@
|
|
|
38
39
|
"files": [
|
|
39
40
|
"bin/skill-cli.js",
|
|
40
41
|
"bin/targets",
|
|
42
|
+
"scripts/install.sh",
|
|
43
|
+
"scripts/install.ps1",
|
|
44
|
+
"scripts/make-install-bundle.js",
|
|
45
|
+
"scripts/check-install-host.js",
|
|
41
46
|
"scripts/postinstall.js",
|
|
42
47
|
"scripts/check-bin.js",
|
|
43
48
|
"README.md",
|
package/scripts/check-bin.js
CHANGED
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const fs = require('fs');
|
|
6
6
|
|
|
7
|
+
const rootDir = path.join(__dirname, '..');
|
|
7
8
|
const binDir = path.join(__dirname, '..', 'bin');
|
|
8
9
|
const targetsDir = path.join(binDir, 'targets');
|
|
10
|
+
const packageJSONPath = path.join(rootDir, 'package.json');
|
|
9
11
|
const expected = [
|
|
10
12
|
'skill-cli-darwin-arm64',
|
|
11
13
|
'skill-cli-darwin-x64',
|
|
@@ -13,6 +15,12 @@ const expected = [
|
|
|
13
15
|
'skill-cli-linux-x64',
|
|
14
16
|
'skill-cli-win32-x64.exe',
|
|
15
17
|
];
|
|
18
|
+
const expectedInstallers = [
|
|
19
|
+
'scripts/install.ps1',
|
|
20
|
+
'scripts/install.sh',
|
|
21
|
+
'scripts/make-install-bundle.js',
|
|
22
|
+
'scripts/check-install-host.js',
|
|
23
|
+
];
|
|
16
24
|
|
|
17
25
|
const missing = expected.filter((name) => !fs.existsSync(path.join(targetsDir, name)));
|
|
18
26
|
|
|
@@ -24,3 +32,49 @@ if (missing.length > 0) {
|
|
|
24
32
|
console.error('Run: bash scripts/build-all.sh');
|
|
25
33
|
process.exit(1);
|
|
26
34
|
}
|
|
35
|
+
|
|
36
|
+
const pkg = JSON.parse(fs.readFileSync(packageJSONPath, 'utf8'));
|
|
37
|
+
const files = new Set(pkg.files || []);
|
|
38
|
+
const missingInstallers = expectedInstallers.filter((name) => !fs.existsSync(path.join(rootDir, name)));
|
|
39
|
+
const missingInstallerFilesEntries = expectedInstallers.filter((name) => !files.has(name));
|
|
40
|
+
|
|
41
|
+
if (missingInstallers.length > 0) {
|
|
42
|
+
console.error('skill-cli: missing one-line installer scripts:');
|
|
43
|
+
for (const name of missingInstallers) {
|
|
44
|
+
console.error(' - ' + name);
|
|
45
|
+
}
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (missingInstallerFilesEntries.length > 0) {
|
|
50
|
+
console.error('skill-cli: package.json files is missing installer scripts:');
|
|
51
|
+
for (const name of missingInstallerFilesEntries) {
|
|
52
|
+
console.error(' - ' + name);
|
|
53
|
+
}
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const installerVersionPatterns = [
|
|
58
|
+
{
|
|
59
|
+
file: 'scripts/install.sh',
|
|
60
|
+
pattern: /DEFAULT_VERSION="([^"]+)"/,
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
file: 'scripts/install.ps1',
|
|
64
|
+
pattern: /\$Version = "([^"]+)"/,
|
|
65
|
+
},
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
for (const item of installerVersionPatterns) {
|
|
69
|
+
const installerPath = path.join(rootDir, item.file);
|
|
70
|
+
const content = fs.readFileSync(installerPath, 'utf8');
|
|
71
|
+
const match = content.match(item.pattern);
|
|
72
|
+
if (!match) {
|
|
73
|
+
console.error(`skill-cli: could not find default version in ${item.file}`);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
if (match[1] !== 'main') {
|
|
77
|
+
console.error(`skill-cli: ${item.file} default version is ${match[1]}, expected main`);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const http = require('http');
|
|
5
|
+
const https = require('https');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
|
|
9
|
+
const rootDir = path.join(__dirname, '..');
|
|
10
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(rootDir, 'package.json'), 'utf8'));
|
|
11
|
+
const version = `v${pkg.version}`;
|
|
12
|
+
|
|
13
|
+
const targets = [
|
|
14
|
+
'skill-cli-darwin-arm64',
|
|
15
|
+
'skill-cli-darwin-x64',
|
|
16
|
+
'skill-cli-linux-arm64',
|
|
17
|
+
'skill-cli-linux-x64',
|
|
18
|
+
'skill-cli-win32-x64.exe',
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
const args = process.argv.slice(2);
|
|
22
|
+
let rootURL = '';
|
|
23
|
+
let scriptRoot = '';
|
|
24
|
+
let binaryBaseURL = '';
|
|
25
|
+
let includeAllBinaries = false;
|
|
26
|
+
|
|
27
|
+
function usage() {
|
|
28
|
+
console.log(`Usage:
|
|
29
|
+
node scripts/check-install-host.js --root URL [--all-binaries]
|
|
30
|
+
node scripts/check-install-host.js --script-root URL --base-url URL [--all-binaries]
|
|
31
|
+
|
|
32
|
+
Examples:
|
|
33
|
+
node scripts/check-install-host.js --root https://intranet.example.com/skill-cli
|
|
34
|
+
node scripts/check-install-host.js \\
|
|
35
|
+
--script-root https://gitee.com/marvin-dev/skill-cli-release/raw/main \\
|
|
36
|
+
--base-url https://gitee.com/marvin-dev/skill-cli-release/raw/main/bin/targets
|
|
37
|
+
|
|
38
|
+
Checks installer scripts and the Windows binary by default. Pass --all-binaries
|
|
39
|
+
to verify every bundled platform binary.`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
43
|
+
const arg = args[i];
|
|
44
|
+
if (arg === '--root') {
|
|
45
|
+
rootURL = args[i + 1] || '';
|
|
46
|
+
i += 1;
|
|
47
|
+
} else if (arg === '--script-root') {
|
|
48
|
+
scriptRoot = args[i + 1] || '';
|
|
49
|
+
i += 1;
|
|
50
|
+
} else if (arg === '--base-url') {
|
|
51
|
+
binaryBaseURL = args[i + 1] || '';
|
|
52
|
+
i += 1;
|
|
53
|
+
} else if (arg === '--all-binaries') {
|
|
54
|
+
includeAllBinaries = true;
|
|
55
|
+
} else if (arg === '-h' || arg === '--help') {
|
|
56
|
+
usage();
|
|
57
|
+
process.exit(0);
|
|
58
|
+
} else {
|
|
59
|
+
console.error(`unknown option: ${arg}`);
|
|
60
|
+
usage();
|
|
61
|
+
process.exit(2);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function trimSlash(value) {
|
|
66
|
+
return value.replace(/\/+$/, '');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (rootURL) {
|
|
70
|
+
rootURL = trimSlash(rootURL);
|
|
71
|
+
scriptRoot = `${rootURL}`;
|
|
72
|
+
binaryBaseURL = `${rootURL}/bin/targets`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!scriptRoot || !binaryBaseURL) {
|
|
76
|
+
console.error('missing --root, or both --script-root and --base-url');
|
|
77
|
+
usage();
|
|
78
|
+
process.exit(2);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
scriptRoot = trimSlash(scriptRoot);
|
|
82
|
+
binaryBaseURL = trimSlash(binaryBaseURL);
|
|
83
|
+
|
|
84
|
+
const checks = [
|
|
85
|
+
`${scriptRoot}/scripts/install.ps1`,
|
|
86
|
+
`${scriptRoot}/scripts/install.sh`,
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
const binaryNames = includeAllBinaries ? targets : ['skill-cli-win32-x64.exe'];
|
|
90
|
+
for (const target of binaryNames) {
|
|
91
|
+
checks.push(`${binaryBaseURL}/${target}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function request(url, method, redirectsRemaining = 5) {
|
|
95
|
+
return new Promise((resolve) => {
|
|
96
|
+
const lib = url.startsWith('https:') ? https : http;
|
|
97
|
+
const req = lib.request(url, { method, timeout: 15000 }, (res) => {
|
|
98
|
+
if (
|
|
99
|
+
res.statusCode >= 300 &&
|
|
100
|
+
res.statusCode < 400 &&
|
|
101
|
+
res.headers.location &&
|
|
102
|
+
redirectsRemaining > 0
|
|
103
|
+
) {
|
|
104
|
+
res.resume();
|
|
105
|
+
const redirectedURL = new URL(res.headers.location, url).toString();
|
|
106
|
+
resolve(request(redirectedURL, method, redirectsRemaining - 1));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
res.resume();
|
|
111
|
+
res.on('end', () => {
|
|
112
|
+
resolve({
|
|
113
|
+
url,
|
|
114
|
+
statusCode: res.statusCode || 0,
|
|
115
|
+
contentLength: res.headers['content-length'] || '',
|
|
116
|
+
ok: res.statusCode >= 200 && res.statusCode < 300,
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
req.on('timeout', () => {
|
|
121
|
+
req.destroy(new Error('timeout'));
|
|
122
|
+
});
|
|
123
|
+
req.on('error', (err) => {
|
|
124
|
+
resolve({ url, statusCode: 0, contentLength: '', ok: false, error: err.message });
|
|
125
|
+
});
|
|
126
|
+
req.end();
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async function checkURL(url) {
|
|
131
|
+
const head = await request(url, 'HEAD');
|
|
132
|
+
if (head.ok) {
|
|
133
|
+
return head;
|
|
134
|
+
}
|
|
135
|
+
const get = await request(url, 'GET');
|
|
136
|
+
return get.ok ? get : head;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
(async () => {
|
|
140
|
+
let failed = false;
|
|
141
|
+
for (const url of checks) {
|
|
142
|
+
const result = await checkURL(url);
|
|
143
|
+
if (result.ok) {
|
|
144
|
+
const size = result.contentLength ? ` (${result.contentLength} bytes)` : '';
|
|
145
|
+
console.log(`OK ${url}${size}`);
|
|
146
|
+
} else {
|
|
147
|
+
failed = true;
|
|
148
|
+
const detail = result.error ? result.error : `HTTP ${result.statusCode}`;
|
|
149
|
+
console.error(`FAIL ${url} - ${detail}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
process.exit(failed ? 1 : 0);
|
|
153
|
+
})();
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[string]$BaseUrl = $env:SKILL_CLI_BASE_URL,
|
|
3
|
+
[string]$Version = $env:SKILL_CLI_VERSION,
|
|
4
|
+
[string]$InstallDir = $env:SKILL_CLI_INSTALL_DIR,
|
|
5
|
+
[string]$ClaudeDir = $env:SKILL_CLI_CLAUDE_DIR,
|
|
6
|
+
[ValidateSet("lite", "full", "none")]
|
|
7
|
+
[string]$Doctor = $(if ($env:SKILL_CLI_DOCTOR) { $env:SKILL_CLI_DOCTOR } else { "lite" }),
|
|
8
|
+
[switch]$NoInstall,
|
|
9
|
+
[switch]$NoPathUpdate,
|
|
10
|
+
[switch]$DryRun
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
$ErrorActionPreference = "Stop"
|
|
14
|
+
|
|
15
|
+
function Test-TruthyEnv {
|
|
16
|
+
param([string]$Value)
|
|
17
|
+
if (-not $Value) {
|
|
18
|
+
return $false
|
|
19
|
+
}
|
|
20
|
+
return @("1", "true", "yes", "on") -contains $Value.ToLowerInvariant()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (Test-TruthyEnv $env:SKILL_CLI_NO_INSTALL) {
|
|
24
|
+
$NoInstall = $true
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (Test-TruthyEnv $env:SKILL_CLI_NO_PATH_UPDATE) {
|
|
28
|
+
$NoPathUpdate = $true
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (Test-TruthyEnv $env:SKILL_CLI_DRY_RUN) {
|
|
32
|
+
$DryRun = $true
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
$baseUrlWasProvided = [bool]$BaseUrl
|
|
36
|
+
|
|
37
|
+
if (-not $Version) {
|
|
38
|
+
$Version = "main"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (-not $BaseUrl) {
|
|
42
|
+
$BaseUrl = "https://gitee.com/marvin-dev/skill-cli-release/raw/$Version/bin/targets"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (-not $InstallDir) {
|
|
46
|
+
$InstallDir = Join-Path $env:LOCALAPPDATA "Programs\skill-cli"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (-not [Environment]::Is64BitOperatingSystem) {
|
|
50
|
+
throw "skill-cli currently provides a Windows x64 binary only."
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
$asset = "skill-cli-win32-x64.exe"
|
|
54
|
+
$url = ($BaseUrl.TrimEnd("/")) + "/" + $asset
|
|
55
|
+
$target = Join-Path $InstallDir "skill-cli.exe"
|
|
56
|
+
|
|
57
|
+
Write-Host "skill-cli installer"
|
|
58
|
+
Write-Host " asset: $asset"
|
|
59
|
+
Write-Host " source: $url"
|
|
60
|
+
Write-Host " target: $target"
|
|
61
|
+
if (-not $baseUrlWasProvided) {
|
|
62
|
+
Write-Host " version: $Version"
|
|
63
|
+
}
|
|
64
|
+
if ($ClaudeDir) {
|
|
65
|
+
Write-Host " claude dir: $ClaudeDir"
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if ($DryRun) {
|
|
69
|
+
Write-Host "dry run: no files written"
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
$tmp = Join-Path ([System.IO.Path]::GetTempPath()) ("skill-cli-install-" + [Guid]::NewGuid().ToString("N"))
|
|
74
|
+
New-Item -ItemType Directory -Path $tmp -Force | Out-Null
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
$downloaded = Join-Path $tmp $asset
|
|
78
|
+
$downloadedOk = $false
|
|
79
|
+
for ($attempt = 1; $attempt -le 3; $attempt++) {
|
|
80
|
+
try {
|
|
81
|
+
Invoke-WebRequest -Uri $url -OutFile $downloaded -UseBasicParsing
|
|
82
|
+
$downloadedOk = $true
|
|
83
|
+
break
|
|
84
|
+
} catch {
|
|
85
|
+
if ($attempt -eq 3) {
|
|
86
|
+
throw
|
|
87
|
+
}
|
|
88
|
+
Start-Sleep -Seconds (2 * $attempt)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (-not $downloadedOk) {
|
|
92
|
+
throw "download failed: $url"
|
|
93
|
+
}
|
|
94
|
+
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
|
|
95
|
+
Copy-Item -LiteralPath $downloaded -Destination $target -Force
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
Unblock-File -LiteralPath $target
|
|
99
|
+
} catch {
|
|
100
|
+
# Unblock-File can fail on filesystems without Zone.Identifier streams.
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (-not $NoPathUpdate) {
|
|
104
|
+
$userPath = [Environment]::GetEnvironmentVariable("Path", "User")
|
|
105
|
+
$parts = @()
|
|
106
|
+
if ($userPath) {
|
|
107
|
+
$parts = $userPath -split ';' | Where-Object { $_ }
|
|
108
|
+
}
|
|
109
|
+
$alreadyInPath = $false
|
|
110
|
+
foreach ($part in $parts) {
|
|
111
|
+
if ([string]::Equals($part.TrimEnd('\'), $InstallDir.TrimEnd('\'), [StringComparison]::OrdinalIgnoreCase)) {
|
|
112
|
+
$alreadyInPath = $true
|
|
113
|
+
break
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (-not $alreadyInPath) {
|
|
117
|
+
$newPath = if ($userPath) { "$userPath;$InstallDir" } else { $InstallDir }
|
|
118
|
+
[Environment]::SetEnvironmentVariable("Path", $newPath, "User")
|
|
119
|
+
$env:Path = "$env:Path;$InstallDir"
|
|
120
|
+
Write-Host " PATH: added to current user PATH"
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
Write-Host ""
|
|
125
|
+
& $target version
|
|
126
|
+
|
|
127
|
+
$claudeArgs = @()
|
|
128
|
+
if ($ClaudeDir) {
|
|
129
|
+
$claudeArgs += @("--claude-dir", $ClaudeDir)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (-not $NoInstall) {
|
|
133
|
+
Write-Host ""
|
|
134
|
+
& $target install @claudeArgs
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if ($Doctor -eq "lite") {
|
|
138
|
+
Write-Host ""
|
|
139
|
+
& $target doctor @claudeArgs --check-adversarial=false
|
|
140
|
+
} elseif ($Doctor -eq "full") {
|
|
141
|
+
Write-Host ""
|
|
142
|
+
& $target doctor @claudeArgs
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
Write-Host ""
|
|
146
|
+
Write-Host "skill-cli install complete."
|
|
147
|
+
Write-Host "Open a new terminal and run: skill-cli doctor"
|
|
148
|
+
} finally {
|
|
149
|
+
Remove-Item -LiteralPath $tmp -Recurse -Force -ErrorAction SilentlyContinue
|
|
150
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
DEFAULT_VERSION="main"
|
|
5
|
+
VERSION="${SKILL_CLI_VERSION:-$DEFAULT_VERSION}"
|
|
6
|
+
DEFAULT_BASE_URL="https://gitee.com/marvin-dev/skill-cli-release/raw/${VERSION}/bin/targets"
|
|
7
|
+
DEFAULT_BASE_URL_USES_VERSION=1
|
|
8
|
+
BASE_URL="${SKILL_CLI_BASE_URL:-$DEFAULT_BASE_URL}"
|
|
9
|
+
BASE_URL_EXPLICIT=0
|
|
10
|
+
if [ -n "${SKILL_CLI_BASE_URL:-}" ]; then
|
|
11
|
+
BASE_URL_EXPLICIT=1
|
|
12
|
+
fi
|
|
13
|
+
INSTALL_DIR="${SKILL_CLI_INSTALL_DIR:-$HOME/.local/bin}"
|
|
14
|
+
CLAUDE_DIR="${SKILL_CLI_CLAUDE_DIR:-}"
|
|
15
|
+
RUN_COMPONENT_INSTALL=1
|
|
16
|
+
DOCTOR_MODE="${SKILL_CLI_DOCTOR:-lite}"
|
|
17
|
+
DRY_RUN=0
|
|
18
|
+
|
|
19
|
+
usage() {
|
|
20
|
+
cat <<'EOF'
|
|
21
|
+
Install skill-cli from a prebuilt binary URL.
|
|
22
|
+
|
|
23
|
+
Usage:
|
|
24
|
+
curl -fsSL <install.sh-url> | bash
|
|
25
|
+
curl -fsSL <install.sh-url> | bash -s -- [options]
|
|
26
|
+
|
|
27
|
+
Options:
|
|
28
|
+
--base-url URL Base URL containing skill-cli-* binaries.
|
|
29
|
+
--version VERSION Gitee ref/tag used by the default Gitee base URL.
|
|
30
|
+
--install-dir DIR Directory to install skill-cli into.
|
|
31
|
+
--claude-dir DIR Pass --claude-dir to skill-cli install/doctor.
|
|
32
|
+
--no-install Only install the skill-cli binary.
|
|
33
|
+
--doctor MODE Doctor mode: lite, full, none. Default: lite.
|
|
34
|
+
--dry-run Print what would happen without downloading or writing.
|
|
35
|
+
-h, --help Show this help.
|
|
36
|
+
|
|
37
|
+
Environment:
|
|
38
|
+
SKILL_CLI_BASE_URL Same as --base-url.
|
|
39
|
+
SKILL_CLI_VERSION Same as --version. Default: main.
|
|
40
|
+
SKILL_CLI_INSTALL_DIR Same as --install-dir.
|
|
41
|
+
SKILL_CLI_CLAUDE_DIR Same as --claude-dir.
|
|
42
|
+
SKILL_CLI_DOCTOR Same as --doctor.
|
|
43
|
+
EOF
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
while [ "$#" -gt 0 ]; do
|
|
47
|
+
case "$1" in
|
|
48
|
+
--base-url)
|
|
49
|
+
BASE_URL="${2:?missing value for --base-url}"
|
|
50
|
+
BASE_URL_EXPLICIT=1
|
|
51
|
+
shift 2
|
|
52
|
+
;;
|
|
53
|
+
--version)
|
|
54
|
+
VERSION="${2:?missing value for --version}"
|
|
55
|
+
if [ "$BASE_URL_EXPLICIT" = "0" ] && [ "$DEFAULT_BASE_URL_USES_VERSION" = "1" ]; then
|
|
56
|
+
BASE_URL="https://gitee.com/marvin-dev/skill-cli-release/raw/${VERSION}/bin/targets"
|
|
57
|
+
fi
|
|
58
|
+
shift 2
|
|
59
|
+
;;
|
|
60
|
+
--install-dir)
|
|
61
|
+
INSTALL_DIR="${2:?missing value for --install-dir}"
|
|
62
|
+
shift 2
|
|
63
|
+
;;
|
|
64
|
+
--claude-dir)
|
|
65
|
+
CLAUDE_DIR="${2:?missing value for --claude-dir}"
|
|
66
|
+
shift 2
|
|
67
|
+
;;
|
|
68
|
+
--no-install)
|
|
69
|
+
RUN_COMPONENT_INSTALL=0
|
|
70
|
+
shift
|
|
71
|
+
;;
|
|
72
|
+
--doctor)
|
|
73
|
+
DOCTOR_MODE="${2:?missing value for --doctor}"
|
|
74
|
+
shift 2
|
|
75
|
+
;;
|
|
76
|
+
--dry-run)
|
|
77
|
+
DRY_RUN=1
|
|
78
|
+
shift
|
|
79
|
+
;;
|
|
80
|
+
-h|--help)
|
|
81
|
+
usage
|
|
82
|
+
exit 0
|
|
83
|
+
;;
|
|
84
|
+
*)
|
|
85
|
+
echo "skill-cli install: unknown option: $1" >&2
|
|
86
|
+
usage >&2
|
|
87
|
+
exit 2
|
|
88
|
+
;;
|
|
89
|
+
esac
|
|
90
|
+
done
|
|
91
|
+
|
|
92
|
+
case "$DOCTOR_MODE" in
|
|
93
|
+
lite|full|none) ;;
|
|
94
|
+
*)
|
|
95
|
+
echo "skill-cli install: --doctor must be one of: lite, full, none" >&2
|
|
96
|
+
exit 2
|
|
97
|
+
;;
|
|
98
|
+
esac
|
|
99
|
+
|
|
100
|
+
detect_asset() {
|
|
101
|
+
local os arch
|
|
102
|
+
os="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
|
103
|
+
arch="$(uname -m | tr '[:upper:]' '[:lower:]')"
|
|
104
|
+
|
|
105
|
+
case "$os" in
|
|
106
|
+
linux*) os="linux" ;;
|
|
107
|
+
darwin*) os="darwin" ;;
|
|
108
|
+
mingw*|msys*|cygwin*) os="win32" ;;
|
|
109
|
+
*)
|
|
110
|
+
echo "unsupported OS: $os" >&2
|
|
111
|
+
return 1
|
|
112
|
+
;;
|
|
113
|
+
esac
|
|
114
|
+
|
|
115
|
+
case "$arch" in
|
|
116
|
+
x86_64|amd64) arch="x64" ;;
|
|
117
|
+
aarch64|arm64) arch="arm64" ;;
|
|
118
|
+
*)
|
|
119
|
+
echo "unsupported architecture: $arch" >&2
|
|
120
|
+
return 1
|
|
121
|
+
;;
|
|
122
|
+
esac
|
|
123
|
+
|
|
124
|
+
if [ "$os" = "win32" ]; then
|
|
125
|
+
if [ "$arch" != "x64" ]; then
|
|
126
|
+
echo "unsupported Windows architecture: $arch" >&2
|
|
127
|
+
return 1
|
|
128
|
+
fi
|
|
129
|
+
printf '%s\n' "skill-cli-win32-x64.exe"
|
|
130
|
+
return 0
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
printf 'skill-cli-%s-%s\n' "$os" "$arch"
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
download_file() {
|
|
137
|
+
local url="$1" out="$2"
|
|
138
|
+
if command -v curl >/dev/null 2>&1; then
|
|
139
|
+
curl -fL --retry 3 --connect-timeout 15 -o "$out" "$url"
|
|
140
|
+
elif command -v wget >/dev/null 2>&1; then
|
|
141
|
+
wget -O "$out" "$url"
|
|
142
|
+
else
|
|
143
|
+
echo "skill-cli install: curl or wget is required" >&2
|
|
144
|
+
return 1
|
|
145
|
+
fi
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
ASSET="$(detect_asset)"
|
|
149
|
+
URL="${BASE_URL%/}/$ASSET"
|
|
150
|
+
TARGET_NAME="skill-cli"
|
|
151
|
+
case "$ASSET" in
|
|
152
|
+
*.exe) TARGET_NAME="skill-cli.exe" ;;
|
|
153
|
+
esac
|
|
154
|
+
TARGET_PATH="$INSTALL_DIR/$TARGET_NAME"
|
|
155
|
+
|
|
156
|
+
echo "skill-cli installer"
|
|
157
|
+
echo " asset: $ASSET"
|
|
158
|
+
echo " source: $URL"
|
|
159
|
+
echo " target: $TARGET_PATH"
|
|
160
|
+
if [ -z "${SKILL_CLI_BASE_URL:-}" ]; then
|
|
161
|
+
echo " version: $VERSION"
|
|
162
|
+
fi
|
|
163
|
+
if [ -n "$CLAUDE_DIR" ]; then
|
|
164
|
+
echo " claude dir: $CLAUDE_DIR"
|
|
165
|
+
fi
|
|
166
|
+
|
|
167
|
+
if [ "$DRY_RUN" = "1" ]; then
|
|
168
|
+
echo "dry run: no files written"
|
|
169
|
+
exit 0
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
TMP_DIR="$(mktemp -d)"
|
|
173
|
+
trap 'rm -rf "$TMP_DIR"' EXIT
|
|
174
|
+
|
|
175
|
+
download_file "$URL" "$TMP_DIR/$ASSET"
|
|
176
|
+
chmod +x "$TMP_DIR/$ASSET" || true
|
|
177
|
+
mkdir -p "$INSTALL_DIR"
|
|
178
|
+
cp "$TMP_DIR/$ASSET" "$TARGET_PATH"
|
|
179
|
+
chmod +x "$TARGET_PATH" || true
|
|
180
|
+
|
|
181
|
+
echo ""
|
|
182
|
+
"$TARGET_PATH" version
|
|
183
|
+
|
|
184
|
+
claude_args=()
|
|
185
|
+
if [ -n "$CLAUDE_DIR" ]; then
|
|
186
|
+
claude_args=(--claude-dir "$CLAUDE_DIR")
|
|
187
|
+
fi
|
|
188
|
+
|
|
189
|
+
if [ "$RUN_COMPONENT_INSTALL" = "1" ]; then
|
|
190
|
+
echo ""
|
|
191
|
+
"$TARGET_PATH" install "${claude_args[@]}"
|
|
192
|
+
fi
|
|
193
|
+
|
|
194
|
+
case "$DOCTOR_MODE" in
|
|
195
|
+
lite)
|
|
196
|
+
echo ""
|
|
197
|
+
"$TARGET_PATH" doctor "${claude_args[@]}" --check-adversarial=false
|
|
198
|
+
;;
|
|
199
|
+
full)
|
|
200
|
+
echo ""
|
|
201
|
+
"$TARGET_PATH" doctor "${claude_args[@]}"
|
|
202
|
+
;;
|
|
203
|
+
none)
|
|
204
|
+
;;
|
|
205
|
+
esac
|
|
206
|
+
|
|
207
|
+
case ":$PATH:" in
|
|
208
|
+
*":$INSTALL_DIR:"*) ;;
|
|
209
|
+
*)
|
|
210
|
+
echo ""
|
|
211
|
+
echo "Add this directory to PATH if 'skill-cli' is not found in new shells:"
|
|
212
|
+
echo " $INSTALL_DIR"
|
|
213
|
+
;;
|
|
214
|
+
esac
|
|
215
|
+
|
|
216
|
+
echo ""
|
|
217
|
+
echo "skill-cli install complete."
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const rootDir = path.join(__dirname, '..');
|
|
8
|
+
const outDir = path.join(rootDir, 'dist', 'install');
|
|
9
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(rootDir, 'package.json'), 'utf8'));
|
|
10
|
+
const version = `v${pkg.version}`;
|
|
11
|
+
const targets = [
|
|
12
|
+
'skill-cli-darwin-arm64',
|
|
13
|
+
'skill-cli-darwin-x64',
|
|
14
|
+
'skill-cli-linux-arm64',
|
|
15
|
+
'skill-cli-linux-x64',
|
|
16
|
+
'skill-cli-win32-x64.exe',
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const args = process.argv.slice(2);
|
|
20
|
+
let baseURL = '';
|
|
21
|
+
let rootURL = '';
|
|
22
|
+
let scriptRootURL = '';
|
|
23
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
24
|
+
if (args[i] === '--base-url') {
|
|
25
|
+
baseURL = args[i + 1] || '';
|
|
26
|
+
i += 1;
|
|
27
|
+
} else if (args[i] === '--root') {
|
|
28
|
+
rootURL = args[i + 1] || '';
|
|
29
|
+
i += 1;
|
|
30
|
+
} else if (args[i] === '--script-root') {
|
|
31
|
+
scriptRootURL = args[i + 1] || '';
|
|
32
|
+
i += 1;
|
|
33
|
+
} else if (args[i] === '-h' || args[i] === '--help') {
|
|
34
|
+
console.log(`Usage:
|
|
35
|
+
node scripts/make-install-bundle.js [--root URL]
|
|
36
|
+
node scripts/make-install-bundle.js [--base-url URL]
|
|
37
|
+
node scripts/make-install-bundle.js [--base-url URL] [--script-root URL]
|
|
38
|
+
|
|
39
|
+
Creates dist/install/ with one-line installer scripts and prebuilt binaries.
|
|
40
|
+
When --root is provided, generated installer copies default to ROOT/bin/targets.
|
|
41
|
+
When --base-url is provided, generated installer copies default to that URL
|
|
42
|
+
for binary downloads, which is useful for intranet static hosting.
|
|
43
|
+
When --script-root is provided, README examples point to SCRIPT_ROOT/scripts.`);
|
|
44
|
+
process.exit(0);
|
|
45
|
+
} else {
|
|
46
|
+
console.error(`unknown option: ${args[i]}`);
|
|
47
|
+
process.exit(2);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function trimSlash(value) {
|
|
52
|
+
return value.replace(/\/+$/, '');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (rootURL && baseURL) {
|
|
56
|
+
console.error('use either --root or --base-url, not both');
|
|
57
|
+
process.exit(2);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (rootURL) {
|
|
61
|
+
rootURL = trimSlash(rootURL);
|
|
62
|
+
baseURL = `${rootURL}/bin/targets`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (scriptRootURL) {
|
|
66
|
+
scriptRootURL = trimSlash(scriptRootURL);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function copyFile(src, dest) {
|
|
70
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
71
|
+
fs.copyFileSync(src, dest);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function writeFile(dest, content) {
|
|
75
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
76
|
+
fs.writeFileSync(dest, content);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
fs.rmSync(outDir, { recursive: true, force: true });
|
|
80
|
+
|
|
81
|
+
for (const target of targets) {
|
|
82
|
+
const src = path.join(rootDir, 'bin', 'targets', target);
|
|
83
|
+
if (!fs.existsSync(src)) {
|
|
84
|
+
console.error(`missing binary: ${src}`);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
copyFile(src, path.join(outDir, 'bin', 'targets', target));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
let installSH = fs.readFileSync(path.join(rootDir, 'scripts', 'install.sh'), 'utf8');
|
|
91
|
+
let installPS1 = fs.readFileSync(path.join(rootDir, 'scripts', 'install.ps1'), 'utf8');
|
|
92
|
+
|
|
93
|
+
installSH = installSH.replace(/DEFAULT_VERSION="[^"]+"/, `DEFAULT_VERSION="${version}"`);
|
|
94
|
+
installSH = installSH.replace(
|
|
95
|
+
/SKILL_CLI_VERSION Same as --version\. Default: [^\n]+/,
|
|
96
|
+
`SKILL_CLI_VERSION Same as --version. Default: ${version}.`
|
|
97
|
+
);
|
|
98
|
+
installPS1 = installPS1.replace(/\$Version = "[^"]+"/, `$Version = "${version}"`);
|
|
99
|
+
|
|
100
|
+
if (baseURL) {
|
|
101
|
+
const normalizedBaseURL = trimSlash(baseURL);
|
|
102
|
+
installSH = installSH.replace(
|
|
103
|
+
/DEFAULT_BASE_URL="https:\/\/gitee\.com\/marvin-dev\/skill-cli-release\/raw\/\$\{VERSION\}\/bin\/targets"/,
|
|
104
|
+
`DEFAULT_BASE_URL="${normalizedBaseURL}"`
|
|
105
|
+
).replace(
|
|
106
|
+
/DEFAULT_BASE_URL_USES_VERSION=1/,
|
|
107
|
+
'DEFAULT_BASE_URL_USES_VERSION=0'
|
|
108
|
+
);
|
|
109
|
+
installPS1 = installPS1.replace(
|
|
110
|
+
/\$BaseUrl = "https:\/\/gitee\.com\/marvin-dev\/skill-cli-release\/raw\/\$Version\/bin\/targets"/,
|
|
111
|
+
`$BaseUrl = "${normalizedBaseURL}"`
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
writeFile(path.join(outDir, 'scripts', 'install.sh'), installSH);
|
|
116
|
+
writeFile(path.join(outDir, 'scripts', 'install.ps1'), installPS1);
|
|
117
|
+
|
|
118
|
+
const manifest = {
|
|
119
|
+
package: pkg.name,
|
|
120
|
+
version: pkg.version,
|
|
121
|
+
tag: version,
|
|
122
|
+
generatedAt: new Date().toISOString(),
|
|
123
|
+
rootURL: rootURL || null,
|
|
124
|
+
scriptRootURL: scriptRootURL || null,
|
|
125
|
+
baseURL: baseURL || null,
|
|
126
|
+
files: [
|
|
127
|
+
'scripts/install.ps1',
|
|
128
|
+
'scripts/install.sh',
|
|
129
|
+
...targets.map((target) => `bin/targets/${target}`),
|
|
130
|
+
],
|
|
131
|
+
};
|
|
132
|
+
writeFile(path.join(outDir, 'manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`);
|
|
133
|
+
|
|
134
|
+
function inferInstallRootFromBaseURL(value) {
|
|
135
|
+
const normalized = trimSlash(value);
|
|
136
|
+
if (normalized.endsWith('/bin/targets')) {
|
|
137
|
+
return normalized.slice(0, -'/bin/targets'.length);
|
|
138
|
+
}
|
|
139
|
+
return '<your-hosted-root>';
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const installRoot = scriptRootURL || rootURL || (baseURL ? inferInstallRootFromBaseURL(baseURL) : `https://gitee.com/marvin-dev/skill-cli-release/raw/${version}`);
|
|
143
|
+
const psURL = baseURL ? `${installRoot}/scripts/install.ps1` : `${installRoot}/scripts/install.ps1`;
|
|
144
|
+
const shURL = baseURL ? `${installRoot}/scripts/install.sh` : `${installRoot}/scripts/install.sh`;
|
|
145
|
+
|
|
146
|
+
writeFile(path.join(outDir, 'README.txt'), `skill-cli ${version} install bundle
|
|
147
|
+
|
|
148
|
+
Host this directory as a static tree. Required layout:
|
|
149
|
+
scripts/install.ps1
|
|
150
|
+
scripts/install.sh
|
|
151
|
+
bin/targets/skill-cli-*
|
|
152
|
+
|
|
153
|
+
Windows PowerShell:
|
|
154
|
+
irm ${psURL} | iex
|
|
155
|
+
|
|
156
|
+
macOS/Linux:
|
|
157
|
+
curl -fsSL ${shURL} | bash
|
|
158
|
+
|
|
159
|
+
If --base-url was not used to generate this bundle, set SKILL_CLI_BASE_URL
|
|
160
|
+
to the hosted bin/targets URL before running the installer.
|
|
161
|
+
`);
|
|
162
|
+
|
|
163
|
+
console.log(`Created ${outDir}`);
|
|
164
|
+
console.log(`Version: ${version}`);
|
|
165
|
+
if (baseURL) {
|
|
166
|
+
console.log(`Default binary base URL: ${baseURL}`);
|
|
167
|
+
}
|