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.
Files changed (523) hide show
  1. checksums.yaml +7 -0
  2. data/ATTRIBUTION.md +139 -0
  3. data/CHANGELOG.md +236 -0
  4. data/LICENSE +21 -0
  5. data/README.md +269 -0
  6. data/bin/rubik +82 -0
  7. data/lib/rubik/adapter/base.rb +195 -0
  8. data/lib/rubik/adapter/c.rb +36 -0
  9. data/lib/rubik/adapter/crystal.rb +78 -0
  10. data/lib/rubik/adapter/generic.rb +86 -0
  11. data/lib/rubik/adapter/go.rb +36 -0
  12. data/lib/rubik/adapter/node.rb +146 -0
  13. data/lib/rubik/adapter/process.rb +78 -0
  14. data/lib/rubik/adapter/python.rb +30 -0
  15. data/lib/rubik/adapter/registry.rb +81 -0
  16. data/lib/rubik/adapter/ruby.rb +30 -0
  17. data/lib/rubik/adapter/rust.rb +36 -0
  18. data/lib/rubik/adapter/zig.rb +36 -0
  19. data/lib/rubik/adapter.rb +18 -0
  20. data/lib/rubik/ast/body_loader.rb +19 -0
  21. data/lib/rubik/ast/c_extractor.rb +114 -0
  22. data/lib/rubik/ast/cache_store.rb +191 -0
  23. data/lib/rubik/ast/extractor.rb +59 -0
  24. data/lib/rubik/ast/fallback_cleaner.rb +145 -0
  25. data/lib/rubik/ast/go_extractor.rb +148 -0
  26. data/lib/rubik/ast/graph.rb +272 -0
  27. data/lib/rubik/ast/python_extractor.rb +120 -0
  28. data/lib/rubik/ast/ruby_extractor.rb +260 -0
  29. data/lib/rubik/ast/rust_extractor.rb +127 -0
  30. data/lib/rubik/ast/symbol.rb +103 -0
  31. data/lib/rubik/ast/treesitter/base_walker.rb +109 -0
  32. data/lib/rubik/ast/treesitter/c_walker.rb +122 -0
  33. data/lib/rubik/ast/treesitter/go_walker.rb +120 -0
  34. data/lib/rubik/ast/treesitter/python_walker.rb +107 -0
  35. data/lib/rubik/ast/treesitter/rust_walker.rb +130 -0
  36. data/lib/rubik/ast/treesitter/typescript_walker.rb +182 -0
  37. data/lib/rubik/ast/treesitter/zig_walker.rb +109 -0
  38. data/lib/rubik/ast/treesitter_extractor.rb +93 -0
  39. data/lib/rubik/ast/typescript_extractor.rb +283 -0
  40. data/lib/rubik/ast/zig_extractor.rb +116 -0
  41. data/lib/rubik/ast.rb +13 -0
  42. data/lib/rubik/benchmark/runner.rb +224 -0
  43. data/lib/rubik/benchmark/synth_repo.rb +59 -0
  44. data/lib/rubik/benchmark.rb +9 -0
  45. data/lib/rubik/buffer/diff.rb +43 -0
  46. data/lib/rubik/buffer/manager.rb +427 -0
  47. data/lib/rubik/buffer/path_validator.rb +60 -0
  48. data/lib/rubik/buffer/snapshot.rb +99 -0
  49. data/lib/rubik/buffer.rb +10 -0
  50. data/lib/rubik/coeffects.rb +129 -0
  51. data/lib/rubik/concurrency/boundary.rb +74 -0
  52. data/lib/rubik/concurrency/dns_pool.rb +68 -0
  53. data/lib/rubik/concurrency/errors.rb +17 -0
  54. data/lib/rubik/concurrency/event_loop.rb +441 -0
  55. data/lib/rubik/concurrency/join.rb +55 -0
  56. data/lib/rubik/concurrency/process_waiter.rb +55 -0
  57. data/lib/rubik/concurrency/scheduler.rb +84 -0
  58. data/lib/rubik/concurrency/timers.rb +109 -0
  59. data/lib/rubik/concurrency.rb +132 -0
  60. data/lib/rubik/config/deep_ops.rb +80 -0
  61. data/lib/rubik/config/defaults.rb +248 -0
  62. data/lib/rubik/config/model_catalog.rb +93 -0
  63. data/lib/rubik/config/store.rb +155 -0
  64. data/lib/rubik/config.rb +216 -0
  65. data/lib/rubik/context/git_info.rb +84 -0
  66. data/lib/rubik/context/git_lister.rb +37 -0
  67. data/lib/rubik/context/index.rb +134 -0
  68. data/lib/rubik/context/repo_context_reader.rb +121 -0
  69. data/lib/rubik/context/scanner.rb +439 -0
  70. data/lib/rubik/context.rb +11 -0
  71. data/lib/rubik/diagnostics/collector.rb +200 -0
  72. data/lib/rubik/diagnostics/entry.rb +60 -0
  73. data/lib/rubik/diagnostics/parser.rb +107 -0
  74. data/lib/rubik/diagnostics.rb +10 -0
  75. data/lib/rubik/event_bus.rb +56 -0
  76. data/lib/rubik/kernel/dispatcher.rb +171 -0
  77. data/lib/rubik/kernel/dmesg.rb +116 -0
  78. data/lib/rubik/kernel/init.rb +177 -0
  79. data/lib/rubik/kernel/record.rb +85 -0
  80. data/lib/rubik/kernel/unit.rb +160 -0
  81. data/lib/rubik/llm/anthropic.rb +202 -0
  82. data/lib/rubik/llm/chunk_assembler.rb +285 -0
  83. data/lib/rubik/llm/client.rb +526 -0
  84. data/lib/rubik/llm/formatter.rb +450 -0
  85. data/lib/rubik/llm/message_sanitizer.rb +87 -0
  86. data/lib/rubik/llm/ollama.rb +167 -0
  87. data/lib/rubik/llm/openai.rb +21 -0
  88. data/lib/rubik/llm/openai_compatible.rb +216 -0
  89. data/lib/rubik/llm/provider.rb +125 -0
  90. data/lib/rubik/llm/registry.rb +336 -0
  91. data/lib/rubik/llm/router.rb +100 -0
  92. data/lib/rubik/llm.rb +18 -0
  93. data/lib/rubik/log.rb +38 -0
  94. data/lib/rubik/lsp/client.rb +475 -0
  95. data/lib/rubik/lsp/manager.rb +366 -0
  96. data/lib/rubik/lsp.rb +9 -0
  97. data/lib/rubik/mcp/boot_lifecycle.rb +114 -0
  98. data/lib/rubik/mcp/client.rb +169 -0
  99. data/lib/rubik/mcp/errors.rb +11 -0
  100. data/lib/rubik/mcp/manager.rb +619 -0
  101. data/lib/rubik/mcp/proxy_tool.rb +104 -0
  102. data/lib/rubik/mcp/transport/stdio.rb +255 -0
  103. data/lib/rubik/mcp.rb +12 -0
  104. data/lib/rubik/orchestrator/activity_log.rb +75 -0
  105. data/lib/rubik/orchestrator/auto_apply.rb +166 -0
  106. data/lib/rubik/orchestrator/budget_manager.rb +97 -0
  107. data/lib/rubik/orchestrator/continuation_manager.rb +161 -0
  108. data/lib/rubik/orchestrator/finish_message_selector.rb +55 -0
  109. data/lib/rubik/orchestrator/goal_ledger/drift.rb +71 -0
  110. data/lib/rubik/orchestrator/goal_ledger/ledger.rb +399 -0
  111. data/lib/rubik/orchestrator/goal_ledger/observation_projection.rb +179 -0
  112. data/lib/rubik/orchestrator/goal_ledger/patch.rb +268 -0
  113. data/lib/rubik/orchestrator/goal_ledger/schema.rb +123 -0
  114. data/lib/rubik/orchestrator/goal_ledger/validator.rb +361 -0
  115. data/lib/rubik/orchestrator/goal_ledger/verifier.rb +129 -0
  116. data/lib/rubik/orchestrator/goal_ledger/verify_spec.rb +50 -0
  117. data/lib/rubik/orchestrator/goal_ledger.rb +65 -0
  118. data/lib/rubik/orchestrator/goal_state.rb +184 -0
  119. data/lib/rubik/orchestrator/goal_wait.rb +125 -0
  120. data/lib/rubik/orchestrator/loop.rb +388 -0
  121. data/lib/rubik/orchestrator/lsp_feedback.rb +55 -0
  122. data/lib/rubik/orchestrator/maestro_gate.rb +65 -0
  123. data/lib/rubik/orchestrator/provider_recovery.rb +90 -0
  124. data/lib/rubik/orchestrator/provider_resolver.rb +69 -0
  125. data/lib/rubik/orchestrator/shell_deps.rb +85 -0
  126. data/lib/rubik/orchestrator/step_executor.rb +328 -0
  127. data/lib/rubik/orchestrator/stream_manager.rb +118 -0
  128. data/lib/rubik/orchestrator/subagent/activation.rb +65 -0
  129. data/lib/rubik/orchestrator/subagent/budget.rb +108 -0
  130. data/lib/rubik/orchestrator/subagent/completion.rb +61 -0
  131. data/lib/rubik/orchestrator/subagent/concurrency_gate.rb +37 -0
  132. data/lib/rubik/orchestrator/subagent/conversation_id.rb +67 -0
  133. data/lib/rubik/orchestrator/subagent/dependency.rb +398 -0
  134. data/lib/rubik/orchestrator/subagent/instance.rb +384 -0
  135. data/lib/rubik/orchestrator/subagent/lifecycle.rb +118 -0
  136. data/lib/rubik/orchestrator/subagent/messaging.rb +61 -0
  137. data/lib/rubik/orchestrator/subagent/narration.rb +125 -0
  138. data/lib/rubik/orchestrator/subagent/notices.rb +209 -0
  139. data/lib/rubik/orchestrator/subagent/questioner.rb +80 -0
  140. data/lib/rubik/orchestrator/subagent/reaper.rb +98 -0
  141. data/lib/rubik/orchestrator/subagent/resilience.rb +70 -0
  142. data/lib/rubik/orchestrator/subagent/reuse.rb +127 -0
  143. data/lib/rubik/orchestrator/subagent/scoped_registry.rb +79 -0
  144. data/lib/rubik/orchestrator/subagent/step_runner.rb +240 -0
  145. data/lib/rubik/orchestrator/subagent/storage_id.rb +26 -0
  146. data/lib/rubik/orchestrator/subagent/supervisor.rb +327 -0
  147. data/lib/rubik/orchestrator/subagent/transcript_formatter.rb +141 -0
  148. data/lib/rubik/orchestrator/subagent/type_registry.rb +199 -0
  149. data/lib/rubik/orchestrator/subagent_notice_inbox.rb +80 -0
  150. data/lib/rubik/orchestrator/tool_call_id.rb +47 -0
  151. data/lib/rubik/orchestrator/tool_circuit_breaker.rb +91 -0
  152. data/lib/rubik/orchestrator/tool_history.rb +39 -0
  153. data/lib/rubik/orchestrator/turn_executor/subagent_channel.rb +102 -0
  154. data/lib/rubik/orchestrator/turn_executor/user_channel.rb +172 -0
  155. data/lib/rubik/orchestrator/turn_executor.rb +376 -0
  156. data/lib/rubik/orchestrator.rb +11 -0
  157. data/lib/rubik/platform/filesystem.rb +64 -0
  158. data/lib/rubik/platform/io_drain.rb +53 -0
  159. data/lib/rubik/platform/path.rb +210 -0
  160. data/lib/rubik/platform/process.rb +38 -0
  161. data/lib/rubik/platform/sanitize.rb +157 -0
  162. data/lib/rubik/platform.rb +113 -0
  163. data/lib/rubik/plugin/dsl.rb +51 -0
  164. data/lib/rubik/plugin/manager.rb +247 -0
  165. data/lib/rubik/plugin/storage.rb +195 -0
  166. data/lib/rubik/plugin.rb +10 -0
  167. data/lib/rubik/prompt/context_builder.rb +377 -0
  168. data/lib/rubik/prompt/context_compactor.rb +326 -0
  169. data/lib/rubik/prompt/conversation_rows.rb +74 -0
  170. data/lib/rubik/prompt/doctrine.rb +160 -0
  171. data/lib/rubik/prompt/emergency_compactor.rb +81 -0
  172. data/lib/rubik/prompt/services.rb +60 -0
  173. data/lib/rubik/prompt/token_estimator.rb +63 -0
  174. data/lib/rubik/prompt/tool_teachings.rb +78 -0
  175. data/lib/rubik/prompt.rb +13 -0
  176. data/lib/rubik/repair/loop.rb +95 -0
  177. data/lib/rubik/repair.rb +8 -0
  178. data/lib/rubik/repl/ast_warmup.rb +129 -0
  179. data/lib/rubik/repl/command_context.rb +214 -0
  180. data/lib/rubik/repl/command_parser.rb +48 -0
  181. data/lib/rubik/repl/commands/agent.rb +30 -0
  182. data/lib/rubik/repl/commands/agent_context.rb +289 -0
  183. data/lib/rubik/repl/commands/agent_execution.rb +342 -0
  184. data/lib/rubik/repl/commands/agent_models.rb +212 -0
  185. data/lib/rubik/repl/commands/agent_providers.rb +232 -0
  186. data/lib/rubik/repl/commands/base.rb +55 -0
  187. data/lib/rubik/repl/commands/buffer.rb +124 -0
  188. data/lib/rubik/repl/commands/dmesg.rb +87 -0
  189. data/lib/rubik/repl/commands/lsp.rb +235 -0
  190. data/lib/rubik/repl/commands/mcp.rb +194 -0
  191. data/lib/rubik/repl/commands/plugins.rb +208 -0
  192. data/lib/rubik/repl/commands/pruner.rb +71 -0
  193. data/lib/rubik/repl/commands/session.rb +183 -0
  194. data/lib/rubik/repl/commands/skills.rb +111 -0
  195. data/lib/rubik/repl/commands/storage.rb +85 -0
  196. data/lib/rubik/repl/commands/subagents.rb +195 -0
  197. data/lib/rubik/repl/commands/system.rb +85 -0
  198. data/lib/rubik/repl/commands/tasks.rb +120 -0
  199. data/lib/rubik/repl/commands/workspace.rb +443 -0
  200. data/lib/rubik/repl/commands.rb +44 -0
  201. data/lib/rubik/repl/composition.rb +32 -0
  202. data/lib/rubik/repl/config_wiring.rb +142 -0
  203. data/lib/rubik/repl/confirmations.rb +56 -0
  204. data/lib/rubik/repl/hooks.rb +47 -0
  205. data/lib/rubik/repl/input_execution.rb +323 -0
  206. data/lib/rubik/repl/input_loop.rb +213 -0
  207. data/lib/rubik/repl/interrupt_handler.rb +217 -0
  208. data/lib/rubik/repl/lifecycle.rb +410 -0
  209. data/lib/rubik/repl/paste_support.rb +88 -0
  210. data/lib/rubik/repl/pending_notice_queue.rb +60 -0
  211. data/lib/rubik/repl/presentation.rb +132 -0
  212. data/lib/rubik/repl/pruner/brief.rb +101 -0
  213. data/lib/rubik/repl/pruner/gate.rb +279 -0
  214. data/lib/rubik/repl/pruner/harness.rb +236 -0
  215. data/lib/rubik/repl/pruner/rules.rb +316 -0
  216. data/lib/rubik/repl/pruner/service.rb +82 -0
  217. data/lib/rubik/repl/pruner.rb +39 -0
  218. data/lib/rubik/repl/service_catalog.rb +374 -0
  219. data/lib/rubik/repl/setup_factories.rb +66 -0
  220. data/lib/rubik/repl/shell.rb +231 -0
  221. data/lib/rubik/repl/step_formatter.rb +324 -0
  222. data/lib/rubik/repl/tee_io.rb +105 -0
  223. data/lib/rubik/repl/terminal_guard.rb +157 -0
  224. data/lib/rubik/repl/turn_recorder.rb +234 -0
  225. data/lib/rubik/repl.rb +14 -0
  226. data/lib/rubik/runtime/ast_service.rb +78 -0
  227. data/lib/rubik/runtime/context.rb +335 -0
  228. data/lib/rubik/runtime/diagnostic_engine.rb +188 -0
  229. data/lib/rubik/runtime/discovery.rb +342 -0
  230. data/lib/rubik/runtime/fiber.rb +142 -0
  231. data/lib/rubik/runtime/fiber_ordering.rb +52 -0
  232. data/lib/rubik/runtime/fiber_retry_gate.rb +84 -0
  233. data/lib/rubik/runtime/index_service.rb +58 -0
  234. data/lib/rubik/runtime/loop_service.rb +73 -0
  235. data/lib/rubik/runtime/manager.rb +241 -0
  236. data/lib/rubik/runtime/overlay_storage.rb +481 -0
  237. data/lib/rubik/runtime/service_definition.rb +54 -0
  238. data/lib/rubik/runtime/service_registration.rb +33 -0
  239. data/lib/rubik/runtime/task_manager.rb +302 -0
  240. data/lib/rubik/runtime.rb +19 -0
  241. data/lib/rubik/sandbox/driver/base.rb +30 -0
  242. data/lib/rubik/sandbox/driver/bubblewrap.rb +111 -0
  243. data/lib/rubik/sandbox/driver/docker.rb +113 -0
  244. data/lib/rubik/sandbox/driver/podman.rb +98 -0
  245. data/lib/rubik/sandbox/driver/process.rb +190 -0
  246. data/lib/rubik/sandbox/driver.rb +91 -0
  247. data/lib/rubik/sandbox/runner.rb +218 -0
  248. data/lib/rubik/sandbox/shell_resolver.rb +178 -0
  249. data/lib/rubik/sandbox.rb +8 -0
  250. data/lib/rubik/security/blocked_guidance.rb +187 -0
  251. data/lib/rubik/security/classifier/classifier.rb +440 -0
  252. data/lib/rubik/security/classifier/commands/agent-browser.yaml +9 -0
  253. data/lib/rubik/security/classifier/commands/apt.yaml +25 -0
  254. data/lib/rubik/security/classifier/commands/awk.yaml +10 -0
  255. data/lib/rubik/security/classifier/commands/basename.yaml +7 -0
  256. data/lib/rubik/security/classifier/commands/bash-classify.yaml +8 -0
  257. data/lib/rubik/security/classifier/commands/bash.yaml +20 -0
  258. data/lib/rubik/security/classifier/commands/black.yaml +12 -0
  259. data/lib/rubik/security/classifier/commands/brew.yaml +31 -0
  260. data/lib/rubik/security/classifier/commands/builtin.yaml +8 -0
  261. data/lib/rubik/security/classifier/commands/cargo.yaml +114 -0
  262. data/lib/rubik/security/classifier/commands/cat.yaml +7 -0
  263. data/lib/rubik/security/classifier/commands/chgrp.yaml +10 -0
  264. data/lib/rubik/security/classifier/commands/chmod.yaml +10 -0
  265. data/lib/rubik/security/classifier/commands/chown.yaml +10 -0
  266. data/lib/rubik/security/classifier/commands/column.yaml +7 -0
  267. data/lib/rubik/security/classifier/commands/comm.yaml +7 -0
  268. data/lib/rubik/security/classifier/commands/command.yaml +12 -0
  269. data/lib/rubik/security/classifier/commands/cp.yaml +7 -0
  270. data/lib/rubik/security/classifier/commands/crystal.yaml +63 -0
  271. data/lib/rubik/security/classifier/commands/curl.yaml +30 -0
  272. data/lib/rubik/security/classifier/commands/cut.yaml +7 -0
  273. data/lib/rubik/security/classifier/commands/date.yaml +10 -0
  274. data/lib/rubik/security/classifier/commands/df.yaml +7 -0
  275. data/lib/rubik/security/classifier/commands/diff.yaml +7 -0
  276. data/lib/rubik/security/classifier/commands/dig.yaml +7 -0
  277. data/lib/rubik/security/classifier/commands/dirname.yaml +7 -0
  278. data/lib/rubik/security/classifier/commands/docker.yaml +177 -0
  279. data/lib/rubik/security/classifier/commands/du.yaml +7 -0
  280. data/lib/rubik/security/classifier/commands/echo.yaml +7 -0
  281. data/lib/rubik/security/classifier/commands/env.yaml +15 -0
  282. data/lib/rubik/security/classifier/commands/eslint.yaml +12 -0
  283. data/lib/rubik/security/classifier/commands/eval.yaml +8 -0
  284. data/lib/rubik/security/classifier/commands/exec.yaml +12 -0
  285. data/lib/rubik/security/classifier/commands/expand.yaml +7 -0
  286. data/lib/rubik/security/classifier/commands/false.yaml +7 -0
  287. data/lib/rubik/security/classifier/commands/file.yaml +7 -0
  288. data/lib/rubik/security/classifier/commands/find.yaml +25 -0
  289. data/lib/rubik/security/classifier/commands/fmt.yaml +7 -0
  290. data/lib/rubik/security/classifier/commands/fold.yaml +7 -0
  291. data/lib/rubik/security/classifier/commands/free.yaml +7 -0
  292. data/lib/rubik/security/classifier/commands/gawk.yaml +10 -0
  293. data/lib/rubik/security/classifier/commands/gcloud.yaml +979 -0
  294. data/lib/rubik/security/classifier/commands/gh.yaml +615 -0
  295. data/lib/rubik/security/classifier/commands/git.yaml +524 -0
  296. data/lib/rubik/security/classifier/commands/glab-discussion.yaml +21 -0
  297. data/lib/rubik/security/classifier/commands/glab.yaml +807 -0
  298. data/lib/rubik/security/classifier/commands/go.yaml +44 -0
  299. data/lib/rubik/security/classifier/commands/gog.yaml +983 -0
  300. data/lib/rubik/security/classifier/commands/gradle.yaml +92 -0
  301. data/lib/rubik/security/classifier/commands/gradlew.yaml +92 -0
  302. data/lib/rubik/security/classifier/commands/grep.yaml +7 -0
  303. data/lib/rubik/security/classifier/commands/groups.yaml +7 -0
  304. data/lib/rubik/security/classifier/commands/gunzip.yaml +8 -0
  305. data/lib/rubik/security/classifier/commands/gws.yaml +211 -0
  306. data/lib/rubik/security/classifier/commands/gzip.yaml +7 -0
  307. data/lib/rubik/security/classifier/commands/hadolint.yaml +9 -0
  308. data/lib/rubik/security/classifier/commands/halt.yaml +8 -0
  309. data/lib/rubik/security/classifier/commands/head.yaml +7 -0
  310. data/lib/rubik/security/classifier/commands/helm.yaml +129 -0
  311. data/lib/rubik/security/classifier/commands/hostname.yaml +7 -0
  312. data/lib/rubik/security/classifier/commands/id.yaml +7 -0
  313. data/lib/rubik/security/classifier/commands/install.yaml +7 -0
  314. data/lib/rubik/security/classifier/commands/isort.yaml +14 -0
  315. data/lib/rubik/security/classifier/commands/java.yaml +35 -0
  316. data/lib/rubik/security/classifier/commands/javac.yaml +39 -0
  317. data/lib/rubik/security/classifier/commands/join.yaml +7 -0
  318. data/lib/rubik/security/classifier/commands/journalctl.yaml +14 -0
  319. data/lib/rubik/security/classifier/commands/jq.yaml +7 -0
  320. data/lib/rubik/security/classifier/commands/kill.yaml +7 -0
  321. data/lib/rubik/security/classifier/commands/killall.yaml +7 -0
  322. data/lib/rubik/security/classifier/commands/kubectl.yaml +211 -0
  323. data/lib/rubik/security/classifier/commands/less.yaml +7 -0
  324. data/lib/rubik/security/classifier/commands/ln.yaml +7 -0
  325. data/lib/rubik/security/classifier/commands/ls.yaml +7 -0
  326. data/lib/rubik/security/classifier/commands/make.yaml +21 -0
  327. data/lib/rubik/security/classifier/commands/md5sum.yaml +7 -0
  328. data/lib/rubik/security/classifier/commands/mise.yaml +579 -0
  329. data/lib/rubik/security/classifier/commands/mkdir.yaml +8 -0
  330. data/lib/rubik/security/classifier/commands/more.yaml +7 -0
  331. data/lib/rubik/security/classifier/commands/mv.yaml +7 -0
  332. data/lib/rubik/security/classifier/commands/mvn.yaml +83 -0
  333. data/lib/rubik/security/classifier/commands/mvnw.yaml +83 -0
  334. data/lib/rubik/security/classifier/commands/mypy.yaml +9 -0
  335. data/lib/rubik/security/classifier/commands/netstat.yaml +7 -0
  336. data/lib/rubik/security/classifier/commands/nice.yaml +11 -0
  337. data/lib/rubik/security/classifier/commands/nl.yaml +7 -0
  338. data/lib/rubik/security/classifier/commands/node.yaml +20 -0
  339. data/lib/rubik/security/classifier/commands/nohup.yaml +9 -0
  340. data/lib/rubik/security/classifier/commands/npm.yaml +71 -0
  341. data/lib/rubik/security/classifier/commands/npx.yaml +42 -0
  342. data/lib/rubik/security/classifier/commands/nslookup.yaml +7 -0
  343. data/lib/rubik/security/classifier/commands/paste.yaml +7 -0
  344. data/lib/rubik/security/classifier/commands/ping.yaml +7 -0
  345. data/lib/rubik/security/classifier/commands/pip.yaml +33 -0
  346. data/lib/rubik/security/classifier/commands/pip3.yaml +33 -0
  347. data/lib/rubik/security/classifier/commands/pipx.yaml +33 -0
  348. data/lib/rubik/security/classifier/commands/pkill.yaml +7 -0
  349. data/lib/rubik/security/classifier/commands/pnpm.yaml +346 -0
  350. data/lib/rubik/security/classifier/commands/poetry.yaml +97 -0
  351. data/lib/rubik/security/classifier/commands/poweroff.yaml +8 -0
  352. data/lib/rubik/security/classifier/commands/prettier.yaml +13 -0
  353. data/lib/rubik/security/classifier/commands/printenv.yaml +7 -0
  354. data/lib/rubik/security/classifier/commands/printf.yaml +7 -0
  355. data/lib/rubik/security/classifier/commands/ps.yaml +7 -0
  356. data/lib/rubik/security/classifier/commands/pup.yaml +882 -0
  357. data/lib/rubik/security/classifier/commands/pwd.yaml +7 -0
  358. data/lib/rubik/security/classifier/commands/pytest.yaml +7 -0
  359. data/lib/rubik/security/classifier/commands/python.yaml +9 -0
  360. data/lib/rubik/security/classifier/commands/python3.yaml +9 -0
  361. data/lib/rubik/security/classifier/commands/read.yaml +7 -0
  362. data/lib/rubik/security/classifier/commands/readlink.yaml +7 -0
  363. data/lib/rubik/security/classifier/commands/realpath.yaml +7 -0
  364. data/lib/rubik/security/classifier/commands/reboot.yaml +8 -0
  365. data/lib/rubik/security/classifier/commands/rev.yaml +7 -0
  366. data/lib/rubik/security/classifier/commands/rg.yaml +7 -0
  367. data/lib/rubik/security/classifier/commands/rm.yaml +8 -0
  368. data/lib/rubik/security/classifier/commands/rsync.yaml +12 -0
  369. data/lib/rubik/security/classifier/commands/rtk.yaml +140 -0
  370. data/lib/rubik/security/classifier/commands/ruff.yaml +29 -0
  371. data/lib/rubik/security/classifier/commands/rustfmt.yaml +14 -0
  372. data/lib/rubik/security/classifier/commands/scp.yaml +7 -0
  373. data/lib/rubik/security/classifier/commands/sed.yaml +14 -0
  374. data/lib/rubik/security/classifier/commands/seq.yaml +7 -0
  375. data/lib/rubik/security/classifier/commands/sh.yaml +14 -0
  376. data/lib/rubik/security/classifier/commands/sha1sum.yaml +7 -0
  377. data/lib/rubik/security/classifier/commands/sha256sum.yaml +7 -0
  378. data/lib/rubik/security/classifier/commands/shellcheck.yaml +10 -0
  379. data/lib/rubik/security/classifier/commands/shutdown.yaml +8 -0
  380. data/lib/rubik/security/classifier/commands/slack.yaml +113 -0
  381. data/lib/rubik/security/classifier/commands/sleep.yaml +8 -0
  382. data/lib/rubik/security/classifier/commands/snip.yaml +79 -0
  383. data/lib/rubik/security/classifier/commands/sort.yaml +10 -0
  384. data/lib/rubik/security/classifier/commands/ss.yaml +7 -0
  385. data/lib/rubik/security/classifier/commands/ssh.yaml +41 -0
  386. data/lib/rubik/security/classifier/commands/stat.yaml +7 -0
  387. data/lib/rubik/security/classifier/commands/stdbuf.yaml +15 -0
  388. data/lib/rubik/security/classifier/commands/strace.yaml +20 -0
  389. data/lib/rubik/security/classifier/commands/strings.yaml +11 -0
  390. data/lib/rubik/security/classifier/commands/sudo.yaml +24 -0
  391. data/lib/rubik/security/classifier/commands/systemctl.yaml +58 -0
  392. data/lib/rubik/security/classifier/commands/systemd-run.yaml +30 -0
  393. data/lib/rubik/security/classifier/commands/tac.yaml +7 -0
  394. data/lib/rubik/security/classifier/commands/tail.yaml +7 -0
  395. data/lib/rubik/security/classifier/commands/tar.yaml +25 -0
  396. data/lib/rubik/security/classifier/commands/tee.yaml +8 -0
  397. data/lib/rubik/security/classifier/commands/terraform.yaml +70 -0
  398. data/lib/rubik/security/classifier/commands/test.yaml +7 -0
  399. data/lib/rubik/security/classifier/commands/time.yaml +8 -0
  400. data/lib/rubik/security/classifier/commands/timeout.yaml +18 -0
  401. data/lib/rubik/security/classifier/commands/top.yaml +7 -0
  402. data/lib/rubik/security/classifier/commands/touch.yaml +8 -0
  403. data/lib/rubik/security/classifier/commands/tr.yaml +7 -0
  404. data/lib/rubik/security/classifier/commands/traceroute.yaml +7 -0
  405. data/lib/rubik/security/classifier/commands/true.yaml +7 -0
  406. data/lib/rubik/security/classifier/commands/tsc.yaml +16 -0
  407. data/lib/rubik/security/classifier/commands/type.yaml +7 -0
  408. data/lib/rubik/security/classifier/commands/uname.yaml +7 -0
  409. data/lib/rubik/security/classifier/commands/unexpand.yaml +7 -0
  410. data/lib/rubik/security/classifier/commands/uniq.yaml +7 -0
  411. data/lib/rubik/security/classifier/commands/unzip.yaml +10 -0
  412. data/lib/rubik/security/classifier/commands/uptime.yaml +7 -0
  413. data/lib/rubik/security/classifier/commands/uv.yaml +156 -0
  414. data/lib/rubik/security/classifier/commands/wait.yaml +11 -0
  415. data/lib/rubik/security/classifier/commands/wc.yaml +7 -0
  416. data/lib/rubik/security/classifier/commands/wget.yaml +7 -0
  417. data/lib/rubik/security/classifier/commands/whereis.yaml +7 -0
  418. data/lib/rubik/security/classifier/commands/which.yaml +7 -0
  419. data/lib/rubik/security/classifier/commands/whoami.yaml +7 -0
  420. data/lib/rubik/security/classifier/commands/xargs.yaml +26 -0
  421. data/lib/rubik/security/classifier/commands/xmllint.yaml +7 -0
  422. data/lib/rubik/security/classifier/commands/yarn.yaml +72 -0
  423. data/lib/rubik/security/classifier/commands/yes.yaml +7 -0
  424. data/lib/rubik/security/classifier/commands/yq.yaml +10 -0
  425. data/lib/rubik/security/classifier/commands/zip.yaml +8 -0
  426. data/lib/rubik/security/classifier/commands/zsh.yaml +14 -0
  427. data/lib/rubik/security/classifier/database.rb +216 -0
  428. data/lib/rubik/security/classifier/matcher/delegation.rb +190 -0
  429. data/lib/rubik/security/classifier/matcher/options.rb +245 -0
  430. data/lib/rubik/security/classifier/matcher/subcommands.rb +103 -0
  431. data/lib/rubik/security/classifier/matcher.rb +249 -0
  432. data/lib/rubik/security/classifier/models.rb +170 -0
  433. data/lib/rubik/security/classifier/parser.rb +23 -0
  434. data/lib/rubik/security/classifier/parsers/bash.rb +280 -0
  435. data/lib/rubik/security/classifier/parsers/bash_extractors.rb +221 -0
  436. data/lib/rubik/security/classifier/parsers/powershell.rb +185 -0
  437. data/lib/rubik/security/classifier/pwsh_rules.rb +224 -0
  438. data/lib/rubik/security/classifier.rb +25 -0
  439. data/lib/rubik/security/errors.rb +39 -0
  440. data/lib/rubik/security/guard.rb +954 -0
  441. data/lib/rubik/security/redactor.rb +89 -0
  442. data/lib/rubik/security.rb +11 -0
  443. data/lib/rubik/session/manager.rb +331 -0
  444. data/lib/rubik/session/recorder.rb +149 -0
  445. data/lib/rubik/session/replayer.rb +65 -0
  446. data/lib/rubik/session.rb +10 -0
  447. data/lib/rubik/skills/frontmatter.rb +41 -0
  448. data/lib/rubik/skills/manager.rb +223 -0
  449. data/lib/rubik/skills/registry.rb +64 -0
  450. data/lib/rubik/skills/skill.rb +33 -0
  451. data/lib/rubik/skills/storage.rb +77 -0
  452. data/lib/rubik/skills/validator.rb +116 -0
  453. data/lib/rubik/skills.rb +20 -0
  454. data/lib/rubik/storage/folding.rb +23 -0
  455. data/lib/rubik/storage/layout.rb +145 -0
  456. data/lib/rubik/storage/render.rb +97 -0
  457. data/lib/rubik/storage/service.rb +42 -0
  458. data/lib/rubik/storage/store.rb +514 -0
  459. data/lib/rubik/storage/transcript_indexer.rb +116 -0
  460. data/lib/rubik/storage/uri_reader.rb +168 -0
  461. data/lib/rubik/storage/vakanuvis/annal_writer.rb +92 -0
  462. data/lib/rubik/storage/vakanuvis/distill_gate.rb +323 -0
  463. data/lib/rubik/storage/vakanuvis/gate.rb +250 -0
  464. data/lib/rubik/storage/vakanuvis/harness.rb +421 -0
  465. data/lib/rubik/storage/vakanuvis/memory_steward.rb +163 -0
  466. data/lib/rubik/storage/vakanuvis/service.rb +69 -0
  467. data/lib/rubik/storage/vakanuvis/vocabulary.rb +99 -0
  468. data/lib/rubik/storage/vakanuvis/wiki_skeleton.rb +67 -0
  469. data/lib/rubik/storage/vakanuvis.rb +77 -0
  470. data/lib/rubik/storage.rb +29 -0
  471. data/lib/rubik/tools/base.rb +107 -0
  472. data/lib/rubik/tools/builtins/dmesg.rb +74 -0
  473. data/lib/rubik/tools/builtins/exec.rb +293 -0
  474. data/lib/rubik/tools/builtins/files.rb +354 -0
  475. data/lib/rubik/tools/builtins/goal_ledger.rb +89 -0
  476. data/lib/rubik/tools/builtins/grep.rb +281 -0
  477. data/lib/rubik/tools/builtins/interactive.rb +175 -0
  478. data/lib/rubik/tools/builtins/lifecycle.rb +359 -0
  479. data/lib/rubik/tools/builtins/lsp.rb +283 -0
  480. data/lib/rubik/tools/builtins/pruner.rb +88 -0
  481. data/lib/rubik/tools/builtins/runtime.rb +120 -0
  482. data/lib/rubik/tools/builtins/send_message.rb +109 -0
  483. data/lib/rubik/tools/builtins/show_file.rb +84 -0
  484. data/lib/rubik/tools/builtins/skill.rb +72 -0
  485. data/lib/rubik/tools/builtins/storage.rb +232 -0
  486. data/lib/rubik/tools/builtins/subagent.rb +356 -0
  487. data/lib/rubik/tools/builtins/subagent_lifecycle.rb +72 -0
  488. data/lib/rubik/tools/builtins/symbols.rb +209 -0
  489. data/lib/rubik/tools/builtins/synthesis.rb +314 -0
  490. data/lib/rubik/tools/builtins/task.rb +168 -0
  491. data/lib/rubik/tools/builtins/unsynthesize.rb +111 -0
  492. data/lib/rubik/tools/builtins/vakanuvis.rb +161 -0
  493. data/lib/rubik/tools/builtins.rb +30 -0
  494. data/lib/rubik/tools/catalog.rb +70 -0
  495. data/lib/rubik/tools/declaration.rb +90 -0
  496. data/lib/rubik/tools/diagnostic_reporter.rb +283 -0
  497. data/lib/rubik/tools/fuzzy_matcher.rb +172 -0
  498. data/lib/rubik/tools/native_search.rb +180 -0
  499. data/lib/rubik/tools/output.rb +54 -0
  500. data/lib/rubik/tools/preflight_runner.rb +209 -0
  501. data/lib/rubik/tools/registry.rb +247 -0
  502. data/lib/rubik/tools/result.rb +71 -0
  503. data/lib/rubik/tools/services.rb +96 -0
  504. data/lib/rubik/tools/truncator.rb +78 -0
  505. data/lib/rubik/tools/uri_resolver.rb +195 -0
  506. data/lib/rubik/tools.rb +14 -0
  507. data/lib/rubik/ui/approvals.rb +52 -0
  508. data/lib/rubik/ui/banner.rb +43 -0
  509. data/lib/rubik/ui/capability.rb +122 -0
  510. data/lib/rubik/ui/dialog.rb +106 -0
  511. data/lib/rubik/ui/diff_viewer.rb +78 -0
  512. data/lib/rubik/ui/frame.rb +95 -0
  513. data/lib/rubik/ui/markdown_stream.rb +107 -0
  514. data/lib/rubik/ui/panel.rb +98 -0
  515. data/lib/rubik/ui/renderer.rb +206 -0
  516. data/lib/rubik/ui/spinner.rb +120 -0
  517. data/lib/rubik/ui/statusline.rb +134 -0
  518. data/lib/rubik/ui/theme.rb +118 -0
  519. data/lib/rubik/ui.rb +57 -0
  520. data/lib/rubik/uris.rb +101 -0
  521. data/lib/rubik/version.rb +5 -0
  522. data/lib/rubik.rb +65 -0
  523. metadata +770 -0
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../base"
4
+ require_relative "../output"
5
+ require_relative "../../coeffects"
6
+
7
+ module Rubik
8
+ module Tools
9
+ # Talep düzlemi (context-pruner planı 2026-10-09): maestro'nun pencere
10
+ # budayıcı masası. İki eylem de Pruner::Harness'e delege olur — 'prune'
11
+ # asenkron kuyruklanır ve deterministik makbuz döner (maestro turn'ü
12
+ # asla LLM bekletilmez; plan turn sınırında uygulanır), 'status' tamamen
13
+ # deterministiktir. Görünürlük: REQUIRES memnuniyetsizse (knob kapalı)
14
+ # araç model yüzünde görünmez; ROOT_ONLY_TOOLS subagent düzlemlerine
15
+ # (self dahil) asla kopyalanmaz — kök penceresini yalnız kök budar.
16
+ # Mimari sınır: tools çekirdeği repl/'e require edemez — harness sınıfı
17
+ # ana yükleme ağacından (repl.rb → repl/pruner) gelir, burada yalnız
18
+ # duck-typed çağrılır.
19
+ class PruneContextTool < BaseTool
20
+ REQUIRES = [Rubik::Coeffects::PRUNER].freeze
21
+
22
+ DECLARATION = Declaration.new(
23
+ name: "prune_context", aliases: ["pruner"],
24
+ description: "Clean the ROOT conversation window (semi-deterministic: an LLM proposes a " \
25
+ "keep/drop/summarize plan; the harness validates it deterministically and applies " \
26
+ "it at the next turn boundary — goal/task turns and recent context are always " \
27
+ "preserved): 'prune' (queue a forced prune now; returns a deterministic receipt, " \
28
+ "never blocks on the LLM), 'status' (window estimate vs ceiling, staged plan " \
29
+ "state, last receipt).",
30
+ risk: :write, archetypes: [], write_grant: false,
31
+ maestro_blocked: false, # vakanüvis emsali: budayıcı düzlemi kökte doğrudan
32
+ params_schema: {
33
+ type: "object",
34
+ properties: {
35
+ action: {
36
+ type: "string", enum: ["prune", "status"],
37
+ description: "Operation (default: 'status')."
38
+ },
39
+ reason: { type: "string", description: "prune: optional one-line motive recorded in dmesg." }
40
+ }
41
+ }
42
+ )
43
+
44
+ def initialize(harness = nil, runtime_context: nil)
45
+ super(DECLARATION)
46
+ @harness = harness
47
+ @runtime_context = runtime_context
48
+ end
49
+
50
+ def execute(args = {})
51
+ action = (args["action"] || args[:action] || "status").to_s
52
+ harness = Rubik::Coeffects.resolve(@runtime_context, Rubik::Coeffects::PRUNER, @harness)
53
+ unless harness
54
+ return ToolOutput.error("Context pruner is not available: disabled by config " \
55
+ "(subagents.pruner.enabled=false) or the harness is not wired " \
56
+ "(the startup warning / dmesg has the cause).")
57
+ end
58
+
59
+ begin
60
+ case action
61
+ when "prune" then harness.prune(reason: arg(args, "reason") || "maestro")
62
+ when "status" then harness.status_text
63
+ else ToolOutput.error("Unknown prune_context action '#{action}' (valid: prune, status).")
64
+ end
65
+ rescue ArgumentError => e
66
+ ToolOutput.error("prune_context #{action}: #{e.message}")
67
+ rescue StandardError => e
68
+ # Duck-typed dmesg halkası (tools çekirdeği repl/pruner'ı require
69
+ # edemez — mimari sınır): ring varsa oraya, yoksa Log'a.
70
+ dmesg = harness.respond_to?(:dmesg) ? harness.dmesg : nil
71
+ if dmesg.respond_to?(:log)
72
+ dmesg.log(:repl, :warn, "prune_context #{action} failed: #{e.class}: #{e.message}")
73
+ else
74
+ Rubik::Log.warn(:repl, "prune_context #{action} failed: #{e.class}: #{e.message}")
75
+ end
76
+ ToolOutput.error("prune_context #{action} failed: #{e.class}: #{e.message} — retry the call " \
77
+ "or inspect dmesg(subsystem: 'repl').")
78
+ end
79
+ end
80
+
81
+ private
82
+
83
+ def arg(args, key, default = nil)
84
+ args[key] || args[key.to_sym] || default
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../base"
4
+ require_relative "../output"
5
+ require_relative "../../coeffects"
6
+
7
+ module Rubik
8
+ module Tools
9
+ class InspectRuntimeTool < BaseTool
10
+ DECLARATION = Declaration.new(
11
+ name: "inspect_runtime", aliases: ["runtime_status", "inspect_fibers"],
12
+ description: "Inspect the Spatiotemporal Composability runtime state: active/pending fibers, coeffects, registered services, tools, and commands",
13
+ risk: :read,
14
+ params_schema: {
15
+ type: "object",
16
+ properties: {
17
+ target: { type: "string", enum: ["all", "fibers", "services", "tools", "commands", "tasks"], description: "Component to inspect (default: all)" }
18
+ }
19
+ }
20
+ )
21
+ def initialize(runtime_manager = nil, tool_registry = nil, shell = nil)
22
+ super(DECLARATION)
23
+ @runtime_manager = runtime_manager
24
+ @tool_registry = tool_registry
25
+ @shell = shell
26
+ end
27
+
28
+ def execute(args = {})
29
+ target = (args["target"] || args[:target] || "all").to_s.downcase
30
+
31
+ lines = ["=== Rubik Spatiotemporal Runtime Diagnostics ==="]
32
+
33
+ if ["all", "services"].include?(target) && @runtime_manager
34
+ root_ctx = @runtime_manager.context
35
+ services = root_ctx.services
36
+ lines << "\n[Services / Coeffects Active (#{services.size})]:"
37
+ services.each { |k, v| lines << " • #{k.to_s.ljust(12)} -> #{v.class}" }
38
+ lines << " (LIFO Accumulator Depth: #{root_ctx.disposable_count} inverse disposables)"
39
+ end
40
+
41
+ if ["all", "fibers"].include?(target) && @runtime_manager
42
+ active = @runtime_manager.active_fibers
43
+ pending = @runtime_manager.pending_fibers
44
+ failed = @runtime_manager.fibers.values.select { |f| f.state == :failed }
45
+ lines << "\n[Fibers (#{active.size} Active, #{pending.size} Pending, #{failed.size} Failed)]:"
46
+ active.each { |f| lines << " 🟢 ACTIVE : #{f.name} (injects: #{f.inject.join(', ')})" }
47
+ pending.each do |f|
48
+ missing = f.inject.reject { |dep| @runtime_manager.context.has?(dep) }
49
+ lines << " ⏳ PENDING: #{f.name} (waiting on: #{missing.join(', ')})"
50
+ end
51
+ failed.each { |f| lines << " 🔴 FAILED : #{f.name} (error: #{f.last_error&.message})" }
52
+ end
53
+
54
+ if ["all", "tools"].include?(target) && @tool_registry
55
+ tools = @tool_registry.list
56
+ lines << "\n[Tool Registry (#{tools.size} Registered Tools)]:"
57
+ tools.each { |t| lines << " ⚙ #{t.name.ljust(22)} [#{t.risk}] - #{t.description[0..60]}" }
58
+ end
59
+
60
+ if ["all", "commands"].include?(target) && @shell
61
+ cmds = @shell.commands
62
+ lines << "\n[REPL Bang Commands (#{cmds.size} Registered)]:"
63
+ cmds.sort.each { |name, meta| lines << " !#{name.ljust(16)} : #{meta[:description]}" }
64
+ end
65
+
66
+ task_mgr = (Rubik::Coeffects.get(@runtime_manager.context, Rubik::Coeffects::TASK_MANAGER) if @runtime_manager&.context.respond_to?(:get))
67
+ task_mgr ||= @shell.task_manager if @shell.respond_to?(:task_manager)
68
+
69
+ if ["all", "tasks"].include?(target) && task_mgr
70
+ tasks = task_mgr.list
71
+ lines << "\n[Background Tasks (#{tasks.size} Tracked)]:"
72
+ if tasks.empty?
73
+ lines << " (none)"
74
+ else
75
+ tasks.each do |t|
76
+ dur = t.running? ? "up #{t.uptime.round(1)}s" : "#{t.status} (exit #{t.exit_code})"
77
+ lines << " • [#{t.id}] #{t.status.to_s.upcase} (PID #{t.pid}, #{dur}): #{t.command}"
78
+ end
79
+ end
80
+ end
81
+
82
+ lines.join("\n")
83
+ end
84
+ end
85
+
86
+ class ProvideServiceTool < BaseTool
87
+ DECLARATION = Declaration.new(
88
+ name: "provide_service", aliases: ["register_service", "add_service"],
89
+ description: "Provide a runtime service/coeffect into the root context, " \
90
+ "triggering reactive state transitions (Pending -> Active) for dependent fibers",
91
+ risk: :execute, maestro_blocked: false, # root runtime self-evolution plane (TOOLS.md maestro policy)
92
+ params_schema: {
93
+ type: "object",
94
+ properties: {
95
+ name: { type: "string", description: "Service/coeffect name (e.g. 'database', 'lsp_client', 'mock_api')" },
96
+ value: { type: "string", description: "Service description or initialization payload" }
97
+ },
98
+ required: ["name"]
99
+ }
100
+ )
101
+ def initialize(runtime_manager = nil)
102
+ super(DECLARATION)
103
+ @runtime_manager = runtime_manager
104
+ end
105
+
106
+ def execute(args = {})
107
+ name = (args["name"] || args[:name]).to_s.strip.downcase
108
+ val = args["value"] || args[:value] || true
109
+ return ToolOutput.error("Service name cannot be empty.") if name.empty?
110
+ return ToolOutput.error("Runtime manager is not available.") unless @runtime_manager
111
+
112
+ @runtime_manager.provide(name, val)
113
+ active_count = @runtime_manager.active_fibers.size
114
+ pending_count = @runtime_manager.pending_fibers.size
115
+
116
+ "Service '#{name}' provided to runtime context. Reconciled fibers: #{active_count} Active, #{pending_count} Pending."
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../base"
4
+ require_relative "../output"
5
+ require_relative "subagent" # SubagentToolHelpers (supervisor resolution)
6
+ require_relative "../../coeffects"
7
+ require_relative "../../orchestrator/subagent/conversation_id"
8
+
9
+ module Rubik
10
+ module Tools
11
+ # Tool for inter-agent messaging between supervisor and subagents (Plan 94).
12
+ # The subagent plane rebinds this tool to the child ctx (ScopedRegistry),
13
+ # so a subagent messaging the maestro carries its REAL sender id; the root
14
+ # plane keeps the machine default sender (agent-0).
15
+ class SendMessageTool < BaseTool
16
+ include SubagentToolHelpers
17
+
18
+ DECLARATION = Declaration.new(
19
+ name: "send_message", aliases: ["msg_agent", "tell_subagent"],
20
+ description: "Send a message or instruction to another agent or subagent by its conversation ID.",
21
+ risk: :execute, maestro_blocked: false, # steering plane — pointing the orchestrator's workers is orchestration
22
+ params_schema: {
23
+ type: "object",
24
+ properties: {
25
+ recipient: { type: "string", description: "The recipient subagent conversation ID (e.g. 'subagent-1')" },
26
+ message: { type: "string", description: "The message content to deliver" },
27
+ steps: { type: "integer", description: "Optional additional step budget to grant alongside message" }
28
+ },
29
+ required: ["recipient", "message"]
30
+ }
31
+ )
32
+ def initialize(supervisor: nil, runtime_context: nil)
33
+ super(DECLARATION)
34
+ @supervisor = supervisor
35
+ @runtime_context = runtime_context
36
+ end
37
+
38
+ def execute(args = {})
39
+ sup = resolve_supervisor(@supervisor, @runtime_context)
40
+ return ToolOutput.error("SubagentSupervisor is not available in runtime context.") unless sup
41
+
42
+ # Same model-output surface as manage_subagents: the recipient id
43
+ # goes through the shared dialect normalizer (B5). A multi-id list
44
+ # is an explicit error — a messaging tool must never silently drop
45
+ # recipients.
46
+ list = Rubik::Orchestrator::Subagent::ConversationId.normalize_list(args["recipient"] || args[:recipient])
47
+ return ToolOutput.error("Missing required parameter 'recipient'.") if list.empty?
48
+ if list.size > 1
49
+ return ToolOutput.error(
50
+ "send_message takes ONE recipient; got #{list.size} (#{list.join(', ')}). " \
51
+ "Send one message per recipient, or use manage_subagents for roster actions."
52
+ )
53
+ end
54
+
55
+ recipient = list.first
56
+ msg = (args["message"] || args[:message]).to_s.strip
57
+ return ToolOutput.error("Missing required parameter 'message'.") if msg.empty?
58
+
59
+ steps = args["steps"] || args[:steps]
60
+ sender = subagent_sender_id
61
+ delivered = if sender
62
+ sup.send_message(recipient, msg, additional_steps: steps, _sender_id: sender)
63
+ else
64
+ sup.send_message(recipient, msg, additional_steps: steps)
65
+ end
66
+ return delivery_text(recipient) if delivered == true
67
+ return queued_text(recipient, steps) if delivered == :queued
68
+
69
+ ToolOutput.error(
70
+ "Subagent '#{recipient}' not found or no longer active. If it recently finished, redeploy it with its " \
71
+ "context intact: manage_subagents(action: 'redeploy', conversation_id: '#{recipient}', prompt: '<task>') " \
72
+ "(if the runtime reports it is still settling, retry shortly); a fresh spawn is needed only after it was reaped."
73
+ )
74
+ end
75
+
76
+ private
77
+
78
+ # Subagent düzlemi (rebound araç): gönderen coeffect'i GERÇEK subagent
79
+ # id'sidir. Kök düzleminde sağlanmaz → Supervisor default'u kalır.
80
+ def subagent_sender_id
81
+ return nil unless @runtime_context.respond_to?(:get)
82
+
83
+ Rubik::Coeffects.get(@runtime_context, Rubik::Coeffects::SUBAGENT_SENDER_ID)
84
+ end
85
+
86
+ # Kök alias'ına giden mesajın yanıtı kök kişisiyle konuşur ("the
87
+ # maestro supervisor"), alıcıyı "subagent" diye adlandırmaz.
88
+ def delivery_text(recipient)
89
+ root_alias = Rubik::Orchestrator::Subagent::ConversationId.root_alias?(recipient)
90
+ return "Message successfully delivered to the maestro supervisor." if root_alias
91
+
92
+ "Message successfully delivered to subagent '#{recipient}'."
93
+ end
94
+
95
+ # Bitmiş ama henüz reap edilmemiş alıcı: mesaj inbox'ta bekler,
96
+ # redeploy history'ye boşaltır (Supervisor#send_message :queued).
97
+ def queued_text(recipient, steps)
98
+ note = if steps.to_i.positive?
99
+ " The requested #{steps}-step grant is NOT applied to a queued message — redeploy mints a fresh budget."
100
+ else
101
+ ""
102
+ end
103
+ "Subagent '#{recipient}' has finished; message QUEUED in its inbox and will be delivered when it is " \
104
+ "redeployed (manage_subagents action: 'redeploy', conversation_id: '#{recipient}'). It is lost if the " \
105
+ "subagent is reaped first.#{note}"
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../base"
4
+ require_relative "../output"
5
+ require_relative "../../coeffects"
6
+ require_relative "../../uris"
7
+
8
+ module Rubik
9
+ module Tools
10
+ # Kalıcı depo varlığını OKUMA aracı — iki düzlemli semantik (kullanıcı
11
+ # kararı 2026-09-30: subagent'ların içeriği kendi bağlamlarına
12
+ # yüklemesi engellenmemeli):
13
+ # • Kök ajan (StepExecutor): tam içerik :user_output event'iyle
14
+ # doğrudan KULLANICININ terminaline akar; modele yalnız kısa stub
15
+ # döner — "raporu göster" isteklerinde read_file + yeniden yazma
16
+ # iki-hop maliyetini (token ×2, yeniden biçimlendirme riski) ortadan
17
+ # kaldırır.
18
+ # • Subagent düzlemi (dispatch_subagent_tool): display kancası orada
19
+ # olmadığından tam içerik ajanın KENDİ bağlamına döner (read_file
20
+ # gibi); ekrana basım kök ajana aittir.
21
+ #
22
+ # Yalnız rubik://storage URI'leri — gerçek FS yolları read_file'ın
23
+ # (sandbox'lı) işi. REQUIRES sayesinde storage bağlanmamışken araç
24
+ # reklam edilmez (StorageTool ile aynı fail-closed gizlenme).
25
+ class ShowFileTool < BaseTool
26
+ REQUIRES = [Rubik::Coeffects::STORAGE_STORE].freeze
27
+
28
+ # Terminali sflamak yerine dürüst düşüş: büyük varlık pagine edilmeli.
29
+ # Satır kapısı tek başına yetmez — tek-dev-satırlık gövde (örn. depoya
30
+ # yazılmış minified JSON) 400 satırın altında kalır; byte kapısı eşlik
31
+ # eder (review-round 2 bulgusu).
32
+ MAX_DISPLAY_LINES = 400
33
+ MAX_DISPLAY_BYTES = 64 * 1024
34
+
35
+ DECLARATION = Declaration.new(
36
+ name: "show_file", aliases: ["show"],
37
+ description: "Read a stored entity (review report, plan, goal snapshot, note...) from the central " \
38
+ "storage database. As the ROOT agent, the full content renders DIRECTLY to the user's " \
39
+ "terminal and you only get a one-line stub — use it for 'show/göster' requests instead of " \
40
+ "read_file + re-echoing. In a subagent context the full content loads into YOUR context " \
41
+ "like read_file (terminal rendering is the root agent's job). Accepts rubik://storage " \
42
+ "URIs only, including refs form 'rubik://storage/<project>/refs/<alias>'.",
43
+ risk: :read,
44
+ params_schema: {
45
+ type: "object",
46
+ properties: {
47
+ path: { type: "string", description: "Storage URI: 'rubik://storage/<project>/<type>/<id>' or " \
48
+ "'rubik://storage/<project>/refs/<alias>'; browse via 'rubik://storage/index'" }
49
+ },
50
+ required: ["path"]
51
+ }
52
+ )
53
+ def initialize(runtime_context: nil)
54
+ super(DECLARATION)
55
+ @runtime_context = runtime_context
56
+ end
57
+
58
+ def execute(args = {})
59
+ path = (args["path"] || args[:path]).to_s.strip
60
+ # Yalnız storage şeması: only: kapısı storage dışı her girdiyi
61
+ # (storagefoo, goal, düz yol...) nil düşürür — ret mesajı bugünküyle
62
+ # bayt-bayt aynı.
63
+ out = UriResolver.resolve(path, ctx: @runtime_context, only: Rubik::Uris::STORAGE)
64
+ if out.nil?
65
+ return ToolOutput.error("show_file renders rubik://storage URIs only (got '#{path[0, 80]}'). " \
66
+ "For filesystem paths use read_file; browse entities via 'rubik://storage/index'.")
67
+ end
68
+
69
+ return out if out.is_a?(ToolOutput) && out.error?
70
+
71
+ content = out.to_s
72
+ lines = content.lines.size
73
+ if lines > MAX_DISPLAY_LINES || content.bytesize > MAX_DISPLAY_BYTES
74
+ return ToolOutput.error("Entity too large to render inline (#{lines} lines / #{content.bytesize} B; " \
75
+ "caps: #{MAX_DISPLAY_LINES} lines / #{MAX_DISPLAY_BYTES} B). " \
76
+ "Use read_file with offset/limit and summarize instead.")
77
+ end
78
+
79
+ ToolOutput.display(content, stub: "Rendered #{lines} lines to the user's terminal: #{Rubik::Uris.storage_relative(path)} " \
80
+ "(you are not expected to know the content; ask read_file only if you must reason about it)")
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../base"
4
+ require_relative "../output"
5
+ require_relative "../../coeffects"
6
+
7
+ module Rubik
8
+ module Tools
9
+ # Level-2 progressive disclosure (agentskills.io): returns the full
10
+ # SKILL.md body of one skill. Read-only — skills are data and are never
11
+ # executed here; auxiliary scripts run through run_command like any file.
12
+ #
13
+ # Coeffect contract (AGENTS.md §2): declared via REQUIRES as
14
+ # defense-in-depth — production registers this tool through
15
+ # Skills::Manager#open_epoch!, which only runs after the skill_manager
16
+ # coeffect is provided, but a direct/static registration (tests, future
17
+ # hosts) stays PENDING (hidden from Registry#schemas) until the coeffect
18
+ # is satisfied — the same gate ListFilesTool uses for context_index.
19
+ class SkillTool < BaseTool
20
+ NAME = "skill"
21
+ REQUIRES = [Rubik::Coeffects::SKILL_MANAGER].freeze
22
+
23
+ # Not in Catalog::BUILTINS — Skills::Manager#open_epoch! registers this
24
+ # tool dynamically with its own ctx inverse; the declaration is real
25
+ # wherever the tool is registered.
26
+ DECLARATION = Declaration.new(
27
+ name: NAME,
28
+ description: "Load the full instructions of an agent skill by name. Available skills are listed in " \
29
+ "the <skills> system-prompt section. Call this before following a skill's guidance; " \
30
+ "files under its scripts/, references/ or assets/ directories are read with read_file " \
31
+ "relative to the returned skill directory.",
32
+ risk: :read, maestro_blocked: false,
33
+ params_schema: {
34
+ type: "object",
35
+ properties: {
36
+ name: { type: "string", description: "Skill name exactly as listed in the <skills> section" }
37
+ },
38
+ required: ["name"]
39
+ }
40
+ )
41
+ def initialize(manager = nil, runtime_context: nil)
42
+ super(DECLARATION)
43
+ @manager = manager
44
+ @runtime_context = runtime_context
45
+ end
46
+
47
+ def execute(args = {})
48
+ manager = Rubik::Coeffects.resolve(@runtime_context, Rubik::Coeffects::SKILL_MANAGER, @manager)
49
+ return ToolOutput.error("Error: skills manager is not available.") unless manager
50
+ return ToolOutput.error("Error: skills are disabled (skills.enabled = false).") unless manager.enabled?
51
+
52
+ name = (args["name"] || args[:name]).to_s.strip
53
+ available = manager.all.map(&:name)
54
+ available_list = available.empty? ? "none" : available.join(", ")
55
+ return ToolOutput.error("Error: `name` is required. Available skills: #{available_list}.") if name.empty?
56
+
57
+ skill = manager.find(name)
58
+ return ToolOutput.error("Error: unknown skill '#{name}'. Available skills: #{available_list}.") unless skill
59
+
60
+ body = manager.body(name)
61
+ return ToolOutput.error("Error: SKILL.md of '#{name}' could not be read (#{skill.path}).") if body.nil?
62
+
63
+ ToolOutput.ok(<<~OUTPUT.strip)
64
+ Skill '#{skill.name}' (scope: #{skill.scope}, directory: #{skill.root})
65
+ Files referenced below (scripts/, references/, assets/) are read with read_file / run_command relative to that directory.
66
+ ---
67
+ #{body}
68
+ OUTPUT
69
+ end
70
+ end
71
+ end
72
+ end