refactorai-cli 0.2.24__tar.gz → 0.2.26__tar.gz

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 (32) hide show
  1. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/PKG-INFO +2 -2
  2. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/README.md +1 -1
  3. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/pyproject.toml +1 -1
  4. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/__init__.py +1 -1
  5. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/commands/setup_cmds.py +6 -0
  6. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/setup_flow.py +185 -1
  7. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli.egg-info/PKG-INFO +2 -2
  8. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/auth.py +0 -0
  9. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/client.py +0 -0
  10. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/commands/__init__.py +0 -0
  11. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/commands/auth_cmds.py +0 -0
  12. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/commands/engine_cmds.py +0 -0
  13. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/commands/model_cmds.py +0 -0
  14. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/commands/rules_cmds.py +0 -0
  15. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/commands/run_cmds.py +0 -0
  16. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/commands/runtime_cmds.py +0 -0
  17. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/commands/runtime_proxy_cmds.py +0 -0
  18. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/control_plane.py +0 -0
  19. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/credentials.py +0 -0
  20. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/local_constitution.py +0 -0
  21. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/local_engine_runtime.py +0 -0
  22. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/local_paths.py +0 -0
  23. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/main.py +0 -0
  24. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/model_policy.py +0 -0
  25. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/runtime_manager.py +0 -0
  26. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli/settings.py +0 -0
  27. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli.egg-info/SOURCES.txt +0 -0
  28. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli.egg-info/dependency_links.txt +0 -0
  29. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli.egg-info/entry_points.txt +0 -0
  30. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli.egg-info/requires.txt +0 -0
  31. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/refactorai_cli.egg-info/top_level.txt +0 -0
  32. {refactorai_cli-0.2.24 → refactorai_cli-0.2.26}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: refactorai-cli
