refactorai-cli 0.7.23__tar.gz → 0.7.25__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 (54) hide show
  1. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/PKG-INFO +1 -1
  2. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/pyproject.toml +1 -1
  3. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/__init__.py +1 -1
  4. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/cloud_rr.py +56 -0
  5. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/commands/run_cmds.py +150 -40
  6. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli.egg-info/PKG-INFO +1 -1
  7. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/README.md +0 -0
  8. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/auth.py +0 -0
  9. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/client.py +0 -0
  10. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/commands/__init__.py +0 -0
  11. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/commands/account_cmds.py +0 -0
  12. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/commands/auth_cmds.py +0 -0
  13. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/commands/branch_cmds.py +0 -0
  14. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/commands/cloud_cmds.py +0 -0
  15. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/commands/engine_cmds.py +0 -0
  16. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/commands/hook_cmds.py +0 -0
  17. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/commands/model_cmds.py +0 -0
  18. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/commands/policy_cmds.py +0 -0
  19. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/commands/pre_push_cmds.py +0 -0
  20. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/commands/request_cmds.py +0 -0
  21. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/commands/rules_cmds.py +0 -0
  22. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/commands/runtime_cmds.py +0 -0
  23. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/commands/runtime_proxy_cmds.py +0 -0
  24. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/commands/setup_cmds.py +0 -0
  25. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/commands/toolchains_cmds.py +0 -0
  26. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/commands/watch_cmds.py +0 -0
  27. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/commands/workspace_cmds.py +0 -0
  28. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/commit_queue.py +0 -0
  29. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/commit_telemetry.py +0 -0
  30. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/control_plane.py +0 -0
  31. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/credentials.py +0 -0
  32. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/dotenv_loader.py +0 -0
  33. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/git_scope.py +0 -0
  34. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/local_constitution.py +0 -0
  35. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/local_engine_runtime.py +0 -0
  36. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/local_paths.py +0 -0
  37. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/main.py +0 -0
  38. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/mode_sync.py +0 -0
  39. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/model_policy.py +0 -0
  40. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/pre_push_gate.py +0 -0
  41. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/refactor_branch_store.py +0 -0
  42. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/review_runner.py +0 -0
  43. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/runtime_manager.py +0 -0
  44. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/settings.py +0 -0
  45. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/setup_flow.py +0 -0
  46. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/watch_ledger.py +0 -0
  47. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/watch_state.py +0 -0
  48. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli/watch_supervisor.py +0 -0
  49. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli.egg-info/SOURCES.txt +0 -0
  50. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli.egg-info/dependency_links.txt +0 -0
  51. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli.egg-info/entry_points.txt +0 -0
  52. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli.egg-info/requires.txt +0 -0
  53. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/refactorai_cli.egg-info/top_level.txt +0 -0
  54. {refactorai_cli-0.7.23 → refactorai_cli-0.7.25}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: refactorai-cli
