ruby-skills 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +46 -0
- data/.yardopts +5 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +110 -0
- data/LICENSE +0 -0
- data/README.md +120 -0
- data/Rakefile +17 -0
- data/bin/ruby-skills +6 -0
- data/lib/ruby_skills/adapters/base.rb +57 -0
- data/lib/ruby_skills/adapters/claude.rb +19 -0
- data/lib/ruby_skills/adapters/codex.rb +19 -0
- data/lib/ruby_skills/adapters/cursor.rb +19 -0
- data/lib/ruby_skills/adapters/vscode.rb +19 -0
- data/lib/ruby_skills/cli.rb +146 -0
- data/lib/ruby_skills/config.rb +72 -0
- data/lib/ruby_skills/installer.rb +87 -0
- data/lib/ruby_skills/lockfile.rb +84 -0
- data/lib/ruby_skills/manifest.rb +91 -0
- data/lib/ruby_skills/remover.rb +50 -0
- data/lib/ruby_skills/resolver.rb +107 -0
- data/lib/ruby_skills/updater.rb +32 -0
- data/lib/ruby_skills/version.rb +8 -0
- data/lib/ruby_skills.rb +20 -0
- data/ruby-skills.gemspec +51 -0
- metadata +169 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 7280b4bcc88be0ead80c3553f82357e294dff35ea86d6c9ac6d8887d3191bd5c
|
|
4
|
+
data.tar.gz: e69af730461bdeadf3f11778f5dfd208b5d2288c70ec2edcee3db226f561b449
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 51aab53ad414ea98a590a0cfc458d6a34b525501c70fa27eefb17e09d51e4a168b7dc5a6926910c366ebf031635d2e79235f7ad3ec6011353965b120ce891a56
|
|
7
|
+
data.tar.gz: 9c4d8b9776bda7309d9500e2c4223e09792338d221eae62d89e789b98b61845cc2b0a0254d5c0cf687658d0e9e65990f99be2d8788e6ad297fad1cd0260252b4
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
plugins:
|
|
2
|
+
- rubocop-performance
|
|
3
|
+
- rubocop-rspec
|
|
4
|
+
|
|
5
|
+
AllCops:
|
|
6
|
+
NewCops: enable
|
|
7
|
+
TargetRubyVersion: 3.1
|
|
8
|
+
SuggestExtensions: false
|
|
9
|
+
Exclude:
|
|
10
|
+
- "bin/*"
|
|
11
|
+
- "tmp/**/*"
|
|
12
|
+
- "vendor/**/*"
|
|
13
|
+
- "doc/**/*"
|
|
14
|
+
|
|
15
|
+
Layout/LineLength:
|
|
16
|
+
Max: 100
|
|
17
|
+
|
|
18
|
+
Metrics/AbcSize:
|
|
19
|
+
Enabled: false
|
|
20
|
+
|
|
21
|
+
Metrics/MethodLength:
|
|
22
|
+
Enabled: false
|
|
23
|
+
|
|
24
|
+
Style/StringLiterals:
|
|
25
|
+
EnforcedStyle: double_quotes
|
|
26
|
+
|
|
27
|
+
Style/StringLiteralsInInterpolation:
|
|
28
|
+
EnforcedStyle: double_quotes
|
|
29
|
+
|
|
30
|
+
Style/BlockDelimiters:
|
|
31
|
+
EnforcedStyle: semantic
|
|
32
|
+
|
|
33
|
+
Style/OptionalBooleanParameter:
|
|
34
|
+
Enabled: false
|
|
35
|
+
|
|
36
|
+
Gemspec/DevelopmentDependencies:
|
|
37
|
+
Enabled: false
|
|
38
|
+
|
|
39
|
+
RSpec/ExampleLength:
|
|
40
|
+
Max: 40
|
|
41
|
+
|
|
42
|
+
RSpec/MultipleExpectations:
|
|
43
|
+
Max: 8
|
|
44
|
+
|
|
45
|
+
RSpec/MultipleDescribes:
|
|
46
|
+
Enabled: false
|
data/.yardopts
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
ruby-skills (0.1.0)
|
|
5
|
+
thor (~> 1.3)
|
|
6
|
+
|
|
7
|
+
GEM
|
|
8
|
+
remote: https://rubygems.org/
|
|
9
|
+
specs:
|
|
10
|
+
ast (2.4.3)
|
|
11
|
+
diff-lcs (1.6.2)
|
|
12
|
+
json (2.21.2)
|
|
13
|
+
language_server-protocol (3.17.0.6)
|
|
14
|
+
lint_roller (1.1.0)
|
|
15
|
+
parallel (2.1.0)
|
|
16
|
+
parser (3.3.12.0)
|
|
17
|
+
ast (~> 2.4.1)
|
|
18
|
+
racc
|
|
19
|
+
prism (1.9.0)
|
|
20
|
+
racc (1.8.1)
|
|
21
|
+
rainbow (3.1.1)
|
|
22
|
+
rake (13.4.2)
|
|
23
|
+
regexp_parser (2.12.0)
|
|
24
|
+
rspec (3.13.2)
|
|
25
|
+
rspec-core (~> 3.13.0)
|
|
26
|
+
rspec-expectations (~> 3.13.0)
|
|
27
|
+
rspec-mocks (~> 3.13.0)
|
|
28
|
+
rspec-core (3.13.6)
|
|
29
|
+
rspec-support (~> 3.13.0)
|
|
30
|
+
rspec-expectations (3.13.5)
|
|
31
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
32
|
+
rspec-support (~> 3.13.0)
|
|
33
|
+
rspec-mocks (3.13.8)
|
|
34
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
35
|
+
rspec-support (~> 3.13.0)
|
|
36
|
+
rspec-support (3.13.7)
|
|
37
|
+
rubocop (1.89.0)
|
|
38
|
+
json (~> 2.3)
|
|
39
|
+
language_server-protocol (~> 3.17.0.2)
|
|
40
|
+
lint_roller (~> 1.1.0)
|
|
41
|
+
parallel (>= 1.10)
|
|
42
|
+
parser (>= 3.3.0.2)
|
|
43
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
44
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
|
45
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
46
|
+
ruby-progressbar (~> 1.7)
|
|
47
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
48
|
+
rubocop-ast (1.50.0)
|
|
49
|
+
parser (>= 3.3.7.2)
|
|
50
|
+
prism (~> 1.7)
|
|
51
|
+
rubocop-performance (1.27.0)
|
|
52
|
+
lint_roller (~> 1.1)
|
|
53
|
+
rubocop (>= 1.89.0, < 2.0)
|
|
54
|
+
rubocop-ast (>= 1.47.1, < 2.0)
|
|
55
|
+
rubocop-rspec (3.10.2)
|
|
56
|
+
lint_roller (~> 1.1)
|
|
57
|
+
regexp_parser (>= 2.0)
|
|
58
|
+
rubocop (~> 1.86, >= 1.86.2)
|
|
59
|
+
ruby-progressbar (1.13.0)
|
|
60
|
+
thor (1.5.0)
|
|
61
|
+
unicode-display_width (3.2.0)
|
|
62
|
+
unicode-emoji (~> 4.1)
|
|
63
|
+
unicode-emoji (4.2.0)
|
|
64
|
+
yard (0.9.45)
|
|
65
|
+
|
|
66
|
+
PLATFORMS
|
|
67
|
+
ruby
|
|
68
|
+
x86_64-linux
|
|
69
|
+
|
|
70
|
+
DEPENDENCIES
|
|
71
|
+
rake (~> 13.0)
|
|
72
|
+
rspec (~> 3.12)
|
|
73
|
+
rubocop (~> 1.58)
|
|
74
|
+
rubocop-performance (~> 1.20)
|
|
75
|
+
rubocop-rspec (~> 3.0)
|
|
76
|
+
ruby-skills!
|
|
77
|
+
yard (~> 0.9)
|
|
78
|
+
|
|
79
|
+
CHECKSUMS
|
|
80
|
+
ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
|
|
81
|
+
bundler (4.0.17) sha256=214e21431b5665dd2f99df8a5511c6b151d7a72e8015c8b38f8b775b61cbb6c1
|
|
82
|
+
diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962
|
|
83
|
+
json (2.21.2) sha256=1f1d3b7cf2b3ba1a69beca0bb6db13d5438b80bff3cd54cdaaa620b9b07c1c6a
|
|
84
|
+
language_server-protocol (3.17.0.6) sha256=5ef2c0c138f8267e1bc631d3328347d354f96724b0af22f2c79516120443b7f0
|
|
85
|
+
lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
|
|
86
|
+
parallel (2.1.0) sha256=b35258865c2e31134c5ecb708beaaf6772adf9d5efae28e93e99260877b09356
|
|
87
|
+
parser (3.3.12.0) sha256=21a6d7f755d5a24dfbdc6e6b772e4e879a52e7631a88bc5a3a134606052c9828
|
|
88
|
+
prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85
|
|
89
|
+
racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
|
|
90
|
+
rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
|
|
91
|
+
rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
|
|
92
|
+
regexp_parser (2.12.0) sha256=35a916a1d63190ab5c9009457136ae5f3c0c7512d60291d0d1378ba18ce08ebb
|
|
93
|
+
rspec (3.13.2) sha256=206284a08ad798e61f86d7ca3e376718d52c0bc944626b2349266f239f820587
|
|
94
|
+
rspec-core (3.13.6) sha256=a8823c6411667b60a8bca135364351dda34cd55e44ff94c4be4633b37d828b2d
|
|
95
|
+
rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836
|
|
96
|
+
rspec-mocks (3.13.8) sha256=086ad3d3d17533f4237643de0b5c42f04b66348c28bf6b9c2d3f4a3b01af1d47
|
|
97
|
+
rspec-support (3.13.7) sha256=0640e5570872aafefd79867901deeeeb40b0c9875a36b983d85f54fb7381c47c
|
|
98
|
+
rubocop (1.89.0) sha256=4dee8e3ee9c45e474834efd9e8d6fd031e8331c8dacdff0de4ad65ae0a6faae7
|
|
99
|
+
rubocop-ast (1.50.0) sha256=b9ca88300da0803ee222ad20cdb30494c0a784eed06fdc35d254b06d662788db
|
|
100
|
+
rubocop-performance (1.27.0) sha256=eeeb1374d062a368ee1c787b70eb0b0cc4b184cb1f8565f424760946146d61ce
|
|
101
|
+
rubocop-rspec (3.10.2) sha256=0b3e2ecc592cd10ecbf0095bb58d1e357905276e069643523cc19eb7495f65e2
|
|
102
|
+
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
|
|
103
|
+
ruby-skills (0.1.0)
|
|
104
|
+
thor (1.5.0) sha256=e3a9e55fe857e44859ce104a84675ab6e8cd59c650a49106a05f55f136425e73
|
|
105
|
+
unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42
|
|
106
|
+
unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f
|
|
107
|
+
yard (0.9.45) sha256=52e211493f7cb8a3ebf7e104a25a1e73937a3103092545d34cb88fafebb3dc51
|
|
108
|
+
|
|
109
|
+
BUNDLED WITH
|
|
110
|
+
4.0.17
|
data/LICENSE
ADDED
|
File without changes
|
data/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# ruby-skills
|
|
2
|
+
|
|
3
|
+
Package manager for installing, updating, removing, and sharing AI development skills in Ruby and Rails projects.
|
|
4
|
+
|
|
5
|
+
Skills are declared in a `Skillfile`, copied into `.ruby-skills/`, recorded in `Skills.lock`, and exposed to editors through adapters (Claude, Codex, Cursor, VS Code).
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- Ruby 3.2 or later
|
|
10
|
+
- [Thor](https://github.com/rails/thor) `~> 1.3` (pulled in by the gem)
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
From a checkout:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
bundle install
|
|
18
|
+
ruby -Ilib bin/ruby-skills version
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Once published:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
gem install ruby-skills
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick start
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
ruby-skills init
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
That creates a `Skillfile` and a `.ruby-skills/` directory. Declare skills in the Skillfile:
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
# Skillfile
|
|
37
|
+
|
|
38
|
+
skill "rails-performance",
|
|
39
|
+
github: "username/rails-performance"
|
|
40
|
+
|
|
41
|
+
skill "local-review",
|
|
42
|
+
path: "../skills/local-review",
|
|
43
|
+
version: "0.1.0"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Each `skill` needs exactly one source: `github:` (`owner/repo`) or `path:`. `version:` is optional.
|
|
47
|
+
|
|
48
|
+
Then install:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
ruby-skills install
|
|
52
|
+
ruby-skills install rails-performance
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Commands
|
|
56
|
+
|
|
57
|
+
| Command | Description |
|
|
58
|
+
| --- | --- |
|
|
59
|
+
| `ruby-skills init` | Create `Skillfile` and `.ruby-skills/` |
|
|
60
|
+
| `ruby-skills install [SKILL]` | Install one skill, or every skill in the Skillfile |
|
|
61
|
+
| `ruby-skills list` | Print installed skills from `Skills.lock` |
|
|
62
|
+
| `ruby-skills list --json` | Same data as JSON (`-j`) |
|
|
63
|
+
| `ruby-skills update [SKILL]` | Update one skill, or every installed skill |
|
|
64
|
+
| `ruby-skills remove SKILL` | Remove an installed skill |
|
|
65
|
+
| `ruby-skills version` | Print the gem version |
|
|
66
|
+
| `ruby-skills help [COMMAND]` | Command help |
|
|
67
|
+
|
|
68
|
+
Human-readable list:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
Installed skills:
|
|
72
|
+
|
|
73
|
+
rails-performance 0.1.0
|
|
74
|
+
rails-security 0.2.0
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Machine-readable list (`ruby-skills list --json`):
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"skills": [
|
|
82
|
+
{
|
|
83
|
+
"name": "rails-performance",
|
|
84
|
+
"version": "0.1.0",
|
|
85
|
+
"source": "github:username/rails-performance"
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
An empty lockfile prints `{"skills":[]}`. Editors should consume `--json` instead of parsing the table.
|
|
92
|
+
|
|
93
|
+
## Project files
|
|
94
|
+
|
|
95
|
+
| Path | Role |
|
|
96
|
+
| --- | --- |
|
|
97
|
+
| `Skillfile` | Declared skills (Ruby DSL) |
|
|
98
|
+
| `Skills.lock` | Installed name, version, and source |
|
|
99
|
+
| `.ruby-skills/` | Local copies of installed skills |
|
|
100
|
+
|
|
101
|
+
`Skillfile` and `Skills.lock` are gitignored in this repo because they are per-project workspace files created by `init` / `install`.
|
|
102
|
+
|
|
103
|
+
## Editor plugins
|
|
104
|
+
|
|
105
|
+
Install still notifies Claude, Codex, Cursor, and VS Code adapters so the skill is visible in those tools.
|
|
106
|
+
|
|
107
|
+
The VS Code extension lives in [`rubyskills-plugins/rubyskills-vscode`](../rubyskills-plugins/rubyskills-vscode). It wraps this CLI and loads the sidebar from `ruby-skills list --json`.
|
|
108
|
+
|
|
109
|
+
## Development
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
bundle install
|
|
113
|
+
ruby -Ilib bin/ruby-skills help
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Library code is under `lib/ruby_skills/`. The executable is `bin/ruby-skills`.
|
|
117
|
+
|
|
118
|
+
## License
|
|
119
|
+
|
|
120
|
+
MIT
|
data/Rakefile
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/gem_tasks"
|
|
4
|
+
require "rspec/core/rake_task"
|
|
5
|
+
require "rubocop/rake_task"
|
|
6
|
+
require "yard"
|
|
7
|
+
|
|
8
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
9
|
+
RuboCop::RakeTask.new
|
|
10
|
+
|
|
11
|
+
YARD::Rake::YardocTask.new do |t|
|
|
12
|
+
t.files = ["lib/**/*.rb"]
|
|
13
|
+
t.stats_options = ["--list-undoc"]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
task default: :spec
|
|
17
|
+
task docs: :yard
|
data/bin/ruby-skills
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubySkills
|
|
4
|
+
module Adapters
|
|
5
|
+
# Base implementation for skill adapters.
|
|
6
|
+
#
|
|
7
|
+
# Subclasses must define an ADAPTER_INFO constant containing:
|
|
8
|
+
#
|
|
9
|
+
# - :adapter — tool directory under the project root
|
|
10
|
+
# - :directory — directory containing skills
|
|
11
|
+
#
|
|
12
|
+
# @abstract
|
|
13
|
+
# @since 0.1.0
|
|
14
|
+
class Base
|
|
15
|
+
# @param root [String, Pathname] project root
|
|
16
|
+
def initialize(root: Dir.pwd)
|
|
17
|
+
@root = Pathname.new(root)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Install a skill into the adapter destination.
|
|
21
|
+
#
|
|
22
|
+
# @param name [String] skill identifier
|
|
23
|
+
# @param source [String, Pathname] source skill path
|
|
24
|
+
# @return [void]
|
|
25
|
+
def install(name, source)
|
|
26
|
+
link(source, destination_for(name))
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Remove an installed skill.
|
|
30
|
+
#
|
|
31
|
+
# @param name [String] skill identifier
|
|
32
|
+
# @return [void]
|
|
33
|
+
def remove(name)
|
|
34
|
+
FileUtils.rm_rf(destination_for(name))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
attr_reader :root
|
|
40
|
+
|
|
41
|
+
# @return [Hash{Symbol => String}]
|
|
42
|
+
def adapter_info
|
|
43
|
+
self.class::ADAPTER_INFO
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @param name [String]
|
|
47
|
+
# @return [Pathname]
|
|
48
|
+
def destination_for(name)
|
|
49
|
+
root.join(
|
|
50
|
+
adapter_info.fetch(:adapter),
|
|
51
|
+
adapter_info.fetch(:directory),
|
|
52
|
+
name
|
|
53
|
+
)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubySkills
|
|
4
|
+
module Adapters
|
|
5
|
+
# Exposes skills to Claude Code under +.claude/skills+.
|
|
6
|
+
#
|
|
7
|
+
# @see RubySkills::Adapters::Base
|
|
8
|
+
# @since 0.1.0
|
|
9
|
+
class Claude < Base
|
|
10
|
+
# Path fragments that locate Claude skills.
|
|
11
|
+
#
|
|
12
|
+
# @return [Hash{Symbol => String}]
|
|
13
|
+
ADAPTER_INFO = {
|
|
14
|
+
adapter: ".claude",
|
|
15
|
+
directory: "skills"
|
|
16
|
+
}.freeze
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubySkills
|
|
4
|
+
module Adapters
|
|
5
|
+
# Exposes skills to Codex under +.codex/skills+.
|
|
6
|
+
#
|
|
7
|
+
# @see RubySkills::Adapters::Base
|
|
8
|
+
# @since 0.1.0
|
|
9
|
+
class Codex < Base
|
|
10
|
+
# Path fragments that locate Codex skills.
|
|
11
|
+
#
|
|
12
|
+
# @return [Hash{Symbol => String}]
|
|
13
|
+
ADAPTER_INFO = {
|
|
14
|
+
adapter: ".codex",
|
|
15
|
+
directory: "skills"
|
|
16
|
+
}.freeze
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubySkills
|
|
4
|
+
module Adapters
|
|
5
|
+
# Exposes skills to Cursor under +.cursor/skills+.
|
|
6
|
+
#
|
|
7
|
+
# @see RubySkills::Adapters::Base
|
|
8
|
+
# @since 0.1.0
|
|
9
|
+
class Cursor < Base
|
|
10
|
+
# Path fragments that locate Cursor skills.
|
|
11
|
+
#
|
|
12
|
+
# @return [Hash{Symbol => String}]
|
|
13
|
+
ADAPTER_INFO = {
|
|
14
|
+
adapter: ".cursor",
|
|
15
|
+
directory: "skills"
|
|
16
|
+
}.freeze
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubySkills
|
|
4
|
+
module Adapters
|
|
5
|
+
# Exposes skills to VS Code under +.vscode/skills+.
|
|
6
|
+
#
|
|
7
|
+
# @see RubySkills::Adapters::Base
|
|
8
|
+
# @since 0.1.0
|
|
9
|
+
class Vscode < Base
|
|
10
|
+
# Path fragments that locate VS Code skills.
|
|
11
|
+
#
|
|
12
|
+
# @return [Hash{Symbol => String}]
|
|
13
|
+
ADAPTER_INFO = {
|
|
14
|
+
adapter: ".vscode",
|
|
15
|
+
directory: "skills"
|
|
16
|
+
}.freeze
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "thor"
|
|
5
|
+
|
|
6
|
+
module RubySkills
|
|
7
|
+
# Thor-based command-line interface for Ruby Skills.
|
|
8
|
+
#
|
|
9
|
+
# The default command is {#help}. +-h+ and +--help+ are aliases for it.
|
|
10
|
+
#
|
|
11
|
+
# @example Initialize a project
|
|
12
|
+
# RubySkills::CLI.start(["init"])
|
|
13
|
+
#
|
|
14
|
+
# @since 0.1.0
|
|
15
|
+
class CLI < Thor
|
|
16
|
+
# Display name used in Thor help banners.
|
|
17
|
+
package_name "ruby-skills"
|
|
18
|
+
|
|
19
|
+
# Show {#help} when no command is given.
|
|
20
|
+
default_command :help
|
|
21
|
+
|
|
22
|
+
# Accept +-h+ and +--help+ as aliases for {#help}.
|
|
23
|
+
map %w[-h --help] => :help
|
|
24
|
+
|
|
25
|
+
desc "help [COMMAND]", "List all commands or show help for one command"
|
|
26
|
+
# List every available command, or describe a single command.
|
|
27
|
+
#
|
|
28
|
+
# @param command [String, nil] command to describe, or +nil+ to list all
|
|
29
|
+
# @param subcommand [Boolean] whether +command+ is a subcommand
|
|
30
|
+
# @return [void]
|
|
31
|
+
def help(command = nil, subcommand = false)
|
|
32
|
+
super
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
desc "init", "Initialize Ruby Skills in the current project"
|
|
36
|
+
# Create a Skillfile and +.ruby-skills+ directory in the current project.
|
|
37
|
+
#
|
|
38
|
+
# @return [void]
|
|
39
|
+
# @raise [SystemExit] when initialization fails
|
|
40
|
+
def init
|
|
41
|
+
config = Config.new
|
|
42
|
+
|
|
43
|
+
config.initialize_project!
|
|
44
|
+
|
|
45
|
+
say "Ruby Skills initialized"
|
|
46
|
+
say " Skillfile created"
|
|
47
|
+
say " .ruby-skills directory created"
|
|
48
|
+
rescue RubySkills::Error => e
|
|
49
|
+
say "Error: #{e.message}", :red
|
|
50
|
+
exit 1
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
desc "install [Skill]", "Install one skill or all skills from Skillfile"
|
|
54
|
+
# Install one skill or every skill declared in the Skillfile.
|
|
55
|
+
#
|
|
56
|
+
# @param skill [String, nil] skill name to install, or +nil+ to install all
|
|
57
|
+
# @return [void]
|
|
58
|
+
# @raise [SystemExit] when installation fails
|
|
59
|
+
def install(skill = nil)
|
|
60
|
+
Installer.new.install(skill)
|
|
61
|
+
rescue RubySkills::Error => e
|
|
62
|
+
say "Error: #{e.message}", :red
|
|
63
|
+
exit 1
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
desc "list", "List installed skills"
|
|
67
|
+
option :json, type: :boolean, default: false, aliases: "-j",
|
|
68
|
+
desc: "Output installed skills as JSON"
|
|
69
|
+
# Print installed skills from the lockfile.
|
|
70
|
+
#
|
|
71
|
+
# With +--json+, emit a machine-readable payload instead of a table.
|
|
72
|
+
#
|
|
73
|
+
# @return [void]
|
|
74
|
+
def list
|
|
75
|
+
skills = Lockfile.new.skills
|
|
76
|
+
|
|
77
|
+
if options[:json]
|
|
78
|
+
puts JSON.generate(list_payload(skills))
|
|
79
|
+
return
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
if skills.empty?
|
|
83
|
+
say "No skills installed."
|
|
84
|
+
return
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
say "Installed skills:"
|
|
88
|
+
say ""
|
|
89
|
+
|
|
90
|
+
skills.each do |name, data|
|
|
91
|
+
say "#{name.ljust(35)} #{data["version"]}"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
desc "remove SKILL", "Remove an installed skill"
|
|
96
|
+
# Remove an installed skill from the project.
|
|
97
|
+
#
|
|
98
|
+
# @param skill [String] name of the skill to remove
|
|
99
|
+
# @return [void]
|
|
100
|
+
# @raise [SystemExit] when removal fails
|
|
101
|
+
def remove(skill)
|
|
102
|
+
Remover.new.remove(skill)
|
|
103
|
+
rescue RubySkills::Error => e
|
|
104
|
+
say "Error: #{e.message}", :red
|
|
105
|
+
exit 1
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
desc "update [SKILL]", "Update one skill or all installed skills"
|
|
109
|
+
# Update one skill or every installed skill.
|
|
110
|
+
#
|
|
111
|
+
# @param skill [String, nil] skill name to update, or +nil+ to update all
|
|
112
|
+
# @return [void]
|
|
113
|
+
# @raise [SystemExit] when the update fails
|
|
114
|
+
def update(skill = nil)
|
|
115
|
+
Updater.new.update(skill)
|
|
116
|
+
rescue RubySkills::Error => e
|
|
117
|
+
say "Error: #{e.message}", :red
|
|
118
|
+
exit 1
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
desc "version", "Display Ruby Skills version"
|
|
122
|
+
# Print the installed gem version.
|
|
123
|
+
#
|
|
124
|
+
# @return [void]
|
|
125
|
+
def version
|
|
126
|
+
say "ruby-skills #{RubySkills::VERSION}"
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
no_commands do
|
|
130
|
+
# @api private
|
|
131
|
+
# @param skills [Hash{String => Hash}] lockfile skill map
|
|
132
|
+
# @return [Hash] JSON-serializable list payload
|
|
133
|
+
def list_payload(skills)
|
|
134
|
+
{
|
|
135
|
+
"skills" => skills.map do |name, data|
|
|
136
|
+
{
|
|
137
|
+
"name" => name,
|
|
138
|
+
"version" => data["version"],
|
|
139
|
+
"source" => data["source"]
|
|
140
|
+
}
|
|
141
|
+
end
|
|
142
|
+
}
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubySkills
|
|
4
|
+
# Resolves project paths and bootstraps a Ruby Skills workspace.
|
|
5
|
+
#
|
|
6
|
+
# Paths for +Skillfile+, +Skills.lock+ and the local skills directory
|
|
7
|
+
# are derived from a project root.
|
|
8
|
+
#
|
|
9
|
+
# @example Initialize the current directory
|
|
10
|
+
# RubySkills::Config.new.initialize_project!
|
|
11
|
+
#
|
|
12
|
+
# @since 0.1.0
|
|
13
|
+
class Config
|
|
14
|
+
# Filename of the project skill manifest.
|
|
15
|
+
SKILLFILE = "Skillfile"
|
|
16
|
+
|
|
17
|
+
# Filename of the installed-skills lockfile.
|
|
18
|
+
LOCKFILE = "Skills.lock"
|
|
19
|
+
|
|
20
|
+
# Directory where installed skills are stored.
|
|
21
|
+
SKILLS_DIRECTORY = ".ruby-skills"
|
|
22
|
+
|
|
23
|
+
# @param root [String, Pathname] project root used to resolve skill paths
|
|
24
|
+
def initialize(root: Dir.pwd)
|
|
25
|
+
@root = Pathname.new(root)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Create the skills directory and a starter Skillfile when missing.
|
|
29
|
+
#
|
|
30
|
+
# @return [void]
|
|
31
|
+
def initialize_project!
|
|
32
|
+
create_skills_directory
|
|
33
|
+
create_skillfile
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @return [Pathname] absolute path to the project Skillfile
|
|
37
|
+
def skillfile_path
|
|
38
|
+
@root.join(SKILLFILE)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# @return [Pathname] absolute path to the project lockfile
|
|
42
|
+
def lockfile_path
|
|
43
|
+
@root.join(LOCKFILE)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @return [Pathname] absolute path to the local skills directory
|
|
47
|
+
def skills_path
|
|
48
|
+
@root.join(SKILLS_DIRECTORY)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
# @api private
|
|
54
|
+
# @return [void]
|
|
55
|
+
def create_skills_directory
|
|
56
|
+
FileUtils.mkdir_p(skills_path)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @api private
|
|
60
|
+
# @return [void]
|
|
61
|
+
def create_skillfile
|
|
62
|
+
return if skillfile_path.exist?
|
|
63
|
+
|
|
64
|
+
skillfile_path.write(<<~RUBY)
|
|
65
|
+
# Ruby Skills
|
|
66
|
+
|
|
67
|
+
# skill "rails-performance",
|
|
68
|
+
# github: "username/rails-performance"
|
|
69
|
+
RUBY
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|