3
- Version: 0.2.24
3
+ Version: 0.2.26
4
4
  Summary: Local-first CLI for the refactor platform
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -53,6 +53,6 @@ python -m twine upload ./refactorai-cli/dist/*
53
53
  ## Install test (local)
54
54
 
55
55
  ```bash
56
- python -m pip install ./refactorai-cli/dist/refactorai_cli-0.2.24-py3-none-any.whl
56
+ python -m pip install ./refactorai-cli/dist/refactorai_cli-0.2.26-py3-none-any.whl
57
57
  refactor --version
58
58
  ```
@@ -42,6 +42,6 @@ python -m twine upload ./refactorai-cli/dist/*
42
42
  ## Install test (local)
43
43
 
44
44
  ```bash
45
- python -m pip install ./refactorai-cli/dist/refactorai_cli-0.2.24-py3-none-any.whl
45
+ python -m pip install ./refactorai-cli/dist/refactorai_cli-0.2.26-py3-none-any.whl
46
46
  refactor --version
47
47
  ```
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "refactorai-cli"
3
- version = "0.2.24"
3
+ version = "0.2.26"
4
4
  description = "Local-first CLI for the refactor platform"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -5,4 +5,4 @@ the shared `refactor_core` pipeline from a project folder while staying
5
5
  authenticated to the hosted platform via a developer key.
6
6
  """
7
7
 
8
- __version__ = "0.2.24"
8
+ __version__ = "0.2.26"
@@ -66,5 +66,11 @@ def setup(
66
66
  console.print("[green]Setup completed successfully.[/green]")
67
67
  if result.execution_backend:
68
68
  console.print(f"[bold]backend[/bold]: {result.execution_backend}")
69
+ if result.sandbox_ready is True:
70
+ runtime = result.sandbox_runtime or "podman"
71
+ console.print(f"[bold]sandbox[/bold]: ready ({runtime})")
72
+ elif result.sandbox_ready is False:
73
+ detail = result.sandbox_reason or "Podman missing or not ready."
74
+ console.print(f"[yellow]sandbox[/yellow]: not ready ({detail})")
69
75
  console.print(f"[bold]completed stages[/bold]: {', '.join(result.completed_stages)}")
70
76
  console.print("[bold]next[/bold]: run `refactor init` and then `refactor review .`")
@@ -4,6 +4,8 @@ from __future__ import annotations
4
4
 
5
5
  import json
6
6
  import shutil
7
+ import subprocess
8
+ import sys
7
9
  from dataclasses import dataclass
8
10
  from datetime import datetime, timezone
9
11
  from pathlib import Path
@@ -55,6 +57,9 @@ class SetupResult:
55
57
  completed_stages: list[str]
56
58
  last_error: str = ""
57
59
  execution_backend: str = ""
60
+ sandbox_ready: bool | None = None
61
+ sandbox_runtime: str = ""
62
+ sandbox_reason: str = ""
58
63
 
59
64
 
60
65
  def _now_iso() -> str:
@@ -147,19 +152,186 @@ def get_setup_diagnostics() -> dict:
147
152
  return {"state": state, "stages": stages}
148
153
 
149
154
 
155
+ def _host_runtime_install_plan(runtime: str) -> list[str]:
156
+ """Return host-level install commands for a missing runtime binary."""
157
+ rt = (runtime or "").strip().lower()
158
+ if rt != "podman":
159
+ return []
160
+ if shutil.which("apt-get"):
161
+ return ["sudo apt-get update", "sudo apt-get install -y podman"]
162
+ if shutil.which("dnf"):
163
+ return ["sudo dnf install -y podman"]
164
+ if shutil.which("yum"):
165
+ return ["sudo yum install -y podman"]
166
+ if shutil.which("apk"):
167
+ return ["sudo apk add --no-cache podman"]
168
+ if shutil.which("pacman"):
169
+ return ["sudo pacman -Sy --noconfirm podman"]
170
+ if shutil.which("brew"):
171
+ plan = ["brew install podman"]
172
+ if sys.platform == "darwin":
173
+ plan.extend(
174
+ [
175
+ "podman machine inspect >/dev/null 2>&1 || podman machine init",
176
+ "podman machine start",
177
+ ]
178
+ )
179
+ return plan
180
+ return []
181
+
182
+
183
+ def _host_runtime_repair_plan(runtime: str) -> list[str]:
184
+ """Return host-level repair commands for an installed runtime."""
185
+ rt = (runtime or "").strip().lower()
186
+ if rt != "podman":
187
+ return []
188
+ if sys.platform == "darwin":
189
+ return [
190
+ "podman machine inspect >/dev/null 2>&1 || podman machine init",
191
+ "podman machine start",
192
+ ]
193
+ return []
194
+
195
+
196
+ def _run_host_plan(commands: list[str], emit: Callable[[str], None] | None = None) -> tuple[bool, str]:
197
+ """Run host-level setup commands sequentially."""
198
+ for command in commands:
199
+ if emit:
200
+ emit(f"Executing host command: {command}")
201
+ proc = subprocess.run(command, shell=True, capture_output=True, text=True)
202
+ if proc.returncode != 0:
203
+ detail = (proc.stderr or proc.stdout or "").strip()[:500]
204
+ return False, f"`{command}` -> {detail or 'unknown error'}"
205
+ return True, ""
206
+
207
+
208
+ def _podman_runtime_ready(runtime: str) -> tuple[bool, str]:
209
+ """Return whether Podman is installed and ready for container operations."""
210
+ try:
211
+ proc = subprocess.run([runtime, "info"], capture_output=True, text=True)
212
+ except OSError as exc:
213
+ return False, str(exc)
214
+ if proc.returncode == 0:
215
+ return True, ""
216
+ detail = (proc.stderr or proc.stdout or "").strip()[:500]
217
+ return False, detail or "Podman runtime is installed but not ready."
218
+
219
+
220
+ def _sandbox_summary_from_precheck() -> tuple[bool | None, str, str]:
221
+ """Read S1 output and derive sandbox readiness summary for CLI output."""
222
+ path = stage_output_path("S1")
223
+ if not path.is_file():
224
+ return None, "", ""
225
+ try:
226
+ payload = json.loads(path.read_text(encoding="utf-8"))
227
+ except (json.JSONDecodeError, OSError):
228
+ return None, "", ""
229
+ output = payload.get("output")
230
+ if not isinstance(output, dict):
231
+ return None, "", ""
232
+ ready_raw = output.get("podman_ready")
233
+ available_raw = output.get("podman_available")
234
+ sandbox_ready: bool | None = None
235
+ if isinstance(ready_raw, bool):
236
+ sandbox_ready = ready_raw
237
+ elif isinstance(available_raw, bool):
238
+ sandbox_ready = available_raw
239
+ reason = str(output.get("podman_ready_reason") or output.get("podman_reason") or "").strip()
240
+ runtime = "podman" if sandbox_ready is not None else ""
241
+ return sandbox_ready, runtime, reason
242
+
243
+
150
244
  def _stage_s1_precheck(_ask_approval: Callable[[str], bool], _emit: Callable[[str], None] | None = None) -> dict:
151
245
  profile = detect_machine_profile()
152
246
  runtime, reason = resolve_engine_runtime("podman")
247
+ podman_install_plan: list[str] = []
248
+ podman_install_approved = False
249
+ podman_install_attempted = False
250
+ podman_repair_plan: list[str] = []
251
+ podman_repair_approved = False
252
+ podman_repair_attempted = False
153
253
  disk = shutil.disk_usage(str(refactor_home()))
154
254
  blockers: list[str] = []
155
255
  if disk.free < 2 * 1024 * 1024 * 1024:
156
256
  blockers.append("Less than 2GB free disk available in REFACTOR_HOME filesystem.")
157
257
  if blockers:
158
258
  raise SetupError("Precheck failed: " + "; ".join(blockers))
259
+ if not runtime:
260
+ podman_install_plan = _host_runtime_install_plan("podman")
261
+ if podman_install_plan:
262
+ podman_install_approved = _ask_approval(
263
+ "Install Podman host runtime now so sandboxed review can run?"
264
+ )
265
+ if podman_install_approved:
266
+ podman_install_attempted = True
267
+ if _emit:
268
+ _emit("Podman was not found. Running guided host install plan...")
269
+ ok, detail = _run_host_plan(podman_install_plan, emit=_emit)
270
+ if not ok:
271
+ raise SetupError(
272
+ "Podman host install failed: "
273
+ f"{detail}. Install manually and retry (`refactor doctor --sandbox`)."
274
+ )
275
+ runtime, reason = resolve_engine_runtime("podman")
276
+ if not runtime:
277
+ raise SetupError(
278
+ "Podman install completed but runtime is still unavailable. "
279
+ "Verify PATH and retry (`refactor doctor --sandbox`)."
280
+ )
281
+ elif _emit:
282
+ _emit("Podman is missing and no automated install plan is available on this host.")
283
+
284
+ podman_ready = False
285
+ podman_ready_reason = reason
286
+ if runtime:
287
+ podman_ready, podman_ready_reason = _podman_runtime_ready(str(runtime))
288
+ if not podman_ready:
289
+ podman_repair_plan = _host_runtime_repair_plan(str(runtime))
290
+ if podman_repair_plan:
291
+ podman_repair_approved = _ask_approval(
292
+ "Podman is installed but not ready. Initialize/start Podman machine now?"
293
+ )
294
+ if podman_repair_approved:
295
+ podman_repair_attempted = True
296
+ if _emit:
297
+ _emit("Podman is installed but not ready. Running repair plan...")
298
+ ok, detail = _run_host_plan(podman_repair_plan, emit=_emit)
299
+ if not ok:
300
+ raise SetupError(
301
+ "Podman runtime repair failed: "
302
+ f"{detail}. Run `podman machine start` and retry."
303
+ )
304
+ podman_ready, podman_ready_reason = _podman_runtime_ready(str(runtime))
305
+ if not podman_ready:
306
+ raise SetupError(
307
+ "Podman is installed but still not ready after repair: "
308
+ f"{podman_ready_reason}"
309
+ )
310
+ if _emit:
311
+ if runtime and podman_ready:
312
+ _emit("Sandbox runtime precheck: Podman is ready.")
313
+ elif runtime:
314
+ _emit(
315
+ "Sandbox runtime precheck: Podman is installed but not ready. "
316
+ "Setup can continue, but `refactor review` may fail until Podman is started."
317
+ )
318
+ else:
319
+ _emit(
320
+ "Sandbox runtime precheck: Podman is not installed. "
321
+ "Setup can continue, but sandboxed review requires Podman."
322
+ )
159
323
  return {
160
324
  "profile": profile,
161
325
  "podman_available": bool(runtime),
162
326
  "podman_reason": reason,
327
+ "podman_ready": bool(runtime and podman_ready),
328
+ "podman_ready_reason": podman_ready_reason,
329
+ "podman_install_plan": podman_install_plan,
330
+ "podman_install_approved": podman_install_approved,
331
+ "podman_install_attempted": podman_install_attempted,
332
+ "podman_repair_plan": podman_repair_plan,
333
+ "podman_repair_approved": podman_repair_approved,
334
+ "podman_repair_attempted": podman_repair_attempted,
163
335
  "disk_free_mb": int(disk.free / (1024 * 1024)),
164
336
  }
165
337
 
@@ -399,7 +571,15 @@ def run_setup(
399
571
  elif resume:
400
572
  pending = [stage for stage in STAGE_IDS if stage not in completed]
401
573
  if not pending:
402
- return SetupResult(status="already_completed", completed_stages=completed, last_error="")
574
+ sandbox_ready, sandbox_runtime, sandbox_reason = _sandbox_summary_from_precheck()
575
+ return SetupResult(
576
+ status="already_completed",
577
+ completed_stages=completed,
578
+ last_error="",
579
+ sandbox_ready=sandbox_ready,
580
+ sandbox_runtime=sandbox_runtime,
581
+ sandbox_reason=sandbox_reason,
582
+ )
403
583
  start_index = STAGE_IDS.index(pending[0])
404
584
  else:
405
585
  start_index = 0
@@ -478,9 +658,13 @@ def run_setup(
478
658
  "last_error": "",
479
659
  }
480
660
  )
661
+ sandbox_ready, sandbox_runtime, sandbox_reason = _sandbox_summary_from_precheck()
481
662
  return SetupResult(
482
663
  status="completed",
483
664
  completed_stages=completed,
484
665
  last_error="",
485
666
  execution_backend=final_backend,
667
+ sandbox_ready=sandbox_ready,
668
+ sandbox_runtime=sandbox_runtime,
669
+ sandbox_reason=sandbox_reason,
486
670
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: refactorai-cli
3
- Version: 0.2.24
3
+ Version: 0.2.26
4
4
  Summary: Local-first CLI for the refactor platform
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -53,6 +53,6 @@ python -m twine upload ./refactorai-cli/dist/*
53
53
  ## Install test (local)
54
54
 
55
55
  ```bash
56
- python -m pip install ./refactorai-cli/dist/refactorai_cli-0.2.24-py3-none-any.whl
56
+ python -m pip install ./refactorai-cli/dist/refactorai_cli-0.2.26-py3-none-any.whl
57
57
  refactor --version
58
58
  ```