3
- Version: 0.7.23
3
+ Version: 0.7.25
4
4
  Summary: Local-first CLI for the refactor platform
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "refactorai-cli"
3
- version = "0.7.23"
3
+ version = "0.7.25"
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.7.23"
8
+ __version__ = "0.7.25"
@@ -769,6 +769,62 @@ def _python_restore_commands(project_root: Path, config: dict) -> list[tuple[str
769
769
  return cmds
770
770
 
771
771
 
772
+ def resolve_dependency_commands(
773
+ project_root: Path,
774
+ *,
775
+ config: dict,
776
+ runtimes: tuple[str, ...] | None = None,
777
+ dep_locator_cb: Callable[[Path], list[tuple[str, str]]] | None = None,
778
+ ) -> list[tuple[str, str]]:
779
+ """Ordered ``(label, shell-command)`` dependency-install steps for a project.
780
+
781
+ Single source of truth shared by the managed-host restore
782
+ (:func:`_restore_dependencies`) and the container sandbox preflight, so both
783
+ resolve dependencies identically instead of re-implementing per-ecosystem
784
+ heuristics. Resolution tiers (docs/35):
785
+
786
+ 1. **Escape hatch** -- ``verification.deps_install`` is honored verbatim and
787
+ overrides everything, so nonstandard layouts have a deterministic path.
788
+ 2. **Deterministic detection** -- lockfile-aware node install
789
+ (:func:`_node_install_command`) and the python manifest family
790
+ (:func:`_python_restore_commands`: requirements*, ``requirements/``,
791
+ Poetry/uv/PDM, PEP 621 extras).
792
+ 3. **Validated agentic fallback** -- when python detection finds nothing and
793
+ ``dep_locator_cb`` is supplied (and not disabled via
794
+ ``verification.llm_dep_discovery``), the locator points at *where* deps are
795
+ declared; the callback re-validates every path/kind on disk before
796
+ returning a command (never a fabricated package or raw LLM command).
797
+
798
+ ``runtimes`` scopes detection (e.g. ``("node",)`` for an ``npm`` test
799
+ command); ``None`` considers both node and python.
800
+ """
801
+ configured = _configured_deps_install(config)
802
+ if configured:
803
+ return [(f"deps_install[{i}]", cmd) for i, cmd in enumerate(configured, start=1)]
804
+
805
+ selected = runtimes if runtimes is not None else ("node", "python")
806
+ out: list[tuple[str, str]] = []
807
+ seen: set[str] = set()
808
+
809
+ def _add(label: str, command: str) -> None:
810
+ if command not in seen:
811
+ seen.add(command)
812
+ out.append((label, command))
813
+
814
+ if "node" in selected and (project_root / "package.json").is_file():
815
+ _, node_command = _node_install_command(project_root)
816
+ _add("node", node_command)
817
+
818
+ if "python" in selected:
819
+ steps = _python_restore_commands(project_root, config)
820
+ if not steps and dep_locator_cb is not None and _llm_dep_discovery_enabled(config):
821
+ steps = dep_locator_cb(project_root)
822
+ for label, command in steps:
823
+ _add(label, command)
824
+
825
+ return out
826
+
827
+
772
828
  # --- LLM locator fallback (find WHERE deps are declared; never WHAT) --------- #
773
829
  # The model only points at existing files/dirs + a kind label; deterministic code
774
830
  # maps kind -> install command and re-verifies the path on disk. The model can
@@ -931,9 +931,15 @@ def _cloud_inference(
931
931
  variant = _execution_variant(constitution)
932
932
  execution_mode = platform_inference_mode(variant) or "cloud_managed"
933
933
  auth_ctx = ensure_authenticated(project_root)
934
- model_hint_value = model_hint or str(
935
- constitution.get_setting("model_id", "managed-default") or "managed-default"
936
- )
934
+ # Managed modes are platform-selected: never derive a model hint from local
935
+ # config (the server picks the provider/model from the admin managed-inference
936
+ # config and ignores any client hint). Only BYOK reads a local model_id.
937
+ if execution_mode == "cloud_managed":
938
+ model_hint_value = model_hint or "managed-default"
939
+ else:
940
+ model_hint_value = model_hint or str(
941
+ constitution.get_setting("model_id", "managed-default") or "managed-default"
942
+ )
937
943
 
938
944
  # Split the indexed documents into context-safe batches so a large first
939
945
  # review is never sent as one oversized request that blows the read timeout.
@@ -1770,48 +1776,95 @@ def _command_binary(command: str) -> str | None:
1770
1776
  return tokens[0] if tokens else None
1771
1777
 
1772
1778
 
1773
- def _install_plan_for_missing_binary(
1774
- *, project_root: Path, binary: str, installer: str | None
1775
- ) -> list[str]:
1776
- """Return a conservative install plan for missing toolchain commands."""
1779
+ def _binary_runtimes(binary: str) -> tuple[str, ...]:
1780
+ """Map a test-command binary to the language runtime(s) whose dependencies it
1781
+ needs, so dependency resolution is scoped to the relevant ecosystem."""
1782
+ b = (binary or "").strip().lower()
1783
+ if b in {"npm", "node", "npx", "yarn", "pnpm", "corepack"}:
1784
+ return ("node",)
1785
+ if b in {"python", "python3", "pip", "pip3", "pytest"}:
1786
+ return ("python",)
1787
+ return ()
1788
+
1789
+
1790
+ def _toolchain_pkg_command(*, binary: str, installer: str | None) -> str:
1791
+ """Finite, bounded language-runtime provisioning for the sandbox image.
1792
+
1793
+ This is the one place that legitimately enumerates (a small, closed set of
1794
+ language runtimes) -- installing the interpreter/toolchain the test command
1795
+ needs. Dependency *resolution* is NOT done here; it is delegated to the shared
1796
+ ``cloud_rr`` resolver so no per-project dependency logic is hardcoded.
1797
+ """
1777
1798
  if not installer:
1778
- return []
1779
- pkg_cmd = ""
1799
+ return ""
1800
+ is_node = binary in {"npm", "node", "npx", "yarn", "pnpm"}
1801
+ is_python = binary in {"python", "python3", "pip", "pip3", "pytest"}
1780
1802
  if installer == "apk":
1781
- if binary in {"npm", "node"}:
1782
- pkg_cmd = "apk add --no-cache nodejs npm"
1783
- elif binary in {"python", "python3", "pip", "pip3", "pytest"}:
1784
- pkg_cmd = "apk add --no-cache python3 py3-pip"
1803
+ if is_node:
1804
+ return "apk add --no-cache nodejs npm"
1805
+ if is_python:
1806
+ return "apk add --no-cache python3 py3-pip"
1785
1807
  elif installer == "apt-get":
1786
- if binary in {"npm", "node"}:
1787
- pkg_cmd = "apt-get update && apt-get install -y nodejs npm"
1788
- elif binary in {"python", "python3", "pip", "pip3", "pytest"}:
1789
- pkg_cmd = "apt-get update && apt-get install -y python3 python3-pip"
1808
+ if is_node:
1809
+ return "apt-get update && apt-get install -y nodejs npm"
1810
+ if is_python:
1811
+ return "apt-get update && apt-get install -y python3 python3-pip"
1790
1812
  elif installer in {"dnf", "yum"}:
1791
- if binary in {"npm", "node"}:
1792
- pkg_cmd = f"{installer} install -y nodejs npm"
1793
- elif binary in {"python", "python3", "pip", "pip3", "pytest"}:
1794
- pkg_cmd = f"{installer} install -y python3 python3-pip"
1813
+ if is_node:
1814
+ return f"{installer} install -y nodejs npm"
1815
+ if is_python:
1816
+ return f"{installer} install -y python3 python3-pip"
1817
+ return ""
1818
+
1819
+
1820
+ def _install_plan_for_missing_binary(
1821
+ *,
1822
+ project_root: Path,
1823
+ binary: str,
1824
+ installer: str | None,
1825
+ config: dict | None = None,
1826
+ dep_locator_cb: Callable[[Path], list[tuple[str, str]]] | None = None,
1827
+ ) -> list[str]:
1828
+ """Install plan for a missing test-command binary: provision the language
1829
+ runtime, then restore dependencies via the shared resolver.
1830
+
1831
+ Two clearly separated concerns:
1832
+
1833
+ * **Toolchain provisioning** (:func:`_toolchain_pkg_command`) -- a small,
1834
+ finite map of language -> package-manager install for the container image.
1835
+ * **Dependency restore** (:func:`cloud_rr.resolve_dependency_commands`) -- the
1836
+ SAME resolver the cloud/managed-host path uses, so the sandbox honors the
1837
+ ``verification.deps_install`` escape hatch, lockfile-aware node installs,
1838
+ the full python manifest family (requirements*/Poetry/uv/PDM/PEP 621
1839
+ extras), and the validated agentic fallback. Previously this path hardcoded
1840
+ ``npm install`` / ``pip install -r requirements.txt``, which both rewrote
1841
+ committed lockfiles and failed to scale to other ecosystems.
1842
+ """
1843
+ if not installer:
1844
+ return []
1845
+ from refactorai_cli.cloud_rr import resolve_dependency_commands
1846
+
1795
1847
  plan: list[str] = []
1848
+ pkg_cmd = _toolchain_pkg_command(binary=binary, installer=installer)
1796
1849
  if pkg_cmd:
1797
1850
  plan.append(pkg_cmd)
1798
- # Dependency restore after toolchain install. Use the SAME lockfile-aware
1799
- # installer as the cloud/managed path (single source of truth in
1800
- # ``cloud_rr._node_install_command``) so sandbox preflight never rewrites a
1801
- # committed lockfile: ``npm ci`` / ``yarn install --immutable`` /
1802
- # ``pnpm install --frozen-lockfile`` when a lockfile is present, falling back
1803
- # to ``npm install`` only for a lockfile-less project. Historically this path
1804
- # hardcoded ``npm install``, which regenerated ``package-lock.json`` /
1805
- # ``yarn.lock`` in the mounted tree and left the working tree dirty (blocking
1806
- # the refactor-branch flow); unifying on the lockfile-aware command removes
1807
- # that divergence at the source.
1808
- if (project_root / "package.json").is_file():
1809
- from refactorai_cli.cloud_rr import _node_install_command
1810
1851
 
1811
- _, node_install_cmd = _node_install_command(project_root)
1812
- plan.append(node_install_cmd)
1813
- elif (project_root / "requirements.txt").is_file():
1814
- plan.append("pip install -r requirements.txt")
1852
+ dep_commands = [
1853
+ cmd
1854
+ for _label, cmd in resolve_dependency_commands(
1855
+ project_root,
1856
+ config=config or {},
1857
+ runtimes=_binary_runtimes(binary),
1858
+ dep_locator_cb=dep_locator_cb,
1859
+ )
1860
+ ]
1861
+ # yarn/pnpm run through Corepack (the modern, version-pinned launcher). Minimal
1862
+ # base images ship Node + npm but omit the corepack shim, so provision it on
1863
+ # demand before any corepack command -- else the step dies with
1864
+ # ``sh: corepack: not found``. Idempotent: skipped when already on PATH.
1865
+ if any(cmd.startswith("corepack") for cmd in dep_commands):
1866
+ plan.append("command -v corepack >/dev/null 2>&1 || npm install -g corepack")
1867
+ plan.extend(dep_commands)
1815
1868
  return plan
1816
1869
 
1817
1870
 
@@ -2017,8 +2070,14 @@ def _sandbox_preflight(
2017
2070
  runtime: str | None = None,
2018
2071
  container_name: str | None = None,
2019
2072
  workdir: str | None = None,
2073
+ dep_locator_cb: Callable[[Path], list[tuple[str, str]]] | None = None,
2020
2074
  ) -> tuple[bool, str]:
2021
- """Run sandbox preflight and optionally perform approved install plan."""
2075
+ """Run sandbox preflight and optionally perform approved install plan.
2076
+
2077
+ ``dep_locator_cb`` is the optional validated agentic dependency-file locator
2078
+ (see :func:`cloud_rr.resolve_dependency_commands`); when omitted, dependency
2079
+ resolution uses the escape hatch + deterministic detection only.
2080
+ """
2022
2081
  _sr = _sandbox_runtime()
2023
2082
  command_exists_in_container = _sr.command_exists_in_container
2024
2083
  command_exists_in_sandbox = _sr.command_exists_in_sandbox
@@ -2121,7 +2180,11 @@ def _sandbox_preflight(
2121
2180
  if missing_binary:
2122
2181
  plan.extend(
2123
2182
  _install_plan_for_missing_binary(
2124
- project_root=project_root, binary=missing_binary, installer=installer
2183
+ project_root=project_root,
2184
+ binary=missing_binary,
2185
+ installer=installer,
2186
+ config=config_settings,
2187
+ dep_locator_cb=dep_locator_cb,
2125
2188
  )
2126
2189
  )
2127
2190
  lsp_plan, unsupported_lsp = _install_plan_for_missing_lsp(
@@ -2317,6 +2380,44 @@ def _sandbox_lifecycle(project_config) -> str:
2317
2380
  return lifecycle if lifecycle in {"per_project", "per_run"} else "per_project"
2318
2381
 
2319
2382
 
2383
+ def _build_sandbox_dep_locator(
2384
+ project_root: Path, constitution, provider: str | None
2385
+ ) -> Callable[[Path], list[tuple[str, str]]] | None:
2386
+ """Best-effort validated agentic dependency-file locator for sandbox preflight.
2387
+
2388
+ Returns a ``callback(root) -> [(label, command)]`` that asks the platform
2389
+ *where* dependencies are declared (nonstandard layouts), re-validating every
2390
+ path/kind on disk before use -- the same locator the cloud RR loop uses
2391
+ (docs/35). Returns ``None`` when a locator cannot be built (e.g. auth/context
2392
+ unavailable), in which case preflight silently uses the escape hatch +
2393
+ deterministic detection only. Never raises.
2394
+ """
2395
+ try:
2396
+ from refactorai_cli.cloud_rr import _located_restore_commands
2397
+
2398
+ variant = _execution_variant(constitution)
2399
+ execution_mode = platform_inference_mode(variant) or variant or "cloud_managed"
2400
+ auth_ctx = ensure_authenticated(project_root)
2401
+ model_hint = provider or str(constitution.get_setting("model_id", "") or "") or None
2402
+
2403
+ def _locator(root: Path) -> list[tuple[str, str]]:
2404
+ try:
2405
+ return _located_restore_commands(
2406
+ root,
2407
+ constitution=constitution,
2408
+ execution_mode=execution_mode,
2409
+ auth_ctx=auth_ctx,
2410
+ model_hint=model_hint,
2411
+ apply_byok_payload=_apply_byok_payload,
2412
+ )
2413
+ except Exception:
2414
+ return []
2415
+
2416
+ return _locator
2417
+ except Exception:
2418
+ return None
2419
+
2420
+
2320
2421
  def _ensure_sandbox_ready(
2321
2422
  *,
2322
2423
  project_root: Path,
@@ -2325,8 +2426,13 @@ def _ensure_sandbox_ready(
2325
2426
  auto_approve_install: bool = False,
2326
2427
  no_install: bool = False,
2327
2428
  continue_on_preflight_failure: bool = False,
2429
+ dep_locator_cb: Callable[[Path], list[tuple[str, str]]] | None = None,
2328
2430
  ) -> dict | None:
2329
- """Ensure sandbox lifecycle + preflight for stage execution."""
2431
+ """Ensure sandbox lifecycle + preflight for stage execution.
2432
+
2433
+ ``dep_locator_cb`` is forwarded to preflight as the validated agentic
2434
+ dependency-file locator (best-effort; ``None`` disables that fallback tier).
2435
+ """
2330
2436
  _sr = _sandbox_runtime()
2331
2437
  resolve_runtime = _sr.resolve_runtime
2332
2438
  sandbox_name = _sr.sandbox_name
@@ -2379,6 +2485,7 @@ def _ensure_sandbox_ready(
2379
2485
  runtime=resolved_runtime,
2380
2486
  container_name=str(state.get("container_name", "") or ""),
2381
2487
  workdir=str(state.get("workdir") or workdir),
2488
+ dep_locator_cb=dep_locator_cb,
2382
2489
  )
2383
2490
  if not preflight_ok:
2384
2491
  if continue_on_preflight_failure:
@@ -3728,6 +3835,9 @@ def code(
3728
3835
  stage="code",
3729
3836
  auto_approve_install=auto_approve,
3730
3837
  no_install=False,
3838
+ dep_locator_cb=_build_sandbox_dep_locator(
3839
+ project_root, constitution, provider
3840
+ ),
3731
3841
  )
3732
3842
  else:
3733
3843
  variant = _execution_variant(constitution)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: refactorai-cli
3
- Version: 0.7.23
3
+ Version: 0.7.25
4
4
  Summary: Local-first CLI for the refactor platform
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown