refactorai-cli 0.2.16__tar.gz → 0.2.19__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.16 → refactorai_cli-0.2.19}/PKG-INFO +1 -1
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/pyproject.toml +1 -1
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/__init__.py +1 -1
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/commands/run_cmds.py +526 -6
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/commands/runtime_proxy_cmds.py +5 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/main.py +1 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/setup_flow.py +21 -1
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli.egg-info/PKG-INFO +1 -1
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/README.md +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/auth.py +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/client.py +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/commands/__init__.py +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/commands/auth_cmds.py +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/commands/engine_cmds.py +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/commands/model_cmds.py +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/commands/rules_cmds.py +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/commands/runtime_cmds.py +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/commands/setup_cmds.py +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/control_plane.py +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/credentials.py +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/local_constitution.py +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/local_engine_runtime.py +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/local_paths.py +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/model_policy.py +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/runtime_manager.py +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/settings.py +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli.egg-info/SOURCES.txt +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli.egg-info/dependency_links.txt +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli.egg-info/entry_points.txt +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli.egg-info/requires.txt +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli.egg-info/top_level.txt +0 -0
- {refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/setup.cfg +0 -0
|
@@ -35,6 +35,13 @@ from refactor_core.constitution import (
|
|
|
35
35
|
raw_secret_matches,
|
|
36
36
|
raw_secret_matches_config,
|
|
37
37
|
)
|
|
38
|
+
from refactor_core.compliance_settings import (
|
|
39
|
+
ComplianceSelectionError,
|
|
40
|
+
resolve_compliance_selection,
|
|
41
|
+
)
|
|
42
|
+
from refactor_core.compliance.loader import CompliancePackError, resolve_compliance_packs
|
|
43
|
+
from refactor_core.compliance.models import CompliancePackResolution
|
|
44
|
+
from refactor_core.compliance.evidence import build_compliance_evidence_bundle, evaluate_compliance_gate
|
|
38
45
|
from refactor_core.apply import (
|
|
39
46
|
ApplyError,
|
|
40
47
|
apply_changes,
|
|
@@ -180,6 +187,25 @@ _REQUIRED_ENV_BY_PROVIDER: dict[str, list[object]] = {
|
|
|
180
187
|
}
|
|
181
188
|
|
|
182
189
|
|
|
190
|
+
def _sanitize_runtime_error_message(message: object) -> str:
|
|
191
|
+
"""Normalize provider/runtime errors to runtime-artifact-friendly guidance."""
|
|
192
|
+
text = str(message or "").strip()
|
|
193
|
+
if not text:
|
|
194
|
+
return "unknown"
|
|
195
|
+
install_hint = re.search(
|
|
196
|
+
r"Install with:\s*pip install ['\"]refactor-core(?:\[[^'\"]+\])?['\"]",
|
|
197
|
+
text,
|
|
198
|
+
flags=re.IGNORECASE,
|
|
199
|
+
)
|
|
200
|
+
if install_hint:
|
|
201
|
+
return (
|
|
202
|
+
"Bedrock credentials are not configured for runtime execution. "
|
|
203
|
+
"Set AWS_BEARER_TOKEN_BEDROCK (for example: `set -a; source .env; set +a`) "
|
|
204
|
+
"or run with AWS SDK credentials in an environment that includes boto3."
|
|
205
|
+
)
|
|
206
|
+
return text
|
|
207
|
+
|
|
208
|
+
|
|
183
209
|
def _agent_progress_logger(
|
|
184
210
|
stage: str, *, status=None, verbose_steps: bool = True
|
|
185
211
|
) -> Callable[[dict], None]:
|
|
@@ -298,16 +324,18 @@ def _agent_progress_logger(
|
|
|
298
324
|
f"[dim]{stage}: step {event.get('step', '?')} result -> {summary}[/dim]"
|
|
299
325
|
)
|
|
300
326
|
elif kind == "tool_error":
|
|
327
|
+
error_text = _sanitize_runtime_error_message(event.get("error", "unknown"))
|
|
301
328
|
console.print(
|
|
302
329
|
f"[yellow]{stage}: step {event.get('step', '?')} tool `{event.get('tool', '?')}` "
|
|
303
|
-
f"error: {
|
|
330
|
+
f"error: {error_text}[/yellow]"
|
|
304
331
|
)
|
|
305
332
|
elif kind == "invalid_response":
|
|
306
333
|
console.print(f"[yellow]{stage}: step {event.get('step', '?')} returned invalid JSON tool call.[/yellow]")
|
|
307
334
|
elif kind == "transport_error":
|
|
335
|
+
error_text = _sanitize_runtime_error_message(event.get("error", "unknown"))
|
|
308
336
|
console.print(
|
|
309
337
|
f"[yellow]{stage}: model transport error at step {event.get('step', '?')}: "
|
|
310
|
-
f"{
|
|
338
|
+
f"{error_text}[/yellow]"
|
|
311
339
|
)
|
|
312
340
|
elif kind == "finish":
|
|
313
341
|
_set_status(
|
|
@@ -661,6 +689,35 @@ def _warn_raw_key(constitution, config) -> None:
|
|
|
661
689
|
)
|
|
662
690
|
|
|
663
691
|
|
|
692
|
+
def _resolve_compliance_context(
|
|
693
|
+
*,
|
|
694
|
+
project_config,
|
|
695
|
+
cli_frameworks: list[str] | None = None,
|
|
696
|
+
cli_level: str | None = None,
|
|
697
|
+
cli_rollout: str | None = None,
|
|
698
|
+
cli_canary_percent: int | None = None,
|
|
699
|
+
) -> tuple[tuple[str, ...], str, CompliancePackResolution, str, int]:
|
|
700
|
+
"""Resolve compliance selection + managed pack set for this run."""
|
|
701
|
+
selection = resolve_compliance_selection(
|
|
702
|
+
dict(getattr(project_config, "settings", {}) or {}),
|
|
703
|
+
cli_frameworks=cli_frameworks,
|
|
704
|
+
cli_level=cli_level,
|
|
705
|
+
cli_rollout=cli_rollout,
|
|
706
|
+
cli_canary_percent=cli_canary_percent,
|
|
707
|
+
)
|
|
708
|
+
resolution = resolve_compliance_packs(
|
|
709
|
+
selection.frameworks,
|
|
710
|
+
level=selection.level,
|
|
711
|
+
)
|
|
712
|
+
return (
|
|
713
|
+
selection.frameworks,
|
|
714
|
+
selection.level,
|
|
715
|
+
resolution,
|
|
716
|
+
selection.rollout,
|
|
717
|
+
selection.canary_percent,
|
|
718
|
+
)
|
|
719
|
+
|
|
720
|
+
|
|
664
721
|
def init(
|
|
665
722
|
force: bool = typer.Option(
|
|
666
723
|
False,
|
|
@@ -1481,10 +1538,64 @@ def review(
|
|
|
1481
1538
|
"--force",
|
|
1482
1539
|
help="Run review even if unapplied patches exist from a prior code run.",
|
|
1483
1540
|
),
|
|
1541
|
+
compliance_framework: list[str] | None = typer.Option(
|
|
1542
|
+
None,
|
|
1543
|
+
"--compliance-framework",
|
|
1544
|
+
help="Compliance framework to enable for this run. Repeat for multiple values.",
|
|
1545
|
+
),
|
|
1546
|
+
compliance_level: str | None = typer.Option(
|
|
1547
|
+
None,
|
|
1548
|
+
"--compliance-level",
|
|
1549
|
+
help="Compliance level override: off | advisory | standard | strict.",
|
|
1550
|
+
),
|
|
1551
|
+
compliance_rollout: str | None = typer.Option(
|
|
1552
|
+
None,
|
|
1553
|
+
"--compliance-rollout",
|
|
1554
|
+
help="Compliance rollout mode: default | staged | canary | off | ga.",
|
|
1555
|
+
),
|
|
1556
|
+
compliance_canary_percent: int | None = typer.Option(
|
|
1557
|
+
None,
|
|
1558
|
+
"--compliance-canary-percent",
|
|
1559
|
+
help="Compliance canary percentage (0-100) when rollout=canary.",
|
|
1560
|
+
),
|
|
1484
1561
|
) -> None:
|
|
1485
1562
|
"""Run review (findings only) and store the result. Requires a valid key."""
|
|
1486
1563
|
_require_auth()
|
|
1487
1564
|
project_root, constitution, project_config = _load_project()
|
|
1565
|
+
try:
|
|
1566
|
+
(
|
|
1567
|
+
compliance_frameworks,
|
|
1568
|
+
resolved_compliance_level,
|
|
1569
|
+
compliance_resolution,
|
|
1570
|
+
compliance_rollout_mode,
|
|
1571
|
+
compliance_canary_pct,
|
|
1572
|
+
) = (
|
|
1573
|
+
_resolve_compliance_context(
|
|
1574
|
+
project_config=project_config,
|
|
1575
|
+
cli_frameworks=compliance_framework,
|
|
1576
|
+
cli_level=compliance_level,
|
|
1577
|
+
cli_rollout=compliance_rollout,
|
|
1578
|
+
cli_canary_percent=compliance_canary_percent,
|
|
1579
|
+
)
|
|
1580
|
+
)
|
|
1581
|
+
except ComplianceSelectionError as exc:
|
|
1582
|
+
console.print(f"[red]review: invalid compliance selection:[/red] {exc}")
|
|
1583
|
+
raise typer.Exit(code=2) from exc
|
|
1584
|
+
except CompliancePackError as exc:
|
|
1585
|
+
console.print(f"[red]review: compliance pack resolution failed:[/red] {exc}")
|
|
1586
|
+
raise typer.Exit(code=1) from exc
|
|
1587
|
+
if compliance_frameworks:
|
|
1588
|
+
pack_label = ", ".join(
|
|
1589
|
+
f"{pack.pack_id}@{pack.version}" for pack in compliance_resolution.packs
|
|
1590
|
+
) or "(none loaded)"
|
|
1591
|
+
console.print(
|
|
1592
|
+
"[dim]review: compliance selection "
|
|
1593
|
+
f"frameworks={list(compliance_frameworks)} level={resolved_compliance_level} "
|
|
1594
|
+
f"rollout={compliance_rollout_mode} canary_percent={compliance_canary_pct} "
|
|
1595
|
+
f"packs={pack_label}[/dim]"
|
|
1596
|
+
)
|
|
1597
|
+
for warning in compliance_resolution.warnings:
|
|
1598
|
+
console.print(f"[yellow]review: compliance warning:[/yellow] {warning}")
|
|
1488
1599
|
register_project(project_root, constitution_hash=constitution.content_hash)
|
|
1489
1600
|
_maybe_build_graph(project_root, project_config)
|
|
1490
1601
|
sandbox_ctx = None
|
|
@@ -1546,7 +1657,7 @@ def review(
|
|
|
1546
1657
|
"Review continued; address sandbox install/toolchain incompatibilities for best results."
|
|
1547
1658
|
)
|
|
1548
1659
|
except Exception as exc: # provider/transport errors should not crash the CLI
|
|
1549
|
-
console.print(f"[red]Review failed:[/red] {exc}")
|
|
1660
|
+
console.print(f"[red]Review failed:[/red] {_sanitize_runtime_error_message(exc)}")
|
|
1550
1661
|
raise typer.Exit(code=1) from exc
|
|
1551
1662
|
finally:
|
|
1552
1663
|
_teardown_sandbox_context(project_root, sandbox_ctx)
|
|
@@ -1562,8 +1673,34 @@ def review(
|
|
|
1562
1673
|
project_root=project_root,
|
|
1563
1674
|
findings=artifact.findings,
|
|
1564
1675
|
run_id=artifact.run_id,
|
|
1676
|
+
compliance_frameworks=compliance_frameworks,
|
|
1677
|
+
compliance_level=resolved_compliance_level,
|
|
1678
|
+
compliance_rollout=compliance_rollout_mode,
|
|
1679
|
+
compliance_canary_percent=compliance_canary_pct,
|
|
1680
|
+
compliance_resolution=compliance_resolution,
|
|
1565
1681
|
artifact=artifact,
|
|
1566
1682
|
)
|
|
1683
|
+
_apply_compliance_gate_to_artifact(artifact)
|
|
1684
|
+
run_store.write_artifact(artifact, target=target, status="completed")
|
|
1685
|
+
if compliance_frameworks:
|
|
1686
|
+
artifact.notes.append(
|
|
1687
|
+
"Compliance selection: frameworks="
|
|
1688
|
+
+ ",".join(compliance_frameworks)
|
|
1689
|
+
+ (
|
|
1690
|
+
f" level={resolved_compliance_level} rollout={compliance_rollout_mode} "
|
|
1691
|
+
f"canary_percent={compliance_canary_pct}"
|
|
1692
|
+
)
|
|
1693
|
+
)
|
|
1694
|
+
if compliance_resolution.packs:
|
|
1695
|
+
artifact.notes.append(
|
|
1696
|
+
"Compliance packs: "
|
|
1697
|
+
+ ", ".join(
|
|
1698
|
+
f"{pack.pack_id}@{pack.version}"
|
|
1699
|
+
for pack in compliance_resolution.packs
|
|
1700
|
+
)
|
|
1701
|
+
)
|
|
1702
|
+
for warning in compliance_resolution.warnings:
|
|
1703
|
+
artifact.notes.append(f"Compliance pack warning: {warning}")
|
|
1567
1704
|
if requests:
|
|
1568
1705
|
console.print(
|
|
1569
1706
|
f"\n[bold]Created {len(requests)} refactor request(s).[/bold] "
|
|
@@ -1608,6 +1745,26 @@ def code(
|
|
|
1608
1745
|
"--equivalence",
|
|
1609
1746
|
help="Equivalence policy: strict | balanced.",
|
|
1610
1747
|
),
|
|
1748
|
+
compliance_framework: list[str] | None = typer.Option(
|
|
1749
|
+
None,
|
|
1750
|
+
"--compliance-framework",
|
|
1751
|
+
help="Compliance framework to enable for this run. Repeat for multiple values.",
|
|
1752
|
+
),
|
|
1753
|
+
compliance_level: str | None = typer.Option(
|
|
1754
|
+
None,
|
|
1755
|
+
"--compliance-level",
|
|
1756
|
+
help="Compliance level override: off | advisory | standard | strict.",
|
|
1757
|
+
),
|
|
1758
|
+
compliance_rollout: str | None = typer.Option(
|
|
1759
|
+
None,
|
|
1760
|
+
"--compliance-rollout",
|
|
1761
|
+
help="Compliance rollout mode: default | staged | canary | off | ga.",
|
|
1762
|
+
),
|
|
1763
|
+
compliance_canary_percent: int | None = typer.Option(
|
|
1764
|
+
None,
|
|
1765
|
+
"--compliance-canary-percent",
|
|
1766
|
+
help="Compliance canary percentage (0-100) when rollout=canary.",
|
|
1767
|
+
),
|
|
1611
1768
|
) -> None:
|
|
1612
1769
|
"""Work through refactor requests one by one, applying & verifying each.
|
|
1613
1770
|
|
|
@@ -1616,6 +1773,40 @@ def code(
|
|
|
1616
1773
|
"""
|
|
1617
1774
|
_require_auth()
|
|
1618
1775
|
project_root, constitution, project_config = _load_project()
|
|
1776
|
+
try:
|
|
1777
|
+
(
|
|
1778
|
+
compliance_frameworks,
|
|
1779
|
+
resolved_compliance_level,
|
|
1780
|
+
compliance_resolution,
|
|
1781
|
+
compliance_rollout_mode,
|
|
1782
|
+
compliance_canary_pct,
|
|
1783
|
+
) = (
|
|
1784
|
+
_resolve_compliance_context(
|
|
1785
|
+
project_config=project_config,
|
|
1786
|
+
cli_frameworks=compliance_framework,
|
|
1787
|
+
cli_level=compliance_level,
|
|
1788
|
+
cli_rollout=compliance_rollout,
|
|
1789
|
+
cli_canary_percent=compliance_canary_percent,
|
|
1790
|
+
)
|
|
1791
|
+
)
|
|
1792
|
+
except ComplianceSelectionError as exc:
|
|
1793
|
+
console.print(f"[red]code: invalid compliance selection:[/red] {exc}")
|
|
1794
|
+
raise typer.Exit(code=2) from exc
|
|
1795
|
+
except CompliancePackError as exc:
|
|
1796
|
+
console.print(f"[red]code: compliance pack resolution failed:[/red] {exc}")
|
|
1797
|
+
raise typer.Exit(code=1) from exc
|
|
1798
|
+
if compliance_frameworks:
|
|
1799
|
+
pack_label = ", ".join(
|
|
1800
|
+
f"{pack.pack_id}@{pack.version}" for pack in compliance_resolution.packs
|
|
1801
|
+
) or "(none loaded)"
|
|
1802
|
+
console.print(
|
|
1803
|
+
"[dim]code: compliance selection "
|
|
1804
|
+
f"frameworks={list(compliance_frameworks)} level={resolved_compliance_level} "
|
|
1805
|
+
f"rollout={compliance_rollout_mode} canary_percent={compliance_canary_pct} "
|
|
1806
|
+
f"packs={pack_label}[/dim]"
|
|
1807
|
+
)
|
|
1808
|
+
for warning in compliance_resolution.warnings:
|
|
1809
|
+
console.print(f"[yellow]code: compliance warning:[/yellow] {warning}")
|
|
1619
1810
|
register_project(project_root, constitution_hash=constitution.content_hash)
|
|
1620
1811
|
_maybe_build_graph(project_root, project_config)
|
|
1621
1812
|
sandbox_ctx = None
|
|
@@ -1676,8 +1867,34 @@ def code(
|
|
|
1676
1867
|
project_root=project_root,
|
|
1677
1868
|
findings=review_artifact.findings,
|
|
1678
1869
|
run_id=review_artifact.run_id,
|
|
1870
|
+
compliance_frameworks=compliance_frameworks,
|
|
1871
|
+
compliance_level=resolved_compliance_level,
|
|
1872
|
+
compliance_rollout=compliance_rollout_mode,
|
|
1873
|
+
compliance_canary_percent=compliance_canary_pct,
|
|
1874
|
+
compliance_resolution=compliance_resolution,
|
|
1679
1875
|
artifact=review_artifact,
|
|
1680
1876
|
)
|
|
1877
|
+
_apply_compliance_gate_to_artifact(review_artifact)
|
|
1878
|
+
if compliance_frameworks:
|
|
1879
|
+
review_artifact.notes.append(
|
|
1880
|
+
"Compliance selection: frameworks="
|
|
1881
|
+
+ ",".join(compliance_frameworks)
|
|
1882
|
+
+ (
|
|
1883
|
+
f" level={resolved_compliance_level} rollout={compliance_rollout_mode} "
|
|
1884
|
+
f"canary_percent={compliance_canary_pct}"
|
|
1885
|
+
)
|
|
1886
|
+
)
|
|
1887
|
+
if compliance_resolution.packs:
|
|
1888
|
+
review_artifact.notes.append(
|
|
1889
|
+
"Compliance packs: "
|
|
1890
|
+
+ ", ".join(
|
|
1891
|
+
f"{pack.pack_id}@{pack.version}"
|
|
1892
|
+
for pack in compliance_resolution.packs
|
|
1893
|
+
)
|
|
1894
|
+
)
|
|
1895
|
+
for warning in compliance_resolution.warnings:
|
|
1896
|
+
review_artifact.notes.append(f"Compliance pack warning: {warning}")
|
|
1897
|
+
review_store.write_artifact(review_artifact, target=target, status="completed")
|
|
1681
1898
|
console.print(f"[bold]Created {len(requests)} refactor request(s).[/bold]")
|
|
1682
1899
|
|
|
1683
1900
|
if not requests:
|
|
@@ -1710,7 +1927,7 @@ def code(
|
|
|
1710
1927
|
equivalence_mode=equivalence,
|
|
1711
1928
|
)
|
|
1712
1929
|
except Exception as exc:
|
|
1713
|
-
console.print(f"[red]Refactor failed:[/red] {exc}")
|
|
1930
|
+
console.print(f"[red]Refactor failed:[/red] {_sanitize_runtime_error_message(exc)}")
|
|
1714
1931
|
raise typer.Exit(code=1) from exc
|
|
1715
1932
|
finally:
|
|
1716
1933
|
_teardown_sandbox_context(project_root, sandbox_ctx)
|
|
@@ -1826,6 +2043,211 @@ def requests(
|
|
|
1826
2043
|
console.print(table)
|
|
1827
2044
|
|
|
1828
2045
|
|
|
2046
|
+
def compliance(
|
|
2047
|
+
action: str = typer.Argument(
|
|
2048
|
+
"show",
|
|
2049
|
+
help="Compliance view action: status | show | coverage | explain | export",
|
|
2050
|
+
),
|
|
2051
|
+
subject: str = typer.Argument(
|
|
2052
|
+
"",
|
|
2053
|
+
help="Rule ID when action=explain.",
|
|
2054
|
+
),
|
|
2055
|
+
compliance_framework: list[str] | None = typer.Option(
|
|
2056
|
+
None,
|
|
2057
|
+
"--compliance-framework",
|
|
2058
|
+
help="Compliance framework selection override. Repeat for multiple values.",
|
|
2059
|
+
),
|
|
2060
|
+
compliance_level: str | None = typer.Option(
|
|
2061
|
+
None,
|
|
2062
|
+
"--compliance-level",
|
|
2063
|
+
help="Compliance level override: off | advisory | standard | strict.",
|
|
2064
|
+
),
|
|
2065
|
+
compliance_rollout: str | None = typer.Option(
|
|
2066
|
+
None,
|
|
2067
|
+
"--compliance-rollout",
|
|
2068
|
+
help="Compliance rollout mode override: default | staged | canary | off | ga.",
|
|
2069
|
+
),
|
|
2070
|
+
compliance_canary_percent: int | None = typer.Option(
|
|
2071
|
+
None,
|
|
2072
|
+
"--compliance-canary-percent",
|
|
2073
|
+
help="Compliance canary percentage override when rollout=canary.",
|
|
2074
|
+
),
|
|
2075
|
+
output: str = typer.Option(
|
|
2076
|
+
"",
|
|
2077
|
+
"--output",
|
|
2078
|
+
help="Output file path for action=export (defaults to latest run directory).",
|
|
2079
|
+
),
|
|
2080
|
+
) -> None:
|
|
2081
|
+
"""Show/export compliance packs, coverage, and rule details."""
|
|
2082
|
+
_require_auth()
|
|
2083
|
+
_project_root, _constitution, project_config = _load_project()
|
|
2084
|
+
try:
|
|
2085
|
+
frameworks, level, resolution, rollout_mode, canary_percent = _resolve_compliance_context(
|
|
2086
|
+
project_config=project_config,
|
|
2087
|
+
cli_frameworks=compliance_framework,
|
|
2088
|
+
cli_level=compliance_level,
|
|
2089
|
+
cli_rollout=compliance_rollout,
|
|
2090
|
+
cli_canary_percent=compliance_canary_percent,
|
|
2091
|
+
)
|
|
2092
|
+
except ComplianceSelectionError as exc:
|
|
2093
|
+
console.print(f"[red]compliance: invalid selection:[/red] {exc}")
|
|
2094
|
+
raise typer.Exit(code=2) from exc
|
|
2095
|
+
except CompliancePackError as exc:
|
|
2096
|
+
console.print(f"[red]compliance: pack resolution failed:[/red] {exc}")
|
|
2097
|
+
raise typer.Exit(code=1) from exc
|
|
2098
|
+
mode = str(action or "show").strip().lower()
|
|
2099
|
+
if mode not in {"status", "show", "coverage", "explain", "export"}:
|
|
2100
|
+
console.print(f"[red]Unknown compliance action:[/red] {action}")
|
|
2101
|
+
raise typer.Exit(code=2)
|
|
2102
|
+
if not frameworks:
|
|
2103
|
+
console.print(
|
|
2104
|
+
"[dim]No compliance frameworks selected. "
|
|
2105
|
+
"Set `compliance.frameworks` in refactor.config or pass --compliance-framework.[/dim]"
|
|
2106
|
+
)
|
|
2107
|
+
return
|
|
2108
|
+
|
|
2109
|
+
if mode == "status":
|
|
2110
|
+
run_dir = head_run_dir(_project_root)
|
|
2111
|
+
report = read_report(run_dir) if run_dir else {}
|
|
2112
|
+
summary = (
|
|
2113
|
+
dict((report or {}).get("compliance_summary", {}) or {})
|
|
2114
|
+
if isinstance(report, dict)
|
|
2115
|
+
else {}
|
|
2116
|
+
)
|
|
2117
|
+
gate = dict((report or {}).get("gate", {}) or {}) if isinstance(report, dict) else {}
|
|
2118
|
+
console.print("[bold]Compliance status[/bold]")
|
|
2119
|
+
console.print(
|
|
2120
|
+
f" selection: frameworks={list(frameworks)} level={level} "
|
|
2121
|
+
f"rollout={rollout_mode} canary_percent={canary_percent}"
|
|
2122
|
+
)
|
|
2123
|
+
table = Table(title="Compliance packs", show_lines=False)
|
|
2124
|
+
table.add_column("pack_id", no_wrap=True)
|
|
2125
|
+
table.add_column("framework", no_wrap=True)
|
|
2126
|
+
table.add_column("version", no_wrap=True)
|
|
2127
|
+
table.add_column("rules", no_wrap=True)
|
|
2128
|
+
for pack in resolution.packs:
|
|
2129
|
+
table.add_row(pack.pack_id, pack.framework, pack.version, str(len(pack.rules)))
|
|
2130
|
+
console.print(table)
|
|
2131
|
+
if not run_dir:
|
|
2132
|
+
console.print(
|
|
2133
|
+
"[yellow]No runs yet.[/yellow] Run `refactor review` to produce compliance evidence."
|
|
2134
|
+
)
|
|
2135
|
+
return
|
|
2136
|
+
run_id = str((report or {}).get("run_id", run_dir.name))
|
|
2137
|
+
created = str((report or {}).get("created_at", ""))
|
|
2138
|
+
gate_status = str(gate.get("status", "unknown"))
|
|
2139
|
+
projected = int(summary.get("projected_count", 0) or 0)
|
|
2140
|
+
blocked = int(summary.get("blocked_count", 0) or 0)
|
|
2141
|
+
warned = int(summary.get("warned_count", 0) or 0)
|
|
2142
|
+
gate_color = "green" if gate_status == "passed" else "red"
|
|
2143
|
+
console.print(
|
|
2144
|
+
f" latest_run: {run_id}" + (f" ({created})" if created else "")
|
|
2145
|
+
)
|
|
2146
|
+
console.print(
|
|
2147
|
+
f" gate: [{gate_color}]{gate_status}[/{gate_color}] "
|
|
2148
|
+
f"projected={projected} blocked={blocked} warned={warned}"
|
|
2149
|
+
)
|
|
2150
|
+
if blocked > 0 and level in {"standard", "strict"}:
|
|
2151
|
+
console.print(
|
|
2152
|
+
"[yellow]next step:[/yellow] resolve blocked controls or run with "
|
|
2153
|
+
"`--compliance-rollout staged` during pilot."
|
|
2154
|
+
)
|
|
2155
|
+
elif projected == 0:
|
|
2156
|
+
console.print(
|
|
2157
|
+
"[dim]No compliance-projected controls were triggered in the latest run.[/dim]"
|
|
2158
|
+
)
|
|
2159
|
+
return
|
|
2160
|
+
|
|
2161
|
+
if mode == "show":
|
|
2162
|
+
console.print(
|
|
2163
|
+
"[bold]Compliance selection[/bold]: "
|
|
2164
|
+
f"frameworks={list(frameworks)} level={level} "
|
|
2165
|
+
f"rollout={rollout_mode} canary_percent={canary_percent}"
|
|
2166
|
+
)
|
|
2167
|
+
table = Table(title="Compliance packs", show_lines=False)
|
|
2168
|
+
table.add_column("pack_id", no_wrap=True)
|
|
2169
|
+
table.add_column("framework", no_wrap=True)
|
|
2170
|
+
table.add_column("version", no_wrap=True)
|
|
2171
|
+
table.add_column("rules", no_wrap=True)
|
|
2172
|
+
table.add_column("depends_on")
|
|
2173
|
+
for pack in resolution.packs:
|
|
2174
|
+
table.add_row(
|
|
2175
|
+
pack.pack_id,
|
|
2176
|
+
pack.framework,
|
|
2177
|
+
pack.version,
|
|
2178
|
+
str(len(pack.rules)),
|
|
2179
|
+
", ".join(pack.depends_on) if pack.depends_on else "-",
|
|
2180
|
+
)
|
|
2181
|
+
console.print(table)
|
|
2182
|
+
for warning in resolution.warnings:
|
|
2183
|
+
console.print(f"[yellow]warning:[/yellow] {warning}")
|
|
2184
|
+
return
|
|
2185
|
+
|
|
2186
|
+
if mode == "export":
|
|
2187
|
+
run_dir = head_run_dir(_project_root)
|
|
2188
|
+
if not run_dir:
|
|
2189
|
+
console.print("[yellow]No runs available to export compliance evidence.[/yellow]")
|
|
2190
|
+
raise typer.Exit(code=1)
|
|
2191
|
+
report = read_report(run_dir) or {}
|
|
2192
|
+
payload = build_compliance_evidence_bundle(report)
|
|
2193
|
+
destination = Path(output).expanduser() if output.strip() else (run_dir / "compliance-evidence.json")
|
|
2194
|
+
try:
|
|
2195
|
+
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
2196
|
+
destination.write_text(json.dumps(payload, indent=2, sort_keys=True), encoding="utf-8")
|
|
2197
|
+
except OSError as exc:
|
|
2198
|
+
console.print(f"[red]Failed to write compliance evidence:[/red] {exc}")
|
|
2199
|
+
raise typer.Exit(code=1) from exc
|
|
2200
|
+
console.print(f"[green]Compliance evidence exported:[/green] {destination}")
|
|
2201
|
+
return
|
|
2202
|
+
|
|
2203
|
+
if mode == "coverage":
|
|
2204
|
+
table = Table(title="Compliance coverage", show_lines=False)
|
|
2205
|
+
table.add_column("framework", no_wrap=True)
|
|
2206
|
+
table.add_column("control", no_wrap=True)
|
|
2207
|
+
table.add_column("classification", no_wrap=True)
|
|
2208
|
+
rows = 0
|
|
2209
|
+
for pack in resolution.packs:
|
|
2210
|
+
if not pack.coverage:
|
|
2211
|
+
table.add_row(pack.framework, "-", "unknown")
|
|
2212
|
+
rows += 1
|
|
2213
|
+
continue
|
|
2214
|
+
for control, classification in sorted(pack.coverage.items()):
|
|
2215
|
+
table.add_row(pack.framework, control, classification)
|
|
2216
|
+
rows += 1
|
|
2217
|
+
if rows == 0:
|
|
2218
|
+
console.print("[dim]No coverage metadata available in selected packs.[/dim]")
|
|
2219
|
+
return
|
|
2220
|
+
console.print(table)
|
|
2221
|
+
return
|
|
2222
|
+
|
|
2223
|
+
# explain
|
|
2224
|
+
rule_id = (subject or "").strip()
|
|
2225
|
+
if not rule_id:
|
|
2226
|
+
console.print("[red]Rule id is required for `refactor compliance explain`.[/red]")
|
|
2227
|
+
raise typer.Exit(code=2)
|
|
2228
|
+
needle = rule_id.lower()
|
|
2229
|
+
matches = []
|
|
2230
|
+
for pack in resolution.packs:
|
|
2231
|
+
for rule in pack.rules:
|
|
2232
|
+
if rule.rule_id.lower() == needle or needle in rule.rule_id.lower():
|
|
2233
|
+
matches.append((pack, rule))
|
|
2234
|
+
if not matches:
|
|
2235
|
+
console.print(f"[yellow]No compliance rule found:[/yellow] {rule_id}")
|
|
2236
|
+
raise typer.Exit(code=1)
|
|
2237
|
+
for pack, rule in matches:
|
|
2238
|
+
console.print(
|
|
2239
|
+
f"[bold]{rule.rule_id}[/bold] "
|
|
2240
|
+
f"[dim](pack={pack.pack_id}@{pack.version}, framework={pack.framework})[/dim]"
|
|
2241
|
+
)
|
|
2242
|
+
if rule.source_standard:
|
|
2243
|
+
console.print(f" standard: {rule.source_standard}")
|
|
2244
|
+
if rule.control_objective:
|
|
2245
|
+
console.print(f" objective: {rule.control_objective}")
|
|
2246
|
+
console.print(f" operation_intent: {rule.operation_intent}")
|
|
2247
|
+
console.print(f" base_severity: {rule.base_severity}")
|
|
2248
|
+
console.print(f" priority: {rule.priority}")
|
|
2249
|
+
|
|
2250
|
+
|
|
1829
2251
|
def _format_operation_scope(rr) -> str:
|
|
1830
2252
|
scope = getattr(rr, "scope", None)
|
|
1831
2253
|
if scope is None:
|
|
@@ -1861,6 +2283,11 @@ def _replace_requests_with_framework_guardrails(
|
|
|
1861
2283
|
project_root: Path,
|
|
1862
2284
|
findings: list[Finding],
|
|
1863
2285
|
run_id: str,
|
|
2286
|
+
compliance_frameworks: tuple[str, ...] = (),
|
|
2287
|
+
compliance_level: str = "standard",
|
|
2288
|
+
compliance_rollout: str = "default",
|
|
2289
|
+
compliance_canary_percent: int = 20,
|
|
2290
|
+
compliance_resolution: CompliancePackResolution | None = None,
|
|
1864
2291
|
artifact: RunArtifact | None = None,
|
|
1865
2292
|
) -> list:
|
|
1866
2293
|
clear_requests(project_root)
|
|
@@ -1868,20 +2295,79 @@ def _replace_requests_with_framework_guardrails(
|
|
|
1868
2295
|
project_root,
|
|
1869
2296
|
findings,
|
|
1870
2297
|
run_id=run_id,
|
|
2298
|
+
compliance_frameworks=compliance_frameworks,
|
|
2299
|
+
compliance_level=compliance_level,
|
|
2300
|
+
compliance_rollout=compliance_rollout,
|
|
2301
|
+
compliance_canary_percent=compliance_canary_percent,
|
|
1871
2302
|
return_diagnostics=True,
|
|
1872
2303
|
)
|
|
1873
2304
|
_report_framework_suppressions(suppressions, artifact=artifact)
|
|
1874
2305
|
_report_framework_warnings(warnings, artifact=artifact)
|
|
2306
|
+
if artifact is not None and compliance_frameworks:
|
|
2307
|
+
compliance_suppressed = [
|
|
2308
|
+
item for item in suppressions if str(item.reason_code).startswith("RR_COMPLIANCE_")
|
|
2309
|
+
]
|
|
2310
|
+
compliance_warnings = [
|
|
2311
|
+
item for item in warnings if str(item.reason_code).startswith("RR_COMPLIANCE_")
|
|
2312
|
+
]
|
|
2313
|
+
artifact.compliance_summary = {
|
|
2314
|
+
"level": compliance_level,
|
|
2315
|
+
"frameworks": list(compliance_frameworks),
|
|
2316
|
+
"rollout": compliance_rollout,
|
|
2317
|
+
"canary_percent": int(compliance_canary_percent),
|
|
2318
|
+
"pack_versions": (
|
|
2319
|
+
compliance_resolution.pack_versions if compliance_resolution is not None else {}
|
|
2320
|
+
),
|
|
2321
|
+
"projected_count": len(compliance_suppressed) + len(compliance_warnings),
|
|
2322
|
+
"blocked_count": len(compliance_suppressed),
|
|
2323
|
+
"warned_count": len(compliance_warnings),
|
|
2324
|
+
"rules_triggered": sorted(
|
|
2325
|
+
{
|
|
2326
|
+
item.rule_id
|
|
2327
|
+
for item in [*compliance_suppressed, *compliance_warnings]
|
|
2328
|
+
if str(item.rule_id).strip()
|
|
2329
|
+
}
|
|
2330
|
+
),
|
|
2331
|
+
}
|
|
1875
2332
|
return requests
|
|
1876
2333
|
|
|
1877
2334
|
|
|
2335
|
+
def _apply_compliance_gate_to_artifact(artifact: RunArtifact) -> None:
|
|
2336
|
+
"""Promote compliance blocking decisions into gate outcome (R18 Phase 7)."""
|
|
2337
|
+
summary = dict(getattr(artifact, "compliance_summary", {}) or {})
|
|
2338
|
+
decision = evaluate_compliance_gate(
|
|
2339
|
+
summary,
|
|
2340
|
+
base_gate_status=str(getattr(artifact.gate, "status", "unknown") or "unknown"),
|
|
2341
|
+
)
|
|
2342
|
+
if decision.status == "blocked":
|
|
2343
|
+
artifact.gate.status = "blocked"
|
|
2344
|
+
reasons = list((artifact.gate.blocking_reasons or {}).get("reasons", []))
|
|
2345
|
+
for reason in decision.reasons:
|
|
2346
|
+
if reason not in reasons:
|
|
2347
|
+
reasons.append(reason)
|
|
2348
|
+
artifact.gate.blocking_reasons["reasons"] = reasons
|
|
2349
|
+
|
|
2350
|
+
|
|
1878
2351
|
def _report_framework_suppressions(
|
|
1879
2352
|
suppressions: list[RequestSuppression], *, artifact: RunArtifact | None = None
|
|
1880
2353
|
) -> None:
|
|
1881
2354
|
if not suppressions:
|
|
1882
2355
|
return
|
|
2356
|
+
feasibility = sum(1 for s in suppressions if s.rule_id == "operation_feasibility")
|
|
2357
|
+
compliance = sum(
|
|
2358
|
+
1 for s in suppressions if s.reason_code.startswith("RR_COMPLIANCE_")
|
|
2359
|
+
)
|
|
2360
|
+
framework = len(suppressions) - feasibility - compliance
|
|
2361
|
+
parts: list[str] = []
|
|
2362
|
+
if framework:
|
|
2363
|
+
parts.append(f"{framework} due to framework invariants")
|
|
2364
|
+
if compliance:
|
|
2365
|
+
parts.append(f"{compliance} due to compliance controls")
|
|
2366
|
+
if feasibility:
|
|
2367
|
+
parts.append(f"{feasibility} not executable as written")
|
|
2368
|
+
detail = "; ".join(parts) if parts else "review-stage checks"
|
|
1883
2369
|
console.print(
|
|
1884
|
-
f"[yellow]warning:[/yellow] suppressed {len(suppressions)} finding(s)
|
|
2370
|
+
f"[yellow]warning:[/yellow] suppressed {len(suppressions)} finding(s) ({detail})."
|
|
1885
2371
|
)
|
|
1886
2372
|
for item in suppressions:
|
|
1887
2373
|
console.print(
|
|
@@ -1897,8 +2383,16 @@ def _report_framework_warnings(
|
|
|
1897
2383
|
) -> None:
|
|
1898
2384
|
if not warnings:
|
|
1899
2385
|
return
|
|
2386
|
+
compliance = sum(1 for item in warnings if item.reason_code.startswith("RR_COMPLIANCE_"))
|
|
2387
|
+
framework = len(warnings) - compliance
|
|
2388
|
+
detail_parts: list[str] = []
|
|
2389
|
+
if framework:
|
|
2390
|
+
detail_parts.append(f"{framework} framework")
|
|
2391
|
+
if compliance:
|
|
2392
|
+
detail_parts.append(f"{compliance} compliance")
|
|
2393
|
+
detail = ", ".join(detail_parts) if detail_parts else "review"
|
|
1900
2394
|
console.print(
|
|
1901
|
-
f"[yellow]warning:[/yellow] flagged {len(warnings)} finding(s) with
|
|
2395
|
+
f"[yellow]warning:[/yellow] flagged {len(warnings)} finding(s) with caution ({detail})."
|
|
1902
2396
|
)
|
|
1903
2397
|
for item in warnings:
|
|
1904
2398
|
console.print(
|
|
@@ -2166,6 +2660,11 @@ def gc(
|
|
|
2166
2660
|
|
|
2167
2661
|
def check(
|
|
2168
2662
|
strict: bool = typer.Option(False, "--strict", help="Exit non-zero if issues are found (for CI)."),
|
|
2663
|
+
compliance_gate: bool = typer.Option(
|
|
2664
|
+
False,
|
|
2665
|
+
"--compliance-gate",
|
|
2666
|
+
help="Also enforce latest run compliance gate status (for CI/PR pipelines).",
|
|
2667
|
+
),
|
|
2169
2668
|
) -> None:
|
|
2170
2669
|
"""Check the constitution for committed secrets (developer/provider keys)."""
|
|
2171
2670
|
files = find_project_files()
|
|
@@ -2176,6 +2675,25 @@ def check(
|
|
|
2176
2675
|
constitution = load_constitution(consti_path)
|
|
2177
2676
|
config = load_config(config_path)
|
|
2178
2677
|
findings = raw_secret_matches(constitution) + raw_secret_matches_config(config)
|
|
2678
|
+
compliance_failed = False
|
|
2679
|
+
if compliance_gate:
|
|
2680
|
+
run_dir = head_run_dir(consti_path.parent)
|
|
2681
|
+
if run_dir is None:
|
|
2682
|
+
console.print("[yellow]Compliance gate check skipped:[/yellow] no runs yet.")
|
|
2683
|
+
else:
|
|
2684
|
+
report = read_report(run_dir) or {}
|
|
2685
|
+
decision = evaluate_compliance_gate(
|
|
2686
|
+
report.get("compliance_summary", {}),
|
|
2687
|
+
base_gate_status=str((report.get("gate") or {}).get("status", "unknown")),
|
|
2688
|
+
)
|
|
2689
|
+
if decision.status == "blocked":
|
|
2690
|
+
compliance_failed = True
|
|
2691
|
+
console.print(
|
|
2692
|
+
"[red]Compliance gate blocked[/red]: "
|
|
2693
|
+
+ ", ".join(decision.reasons or ("compliance_controls_blocked",))
|
|
2694
|
+
)
|
|
2695
|
+
else:
|
|
2696
|
+
console.print("[green]Compliance gate[/green]: passed")
|
|
2179
2697
|
if findings:
|
|
2180
2698
|
kinds = ", ".join(sorted({kind for kind, _ in findings}))
|
|
2181
2699
|
console.print(
|
|
@@ -2183,6 +2701,8 @@ def check(
|
|
|
2183
2701
|
f"{consti_path} or {config_path}. Replace secrets with `${{ENV_VAR}}` references."
|
|
2184
2702
|
)
|
|
2185
2703
|
raise typer.Exit(code=1 if strict else 0)
|
|
2704
|
+
if compliance_failed:
|
|
2705
|
+
raise typer.Exit(code=1 if strict else 0)
|
|
2186
2706
|
console.print("[green]OK[/green]: no committed secret-like literals detected.")
|
|
2187
2707
|
|
|
2188
2708
|
|
{refactorai_cli-0.2.16 → refactorai_cli-0.2.19}/refactorai_cli/commands/runtime_proxy_cmds.py
RENAMED
|
@@ -136,3 +136,8 @@ def doctor(ctx: typer.Context) -> None:
|
|
|
136
136
|
def config(ctx: typer.Context) -> None:
|
|
137
137
|
"""Manage config via proprietary runtime."""
|
|
138
138
|
_exec_runtime("config", list(ctx.args))
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def compliance(ctx: typer.Context) -> None:
|
|
142
|
+
"""Inspect compliance packs/coverage via proprietary runtime."""
|
|
143
|
+
_exec_runtime("compliance", list(ctx.args))
|
|
@@ -56,6 +56,7 @@ app.command(context_settings=_RUNTIME_CTX)(runtime_proxy_cmds.gc)
|
|
|
56
56
|
app.command(context_settings=_RUNTIME_CTX)(runtime_proxy_cmds.check)
|
|
57
57
|
app.command(context_settings=_RUNTIME_CTX)(runtime_proxy_cmds.doctor)
|
|
58
58
|
app.command(context_settings=_RUNTIME_CTX)(runtime_proxy_cmds.config)
|
|
59
|
+
app.command(context_settings=_RUNTIME_CTX)(runtime_proxy_cmds.compliance)
|
|
59
60
|
|
|
60
61
|
app.command()(setup_cmds.setup)
|
|
61
62
|
|
|
@@ -10,6 +10,9 @@ from pathlib import Path
|
|
|
10
10
|
from inspect import signature
|
|
11
11
|
from typing import Callable
|
|
12
12
|
|
|
13
|
+
from rich.console import Console
|
|
14
|
+
from rich.progress import BarColumn, DownloadColumn, Progress, TaskID, TextColumn, TimeRemainingColumn, TransferSpeedColumn
|
|
15
|
+
|
|
13
16
|
from refactorai_cli.local_engine_runtime import (
|
|
14
17
|
DEFAULT_ENGINE_CONTAINER,
|
|
15
18
|
DEFAULT_ENGINE_IMAGE,
|
|
@@ -39,6 +42,7 @@ STAGE_NAMES = {
|
|
|
39
42
|
"S5": "backend_bootstrap",
|
|
40
43
|
"S6": "validate",
|
|
41
44
|
}
|
|
45
|
+
_setup_console = Console()
|
|
42
46
|
|
|
43
47
|
|
|
44
48
|
class SetupError(RuntimeError):
|
|
@@ -180,7 +184,23 @@ def _stage_s3_runtime(ask_approval: Callable[[str], bool], emit: Callable[[str],
|
|
|
180
184
|
raise SetupError("Runtime installation was not approved.")
|
|
181
185
|
if emit:
|
|
182
186
|
emit(f"Downloading runtime artifact {manifest.runtime_version}...")
|
|
183
|
-
|
|
187
|
+
progress_columns = (
|
|
188
|
+
TextColumn("[progress.description]{task.description}"),
|
|
189
|
+
BarColumn(),
|
|
190
|
+
DownloadColumn(),
|
|
191
|
+
TransferSpeedColumn(),
|
|
192
|
+
TimeRemainingColumn(),
|
|
193
|
+
)
|
|
194
|
+
with Progress(*progress_columns, console=_setup_console, transient=True) as progress:
|
|
195
|
+
task_id: TaskID = progress.add_task("Downloading runtime artifact", total=None)
|
|
196
|
+
|
|
197
|
+
def _on_progress(downloaded: int, total: int | None) -> None:
|
|
198
|
+
update_kwargs = {"completed": int(max(downloaded, 0))}
|
|
199
|
+
if total is not None and total > 0:
|
|
200
|
+
update_kwargs["total"] = total
|
|
201
|
+
progress.update(task_id, **update_kwargs)
|
|
202
|
+
|
|
203
|
+
artifact = download_artifact(manifest.artifact_url, progress_cb=_on_progress)
|
|
184
204
|
if emit:
|
|
185
205
|
emit("Verifying and activating runtime artifact...")
|
|
186
206
|
path = activate_runtime(manifest, artifact, channel="stable")
|
|
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
|
|
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.16 → refactorai_cli-0.2.19}/refactorai_cli.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|