rubik 0.1.6 → 0.3.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 +4 -4
- data/ATTRIBUTION.md +5 -1
- data/CHANGELOG.md +169 -0
- data/README.md +137 -255
- data/bin/rubik +9 -0
- data/lib/rubik/ast/extraction_result.rb +37 -0
- data/lib/rubik/ast/extractor.rb +35 -9
- data/lib/rubik/ast/graph.rb +27 -1
- data/lib/rubik/ast/treesitter/c_walker.rb +136 -28
- data/lib/rubik/ast/treesitter_extractor.rb +45 -17
- data/lib/rubik/buffer/apply_contract.rb +78 -0
- data/lib/rubik/buffer/manager.rb +61 -5
- data/lib/rubik/cli/workspace_trust.rb +78 -0
- data/lib/rubik/concurrency/event_loop.rb +56 -44
- data/lib/rubik/concurrency/scheduler.rb +7 -24
- data/lib/rubik/context/git_lister.rb +6 -1
- data/lib/rubik/context/scanner.rb +15 -3
- data/lib/rubik/kernel/init.rb +15 -0
- data/lib/rubik/mcp/transport/stdio.rb +14 -11
- data/lib/rubik/orchestrator/auto_apply.rb +1 -1
- data/lib/rubik/orchestrator/subagent/activation.rb +29 -4
- data/lib/rubik/orchestrator/subagent/builtin_types.rb +117 -0
- data/lib/rubik/orchestrator/subagent/dynamic_store.rb +119 -0
- data/lib/rubik/orchestrator/subagent/instance.rb +8 -36
- data/lib/rubik/orchestrator/subagent/journal.rb +77 -4
- data/lib/rubik/orchestrator/subagent/profile_contract.rb +187 -0
- data/lib/rubik/orchestrator/subagent/profile_snapshot.rb +72 -0
- data/lib/rubik/orchestrator/subagent/reuse.rb +2 -1
- data/lib/rubik/orchestrator/subagent/scoped_registry.rb +2 -0
- data/lib/rubik/orchestrator/subagent/spawn_transaction.rb +170 -0
- data/lib/rubik/orchestrator/subagent/start_gate.rb +98 -0
- data/lib/rubik/orchestrator/subagent/supervisor.rb +4 -67
- data/lib/rubik/orchestrator/subagent/type_definition.rb +84 -0
- data/lib/rubik/orchestrator/subagent/type_registry.rb +139 -159
- data/lib/rubik/orchestrator/turn_executor/subagent_channel.rb +4 -2
- data/lib/rubik/platform/process.rb +152 -3
- data/lib/rubik/plugin/manager.rb +148 -71
- data/lib/rubik/plugin/package_inventory.rb +84 -0
- data/lib/rubik/plugin/requires_dag.rb +40 -0
- data/lib/rubik/plugin/storage.rb +100 -14
- data/lib/rubik/prompt/context_builder.rb +54 -20
- data/lib/rubik/prompt/doctrine.rb +158 -22
- data/lib/rubik/prompt/token_estimator.rb +5 -3
- data/lib/rubik/prompt/tool_teachings.rb +19 -12
- data/lib/rubik/repl/commands/buffer.rb +28 -18
- data/lib/rubik/runtime/repair_probe.rb +98 -0
- data/lib/rubik/sandbox/driver/bubblewrap.rb +13 -59
- data/lib/rubik/sandbox/driver/docker.rb +14 -60
- data/lib/rubik/sandbox/driver/podman.rb +13 -56
- data/lib/rubik/sandbox/driver/process.rb +12 -64
- data/lib/rubik/security/blocked_guidance.rb +19 -0
- data/lib/rubik/security/guard.rb +116 -7
- data/lib/rubik/storage/store.rb +52 -11
- data/lib/rubik/tools/builtins/define_subagent.rb +69 -0
- data/lib/rubik/tools/builtins/lifecycle.rb +129 -136
- data/lib/rubik/tools/builtins/storage.rb +8 -5
- data/lib/rubik/tools/builtins/subagent.rb +20 -53
- data/lib/rubik/tools/builtins/synthesis.rb +6 -1
- data/lib/rubik/tools/builtins.rb +1 -0
- data/lib/rubik/tools/diagnostic_reporter.rb +2 -1
- data/lib/rubik/version.rb +1 -1
- metadata +15 -1
data/README.md
CHANGED
|
@@ -1,284 +1,166 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Rubik
|
|
2
2
|
|
|
3
3
|
English | [Türkçe](README.tr.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://github.com/ozgurulukir/rubik/actions/workflows/ci.yml)
|
|
6
|
+
[](https://rubygems.org/gems/rubik)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
[](https://www.ruby-lang.org/)
|
|
9
|
+
[](https://github.com/ozgurulukir/rubik/actions/workflows/ci.yml)
|
|
10
|
+
[](https://github.com/ozgurulukir/rubik/actions/workflows/ci.yml)
|
|
6
11
|
|
|
7
|
-
|
|
8
|
-
[](https://rubygems.org/gems/rubik)
|
|
9
|
-
[](https://www.ruby-lang.org)
|
|
10
|
-
[]()
|
|
11
|
-
[](AGENTS.md)
|
|
12
|
-
[](COMMANDS.md)
|
|
13
|
-
[](CONFIG.md)
|
|
14
|
-
[]()
|
|
12
|
+
## About
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
Rubik is a Ruby terminal coding agent and interactive REPL. It connects an LLM to
|
|
15
|
+
workspace tools for reading and changing code, while staging file edits in a
|
|
16
|
+
reviewable in-memory buffer. Developers can use it as a CLI or embed its runtime
|
|
17
|
+
from Ruby with `require "rubik"`.
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
Rubik is for developers who want an agent in their terminal and control over how
|
|
20
|
+
its changes reach disk. It supports OpenAI-compatible providers, Anthropic, and
|
|
21
|
+
local Ollama. Its security checks and optional OS sandbox are described in
|
|
22
|
+
[Security](SECURITY.md).
|
|
19
23
|
|
|
20
|
-
|
|
24
|
+
## Quickstart
|
|
21
25
|
|
|
22
|
-
|
|
26
|
+
**Prerequisites:** Ruby 3.4 or later and an OpenRouter API key for this example.
|
|
27
|
+
The gem is the shortest install path:
|
|
23
28
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
### From the gem
|
|
27
|
-
|
|
28
|
-
Requires **Ruby 3.4+**:
|
|
29
|
-
|
|
30
|
-
```bash
|
|
29
|
+
```sh
|
|
31
30
|
gem install rubik
|
|
32
31
|
```
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
Set the key in your shell, then start Rubik. Replace the example value with your
|
|
34
|
+
key:
|
|
35
35
|
|
|
36
|
-
```
|
|
36
|
+
```sh
|
|
37
|
+
export OPENROUTER_API_KEY="your-key"
|
|
37
38
|
rubik
|
|
38
39
|
```
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
```ruby
|
|
43
|
-
gem "rubik"
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
#### Platform notes
|
|
47
|
-
|
|
48
|
-
| Platform | Install experience |
|
|
49
|
-
| :--- | :--- |
|
|
50
|
-
| 🐧 Linux / 🍎 macOS | `gem install rubik` — dependencies ship prebuilt. |
|
|
51
|
-
| 🪟 Windows | `tree_sitter_language_pack` has no Windows prebuilt and compiles from source: install Rust with the GNU toolchain and export `RUST_TARGET=x86_64-pc-windows-gnu` before installing. The exact, working recipe is [`.github/workflows/ci.yml`](.github/workflows/ci.yml). |
|
|
52
|
-
|
|
53
|
-
### From source
|
|
54
|
-
|
|
55
|
-
**Prerequisites**
|
|
56
|
-
|
|
57
|
-
- **Ruby:** 3.4.0 or later (`ruby -v`)
|
|
58
|
-
- **Linux / macOS:** Via the system package manager, `rbenv`, `rvm`, or `asdf`.
|
|
59
|
-
- **Windows:** [Scoop](https://scoop.sh) (`scoop install ruby`) or [RubyInstaller with DevKit](https://rubyinstaller.org).
|
|
60
|
-
- **Git:** Git 2.30+ (`git -v`)
|
|
61
|
-
- **LLM Provider:** Local [Ollama](https://ollama.ai) (`ollama run qwen2.5-coder:7b`) or a DeepSeek, OpenRouter, Anthropic, or OpenAI API key.
|
|
62
|
-
|
|
63
|
-
Clone the project, install the dependencies, and start the REPL:
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
git clone https://github.com/ozgurulukir/rubik.git
|
|
67
|
-
cd rubik
|
|
68
|
-
bundle install
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
#### 🐧 Linux & 🍎 macOS (POSIX)
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
# Proje dizininden doğrudan çalıştırma
|
|
75
|
-
./bin/rubik
|
|
76
|
-
|
|
77
|
-
# Veya sistemde global kullanmak için ~/.local/bin dizinine bağlayın:
|
|
78
|
-
ln -sf $(pwd)/bin/rubik ~/.local/bin/rubik
|
|
79
|
-
rubik
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
> [!NOTE]
|
|
83
|
-
> **The gem and a clone can coexist.** On POSIX the symlink always runs your clone: `bin/rubik` resolves `lib/` from its own real path, so a `git pull` is live on the very next launch — even while the `rubik` gem stays installed. The gem-installed `rubik` keeps serving the last released version until you run `gem update rubik`. On Windows, whichever `bin` folder comes first in `PATH` wins — `where.exe rubik` shows the winner.
|
|
84
|
-
|
|
85
|
-
#### 🪟 Windows (PowerShell / Command Prompt)
|
|
86
|
-
|
|
87
|
-
Rubik ships with built-in `.cmd`, `.bat`, and `.ps1` wrappers for Windows:
|
|
41
|
+
In PowerShell:
|
|
88
42
|
|
|
89
43
|
```powershell
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
# veya Command Prompt / Terminal üzerinden
|
|
94
|
-
.\bin\rubik.cmd
|
|
95
|
-
|
|
96
|
-
# veya Ruby üzerinden doğrudan
|
|
97
|
-
ruby bin\rubik
|
|
44
|
+
$env:OPENROUTER_API_KEY = "your-key"
|
|
45
|
+
rubik
|
|
98
46
|
```
|
|
99
47
|
|
|
100
|
-
|
|
101
|
-
> **The Global `rubik` Command on Windows:**
|
|
102
|
-
> By adding Rubik's `bin` folder to your environment variables (User PATH), you can launch it from any terminal simply by typing `rubik`:
|
|
103
|
-
> ```powershell
|
|
104
|
-
> [Environment]::SetEnvironmentVariable("PATH", "$env:PATH;$PWD\bin", "User")
|
|
105
|
-
> ```
|
|
106
|
-
|
|
107
|
-
### Adding a Provider & Model
|
|
48
|
+
At the REPL prompt, register the provider and choose a model:
|
|
108
49
|
|
|
109
|
-
|
|
50
|
+
<!-- markdownlint-disable MD013 -->
|
|
110
51
|
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
rubik > !model deepseek/deepseek-coder
|
|
52
|
+
```text
|
|
53
|
+
!provider add openrouter openai_compatible https://openrouter.ai/api/v1/chat/completions --key-env=OPENROUTER_API_KEY --model=anthropic/claude-sonnet-5.5 --context=200000 -g
|
|
54
|
+
!model openrouter/anthropic/claude-sonnet-5.5
|
|
115
55
|
```
|
|
116
56
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
```bash
|
|
120
|
-
rubik > !model anthropic/claude-sonnet-5-5
|
|
121
|
-
```
|
|
57
|
+
<!-- markdownlint-enable MD013 -->
|
|
122
58
|
|
|
123
|
-
|
|
59
|
+
Then enter a prompt at the REPL:
|
|
124
60
|
|
|
125
61
|
```text
|
|
126
|
-
|
|
127
|
-
│ 🎲 Rubik v0.1.0 │
|
|
128
|
-
│ deepseek/deepseek-coder │
|
|
129
|
-
│ my_project · main │
|
|
130
|
-
│ !help komutlar · ctrl+c kes · !config ayarlar │
|
|
131
|
-
╰──────────────────────────────────────────────────────────╯
|
|
132
|
-
deepseek/deepseek-coder · ctx 3% · temiz · sandbox kapalı
|
|
133
|
-
rubik (my_project) [main] > !status
|
|
134
|
-
Project: my_project (main)
|
|
135
|
-
Default Model: deepseek/deepseek-coder
|
|
136
|
-
Dirty buffer: false
|
|
137
|
-
|
|
138
|
-
rubik (my_project) [main] > Kullanıcı kayıt formunu doğrulayan bir helper fonksiyonu yaz
|
|
139
|
-
✻ Düşünüyor… · 1s (ctrl+c: kes)
|
|
140
|
-
⏺ write_file — lib/validator.rb
|
|
141
|
-
⎿ 3 lines · 18ms
|
|
142
|
-
|
|
143
|
-
[Rubik] In-memory buffer updated. Type `!diff` to view, `!apply` to save.
|
|
144
|
-
|
|
145
|
-
rubik (my_project) [main] [DIRTY: 1 ✎] > !diff
|
|
146
|
-
+ def validate_user(params)
|
|
147
|
-
+ raise "Invalid email" unless params[:email]&.include?("@")
|
|
148
|
-
+ end
|
|
149
|
-
|
|
150
|
-
rubik (my_project) [main] [DIRTY: 1 ✎] > !test
|
|
151
|
-
Applied 1 file(s) before test. All 12 tests passed!
|
|
62
|
+
Summarize the files in this project.
|
|
152
63
|
```
|
|
153
64
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
>
|
|
160
|
-
>
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
| Guide | What it covers |
|
|
258
|
-
| :--- | :--- |
|
|
259
|
-
| 🌌 [AGENTS.md](AGENTS.md) | The Spatiotemporal Composability Protocol — theory, invariants, the fiber lifecycle state machine. |
|
|
260
|
-
| 🏗️ [ARCHITECTURE.md](ARCHITECTURE.md) | The 30 core domains and the responsibility matrix. |
|
|
261
|
-
| 🧬 [SELF_EVOLUTION.md](SELF_EVOLUTION.md) | How the LLM synthesizes tools, repairs services, and evolves its own runtime. |
|
|
262
|
-
| 🔌 [API.md](API.md) | Embedding the runtime from Ruby: config, tool registry, provider contract, orchestrator loop, error contracts. |
|
|
263
|
-
|
|
264
|
-
### User & Operator Guides
|
|
265
|
-
|
|
266
|
-
| Guide | What it covers |
|
|
267
|
-
| :--- | :--- |
|
|
268
|
-
| 🕹️ [COMMANDS.md](COMMANDS.md) | All 30+ REPL bang commands with parameters and usage scenarios. |
|
|
269
|
-
| 🧰 [TOOLS.md](TOOLS.md) | Catalog of the 34 built-in agent tools: parameters, risk classes, diagnostics. |
|
|
270
|
-
| ⚙️ [CONFIG.md](CONFIG.md) | Every configuration knob (models, LSP, buffer policy, sandbox, subagents, pruner…). |
|
|
271
|
-
| 🌍 [ENV.md](ENV.md) | Environment variables — single consolidated reference table. |
|
|
272
|
-
| 🖥️ [LSP.md](LSP.md) | Step-by-step language-server setup and diagnostics walkthrough. |
|
|
273
|
-
| 🔌 [PLUGINS.md](PLUGINS.md) | The drop-in plugin system: layout, manifests, zero-downtime reloads. |
|
|
274
|
-
|
|
275
|
-
### Project & Policy
|
|
276
|
-
|
|
277
|
-
| Guide | What it covers |
|
|
278
|
-
| :--- | :--- |
|
|
279
|
-
| 🤝 [CONTRIBUTING.md](CONTRIBUTING.md) | Dev setup, test commands, commit/PR conventions, security reporting. |
|
|
280
|
-
| 🧪 [TESTING.md](TESTING.md) | Running the suite, naming conventions, test templates, flaky-test policy. |
|
|
281
|
-
| 🔒 [SECURITY.md](SECURITY.md) | Command gate, critical-write protection, synthesis gates, sandbox, audit log. |
|
|
282
|
-
| 📜 [ATTRIBUTION.md](ATTRIBUTION.md) | Open-source attributions and third-party notices. |
|
|
283
|
-
| 📜 [CHANGELOG.md](CHANGELOG.md) | Thematic release history; the full record lives in `git log`. |
|
|
284
|
-
| 📄 [LICENSE](LICENSE) | Software license (MIT). |
|
|
65
|
+
Use `!diff` to review staged file changes and `!apply` to write them to disk. See the
|
|
66
|
+
[first-session tutorial](docs/tutorials/first-session.md) for platform-specific
|
|
67
|
+
credential setup and a longer walkthrough. Windows gem installation may compile
|
|
68
|
+
a dependency from source; see the [installation guide](docs/how-to/installation.md).
|
|
69
|
+
|
|
70
|
+
> **Safety note:** Model-generated code and commands can be incorrect or unsafe. Review
|
|
71
|
+
> changes with `!diff` and run tests before relying on them. For strict human approval
|
|
72
|
+
> of **buffered file changes only**, set `buffer.auto_apply: manual` and
|
|
73
|
+
> `buffer.model_can_apply: false`. These settings do not gate shell commands or
|
|
74
|
+
> background processes: the command safety gate checks them, but allowed commands run
|
|
75
|
+
> without a separate per-command approval prompt. The OS sandbox is disabled by default;
|
|
76
|
+
> run untrusted code in an isolated environment. See [Security](SECURITY.md).
|
|
77
|
+
|
|
78
|
+
## Features
|
|
79
|
+
|
|
80
|
+
1. **Core · Cross-platform CLI.** Run the terminal agent and REPL on Linux,
|
|
81
|
+
macOS, or Windows. The CI matrix covers Ubuntu with Ruby 3.4 and 4.0, and
|
|
82
|
+
macOS and Windows with Ruby 4.0. In the Windows CI environment, gem
|
|
83
|
+
installation compiles a native dependency with the Rust GNU toolchain. See
|
|
84
|
+
the [installation guide](docs/how-to/installation.md).
|
|
85
|
+
2. **Core · Staged file edits.** Model writes go to an in-memory virtual buffer;
|
|
86
|
+
inspect them with `!diff`, apply them with `!apply`, or discard unapplied
|
|
87
|
+
edits with `!undo`.
|
|
88
|
+
3. **Core · Review control and write semantics.** To require operator approval
|
|
89
|
+
for buffered file changes, set `buffer.model_can_apply: false` together with
|
|
90
|
+
`buffer.auto_apply: manual`. This does not add approval prompts for shell
|
|
91
|
+
commands or background processes; see [security practices](SECURITY.md). Each
|
|
92
|
+
file is written atomically, but a multi-file apply is not a transaction: a
|
|
93
|
+
partial failure leaves the remaining changes dirty and reports applied,
|
|
94
|
+
failed, and pending files. See [buffer configuration](docs/how-to/configuration.md).
|
|
95
|
+
4. **Core · Multiple workspace roots.** Add sibling or external directories as
|
|
96
|
+
read-only roots by default, or allow writes with `--rw`; additional roots can
|
|
97
|
+
join code search and the AST index. See the [`!workspace` commands](docs/reference/commands.md).
|
|
98
|
+
5. **Core · Guarded command execution.** Commands pass through Rubik's safety
|
|
99
|
+
checks. Bubblewrap, Docker, or Podman isolation is optional and disabled by
|
|
100
|
+
default. See [security practices](SECURITY.md).
|
|
101
|
+
6. **Models · Provider and role routing.** Connect OpenAI-compatible endpoints,
|
|
102
|
+
Anthropic, OpenAI, or local Ollama, then assign models to default, fast, and
|
|
103
|
+
advanced roles or use task-based routing. See [provider configuration](docs/how-to/configuration.md).
|
|
104
|
+
7. **Code intelligence · Hybrid AST.** Prism parses Ruby; Tree-Sitter grammars
|
|
105
|
+
cover Python, Go, Rust, TypeScript, TSX, JavaScript, C, C++, and Zig. Symbol
|
|
106
|
+
and call-graph indexing can warm in the background and persists to a local
|
|
107
|
+
cache. If Tree-Sitter is unavailable, Rubik can use regex extractors, which
|
|
108
|
+
have structural limits. Parsing errors have structured statuses, and a
|
|
109
|
+
failed re-index preserves previously indexed symbols. See [architecture](docs/explanation/architecture.md).
|
|
110
|
+
8. **Code intelligence · Live LSP diagnostics.** Configured language servers
|
|
111
|
+
can start on demand and return compiler or linter diagnostics after edits.
|
|
112
|
+
Missing or failing servers do not block a session; Rubik falls back to its
|
|
113
|
+
built-in syntax and AST analysis. See [language-server setup](docs/how-to/language-servers.md).
|
|
114
|
+
9. **Code intelligence · Native fast paths.** When available, ripgrep and Git
|
|
115
|
+
accelerate search and context scanning; Rubik falls back to pure Ruby when
|
|
116
|
+
those binaries are missing or native paths are disabled. Control them through
|
|
117
|
+
`tools.native` or `RUBIK_NATIVE`. See [configuration](docs/how-to/configuration.md).
|
|
118
|
+
10. **Extensions · Runtime synthesis.** The model can create REPL commands and
|
|
119
|
+
tools during a session. Managed runtime effects register cleanup actions
|
|
120
|
+
and unwind them in LIFO order. See [self-evolution](docs/explanation/self-evolution.md).
|
|
121
|
+
11. **Extensions · Plugins.** Load or reload drop-in Ruby plugins from user or
|
|
122
|
+
project directories. SHA-256 manifests detect modified files, but plugins
|
|
123
|
+
execute arbitrary Ruby in the host process and are not sandboxed. See the
|
|
124
|
+
[plugin guide](docs/how-to/plugins.md).
|
|
125
|
+
12. **Extensions · MCP servers.** Connect external stdio servers and expose
|
|
126
|
+
discovered tools through Rubik's registry. Lifecycle cleanup removes proxy
|
|
127
|
+
tools and attempts to stop child processes when the server is disconnected.
|
|
128
|
+
See [MCP commands](docs/reference/commands.md).
|
|
129
|
+
13. **Recovery · Live service repair.** Inspect runtime state, verify a
|
|
130
|
+
replacement command in a disposable context, then promote it without
|
|
131
|
+
restarting the process. Failed promotion or persistence unwinds session
|
|
132
|
+
changes; if a previous service cannot be restored, the repair result reports
|
|
133
|
+
incomplete rollback. Successful operator configuration saves remain in
|
|
134
|
+
place. See [runtime repair](docs/explanation/runtime-repair.md).
|
|
135
|
+
14. **Long sessions · Structured goal ledger.** The `!goal` loop keeps a
|
|
136
|
+
revision-guarded record of objectives, tasks, findings, and decisions;
|
|
137
|
+
current state survives compaction, and configured verification checks run
|
|
138
|
+
at step boundaries. See [goal commands](docs/reference/commands.md).
|
|
139
|
+
15. **Long sessions · Context pruning.** A pruner can propose what to keep,
|
|
140
|
+
drop, or summarize; the harness validates the plan and applies it at a turn
|
|
141
|
+
boundary. The operator can also invoke it with `!prune`. See [pruner settings](docs/how-to/configuration.md).
|
|
142
|
+
16. **Long sessions · Vakanüvis annals.** When configured, the chronicler
|
|
143
|
+
records session turns and subagent events; its distiller can build memory
|
|
144
|
+
notes and a wiki skeleton. See [runtime architecture](docs/explanation/architecture.md).
|
|
145
|
+
17. **Interaction · Live monitoring and TUI.** Choose quiet, normal, verbose,
|
|
146
|
+
or debug output. The interface combines a statusline, spinner, Markdown
|
|
147
|
+
renderer, colored diff view, and interactive `!agents` board. `NO_COLOR` and
|
|
148
|
+
pipe mode fall back to plain text, and session logs omit ANSI codes. See
|
|
149
|
+
[UI configuration](docs/how-to/configuration.md).
|
|
150
|
+
18. **Runtime · Cooperative I/O concurrency.** A pure-Ruby Fiber Scheduler can
|
|
151
|
+
overlap supported blocking I/O on one thread; it does not parallelize CPU
|
|
152
|
+
work; disable it with `RUBIK_FIBER_SCHEDULER=off`. The capacity harness
|
|
153
|
+
exercises lifecycle checks at 1,000 epochs, 100 and 1,000 concurrent loopback
|
|
154
|
+
requests, and AST-cache behavior. See [architecture](docs/explanation/architecture.md)
|
|
155
|
+
and [testing](docs/development/testing.md).
|
|
156
|
+
|
|
157
|
+
## Documentation
|
|
158
|
+
|
|
159
|
+
Browse the [documentation index](docs/index.md) for tutorials, how-to guides,
|
|
160
|
+
references, architecture explanations, and development guidance. The
|
|
161
|
+
[changelog](CHANGELOG.md) records releases.
|
|
162
|
+
|
|
163
|
+
## Contributing and policies
|
|
164
|
+
|
|
165
|
+
[Contributing](CONTRIBUTING.md) · [Code of Conduct](CODE_OF_CONDUCT.md) ·
|
|
166
|
+
[Security policy](SECURITY.md) · [License](LICENSE)
|
data/bin/rubik
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
5
5
|
require "rubik"
|
|
6
|
+
require "rubik/cli/workspace_trust"
|
|
6
7
|
require "optparse"
|
|
7
8
|
|
|
8
9
|
# Global SIGINT safety net. The REPL installs its own "INT" handler while
|
|
@@ -60,6 +61,14 @@ OptionParser.new do |opts|
|
|
|
60
61
|
end
|
|
61
62
|
end.parse!
|
|
62
63
|
|
|
64
|
+
workspace_trusted = options[:script] ||
|
|
65
|
+
Rubik::CLI::WorkspaceTrust.authorize!(
|
|
66
|
+
workspace: Dir.pwd,
|
|
67
|
+
input: $stdin,
|
|
68
|
+
output: $stdout
|
|
69
|
+
)
|
|
70
|
+
Kernel.exit(0) unless workspace_trusted
|
|
71
|
+
|
|
63
72
|
shell = Rubik::REPL::Shell.new
|
|
64
73
|
|
|
65
74
|
if options[:continue]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubik
|
|
4
|
+
module AST
|
|
5
|
+
# Structured outcome of one file extraction (issue #147): `symbols` is
|
|
6
|
+
# always the best available list (possibly empty), while `status` says HOW
|
|
7
|
+
# much it can be trusted — so "no symbols here" and "extraction failed"
|
|
8
|
+
# are never confused:
|
|
9
|
+
# :ok — authoritative result (clean parse, or the primary
|
|
10
|
+
# extractor for this file/environment)
|
|
11
|
+
# :partial — the language parser reported syntax errors; extracted
|
|
12
|
+
# symbols are usable but may be incomplete
|
|
13
|
+
# :failed — no trustworthy result (parser crashed, parse errors
|
|
14
|
+
# with nothing extracted, fallback failed too);
|
|
15
|
+
# `symbols` may carry best-effort output
|
|
16
|
+
# :unavailable — no language extractor claims this extension; the
|
|
17
|
+
# legacy graceful fallback produced whatever it could
|
|
18
|
+
# `source` names who produced the symbols (:ruby, :tree_sitter,
|
|
19
|
+
# :fallback, :none) and `detail` carries the failure reason when there is
|
|
20
|
+
# one.
|
|
21
|
+
ExtractionResult = Struct.new(:symbols, :status, :source, :detail, keyword_init: true) do
|
|
22
|
+
def ok?
|
|
23
|
+
status == :ok
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def failed?
|
|
27
|
+
status == :failed
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# A result a caller may rely on for symbol lookup (possibly incomplete
|
|
31
|
+
# but produced by the language parser itself).
|
|
32
|
+
def trustworthy?
|
|
33
|
+
[:ok, :partial].include?(status)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/rubik/ast/extractor.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "extraction_result"
|
|
3
4
|
require_relative "ruby_extractor"
|
|
4
5
|
require_relative "go_extractor"
|
|
5
6
|
require_relative "rust_extractor"
|
|
@@ -31,24 +32,49 @@ module Rubik
|
|
|
31
32
|
EXTENSIONS = FALLBACK_EXTRACTORS
|
|
32
33
|
|
|
33
34
|
def self.extract(file_path, content = nil)
|
|
35
|
+
extract_result(file_path, content).symbols
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Structured outcome (issue #147): symbols plus status/source/detail, so
|
|
39
|
+
# a failed extraction is distinguishable from a legitimately empty file
|
|
40
|
+
# and from a degraded regex fallback. Status vocabulary lives in
|
|
41
|
+
# AST::ExtractionResult.
|
|
42
|
+
def self.extract_result(file_path, content = nil)
|
|
34
43
|
ext = File.extname(file_path).downcase
|
|
35
44
|
|
|
36
45
|
# 1. Ruby files: always use Prism-powered RubyExtractor first
|
|
37
|
-
|
|
46
|
+
if ext == ".rb"
|
|
47
|
+
return ExtractionResult.new(symbols: RubyExtractor.extract(file_path, content),
|
|
48
|
+
status: :ok, source: :ruby)
|
|
49
|
+
end
|
|
38
50
|
|
|
39
|
-
# 2. Polyglot files: use Tree-Sitter AST extractor if available
|
|
51
|
+
# 2. Polyglot files: use the Tree-Sitter AST extractor if available
|
|
40
52
|
if TreeSitterExtractor.available? && TreeSitterExtractor.supports?(ext)
|
|
41
|
-
|
|
42
|
-
|
|
53
|
+
ts = TreeSitterExtractor.extract_result(file_path, content)
|
|
54
|
+
if ts.trustworthy?
|
|
55
|
+
return ExtractionResult.new(symbols: ts.symbols, status: ts.status,
|
|
56
|
+
source: :tree_sitter, detail: ts.detail)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# The language parser failed (crash / unparsable): the regex
|
|
60
|
+
# fallback is best-effort only, and the status says so.
|
|
61
|
+
return fallback_result(file_path, content, ext, status: :failed, detail: ts.detail) if ts.failed?
|
|
43
62
|
end
|
|
44
63
|
|
|
45
|
-
# 3. Graceful
|
|
46
|
-
|
|
47
|
-
|
|
64
|
+
# 3. Graceful fallback: the legacy regex extractor — the primary path
|
|
65
|
+
# in environments without the tree-sitter pack or for extensions no
|
|
66
|
+
# language extractor claims (:unavailable, legacy Ruby parse).
|
|
67
|
+
fallback_result(file_path, content, ext)
|
|
48
68
|
rescue StandardError, ScriptError => e
|
|
49
69
|
warn "[WARN] Extraction failed for #{file_path}: #{e.class}: #{e.message}" if ENV["RUBIK_DEBUG"]
|
|
50
|
-
|
|
51
|
-
|
|
70
|
+
ExtractionResult.new(symbols: [], status: :failed, source: :none, detail: "#{e.class}: #{e.message}")
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def self.fallback_result(file_path, content, ext, status: nil, detail: nil)
|
|
74
|
+
extractor = FALLBACK_EXTRACTORS[ext]
|
|
75
|
+
status ||= extractor ? :ok : :unavailable
|
|
76
|
+
symbols = (extractor || RubyExtractor).extract(file_path, content)
|
|
77
|
+
ExtractionResult.new(symbols: symbols, status: status, source: :fallback, detail: detail)
|
|
52
78
|
end
|
|
53
79
|
|
|
54
80
|
def self.supported_extensions
|