refactorai-cli 0.5.2__tar.gz → 0.5.5__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.5.2 → refactorai_cli-0.5.5}/PKG-INFO +1 -1
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/pyproject.toml +1 -1
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/__init__.py +1 -1
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/commands/watch_cmds.py +21 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/commit_telemetry.py +88 -2
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli.egg-info/PKG-INFO +1 -1
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/README.md +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/auth.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/client.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/cloud_rr.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/commands/__init__.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/commands/account_cmds.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/commands/auth_cmds.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/commands/branch_cmds.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/commands/cloud_cmds.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/commands/engine_cmds.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/commands/hook_cmds.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/commands/model_cmds.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/commands/pre_push_cmds.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/commands/request_cmds.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/commands/rules_cmds.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/commands/run_cmds.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/commands/runtime_cmds.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/commands/runtime_proxy_cmds.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/commands/setup_cmds.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/commands/toolchains_cmds.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/commit_queue.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/control_plane.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/credentials.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/dotenv_loader.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/git_scope.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/local_constitution.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/local_engine_runtime.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/local_paths.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/main.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/model_policy.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/pre_push_gate.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/refactor_branch_store.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/review_runner.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/runtime_manager.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/settings.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/setup_flow.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/watch_state.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli/watch_supervisor.py +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli.egg-info/SOURCES.txt +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli.egg-info/dependency_links.txt +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli.egg-info/entry_points.txt +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli.egg-info/requires.txt +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/refactorai_cli.egg-info/top_level.txt +0 -0
- {refactorai_cli-0.5.2 → refactorai_cli-0.5.5}/setup.cfg +0 -0
|
@@ -330,6 +330,21 @@ def _report_node(project_root: Path, node) -> None:
|
|
|
330
330
|
pass
|
|
331
331
|
|
|
332
332
|
|
|
333
|
+
def _report_refactor_requests(project_root: Path) -> None:
|
|
334
|
+
"""Best-effort sync of the local RR store to the platform Inbox (docs/44).
|
|
335
|
+
|
|
336
|
+
Fail-open like commit telemetry: no-ops unless the repo is bound to a project
|
|
337
|
+
and never raises. Called after any pass/action that can change RR state so the
|
|
338
|
+
cloud Inbox mirrors the developer's local requests.
|
|
339
|
+
"""
|
|
340
|
+
try:
|
|
341
|
+
from refactorai_cli import commit_telemetry
|
|
342
|
+
|
|
343
|
+
commit_telemetry.post_refactor_requests(project_root)
|
|
344
|
+
except Exception:
|
|
345
|
+
pass
|
|
346
|
+
|
|
347
|
+
|
|
333
348
|
def process_pending(
|
|
334
349
|
project_root: Path,
|
|
335
350
|
state: WatchState,
|
|
@@ -382,6 +397,8 @@ def process_pending(
|
|
|
382
397
|
refresh_finalize(project_root, state)
|
|
383
398
|
if on_update:
|
|
384
399
|
on_update(state)
|
|
400
|
+
if reviewed:
|
|
401
|
+
_report_refactor_requests(project_root)
|
|
385
402
|
return reviewed
|
|
386
403
|
|
|
387
404
|
|
|
@@ -574,6 +591,9 @@ def _run_action(
|
|
|
574
591
|
refactor_branch_store.set_outcome(project_root, branch, refactor_branch_store.OUTCOME_DROPPED)
|
|
575
592
|
_sync_current_branch(project_root, state)
|
|
576
593
|
refresh_finalize(project_root, state)
|
|
594
|
+
# `[r]`/`[m]`/`[d]` can change RR status; mirror the local store to the Inbox.
|
|
595
|
+
if action in ("code", "merge", "drop"):
|
|
596
|
+
_report_refactor_requests(project_root)
|
|
577
597
|
console.print("\n[dim]watch: returning to the Refactor Terminal...[/dim]")
|
|
578
598
|
live.start()
|
|
579
599
|
|
|
@@ -609,6 +629,7 @@ def _run_revert_action(live, project_root: Path, node, state: WatchState) -> Non
|
|
|
609
629
|
build_action_command("revert", node.sha, rr_id=rr_id), project_root
|
|
610
630
|
)
|
|
611
631
|
refresh_finalize(project_root, state)
|
|
632
|
+
_report_refactor_requests(project_root)
|
|
612
633
|
else:
|
|
613
634
|
console.print("[dim]watch: nothing reverted (out of range).[/dim]")
|
|
614
635
|
else:
|
|
@@ -47,6 +47,25 @@ _GATE_MAP = {
|
|
|
47
47
|
"blocked": "high",
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
# Local RR lifecycle states -> server RefactorRequest.status. The server Inbox
|
|
51
|
+
# treats {pending,in_progress,deferred,failed} as open; applied is terminal-done;
|
|
52
|
+
# denied is a human "won't fix" (mapped to suppressed); reverted re-opens the
|
|
53
|
+
# finding locally, so it maps back to pending.
|
|
54
|
+
_RR_STATUS_MAP = {
|
|
55
|
+
"pending": "pending",
|
|
56
|
+
"in_progress": "in_progress",
|
|
57
|
+
"deferred": "deferred",
|
|
58
|
+
"failed": "failed",
|
|
59
|
+
"applied": "applied",
|
|
60
|
+
"denied": "suppressed",
|
|
61
|
+
"reverted": "pending",
|
|
62
|
+
}
|
|
63
|
+
# Local RR states that imply a resolution outcome on the server row.
|
|
64
|
+
_RR_OUTCOME_MAP = {
|
|
65
|
+
"applied": "applied",
|
|
66
|
+
"denied": "suppressed",
|
|
67
|
+
}
|
|
68
|
+
|
|
50
69
|
|
|
51
70
|
def telemetry_disabled() -> bool:
|
|
52
71
|
return str(os.environ.get(ENV_DISABLE, "")).strip().lower() in _TRUTHY
|
|
@@ -130,6 +149,46 @@ def build_commit_event_from_queue(event: dict) -> dict:
|
|
|
130
149
|
}
|
|
131
150
|
|
|
132
151
|
|
|
152
|
+
def build_refactor_request(rr) -> dict:
|
|
153
|
+
"""Map a local ``refactor_core`` RefactorRequest to the RR ingest body.
|
|
154
|
+
|
|
155
|
+
Accepts the dataclass instance (uses attributes) and normalizes the local
|
|
156
|
+
lifecycle status/outcome to the server's enum. Attempts are flattened to a
|
|
157
|
+
compact per-proposal snapshot so the Inbox can show attempt history.
|
|
158
|
+
"""
|
|
159
|
+
status = _RR_STATUS_MAP.get(str(getattr(rr, "status", "") or "").strip().lower(), "pending")
|
|
160
|
+
outcome = _RR_OUTCOME_MAP.get(str(getattr(rr, "status", "") or "").strip().lower())
|
|
161
|
+
attempts: list[dict] = []
|
|
162
|
+
for att in getattr(rr, "attempts", None) or []:
|
|
163
|
+
to_dict = getattr(att, "to_dict", None)
|
|
164
|
+
if callable(to_dict):
|
|
165
|
+
try:
|
|
166
|
+
attempts.append(to_dict())
|
|
167
|
+
continue
|
|
168
|
+
except Exception:
|
|
169
|
+
pass
|
|
170
|
+
if isinstance(att, dict):
|
|
171
|
+
attempts.append(att)
|
|
172
|
+
return {
|
|
173
|
+
"rr_id": str(getattr(rr, "rr_id", "") or ""),
|
|
174
|
+
"file_path": str(getattr(rr, "file_path", "") or ""),
|
|
175
|
+
"symbol": getattr(rr, "symbol", None),
|
|
176
|
+
"category": str(getattr(rr, "category", "") or ""),
|
|
177
|
+
"severity": str(getattr(rr, "severity", "medium") or "medium"),
|
|
178
|
+
"rationale": str(getattr(rr, "rationale", "") or ""),
|
|
179
|
+
"recommendation": str(getattr(rr, "recommendation", "") or ""),
|
|
180
|
+
"operation_type": str(getattr(rr, "operation_type", "content_patch") or "content_patch"),
|
|
181
|
+
"status": status,
|
|
182
|
+
"outcome": outcome,
|
|
183
|
+
"attempt_count": int(getattr(rr, "attempt_count", 0) or 0),
|
|
184
|
+
"detail": None,
|
|
185
|
+
"attempts": attempts,
|
|
186
|
+
"refactor_branch": str(getattr(rr, "refactor_branch", "") or ""),
|
|
187
|
+
"commit_sha": str(getattr(rr, "commit_sha", "") or ""),
|
|
188
|
+
"reverted": bool(getattr(rr, "reverted", False)),
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
|
|
133
192
|
def _auth_and_project(project_root: Path | str, config: dict | None) -> tuple[object | None, str]:
|
|
134
193
|
if telemetry_disabled():
|
|
135
194
|
return None, ""
|
|
@@ -165,7 +224,9 @@ def post_commit_event(
|
|
|
165
224
|
auth, project_id = _auth_and_project(project_root, config)
|
|
166
225
|
if not auth or not project_id:
|
|
167
226
|
return False
|
|
168
|
-
|
|
227
|
+
# Developer-key ingest path (the JWT-gated endpoint cannot be called from
|
|
228
|
+
# local CLI telemetry, which only has a developer key).
|
|
229
|
+
url = f"{platform_url()}/v1/projects/{project_id}/commit-events/ingest"
|
|
169
230
|
return _post(url, auth.key.key, body, timeout)
|
|
170
231
|
|
|
171
232
|
|
|
@@ -182,11 +243,36 @@ def post_heartbeat(
|
|
|
182
243
|
auth, project_id = _auth_and_project(project_root, config)
|
|
183
244
|
if not auth or not project_id:
|
|
184
245
|
return False
|
|
185
|
-
|
|
246
|
+
# Developer-key ingest path paired with `post_commit_event`.
|
|
247
|
+
url = f"{platform_url()}/v1/projects/{project_id}/watch/heartbeat/ingest"
|
|
186
248
|
body = {"host": host, "branch": branch, "watch_version": watch_version}
|
|
187
249
|
return _post(url, auth.key.key, body, timeout)
|
|
188
250
|
|
|
189
251
|
|
|
252
|
+
def post_refactor_requests(
|
|
253
|
+
project_root: Path | str, *, config: dict | None = None, timeout: float = 8.0
|
|
254
|
+
) -> bool:
|
|
255
|
+
"""Sync the full local RR store to the platform. Best-effort + fail-open.
|
|
256
|
+
|
|
257
|
+
Sends the complete local snapshot (so terminal RRs land as their resolved
|
|
258
|
+
status) and asks the server to reconcile any previously-synced open RRs that
|
|
259
|
+
are no longer present locally (e.g. cleared by a fresh review). Never raises.
|
|
260
|
+
"""
|
|
261
|
+
auth, project_id = _auth_and_project(project_root, config)
|
|
262
|
+
if not auth or not project_id:
|
|
263
|
+
return False
|
|
264
|
+
try:
|
|
265
|
+
from refactor_core.refactor_requests import list_requests
|
|
266
|
+
|
|
267
|
+
requests = list_requests(Path(project_root))
|
|
268
|
+
except Exception:
|
|
269
|
+
return False
|
|
270
|
+
items = [build_refactor_request(rr) for rr in requests]
|
|
271
|
+
url = f"{platform_url()}/v1/projects/{project_id}/refactor-requests/ingest"
|
|
272
|
+
body = {"reconcile": True, "requests": items}
|
|
273
|
+
return _post(url, auth.key.key, body, timeout)
|
|
274
|
+
|
|
275
|
+
|
|
190
276
|
def emit_node(project_root: Path | str, node, *, config: dict | None = None) -> bool:
|
|
191
277
|
"""Build + post a commit event from a watch ``CommitNode``. Never raises."""
|
|
192
278
|
try:
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|