refactorai-cli 0.2.14__tar.gz → 0.2.16__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.
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/PKG-INFO +1 -1
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/pyproject.toml +1 -1
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/__init__.py +1 -1
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/commands/run_cmds.py +256 -23
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/commands/runtime_cmds.py +18 -1
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/runtime_manager.py +38 -5
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli.egg-info/PKG-INFO +1 -1
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/README.md +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/auth.py +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/client.py +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/commands/__init__.py +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/commands/auth_cmds.py +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/commands/engine_cmds.py +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/commands/model_cmds.py +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/commands/rules_cmds.py +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/commands/runtime_proxy_cmds.py +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/commands/setup_cmds.py +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/control_plane.py +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/credentials.py +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/local_constitution.py +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/local_engine_runtime.py +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/local_paths.py +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/main.py +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/model_policy.py +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/settings.py +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/setup_flow.py +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli.egg-info/SOURCES.txt +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli.egg-info/dependency_links.txt +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli.egg-info/entry_points.txt +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli.egg-info/requires.txt +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli.egg-info/top_level.txt +0 -0
- {refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/setup.cfg +0 -0
|
@@ -46,13 +46,20 @@ from refactor_core.budgeting import compute_budget
|
|
|
46
46
|
from refactor_core.capabilities import resolve_capabilities
|
|
47
47
|
from refactor_core.execution import resolve_mode, run_with_mode
|
|
48
48
|
from refactor_core.execution.rr_executor import run_refactor_requests
|
|
49
|
+
from refactor_core.execution.structural_ops import structural_compatibility_matrix
|
|
49
50
|
from refactor_core.gate import evaluate_gate
|
|
50
51
|
from refactor_core.refactor_requests import (
|
|
52
|
+
DEFERRED,
|
|
53
|
+
RequestSuppression,
|
|
54
|
+
RequestWarning,
|
|
51
55
|
clear_requests,
|
|
52
56
|
create_requests,
|
|
53
57
|
list_requests,
|
|
58
|
+
load_request,
|
|
54
59
|
pending_requests,
|
|
60
|
+
save_request,
|
|
55
61
|
)
|
|
62
|
+
from refactor_core.refactor_ops import remediation_hint
|
|
56
63
|
from refactor_core.indexing import index_target
|
|
57
64
|
from refactor_core.models import Finding, GeneratedTest, PatchGroup, RunArtifact
|
|
58
65
|
from refactor_core.pipeline import build_refactor_prompt, build_review_prompt
|
|
@@ -486,6 +493,20 @@ def _rr_progress_logger(status=None) -> Callable[[dict], None]:
|
|
|
486
493
|
elif ev == "run_done":
|
|
487
494
|
if status:
|
|
488
495
|
status.update("[green]code[/green] completed.")
|
|
496
|
+
elif ev == "rr_deferred":
|
|
497
|
+
if status:
|
|
498
|
+
status.update("[yellow]code[/yellow] deferred unsupported operation...")
|
|
499
|
+
reason = str(event.get("reason", "") or "")[:300]
|
|
500
|
+
hint = remediation_hint(reason)
|
|
501
|
+
suffix = f" [dim]hint: {hint}[/dim]" if hint else ""
|
|
502
|
+
console.print(f"[yellow] ↷ deferred:[/yellow] {reason}{suffix}")
|
|
503
|
+
elif ev == "rr_failed":
|
|
504
|
+
if status:
|
|
505
|
+
status.update("[red]code[/red] failed unsupported operation.")
|
|
506
|
+
reason = str(event.get("reason", "") or "")[:300]
|
|
507
|
+
hint = remediation_hint(reason)
|
|
508
|
+
suffix = f" [dim]hint: {hint}[/dim]" if hint else ""
|
|
509
|
+
console.print(f"[red] ✗ failed:[/red] {reason}{suffix}")
|
|
489
510
|
|
|
490
511
|
return _log
|
|
491
512
|
|
|
@@ -1536,9 +1557,13 @@ def review(
|
|
|
1536
1557
|
_print_findings(artifact.findings)
|
|
1537
1558
|
|
|
1538
1559
|
# A fresh review supersedes prior refactor requests: replace them with one
|
|
1539
|
-
# RR per finding (central-only; nothing is written into
|
|
1540
|
-
|
|
1541
|
-
|
|
1560
|
+
# RR per actionable finding (central-only; nothing is written into project tree).
|
|
1561
|
+
requests = _replace_requests_with_framework_guardrails(
|
|
1562
|
+
project_root=project_root,
|
|
1563
|
+
findings=artifact.findings,
|
|
1564
|
+
run_id=artifact.run_id,
|
|
1565
|
+
artifact=artifact,
|
|
1566
|
+
)
|
|
1542
1567
|
if requests:
|
|
1543
1568
|
console.print(
|
|
1544
1569
|
f"\n[bold]Created {len(requests)} refactor request(s).[/bold] "
|
|
@@ -1573,6 +1598,16 @@ def code(
|
|
|
1573
1598
|
"--auto-approve",
|
|
1574
1599
|
help="Skip interactive issue approvals in agentic code mode.",
|
|
1575
1600
|
),
|
|
1601
|
+
on_rr_failure: str = typer.Option(
|
|
1602
|
+
"stop",
|
|
1603
|
+
"--on-rr-failure",
|
|
1604
|
+
help="RR failure behavior: stop | continue | defer.",
|
|
1605
|
+
),
|
|
1606
|
+
equivalence: str = typer.Option(
|
|
1607
|
+
"strict",
|
|
1608
|
+
"--equivalence",
|
|
1609
|
+
help="Equivalence policy: strict | balanced.",
|
|
1610
|
+
),
|
|
1576
1611
|
) -> None:
|
|
1577
1612
|
"""Work through refactor requests one by one, applying & verifying each.
|
|
1578
1613
|
|
|
@@ -1637,9 +1672,11 @@ def code(
|
|
|
1637
1672
|
review_store = create_run(project_root, run_id=review_artifact.run_id)
|
|
1638
1673
|
review_store.write_artifact(review_artifact, target=target, status="completed")
|
|
1639
1674
|
_print_findings(review_artifact.findings)
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1675
|
+
requests = _replace_requests_with_framework_guardrails(
|
|
1676
|
+
project_root=project_root,
|
|
1677
|
+
findings=review_artifact.findings,
|
|
1678
|
+
run_id=review_artifact.run_id,
|
|
1679
|
+
artifact=review_artifact,
|
|
1643
1680
|
)
|
|
1644
1681
|
console.print(f"[bold]Created {len(requests)} refactor request(s).[/bold]")
|
|
1645
1682
|
|
|
@@ -1656,19 +1693,21 @@ def code(
|
|
|
1656
1693
|
return
|
|
1657
1694
|
|
|
1658
1695
|
with console.status("[cyan]code[/cyan] running...", spinner="dots") as status:
|
|
1696
|
+
rr_config = (
|
|
1697
|
+
dict(getattr(project_config, "settings", {}) or {})
|
|
1698
|
+
| ({"sandbox": {"enabled": True}} if sandbox_on else {})
|
|
1699
|
+
| ({"_sandbox_context": sandbox_ctx} if sandbox_ctx else {})
|
|
1700
|
+
) or dict(getattr(constitution, "settings", {}) or {})
|
|
1659
1701
|
artifact = run_refactor_requests(
|
|
1660
1702
|
project_root=project_root,
|
|
1661
1703
|
constitution=constitution,
|
|
1662
1704
|
provider=selected_provider,
|
|
1663
1705
|
requests=requests,
|
|
1664
|
-
config=
|
|
1665
|
-
dict(getattr(project_config, "settings", {}) or {})
|
|
1666
|
-
| ({"sandbox": {"enabled": True}} if sandbox_on else {})
|
|
1667
|
-
| ({"_sandbox_context": sandbox_ctx} if sandbox_ctx else {})
|
|
1668
|
-
)
|
|
1669
|
-
or dict(getattr(constitution, "settings", {}) or {}),
|
|
1706
|
+
config=rr_config,
|
|
1670
1707
|
progress_cb=_rr_progress_logger(status=status),
|
|
1671
1708
|
approval_cb=_rr_approval_prompt(auto_approve=auto_approve),
|
|
1709
|
+
on_rr_failure=on_rr_failure,
|
|
1710
|
+
equivalence_mode=equivalence,
|
|
1672
1711
|
)
|
|
1673
1712
|
except Exception as exc:
|
|
1674
1713
|
console.print(f"[red]Refactor failed:[/red] {exc}")
|
|
@@ -1686,32 +1725,190 @@ def code(
|
|
|
1686
1725
|
)
|
|
1687
1726
|
|
|
1688
1727
|
|
|
1689
|
-
def requests(
|
|
1690
|
-
|
|
1728
|
+
def requests(
|
|
1729
|
+
show_operation: bool = typer.Option(
|
|
1730
|
+
False,
|
|
1731
|
+
"--show-operation",
|
|
1732
|
+
help="Show operation scope details (source/target/split map).",
|
|
1733
|
+
),
|
|
1734
|
+
retry_deferred: bool = typer.Option(
|
|
1735
|
+
False,
|
|
1736
|
+
"--retry-deferred",
|
|
1737
|
+
help="Re-run deferred requests immediately.",
|
|
1738
|
+
),
|
|
1739
|
+
provider: str | None = typer.Option(
|
|
1740
|
+
None,
|
|
1741
|
+
"--provider",
|
|
1742
|
+
help="Provider override when --retry-deferred is used.",
|
|
1743
|
+
),
|
|
1744
|
+
auto_approve: bool = typer.Option(
|
|
1745
|
+
False,
|
|
1746
|
+
"--auto-approve",
|
|
1747
|
+
help="Auto-approve retry-deferred proposals.",
|
|
1748
|
+
),
|
|
1749
|
+
on_rr_failure: str = typer.Option(
|
|
1750
|
+
"stop",
|
|
1751
|
+
"--on-rr-failure",
|
|
1752
|
+
help="RR failure behavior for retry: stop | continue | defer.",
|
|
1753
|
+
),
|
|
1754
|
+
equivalence: str = typer.Option(
|
|
1755
|
+
"strict",
|
|
1756
|
+
"--equivalence",
|
|
1757
|
+
help="Equivalence policy for retry: strict | balanced.",
|
|
1758
|
+
),
|
|
1759
|
+
) -> None:
|
|
1760
|
+
"""List refactor requests and optionally re-run deferred requests."""
|
|
1691
1761
|
_require_auth()
|
|
1692
|
-
project_root,
|
|
1762
|
+
project_root, constitution, project_config = _load_project()
|
|
1763
|
+
if retry_deferred:
|
|
1764
|
+
deferred_rrs = [rr for rr in list_requests(project_root) if rr.status == DEFERRED]
|
|
1765
|
+
if not deferred_rrs:
|
|
1766
|
+
console.print("[dim]No deferred requests to retry.[/dim]")
|
|
1767
|
+
else:
|
|
1768
|
+
selected_provider = get_provider(
|
|
1769
|
+
constitution, project_root=project_root, provider_name=provider
|
|
1770
|
+
)
|
|
1771
|
+
for rr in deferred_rrs:
|
|
1772
|
+
rr.status = "pending"
|
|
1773
|
+
loaded = load_request(project_root, rr.rr_id)
|
|
1774
|
+
if loaded is not None:
|
|
1775
|
+
loaded.status = "pending"
|
|
1776
|
+
save_request(project_root, loaded)
|
|
1777
|
+
with console.status("[cyan]requests[/cyan] retrying deferred...", spinner="dots") as status:
|
|
1778
|
+
_ = run_refactor_requests(
|
|
1779
|
+
project_root=project_root,
|
|
1780
|
+
constitution=constitution,
|
|
1781
|
+
provider=selected_provider,
|
|
1782
|
+
requests=[rr for rr in list_requests(project_root) if rr.status == "pending"],
|
|
1783
|
+
config=dict(getattr(project_config, "settings", {}) or {}),
|
|
1784
|
+
progress_cb=_rr_progress_logger(status=status),
|
|
1785
|
+
approval_cb=_rr_approval_prompt(auto_approve=auto_approve),
|
|
1786
|
+
on_rr_failure=on_rr_failure,
|
|
1787
|
+
equivalence_mode=equivalence,
|
|
1788
|
+
)
|
|
1693
1789
|
rrs = list_requests(project_root)
|
|
1694
1790
|
if not rrs:
|
|
1695
1791
|
console.print("[dim]No refactor requests. Run `refactor review` to create them.[/dim]")
|
|
1696
1792
|
return
|
|
1697
1793
|
table = Table(title="Refactor requests", show_lines=False)
|
|
1698
1794
|
table.add_column("issue")
|
|
1795
|
+
table.add_column("operation", no_wrap=True)
|
|
1796
|
+
if show_operation:
|
|
1797
|
+
table.add_column("scope")
|
|
1699
1798
|
table.add_column("severity", no_wrap=True)
|
|
1700
1799
|
table.add_column("category")
|
|
1701
1800
|
table.add_column("status", no_wrap=True)
|
|
1702
1801
|
table.add_column("attempts", no_wrap=True)
|
|
1703
|
-
color = {
|
|
1802
|
+
color = {
|
|
1803
|
+
"applied": "green",
|
|
1804
|
+
"denied": "yellow",
|
|
1805
|
+
"failed": "red",
|
|
1806
|
+
"deferred": "yellow",
|
|
1807
|
+
"pending": "cyan",
|
|
1808
|
+
"in_progress": "cyan",
|
|
1809
|
+
}
|
|
1704
1810
|
for rr in rrs:
|
|
1705
|
-
|
|
1811
|
+
row = [
|
|
1706
1812
|
rr.location,
|
|
1707
|
-
rr.
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1813
|
+
rr.operation_type,
|
|
1814
|
+
]
|
|
1815
|
+
if show_operation:
|
|
1816
|
+
row.append(_format_operation_scope(rr))
|
|
1817
|
+
row.extend(
|
|
1818
|
+
[
|
|
1819
|
+
rr.severity,
|
|
1820
|
+
rr.category,
|
|
1821
|
+
f"[{color.get(rr.status, 'white')}]{rr.status}[/{color.get(rr.status, 'white')}]",
|
|
1822
|
+
str(rr.attempt_count),
|
|
1823
|
+
]
|
|
1711
1824
|
)
|
|
1825
|
+
table.add_row(*row)
|
|
1712
1826
|
console.print(table)
|
|
1713
1827
|
|
|
1714
1828
|
|
|
1829
|
+
def _format_operation_scope(rr) -> str:
|
|
1830
|
+
scope = getattr(rr, "scope", None)
|
|
1831
|
+
if scope is None:
|
|
1832
|
+
return "-"
|
|
1833
|
+
source = str(getattr(scope, "source_path", "") or "").strip()
|
|
1834
|
+
target = str(getattr(scope, "target_path", "") or "").strip()
|
|
1835
|
+
split_map = dict(getattr(scope, "split_map", {}) or {})
|
|
1836
|
+
symbol = str(getattr(scope, "symbol", "") or "").strip()
|
|
1837
|
+
new_name = str(getattr(scope, "new_name", "") or "").strip()
|
|
1838
|
+
if split_map:
|
|
1839
|
+
if "__sources__" in split_map:
|
|
1840
|
+
srcs = ", ".join(str(item) for item in split_map.get("__sources__", []))
|
|
1841
|
+
return f"merge: [{srcs}] -> {target or '?'}"
|
|
1842
|
+
chunks = []
|
|
1843
|
+
for dst, symbols in split_map.items():
|
|
1844
|
+
if symbols:
|
|
1845
|
+
chunks.append(f"{dst}({','.join(str(s) for s in symbols)})")
|
|
1846
|
+
else:
|
|
1847
|
+
chunks.append(str(dst))
|
|
1848
|
+
src_label = source or "?"
|
|
1849
|
+
return f"split: {src_label} -> {', '.join(chunks)}"
|
|
1850
|
+
if source or target:
|
|
1851
|
+
if source and target:
|
|
1852
|
+
return f"{source} -> {target}"
|
|
1853
|
+
return source or target
|
|
1854
|
+
if symbol and new_name:
|
|
1855
|
+
return f"{symbol} -> {new_name}"
|
|
1856
|
+
return "-"
|
|
1857
|
+
|
|
1858
|
+
|
|
1859
|
+
def _replace_requests_with_framework_guardrails(
|
|
1860
|
+
*,
|
|
1861
|
+
project_root: Path,
|
|
1862
|
+
findings: list[Finding],
|
|
1863
|
+
run_id: str,
|
|
1864
|
+
artifact: RunArtifact | None = None,
|
|
1865
|
+
) -> list:
|
|
1866
|
+
clear_requests(project_root)
|
|
1867
|
+
requests, suppressions, warnings = create_requests(
|
|
1868
|
+
project_root,
|
|
1869
|
+
findings,
|
|
1870
|
+
run_id=run_id,
|
|
1871
|
+
return_diagnostics=True,
|
|
1872
|
+
)
|
|
1873
|
+
_report_framework_suppressions(suppressions, artifact=artifact)
|
|
1874
|
+
_report_framework_warnings(warnings, artifact=artifact)
|
|
1875
|
+
return requests
|
|
1876
|
+
|
|
1877
|
+
|
|
1878
|
+
def _report_framework_suppressions(
|
|
1879
|
+
suppressions: list[RequestSuppression], *, artifact: RunArtifact | None = None
|
|
1880
|
+
) -> None:
|
|
1881
|
+
if not suppressions:
|
|
1882
|
+
return
|
|
1883
|
+
console.print(
|
|
1884
|
+
f"[yellow]warning:[/yellow] suppressed {len(suppressions)} finding(s) due to framework invariants."
|
|
1885
|
+
)
|
|
1886
|
+
for item in suppressions:
|
|
1887
|
+
console.print(
|
|
1888
|
+
f"[yellow]-[/yellow] {item.location}: {item.message} "
|
|
1889
|
+
f"[dim](framework={item.framework or 'unknown'}, rule={item.rule_id or 'unspecified'})[/dim]"
|
|
1890
|
+
)
|
|
1891
|
+
if artifact is not None:
|
|
1892
|
+
artifact.notes.append(item.note())
|
|
1893
|
+
|
|
1894
|
+
|
|
1895
|
+
def _report_framework_warnings(
|
|
1896
|
+
warnings: list[RequestWarning], *, artifact: RunArtifact | None = None
|
|
1897
|
+
) -> None:
|
|
1898
|
+
if not warnings:
|
|
1899
|
+
return
|
|
1900
|
+
console.print(
|
|
1901
|
+
f"[yellow]warning:[/yellow] flagged {len(warnings)} finding(s) with framework caution."
|
|
1902
|
+
)
|
|
1903
|
+
for item in warnings:
|
|
1904
|
+
console.print(
|
|
1905
|
+
f"[yellow]-[/yellow] {item.location}: {item.message} "
|
|
1906
|
+
f"[dim](framework={item.framework or 'unknown'}, rule={item.rule_id or 'unspecified'})[/dim]"
|
|
1907
|
+
)
|
|
1908
|
+
if artifact is not None:
|
|
1909
|
+
artifact.notes.append(item.note())
|
|
1910
|
+
|
|
1911
|
+
|
|
1715
1912
|
def apply(
|
|
1716
1913
|
force: bool = typer.Option(False, "--force", help="Apply even if the quality gate blocks."),
|
|
1717
1914
|
) -> None:
|
|
@@ -2113,6 +2310,7 @@ def doctor(
|
|
|
2113
2310
|
)
|
|
2114
2311
|
|
|
2115
2312
|
_report_intelligence(project_root)
|
|
2313
|
+
_report_structural_readiness(project_root, project_config)
|
|
2116
2314
|
|
|
2117
2315
|
if skip_ping:
|
|
2118
2316
|
console.print("[dim]Skipping provider live ping (--skip-ping).[/dim]")
|
|
@@ -2246,6 +2444,39 @@ def _report_sandbox(project_root: Path, config) -> None:
|
|
|
2246
2444
|
console.print(f" [dim]latest command results: {len(latest.get('results', []))} (failures={failures})[/dim]")
|
|
2247
2445
|
|
|
2248
2446
|
|
|
2447
|
+
def _report_structural_readiness(project_root: Path, config) -> None:
|
|
2448
|
+
settings = dict(getattr(config, "settings", {}) or {})
|
|
2449
|
+
refactor_cfg = settings.get("refactor", {})
|
|
2450
|
+
if not isinstance(refactor_cfg, dict):
|
|
2451
|
+
refactor_cfg = {}
|
|
2452
|
+
structural = refactor_cfg.get("structural", {})
|
|
2453
|
+
if not isinstance(structural, dict):
|
|
2454
|
+
structural = {}
|
|
2455
|
+
eq_mode = str(structural.get("equivalence_mode", "strict") or "strict")
|
|
2456
|
+
rr_policy = str(structural.get("on_rr_failure", "stop") or "stop")
|
|
2457
|
+
rewrite_mode = str(structural.get("reference_rewrite", "auto") or "auto")
|
|
2458
|
+
langs = structural.get("languages", [])
|
|
2459
|
+
rollout = str(structural.get("rollout", "default") or "default")
|
|
2460
|
+
canary_percent = int(structural.get("canary_percent", 20) or 20)
|
|
2461
|
+
if not isinstance(langs, list):
|
|
2462
|
+
langs = []
|
|
2463
|
+
console.print(
|
|
2464
|
+
f"[bold]structural mode[/bold]: equivalence={eq_mode} on_rr_failure={rr_policy} "
|
|
2465
|
+
f"rollout={rollout} canary_percent={canary_percent}"
|
|
2466
|
+
)
|
|
2467
|
+
console.print(f"[bold]reference rewrite[/bold]: {rewrite_mode} [{', '.join(str(x) for x in langs) or 'defaults'}]")
|
|
2468
|
+
matrix = structural_compatibility_matrix()
|
|
2469
|
+
enabled_langs = [name for name, ok in matrix.items() if ok]
|
|
2470
|
+
disabled_langs = [name for name, ok in matrix.items() if not ok]
|
|
2471
|
+
console.print(
|
|
2472
|
+
f"[bold]adapter matrix[/bold]: enabled={', '.join(enabled_langs) or '-'}; "
|
|
2473
|
+
f"degraded={', '.join(disabled_langs) or '-'}"
|
|
2474
|
+
)
|
|
2475
|
+
rrs = list_requests(project_root)
|
|
2476
|
+
deferred = sum(1 for rr in rrs if rr.status == DEFERRED)
|
|
2477
|
+
console.print(f"[bold]deferred requests[/bold]: {deferred}")
|
|
2478
|
+
|
|
2479
|
+
|
|
2249
2480
|
def _maybe_build_graph(project_root: Path, config) -> None:
|
|
2250
2481
|
"""Build + persist the symbol graph when intelligence.graph is enabled."""
|
|
2251
2482
|
settings = dict(getattr(config, "settings", {}) or {})
|
|
@@ -2275,20 +2506,22 @@ def _print_rr_summary(artifact) -> None:
|
|
|
2275
2506
|
return
|
|
2276
2507
|
table = Table(title="Refactor request outcomes", show_lines=False)
|
|
2277
2508
|
table.add_column("issue")
|
|
2509
|
+
table.add_column("operation", no_wrap=True)
|
|
2278
2510
|
table.add_column("outcome", no_wrap=True)
|
|
2279
2511
|
table.add_column("attempts", no_wrap=True)
|
|
2280
|
-
color = {"applied": "green", "denied": "yellow", "failed": "red"}
|
|
2512
|
+
color = {"applied": "green", "denied": "yellow", "failed": "red", "deferred": "yellow"}
|
|
2281
2513
|
for o in outcomes:
|
|
2282
2514
|
outcome = str(o.get("outcome", "?"))
|
|
2283
2515
|
table.add_row(
|
|
2284
2516
|
str(o.get("location", "?")),
|
|
2517
|
+
str(o.get("operation_type", "content_patch")),
|
|
2285
2518
|
f"[{color.get(outcome, 'white')}]{outcome}[/{color.get(outcome, 'white')}]",
|
|
2286
2519
|
str(o.get("attempts", 0)),
|
|
2287
2520
|
)
|
|
2288
2521
|
console.print(table)
|
|
2289
2522
|
console.print(
|
|
2290
2523
|
f"[dim]applied={trace.get('applied', 0)} denied={trace.get('denied', 0)} "
|
|
2291
|
-
f"failed={trace.get('failed', 0)}[/dim]"
|
|
2524
|
+
f"failed={trace.get('failed', 0)} deferred={trace.get('deferred', 0)}[/dim]"
|
|
2292
2525
|
)
|
|
2293
2526
|
|
|
2294
2527
|
|
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import typer
|
|
6
6
|
from rich.console import Console
|
|
7
|
+
from rich.progress import BarColumn, DownloadColumn, Progress, TaskID, TextColumn, TimeRemainingColumn, TransferSpeedColumn
|
|
7
8
|
|
|
8
9
|
from refactorai_cli.auth import AuthError, ensure_authenticated
|
|
9
10
|
from refactorai_cli.control_plane import ensure_lease, heartbeat, read_cached_lease, resolve_policy
|
|
@@ -62,7 +63,23 @@ def update(
|
|
|
62
63
|
f"[bold]resolved manifest[/bold]: version={manifest.runtime_version} "
|
|
63
64
|
f"channel={channel}"
|
|
64
65
|
)
|
|
65
|
-
|
|
66
|
+
progress_columns = (
|
|
67
|
+
TextColumn("[progress.description]{task.description}"),
|
|
68
|
+
BarColumn(),
|
|
69
|
+
DownloadColumn(),
|
|
70
|
+
TransferSpeedColumn(),
|
|
71
|
+
TimeRemainingColumn(),
|
|
72
|
+
)
|
|
73
|
+
with Progress(*progress_columns, console=console, transient=True) as progress:
|
|
74
|
+
task_id: TaskID = progress.add_task("Downloading runtime artifact", total=None)
|
|
75
|
+
|
|
76
|
+
def _on_progress(downloaded: int, total: int | None) -> None:
|
|
77
|
+
update_kwargs = {"completed": int(max(downloaded, 0))}
|
|
78
|
+
if total is not None and total > 0:
|
|
79
|
+
update_kwargs["total"] = total
|
|
80
|
+
progress.update(task_id, **update_kwargs)
|
|
81
|
+
|
|
82
|
+
artifact = download_artifact(manifest.artifact_url, progress_cb=_on_progress)
|
|
66
83
|
console.print(f"[bold]downloaded artifact[/bold]: {len(artifact)} bytes")
|
|
67
84
|
if dry_run:
|
|
68
85
|
# Verification happens in activate_runtime; dry-run still checks
|
|
@@ -14,6 +14,7 @@ import platform
|
|
|
14
14
|
from dataclasses import dataclass
|
|
15
15
|
from datetime import datetime, timezone
|
|
16
16
|
from pathlib import Path
|
|
17
|
+
from typing import Callable
|
|
17
18
|
from urllib.parse import urlparse
|
|
18
19
|
|
|
19
20
|
import httpx
|
|
@@ -153,17 +154,49 @@ def resolve_runtime_manifest(*, channel: str = "stable", timeout: float = 20.0)
|
|
|
153
154
|
return manifest
|
|
154
155
|
|
|
155
156
|
|
|
156
|
-
def download_artifact(
|
|
157
|
+
def download_artifact(
|
|
158
|
+
url: str,
|
|
159
|
+
*,
|
|
160
|
+
timeout: float = 60.0,
|
|
161
|
+
progress_cb: Callable[[int, int | None], None] | None = None,
|
|
162
|
+
) -> bytes:
|
|
157
163
|
headers: dict[str, str] = {}
|
|
158
164
|
if _should_send_runtime_auth(url):
|
|
159
165
|
headers["Authorization"] = _runtime_auth_header()
|
|
166
|
+
resolved_timeout = max(float(timeout), 300.0)
|
|
167
|
+
if progress_cb is None:
|
|
168
|
+
try:
|
|
169
|
+
response = httpx.get(url, headers=headers, timeout=resolved_timeout)
|
|
170
|
+
except httpx.HTTPError as exc:
|
|
171
|
+
raise RuntimeError(f"Could not download runtime artifact: {exc}") from exc
|
|
172
|
+
if response.status_code >= 400:
|
|
173
|
+
raise RuntimeError(f"Runtime artifact download failed ({response.status_code})")
|
|
174
|
+
return response.content
|
|
160
175
|
try:
|
|
161
|
-
|
|
176
|
+
with httpx.stream("GET", url, headers=headers, timeout=resolved_timeout) as response:
|
|
177
|
+
if response.status_code >= 400:
|
|
178
|
+
raise RuntimeError(f"Runtime artifact download failed ({response.status_code})")
|
|
179
|
+
total: int | None = None
|
|
180
|
+
total_header = str(response.headers.get("Content-Length") or "").strip()
|
|
181
|
+
if total_header:
|
|
182
|
+
try:
|
|
183
|
+
parsed_total = int(total_header)
|
|
184
|
+
except ValueError:
|
|
185
|
+
parsed_total = -1
|
|
186
|
+
if parsed_total > 0:
|
|
187
|
+
total = parsed_total
|
|
188
|
+
downloaded = 0
|
|
189
|
+
chunks: list[bytes] = []
|
|
190
|
+
progress_cb(downloaded, total)
|
|
191
|
+
for chunk in response.iter_bytes(chunk_size=64 * 1024):
|
|
192
|
+
if not chunk:
|
|
193
|
+
continue
|
|
194
|
+
chunks.append(chunk)
|
|
195
|
+
downloaded += len(chunk)
|
|
196
|
+
progress_cb(downloaded, total)
|
|
162
197
|
except httpx.HTTPError as exc:
|
|
163
198
|
raise RuntimeError(f"Could not download runtime artifact: {exc}") from exc
|
|
164
|
-
|
|
165
|
-
raise RuntimeError(f"Runtime artifact download failed ({response.status_code})")
|
|
166
|
-
return response.content
|
|
199
|
+
return b"".join(chunks)
|
|
167
200
|
|
|
168
201
|
|
|
169
202
|
def _should_send_runtime_auth(url: str) -> bool:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli/commands/runtime_proxy_cmds.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{refactorai_cli-0.2.14 → refactorai_cli-0.2.16}/refactorai_cli.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|