mcptask-rails-runner 0.2.4 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -0
- data/README.md +62 -16
- data/lib/mcptask_rails_runner/binary.rb +106 -4
- data/lib/mcptask_rails_runner/version.rb +10 -3
- data/lib/tasks/mcptask_runner.rake +9 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '0519b4bebbc7206e258a1c0ca68d4b33a1d4ca65e7b1df96e94bc7fcea9d195a'
|
|
4
|
+
data.tar.gz: fb10b8db54c85034117828907847bb13c62d80f316591490724c2e8804fcebdd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5d80a74fce1cb46bcef44e67e6d17c3015a9651a53fc8099b05fd75abb29c9f5b7f37e22d194f1192cfb6e1a7527ae9c5f3ae21b7462ce5bf43d01c64d49722e
|
|
7
|
+
data.tar.gz: 5fa67df8de13a98d9f42990dacfadea7b56b7cb040bbde6186cb9cb1d764ca46f9a191dbb163c4aade6bb4d036334249820af81e389801c7ba95e3279a2c9773
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,36 @@ entries below describe wrapper changes only. Binary changes are listed in the
|
|
|
5
5
|
[mcptask-releases](https://github.com/jchsoft/mcptask-releases/releases)
|
|
6
6
|
release notes for the same tag.
|
|
7
7
|
|
|
8
|
+
## 0.3.1
|
|
9
|
+
|
|
10
|
+
- `mcptask_runner:install` no longer asks for mcptask.online credentials on a
|
|
11
|
+
host whose token already resolves — from `.mcp.json` or the environment. It
|
|
12
|
+
says which one it found and where, and leaves it alone; set `MCPTASK_EMAIL`
|
|
13
|
+
and `MCPTASK_PASSWORD` to replace it deliberately. Where there really is no
|
|
14
|
+
token, the step now says whose account it wants, that the password is
|
|
15
|
+
exchanged once and never stored, which file the token lands in, and that the
|
|
16
|
+
runner will not start without one.
|
|
17
|
+
- The release workflow waits for the Go binaries instead of failing when the two
|
|
18
|
+
tags are pushed minutes apart.
|
|
19
|
+
|
|
20
|
+
## 0.3.0
|
|
21
|
+
|
|
22
|
+
- The Go runner is the runner: this gem is the Rails distribution, and the
|
|
23
|
+
legacy `mcptask_runner` gem is retired to critical fixes and its role as the
|
|
24
|
+
conformance suite's reference implementation.
|
|
25
|
+
|
|
26
|
+
- The ARM Linux platform gem is named `aarch64-linux`, which is the platform
|
|
27
|
+
such hosts actually resolve. 0.2.4 published it as `arm64-linux`, which
|
|
28
|
+
matches nothing: every Graviton server, ARM CI runner and Docker container on
|
|
29
|
+
Apple Silicon fell back to the binary-less `ruby` gem and failed at run time.
|
|
30
|
+
That gem stays published and unreachable.
|
|
31
|
+
- `mcptask_runner:install` and `:update` copy the binary out of the gem to
|
|
32
|
+
`~/.mcptask/bin/mcptask_runner` and run it from there, so the scheduled job
|
|
33
|
+
they generate survives the next `bundle update` — which deletes the gem
|
|
34
|
+
directory the job used to point into. They print which version they wrote and
|
|
35
|
+
never replace a newer installed binary with an older one. Migrating hosts
|
|
36
|
+
should re-run install once, with `FORCE=1`, to regenerate the job.
|
|
37
|
+
|
|
8
38
|
## 0.2.4
|
|
9
39
|
|
|
10
40
|
- First release. Thin Rails wrapper around the `mcptask_runner` Go binary,
|
data/README.md
CHANGED
|
@@ -1,14 +1,33 @@
|
|
|
1
1
|
# mcptask-rails-runner
|
|
2
2
|
|
|
3
3
|
Rails distribution of the [mcptask.online](https://mcptask.online) autonomous
|
|
4
|
-
runner. A thin Ruby wrapper around the
|
|
5
|
-
ships the platform-specific binary inside
|
|
6
|
-
|
|
4
|
+
runner, and the way a Rails app installs it. A thin Ruby wrapper around the
|
|
5
|
+
`mcptask_runner` Go binary: the gem ships the platform-specific binary inside
|
|
6
|
+
itself (`libexec/`) and exposes the same rake tasks as the legacy
|
|
7
|
+
`mcptask_runner` gem, delegating 1:1 to the CLI.
|
|
8
|
+
|
|
9
|
+
The legacy gem is retired. It gets critical fixes only, and it stays in
|
|
10
|
+
existence as the reference implementation the Go runner's conformance suite
|
|
11
|
+
measures against; everything new is written in Go. What you gain by moving:
|
|
12
|
+
Linux and Windows hosts, a scheduled job with no bundler in its path, and a
|
|
13
|
+
handful of places where the old implementation was simply wrong (its token
|
|
14
|
+
resolution read a different half of `.mcp.json` in each of three places, and
|
|
15
|
+
its stream reader died mid-run on an API error envelope).
|
|
7
16
|
|
|
8
17
|
One gem version carries exactly one binary version — `mcptask-rails-runner
|
|
9
18
|
X.Y.Z` contains the binary from the `vX.Y.Z` release of
|
|
10
19
|
[jchsoft/mcptask-releases](https://github.com/jchsoft/mcptask-releases).
|
|
11
20
|
|
|
21
|
+
`mcptask_runner:install` and `:update` copy that binary out of the gem to
|
|
22
|
+
`~/.mcptask/bin/mcptask_runner` and run it from there. The scheduled job runs
|
|
23
|
+
that copy, because a job pointing inside a gem directory dies at the next
|
|
24
|
+
`bundle update` — at 08:00, in a log nobody reads. So the pin is per project:
|
|
25
|
+
the Gemfile decides what a foreground `rake mcptask_runner:*` runs, while the
|
|
26
|
+
machine has one installed binary however many projects it carries, and the
|
|
27
|
+
newest version any of them offers is the one that stays. Install and update
|
|
28
|
+
print which version they wrote, and never replace a newer installed binary
|
|
29
|
+
with an older one.
|
|
30
|
+
|
|
12
31
|
## Requirements
|
|
13
32
|
|
|
14
33
|
- Ruby >= 3.0, Rails >= 6.0
|
|
@@ -36,8 +55,21 @@ The rake surface is identical — the migration is one Gemfile line:
|
|
|
36
55
|
+ gem "mcptask-rails-runner"
|
|
37
56
|
```
|
|
38
57
|
|
|
39
|
-
Then
|
|
40
|
-
|
|
58
|
+
Then:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
bundle install
|
|
62
|
+
FORCE=1 bundle exec rake mcptask_runner:install
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Re-running install is what regenerates the scheduled job. The legacy launcher
|
|
66
|
+
runs `bundle exec rake` and logs the active version by grepping `Gemfile.lock`
|
|
67
|
+
for the old gem name — neither survives the rename, so a job left as it is
|
|
68
|
+
keeps working but stops recording what it ran. The regenerated one execs
|
|
69
|
+
`~/.mcptask/bin/mcptask_runner` directly, with no bundler in the 08:00 path.
|
|
70
|
+
|
|
71
|
+
Every `rake mcptask_runner:*` invocation and shell alias keeps working
|
|
72
|
+
unchanged. Your existing
|
|
41
73
|
`config/mcptask_runner.yml`, `.mcp.json` and `.claude/` setup are read by the
|
|
42
74
|
Go binary as-is. The only legacy task without a counterpart is
|
|
43
75
|
`mcptask_runner:prepare:permissions` — permission sync is part of
|
|
@@ -47,8 +79,8 @@ Go binary as-is. The only legacy task without a counterpart is
|
|
|
47
79
|
|
|
48
80
|
| Task | Delegates to |
|
|
49
81
|
|---|---|
|
|
50
|
-
| `mcptask_runner:install` | `mcptask_runner init` |
|
|
51
|
-
| `mcptask_runner:update` | `mcptask_runner update` |
|
|
82
|
+
| `mcptask_runner:install` | `mcptask_runner init` (from `~/.mcptask/bin`) |
|
|
83
|
+
| `mcptask_runner:update` | `mcptask_runner update` (from `~/.mcptask/bin`) |
|
|
52
84
|
| `mcptask_runner:bug_report` | `mcptask_runner bug-report` |
|
|
53
85
|
| `mcptask_runner:version` | `mcptask_runner version` |
|
|
54
86
|
| `mcptask_runner:manual:once` (`once_dry`, `today`, `daily`, `review`, `reviews`, `workflow`, `queue`) | `mcptask_runner run <mode>` |
|
|
@@ -61,7 +93,7 @@ the binary itself, exactly as before.
|
|
|
61
93
|
|
|
62
94
|
## Supported platforms
|
|
63
95
|
|
|
64
|
-
Platform gems exist for `arm64-darwin`, `x86_64-darwin`, `
|
|
96
|
+
Platform gems exist for `arm64-darwin`, `x86_64-darwin`, `aarch64-linux`,
|
|
65
97
|
`x86_64-linux` and `x64-mingw-ucrt`. On anything else bundler falls back to
|
|
66
98
|
the binary-less `ruby` platform gem, which fails at run time with
|
|
67
99
|
instructions: install the binary from
|
|
@@ -69,9 +101,11 @@ instructions: install the binary from
|
|
|
69
101
|
`install.sh` / npm `@mcptask/cli`) and point `MCPTASK_RUNNER_BIN` at it. The
|
|
70
102
|
same variable also serves offline or air-gapped installs.
|
|
71
103
|
|
|
72
|
-
The wrapper always executes the binary through an absolute path inside the
|
|
73
|
-
gem
|
|
74
|
-
|
|
104
|
+
The wrapper always executes the binary through an absolute path — inside the
|
|
105
|
+
gem for the run tasks, `~/.mcptask/bin` for install and update — and never
|
|
106
|
+
through PATH: the binary shares its name with the legacy tooling, and a PATH
|
|
107
|
+
lookup could pick up the wrong install. `MCPTASK_RUNNER_BIN` overrides both,
|
|
108
|
+
and install leaves `~/.mcptask/bin` untouched while it is set.
|
|
75
109
|
|
|
76
110
|
## Development
|
|
77
111
|
|
|
@@ -84,11 +118,23 @@ bundle exec rake package:all # build all platform gems into pkg/
|
|
|
84
118
|
|
|
85
119
|
## Releasing
|
|
86
120
|
|
|
87
|
-
Releases are cut by tagging
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
121
|
+
Releases are cut by tagging, twice — the binaries come from the Go repository
|
|
122
|
+
and the gems from this one:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# 1. bump lib/mcptask_rails_runner/version.rb, commit, push
|
|
126
|
+
# 2. in mcptask_go_runner:
|
|
127
|
+
git tag -a v0.3.0 -m v0.3.0 && git push origin v0.3.0
|
|
128
|
+
# 3. here, straight after — no waiting:
|
|
129
|
+
git tag -a v0.3.0 -m v0.3.0 && git push origin v0.3.0
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Step 3 needs no waiting because the Release workflow's fetch waits for the
|
|
133
|
+
binaries itself (`MCPTASK_WAIT_FOR_RELEASE`, 15 minutes against a Go release
|
|
134
|
+
that takes about four). It then verifies each archive against the release's
|
|
135
|
+
`checksums.txt`, builds the platform gems and publishes them to rubygems.org
|
|
136
|
+
through OIDC trusted publishing. A tag that disagrees with `version.rb` is
|
|
137
|
+
refused before anything is downloaded. See `.github/workflows/release.yml`.
|
|
92
138
|
|
|
93
139
|
One-time setup on rubygems.org, before the first tag can publish anything —
|
|
94
140
|
the gem name has to exist as a trusted-publisher entry:
|
|
@@ -1,31 +1,52 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "fileutils"
|
|
4
|
+
|
|
3
5
|
module McptaskRailsRunner
|
|
4
|
-
# Locates and executes the bundled Go binary.
|
|
6
|
+
# Locates, installs and executes the bundled Go binary.
|
|
5
7
|
module Binary
|
|
6
8
|
GEM_ROOT = File.expand_path("../..", __dir__)
|
|
7
9
|
|
|
8
10
|
SUPPORTED_PLATFORMS = %w[
|
|
9
11
|
arm64-darwin
|
|
10
12
|
x86_64-darwin
|
|
11
|
-
|
|
13
|
+
aarch64-linux
|
|
12
14
|
x86_64-linux
|
|
13
15
|
x64-mingw-ucrt
|
|
14
16
|
].freeze
|
|
15
17
|
|
|
18
|
+
# Where the binary is installed to live, outside every gem directory.
|
|
19
|
+
#
|
|
20
|
+
# The scheduled job runs this path, and it has to be one that survives a
|
|
21
|
+
# `bundle update`: a job pointing into
|
|
22
|
+
# gems/mcptask-rails-runner-<version>-<platform>/libexec dies the moment the
|
|
23
|
+
# gem is bumped, at 08:00, in a log nobody reads. Under the runner's own
|
|
24
|
+
# ~/.mcptask rather than /usr/local/bin, because `bundle install` has no
|
|
25
|
+
# sudo and a gem cannot write there. The Go side knows the same path — see
|
|
26
|
+
# InstalledBinary in internal/install/schedule.go.
|
|
27
|
+
INSTALL_DIR = File.join(Dir.home, ".mcptask", "bin")
|
|
28
|
+
|
|
29
|
+
# The line `mcptask_runner version` prints the version on.
|
|
30
|
+
VERSION_LINE = /Version:\s*(\S+)/
|
|
31
|
+
|
|
16
32
|
module_function
|
|
17
33
|
|
|
18
34
|
def executable_name
|
|
19
35
|
Gem.win_platform? ? "mcptask_runner.exe" : "mcptask_runner"
|
|
20
36
|
end
|
|
21
37
|
|
|
22
|
-
# Absolute path to the
|
|
23
|
-
# binary shares the mcptask_runner name with the legacy gem's rake
|
|
38
|
+
# Absolute path to the binary this gem runs. Never resolved through PATH:
|
|
39
|
+
# the binary shares the mcptask_runner name with the legacy gem's rake
|
|
24
40
|
# namespace, and a PATH lookup could pick up a stale or wrong install.
|
|
25
41
|
def path(gem_root: GEM_ROOT)
|
|
26
42
|
override = ENV["MCPTASK_RUNNER_BIN"]
|
|
27
43
|
return override unless override.nil? || override.empty?
|
|
28
44
|
|
|
45
|
+
bundled_path(gem_root: gem_root)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# The copy that ships inside this gem, which is the one the Gemfile pins.
|
|
49
|
+
def bundled_path(gem_root: GEM_ROOT)
|
|
29
50
|
exe = File.join(gem_root, "libexec", executable_name)
|
|
30
51
|
return exe if File.file?(exe)
|
|
31
52
|
|
|
@@ -43,10 +64,91 @@ module McptaskRailsRunner
|
|
|
43
64
|
MSG
|
|
44
65
|
end
|
|
45
66
|
|
|
67
|
+
# The version-free path the installed copy lives at.
|
|
68
|
+
def installed_path(install_dir: INSTALL_DIR)
|
|
69
|
+
File.join(install_dir, executable_name)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Copies the bundled binary out of the gem, and returns what to run.
|
|
73
|
+
#
|
|
74
|
+
# The gem bootstraps the binary; it does not host it. Everything the
|
|
75
|
+
# scheduled job touches has to outlive `bundle update`, and a gem directory
|
|
76
|
+
# does not — so install and update put a copy where nothing but they will
|
|
77
|
+
# ever move it. A copy rather than a symlink: a link into the gem's libexec
|
|
78
|
+
# dangles on the same bundle update, which is the identical 08:00 failure
|
|
79
|
+
# moved one step along, and Windows wants a privilege for symlinks besides.
|
|
80
|
+
#
|
|
81
|
+
# Teaching the launcher to run `bundle exec rake` instead would fix the path
|
|
82
|
+
# and put bundler and Gemfile.lock back into the 08:00 path — the layer the
|
|
83
|
+
# Go port set out to remove.
|
|
84
|
+
#
|
|
85
|
+
# Newest wins, and says so. A host with several projects has several gem
|
|
86
|
+
# versions and one installed binary, so a project pinning an older gem must
|
|
87
|
+
# not quietly drag the machine's runner backwards.
|
|
88
|
+
def install!(install_dir: INSTALL_DIR, gem_root: GEM_ROOT, out: $stdout)
|
|
89
|
+
override = ENV["MCPTASK_RUNNER_BIN"]
|
|
90
|
+
unless override.nil? || override.empty?
|
|
91
|
+
out.puts "[mcptask_runner] MCPTASK_RUNNER_BIN is set — running #{override} " \
|
|
92
|
+
"and leaving #{installed_path(install_dir: install_dir)} alone."
|
|
93
|
+
return override
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
source = bundled_path(gem_root: gem_root)
|
|
97
|
+
target = installed_path(install_dir: install_dir)
|
|
98
|
+
|
|
99
|
+
existing = installed_version(target)
|
|
100
|
+
if existing && existing > Gem::Version.new(VERSION)
|
|
101
|
+
out.puts "[mcptask_runner] #{target} already holds #{existing}, which is newer than this " \
|
|
102
|
+
"gem's #{VERSION} — keeping it. Delete that file to install this gem's binary instead."
|
|
103
|
+
return target
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
copy(source, target)
|
|
107
|
+
out.puts "[mcptask_runner] installed mcptask_runner #{VERSION} into #{target}" \
|
|
108
|
+
"#{existing ? " (replacing #{existing})" : ''}."
|
|
109
|
+
target
|
|
110
|
+
end
|
|
111
|
+
|
|
46
112
|
# Replaces the current process, so the binary's exit code and signal
|
|
47
113
|
# handling reach the caller (rake) unchanged.
|
|
48
114
|
def exec!(*args)
|
|
49
115
|
Kernel.exec(path, *args)
|
|
50
116
|
end
|
|
117
|
+
|
|
118
|
+
# Installs the binary outside the gem first, then runs that copy.
|
|
119
|
+
#
|
|
120
|
+
# Used by install and update, the two tasks that generate the scheduled job:
|
|
121
|
+
# the job runs whichever binary is executing them, so it has to be the copy
|
|
122
|
+
# at the version-free path rather than the one inside this gem.
|
|
123
|
+
def exec_installed!(*args)
|
|
124
|
+
Kernel.exec(install!, *args)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# What the installed copy reports about itself, or nil when there is none —
|
|
128
|
+
# or when it cannot be asked, which a stray file at that path cannot be.
|
|
129
|
+
#
|
|
130
|
+
# Asked of the binary rather than recorded in a marker file beside it: the
|
|
131
|
+
# binary is what actually runs at 08:00, and a marker can only be right
|
|
132
|
+
# about installs that went through here.
|
|
133
|
+
def installed_version(target)
|
|
134
|
+
return nil unless File.file?(target)
|
|
135
|
+
|
|
136
|
+
banner = IO.popen([target, "version"], err: File::NULL, &:read)
|
|
137
|
+
raw = banner.to_s[VERSION_LINE, 1]
|
|
138
|
+
raw && Gem::Version.new(raw)
|
|
139
|
+
rescue StandardError
|
|
140
|
+
nil
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Written beside the target and renamed into place: a half-copied binary
|
|
144
|
+
# over a working one is a scheduled job that fails on a corrupt file, and
|
|
145
|
+
# the rename also sidesteps the ETXTBSY a running copy would give.
|
|
146
|
+
def copy(source, target)
|
|
147
|
+
FileUtils.mkdir_p(File.dirname(target))
|
|
148
|
+
staged = "#{target}.new"
|
|
149
|
+
FileUtils.cp(source, staged)
|
|
150
|
+
FileUtils.chmod(0o755, staged)
|
|
151
|
+
File.rename(staged, target)
|
|
152
|
+
end
|
|
51
153
|
end
|
|
52
154
|
end
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module McptaskRailsRunner
|
|
4
|
-
# The gem version
|
|
5
|
-
#
|
|
6
|
-
|
|
4
|
+
# The gem version names the mcptask_runner binary release it carries (tag
|
|
5
|
+
# v#{VERSION} in jchsoft/mcptask-releases). Bump both together.
|
|
6
|
+
#
|
|
7
|
+
# What it does not name is the binary the host runs at 08:00. That one is
|
|
8
|
+
# installed outside every gem directory, by install and update, and a machine
|
|
9
|
+
# has one of it however many projects and gem versions it carries — see
|
|
10
|
+
# Binary::INSTALL_DIR. So the pin is per project and per foreground rake
|
|
11
|
+
# invocation; the installed copy is per machine, and the newest binary any of
|
|
12
|
+
# those projects offers is the one that stays.
|
|
13
|
+
VERSION = "0.3.1"
|
|
7
14
|
end
|
|
@@ -4,18 +4,25 @@
|
|
|
4
4
|
# a customer is only a Gemfile line swap. Every task delegates 1:1 to the
|
|
5
5
|
# bundled Go CLI via Kernel#exec — the binary's exit code and signal handling
|
|
6
6
|
# reach the caller unchanged, and nothing runs after the delegation line.
|
|
7
|
+
#
|
|
8
|
+
# Two of them delegate to the installed copy instead of the bundled one. install
|
|
9
|
+
# and update are the tasks that generate the scheduled job, and the job runs
|
|
10
|
+
# whichever binary generated it: pointing it inside this gem would have it die
|
|
11
|
+
# at the next `bundle update`, which deletes that directory. Everything else
|
|
12
|
+
# runs the binary the Gemfile pins, which is what a foreground rake invocation
|
|
13
|
+
# should do.
|
|
7
14
|
|
|
8
15
|
require "mcptask_rails_runner"
|
|
9
16
|
|
|
10
17
|
namespace :mcptask_runner do
|
|
11
18
|
desc "Install skills, permissions, token and scheduled job into this project"
|
|
12
19
|
task :install do
|
|
13
|
-
McptaskRailsRunner::Binary.
|
|
20
|
+
McptaskRailsRunner::Binary.exec_installed!("init")
|
|
14
21
|
end
|
|
15
22
|
|
|
16
23
|
desc "Refresh bundled skills and helpers"
|
|
17
24
|
task :update do
|
|
18
|
-
McptaskRailsRunner::Binary.
|
|
25
|
+
McptaskRailsRunner::Binary.exec_installed!("update")
|
|
19
26
|
end
|
|
20
27
|
|
|
21
28
|
desc "File a bug against the project with the last run log attached"
|