refactorai-cli 0.4.7__tar.gz → 0.4.9__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.4.7 → refactorai_cli-0.4.9}/PKG-INFO +1 -1
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/pyproject.toml +1 -1
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/__init__.py +1 -1
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/commands/watch_cmds.py +63 -8
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/review_runner.py +18 -2
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/watch_state.py +1 -1
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli.egg-info/PKG-INFO +1 -1
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/README.md +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/auth.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/client.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/cloud_rr.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/commands/__init__.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/commands/account_cmds.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/commands/auth_cmds.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/commands/branch_cmds.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/commands/cloud_cmds.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/commands/engine_cmds.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/commands/hook_cmds.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/commands/model_cmds.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/commands/request_cmds.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/commands/rules_cmds.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/commands/run_cmds.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/commands/runtime_cmds.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/commands/runtime_proxy_cmds.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/commands/setup_cmds.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/commands/toolchains_cmds.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/commit_queue.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/control_plane.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/credentials.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/dotenv_loader.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/git_scope.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/local_constitution.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/local_engine_runtime.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/local_paths.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/main.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/model_policy.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/refactor_branch_store.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/runtime_manager.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/settings.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli/setup_flow.py +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli.egg-info/SOURCES.txt +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli.egg-info/dependency_links.txt +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli.egg-info/entry_points.txt +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli.egg-info/requires.txt +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/refactorai_cli.egg-info/top_level.txt +0 -0
- {refactorai_cli-0.4.7 → refactorai_cli-0.4.9}/setup.cfg +0 -0
|
@@ -79,6 +79,48 @@ def _preview_for_run(project_root: Path, run_id: str, *, limit: int = 3) -> list
|
|
|
79
79
|
return lines
|
|
80
80
|
|
|
81
81
|
|
|
82
|
+
def _pending_for_run(
|
|
83
|
+
project_root: Path,
|
|
84
|
+
run_id: str,
|
|
85
|
+
*,
|
|
86
|
+
limit: int = 3,
|
|
87
|
+
) -> tuple[int, list[str]]:
|
|
88
|
+
"""Return ``(pending_count, preview_lines)`` for requests created by ``run_id``."""
|
|
89
|
+
if not run_id:
|
|
90
|
+
return 0, []
|
|
91
|
+
try:
|
|
92
|
+
from refactor_core.refactor_requests import IN_PROGRESS, PENDING, list_requests
|
|
93
|
+
except Exception:
|
|
94
|
+
return 0, []
|
|
95
|
+
try:
|
|
96
|
+
requests = list_requests(project_root)
|
|
97
|
+
except Exception:
|
|
98
|
+
return 0, []
|
|
99
|
+
matches = [
|
|
100
|
+
rr
|
|
101
|
+
for rr in requests
|
|
102
|
+
if str(getattr(rr, "created_by_run", "") or "") == run_id
|
|
103
|
+
and str(getattr(rr, "status", "") or "") in {PENDING, IN_PROGRESS}
|
|
104
|
+
]
|
|
105
|
+
if not matches:
|
|
106
|
+
return 0, []
|
|
107
|
+
lines: list[str] = []
|
|
108
|
+
for rr in matches[: max(1, limit)]:
|
|
109
|
+
sev = str(getattr(rr, "severity", "medium") or "medium").lower()
|
|
110
|
+
location = str(getattr(rr, "location", "") or "").strip() or str(
|
|
111
|
+
getattr(rr, "file_path", "") or "(unknown location)"
|
|
112
|
+
)
|
|
113
|
+
rec = _truncate(
|
|
114
|
+
str(getattr(rr, "recommendation", "") or getattr(rr, "rationale", "") or "").strip(),
|
|
115
|
+
limit=100,
|
|
116
|
+
)
|
|
117
|
+
if rec:
|
|
118
|
+
lines.append(f"[{sev}] {location} - {rec}")
|
|
119
|
+
else:
|
|
120
|
+
lines.append(f"[{sev}] {location}")
|
|
121
|
+
return len(matches), lines
|
|
122
|
+
|
|
123
|
+
|
|
82
124
|
def _resolve_repo(project_root: Path | None) -> Path:
|
|
83
125
|
root = git_scope.repo_root(project_root or Path.cwd())
|
|
84
126
|
if not root:
|
|
@@ -157,7 +199,11 @@ def process_pending(
|
|
|
157
199
|
if on_update:
|
|
158
200
|
on_update(state)
|
|
159
201
|
intent = intent_for(node.sha) if intent_for else None
|
|
160
|
-
outcome = runner.run(
|
|
202
|
+
outcome = runner.run(
|
|
203
|
+
sha=node.sha,
|
|
204
|
+
intent=intent,
|
|
205
|
+
yes_full_project=(node.scope_mode == "full"),
|
|
206
|
+
)
|
|
161
207
|
if outcome.run_id:
|
|
162
208
|
outcome.rr_preview = _preview_for_run(project_root, outcome.run_id)
|
|
163
209
|
state.apply_outcome(node.sha, outcome)
|
|
@@ -171,7 +217,7 @@ def _read_key(timeout: float) -> str:
|
|
|
171
217
|
"""Non-blocking key read on a POSIX TTY, normalized to a token.
|
|
172
218
|
|
|
173
219
|
Returns ``up``/``down`` for arrow keys, the raw character for normal keys
|
|
174
|
-
(
|
|
220
|
+
(used for hotkeys like ``[r]`` and ``[f]``), ``esc`` for a
|
|
175
221
|
bare Escape, or ``""`` when nothing was pressed / the terminal is not
|
|
176
222
|
interactive. Sleeps ``timeout`` in the non-interactive case so the caller's
|
|
177
223
|
poll cadence is preserved.
|
|
@@ -222,7 +268,7 @@ def build_action_command(action: str, sha: str, *, executable: str = "refactor")
|
|
|
222
268
|
# Commit-scoped so `[r]` resolves THIS commit's requests (docs/41 Phase 4).
|
|
223
269
|
return [executable, "code", "--commit", sha]
|
|
224
270
|
if action == "refresh":
|
|
225
|
-
# `[
|
|
271
|
+
# `[f]` regenerates the requests for this commit before resolving.
|
|
226
272
|
return [executable, "code", "--commit", sha, "--refresh-requests"]
|
|
227
273
|
if action == "diff":
|
|
228
274
|
# Shows the pending refactor-request patch diffs (not the git diff).
|
|
@@ -276,10 +322,19 @@ def _run_action(live, project_root: Path, action: str, node, state: WatchState)
|
|
|
276
322
|
console.print(f"\n[bold bright_cyan]watch:[/bold bright_cyan] {action} for "
|
|
277
323
|
f"[yellow]{node.short_sha}[/yellow] ({node.branch or 'detached'})\n")
|
|
278
324
|
_launch_interactive(cmd, project_root)
|
|
279
|
-
if action
|
|
280
|
-
#
|
|
281
|
-
#
|
|
325
|
+
if action == "refresh":
|
|
326
|
+
# `[f]` explicitly regenerates requests, so re-review this commit on the
|
|
327
|
+
# next pass.
|
|
282
328
|
state.requeue(node.sha)
|
|
329
|
+
elif action == "code":
|
|
330
|
+
# `[r]` is resolve/reuse. Do NOT auto re-review here (that can regenerate
|
|
331
|
+
# duplicate-looking findings); instead reflect current pending requests
|
|
332
|
+
# from the existing run in-place.
|
|
333
|
+
node_after = state.get(node.sha)
|
|
334
|
+
if node_after and node_after.run_id:
|
|
335
|
+
pending_count, preview = _pending_for_run(project_root, node_after.run_id)
|
|
336
|
+
node_after.rr_count = pending_count
|
|
337
|
+
node_after.rr_preview = preview
|
|
283
338
|
console.print("\n[dim]watch: returning to the Refactor Terminal...[/dim]")
|
|
284
339
|
live.start()
|
|
285
340
|
|
|
@@ -311,10 +366,10 @@ def _run_tui(project_root: Path, state: WatchState, runner: ReviewRunner) -> Non
|
|
|
311
366
|
state.move_selection(-1)
|
|
312
367
|
elif key in ("down", "j"):
|
|
313
368
|
state.move_selection(+1)
|
|
314
|
-
elif key in ("r", "
|
|
369
|
+
elif key in ("r", "f", "d", "m", "x"):
|
|
315
370
|
action = {
|
|
316
371
|
"r": "code",
|
|
317
|
-
"
|
|
372
|
+
"f": "refresh",
|
|
318
373
|
"d": "diff",
|
|
319
374
|
"m": "merge",
|
|
320
375
|
"x": "drop",
|
|
@@ -52,7 +52,13 @@ class ReviewOutcome:
|
|
|
52
52
|
class ReviewRunner(Protocol):
|
|
53
53
|
"""Runs a commit-scoped review and returns a structured outcome."""
|
|
54
54
|
|
|
55
|
-
def run(
|
|
55
|
+
def run(
|
|
56
|
+
self,
|
|
57
|
+
*,
|
|
58
|
+
sha: str,
|
|
59
|
+
intent: str | None = None,
|
|
60
|
+
yes_full_project: bool = False,
|
|
61
|
+
) -> ReviewOutcome: ...
|
|
56
62
|
|
|
57
63
|
|
|
58
64
|
def parse_review_output(sha: str, stdout: str, returncode: int) -> ReviewOutcome:
|
|
@@ -111,10 +117,20 @@ class SubprocessReviewRunner:
|
|
|
111
117
|
self.timeout = timeout
|
|
112
118
|
self.extra_args = list(extra_args or [])
|
|
113
119
|
|
|
114
|
-
def run(
|
|
120
|
+
def run(
|
|
121
|
+
self,
|
|
122
|
+
*,
|
|
123
|
+
sha: str,
|
|
124
|
+
intent: str | None = None,
|
|
125
|
+
yes_full_project: bool = False,
|
|
126
|
+
) -> ReviewOutcome:
|
|
115
127
|
cmd = [self.executable, "review", "--commit", sha, *self.extra_args]
|
|
116
128
|
if intent and intent.strip():
|
|
117
129
|
cmd += ["--intent", intent.strip()]
|
|
130
|
+
if yes_full_project:
|
|
131
|
+
# `watch` runs review in a captured subprocess. For root commits, force
|
|
132
|
+
# non-interactive confirmation so the loop never blocks on a hidden prompt.
|
|
133
|
+
cmd.append("--yes-full-project")
|
|
118
134
|
# Wide, non-interactive output so rich does not wrap the status lines the
|
|
119
135
|
# parser depends on.
|
|
120
136
|
env = dict(os.environ, COLUMNS="200", NO_COLOR="1")
|
|
@@ -329,7 +329,7 @@ def render_graph(state: WatchState, *, now: datetime | None = None, width: int =
|
|
|
329
329
|
_with_pad(
|
|
330
330
|
Text.from_markup(
|
|
331
331
|
"[dim]\\[↑/↓ or j/k][/dim] select [bold]\\[r][/bold] refactor "
|
|
332
|
-
"[bold]\\[
|
|
332
|
+
"[bold]\\[f][/bold] fresh review [bold]\\[d][/bold] diff "
|
|
333
333
|
"[bold]\\[m][/bold] merge [bold]\\[x][/bold] drop "
|
|
334
334
|
"[bold]\\[p][/bold] push [bold]\\[q][/bold] quit"
|
|
335
335
|
)
|
|
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
|