Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
bbf24a9
rpg_edit: Add a shared CoderMind Explain View renderer with `write_com
QingtaoLi1 Jun 30, 2026
416764d
fix(cmind): handle RPG updates from git subdirectory workspaces
QingtaoLi1 Jun 30, 2026
2b443e9
fix(cmind): correct update_rpg report delta reporting
QingtaoLi1 Jul 1, 2026
f6b79a6
Update .gitignore.
QingtaoLi1 Jul 1, 2026
9c2db7d
rpg_edit: At _normalize_artifacts() lines 224-240 and _render_artifact
QingtaoLi1 Jul 1, 2026
fd5a29c
fix(cmind): clear smoke test baseline failures
QingtaoLi1 Jul 1, 2026
da7bc2b
rpg_edit: merge to base branch instead of main branch.
QingtaoLi1 Jul 1, 2026
2acefc3
fix: GitRunner init parameter main_branch.
QingtaoLi1 Jul 1, 2026
294727f
fix: handle list-valued RPG meta paths in graph search
QingtaoLi1 Jul 1, 2026
5e6930b
rpg_edit: Add the structured event contract currently missing from the
QingtaoLi1 Jul 1, 2026
f916fe3
rpg_edit: merge 674a41c3
QingtaoLi1 Jul 1, 2026
46423f9
rpg_edit: Extend _publish_review_report() at scripts/rpg_edit/review.p
QingtaoLi1 Jul 1, 2026
fe67ac1
rpg_edit: merge a8151bb7
QingtaoLi1 Jul 1, 2026
40a51ba
fix(dep_graph): missing property.
QingtaoLi1 Jul 1, 2026
ccf9e62
fix(rpg_edit): clear recovered code errors
QingtaoLi1 Jul 1, 2026
915a04b
rpg_edit: Add RPG_EDIT_APPLY_RESULT_FILE beside RPG_EDIT_PLAN_FILE/RPG
QingtaoLi1 Jul 1, 2026
fe2bd7b
rpg_edit: merge a8151bb7
QingtaoLi1 Jul 1, 2026
f54b1bf
version: update to 0.1.10
QingtaoLi1 Jul 2, 2026
32ec402
rpg_edit: Update _retrieval_hit_reason() at scripts/rpg_edit/review.py
QingtaoLi1 Jul 2, 2026
5043b8f
rpg_edit: merge 2e3ac816
QingtaoLi1 Jul 2, 2026
7fb0de9
rpg_edit: Stop producing standalone focused HTML: remove/disable _focu
QingtaoLi1 Jul 3, 2026
827ab8f
rpg_edit: merge 2e3ac816
QingtaoLi1 Jul 3, 2026
137d12f
rpg_edit: At write_command_report() lines 50-56, stop sourcing code_de
QingtaoLi1 Jul 3, 2026
ac93229
rpg_edit: merge 2e3ac816
QingtaoLi1 Jul 3, 2026
67bea34
rpg_edit: Extend _feature_evidence_groups() at lines 510-844 to derive
QingtaoLi1 Jul 3, 2026
09a3214
rpg_edit: merge 46abb9bf
QingtaoLi1 Jul 3, 2026
c7d18cd
rpg_edit: Preserve Step 5b rpg-only apply metadata in _record_apply_re
QingtaoLi1 Jul 6, 2026
bcd6428
rpg_edit: merge 1a62ae13
QingtaoLi1 Jul 6, 2026
87cc10d
rpg_edit: Add explicit report publishing scope handling around `_publi
QingtaoLi1 Jul 6, 2026
50f2ccd
rpg_edit: merge a8151bb7
QingtaoLi1 Jul 6, 2026
88186db
fix(update_graphs): use actual result status for update_rpg report
HuYaSen Jul 6, 2026
905d87b
rpg_edit: At _build_nodes_view (line 435), add focused graph hierarchy
QingtaoLi1 Jul 6, 2026
3de7cf6
rpg_edit: merge 46abb9bf
QingtaoLi1 Jul 6, 2026
fe30e63
decoder: fix abstractmethod usage — make RepoNode ABC and remove abst…
HuYaSen Jul 6, 2026
2c59ad2
rpg_edit: Harden `generate_html()` around lines 414-454 and 608-616 by
QingtaoLi1 Jul 6, 2026
0f82b73
rpg_edit: preserve bundled D3 attribution
QingtaoLi1 Jul 6, 2026
1fe7434
rpg_edit: merge 3ee6aa2f
QingtaoLi1 Jul 6, 2026
4e0c966
rpg_edit: guard rollback-branch to rpg-edit/* and add regression test
HuYaSen Jul 6, 2026
8d43e18
update_graphs: prefer explicit status or infer 'error' when result co…
HuYaSen Jul 6, 2026
bce3c6a
plan: preserve state.message for warnings instead of overwriting reason
HuYaSen Jul 6, 2026
9579945
update_graphs: make _git_delta_files use --relative for subdirectory …
HuYaSen Jul 6, 2026
3d5038a
rpg_edit: In _expected_report_path() around lines 117-118, stop buildi
QingtaoLi1 Jul 7, 2026
0ee64b3
rpg_edit: merge 2faa836d
QingtaoLi1 Jul 7, 2026
f1a87c9
rpg_edit: Modify `_focused_graph_runtime()` at scripts/common/run_repo
QingtaoLi1 Jul 7, 2026
535af58
rpg_edit: merge 46abb9bf
QingtaoLi1 Jul 7, 2026
6089add
review: fix focused graph hierarchy layout
QingtaoLi1 Jul 7, 2026
f245616
rpg_edit: Remove the low-density static focused graph evidence block f
QingtaoLi1 Jul 7, 2026
1003751
rpg_edit: merge 46abb9bf
QingtaoLi1 Jul 7, 2026
b045d15
Merge remote-tracking branch 'origin/dev/rpg_visualization' into dev/…
QingtaoLi1 Jul 7, 2026
8169283
decoder_lang: implement Python backend test hooks
QingtaoLi1 Jul 8, 2026
17c9111
rpg_edit: rework focused graph visualization
QingtaoLi1 Jul 8, 2026
1fc9983
Update rpg_edit command.
QingtaoLi1 Jul 8, 2026
690c124
rpg_edit: Extend `_git_delta_files()` at lines 125-142 to return real
QingtaoLi1 Jul 8, 2026
f8fb535
rpg_edit: merge ff0f6a4d
QingtaoLi1 Jul 8, 2026
657461b
rpg_edit: At lines 1519-1567, remove the focused graph slicing by _FOC
QingtaoLi1 Jul 8, 2026
a939de2
rpg_edit: merge 46abb9bf-052936
QingtaoLi1 Jul 8, 2026
e49ed9c
rpg_edit: In _append_hierarchy_nodes() at lines 963-1024, preserve add
QingtaoLi1 Jul 8, 2026
070223c
rpg_edit: merge a8151bb7
QingtaoLi1 Jul 8, 2026
6da5297
rpg_edit: Enhance `_build_update_focus()` at scripts/update_graphs.py:
QingtaoLi1 Jul 8, 2026
1a580af
rpg_edit: merge update-focus-104832
QingtaoLi1 Jul 8, 2026
79dfe36
rpg_edit: Update _feature_evidence_groups() at lines 1466-1807 and _bu
QingtaoLi1 Jul 8, 2026
59bc961
rpg_edit: merge 46abb9bf-112159
QingtaoLi1 Jul 8, 2026
aaddfad
rpg_edit: Update _review_summary_cards() at lines 1841-1860 so the Sum
QingtaoLi1 Jul 9, 2026
93cb6d6
rpg_edit: merge 2e3ac816
QingtaoLi1 Jul 9, 2026
74af200
rpg_edit: In _render_page() CSS around lines 424-428, add a persistent
QingtaoLi1 Jul 9, 2026
4ad6abc
rpg_edit: merge a8151bb7
QingtaoLi1 Jul 9, 2026
96a386e
rpg_edit: In _render_page() CSS at lines 391-433, convert .focused-gra
QingtaoLi1 Jul 9, 2026
727e827
rpg_edit: merge 2e3ac816
QingtaoLi1 Jul 9, 2026
63b2433
rpg_edit: In _render_page() CSS at lines 424-428, set the selected/act
QingtaoLi1 Jul 9, 2026
0bc306e
rpg_edit: merge 2e3ac816-042727
QingtaoLi1 Jul 9, 2026
83b26d0
rpg_edit: In _focused_graph_default_focus() around lines 785-931, rest
QingtaoLi1 Jul 9, 2026
10f9403
review: fix issues found in impact review
QingtaoLi1 Jul 9, 2026
2194a4b
rpg_edit: merge a8151bb7
QingtaoLi1 Jul 9, 2026
aeb48b7
llm_client: clarify AI CLI subprocess errors
QingtaoLi1 Jul 9, 2026
31a3e8e
rpg_edit: focus graph counts on modified nodes
QingtaoLi1 Jul 9, 2026
c660e33
rpg_edit: In _render_focused_graph() at lines 1828-1889, compute relat
QingtaoLi1 Jul 9, 2026
04c6e33
review: fix issues found in impact review
QingtaoLi1 Jul 9, 2026
52648ca
rpg_edit: merge 46abb9bf-092647
QingtaoLi1 Jul 9, 2026
cb52965
rpg_edit: In _feature_evidence_groups() lines 1494-1846, derive visibl
QingtaoLi1 Jul 9, 2026
6deb099
rpg_edit: merge 46abb9bf-103202
QingtaoLi1 Jul 9, 2026
9d031fb
rpg_edit: In _render_page() CSS at lines 395-403, add in-browser fulls
QingtaoLi1 Jul 9, 2026
23f0f0d
rpg_edit: merge 46abb9bf-110803
QingtaoLi1 Jul 9, 2026
401ec88
encode: recover from corrupt RPG file
QingtaoLi1 Jul 10, 2026
4064f9c
rpg_edit: align focused graph semantic containers
QingtaoLi1 Jul 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CoderMind/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -239,3 +239,5 @@ plans/
.mcp.json
.github/agents/
.github/prompts/

.claude/commands/
2 changes: 1 addition & 1 deletion CoderMind/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "cmind-cli"
version = "0.1.9"
version = "0.1.10"
description = "CoderMind CLI - A tool to generate feature trees for repository planning and code generation."
requires-python = ">=3.12"
dependencies = [
Expand Down
54 changes: 53 additions & 1 deletion CoderMind/scripts/check_code_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,14 @@

import json
import argparse
import sys
from pathlib import Path
from typing import Dict, Any, List, Tuple

SCRIPTS_DIR = Path(__file__).resolve().parent
if str(SCRIPTS_DIR) not in sys.path:
sys.path.insert(0, str(SCRIPTS_DIR))

# Import centralized paths and state loader
from common.paths import (
TASKS_FILE,
Expand All @@ -24,6 +29,8 @@
cmd_for,
REPO_DIR,
)
from common.run_events import ArtifactEvent, CommandRun, StepEvent, VerificationEvent
from common.run_report import write_command_report
from common.execution_state import load_code_gen_state
from common.execution_state import load_code_gen_state as _load_state, save_code_gen_state as _save_state
from common.execution_state import complete_batch as _complete_batch
Expand Down Expand Up @@ -427,6 +434,46 @@ def determine_state(
return result


def _write_code_gen_report(result: Dict[str, Any]) -> str | None:
try:
stats = result.get("stats") or {}
report_path = write_command_report(CommandRun(
command="code_gen",
title="CoderMind code_gen Progress View",
status=result.get("type"),
summary=[
{"label": "state", "value": result.get("type", "")},
{"label": "total", "value": stats.get("total_tasks", 0)},
{"label": "completed", "value": stats.get("completed", 0)},
{"label": "failed", "value": stats.get("failed", 0)},
{"label": "remaining", "value": stats.get("remaining", 0)},
{"label": "current batch", "value": (result.get("current_batch") or {}).get("batch_id", "")},
{"label": "next batch", "value": result.get("next_batch", "")},
],
steps=[
StepEvent(name="determine_state", status=result.get("type"), reason=result.get("message", "")),
StepEvent(name="current_batch", status=(result.get("current_batch") or {}).get("phase", "none"), reason=(result.get("current_batch") or {}).get("file_path", "")),
StepEvent(name="next_action", status="available" if result.get("next_action") else "missing", reason=result.get("next_action", "")),
],
artifacts=[
ArtifactEvent(label="tasks", path=TASKS_FILE),
ArtifactEvent(label="code_gen_state", path=STATE_FILE),
],
verification=[VerificationEvent(name="state", status=result.get("type"), detail=result.get("message", ""))],
evidence={
"type": result.get("type"),
"stats": stats,
"current_batch": result.get("current_batch"),
"next_batch": result.get("next_batch"),
"next_action": result.get("next_action"),
},
))
return str(report_path)
except Exception as exc:
result["report_error"] = str(exc)
return None


def print_status(result: Dict[str, Any], json_output: bool = False) -> None:
"""Print the status in human-readable or JSON format."""
if json_output:
Expand Down Expand Up @@ -474,7 +521,9 @@ def print_status(result: Dict[str, Any], json_output: bool = False) -> None:
# Next batch info
if result.get("next_batch"):
print(f"\n Next Batch: {result['next_batch']}")

if result.get("report_path"):
print(f"\n Report: {result['report_path']}")

# Guidance
print("\n " + "─" * 60)

Expand Down Expand Up @@ -516,6 +565,9 @@ def main():
args = parser.parse_args()

result = determine_state(args.tasks, args.state)
report_path = _write_code_gen_report(result)
if report_path:
result["report_path"] = report_path
print_status(result, json_output=args.json)

# Return exit code based on state
Expand Down
2 changes: 2 additions & 0 deletions CoderMind/scripts/common/assets/d3.v7.min.js

Large diffs are not rendered by default.

107 changes: 107 additions & 0 deletions CoderMind/scripts/common/diff_ranges.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
"""Helpers for matching unified diffs to code entity line ranges."""

from __future__ import annotations

import re
from typing import Any, Mapping, Sequence

_HUNK_RE = re.compile(r"@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@")


def _to_int(value: Any) -> int | None:
try:
return int(value)
except (TypeError, ValueError):
return None


def merge_line_ranges(ranges: Sequence[tuple[int, int]]) -> list[tuple[int, int]]:
ordered = sorted((start, end) for start, end in ranges if start > 0 and end >= start)
merged: list[tuple[int, int]] = []
for start, end in ordered:
if not merged or start > merged[-1][1] + 1:
merged.append((start, end))
else:
merged[-1] = (merged[-1][0], max(merged[-1][1], end))
return merged


def changed_line_ranges_from_diff(diff: Any) -> list[tuple[int, int]]:
if not isinstance(diff, str) or "@@" not in diff:
return []
ranges: list[tuple[int, int]] = []
new_line: int | None = None
for raw_line in diff.splitlines():
match = _HUNK_RE.search(raw_line)
if match:
new_line = int(match.group(1))
continue
if new_line is None:
continue
if raw_line.startswith("\\") or raw_line.startswith("+++") or raw_line.startswith("---"):
continue
prefix = raw_line[:1]
if prefix == "+":
ranges.append((new_line, new_line))
new_line += 1
elif prefix == "-":
continue
else:
new_line += 1
return merge_line_ranges(ranges)


def changed_line_ranges_by_file(code_deltas: Sequence[Mapping[str, Any]]) -> dict[str, list[tuple[int, int]]]:
ranges_by_file: dict[str, list[tuple[int, int]]] = {}
for delta in code_deltas:
file_path = str(delta.get("file") or delta.get("path") or delta.get("after") or delta.get("before") or "")
if not file_path:
continue
ranges = changed_line_ranges_from_diff(delta.get("diff"))
if file_path in ranges_by_file:
ranges_by_file[file_path] = merge_line_ranges(ranges_by_file[file_path] + ranges)
else:
ranges_by_file[file_path] = ranges
return ranges_by_file


def line_range_from_mapping(row: Mapping[str, Any]) -> tuple[int, int] | None:
nested = row.get("line_range") if isinstance(row.get("line_range"), Mapping) else {}
start = _to_int(nested.get("start") if nested else None)
end = _to_int(nested.get("end") if nested else None)
if start is None:
start = _to_int(
row.get("line_start")
or row.get("start_line")
or row.get("lineno")
or row.get("line")
or row.get("start")
)
if end is None:
end = _to_int(row.get("line_end") or row.get("end_line") or row.get("end"))
if start is None:
return None
return (start, end if end is not None else start)


def line_range_overlaps_any(line_range: tuple[int, int] | None, ranges: Sequence[tuple[int, int]]) -> bool:
if line_range is None or not ranges:
return False
start, end = line_range
return any(start <= range_end and end >= range_start for range_start, range_end in ranges)


def row_overlaps_changed_lines(
row: Mapping[str, Any],
file_path: str,
ranges_by_file: Mapping[str, Sequence[tuple[int, int]]],
) -> bool:
return line_range_overlaps_any(line_range_from_mapping(row), ranges_by_file.get(file_path, []))


def is_file_level_node(node_id: Any, row: Mapping[str, Any], file_path: str) -> bool:
node_id_text = str(node_id or "")
node_type = str(row.get("type") or row.get("kind") or "").lower()
if node_type in {"file", "module"}:
return True
return node_id_text == file_path or (":" not in node_id_text and str(row.get("path") or row.get("file") or row.get("module") or "") == file_path)
Loading
Loading