rubik 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/ATTRIBUTION.md +139 -0
- data/CHANGELOG.md +236 -0
- data/LICENSE +21 -0
- data/README.md +269 -0
- data/bin/rubik +82 -0
- data/lib/rubik/adapter/base.rb +195 -0
- data/lib/rubik/adapter/c.rb +36 -0
- data/lib/rubik/adapter/crystal.rb +78 -0
- data/lib/rubik/adapter/generic.rb +86 -0
- data/lib/rubik/adapter/go.rb +36 -0
- data/lib/rubik/adapter/node.rb +146 -0
- data/lib/rubik/adapter/process.rb +78 -0
- data/lib/rubik/adapter/python.rb +30 -0
- data/lib/rubik/adapter/registry.rb +81 -0
- data/lib/rubik/adapter/ruby.rb +30 -0
- data/lib/rubik/adapter/rust.rb +36 -0
- data/lib/rubik/adapter/zig.rb +36 -0
- data/lib/rubik/adapter.rb +18 -0
- data/lib/rubik/ast/body_loader.rb +19 -0
- data/lib/rubik/ast/c_extractor.rb +114 -0
- data/lib/rubik/ast/cache_store.rb +191 -0
- data/lib/rubik/ast/extractor.rb +59 -0
- data/lib/rubik/ast/fallback_cleaner.rb +145 -0
- data/lib/rubik/ast/go_extractor.rb +148 -0
- data/lib/rubik/ast/graph.rb +272 -0
- data/lib/rubik/ast/python_extractor.rb +120 -0
- data/lib/rubik/ast/ruby_extractor.rb +260 -0
- data/lib/rubik/ast/rust_extractor.rb +127 -0
- data/lib/rubik/ast/symbol.rb +103 -0
- data/lib/rubik/ast/treesitter/base_walker.rb +109 -0
- data/lib/rubik/ast/treesitter/c_walker.rb +122 -0
- data/lib/rubik/ast/treesitter/go_walker.rb +120 -0
- data/lib/rubik/ast/treesitter/python_walker.rb +107 -0
- data/lib/rubik/ast/treesitter/rust_walker.rb +130 -0
- data/lib/rubik/ast/treesitter/typescript_walker.rb +182 -0
- data/lib/rubik/ast/treesitter/zig_walker.rb +109 -0
- data/lib/rubik/ast/treesitter_extractor.rb +93 -0
- data/lib/rubik/ast/typescript_extractor.rb +283 -0
- data/lib/rubik/ast/zig_extractor.rb +116 -0
- data/lib/rubik/ast.rb +13 -0
- data/lib/rubik/benchmark/runner.rb +224 -0
- data/lib/rubik/benchmark/synth_repo.rb +59 -0
- data/lib/rubik/benchmark.rb +9 -0
- data/lib/rubik/buffer/diff.rb +43 -0
- data/lib/rubik/buffer/manager.rb +427 -0
- data/lib/rubik/buffer/path_validator.rb +60 -0
- data/lib/rubik/buffer/snapshot.rb +99 -0
- data/lib/rubik/buffer.rb +10 -0
- data/lib/rubik/coeffects.rb +129 -0
- data/lib/rubik/concurrency/boundary.rb +74 -0
- data/lib/rubik/concurrency/dns_pool.rb +68 -0
- data/lib/rubik/concurrency/errors.rb +17 -0
- data/lib/rubik/concurrency/event_loop.rb +441 -0
- data/lib/rubik/concurrency/join.rb +55 -0
- data/lib/rubik/concurrency/process_waiter.rb +55 -0
- data/lib/rubik/concurrency/scheduler.rb +84 -0
- data/lib/rubik/concurrency/timers.rb +109 -0
- data/lib/rubik/concurrency.rb +132 -0
- data/lib/rubik/config/deep_ops.rb +80 -0
- data/lib/rubik/config/defaults.rb +248 -0
- data/lib/rubik/config/model_catalog.rb +93 -0
- data/lib/rubik/config/store.rb +155 -0
- data/lib/rubik/config.rb +216 -0
- data/lib/rubik/context/git_info.rb +84 -0
- data/lib/rubik/context/git_lister.rb +37 -0
- data/lib/rubik/context/index.rb +134 -0
- data/lib/rubik/context/repo_context_reader.rb +121 -0
- data/lib/rubik/context/scanner.rb +439 -0
- data/lib/rubik/context.rb +11 -0
- data/lib/rubik/diagnostics/collector.rb +200 -0
- data/lib/rubik/diagnostics/entry.rb +60 -0
- data/lib/rubik/diagnostics/parser.rb +107 -0
- data/lib/rubik/diagnostics.rb +10 -0
- data/lib/rubik/event_bus.rb +56 -0
- data/lib/rubik/kernel/dispatcher.rb +171 -0
- data/lib/rubik/kernel/dmesg.rb +116 -0
- data/lib/rubik/kernel/init.rb +177 -0
- data/lib/rubik/kernel/record.rb +85 -0
- data/lib/rubik/kernel/unit.rb +160 -0
- data/lib/rubik/llm/anthropic.rb +202 -0
- data/lib/rubik/llm/chunk_assembler.rb +285 -0
- data/lib/rubik/llm/client.rb +526 -0
- data/lib/rubik/llm/formatter.rb +450 -0
- data/lib/rubik/llm/message_sanitizer.rb +87 -0
- data/lib/rubik/llm/ollama.rb +167 -0
- data/lib/rubik/llm/openai.rb +21 -0
- data/lib/rubik/llm/openai_compatible.rb +216 -0
- data/lib/rubik/llm/provider.rb +125 -0
- data/lib/rubik/llm/registry.rb +336 -0
- data/lib/rubik/llm/router.rb +100 -0
- data/lib/rubik/llm.rb +18 -0
- data/lib/rubik/log.rb +38 -0
- data/lib/rubik/lsp/client.rb +475 -0
- data/lib/rubik/lsp/manager.rb +366 -0
- data/lib/rubik/lsp.rb +9 -0
- data/lib/rubik/mcp/boot_lifecycle.rb +114 -0
- data/lib/rubik/mcp/client.rb +169 -0
- data/lib/rubik/mcp/errors.rb +11 -0
- data/lib/rubik/mcp/manager.rb +619 -0
- data/lib/rubik/mcp/proxy_tool.rb +104 -0
- data/lib/rubik/mcp/transport/stdio.rb +255 -0
- data/lib/rubik/mcp.rb +12 -0
- data/lib/rubik/orchestrator/activity_log.rb +75 -0
- data/lib/rubik/orchestrator/auto_apply.rb +166 -0
- data/lib/rubik/orchestrator/budget_manager.rb +97 -0
- data/lib/rubik/orchestrator/continuation_manager.rb +161 -0
- data/lib/rubik/orchestrator/finish_message_selector.rb +55 -0
- data/lib/rubik/orchestrator/goal_ledger/drift.rb +71 -0
- data/lib/rubik/orchestrator/goal_ledger/ledger.rb +399 -0
- data/lib/rubik/orchestrator/goal_ledger/observation_projection.rb +179 -0
- data/lib/rubik/orchestrator/goal_ledger/patch.rb +268 -0
- data/lib/rubik/orchestrator/goal_ledger/schema.rb +123 -0
- data/lib/rubik/orchestrator/goal_ledger/validator.rb +361 -0
- data/lib/rubik/orchestrator/goal_ledger/verifier.rb +129 -0
- data/lib/rubik/orchestrator/goal_ledger/verify_spec.rb +50 -0
- data/lib/rubik/orchestrator/goal_ledger.rb +65 -0
- data/lib/rubik/orchestrator/goal_state.rb +184 -0
- data/lib/rubik/orchestrator/goal_wait.rb +125 -0
- data/lib/rubik/orchestrator/loop.rb +388 -0
- data/lib/rubik/orchestrator/lsp_feedback.rb +55 -0
- data/lib/rubik/orchestrator/maestro_gate.rb +65 -0
- data/lib/rubik/orchestrator/provider_recovery.rb +90 -0
- data/lib/rubik/orchestrator/provider_resolver.rb +69 -0
- data/lib/rubik/orchestrator/shell_deps.rb +85 -0
- data/lib/rubik/orchestrator/step_executor.rb +328 -0
- data/lib/rubik/orchestrator/stream_manager.rb +118 -0
- data/lib/rubik/orchestrator/subagent/activation.rb +65 -0
- data/lib/rubik/orchestrator/subagent/budget.rb +108 -0
- data/lib/rubik/orchestrator/subagent/completion.rb +61 -0
- data/lib/rubik/orchestrator/subagent/concurrency_gate.rb +37 -0
- data/lib/rubik/orchestrator/subagent/conversation_id.rb +67 -0
- data/lib/rubik/orchestrator/subagent/dependency.rb +398 -0
- data/lib/rubik/orchestrator/subagent/instance.rb +384 -0
- data/lib/rubik/orchestrator/subagent/lifecycle.rb +118 -0
- data/lib/rubik/orchestrator/subagent/messaging.rb +61 -0
- data/lib/rubik/orchestrator/subagent/narration.rb +125 -0
- data/lib/rubik/orchestrator/subagent/notices.rb +209 -0
- data/lib/rubik/orchestrator/subagent/questioner.rb +80 -0
- data/lib/rubik/orchestrator/subagent/reaper.rb +98 -0
- data/lib/rubik/orchestrator/subagent/resilience.rb +70 -0
- data/lib/rubik/orchestrator/subagent/reuse.rb +127 -0
- data/lib/rubik/orchestrator/subagent/scoped_registry.rb +79 -0
- data/lib/rubik/orchestrator/subagent/step_runner.rb +240 -0
- data/lib/rubik/orchestrator/subagent/storage_id.rb +26 -0
- data/lib/rubik/orchestrator/subagent/supervisor.rb +327 -0
- data/lib/rubik/orchestrator/subagent/transcript_formatter.rb +141 -0
- data/lib/rubik/orchestrator/subagent/type_registry.rb +199 -0
- data/lib/rubik/orchestrator/subagent_notice_inbox.rb +80 -0
- data/lib/rubik/orchestrator/tool_call_id.rb +47 -0
- data/lib/rubik/orchestrator/tool_circuit_breaker.rb +91 -0
- data/lib/rubik/orchestrator/tool_history.rb +39 -0
- data/lib/rubik/orchestrator/turn_executor/subagent_channel.rb +102 -0
- data/lib/rubik/orchestrator/turn_executor/user_channel.rb +172 -0
- data/lib/rubik/orchestrator/turn_executor.rb +376 -0
- data/lib/rubik/orchestrator.rb +11 -0
- data/lib/rubik/platform/filesystem.rb +64 -0
- data/lib/rubik/platform/io_drain.rb +53 -0
- data/lib/rubik/platform/path.rb +210 -0
- data/lib/rubik/platform/process.rb +38 -0
- data/lib/rubik/platform/sanitize.rb +157 -0
- data/lib/rubik/platform.rb +113 -0
- data/lib/rubik/plugin/dsl.rb +51 -0
- data/lib/rubik/plugin/manager.rb +247 -0
- data/lib/rubik/plugin/storage.rb +195 -0
- data/lib/rubik/plugin.rb +10 -0
- data/lib/rubik/prompt/context_builder.rb +377 -0
- data/lib/rubik/prompt/context_compactor.rb +326 -0
- data/lib/rubik/prompt/conversation_rows.rb +74 -0
- data/lib/rubik/prompt/doctrine.rb +160 -0
- data/lib/rubik/prompt/emergency_compactor.rb +81 -0
- data/lib/rubik/prompt/services.rb +60 -0
- data/lib/rubik/prompt/token_estimator.rb +63 -0
- data/lib/rubik/prompt/tool_teachings.rb +78 -0
- data/lib/rubik/prompt.rb +13 -0
- data/lib/rubik/repair/loop.rb +95 -0
- data/lib/rubik/repair.rb +8 -0
- data/lib/rubik/repl/ast_warmup.rb +129 -0
- data/lib/rubik/repl/command_context.rb +214 -0
- data/lib/rubik/repl/command_parser.rb +48 -0
- data/lib/rubik/repl/commands/agent.rb +30 -0
- data/lib/rubik/repl/commands/agent_context.rb +289 -0
- data/lib/rubik/repl/commands/agent_execution.rb +342 -0
- data/lib/rubik/repl/commands/agent_models.rb +212 -0
- data/lib/rubik/repl/commands/agent_providers.rb +232 -0
- data/lib/rubik/repl/commands/base.rb +55 -0
- data/lib/rubik/repl/commands/buffer.rb +124 -0
- data/lib/rubik/repl/commands/dmesg.rb +87 -0
- data/lib/rubik/repl/commands/lsp.rb +235 -0
- data/lib/rubik/repl/commands/mcp.rb +194 -0
- data/lib/rubik/repl/commands/plugins.rb +208 -0
- data/lib/rubik/repl/commands/pruner.rb +71 -0
- data/lib/rubik/repl/commands/session.rb +183 -0
- data/lib/rubik/repl/commands/skills.rb +111 -0
- data/lib/rubik/repl/commands/storage.rb +85 -0
- data/lib/rubik/repl/commands/subagents.rb +195 -0
- data/lib/rubik/repl/commands/system.rb +85 -0
- data/lib/rubik/repl/commands/tasks.rb +120 -0
- data/lib/rubik/repl/commands/workspace.rb +443 -0
- data/lib/rubik/repl/commands.rb +44 -0
- data/lib/rubik/repl/composition.rb +32 -0
- data/lib/rubik/repl/config_wiring.rb +142 -0
- data/lib/rubik/repl/confirmations.rb +56 -0
- data/lib/rubik/repl/hooks.rb +47 -0
- data/lib/rubik/repl/input_execution.rb +323 -0
- data/lib/rubik/repl/input_loop.rb +213 -0
- data/lib/rubik/repl/interrupt_handler.rb +217 -0
- data/lib/rubik/repl/lifecycle.rb +410 -0
- data/lib/rubik/repl/paste_support.rb +88 -0
- data/lib/rubik/repl/pending_notice_queue.rb +60 -0
- data/lib/rubik/repl/presentation.rb +132 -0
- data/lib/rubik/repl/pruner/brief.rb +101 -0
- data/lib/rubik/repl/pruner/gate.rb +279 -0
- data/lib/rubik/repl/pruner/harness.rb +236 -0
- data/lib/rubik/repl/pruner/rules.rb +316 -0
- data/lib/rubik/repl/pruner/service.rb +82 -0
- data/lib/rubik/repl/pruner.rb +39 -0
- data/lib/rubik/repl/service_catalog.rb +374 -0
- data/lib/rubik/repl/setup_factories.rb +66 -0
- data/lib/rubik/repl/shell.rb +231 -0
- data/lib/rubik/repl/step_formatter.rb +324 -0
- data/lib/rubik/repl/tee_io.rb +105 -0
- data/lib/rubik/repl/terminal_guard.rb +157 -0
- data/lib/rubik/repl/turn_recorder.rb +234 -0
- data/lib/rubik/repl.rb +14 -0
- data/lib/rubik/runtime/ast_service.rb +78 -0
- data/lib/rubik/runtime/context.rb +335 -0
- data/lib/rubik/runtime/diagnostic_engine.rb +188 -0
- data/lib/rubik/runtime/discovery.rb +342 -0
- data/lib/rubik/runtime/fiber.rb +142 -0
- data/lib/rubik/runtime/fiber_ordering.rb +52 -0
- data/lib/rubik/runtime/fiber_retry_gate.rb +84 -0
- data/lib/rubik/runtime/index_service.rb +58 -0
- data/lib/rubik/runtime/loop_service.rb +73 -0
- data/lib/rubik/runtime/manager.rb +241 -0
- data/lib/rubik/runtime/overlay_storage.rb +481 -0
- data/lib/rubik/runtime/service_definition.rb +54 -0
- data/lib/rubik/runtime/service_registration.rb +33 -0
- data/lib/rubik/runtime/task_manager.rb +302 -0
- data/lib/rubik/runtime.rb +19 -0
- data/lib/rubik/sandbox/driver/base.rb +30 -0
- data/lib/rubik/sandbox/driver/bubblewrap.rb +111 -0
- data/lib/rubik/sandbox/driver/docker.rb +113 -0
- data/lib/rubik/sandbox/driver/podman.rb +98 -0
- data/lib/rubik/sandbox/driver/process.rb +190 -0
- data/lib/rubik/sandbox/driver.rb +91 -0
- data/lib/rubik/sandbox/runner.rb +218 -0
- data/lib/rubik/sandbox/shell_resolver.rb +178 -0
- data/lib/rubik/sandbox.rb +8 -0
- data/lib/rubik/security/blocked_guidance.rb +187 -0
- data/lib/rubik/security/classifier/classifier.rb +440 -0
- data/lib/rubik/security/classifier/commands/agent-browser.yaml +9 -0
- data/lib/rubik/security/classifier/commands/apt.yaml +25 -0
- data/lib/rubik/security/classifier/commands/awk.yaml +10 -0
- data/lib/rubik/security/classifier/commands/basename.yaml +7 -0
- data/lib/rubik/security/classifier/commands/bash-classify.yaml +8 -0
- data/lib/rubik/security/classifier/commands/bash.yaml +20 -0
- data/lib/rubik/security/classifier/commands/black.yaml +12 -0
- data/lib/rubik/security/classifier/commands/brew.yaml +31 -0
- data/lib/rubik/security/classifier/commands/builtin.yaml +8 -0
- data/lib/rubik/security/classifier/commands/cargo.yaml +114 -0
- data/lib/rubik/security/classifier/commands/cat.yaml +7 -0
- data/lib/rubik/security/classifier/commands/chgrp.yaml +10 -0
- data/lib/rubik/security/classifier/commands/chmod.yaml +10 -0
- data/lib/rubik/security/classifier/commands/chown.yaml +10 -0
- data/lib/rubik/security/classifier/commands/column.yaml +7 -0
- data/lib/rubik/security/classifier/commands/comm.yaml +7 -0
- data/lib/rubik/security/classifier/commands/command.yaml +12 -0
- data/lib/rubik/security/classifier/commands/cp.yaml +7 -0
- data/lib/rubik/security/classifier/commands/crystal.yaml +63 -0
- data/lib/rubik/security/classifier/commands/curl.yaml +30 -0
- data/lib/rubik/security/classifier/commands/cut.yaml +7 -0
- data/lib/rubik/security/classifier/commands/date.yaml +10 -0
- data/lib/rubik/security/classifier/commands/df.yaml +7 -0
- data/lib/rubik/security/classifier/commands/diff.yaml +7 -0
- data/lib/rubik/security/classifier/commands/dig.yaml +7 -0
- data/lib/rubik/security/classifier/commands/dirname.yaml +7 -0
- data/lib/rubik/security/classifier/commands/docker.yaml +177 -0
- data/lib/rubik/security/classifier/commands/du.yaml +7 -0
- data/lib/rubik/security/classifier/commands/echo.yaml +7 -0
- data/lib/rubik/security/classifier/commands/env.yaml +15 -0
- data/lib/rubik/security/classifier/commands/eslint.yaml +12 -0
- data/lib/rubik/security/classifier/commands/eval.yaml +8 -0
- data/lib/rubik/security/classifier/commands/exec.yaml +12 -0
- data/lib/rubik/security/classifier/commands/expand.yaml +7 -0
- data/lib/rubik/security/classifier/commands/false.yaml +7 -0
- data/lib/rubik/security/classifier/commands/file.yaml +7 -0
- data/lib/rubik/security/classifier/commands/find.yaml +25 -0
- data/lib/rubik/security/classifier/commands/fmt.yaml +7 -0
- data/lib/rubik/security/classifier/commands/fold.yaml +7 -0
- data/lib/rubik/security/classifier/commands/free.yaml +7 -0
- data/lib/rubik/security/classifier/commands/gawk.yaml +10 -0
- data/lib/rubik/security/classifier/commands/gcloud.yaml +979 -0
- data/lib/rubik/security/classifier/commands/gh.yaml +615 -0
- data/lib/rubik/security/classifier/commands/git.yaml +524 -0
- data/lib/rubik/security/classifier/commands/glab-discussion.yaml +21 -0
- data/lib/rubik/security/classifier/commands/glab.yaml +807 -0
- data/lib/rubik/security/classifier/commands/go.yaml +44 -0
- data/lib/rubik/security/classifier/commands/gog.yaml +983 -0
- data/lib/rubik/security/classifier/commands/gradle.yaml +92 -0
- data/lib/rubik/security/classifier/commands/gradlew.yaml +92 -0
- data/lib/rubik/security/classifier/commands/grep.yaml +7 -0
- data/lib/rubik/security/classifier/commands/groups.yaml +7 -0
- data/lib/rubik/security/classifier/commands/gunzip.yaml +8 -0
- data/lib/rubik/security/classifier/commands/gws.yaml +211 -0
- data/lib/rubik/security/classifier/commands/gzip.yaml +7 -0
- data/lib/rubik/security/classifier/commands/hadolint.yaml +9 -0
- data/lib/rubik/security/classifier/commands/halt.yaml +8 -0
- data/lib/rubik/security/classifier/commands/head.yaml +7 -0
- data/lib/rubik/security/classifier/commands/helm.yaml +129 -0
- data/lib/rubik/security/classifier/commands/hostname.yaml +7 -0
- data/lib/rubik/security/classifier/commands/id.yaml +7 -0
- data/lib/rubik/security/classifier/commands/install.yaml +7 -0
- data/lib/rubik/security/classifier/commands/isort.yaml +14 -0
- data/lib/rubik/security/classifier/commands/java.yaml +35 -0
- data/lib/rubik/security/classifier/commands/javac.yaml +39 -0
- data/lib/rubik/security/classifier/commands/join.yaml +7 -0
- data/lib/rubik/security/classifier/commands/journalctl.yaml +14 -0
- data/lib/rubik/security/classifier/commands/jq.yaml +7 -0
- data/lib/rubik/security/classifier/commands/kill.yaml +7 -0
- data/lib/rubik/security/classifier/commands/killall.yaml +7 -0
- data/lib/rubik/security/classifier/commands/kubectl.yaml +211 -0
- data/lib/rubik/security/classifier/commands/less.yaml +7 -0
- data/lib/rubik/security/classifier/commands/ln.yaml +7 -0
- data/lib/rubik/security/classifier/commands/ls.yaml +7 -0
- data/lib/rubik/security/classifier/commands/make.yaml +21 -0
- data/lib/rubik/security/classifier/commands/md5sum.yaml +7 -0
- data/lib/rubik/security/classifier/commands/mise.yaml +579 -0
- data/lib/rubik/security/classifier/commands/mkdir.yaml +8 -0
- data/lib/rubik/security/classifier/commands/more.yaml +7 -0
- data/lib/rubik/security/classifier/commands/mv.yaml +7 -0
- data/lib/rubik/security/classifier/commands/mvn.yaml +83 -0
- data/lib/rubik/security/classifier/commands/mvnw.yaml +83 -0
- data/lib/rubik/security/classifier/commands/mypy.yaml +9 -0
- data/lib/rubik/security/classifier/commands/netstat.yaml +7 -0
- data/lib/rubik/security/classifier/commands/nice.yaml +11 -0
- data/lib/rubik/security/classifier/commands/nl.yaml +7 -0
- data/lib/rubik/security/classifier/commands/node.yaml +20 -0
- data/lib/rubik/security/classifier/commands/nohup.yaml +9 -0
- data/lib/rubik/security/classifier/commands/npm.yaml +71 -0
- data/lib/rubik/security/classifier/commands/npx.yaml +42 -0
- data/lib/rubik/security/classifier/commands/nslookup.yaml +7 -0
- data/lib/rubik/security/classifier/commands/paste.yaml +7 -0
- data/lib/rubik/security/classifier/commands/ping.yaml +7 -0
- data/lib/rubik/security/classifier/commands/pip.yaml +33 -0
- data/lib/rubik/security/classifier/commands/pip3.yaml +33 -0
- data/lib/rubik/security/classifier/commands/pipx.yaml +33 -0
- data/lib/rubik/security/classifier/commands/pkill.yaml +7 -0
- data/lib/rubik/security/classifier/commands/pnpm.yaml +346 -0
- data/lib/rubik/security/classifier/commands/poetry.yaml +97 -0
- data/lib/rubik/security/classifier/commands/poweroff.yaml +8 -0
- data/lib/rubik/security/classifier/commands/prettier.yaml +13 -0
- data/lib/rubik/security/classifier/commands/printenv.yaml +7 -0
- data/lib/rubik/security/classifier/commands/printf.yaml +7 -0
- data/lib/rubik/security/classifier/commands/ps.yaml +7 -0
- data/lib/rubik/security/classifier/commands/pup.yaml +882 -0
- data/lib/rubik/security/classifier/commands/pwd.yaml +7 -0
- data/lib/rubik/security/classifier/commands/pytest.yaml +7 -0
- data/lib/rubik/security/classifier/commands/python.yaml +9 -0
- data/lib/rubik/security/classifier/commands/python3.yaml +9 -0
- data/lib/rubik/security/classifier/commands/read.yaml +7 -0
- data/lib/rubik/security/classifier/commands/readlink.yaml +7 -0
- data/lib/rubik/security/classifier/commands/realpath.yaml +7 -0
- data/lib/rubik/security/classifier/commands/reboot.yaml +8 -0
- data/lib/rubik/security/classifier/commands/rev.yaml +7 -0
- data/lib/rubik/security/classifier/commands/rg.yaml +7 -0
- data/lib/rubik/security/classifier/commands/rm.yaml +8 -0
- data/lib/rubik/security/classifier/commands/rsync.yaml +12 -0
- data/lib/rubik/security/classifier/commands/rtk.yaml +140 -0
- data/lib/rubik/security/classifier/commands/ruff.yaml +29 -0
- data/lib/rubik/security/classifier/commands/rustfmt.yaml +14 -0
- data/lib/rubik/security/classifier/commands/scp.yaml +7 -0
- data/lib/rubik/security/classifier/commands/sed.yaml +14 -0
- data/lib/rubik/security/classifier/commands/seq.yaml +7 -0
- data/lib/rubik/security/classifier/commands/sh.yaml +14 -0
- data/lib/rubik/security/classifier/commands/sha1sum.yaml +7 -0
- data/lib/rubik/security/classifier/commands/sha256sum.yaml +7 -0
- data/lib/rubik/security/classifier/commands/shellcheck.yaml +10 -0
- data/lib/rubik/security/classifier/commands/shutdown.yaml +8 -0
- data/lib/rubik/security/classifier/commands/slack.yaml +113 -0
- data/lib/rubik/security/classifier/commands/sleep.yaml +8 -0
- data/lib/rubik/security/classifier/commands/snip.yaml +79 -0
- data/lib/rubik/security/classifier/commands/sort.yaml +10 -0
- data/lib/rubik/security/classifier/commands/ss.yaml +7 -0
- data/lib/rubik/security/classifier/commands/ssh.yaml +41 -0
- data/lib/rubik/security/classifier/commands/stat.yaml +7 -0
- data/lib/rubik/security/classifier/commands/stdbuf.yaml +15 -0
- data/lib/rubik/security/classifier/commands/strace.yaml +20 -0
- data/lib/rubik/security/classifier/commands/strings.yaml +11 -0
- data/lib/rubik/security/classifier/commands/sudo.yaml +24 -0
- data/lib/rubik/security/classifier/commands/systemctl.yaml +58 -0
- data/lib/rubik/security/classifier/commands/systemd-run.yaml +30 -0
- data/lib/rubik/security/classifier/commands/tac.yaml +7 -0
- data/lib/rubik/security/classifier/commands/tail.yaml +7 -0
- data/lib/rubik/security/classifier/commands/tar.yaml +25 -0
- data/lib/rubik/security/classifier/commands/tee.yaml +8 -0
- data/lib/rubik/security/classifier/commands/terraform.yaml +70 -0
- data/lib/rubik/security/classifier/commands/test.yaml +7 -0
- data/lib/rubik/security/classifier/commands/time.yaml +8 -0
- data/lib/rubik/security/classifier/commands/timeout.yaml +18 -0
- data/lib/rubik/security/classifier/commands/top.yaml +7 -0
- data/lib/rubik/security/classifier/commands/touch.yaml +8 -0
- data/lib/rubik/security/classifier/commands/tr.yaml +7 -0
- data/lib/rubik/security/classifier/commands/traceroute.yaml +7 -0
- data/lib/rubik/security/classifier/commands/true.yaml +7 -0
- data/lib/rubik/security/classifier/commands/tsc.yaml +16 -0
- data/lib/rubik/security/classifier/commands/type.yaml +7 -0
- data/lib/rubik/security/classifier/commands/uname.yaml +7 -0
- data/lib/rubik/security/classifier/commands/unexpand.yaml +7 -0
- data/lib/rubik/security/classifier/commands/uniq.yaml +7 -0
- data/lib/rubik/security/classifier/commands/unzip.yaml +10 -0
- data/lib/rubik/security/classifier/commands/uptime.yaml +7 -0
- data/lib/rubik/security/classifier/commands/uv.yaml +156 -0
- data/lib/rubik/security/classifier/commands/wait.yaml +11 -0
- data/lib/rubik/security/classifier/commands/wc.yaml +7 -0
- data/lib/rubik/security/classifier/commands/wget.yaml +7 -0
- data/lib/rubik/security/classifier/commands/whereis.yaml +7 -0
- data/lib/rubik/security/classifier/commands/which.yaml +7 -0
- data/lib/rubik/security/classifier/commands/whoami.yaml +7 -0
- data/lib/rubik/security/classifier/commands/xargs.yaml +26 -0
- data/lib/rubik/security/classifier/commands/xmllint.yaml +7 -0
- data/lib/rubik/security/classifier/commands/yarn.yaml +72 -0
- data/lib/rubik/security/classifier/commands/yes.yaml +7 -0
- data/lib/rubik/security/classifier/commands/yq.yaml +10 -0
- data/lib/rubik/security/classifier/commands/zip.yaml +8 -0
- data/lib/rubik/security/classifier/commands/zsh.yaml +14 -0
- data/lib/rubik/security/classifier/database.rb +216 -0
- data/lib/rubik/security/classifier/matcher/delegation.rb +190 -0
- data/lib/rubik/security/classifier/matcher/options.rb +245 -0
- data/lib/rubik/security/classifier/matcher/subcommands.rb +103 -0
- data/lib/rubik/security/classifier/matcher.rb +249 -0
- data/lib/rubik/security/classifier/models.rb +170 -0
- data/lib/rubik/security/classifier/parser.rb +23 -0
- data/lib/rubik/security/classifier/parsers/bash.rb +280 -0
- data/lib/rubik/security/classifier/parsers/bash_extractors.rb +221 -0
- data/lib/rubik/security/classifier/parsers/powershell.rb +185 -0
- data/lib/rubik/security/classifier/pwsh_rules.rb +224 -0
- data/lib/rubik/security/classifier.rb +25 -0
- data/lib/rubik/security/errors.rb +39 -0
- data/lib/rubik/security/guard.rb +954 -0
- data/lib/rubik/security/redactor.rb +89 -0
- data/lib/rubik/security.rb +11 -0
- data/lib/rubik/session/manager.rb +331 -0
- data/lib/rubik/session/recorder.rb +149 -0
- data/lib/rubik/session/replayer.rb +65 -0
- data/lib/rubik/session.rb +10 -0
- data/lib/rubik/skills/frontmatter.rb +41 -0
- data/lib/rubik/skills/manager.rb +223 -0
- data/lib/rubik/skills/registry.rb +64 -0
- data/lib/rubik/skills/skill.rb +33 -0
- data/lib/rubik/skills/storage.rb +77 -0
- data/lib/rubik/skills/validator.rb +116 -0
- data/lib/rubik/skills.rb +20 -0
- data/lib/rubik/storage/folding.rb +23 -0
- data/lib/rubik/storage/layout.rb +145 -0
- data/lib/rubik/storage/render.rb +97 -0
- data/lib/rubik/storage/service.rb +42 -0
- data/lib/rubik/storage/store.rb +514 -0
- data/lib/rubik/storage/transcript_indexer.rb +116 -0
- data/lib/rubik/storage/uri_reader.rb +168 -0
- data/lib/rubik/storage/vakanuvis/annal_writer.rb +92 -0
- data/lib/rubik/storage/vakanuvis/distill_gate.rb +323 -0
- data/lib/rubik/storage/vakanuvis/gate.rb +250 -0
- data/lib/rubik/storage/vakanuvis/harness.rb +421 -0
- data/lib/rubik/storage/vakanuvis/memory_steward.rb +163 -0
- data/lib/rubik/storage/vakanuvis/service.rb +69 -0
- data/lib/rubik/storage/vakanuvis/vocabulary.rb +99 -0
- data/lib/rubik/storage/vakanuvis/wiki_skeleton.rb +67 -0
- data/lib/rubik/storage/vakanuvis.rb +77 -0
- data/lib/rubik/storage.rb +29 -0
- data/lib/rubik/tools/base.rb +107 -0
- data/lib/rubik/tools/builtins/dmesg.rb +74 -0
- data/lib/rubik/tools/builtins/exec.rb +293 -0
- data/lib/rubik/tools/builtins/files.rb +354 -0
- data/lib/rubik/tools/builtins/goal_ledger.rb +89 -0
- data/lib/rubik/tools/builtins/grep.rb +281 -0
- data/lib/rubik/tools/builtins/interactive.rb +175 -0
- data/lib/rubik/tools/builtins/lifecycle.rb +359 -0
- data/lib/rubik/tools/builtins/lsp.rb +283 -0
- data/lib/rubik/tools/builtins/pruner.rb +88 -0
- data/lib/rubik/tools/builtins/runtime.rb +120 -0
- data/lib/rubik/tools/builtins/send_message.rb +109 -0
- data/lib/rubik/tools/builtins/show_file.rb +84 -0
- data/lib/rubik/tools/builtins/skill.rb +72 -0
- data/lib/rubik/tools/builtins/storage.rb +232 -0
- data/lib/rubik/tools/builtins/subagent.rb +356 -0
- data/lib/rubik/tools/builtins/subagent_lifecycle.rb +72 -0
- data/lib/rubik/tools/builtins/symbols.rb +209 -0
- data/lib/rubik/tools/builtins/synthesis.rb +314 -0
- data/lib/rubik/tools/builtins/task.rb +168 -0
- data/lib/rubik/tools/builtins/unsynthesize.rb +111 -0
- data/lib/rubik/tools/builtins/vakanuvis.rb +161 -0
- data/lib/rubik/tools/builtins.rb +30 -0
- data/lib/rubik/tools/catalog.rb +70 -0
- data/lib/rubik/tools/declaration.rb +90 -0
- data/lib/rubik/tools/diagnostic_reporter.rb +283 -0
- data/lib/rubik/tools/fuzzy_matcher.rb +172 -0
- data/lib/rubik/tools/native_search.rb +180 -0
- data/lib/rubik/tools/output.rb +54 -0
- data/lib/rubik/tools/preflight_runner.rb +209 -0
- data/lib/rubik/tools/registry.rb +247 -0
- data/lib/rubik/tools/result.rb +71 -0
- data/lib/rubik/tools/services.rb +96 -0
- data/lib/rubik/tools/truncator.rb +78 -0
- data/lib/rubik/tools/uri_resolver.rb +195 -0
- data/lib/rubik/tools.rb +14 -0
- data/lib/rubik/ui/approvals.rb +52 -0
- data/lib/rubik/ui/banner.rb +43 -0
- data/lib/rubik/ui/capability.rb +122 -0
- data/lib/rubik/ui/dialog.rb +106 -0
- data/lib/rubik/ui/diff_viewer.rb +78 -0
- data/lib/rubik/ui/frame.rb +95 -0
- data/lib/rubik/ui/markdown_stream.rb +107 -0
- data/lib/rubik/ui/panel.rb +98 -0
- data/lib/rubik/ui/renderer.rb +206 -0
- data/lib/rubik/ui/spinner.rb +120 -0
- data/lib/rubik/ui/statusline.rb +134 -0
- data/lib/rubik/ui/theme.rb +118 -0
- data/lib/rubik/ui.rb +57 -0
- data/lib/rubik/uris.rb +101 -0
- data/lib/rubik/version.rb +5 -0
- data/lib/rubik.rb +65 -0
- metadata +770 -0
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../coeffects"
|
|
4
|
+
require_relative "../event_bus" unless defined?(Rubik::EventBus)
|
|
5
|
+
require_relative "../orchestrator/subagent/supervisor"
|
|
6
|
+
require_relative "../runtime/service_definition"
|
|
7
|
+
|
|
8
|
+
module Rubik
|
|
9
|
+
module REPL
|
|
10
|
+
# The ONE ordered, declarative catalog of everything Composition builds
|
|
11
|
+
# and the Shell publishes (architecture-review Candidate 05). Entry order
|
|
12
|
+
# IS construction order — the historical Shell#initialize sequence, which
|
|
13
|
+
# is load-bearing: the shared guard is built BEFORE every consumer
|
|
14
|
+
# (buffer, mcp, sandbox runner, task manager) so they all share the same
|
|
15
|
+
# instance; runtime_manager precedes task_manager / skills / mcp, which
|
|
16
|
+
# wire into its context; buffer precedes the subagent supervisor.
|
|
17
|
+
#
|
|
18
|
+
# owns : the entries (builders, provide keys, optional/reader flags,
|
|
19
|
+
# inject hooks) and the load-time derivations — Parts struct
|
|
20
|
+
# members, shell reader names, the build fold, wire provide rows
|
|
21
|
+
# leaves : key STRINGS and legacy aliases (Rubik::Coeffects SSOT —
|
|
22
|
+
# entries reference the constants); shell-identity phases
|
|
23
|
+
# (register shims, tool registry, UI, LLM route — lifecycle.rb);
|
|
24
|
+
# override-kwarg resolution and root resolution (composition.rb);
|
|
25
|
+
# tool-layer fallback defaults (Tools::Services)
|
|
26
|
+
#
|
|
27
|
+
# Adding a runtime service = its file + barrel require + a Coeffects key
|
|
28
|
+
# constant + ONE entry here. Parts members, the Shell ivar, the public
|
|
29
|
+
# reader and the wire provide all derive from that entry at load time;
|
|
30
|
+
# test_service_catalog.rb locks catalog <-> Parts <-> readers <->
|
|
31
|
+
# provides <-> Coeffects consistency so the derivation cannot drift.
|
|
32
|
+
module ServiceCatalog
|
|
33
|
+
# The fold scope: root inputs, caller-supplied overrides, and hash
|
|
34
|
+
# access to already-constructed entries. Service constants referenced
|
|
35
|
+
# inside builders resolve lazily (at fold time), so catalog load order
|
|
36
|
+
# carries no construction coupling.
|
|
37
|
+
class Scope
|
|
38
|
+
attr_reader :root_dir, :built
|
|
39
|
+
|
|
40
|
+
def initialize(root_dir:, overrides:)
|
|
41
|
+
@root_dir = root_dir
|
|
42
|
+
@overrides = overrides
|
|
43
|
+
@built = {}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def override_for(name)
|
|
47
|
+
@overrides[name]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def store(name, instance)
|
|
51
|
+
@built[name] = instance
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Forward-reference guard: a builder reaching for a service the fold
|
|
55
|
+
# has not produced yet fails here, loudly, instead of silently
|
|
56
|
+
# threading nil downstream. Overrides are visible immediately (an
|
|
57
|
+
# injected part IS the value its entry will adopt).
|
|
58
|
+
def [](name)
|
|
59
|
+
return @built[name] if @built.key?(name)
|
|
60
|
+
return @overrides[name] if @overrides.key?(name)
|
|
61
|
+
|
|
62
|
+
raise KeyError, "ServiceCatalog: :#{name} is not constructed yet — ordered later in the catalog (or missing)"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# instance_variable_get (not the home_dir reader) is kept verbatim
|
|
66
|
+
# from the pre-catalog Shell#initialize: it tolerates duck-typed
|
|
67
|
+
# configs without the reader.
|
|
68
|
+
def home_dir
|
|
69
|
+
@home_dir ||= self[:config]&.instance_variable_get(:@home_dir) || ENV.fetch("HOME", nil)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
DEFINITION = Rubik::Runtime::ServiceDefinition
|
|
74
|
+
|
|
75
|
+
ENTRIES = [
|
|
76
|
+
DEFINITION.new(
|
|
77
|
+
name: :config,
|
|
78
|
+
builder: ->(s) { Rubik::Config.new(root_dir: s.root_dir) },
|
|
79
|
+
provide: Rubik::Coeffects::CONFIG
|
|
80
|
+
),
|
|
81
|
+
DEFINITION.new(
|
|
82
|
+
name: :dmesg,
|
|
83
|
+
builder: ->(_s) { Rubik::Kernel::Dmesg.new },
|
|
84
|
+
provide: Rubik::Coeffects::DMESG
|
|
85
|
+
),
|
|
86
|
+
DEFINITION.new(
|
|
87
|
+
name: :dispatcher,
|
|
88
|
+
builder: ->(s) { Rubik::Kernel::Dispatcher.new(dmesg: s[:dmesg]) },
|
|
89
|
+
provide: Rubik::Coeffects::DISPATCHER,
|
|
90
|
+
after_inject: lambda do |values, _parts, _injected|
|
|
91
|
+
dispatcher = values.fetch(:dispatcher)
|
|
92
|
+
values[:runtime_manager]&.context&.on_dispose { dispatcher.stop }
|
|
93
|
+
end
|
|
94
|
+
),
|
|
95
|
+
DEFINITION.new(
|
|
96
|
+
name: :event_bus,
|
|
97
|
+
builder: ->(s) { Rubik::EventBus.new(dispatcher: s[:dispatcher]) },
|
|
98
|
+
provide: Rubik::Coeffects::EVENTS,
|
|
99
|
+
after_build: ->(s) { s[:config].event_bus = s[:event_bus] if s[:config].respond_to?(:event_bus=) }
|
|
100
|
+
),
|
|
101
|
+
DEFINITION.new(name: :extra_roots, input: true,
|
|
102
|
+
builder: ->(s) { Array(s[:config].fetch("workspace.additional_roots", [])).compact }),
|
|
103
|
+
DEFINITION.new(name: :allowed_ext_dirs, input: true,
|
|
104
|
+
builder: ->(s) { Array(s[:config].fetch("workspace.allowed_external_dirs", [])).compact }),
|
|
105
|
+
DEFINITION.new(name: :allow_ext_writes, input: true,
|
|
106
|
+
builder: ->(s) { s[:config].fetch("workspace.allow_external_writes", false) || false }),
|
|
107
|
+
# The ONE operator-policy guard (security.*) — built BEFORE every
|
|
108
|
+
# consumer below (buffer, mcp, sandbox runner, task manager) so they
|
|
109
|
+
# all share this instance. Live in-place mutation from !allow-cmd /
|
|
110
|
+
# !config (repl/config_wiring.rb) then reaches every verification
|
|
111
|
+
# path in the same session without restarts.
|
|
112
|
+
DEFINITION.new(
|
|
113
|
+
name: :guard,
|
|
114
|
+
builder: ->(s) { Rubik::Security::Guard.for_config(s[:config]) },
|
|
115
|
+
provide: Rubik::Coeffects::GUARD
|
|
116
|
+
),
|
|
117
|
+
DEFINITION.new(
|
|
118
|
+
name: :buffer_manager,
|
|
119
|
+
builder: lambda do |s|
|
|
120
|
+
Rubik::Buffer::Manager.new(
|
|
121
|
+
root_dir: s.root_dir, additional_roots: s[:extra_roots],
|
|
122
|
+
allowed_external_dirs: s[:allowed_ext_dirs], allow_external_writes: s[:allow_ext_writes],
|
|
123
|
+
event_bus: s[:event_bus], config: s[:config], guard: s[:guard]
|
|
124
|
+
)
|
|
125
|
+
end,
|
|
126
|
+
provide: Rubik::Coeffects::BUFFER_MANAGER,
|
|
127
|
+
after_inject: lambda do |values, parts, injected_buffer|
|
|
128
|
+
next unless injected_buffer
|
|
129
|
+
|
|
130
|
+
# Injected-buffer post-wiring runs only on the buffer_manager
|
|
131
|
+
# kwarg route, where Composition did not own the manager's config.
|
|
132
|
+
bm = values.fetch(:buffer_manager)
|
|
133
|
+
(parts.extra_roots || []).each { |r| bm.add_root(r) }
|
|
134
|
+
(parts.allowed_ext_dirs || []).each { |d| bm.add_allowed_dir(d) if bm.respond_to?(:add_allowed_dir) }
|
|
135
|
+
bm.allow_external_writes = parts.allow_ext_writes if bm.respond_to?(:allow_external_writes=)
|
|
136
|
+
end
|
|
137
|
+
),
|
|
138
|
+
DEFINITION.new(
|
|
139
|
+
name: :snapshot_store,
|
|
140
|
+
builder: lambda do |s|
|
|
141
|
+
Rubik::Buffer::SnapshotStore.new(storage_dir: File.join(s.home_dir, ".rubik", "snapshots",
|
|
142
|
+
File.basename(s.root_dir)))
|
|
143
|
+
end,
|
|
144
|
+
provide: Rubik::Coeffects::SNAPSHOT_STORE
|
|
145
|
+
),
|
|
146
|
+
DEFINITION.new(
|
|
147
|
+
name: :cache_store,
|
|
148
|
+
builder: ->(s) { Rubik::AST::CacheStore.new(root_dir: s.root_dir, home_dir: s.home_dir) }
|
|
149
|
+
),
|
|
150
|
+
DEFINITION.new(
|
|
151
|
+
name: :ast_graph,
|
|
152
|
+
# Provided into the context later, by Runtime::ASTService (Shell
|
|
153
|
+
# phase 4) — not by wire_runtime_context.
|
|
154
|
+
builder: ->(_s) { Rubik::AST::Graph.new },
|
|
155
|
+
# Sync load: cache is small (no bodies), symbols instantly
|
|
156
|
+
# available; the expensive walk/extract stays in the background
|
|
157
|
+
# warm-up phase.
|
|
158
|
+
after_inject: lambda do |values, _parts, _injected|
|
|
159
|
+
values.fetch(:ast_graph).load_from_cache(values.fetch(:cache_store))
|
|
160
|
+
end
|
|
161
|
+
),
|
|
162
|
+
# Provided into the context later, by Runtime::IndexService (Shell
|
|
163
|
+
# phase 4) — not by wire_runtime_context.
|
|
164
|
+
DEFINITION.new(
|
|
165
|
+
name: :context_index,
|
|
166
|
+
builder: lambda do |s|
|
|
167
|
+
includes = Array(s[:config]&.fetch("context.include", [])).compact
|
|
168
|
+
excludes = Array(s[:config]&.fetch("context.exclude", [])).compact
|
|
169
|
+
Rubik::Context::Index.new(
|
|
170
|
+
root_dir: s.root_dir,
|
|
171
|
+
additional_roots: (s[:config].fetch("workspace.auto_index_additional", true) ? s[:extra_roots] : []),
|
|
172
|
+
includes: includes,
|
|
173
|
+
excludes: excludes,
|
|
174
|
+
native: s[:config]&.fetch("tools.native")
|
|
175
|
+
)
|
|
176
|
+
end
|
|
177
|
+
),
|
|
178
|
+
DEFINITION.new(
|
|
179
|
+
name: :recorder,
|
|
180
|
+
# Absorb (storage.absorb_artifacts, default true): yeni oturumlar
|
|
181
|
+
# storage köküne yazılır — worktree .rubik/'sü temiz kalır; okuma
|
|
182
|
+
# tarafı (Session::Manager) her iki konumu da tarar.
|
|
183
|
+
builder: lambda { |s|
|
|
184
|
+
Rubik::Session::Recorder.new(root_dir: s.root_dir, home_dir: s.home_dir,
|
|
185
|
+
sessions_dir: Rubik::Storage::Layout.sessions_dir_for(s.root_dir, s[:config]))
|
|
186
|
+
}
|
|
187
|
+
),
|
|
188
|
+
DEFINITION.new(
|
|
189
|
+
name: :adapter_registry,
|
|
190
|
+
builder: ->(_s) { Rubik::Adapter::Registry.new },
|
|
191
|
+
provide: Rubik::Coeffects::ADAPTER_REGISTRY
|
|
192
|
+
),
|
|
193
|
+
DEFINITION.new(name: :llm_registry, builder: ->(s) { Rubik::LLM::Registry.new(s[:config]) }),
|
|
194
|
+
DEFINITION.new(
|
|
195
|
+
name: :router,
|
|
196
|
+
builder: ->(s) { Rubik::LLM::Router.new(config: s[:config], registry: s[:llm_registry]) },
|
|
197
|
+
provide: Rubik::Coeffects::ROUTER
|
|
198
|
+
),
|
|
199
|
+
# The context owner every later entry wires into; provided to tools
|
|
200
|
+
# by constructor injection, never as a coeffect.
|
|
201
|
+
DEFINITION.new(name: :runtime_manager, builder: ->(_s) { Rubik::Runtime::Manager.new }),
|
|
202
|
+
DEFINITION.new(name: :overlay_storage,
|
|
203
|
+
builder: ->(s) { Rubik::Runtime::OverlayStorage.new(root_dir: s.root_dir, home_dir: s.home_dir, guard: s[:guard]) }),
|
|
204
|
+
DEFINITION.new(
|
|
205
|
+
name: :lsp_manager,
|
|
206
|
+
builder: ->(s) { Rubik::LSP::Manager.new(config: s[:config], root_dir: s.root_dir) },
|
|
207
|
+
provide: Rubik::Coeffects::LSP_MANAGER,
|
|
208
|
+
after_inject: lambda do |values, _parts, _injected|
|
|
209
|
+
lsp = values.fetch(:lsp_manager)
|
|
210
|
+
values[:runtime_manager]&.context&.on_dispose { lsp&.stop_all }
|
|
211
|
+
end,
|
|
212
|
+
optional: true
|
|
213
|
+
),
|
|
214
|
+
DEFINITION.new(
|
|
215
|
+
name: :mcp_manager,
|
|
216
|
+
builder: lambda do |s|
|
|
217
|
+
Rubik::MCP::Manager.new(config: s[:config], root_dir: s.root_dir,
|
|
218
|
+
runtime_manager: s[:runtime_manager], guard: s[:guard])
|
|
219
|
+
end,
|
|
220
|
+
provide: Rubik::Coeffects::MCP_MANAGER,
|
|
221
|
+
after_inject: lambda do |values, _parts, _injected|
|
|
222
|
+
mcp = values.fetch(:mcp_manager)
|
|
223
|
+
values[:runtime_manager]&.context&.on_dispose { mcp&.stop_all }
|
|
224
|
+
end,
|
|
225
|
+
optional: true
|
|
226
|
+
),
|
|
227
|
+
DEFINITION.new(
|
|
228
|
+
name: :skill_manager,
|
|
229
|
+
builder: lambda do |s|
|
|
230
|
+
Rubik::Skills::Manager.new(config: s[:config], root_dir: s.root_dir, home_dir: s.home_dir,
|
|
231
|
+
runtime_context: s[:runtime_manager].context)
|
|
232
|
+
end,
|
|
233
|
+
provide: Rubik::Coeffects::SKILL_MANAGER,
|
|
234
|
+
optional: true
|
|
235
|
+
),
|
|
236
|
+
# Provide key deliberately differs from the member name: third
|
|
237
|
+
# parties resolve "sandbox" (ctx.require / Coeffects bridge).
|
|
238
|
+
DEFINITION.new(
|
|
239
|
+
name: :sandbox_runner,
|
|
240
|
+
builder: lambda do |s|
|
|
241
|
+
Rubik::Sandbox::Runner.new(root_dir: s.root_dir, config: s[:config],
|
|
242
|
+
allowed_external_dirs: s[:allowed_ext_dirs], guard: s[:guard])
|
|
243
|
+
end,
|
|
244
|
+
provide: Rubik::Coeffects::SANDBOX_RUNNER
|
|
245
|
+
),
|
|
246
|
+
DEFINITION.new(
|
|
247
|
+
name: :plugin_manager,
|
|
248
|
+
builder: ->(_s) { Rubik::Plugin::Manager.new },
|
|
249
|
+
provide: Rubik::Coeffects::PLUGIN_MANAGER,
|
|
250
|
+
reader: false
|
|
251
|
+
),
|
|
252
|
+
DEFINITION.new(
|
|
253
|
+
name: :plugin_storage,
|
|
254
|
+
builder: lambda do |s|
|
|
255
|
+
defined?(Rubik::Plugin::Storage) ? Rubik::Plugin::Storage.new(root_dir: s.root_dir, home_dir: s.home_dir) : nil
|
|
256
|
+
end,
|
|
257
|
+
provide: Rubik::Coeffects::PLUGIN_STORAGE,
|
|
258
|
+
provide_from: :parts,
|
|
259
|
+
assign_ivar: false
|
|
260
|
+
),
|
|
261
|
+
DEFINITION.new(
|
|
262
|
+
name: :task_manager,
|
|
263
|
+
builder: lambda do |s|
|
|
264
|
+
Rubik::Runtime::TaskManager.new(guard: s[:guard], context: s[:runtime_manager].context, root_dir: s.root_dir)
|
|
265
|
+
end,
|
|
266
|
+
provide: Rubik::Coeffects::TASK_MANAGER,
|
|
267
|
+
optional: true
|
|
268
|
+
),
|
|
269
|
+
DEFINITION.new(
|
|
270
|
+
name: :subagent_supervisor,
|
|
271
|
+
builder: lambda do |s|
|
|
272
|
+
Rubik::Orchestrator::Subagent::Supervisor.new(
|
|
273
|
+
root_context: s[:runtime_manager].context,
|
|
274
|
+
buffer_manager: s[:buffer_manager],
|
|
275
|
+
tool_registry: nil,
|
|
276
|
+
provider: nil,
|
|
277
|
+
router: s[:router],
|
|
278
|
+
config: s[:config],
|
|
279
|
+
root_dir: s.root_dir,
|
|
280
|
+
event_bus: s[:event_bus]
|
|
281
|
+
)
|
|
282
|
+
end,
|
|
283
|
+
provide: Rubik::Coeffects::SUBAGENT_SUPERVISOR,
|
|
284
|
+
optional: true
|
|
285
|
+
),
|
|
286
|
+
DEFINITION.new(
|
|
287
|
+
name: :init,
|
|
288
|
+
builder: lambda do |s|
|
|
289
|
+
Rubik::Kernel::Init.new(
|
|
290
|
+
context: s[:runtime_manager]&.context,
|
|
291
|
+
dmesg: s[:dmesg],
|
|
292
|
+
dispatcher: s[:dispatcher]
|
|
293
|
+
)
|
|
294
|
+
end,
|
|
295
|
+
provide: Rubik::Coeffects::INIT,
|
|
296
|
+
after_inject: lambda do |values, _parts, _injected|
|
|
297
|
+
init = values.fetch(:init)
|
|
298
|
+
values[:runtime_manager]&.context&.on_dispose { init.stop }
|
|
299
|
+
values[:task_manager].init = init if values[:task_manager].respond_to?(:init=)
|
|
300
|
+
values[:subagent_supervisor].init = init if values[:subagent_supervisor].respond_to?(:init=)
|
|
301
|
+
end
|
|
302
|
+
),
|
|
303
|
+
# The shell identity itself — provided at wire time, never built.
|
|
304
|
+
DEFINITION.new(
|
|
305
|
+
name: :shell,
|
|
306
|
+
parts_member: false,
|
|
307
|
+
builder: nil,
|
|
308
|
+
provide: Rubik::Coeffects::SHELL,
|
|
309
|
+
provide_from: :self
|
|
310
|
+
)
|
|
311
|
+
].each(&:freeze).freeze
|
|
312
|
+
|
|
313
|
+
class << self
|
|
314
|
+
def member_names
|
|
315
|
+
ENTRIES.reject { |e| e.parts_member == false }.map(&:name)
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def parts_struct
|
|
319
|
+
Struct.new(*member_names, keyword_init: true)
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
def injectable
|
|
323
|
+
ENTRIES.select(&:injectable?)
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def reader_names
|
|
327
|
+
ENTRIES.select(&:expose_reader?).map(&:name)
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def provided
|
|
331
|
+
ENTRIES.select(&:provided?)
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
def wire_after_inject(values, parts = nil, injected_buffer: false)
|
|
335
|
+
rm = values[:runtime_manager]
|
|
336
|
+
unless rm&.instance_variable_get(:@_catalog_after_injected)
|
|
337
|
+
rm&.instance_variable_set(:@_catalog_after_injected, true)
|
|
338
|
+
injectable.each { |e| e.after_inject&.call(values, parts, injected_buffer) }
|
|
339
|
+
end
|
|
340
|
+
injectable.find { |e| e.name == :buffer_manager }&.after_inject&.call(values, parts, true) if injected_buffer
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
# The construction fold. Caller-supplied overrides (config, event_bus,
|
|
344
|
+
# buffer_manager, snapshot_store kwargs) adopt their entry verbatim;
|
|
345
|
+
# everything else runs its builder with the scope. after_build hooks
|
|
346
|
+
# run per-entry (the config.event_bus cross-wire).
|
|
347
|
+
def build(scope)
|
|
348
|
+
ENTRIES.each do |entry|
|
|
349
|
+
next if entry.parts_member == false
|
|
350
|
+
|
|
351
|
+
scope.store(entry.name, scope.override_for(entry.name) || entry.builder&.call(scope))
|
|
352
|
+
entry.after_build&.call(scope)
|
|
353
|
+
end
|
|
354
|
+
wire_after_inject(scope.built)
|
|
355
|
+
scope.built
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
# Wire provide rows, in catalog order. Order is inert at wire time:
|
|
359
|
+
# the runtime manager holds zero registered fibers until phase 4
|
|
360
|
+
# (register_runtime_services) and phase 3 (load_plugins) run — every
|
|
361
|
+
# reconcile_all inside Manager#provide iterates an empty fiber map.
|
|
362
|
+
def wire_rows(shell, parts)
|
|
363
|
+
provided.to_h do |entry|
|
|
364
|
+
[entry.provide, case entry.provide_from
|
|
365
|
+
when :ivar then shell.instance_variable_get(:"@#{entry.name}")
|
|
366
|
+
when :parts then parts.respond_to?(entry.name) ? parts[entry.name] : nil
|
|
367
|
+
when :self then shell
|
|
368
|
+
end]
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
end
|
|
374
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubik
|
|
4
|
+
module REPL
|
|
5
|
+
# Öneri 3 (Kademe 3): Shell'den ayrılan kurulum fabrikaları. build_tool_registry
|
|
6
|
+
# default araç kaydını enjekte edilen alt sistemlerle kurar; orchestrator_loop
|
|
7
|
+
# aktif loop fiber'ını erişir (yoksa / farklı opts ile yeniden kurar);
|
|
8
|
+
# build_orchestrator_loop route/provider çözümlemesiyle LoopService.build_loop
|
|
9
|
+
# fabrikasını çalıştırır.
|
|
10
|
+
# Durum Shell'de yaşar (@buffer_manager, @context_index, @ast_graph,
|
|
11
|
+
# @adapter_registry, @guard, @sandbox_runner, @overlay_storage,
|
|
12
|
+
# @runtime_manager, @lsp_manager, @config, @router); mixin yalnızca
|
|
13
|
+
# fabrika politikasını kodlar.
|
|
14
|
+
module SetupFactories
|
|
15
|
+
# Öneri 3 (Kademe 3): build_tool_registry / orchestrator_loop /
|
|
16
|
+
# build_orchestrator_loop, lib/rubik/repl/setup_factories.rb mixin'ine
|
|
17
|
+
# taşındı (araç kaydı kurulumu ve orchestrator loop fabrikaları).
|
|
18
|
+
|
|
19
|
+
def build_tool_registry
|
|
20
|
+
# Service slots (guard, adapters, ast, tasks, sandbox, supervisor)
|
|
21
|
+
# resolve through Tools::Services' triple chain — the wire phase
|
|
22
|
+
# already provided the session's own instances. context_index stays
|
|
23
|
+
# an explicit override: RunTestsTool consumes the RAW kwarg for
|
|
24
|
+
# language detection, which must be the session's index on this
|
|
25
|
+
# path (a nil silently defaults every project to the ruby adapter).
|
|
26
|
+
Rubik::Tools::Registry.build_default(
|
|
27
|
+
buffer_manager: @buffer_manager, context_index: @context_index,
|
|
28
|
+
shell: self, runtime_manager: @runtime_manager,
|
|
29
|
+
overlay_storage: @overlay_storage, lsp_manager: @lsp_manager,
|
|
30
|
+
config: @config, root_dir: Dir.pwd
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def orchestrator_loop(opts = {})
|
|
35
|
+
fiber = @runtime_manager&.fibers&.[]("orchestrator_loop")
|
|
36
|
+
return fiber.instance if fiber && fiber.state == :active && fiber.instance && opts.empty?
|
|
37
|
+
|
|
38
|
+
build_orchestrator_loop(opts)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def build_orchestrator_loop(opts = {})
|
|
42
|
+
routed = if opts[:provider]
|
|
43
|
+
nil
|
|
44
|
+
else
|
|
45
|
+
begin
|
|
46
|
+
@router.route(task_type: opts[:task_type] || :auto, prompt: opts[:prompt])
|
|
47
|
+
rescue => e
|
|
48
|
+
Rubik::Platform.debug_warn("orchestrator loop route unavailable (coeffect fallback): #{e.class}: #{e.message}")
|
|
49
|
+
nil
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
provider = opts[:provider] || routed&.fetch(:provider, nil) ||
|
|
53
|
+
(@runtime_manager&.context.respond_to?(:get) ? Rubik::Coeffects.get(@runtime_manager.context, Rubik::Coeffects::LLM_CLIENT) : nil)
|
|
54
|
+
return nil unless provider
|
|
55
|
+
|
|
56
|
+
merged = opts.merge(
|
|
57
|
+
provider: provider,
|
|
58
|
+
model: opts[:model] || routed&.fetch(:model, nil),
|
|
59
|
+
context_limit: opts[:context_limit] || routed&.fetch(:context_limit, nil),
|
|
60
|
+
max_output_tokens: opts[:max_output_tokens] || routed&.fetch(:max_output_tokens, nil)
|
|
61
|
+
)
|
|
62
|
+
Rubik::Runtime::LoopService.build_loop(@runtime_manager&.context, shell: self, config: merged)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "reline"
|
|
4
|
+
require "stringio"
|
|
5
|
+
require_relative "command_parser"
|
|
6
|
+
require_relative "command_context"
|
|
7
|
+
require_relative "composition"
|
|
8
|
+
require_relative "../coeffects"
|
|
9
|
+
require_relative "hooks"
|
|
10
|
+
require_relative "commands"
|
|
11
|
+
require_relative "config_wiring"
|
|
12
|
+
require_relative "tee_io"
|
|
13
|
+
require_relative "interrupt_handler"
|
|
14
|
+
require_relative "confirmations"
|
|
15
|
+
require_relative "presentation"
|
|
16
|
+
require_relative "turn_recorder"
|
|
17
|
+
require_relative "lifecycle"
|
|
18
|
+
require_relative "input_loop"
|
|
19
|
+
require_relative "input_execution"
|
|
20
|
+
require_relative "paste_support"
|
|
21
|
+
require_relative "setup_factories"
|
|
22
|
+
require_relative "ast_warmup"
|
|
23
|
+
require_relative "../runtime"
|
|
24
|
+
|
|
25
|
+
module Rubik
|
|
26
|
+
module REPL
|
|
27
|
+
class Shell
|
|
28
|
+
include Confirmations
|
|
29
|
+
include Presentation
|
|
30
|
+
include TurnRecorder
|
|
31
|
+
include Lifecycle
|
|
32
|
+
include InputLoop
|
|
33
|
+
include InputExecution
|
|
34
|
+
include PasteSupport
|
|
35
|
+
include SetupFactories
|
|
36
|
+
include AstWarmup
|
|
37
|
+
|
|
38
|
+
attr_accessor :output, :conversation_history, :conversation_route_stamp,
|
|
39
|
+
:active_loop, :agent_caller, :terminal_guard
|
|
40
|
+
# Shell-owned readers (lifecycle state, not composed services).
|
|
41
|
+
attr_reader :commands, :hooks, :tool_registry, :input, :reline, :ui_theme,
|
|
42
|
+
:ui_renderer, :config_cleanups, :indexer_thread
|
|
43
|
+
# Composed-service readers derive from the ServiceCatalog SSOT
|
|
44
|
+
# (Candidate 05): adding a service = Coeffects key + catalog entry,
|
|
45
|
+
# and the reader follows the entry. Guarded by test_service_catalog.
|
|
46
|
+
attr_reader(*ServiceCatalog.reader_names)
|
|
47
|
+
|
|
48
|
+
# Plan 63 Faz B/C: subsystem construction lives in Composition.build; the
|
|
49
|
+
# shell keeps only phased coordination below (inject → invariant → wire →
|
|
50
|
+
# register → sync → warm-up). initialize stays a ~15-line orchestrator.
|
|
51
|
+
def initialize(config: nil, event_bus: nil, buffer_manager: nil, snapshot_store: nil, output: $stdout, input: $stdin, reline: Reline, root_dir: nil,
|
|
52
|
+
parts: nil, terminal_guard: nil)
|
|
53
|
+
parts ||= Composition.build(config: config, root_dir: root_dir, event_bus: event_bus,
|
|
54
|
+
buffer_manager: buffer_manager, snapshot_store: snapshot_store)
|
|
55
|
+
inject_parts(parts, injected_buffer: !buffer_manager.nil?)
|
|
56
|
+
@output = output
|
|
57
|
+
@input = input
|
|
58
|
+
@reline = reline
|
|
59
|
+
@terminal_guard = terminal_guard || TerminalGuard.new(
|
|
60
|
+
output: @output,
|
|
61
|
+
reline: @reline,
|
|
62
|
+
quiet: (@config.respond_to?(:fetch) ? @config.fetch("ui.quiet_notices", false) : false) == true
|
|
63
|
+
)
|
|
64
|
+
@hooks = Hooks.new
|
|
65
|
+
@commands = {}
|
|
66
|
+
@running = false
|
|
67
|
+
@dirty_turns = 0
|
|
68
|
+
# Plan 91 — set by the !paste command, consumed once by
|
|
69
|
+
# read_and_process_line to enter explicit paste mode.
|
|
70
|
+
@paste_requested = false
|
|
71
|
+
@conversation_history = []
|
|
72
|
+
# The in-flight Orchestrator::Loop during a free-text/goal turn, nil at
|
|
73
|
+
# idle. Set for the duration of a turn only (same-thread, synchronous
|
|
74
|
+
# tool execution); the ensure block in execute_free_text/goal clears it.
|
|
75
|
+
# NOT the runtime manager's orchestrator_loop fiber instance — that is
|
|
76
|
+
# a different, rebuilt-on-reprovide object no running turn is using.
|
|
77
|
+
@active_loop = nil
|
|
78
|
+
|
|
79
|
+
wire_runtime_context(parts)
|
|
80
|
+
load_plugins(parts)
|
|
81
|
+
register_runtime_services
|
|
82
|
+
build_and_provide_tool_registry
|
|
83
|
+
sync_ui
|
|
84
|
+
sync_default_llm_route
|
|
85
|
+
warm_up!
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def sync_context_and_ast(files)
|
|
89
|
+
return unless files && !files.empty?
|
|
90
|
+
|
|
91
|
+
root_d = @buffer_manager&.root_dir || Dir.pwd
|
|
92
|
+
files.each do |rel_file|
|
|
93
|
+
@context_index.update_file(rel_file)
|
|
94
|
+
full_path = File.join(root_d, rel_file)
|
|
95
|
+
File.exist?(full_path) ? @ast_graph.index_file(full_path) : @ast_graph.remove_file(full_path)
|
|
96
|
+
end
|
|
97
|
+
@ast_graph.save_to_cache(@cache_store) if @cache_store
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Öneri 3 (Kademe 4): warm_ast_graph / stop_background_indexer /
|
|
101
|
+
# join_indexer_safely / perform_warm_ast_graph,
|
|
102
|
+
# lib/rubik/repl/ast_warmup.rb mixin'ine taşındı (AST grafiği ısınma ve
|
|
103
|
+
# arka plan indexer yaşam döngüsü).
|
|
104
|
+
|
|
105
|
+
def outline_for(file_path)
|
|
106
|
+
full_path = File.expand_path(file_path, @buffer_manager&.root_dir || Dir.pwd)
|
|
107
|
+
@ast_graph.index_file(full_path) if File.exist?(full_path) && !@ast_graph.file_symbols.key?(full_path)
|
|
108
|
+
@ast_graph.outline_for(file_path)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def symbol_definition(symbol_name)
|
|
112
|
+
res = @ast_graph.symbol_definition(symbol_name)
|
|
113
|
+
if res.nil? && @indexer_thread&.alive?
|
|
114
|
+
join_indexer_safely(0.2)
|
|
115
|
+
res = @ast_graph.symbol_definition(symbol_name)
|
|
116
|
+
end
|
|
117
|
+
res
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def search_symbols(query)
|
|
121
|
+
join_indexer_safely(0.2) if @ast_graph.symbols.empty? && @indexer_thread&.alive?
|
|
122
|
+
@ast_graph.symbols.values.select { |sym| sym.name.downcase.include?(query.downcase) }
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def register_command(name, description:, usage: nil, custom: false, audience: nil, &handler)
|
|
126
|
+
key = name.to_s.downcase.delete_prefix("!")
|
|
127
|
+
return false if custom && @commands.key?(key) && !@commands[key][:custom]
|
|
128
|
+
|
|
129
|
+
resolved = { human: :human, agent: :agent, both: :both }.fetch(audience || (custom ? :both : :human)) do
|
|
130
|
+
raise ArgumentError, "invalid audience: #{audience.inspect}"
|
|
131
|
+
end
|
|
132
|
+
@commands[key] = { description: description, usage: usage, handler: handler, custom: custom, audience: resolved }
|
|
133
|
+
true
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def unregister_command(name)
|
|
137
|
+
@commands.delete(name.to_s.downcase.delete_prefix("!"))
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def run(input_stream = nil)
|
|
141
|
+
@running = true
|
|
142
|
+
|
|
143
|
+
if input_stream
|
|
144
|
+
run_stream(input_stream)
|
|
145
|
+
else
|
|
146
|
+
run_interactive
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def running?
|
|
151
|
+
!@running.nil? && @running
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def stop
|
|
155
|
+
if @buffer_manager&.dirty? && (@config.nil? || @config.fetch("buffer.exit_guard", true) != false)
|
|
156
|
+
count = @buffer_manager.dirty_files.size
|
|
157
|
+
@output.puts "⚠️ Warning: You have #{count} unapplied dirty buffer change(s)! Run '!apply' to persist or '!diff' to review."
|
|
158
|
+
end
|
|
159
|
+
@ui_renderer&.spinner&.kill
|
|
160
|
+
stop_background_indexer
|
|
161
|
+
@config_cleanups&.reverse_each(&:call)
|
|
162
|
+
@config_cleanups = []
|
|
163
|
+
# Ordering is load-bearing: disposing the runtime manager drains the
|
|
164
|
+
# ctx.on_dispose inverses (including LSP and MCP stop_all, and the
|
|
165
|
+
# subagent-notice unsubscribe) BEFORE shutdown_all kills subagents,
|
|
166
|
+
# so kill-time completion events find no listener and never spam the
|
|
167
|
+
# terminal on exit. Subsequent stop_all calls are idempotent no-ops.
|
|
168
|
+
@runtime_manager&.dispose!
|
|
169
|
+
@subagent_supervisor&.shutdown_all
|
|
170
|
+
@lsp_manager&.stop_all
|
|
171
|
+
@mcp_manager&.stop_all
|
|
172
|
+
Rubik.current_shell = nil if Rubik.current_shell == self
|
|
173
|
+
Rubik.runtime_manager = nil if Rubik.runtime_manager == @runtime_manager
|
|
174
|
+
@running = false
|
|
175
|
+
end
|
|
176
|
+
alias close stop
|
|
177
|
+
alias dispose stop
|
|
178
|
+
|
|
179
|
+
# Parses and dispatches a single line of REPL input to the appropriate handler.
|
|
180
|
+
#
|
|
181
|
+
# @param input_text [String] the raw input line from the user
|
|
182
|
+
# @return [void]
|
|
183
|
+
def execute_input(input_text)
|
|
184
|
+
parsed = CommandParser.parse(input_text)
|
|
185
|
+
@recorder.record(parsed.type, input_text) if !@replaying && parsed.type != :empty && parsed.type != :prompt
|
|
186
|
+
|
|
187
|
+
case parsed.type
|
|
188
|
+
when :empty
|
|
189
|
+
# noop
|
|
190
|
+
when :command
|
|
191
|
+
execute_command(parsed)
|
|
192
|
+
when :prompt
|
|
193
|
+
execute_free_text(parsed.raw)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
check_dirty_buffer_reminder unless @replaying
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def check_dirty_buffer_reminder
|
|
200
|
+
return unless @buffer_manager
|
|
201
|
+
|
|
202
|
+
if @buffer_manager.dirty?
|
|
203
|
+
@dirty_turns += 1
|
|
204
|
+
interval = @config.fetch("buffer.reminder_interval", 3).to_i
|
|
205
|
+
if interval.positive? && @dirty_turns >= interval
|
|
206
|
+
count = @buffer_manager.dirty_files.size
|
|
207
|
+
@output.puts "💡 [Rubik::Buffer] #{count} unapplied file modification(s) in buffer. Run '!diff' to review or '!apply' to persist to disk."
|
|
208
|
+
@dirty_turns = 0
|
|
209
|
+
end
|
|
210
|
+
else
|
|
211
|
+
@dirty_turns = 0
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def allowed_external_dirs
|
|
216
|
+
@buffer_manager&.allowed_external_dirs || []
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# Öneri 3 (Kademe 2): with_output / capture_output / execute_command /
|
|
220
|
+
# execute_free_text, lib/rubik/repl/input_execution.rb mixin'ine taşındı
|
|
221
|
+
# (I/O geçişi, bang-komut dispatch'i, serbest metin turn yaşam döngüsü).
|
|
222
|
+
# Öneri 3 (Kademe 3): build_tool_registry / orchestrator_loop /
|
|
223
|
+
# build_orchestrator_loop, lib/rubik/repl/setup_factories.rb mixin'ine
|
|
224
|
+
# taşındı (araç kaydı kurulumu ve orchestrator loop fabrikaları).
|
|
225
|
+
|
|
226
|
+
def register_default_commands
|
|
227
|
+
Rubik::REPL::Commands.register_all(self)
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
end
|