@oh-my-pi/pi-coding-agent 8.2.1 → 8.2.2
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.
- package/CHANGELOG.md +4 -0
- package/package.json +6 -6
- package/src/ipy/prelude.py +0 -182
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
3
|
-
"version": "8.2.
|
|
3
|
+
"version": "8.2.2",
|
|
4
4
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"ompConfig": {
|
|
@@ -75,11 +75,11 @@
|
|
|
75
75
|
"test": "bun test"
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
|
-
"@oh-my-pi/omp-stats": "8.2.
|
|
79
|
-
"@oh-my-pi/pi-agent-core": "8.2.
|
|
80
|
-
"@oh-my-pi/pi-ai": "8.2.
|
|
81
|
-
"@oh-my-pi/pi-tui": "8.2.
|
|
82
|
-
"@oh-my-pi/pi-utils": "8.2.
|
|
78
|
+
"@oh-my-pi/omp-stats": "8.2.2",
|
|
79
|
+
"@oh-my-pi/pi-agent-core": "8.2.2",
|
|
80
|
+
"@oh-my-pi/pi-ai": "8.2.2",
|
|
81
|
+
"@oh-my-pi/pi-tui": "8.2.2",
|
|
82
|
+
"@oh-my-pi/pi-utils": "8.2.2",
|
|
83
83
|
"@openai/agents": "^0.4.3",
|
|
84
84
|
"@sinclair/typebox": "^0.34.46",
|
|
85
85
|
"ajv": "^8.17.1",
|
package/src/ipy/prelude.py
CHANGED
|
@@ -724,188 +724,6 @@ if "__omp_prelude_loaded__" not in globals():
|
|
|
724
724
|
_emit_status("insert_at", path=str(p), line=line_num, lines_inserted=len(new_lines), position=pos)
|
|
725
725
|
return p
|
|
726
726
|
|
|
727
|
-
def _git(*args: str, cwd: str | Path | None = None) -> tuple[int, str, str]:
|
|
728
|
-
"""Run git command, return (returncode, stdout, stderr)."""
|
|
729
|
-
result = subprocess.run(
|
|
730
|
-
["git", *args],
|
|
731
|
-
cwd=str(cwd) if cwd else None,
|
|
732
|
-
capture_output=True,
|
|
733
|
-
text=True,
|
|
734
|
-
)
|
|
735
|
-
return result.returncode, result.stdout, result.stderr
|
|
736
|
-
|
|
737
|
-
@_category("Git")
|
|
738
|
-
def git_status(*, cwd: str | Path | None = None) -> dict:
|
|
739
|
-
"""Get structured git status: {branch, staged, modified, untracked, ahead, behind}."""
|
|
740
|
-
code, out, err = _git("status", "--porcelain=v2", "--branch", cwd=cwd)
|
|
741
|
-
if code != 0:
|
|
742
|
-
_emit_status("git_status", error=err.strip())
|
|
743
|
-
return {}
|
|
744
|
-
|
|
745
|
-
result: dict = {"branch": None, "staged": [], "modified": [], "untracked": [], "ahead": 0, "behind": 0}
|
|
746
|
-
for line in out.splitlines():
|
|
747
|
-
if line.startswith("# branch.head "):
|
|
748
|
-
result["branch"] = line.split(" ", 2)[2]
|
|
749
|
-
elif line.startswith("# branch.ab "):
|
|
750
|
-
parts = line.split()
|
|
751
|
-
for p in parts[2:]:
|
|
752
|
-
if p.startswith("+"):
|
|
753
|
-
result["ahead"] = int(p[1:])
|
|
754
|
-
elif p.startswith("-"):
|
|
755
|
-
result["behind"] = int(p[1:])
|
|
756
|
-
elif line.startswith("1 ") or line.startswith("2 "):
|
|
757
|
-
parts = line.split(" ", 8)
|
|
758
|
-
xy = parts[1]
|
|
759
|
-
path = parts[-1]
|
|
760
|
-
if xy[0] != ".":
|
|
761
|
-
result["staged"].append(path)
|
|
762
|
-
if xy[1] != ".":
|
|
763
|
-
result["modified"].append(path)
|
|
764
|
-
elif line.startswith("? "):
|
|
765
|
-
result["untracked"].append(line[2:])
|
|
766
|
-
|
|
767
|
-
clean = not any([result["staged"], result["modified"], result["untracked"]])
|
|
768
|
-
_emit_status("git_status", branch=result["branch"], staged=len(result["staged"]), modified=len(result["modified"]), untracked=len(result["untracked"]), clean=clean, files=result["staged"][:5] + result["modified"][:5])
|
|
769
|
-
return result
|
|
770
|
-
|
|
771
|
-
@_category("Git")
|
|
772
|
-
def git_diff(
|
|
773
|
-
*paths: str,
|
|
774
|
-
staged: bool = False,
|
|
775
|
-
ref: str | None = None,
|
|
776
|
-
stat: bool = False,
|
|
777
|
-
cwd: str | Path | None = None,
|
|
778
|
-
) -> str:
|
|
779
|
-
"""Show git diff. staged=True for --cached, ref for commit comparison."""
|
|
780
|
-
args = ["diff"]
|
|
781
|
-
if stat:
|
|
782
|
-
args.append("--stat")
|
|
783
|
-
if staged:
|
|
784
|
-
args.append("--cached")
|
|
785
|
-
if ref:
|
|
786
|
-
args.append(ref)
|
|
787
|
-
if paths:
|
|
788
|
-
args.append("--")
|
|
789
|
-
args.extend(paths)
|
|
790
|
-
code, out, err = _git(*args, cwd=cwd)
|
|
791
|
-
if code != 0:
|
|
792
|
-
_emit_status("git_diff", error=err.strip())
|
|
793
|
-
return ""
|
|
794
|
-
lines_count = len(out.splitlines()) if out else 0
|
|
795
|
-
_emit_status("git_diff", staged=staged, ref=ref, lines=lines_count, preview=out[:500])
|
|
796
|
-
return out
|
|
797
|
-
|
|
798
|
-
@_category("Git")
|
|
799
|
-
def git_log(
|
|
800
|
-
n: int = 10,
|
|
801
|
-
*,
|
|
802
|
-
oneline: bool = True,
|
|
803
|
-
ref_range: str | None = None,
|
|
804
|
-
paths: list[str] | None = None,
|
|
805
|
-
cwd: str | Path | None = None,
|
|
806
|
-
) -> list[dict]:
|
|
807
|
-
"""Get git log as list of {sha, subject, author, date}."""
|
|
808
|
-
fmt = "%H%x00%s%x00%an%x00%aI" if not oneline else "%h%x00%s%x00%an%x00%aI"
|
|
809
|
-
args = ["log", f"-{n}", f"--format={fmt}"]
|
|
810
|
-
if ref_range:
|
|
811
|
-
args.append(ref_range)
|
|
812
|
-
if paths:
|
|
813
|
-
args.append("--")
|
|
814
|
-
args.extend(paths)
|
|
815
|
-
code, out, err = _git(*args, cwd=cwd)
|
|
816
|
-
if code != 0:
|
|
817
|
-
_emit_status("git_log", error=err.strip())
|
|
818
|
-
return []
|
|
819
|
-
|
|
820
|
-
commits = []
|
|
821
|
-
for line in out.strip().splitlines():
|
|
822
|
-
parts = line.split("\x00")
|
|
823
|
-
if len(parts) >= 4:
|
|
824
|
-
commits.append({"sha": parts[0], "subject": parts[1], "author": parts[2], "date": parts[3]})
|
|
825
|
-
|
|
826
|
-
_emit_status("git_log", commits=len(commits), entries=[{"sha": c["sha"][:8], "subject": c["subject"][:50]} for c in commits[:5]])
|
|
827
|
-
return commits
|
|
828
|
-
|
|
829
|
-
@_category("Git")
|
|
830
|
-
def git_show(ref: str = "HEAD", *, stat: bool = True, cwd: str | Path | None = None) -> dict:
|
|
831
|
-
"""Show commit details as {sha, subject, author, date, body, files}."""
|
|
832
|
-
args = ["show", ref, "--format=%H%x00%s%x00%an%x00%aI%x00%b", "--no-patch"]
|
|
833
|
-
code, out, err = _git(*args, cwd=cwd)
|
|
834
|
-
if code != 0:
|
|
835
|
-
_emit_status("git_show", ref=ref, error=err.strip())
|
|
836
|
-
return {}
|
|
837
|
-
|
|
838
|
-
parts = out.strip().split("\x00")
|
|
839
|
-
result = {
|
|
840
|
-
"sha": parts[0] if len(parts) > 0 else "",
|
|
841
|
-
"subject": parts[1] if len(parts) > 1 else "",
|
|
842
|
-
"author": parts[2] if len(parts) > 2 else "",
|
|
843
|
-
"date": parts[3] if len(parts) > 3 else "",
|
|
844
|
-
"body": parts[4].strip() if len(parts) > 4 else "",
|
|
845
|
-
"files": [],
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
if stat:
|
|
849
|
-
_, stat_out, _ = _git("show", ref, "--stat", "--format=", cwd=cwd)
|
|
850
|
-
result["files"] = [l.strip() for l in stat_out.strip().splitlines() if l.strip()]
|
|
851
|
-
|
|
852
|
-
_emit_status("git_show", ref=ref, sha=result["sha"][:12], subject=result["subject"][:60], files=len(result["files"]))
|
|
853
|
-
return result
|
|
854
|
-
|
|
855
|
-
@_category("Git")
|
|
856
|
-
def git_file_at(ref: str, path: str, *, lines: tuple[int, int] | None = None, cwd: str | Path | None = None) -> str:
|
|
857
|
-
"""Get file content at ref. Optional lines=(start, end) for range (1-indexed)."""
|
|
858
|
-
code, out, err = _git("show", f"{ref}:{path}", cwd=cwd)
|
|
859
|
-
if code != 0:
|
|
860
|
-
_emit_status("git_file_at", ref=ref, path=path, error=err.strip())
|
|
861
|
-
return ""
|
|
862
|
-
|
|
863
|
-
if lines:
|
|
864
|
-
all_lines = out.splitlines()
|
|
865
|
-
start, end = lines
|
|
866
|
-
start = max(1, start)
|
|
867
|
-
end = min(len(all_lines), end)
|
|
868
|
-
selected = all_lines[start - 1 : end]
|
|
869
|
-
out = "\n".join(selected)
|
|
870
|
-
_emit_status("git_file_at", ref=ref, path=path, start=start, end=end, lines=len(selected))
|
|
871
|
-
return out
|
|
872
|
-
|
|
873
|
-
_emit_status("git_file_at", ref=ref, path=path, chars=len(out))
|
|
874
|
-
return out
|
|
875
|
-
|
|
876
|
-
@_category("Git")
|
|
877
|
-
def git_branch(*, cwd: str | Path | None = None) -> dict:
|
|
878
|
-
"""Get branches: {current, local, remote}."""
|
|
879
|
-
code, out, _ = _git("branch", "-a", "--format=%(refname:short)%00%(HEAD)", cwd=cwd)
|
|
880
|
-
if code != 0:
|
|
881
|
-
_emit_status("git_branch", error="failed to list branches")
|
|
882
|
-
return {"current": None, "local": [], "remote": []}
|
|
883
|
-
|
|
884
|
-
result: dict = {"current": None, "local": [], "remote": []}
|
|
885
|
-
for line in out.strip().splitlines():
|
|
886
|
-
parts = line.split("\x00")
|
|
887
|
-
name = parts[0]
|
|
888
|
-
is_current = len(parts) > 1 and parts[1] == "*"
|
|
889
|
-
if is_current:
|
|
890
|
-
result["current"] = name
|
|
891
|
-
if name.startswith("remotes/") or "/" in name and not name.startswith("feature/"):
|
|
892
|
-
result["remote"].append(name)
|
|
893
|
-
else:
|
|
894
|
-
result["local"].append(name)
|
|
895
|
-
if is_current:
|
|
896
|
-
result["current"] = name
|
|
897
|
-
|
|
898
|
-
_emit_status("git_branch", current=result["current"], local=len(result["local"]), remote=len(result["remote"]), branches=result["local"][:10])
|
|
899
|
-
return result
|
|
900
|
-
|
|
901
|
-
@_category("Git")
|
|
902
|
-
def git_has_changes(*, cwd: str | Path | None = None) -> bool:
|
|
903
|
-
"""Check if there are uncommitted changes (staged or unstaged)."""
|
|
904
|
-
code, out, _ = _git("status", "--porcelain", cwd=cwd)
|
|
905
|
-
has_changes = bool(out.strip())
|
|
906
|
-
_emit_status("git_has_changes", has_changes=has_changes)
|
|
907
|
-
return has_changes
|
|
908
|
-
|
|
909
727
|
@_category("Agent")
|
|
910
728
|
def output(
|
|
911
729
|
*ids: str,
|