@mcptask/cli 0.2.3
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 +69 -0
- package/bin/mcptask_runner.js +37 -0
- package/install.js +143 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# @mcptask/cli
|
|
2
|
+
|
|
3
|
+
The [mcptask](https://mcptask.online) runner — drives Claude Code through the
|
|
4
|
+
tasks on mcptask.online.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npx @mcptask/cli init
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Run that in the project you want the runner to work on. It installs the skills,
|
|
11
|
+
helper scripts and configuration the runner needs, and prints how to switch on a
|
|
12
|
+
scheduled job — it does not switch one on for you.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx @mcptask/cli run today # work today's tasks
|
|
16
|
+
npx @mcptask/cli version # version and resolved configuration
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## What this package is
|
|
20
|
+
|
|
21
|
+
A thin wrapper around a single static binary. It carries no binary of its own:
|
|
22
|
+
publishing six of them in one tarball would make every project download five it
|
|
23
|
+
cannot run, so the postinstall downloads the one archive this platform needs and
|
|
24
|
+
verifies it against the release's published `checksums.txt` before unpacking it.
|
|
25
|
+
|
|
26
|
+
macOS, Linux and Windows, on amd64 and arm64. The binary needs no Go and no Ruby.
|
|
27
|
+
|
|
28
|
+
The wrapper forwards arguments and exit codes untouched — the runner's exit codes
|
|
29
|
+
are a contract that scheduled jobs read, and a wrapper that flattened them to 0/1
|
|
30
|
+
would break every one of them.
|
|
31
|
+
|
|
32
|
+
## Not a JS project?
|
|
33
|
+
|
|
34
|
+
The same binary installs without npm:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
curl -fsSL https://github.com/jchsoft/mcptask-releases/releases/latest/download/install.sh | sh
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Or `brew install jchsoft/tap/mcptask_runner` on macOS, and on Windows:
|
|
41
|
+
|
|
42
|
+
```powershell
|
|
43
|
+
scoop bucket add jchsoft https://github.com/jchsoft/scoop-bucket
|
|
44
|
+
scoop install mcptask_runner
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Once installed any way, it updates itself:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
mcptask_runner update --self
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Environment
|
|
54
|
+
|
|
55
|
+
| Variable | Effect |
|
|
56
|
+
| --- | --- |
|
|
57
|
+
| `MCPTASK_VERSION` | install a specific release instead of the one matching this package |
|
|
58
|
+
| `MCPTASK_NO_UPDATE_CHECK` | set to `1` to stop the runner mentioning newer releases |
|
|
59
|
+
|
|
60
|
+
The package version is the release it installs, so `@mcptask/cli@0.2.3` gives you
|
|
61
|
+
`mcptask_runner` 0.2.3.
|
|
62
|
+
|
|
63
|
+
## Where things live
|
|
64
|
+
|
|
65
|
+
Binaries and checksums: [jchsoft/mcptask-releases](https://github.com/jchsoft/mcptask-releases).
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
Proprietary — © JCHSoft. All rights reserved.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Thin wrapper: run the binary the postinstall script downloaded (#11273).
|
|
3
|
+
//
|
|
4
|
+
// It exists so `npx @mcptask/cli init` works, and it deliberately does nothing
|
|
5
|
+
// beyond handing over — arguments through untouched, stdio inherited so the
|
|
6
|
+
// runner's own progress output and prompts behave as if it had been invoked
|
|
7
|
+
// directly, and its exit code passed back. The runner's exit codes are a
|
|
8
|
+
// documented contract, and a wrapper that collapsed them to 0/1 would break
|
|
9
|
+
// every scheduled job that reads them.
|
|
10
|
+
'use strict'
|
|
11
|
+
|
|
12
|
+
const path = require('node:path')
|
|
13
|
+
const fs = require('node:fs')
|
|
14
|
+
const { spawnSync } = require('node:child_process')
|
|
15
|
+
|
|
16
|
+
const binary = process.platform === 'win32' ? 'mcptask_runner.exe' : 'mcptask_runner'
|
|
17
|
+
const executable = path.join(__dirname, '..', 'vendor', binary)
|
|
18
|
+
|
|
19
|
+
if (!fs.existsSync(executable)) {
|
|
20
|
+
console.error(
|
|
21
|
+
'@mcptask/cli: the runner binary is missing — the postinstall download did ' +
|
|
22
|
+
'not complete.\nReinstall with `npm install @mcptask/cli`, or run ' +
|
|
23
|
+
'`node install.js` inside the package.'
|
|
24
|
+
)
|
|
25
|
+
process.exit(1)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const result = spawnSync(executable, process.argv.slice(2), { stdio: 'inherit' })
|
|
29
|
+
|
|
30
|
+
if (result.error) {
|
|
31
|
+
console.error(`@mcptask/cli: could not start the runner — ${result.error.message}`)
|
|
32
|
+
process.exit(1)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// A process killed by a signal has a null status; report it the way a shell
|
|
36
|
+
// does rather than as a success.
|
|
37
|
+
process.exit(result.status === null ? 1 : result.status)
|
package/install.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// postinstall: fetch the mcptask_runner binary for this platform (#11273).
|
|
2
|
+
//
|
|
3
|
+
// The npm package carries no binary of its own — publishing six of them in one
|
|
4
|
+
// tarball would make every JS project download five it cannot run. Instead the
|
|
5
|
+
// package version tracks the release tag, and this script downloads the one
|
|
6
|
+
// archive this platform needs and verifies it against the release's checksums.
|
|
7
|
+
//
|
|
8
|
+
// Node's standard library only, on purpose: a postinstall script with
|
|
9
|
+
// dependencies has to be installed before it can install, and every dependency
|
|
10
|
+
// here would run in the same privileged position on every host.
|
|
11
|
+
'use strict'
|
|
12
|
+
|
|
13
|
+
const crypto = require('node:crypto')
|
|
14
|
+
const fs = require('node:fs')
|
|
15
|
+
const https = require('node:https')
|
|
16
|
+
const os = require('node:os')
|
|
17
|
+
const path = require('node:path')
|
|
18
|
+
const { execFileSync } = require('node:child_process')
|
|
19
|
+
|
|
20
|
+
const REPO = process.env.MCPTASK_RELEASE_REPO || 'jchsoft/mcptask-releases'
|
|
21
|
+
const BINARY = process.platform === 'win32' ? 'mcptask_runner.exe' : 'mcptask_runner'
|
|
22
|
+
const VENDOR = path.join(__dirname, 'vendor')
|
|
23
|
+
|
|
24
|
+
// npm normalises the package version; the release tag it came from is that
|
|
25
|
+
// version with a leading v. MCPTASK_VERSION overrides both, which is what makes
|
|
26
|
+
// a pre-release installable without republishing the package.
|
|
27
|
+
const version = process.env.MCPTASK_VERSION || `v${require('./package.json').version}`
|
|
28
|
+
|
|
29
|
+
function platformSlug () {
|
|
30
|
+
const goos = { darwin: 'darwin', linux: 'linux', win32: 'windows' }[process.platform]
|
|
31
|
+
const goarch = { x64: 'amd64', arm64: 'arm64' }[process.arch]
|
|
32
|
+
if (!goos || !goarch) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
`unsupported platform ${process.platform}/${process.arch} — ` +
|
|
35
|
+
'the release builds darwin, linux and windows on amd64 and arm64'
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
return { goos, goarch }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// GitHub redirects release downloads to a storage host, so redirects have to be
|
|
42
|
+
// followed by hand: https.get does not do it.
|
|
43
|
+
function get (url, redirectsLeft = 5) {
|
|
44
|
+
return new Promise((resolve, reject) => {
|
|
45
|
+
const headers = { 'user-agent': '@mcptask/cli' }
|
|
46
|
+
// Only needed while the release repository is private.
|
|
47
|
+
const token = process.env.MCPTASK_GITHUB_TOKEN || process.env.GITHUB_TOKEN
|
|
48
|
+
if (token) headers.authorization = `Bearer ${token}`
|
|
49
|
+
|
|
50
|
+
https.get(url, { headers }, (res) => {
|
|
51
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
52
|
+
res.resume()
|
|
53
|
+
if (redirectsLeft === 0) return reject(new Error(`too many redirects for ${url}`))
|
|
54
|
+
return resolve(get(res.headers.location, redirectsLeft - 1))
|
|
55
|
+
}
|
|
56
|
+
if (res.statusCode !== 200) {
|
|
57
|
+
res.resume()
|
|
58
|
+
return reject(new Error(`GET ${url} failed with HTTP ${res.statusCode}`))
|
|
59
|
+
}
|
|
60
|
+
const chunks = []
|
|
61
|
+
res.on('data', (c) => chunks.push(c))
|
|
62
|
+
res.on('end', () => resolve(Buffer.concat(chunks)))
|
|
63
|
+
res.on('error', reject)
|
|
64
|
+
}).on('error', reject)
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// The archive is only unpacked once its hash matches what the release published.
|
|
69
|
+
// This runs as a postinstall script, so the binary it produces will be executed
|
|
70
|
+
// by the developer without further inspection — an unverified download here is
|
|
71
|
+
// an unverified download straight onto PATH.
|
|
72
|
+
function verify (archiveName, archive, checksums) {
|
|
73
|
+
const digest = crypto.createHash('sha256').update(archive).digest('hex')
|
|
74
|
+
const line = checksums
|
|
75
|
+
.toString('utf8')
|
|
76
|
+
.split('\n')
|
|
77
|
+
.find((l) => l.trim().endsWith(archiveName))
|
|
78
|
+
if (!line) throw new Error(`checksums.txt does not list ${archiveName}`)
|
|
79
|
+
|
|
80
|
+
const expected = line.trim().split(/\s+/)[0]
|
|
81
|
+
if (expected !== digest) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
`checksum mismatch for ${archiveName}\n expected ${expected}\n got ${digest}`
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function extract (archivePath, destination) {
|
|
89
|
+
if (archivePath.endsWith('.zip')) {
|
|
90
|
+
// Windows: PowerShell rather than a zip dependency.
|
|
91
|
+
execFileSync('powershell', [
|
|
92
|
+
'-NoProfile', '-NonInteractive', '-Command',
|
|
93
|
+
`Expand-Archive -Path "${archivePath}" -DestinationPath "${destination}" -Force`
|
|
94
|
+
], { stdio: 'inherit' })
|
|
95
|
+
} else {
|
|
96
|
+
// bsdtar/GNU tar, present on every macOS and Linux host.
|
|
97
|
+
execFileSync('tar', ['-xzf', archivePath, '-C', destination], { stdio: 'inherit' })
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function main () {
|
|
102
|
+
const { goos, goarch } = platformSlug()
|
|
103
|
+
const bare = version.replace(/^v/, '')
|
|
104
|
+
const ext = goos === 'windows' ? 'zip' : 'tar.gz'
|
|
105
|
+
const archiveName = `mcptask_runner_${bare}_${goos}_${goarch}.${ext}`
|
|
106
|
+
const base = `https://github.com/${REPO}/releases/download/${version}`
|
|
107
|
+
|
|
108
|
+
console.log(`@mcptask/cli: downloading ${archiveName}`)
|
|
109
|
+
const [archive, checksums] = await Promise.all([
|
|
110
|
+
get(`${base}/${archiveName}`),
|
|
111
|
+
get(`${base}/checksums.txt`)
|
|
112
|
+
])
|
|
113
|
+
|
|
114
|
+
verify(archiveName, archive, checksums)
|
|
115
|
+
|
|
116
|
+
fs.rmSync(VENDOR, { recursive: true, force: true })
|
|
117
|
+
fs.mkdirSync(VENDOR, { recursive: true })
|
|
118
|
+
|
|
119
|
+
const staging = fs.mkdtempSync(path.join(os.tmpdir(), 'mcptask-'))
|
|
120
|
+
try {
|
|
121
|
+
const archivePath = path.join(staging, archiveName)
|
|
122
|
+
fs.writeFileSync(archivePath, archive)
|
|
123
|
+
extract(archivePath, staging)
|
|
124
|
+
|
|
125
|
+
const from = path.join(staging, BINARY)
|
|
126
|
+
if (!fs.existsSync(from)) throw new Error(`the archive did not contain ${BINARY}`)
|
|
127
|
+
fs.copyFileSync(from, path.join(VENDOR, BINARY))
|
|
128
|
+
// npm does not preserve the executable bit through this path, and the
|
|
129
|
+
// wrapper execs the file directly rather than through a shell.
|
|
130
|
+
fs.chmodSync(path.join(VENDOR, BINARY), 0o755)
|
|
131
|
+
} finally {
|
|
132
|
+
fs.rmSync(staging, { recursive: true, force: true })
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
console.log(`@mcptask/cli: installed mcptask_runner ${version}`)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
main().catch((err) => {
|
|
139
|
+
console.error(`@mcptask/cli: ${err.message}`)
|
|
140
|
+
// Fail the install rather than leaving a package whose only command is
|
|
141
|
+
// missing; `npx @mcptask/cli` would otherwise fail later and less clearly.
|
|
142
|
+
process.exit(1)
|
|
143
|
+
})
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mcptask/cli",
|
|
3
|
+
"version": "0.2.3",
|
|
4
|
+
"description": "mcptask runner — drives Claude Code through the tasks on mcptask.online",
|
|
5
|
+
"homepage": "https://mcptask.online",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/jchsoft/mcptask-releases.git"
|
|
10
|
+
},
|
|
11
|
+
"bin": {
|
|
12
|
+
"mcptask_runner": "bin/mcptask_runner.js"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"postinstall": "node install.js"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"bin/mcptask_runner.js",
|
|
19
|
+
"install.js",
|
|
20
|
+
"README.md"
|
|
21
|
+
],
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=18"
|
|
24
|
+
},
|
|
25
|
+
"os": [
|
|
26
|
+
"darwin",
|
|
27
|
+
"linux",
|
|
28
|
+
"win32"
|
|
29
|
+
],
|
|
30
|
+
"cpu": [
|
|
31
|
+
"x64",
|
|
32
|
+
"arm64"
|
|
33
|
+
]
|
|
34
|
+
}
|