rubyn-code 0.4.0 → 0.5.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/README.md +247 -9
- data/lib/rubyn_code/agent/conversation.rb +2 -1
- data/lib/rubyn_code/agent/dynamic_tool_schema.rb +2 -1
- data/lib/rubyn_code/agent/llm_caller.rb +4 -2
- data/lib/rubyn_code/agent/loop.rb +7 -3
- data/lib/rubyn_code/agent/response_modes.rb +2 -1
- data/lib/rubyn_code/agent/system_prompt_builder.rb +39 -0
- data/lib/rubyn_code/agent/tool_processor.rb +4 -2
- data/lib/rubyn_code/cli/app.rb +87 -13
- data/lib/rubyn_code/cli/commands/install_skills.rb +44 -0
- data/lib/rubyn_code/cli/commands/list_skills.rb +149 -0
- data/lib/rubyn_code/cli/commands/megaplan.rb +50 -0
- data/lib/rubyn_code/cli/commands/provider.rb +2 -1
- data/lib/rubyn_code/cli/commands/remove_skills.rb +35 -0
- data/lib/rubyn_code/cli/commands/skill.rb +4 -2
- data/lib/rubyn_code/cli/commands/skills.rb +104 -0
- data/lib/rubyn_code/cli/repl.rb +11 -1
- data/lib/rubyn_code/cli/repl_commands.rb +3 -1
- data/lib/rubyn_code/cli/repl_setup.rb +38 -1
- data/lib/rubyn_code/cli/setup.rb +13 -0
- data/lib/rubyn_code/config/defaults.rb +2 -0
- data/lib/rubyn_code/config/settings.rb +5 -2
- data/lib/rubyn_code/context/context_budget.rb +2 -1
- data/lib/rubyn_code/context/manager.rb +3 -3
- data/lib/rubyn_code/ide/handlers/plan_interview_answer_handler.rb +65 -0
- data/lib/rubyn_code/ide/handlers/plan_interview_cancel_handler.rb +22 -0
- data/lib/rubyn_code/ide/handlers/plan_interview_start_handler.rb +53 -0
- data/lib/rubyn_code/ide/handlers/plan_propose_handler.rb +41 -0
- data/lib/rubyn_code/ide/handlers/prompt_handler.rb +6 -3
- data/lib/rubyn_code/ide/handlers/recover_ci_handler.rb +132 -0
- data/lib/rubyn_code/ide/handlers/review_handler.rb +19 -2
- data/lib/rubyn_code/ide/handlers.rb +17 -2
- data/lib/rubyn_code/ide/protocol.rb +17 -1
- data/lib/rubyn_code/ide/server.rb +39 -1
- data/lib/rubyn_code/index/codebase_index.rb +2 -1
- data/lib/rubyn_code/learning/extractor.rb +4 -2
- data/lib/rubyn_code/llm/model_router.rb +2 -1
- data/lib/rubyn_code/mcp/tool_bridge.rb +1 -1
- data/lib/rubyn_code/megaplan/ci_recovery.rb +104 -0
- data/lib/rubyn_code/megaplan/interview_session.rb +245 -0
- data/lib/rubyn_code/megaplan/plan_proposer.rb +153 -0
- data/lib/rubyn_code/observability/usage_reporter.rb +4 -2
- data/lib/rubyn_code/output/diff_renderer.rb +3 -2
- data/lib/rubyn_code/self_test.rb +2 -1
- data/lib/rubyn_code/skills/auto_suggest.rb +131 -0
- data/lib/rubyn_code/skills/catalog.rb +10 -0
- data/lib/rubyn_code/skills/document.rb +8 -2
- data/lib/rubyn_code/skills/gemfile_parser.rb +40 -0
- data/lib/rubyn_code/skills/loader.rb +1 -1
- data/lib/rubyn_code/skills/matcher.rb +89 -0
- data/lib/rubyn_code/skills/pack_context.rb +163 -0
- data/lib/rubyn_code/skills/pack_installer.rb +194 -0
- data/lib/rubyn_code/skills/pack_manager.rb +230 -0
- data/lib/rubyn_code/skills/registry_autoload.rb +112 -0
- data/lib/rubyn_code/skills/registry_client.rb +241 -0
- data/lib/rubyn_code/tools/executor.rb +4 -2
- data/lib/rubyn_code/tools/grep.rb +2 -1
- data/lib/rubyn_code/tools/ide_diagnostics.rb +3 -1
- data/lib/rubyn_code/tools/ide_symbols.rb +3 -1
- data/lib/rubyn_code/tools/load_skill.rb +2 -1
- data/lib/rubyn_code/tools/output_compressor.rb +3 -6
- data/lib/rubyn_code/tools/review_pr.rb +15 -4
- data/lib/rubyn_code/tools/web_search.rb +2 -1
- data/lib/rubyn_code/version.rb +1 -1
- data/lib/rubyn_code.rb +20 -0
- data/skills/megaplan/megaplan.md +156 -0
- data/skills/rubyn_self_test.md +75 -0
- metadata +25 -4
|
@@ -24,7 +24,7 @@ module RubynCode
|
|
|
24
24
|
}.freeze
|
|
25
25
|
RISK_LEVEL = :read
|
|
26
26
|
|
|
27
|
-
def execute(base_branch: 'main', focus: 'all')
|
|
27
|
+
def execute(base_branch: 'main', focus: 'all', pack_context: nil)
|
|
28
28
|
error = validate_git_repo
|
|
29
29
|
return error if error
|
|
30
30
|
|
|
@@ -37,7 +37,7 @@ module RubynCode
|
|
|
37
37
|
diff = run_git("diff #{base_branch}...HEAD")
|
|
38
38
|
return "No changes found between #{current} and #{base_branch}." if diff.strip.empty?
|
|
39
39
|
|
|
40
|
-
build_full_review(current, base_branch, diff, focus)
|
|
40
|
+
build_full_review(current, base_branch, diff, focus, pack_context: pack_context)
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
FILE_CATEGORIES = [
|
|
@@ -80,8 +80,9 @@ module RubynCode
|
|
|
80
80
|
[nil, "Error: Base branch '#{base_branch}' not found."]
|
|
81
81
|
end
|
|
82
82
|
|
|
83
|
-
def build_full_review(current, base_branch, diff, focus)
|
|
84
|
-
review =
|
|
83
|
+
def build_full_review(current, base_branch, diff, focus, pack_context: nil)
|
|
84
|
+
review = build_pack_context_section(pack_context)
|
|
85
|
+
review.concat(build_review_header(current, base_branch))
|
|
85
86
|
review.concat(build_file_categories(base_branch))
|
|
86
87
|
review.concat(build_focus_section(focus))
|
|
87
88
|
review.concat(build_diff_section(diff))
|
|
@@ -158,6 +159,16 @@ module RubynCode
|
|
|
158
159
|
]
|
|
159
160
|
end
|
|
160
161
|
|
|
162
|
+
def build_pack_context_section(pack_context)
|
|
163
|
+
return [] if pack_context.nil? || pack_context.strip.empty?
|
|
164
|
+
|
|
165
|
+
[
|
|
166
|
+
'## Skill Pack Context',
|
|
167
|
+
pack_context.strip,
|
|
168
|
+
''
|
|
169
|
+
]
|
|
170
|
+
end
|
|
171
|
+
|
|
161
172
|
def run_git(command)
|
|
162
173
|
`cd #{project_root} && git #{command} 2>/dev/null`
|
|
163
174
|
end
|
|
@@ -85,7 +85,8 @@ module RubynCode
|
|
|
85
85
|
html.scan(%r{<a[^>]+href="(https?://(?!lite\.duckduckgo)[^"]+)"[^>]*>(.*?)</a>}i)
|
|
86
86
|
end
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
# -- HTML parsing with filtering
|
|
89
|
+
def build_ddg_results(links, snippets, max)
|
|
89
90
|
results = []
|
|
90
91
|
links.each_with_index do |match, idx|
|
|
91
92
|
break if results.length >= max
|
data/lib/rubyn_code/version.rb
CHANGED
data/lib/rubyn_code.rb
CHANGED
|
@@ -137,7 +137,16 @@ module RubynCode
|
|
|
137
137
|
autoload :Loader, 'rubyn_code/skills/loader'
|
|
138
138
|
autoload :Catalog, 'rubyn_code/skills/catalog'
|
|
139
139
|
autoload :Document, 'rubyn_code/skills/document'
|
|
140
|
+
autoload :Matcher, 'rubyn_code/skills/matcher'
|
|
141
|
+
autoload :RegistryAutoload, 'rubyn_code/skills/registry_autoload'
|
|
140
142
|
autoload :TtlManager, 'rubyn_code/skills/ttl_manager'
|
|
143
|
+
autoload :RegistryClient, 'rubyn_code/skills/registry_client'
|
|
144
|
+
autoload :PackManager, 'rubyn_code/skills/pack_manager'
|
|
145
|
+
autoload :PackInstaller, 'rubyn_code/skills/pack_installer'
|
|
146
|
+
autoload :PackContext, 'rubyn_code/skills/pack_context'
|
|
147
|
+
autoload :GemfileParser, 'rubyn_code/skills/gemfile_parser'
|
|
148
|
+
autoload :AutoSuggest, 'rubyn_code/skills/auto_suggest'
|
|
149
|
+
autoload :RegistryError, 'rubyn_code/skills/registry_client'
|
|
141
150
|
end
|
|
142
151
|
|
|
143
152
|
# Layer 6: Sub-Agents
|
|
@@ -153,6 +162,13 @@ module RubynCode
|
|
|
153
162
|
autoload :Models, 'rubyn_code/tasks/models'
|
|
154
163
|
end
|
|
155
164
|
|
|
165
|
+
# Layer 7b: Megaplan
|
|
166
|
+
module Megaplan
|
|
167
|
+
autoload :PlanProposer, 'rubyn_code/megaplan/plan_proposer'
|
|
168
|
+
autoload :InterviewSession, 'rubyn_code/megaplan/interview_session'
|
|
169
|
+
autoload :CiRecovery, 'rubyn_code/megaplan/ci_recovery'
|
|
170
|
+
end
|
|
171
|
+
|
|
156
172
|
# Layer 8: Background
|
|
157
173
|
module Background
|
|
158
174
|
autoload :Worker, 'rubyn_code/background/worker'
|
|
@@ -284,6 +300,10 @@ module RubynCode
|
|
|
284
300
|
autoload :Model, 'rubyn_code/cli/commands/model'
|
|
285
301
|
autoload :NewSession, 'rubyn_code/cli/commands/new_session'
|
|
286
302
|
autoload :Provider, 'rubyn_code/cli/commands/provider'
|
|
303
|
+
autoload :InstallSkills, 'rubyn_code/cli/commands/install_skills'
|
|
304
|
+
autoload :RemoveSkills, 'rubyn_code/cli/commands/remove_skills'
|
|
305
|
+
autoload :Skills, 'rubyn_code/cli/commands/skills'
|
|
306
|
+
autoload :Megaplan, 'rubyn_code/cli/commands/megaplan'
|
|
287
307
|
end
|
|
288
308
|
end
|
|
289
309
|
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: megaplan
|
|
3
|
+
description: Phased project planning. Interview the user one question at a time, then scaffold numbered phase folders (requirements/design/tasks). Trigger phrases include "megaplan", "mega plan", "plan phases", "phase this out", or any feature spanning 3+ PRs.
|
|
4
|
+
tags:
|
|
5
|
+
- planning
|
|
6
|
+
- process
|
|
7
|
+
- phases
|
|
8
|
+
- megaplan
|
|
9
|
+
triggers:
|
|
10
|
+
- megaplan
|
|
11
|
+
- mega plan
|
|
12
|
+
- plan phases
|
|
13
|
+
- phase this out
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Megaplan — Phased Project Planning
|
|
17
|
+
|
|
18
|
+
Ship in vertical slices. Each phase merges cleanly and leaves the trunk working.
|
|
19
|
+
|
|
20
|
+
## Don't use for
|
|
21
|
+
|
|
22
|
+
- Single-PR features — just do them
|
|
23
|
+
- Pure research / exploration — nothing shippable
|
|
24
|
+
- Work where the *shape* (not just the details) will change weekly — plan something smaller first
|
|
25
|
+
|
|
26
|
+
## Design principles to apply throughout
|
|
27
|
+
|
|
28
|
+
Hold the work to these when proposing phases and reviewing each `design.md`:
|
|
29
|
+
|
|
30
|
+
- **Vertical slices, not horizontal.** A phase touches every layer it needs to be end-to-end testable. The classic anti-pattern this skill exists to prevent: "Phase 1: all models. Phase 2: all controllers. Phase 3: all views." Trunk is unshippable until Phase 3 and Phase 2 has nothing to test. Instead: "Phase 1: one feature, full-stack, behind a flag."
|
|
31
|
+
- **SOLID, applied lightly.** Single Responsibility and Dependency Inversion are the two that actually bite at the phase-design level. The others usually take care of themselves if those two are clean.
|
|
32
|
+
- **KISS.** Skip the abstraction until you have two concrete callers. Three similar lines beat a premature framework. Inline before you extract.
|
|
33
|
+
- **Justify abstractions.** Every new module/service/class in `design.md` needs a one-sentence reason it exists separately. If you can't write it, inline the code.
|
|
34
|
+
|
|
35
|
+
## The workflow
|
|
36
|
+
|
|
37
|
+
### 1. Interview first
|
|
38
|
+
|
|
39
|
+
Don't propose phases until you understand the shape. Walk through the agenda below **one question per turn** — never dump the full list in a single message. The point is to let the operator steer at every step.
|
|
40
|
+
|
|
41
|
+
**How to ask:**
|
|
42
|
+
|
|
43
|
+
- **One topic per turn.** Pick the next unanswered item from the agenda. Ask only about that.
|
|
44
|
+
- **Number the options.** Whenever the question has 2+ plausible answers, present them as a numbered list so the operator can reply with just the number. Include a **recommended** pick (the one you'd default to given what you know so far) and say *why* it's the recommendation in one short line.
|
|
45
|
+
- **Restate locked-in answers at the top of each follow-up.** A running "Decisions so far:" block of one-line bullets, so the operator can spot drift and you can spot contradictions.
|
|
46
|
+
- **Open-ended questions are fine** when no obvious option set exists (e.g. "What's the end-state in user-facing terms?"). Still ask one at a time.
|
|
47
|
+
- **Stop when you're 95% sure of the shape.** Don't run the whole agenda for its own sake — skip topics that are already obvious from context. The agenda is a checklist *for you*, not a script to read aloud.
|
|
48
|
+
|
|
49
|
+
**Agenda (interviewer's checklist, not a dump):**
|
|
50
|
+
|
|
51
|
+
- **Goal** — end state in user-facing terms
|
|
52
|
+
- **Constraints** — deadlines, infra limits, things you can't break
|
|
53
|
+
- **Existing assets** — what's there to build on or rip out
|
|
54
|
+
- **Natural ordering** — dependency sequence (data → API → UI)?
|
|
55
|
+
- **External dependencies** — other teams, third-party APIs, infra access, design review. These reorder phases more than technical concerns do.
|
|
56
|
+
- **Destructive operations** — schema drops, data deletes, deprecations. These need their own phase with an explicit rollback note.
|
|
57
|
+
- **Test strategy** — what coverage is needed?
|
|
58
|
+
- **Done-per-phase** — minimum manual test that proves each phase shipped?
|
|
59
|
+
|
|
60
|
+
### 2. Propose phases, get agreement
|
|
61
|
+
|
|
62
|
+
A good phase:
|
|
63
|
+
- Is a vertical slice — testable end-to-end at merge time
|
|
64
|
+
- Ships independently — trunk works at every boundary
|
|
65
|
+
- Has a clear definition of done
|
|
66
|
+
- Is roughly 1–3 days of focused work
|
|
67
|
+
- Has a name that survives the PR title. If it adds *and* removes, capture both (e.g. "TX-Only Checkout + Geofencing Removal").
|
|
68
|
+
|
|
69
|
+
A good phase list:
|
|
70
|
+
- 3–8 phases for most projects
|
|
71
|
+
- Ordered by dependency, not priority
|
|
72
|
+
- Destructive operations isolated to their own phase
|
|
73
|
+
- Ends with a phase that visibly delivers the goal
|
|
74
|
+
|
|
75
|
+
Propose as a numbered outline. Let the user reorder, merge, or split before any files exist.
|
|
76
|
+
|
|
77
|
+
### 3. Scaffold the structure
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
docs/
|
|
81
|
+
README.md # roadmap tracker
|
|
82
|
+
NN-slug/
|
|
83
|
+
requirements.md # user stories + acceptance criteria
|
|
84
|
+
design.md # architecture + interfaces + test strategy
|
|
85
|
+
tasks.md # numbered checklist
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Numbering: zero-padded (`01-`, `02-`). Slugs: kebab-case, ≤4 words.
|
|
89
|
+
|
|
90
|
+
Default: fully scaffold the *current* phase; future phases stay as one-liners in `README.md` until you start them. Later phases mutate based on what's learned early — don't pre-write what you'll have to rewrite.
|
|
91
|
+
|
|
92
|
+
### 4. Implement phase-by-phase
|
|
93
|
+
|
|
94
|
+
For each phase:
|
|
95
|
+
1. **Read the running architecture doc first** (`CLAUDE.md` or equivalent). That's how you don't repeat decisions or miss constraints from earlier phases.
|
|
96
|
+
2. Branch off main: `git checkout -b phase-NN-slug`
|
|
97
|
+
3. Work `tasks.md` top-to-bottom, checking subtasks as you go
|
|
98
|
+
4. Commit at section boundaries: `Phase N (M/X): description` — where `M` is the current section number and `X` is the total number of sections in `tasks.md`
|
|
99
|
+
5. Run full test suite + lint + format at each commit boundary
|
|
100
|
+
6. When `tasks.md` is fully checked, push and open a PR (see PR description shape below)
|
|
101
|
+
7. After merge: check the box in `docs/README.md`, update the running architecture doc if anything moved
|
|
102
|
+
|
|
103
|
+
## File templates
|
|
104
|
+
|
|
105
|
+
### requirements.md
|
|
106
|
+
|
|
107
|
+
Use RFC 2119 SHALL/SHOULD/MAY language for acceptance criteria. They're contracts — write them as something a QA tester could check.
|
|
108
|
+
|
|
109
|
+
Sections: Overview, Glossary, Requirements (per requirement: user story + numbered SHALL criteria), Out of scope.
|
|
110
|
+
|
|
111
|
+
### design.md
|
|
112
|
+
|
|
113
|
+
Sections: Overview, Architecture (each component gets Responsibility, Collaborators, "Why not inline?"), Data model changes, Test strategy, Migration / rollout, Future enhancements.
|
|
114
|
+
|
|
115
|
+
Every new abstraction needs a justification line. If you can't answer "why not inline this", inline it.
|
|
116
|
+
|
|
117
|
+
### tasks.md
|
|
118
|
+
|
|
119
|
+
Sections (`## [ ] N. <name>`) and tasks (`- [ ] N.M ...`) both get checkboxes. A section ticks only when every task under it ticks. Reference requirements by ID (`refs Req 1.1`) so coverage gaps are visible. Always end with a Validation section that includes the manual smoke flow.
|
|
120
|
+
|
|
121
|
+
## PR description shape
|
|
122
|
+
|
|
123
|
+
Three bullets. Don't pad them.
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
## What shipped
|
|
127
|
+
- <user-facing capability or removal>
|
|
128
|
+
|
|
129
|
+
## What proves it
|
|
130
|
+
- <new tests, smoke flow, manual check>
|
|
131
|
+
|
|
132
|
+
## What's deferred
|
|
133
|
+
- <link to later phase, or "none">
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Patterns and pitfalls
|
|
137
|
+
|
|
138
|
+
**Patterns to keep:**
|
|
139
|
+
- **Branch per phase:** `phase-NN-slug` — disposable, one PR per branch
|
|
140
|
+
- **Squash-merge:** one phase = one commit on main, full PR description preserved
|
|
141
|
+
- **Plan before code:** `requirements.md` is finalized and `design.md` is sketched before any task in `tasks.md` gets implemented.
|
|
142
|
+
- **Semantic test anchors** so later phases don't break earlier tests
|
|
143
|
+
- **One running architecture doc** kept current — read it before each phase, update it after
|
|
144
|
+
|
|
145
|
+
**When to break the rules:**
|
|
146
|
+
- **Phase grew mid-stream?** Split it. Add `NN-a-slug` / `NN-b-slug` or renumber.
|
|
147
|
+
- **Later phase invalidates an earlier requirement?** Update the earlier doc with a "Superseded by Phase N" note.
|
|
148
|
+
- **Phase ships nothing user-visible** (e.g. refactor prep)? Still its own PR — but say so in the description.
|
|
149
|
+
|
|
150
|
+
**Pitfalls to avoid:**
|
|
151
|
+
- **Horizontal-slice phases** (all models / all controllers / all views). Trunk is unshippable until the last phase merges.
|
|
152
|
+
- **Scaffolding all phases upfront in full detail** — later phases get invalidated by what you learn early.
|
|
153
|
+
- **Phases longer than ~3 days** — the phase should split. Long phases hide scope creep.
|
|
154
|
+
- **Requirements without acceptance criteria** — "Make X work" isn't a requirement; "When <condition>, the system SHALL <observable behavior>" is.
|
|
155
|
+
- **Tasks that don't reference requirements** — if you can't cite which requirement a task serves, the task probably isn't load-bearing.
|
|
156
|
+
- **Destructive operations mixed with feature work** — schema drops, deletes, deprecations belong in their own phase with a rollback note.
|
data/skills/rubyn_self_test.md
CHANGED
|
@@ -115,6 +115,81 @@ Score: 18/22 (82%) — 4 failures
|
|
|
115
115
|
- **glob**: Check that all 16 layer directories exist under `lib/rubyn_code/`. PASS if at least 14 found.
|
|
116
116
|
- **read_file**: Read `lib/rubyn_code.rb` and verify it has modules for Agent, Tools, Context, Skills, Memory, Observability, Learning. PASS if all 7 found.
|
|
117
117
|
|
|
118
|
+
### 15. Skill-Pack Autoload — Live Registry Roundtrip
|
|
119
|
+
|
|
120
|
+
End-to-end exercise of the autoload pipeline against the real registry at `rubyn.ai`: fetch the catalog, install a pack the user does **not** already have, verify it works on disk + in the catalog + through the matcher, then remove it. The user's pre-existing installed packs are not touched.
|
|
121
|
+
|
|
122
|
+
- **Live roundtrip**: `bash` with the script below. PASS if the final line is `ROUNDTRIP: PASS`. SKIP if the final line starts with `SKIP:` (means every registry pack is already installed locally — rare).
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
bundle exec ruby -e '
|
|
126
|
+
require_relative "lib/rubyn_code"
|
|
127
|
+
|
|
128
|
+
client = RubynCode::Skills::RegistryClient.new
|
|
129
|
+
pack_manager = RubynCode::Skills::PackManager.new
|
|
130
|
+
|
|
131
|
+
catalog_packs = client.fetch_catalog[:data] || []
|
|
132
|
+
abort "FAIL: empty registry catalog" if catalog_packs.empty?
|
|
133
|
+
|
|
134
|
+
already_installed = catalog_packs.map { |p| p[:name] || p["name"] }
|
|
135
|
+
.select { |n| pack_manager.installed?(n) }
|
|
136
|
+
target = catalog_packs.find { |p| !already_installed.include?(p[:name] || p["name"]) }
|
|
137
|
+
abort "SKIP: every registry pack is already installed" if target.nil?
|
|
138
|
+
|
|
139
|
+
name = target[:name] || target["name"]
|
|
140
|
+
puts "TEST PACK: #{name}"
|
|
141
|
+
|
|
142
|
+
success = false
|
|
143
|
+
begin
|
|
144
|
+
result = client.fetch_pack(name)
|
|
145
|
+
pack_manager.install(result[:data], etag: result[:etag])
|
|
146
|
+
raise "install did not create directory" unless pack_manager.installed?(name)
|
|
147
|
+
puts "STEP install: PASS"
|
|
148
|
+
|
|
149
|
+
catalog_obj = RubynCode::Skills::Catalog.new(
|
|
150
|
+
File.join(Dir.home, ".rubyn-code", "skill-packs")
|
|
151
|
+
)
|
|
152
|
+
skills = catalog_obj.available.select { |e| e[:path].include?("/#{name}/") }
|
|
153
|
+
raise "catalog sees no skills" if skills.empty?
|
|
154
|
+
raise "no skills have triggers" if skills.none? { |s| !s[:triggers].empty? }
|
|
155
|
+
puts "STEP catalog: PASS (#{skills.size} skills, #{skills.count { |s| !s[:triggers].empty? }} with triggers)"
|
|
156
|
+
|
|
157
|
+
sample = skills.find { |s| !s[:triggers].empty? }
|
|
158
|
+
matcher = RubynCode::Skills::Matcher.new(catalog: catalog_obj)
|
|
159
|
+
hits = matcher.match("question about #{sample[:triggers].first}")
|
|
160
|
+
raise "matcher did not hit on \"#{sample[:triggers].first}\"" if hits.none? { |h| h[:name] == sample[:name] }
|
|
161
|
+
puts "STEP matcher: PASS (hit \"#{sample[:name]}\" via \"#{sample[:triggers].first}\")"
|
|
162
|
+
success = true
|
|
163
|
+
ensure
|
|
164
|
+
pack_manager.remove(name)
|
|
165
|
+
if pack_manager.installed?(name)
|
|
166
|
+
puts "STEP cleanup: FAIL (pack still on disk)"
|
|
167
|
+
else
|
|
168
|
+
puts "STEP cleanup: PASS"
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
puts(success ? "ROUNDTRIP: PASS" : "ROUNDTRIP: FAIL")
|
|
173
|
+
'
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
The script:
|
|
177
|
+
1. Fetches the registry catalog (proves the static API at `rubyn.ai/api/v1/skills/packs.json` is reachable).
|
|
178
|
+
2. Picks the first pack the user does **not** have installed, so we never touch their existing packs.
|
|
179
|
+
3. Installs the pack via `RegistryClient#fetch_pack` + `PackManager#install` — exactly the path the autoload pipeline uses.
|
|
180
|
+
4. Reads the disk back through a fresh `Skills::Catalog` and confirms the new skills are visible with parsed triggers.
|
|
181
|
+
5. Runs `Skills::Matcher#match` against a real trigger from one of the freshly-installed skills, confirming the matcher would have fired in a real session.
|
|
182
|
+
6. Removes the pack in an `ensure` block so a partial failure still leaves the user's system clean.
|
|
183
|
+
|
|
184
|
+
PASS criteria: `STEP install`, `STEP catalog`, `STEP matcher`, and `STEP cleanup` all `PASS`, with a final `ROUNDTRIP: PASS`.
|
|
185
|
+
|
|
186
|
+
- **Live autoload notification (manual verification, not scored)**: This isn't a tool call — it's a hint to surface in the scorecard for the user. Tell them: after the self-test completes, send a follow-up prompt that includes a trigger word from any pack in the registry (e.g. `"explain turbo drive"`). The Rubyn renderer should print:
|
|
187
|
+
```
|
|
188
|
+
📥 Fetching skill pack 'hotwire' from registry…
|
|
189
|
+
📚 Loaded: turbo-drive
|
|
190
|
+
```
|
|
191
|
+
before the next response (the `📥` line appears only if the pack wasn't already installed). Do **not** count this as PASS/FAIL — just mention it in the scorecard so the user can verify the renderer side themselves.
|
|
192
|
+
|
|
118
193
|
## Scoring
|
|
119
194
|
|
|
120
195
|
Count total PASS results out of total tests run. Report the percentage.
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubyn-code
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- fadedmaturity
|
|
@@ -226,16 +226,21 @@ files:
|
|
|
226
226
|
- lib/rubyn_code/cli/commands/diff.rb
|
|
227
227
|
- lib/rubyn_code/cli/commands/doctor.rb
|
|
228
228
|
- lib/rubyn_code/cli/commands/help.rb
|
|
229
|
+
- lib/rubyn_code/cli/commands/install_skills.rb
|
|
230
|
+
- lib/rubyn_code/cli/commands/list_skills.rb
|
|
229
231
|
- lib/rubyn_code/cli/commands/mcp.rb
|
|
232
|
+
- lib/rubyn_code/cli/commands/megaplan.rb
|
|
230
233
|
- lib/rubyn_code/cli/commands/model.rb
|
|
231
234
|
- lib/rubyn_code/cli/commands/new_session.rb
|
|
232
235
|
- lib/rubyn_code/cli/commands/plan.rb
|
|
233
236
|
- lib/rubyn_code/cli/commands/provider.rb
|
|
234
237
|
- lib/rubyn_code/cli/commands/quit.rb
|
|
235
238
|
- lib/rubyn_code/cli/commands/registry.rb
|
|
239
|
+
- lib/rubyn_code/cli/commands/remove_skills.rb
|
|
236
240
|
- lib/rubyn_code/cli/commands/resume.rb
|
|
237
241
|
- lib/rubyn_code/cli/commands/review.rb
|
|
238
242
|
- lib/rubyn_code/cli/commands/skill.rb
|
|
243
|
+
- lib/rubyn_code/cli/commands/skills.rb
|
|
239
244
|
- lib/rubyn_code/cli/commands/spawn.rb
|
|
240
245
|
- lib/rubyn_code/cli/commands/tasks.rb
|
|
241
246
|
- lib/rubyn_code/cli/commands/tokens.rb
|
|
@@ -290,7 +295,12 @@ files:
|
|
|
290
295
|
- lib/rubyn_code/ide/handlers/config_set_handler.rb
|
|
291
296
|
- lib/rubyn_code/ide/handlers/initialize_handler.rb
|
|
292
297
|
- lib/rubyn_code/ide/handlers/models_list_handler.rb
|
|
298
|
+
- lib/rubyn_code/ide/handlers/plan_interview_answer_handler.rb
|
|
299
|
+
- lib/rubyn_code/ide/handlers/plan_interview_cancel_handler.rb
|
|
300
|
+
- lib/rubyn_code/ide/handlers/plan_interview_start_handler.rb
|
|
301
|
+
- lib/rubyn_code/ide/handlers/plan_propose_handler.rb
|
|
293
302
|
- lib/rubyn_code/ide/handlers/prompt_handler.rb
|
|
303
|
+
- lib/rubyn_code/ide/handlers/recover_ci_handler.rb
|
|
294
304
|
- lib/rubyn_code/ide/handlers/review_handler.rb
|
|
295
305
|
- lib/rubyn_code/ide/handlers/session_fork_handler.rb
|
|
296
306
|
- lib/rubyn_code/ide/handlers/session_list_handler.rb
|
|
@@ -326,6 +336,9 @@ files:
|
|
|
326
336
|
- lib/rubyn_code/mcp/sse_transport.rb
|
|
327
337
|
- lib/rubyn_code/mcp/stdio_transport.rb
|
|
328
338
|
- lib/rubyn_code/mcp/tool_bridge.rb
|
|
339
|
+
- lib/rubyn_code/megaplan/ci_recovery.rb
|
|
340
|
+
- lib/rubyn_code/megaplan/interview_session.rb
|
|
341
|
+
- lib/rubyn_code/megaplan/plan_proposer.rb
|
|
329
342
|
- lib/rubyn_code/memory/RUBYN.md
|
|
330
343
|
- lib/rubyn_code/memory/models.rb
|
|
331
344
|
- lib/rubyn_code/memory/search.rb
|
|
@@ -353,9 +366,17 @@ files:
|
|
|
353
366
|
- lib/rubyn_code/protocols/shutdown_handshake.rb
|
|
354
367
|
- lib/rubyn_code/self_test.rb
|
|
355
368
|
- lib/rubyn_code/skills/RUBYN.md
|
|
369
|
+
- lib/rubyn_code/skills/auto_suggest.rb
|
|
356
370
|
- lib/rubyn_code/skills/catalog.rb
|
|
357
371
|
- lib/rubyn_code/skills/document.rb
|
|
372
|
+
- lib/rubyn_code/skills/gemfile_parser.rb
|
|
358
373
|
- lib/rubyn_code/skills/loader.rb
|
|
374
|
+
- lib/rubyn_code/skills/matcher.rb
|
|
375
|
+
- lib/rubyn_code/skills/pack_context.rb
|
|
376
|
+
- lib/rubyn_code/skills/pack_installer.rb
|
|
377
|
+
- lib/rubyn_code/skills/pack_manager.rb
|
|
378
|
+
- lib/rubyn_code/skills/registry_autoload.rb
|
|
379
|
+
- lib/rubyn_code/skills/registry_client.rb
|
|
359
380
|
- lib/rubyn_code/skills/ttl_manager.rb
|
|
360
381
|
- lib/rubyn_code/sub_agents/RUBYN.md
|
|
361
382
|
- lib/rubyn_code/sub_agents/runner.rb
|
|
@@ -440,6 +461,7 @@ files:
|
|
|
440
461
|
- skills/gems/rubocop.md
|
|
441
462
|
- skills/gems/sidekiq.md
|
|
442
463
|
- skills/gems/stripe.md
|
|
464
|
+
- skills/megaplan/megaplan.md
|
|
443
465
|
- skills/minitest/assertions.md
|
|
444
466
|
- skills/minitest/fixtures.md
|
|
445
467
|
- skills/minitest/integration_tests.md
|
|
@@ -530,8 +552,7 @@ post_install_message: |
|
|
|
530
552
|
Rubyn Code installed! Run `rubyn-code --setup` to pin it to this Ruby
|
|
531
553
|
so it works in any project regardless of .ruby-version.
|
|
532
554
|
|
|
533
|
-
Tip:
|
|
534
|
-
RBENV_VERSION=4.0.2 gem install rubyn-code && rubyn-code --setup
|
|
555
|
+
Tip: install under your latest Ruby for best performance.
|
|
535
556
|
rdoc_options: []
|
|
536
557
|
require_paths:
|
|
537
558
|
- lib
|
|
@@ -539,7 +560,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
539
560
|
requirements:
|
|
540
561
|
- - ">="
|
|
541
562
|
- !ruby/object:Gem::Version
|
|
542
|
-
version:
|
|
563
|
+
version: 4.0.2
|
|
543
564
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
544
565
|
requirements:
|
|
545
566
|
- - ">="
|