refactorai-cli 0.2.30__tar.gz → 0.3.0__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 (33) hide show
  1. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/PKG-INFO +3 -2
  2. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/README.md +1 -1
  3. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/pyproject.toml +5 -1
  4. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/__init__.py +1 -1
  5. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/commands/run_cmds.py +81 -36
  6. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli.egg-info/PKG-INFO +3 -2
  7. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli.egg-info/requires.txt +1 -0
  8. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/auth.py +0 -0
  9. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/client.py +0 -0
  10. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/commands/__init__.py +0 -0
  11. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/commands/auth_cmds.py +0 -0
  12. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/commands/cloud_cmds.py +0 -0
  13. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/commands/engine_cmds.py +0 -0
  14. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/commands/model_cmds.py +0 -0
  15. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/commands/rules_cmds.py +0 -0
  16. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/commands/runtime_cmds.py +0 -0
  17. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/commands/runtime_proxy_cmds.py +0 -0
  18. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/commands/setup_cmds.py +0 -0
  19. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/control_plane.py +0 -0
  20. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/credentials.py +0 -0
  21. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/local_constitution.py +0 -0
  22. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/local_engine_runtime.py +0 -0
  23. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/local_paths.py +0 -0
  24. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/main.py +0 -0
  25. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/model_policy.py +0 -0
  26. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/runtime_manager.py +0 -0
  27. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/settings.py +0 -0
  28. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli/setup_flow.py +0 -0
  29. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli.egg-info/SOURCES.txt +0 -0
  30. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli.egg-info/dependency_links.txt +0 -0
  31. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli.egg-info/entry_points.txt +0 -0
  32. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/refactorai_cli.egg-info/top_level.txt +0 -0
  33. {refactorai_cli-0.2.30 → refactorai_cli-0.3.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: refactorai-cli
3
- Version: 0.2.30
3
+ Version: 0.3.0
4
4
  Summary: Local-first CLI for the refactor platform
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -8,6 +8,7 @@ Requires-Dist: typer>=0.12.0
8
8
  Requires-Dist: httpx>=0.27.0
9
9
  Requires-Dist: rich>=13.7.0
10
10
  Requires-Dist: PyYAML>=6.0.1
11
+ Requires-Dist: refactorai-core>=3.0.0
11
12
 
12
13
  # refactorai-cli
13
14
 
@@ -53,7 +54,7 @@ python -m twine upload ./refactorai-cli/dist/*
53
54
  ## Install test (local)
54
55
 
55
56
  ```bash
56
- python -m pip install ./refactorai-cli/dist/refactorai_cli-0.2.30-py3-none-any.whl
57
+ python -m pip install ./refactorai-cli/dist/refactorai_cli-0.3.0-py3-none-any.whl
57
58
  refactor --version
58
59
  ```
59
60
 
@@ -42,7 +42,7 @@ 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.30-py3-none-any.whl
45
+ python -m pip install ./refactorai-cli/dist/refactorai_cli-0.3.0-py3-none-any.whl
46
46
  refactor --version
47
47
  ```
48
48
 
@@ -1,14 +1,18 @@
1
1
  [project]
2
2
  name = "refactorai-cli"
3
- version = "0.2.30"
3
+ version = "0.3.0"
4
4
  description = "Local-first CLI for the refactor platform"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
7
+ # R21 core split: the CLI depends on the PUBLIC client core only. The proprietary
8
+ # engine (refactor-core-engine) is never installed on a developer's machine via
9
+ # pip; local mode runs the engine from the downloaded runtime binary instead.
7
10
  dependencies = [
8
11
  "typer>=0.12.0",
9
12
  "httpx>=0.27.0",
10
13
  "rich>=13.7.0",
11
14
  "PyYAML>=6.0.1",
15
+ "refactorai-core>=3.0.0",
12
16
  ]
13
17
 
14
18
  [project.scripts]
@@ -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.30"
8
+ __version__ = "0.3.0"
@@ -52,9 +52,6 @@ from refactor_core.apply import (
52
52
  )
53
53
  from refactor_core.budgeting import compute_budget
54
54
  from refactor_core.capabilities import resolve_capabilities
55
- from refactor_core.execution import resolve_mode, run_with_mode
56
- from refactor_core.execution.rr_executor import run_refactor_requests
57
- from refactor_core.execution.structural_ops import structural_compatibility_matrix
58
55
  from refactor_core.gate import evaluate_gate
59
56
  from refactor_core.refactor_requests import (
60
57
  DEFERRED,
@@ -70,30 +67,10 @@ from refactor_core.refactor_requests import (
70
67
  from refactor_core.refactor_ops import remediation_hint
71
68
  from refactor_core.indexing import index_target
72
69
  from refactor_core.models import Finding, GeneratedTest, PatchGroup, RunArtifact
73
- from refactor_core.pipeline import build_refactor_prompt, build_review_prompt
74
- from refactor_core.providers import get_provider, resolve_provider_name, supported_providers
75
70
  from refactor_core.rules import annotate_documents_with_rules, filter_documents_by_rules
76
71
  from refactor_core.security import merge_refactor_findings, suppress_findings_for_rr
77
72
  from refactor_core.security.semgrep_runner import EMBEDDED_SEMGREP_SENTINEL
78
73
  from refactor_core.security.suppression import SecuritySuppression
79
- from refactor_core.sandbox_runtime import (
80
- DEFAULT_IMAGE as SANDBOX_DEFAULT_IMAGE,
81
- DEFAULT_SHELL as SANDBOX_DEFAULT_SHELL,
82
- attach_shell as attach_sandbox_shell,
83
- command_exists_in_container,
84
- command_exists_in_sandbox,
85
- detect_installer_in_container,
86
- detect_installer_in_sandbox,
87
- ensure_sandbox,
88
- exec_in_container,
89
- exec_in_container_stream,
90
- exec_in_sandbox,
91
- exec_in_sandbox_stream,
92
- remove_sandbox_container,
93
- sandbox_name,
94
- resolve_runtime,
95
- stop_sandbox,
96
- )
97
74
  from refactor_core.store import (
98
75
  append_sandbox_install_history,
99
76
  clear_sandbox_state,
@@ -125,6 +102,27 @@ from refactorai_cli.setup_flow import (
125
102
 
126
103
  console = Console()
127
104
 
105
+ # Local mirrors of engine-only sandbox defaults (R21 core split). These are used
106
+ # as Typer option defaults, which are evaluated at import time, so they cannot be
107
+ # lazy-imported from the engine-only ``refactor_core.enginecore.sandbox_runtime`` module.
108
+ # They mirror ``sandbox_runtime.DEFAULT_IMAGE`` / ``DEFAULT_SHELL`` and are only
109
+ # meaningful in local mode (where the engine is present via the runtime binary).
110
+ SANDBOX_DEFAULT_IMAGE = "docker.io/library/alpine:3.20"
111
+ SANDBOX_DEFAULT_SHELL = "/bin/sh"
112
+
113
+
114
+ def _sandbox_runtime():
115
+ """Lazily import the engine-only sandbox runtime module (local mode only).
116
+
117
+ Cloud modes never touch the sandbox; this import is therefore reached only on
118
+ the local execution path, where the engine is present (inside the runtime
119
+ binary). A client-only install that never runs local commands never imports
120
+ it, keeping engine code off the developer's disk (R21 core split).
121
+ """
122
+ from refactor_core.enginecore import sandbox_runtime as _sr
123
+
124
+ return _sr
125
+
128
126
 
129
127
  def _read_stage_output(stage_id: str) -> dict:
130
128
  path = stage_output_path(stage_id)
@@ -638,14 +636,14 @@ def _cloud_inference(
638
636
  documents, _scope_meta = filter_documents_by_rules(documents, project_root=Path(project_root))
639
637
  rule_meta = annotate_documents_with_rules(documents, project_root=Path(project_root))
640
638
 
641
- if stage == "review":
642
- system_prompt, user_prompt = build_review_prompt(constitution, documents, max_alerts)
643
- else:
644
- # Feed prior review findings into the refactor prompt so cloud `code`
645
- # generates patches targeting the same issues (parity with local RR).
646
- system_prompt, user_prompt = build_refactor_prompt(
647
- constitution, documents, list(findings or []), max_alerts
648
- )
639
+ # Server-side prompt building (R21): send raw indexed documents + the
640
+ # constitution body and let the platform build the prompts. The proprietary
641
+ # prompt engineering stays off the developer's machine. Prior review findings
642
+ # are forwarded for the refactor stage so cloud `code` targets the same
643
+ # issues (parity with local RR).
644
+ request_findings = [
645
+ f.model_dump() if hasattr(f, "model_dump") else dict(f) for f in (findings or [])
646
+ ]
649
647
 
650
648
  execution_mode = _cloud_execution_mode(constitution) or "cloud_managed"
651
649
  auth_ctx = ensure_authenticated(project_root)
@@ -653,8 +651,9 @@ def _cloud_inference(
653
651
  "stage": stage,
654
652
  "execution_mode": execution_mode,
655
653
  "constitution_hash": constitution.content_hash,
656
- "system_prompt": system_prompt,
657
- "user_prompt": user_prompt,
654
+ "documents": documents,
655
+ "constitution_body": getattr(constitution, "body", "") or "",
656
+ "findings": request_findings if stage != "review" else [],
658
657
  "max_alerts": max_alerts,
659
658
  "model_hint": model_hint or str(constitution.get_setting("model_id", "managed-default") or "managed-default"),
660
659
  }
@@ -1186,6 +1185,15 @@ def _sandbox_preflight(
1186
1185
  workdir: str | None = None,
1187
1186
  ) -> tuple[bool, str]:
1188
1187
  """Run sandbox preflight and optionally perform approved install plan."""
1188
+ _sr = _sandbox_runtime()
1189
+ command_exists_in_container = _sr.command_exists_in_container
1190
+ command_exists_in_sandbox = _sr.command_exists_in_sandbox
1191
+ exec_in_container = _sr.exec_in_container
1192
+ exec_in_container_stream = _sr.exec_in_container_stream
1193
+ exec_in_sandbox = _sr.exec_in_sandbox
1194
+ exec_in_sandbox_stream = _sr.exec_in_sandbox_stream
1195
+ detect_installer_in_container = _sr.detect_installer_in_container
1196
+ detect_installer_in_sandbox = _sr.detect_installer_in_sandbox
1189
1197
 
1190
1198
  has_container_ctx = bool(runtime and container_name)
1191
1199
  resolved_workdir = str(workdir or "/workspace")
@@ -1485,6 +1493,10 @@ def _ensure_sandbox_ready(
1485
1493
  continue_on_preflight_failure: bool = False,
1486
1494
  ) -> dict | None:
1487
1495
  """Ensure sandbox lifecycle + preflight for stage execution."""
1496
+ _sr = _sandbox_runtime()
1497
+ resolve_runtime = _sr.resolve_runtime
1498
+ sandbox_name = _sr.sandbox_name
1499
+ ensure_sandbox = _sr.ensure_sandbox
1488
1500
  sandbox_cfg = _sandbox_settings(project_config)
1489
1501
  lifecycle = _sandbox_lifecycle(project_config)
1490
1502
  ephemeral = lifecycle == "per_run" and stage in {"review", "code"}
@@ -1553,6 +1565,9 @@ def _teardown_sandbox_context(project_root: Path, ctx: dict | None) -> None:
1553
1565
  """Clean up ephemeral per-run sandboxes."""
1554
1566
  if not ctx or not ctx.get("ephemeral"):
1555
1567
  return
1568
+ _sr = _sandbox_runtime()
1569
+ remove_sandbox_container = _sr.remove_sandbox_container
1570
+ sandbox_name = _sr.sandbox_name
1556
1571
  runtime = str(ctx.get("runtime") or "")
1557
1572
  name = str(ctx.get("container_name") or "")
1558
1573
  ok, msg = remove_sandbox_container(runtime=runtime, container_name=name)
@@ -1587,6 +1602,10 @@ def start(
1587
1602
  project_root, _constitution, project_config = _load_project()
1588
1603
  register_project(project_root)
1589
1604
 
1605
+ _sr = _sandbox_runtime()
1606
+ resolve_runtime = _sr.resolve_runtime
1607
+ ensure_sandbox = _sr.ensure_sandbox
1608
+ attach_sandbox_shell = _sr.attach_shell
1590
1609
  sandbox_cfg = _sandbox_settings(project_config)
1591
1610
  preferred_runtime = str(runtime or sandbox_cfg.get("runtime", "podman") or "podman")
1592
1611
  resolved_runtime, reason = resolve_runtime(preferred_runtime)
@@ -1662,7 +1681,7 @@ def stop() -> None:
1662
1681
  "Switch to a valid directory and retry."
1663
1682
  )
1664
1683
  raise typer.Exit(code=1) from None
1665
- ok, message = stop_sandbox(project_root=project_root)
1684
+ ok, message = _sandbox_runtime().stop_sandbox(project_root=project_root)
1666
1685
  if ok:
1667
1686
  console.print(f"[green]{message}[/green]")
1668
1687
  return
@@ -1685,7 +1704,7 @@ def shell(
1685
1704
  if not sys.stdin.isatty():
1686
1705
  console.print("[yellow]Non-interactive terminal; cannot attach shell.[/yellow]")
1687
1706
  raise typer.Exit(code=1)
1688
- ok, message = attach_sandbox_shell(project_root=project_root, shell_path=shell_path)
1707
+ ok, message = _sandbox_runtime().attach_shell(project_root=project_root, shell_path=shell_path)
1689
1708
  if ok:
1690
1709
  return
1691
1710
  console.print(f"[red]Sandbox shell failed:[/red] {message}")
@@ -1797,6 +1816,9 @@ def review(
1797
1816
  model_hint=provider,
1798
1817
  )
1799
1818
  else:
1819
+ from refactor_core.execution.orchestrator import run_with_mode
1820
+ from refactor_core.providers import get_provider
1821
+
1800
1822
  selected_provider = get_provider(
1801
1823
  constitution, project_root=project_root, provider_name=provider
1802
1824
  )
@@ -2013,6 +2035,8 @@ def code(
2013
2035
  )
2014
2036
  selected_provider = None
2015
2037
  if not cloud:
2038
+ from refactor_core.providers import get_provider
2039
+
2016
2040
  selected_provider = get_provider(
2017
2041
  constitution, project_root=project_root, provider_name=provider
2018
2042
  )
@@ -2035,6 +2059,8 @@ def code(
2035
2059
  )
2036
2060
  cloud_review_findings = list(review_artifact.findings or [])
2037
2061
  else:
2062
+ from refactor_core.execution.orchestrator import run_with_mode
2063
+
2038
2064
  with console.status("[cyan]review[/cyan] analyzing...", spinner="dots") as status:
2039
2065
  review_progress = _agent_progress_logger(
2040
2066
  "review", status=status, verbose_steps=True
@@ -2158,6 +2184,8 @@ def code(
2158
2184
  )
2159
2185
  return
2160
2186
 
2187
+ from refactor_core.execution.rr_executor import run_refactor_requests
2188
+
2161
2189
  with console.status("[cyan]code[/cyan] running...", spinner="dots") as status:
2162
2190
  rr_config = (
2163
2191
  dict(getattr(project_config, "settings", {}) or {})
@@ -2234,6 +2262,9 @@ def requests(
2234
2262
  if not deferred_rrs:
2235
2263
  console.print("[dim]No deferred requests to retry.[/dim]")
2236
2264
  else:
2265
+ from refactor_core.execution.rr_executor import run_refactor_requests
2266
+ from refactor_core.providers import get_provider
2267
+
2237
2268
  selected_provider = get_provider(
2238
2269
  constitution, project_root=project_root, provider_name=provider
2239
2270
  )
@@ -3253,6 +3284,16 @@ def doctor(
3253
3284
  )
3254
3285
  return
3255
3286
 
3287
+ # Local-mode doctor uses engine-only provider/execution helpers. These are
3288
+ # lazily imported here so a client-only install (cloud modes) never requires
3289
+ # the engine on disk (R21 core split); local mode has the engine via binary.
3290
+ from refactor_core.execution.modes import resolve_mode
3291
+ from refactor_core.providers import (
3292
+ get_provider,
3293
+ resolve_provider_name,
3294
+ supported_providers,
3295
+ )
3296
+
3256
3297
  mode = str(constitution.get_setting("mode", "local") or "local")
3257
3298
  provider_name = resolve_provider_name(constitution, provider_name=provider)
3258
3299
 
@@ -3398,7 +3439,7 @@ def _report_sandbox(project_root: Path, config) -> None:
3398
3439
  enabled = True
3399
3440
  runtime_pref = str(sandbox_cfg.get("runtime", "podman") or "podman")
3400
3441
  image = str(sandbox_cfg.get("image") or SANDBOX_DEFAULT_IMAGE)
3401
- resolved_runtime, reason = resolve_runtime(runtime_pref)
3442
+ resolved_runtime, reason = _sandbox_runtime().resolve_runtime(runtime_pref)
3402
3443
 
3403
3444
  console.print(f"[bold]project[/bold]: {project_root}")
3404
3445
  console.print(f"[bold]sandbox enabled[/bold]: {enabled} [dim](mandatory for local runs)[/dim]")
@@ -3448,6 +3489,10 @@ def _report_sandbox(project_root: Path, config) -> None:
3448
3489
 
3449
3490
 
3450
3491
  def _report_structural_readiness(project_root: Path, config) -> None:
3492
+ # Engine-only structural ops (local doctor diagnostic); lazy so client-only
3493
+ # installs never require the engine on disk (R21 core split).
3494
+ from refactor_core.execution.structural_ops import structural_compatibility_matrix
3495
+
3451
3496
  settings = dict(getattr(config, "settings", {}) or {})
3452
3497
  refactor_cfg = settings.get("refactor", {})
3453
3498
  if not isinstance(refactor_cfg, dict):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: refactorai-cli
3
- Version: 0.2.30
3
+ Version: 0.3.0
4
4
  Summary: Local-first CLI for the refactor platform
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -8,6 +8,7 @@ Requires-Dist: typer>=0.12.0
8
8
  Requires-Dist: httpx>=0.27.0
9
9
  Requires-Dist: rich>=13.7.0
10
10
  Requires-Dist: PyYAML>=6.0.1
11
+ Requires-Dist: refactorai-core>=3.0.0
11
12
 
12
13
  # refactorai-cli
13
14
 
@@ -53,7 +54,7 @@ python -m twine upload ./refactorai-cli/dist/*
53
54
  ## Install test (local)
54
55
 
55
56
  ```bash
56
- python -m pip install ./refactorai-cli/dist/refactorai_cli-0.2.30-py3-none-any.whl
57
+ python -m pip install ./refactorai-cli/dist/refactorai_cli-0.3.0-py3-none-any.whl
57
58
  refactor --version
58
59
  ```
59
60
 
@@ -2,3 +2,4 @@ typer>=0.12.0
2
2
  httpx>=0.27.0
3
3
  rich>=13.7.0
4
4
  PyYAML>=6.0.1
5
+ refactorai-core>=3.0.0