ralph-code 0.6.2__tar.gz → 0.6.3__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.
- {ralph_code-0.6.2/ralph_code.egg-info → ralph_code-0.6.3}/PKG-INFO +7 -1
- {ralph_code-0.6.2 → ralph_code-0.6.3}/README.md +6 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/pyproject.toml +1 -1
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph/__init__.py +1 -1
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph/git_manager.py +9 -4
- {ralph_code-0.6.2 → ralph_code-0.6.3/ralph_code.egg-info}/PKG-INFO +7 -1
- {ralph_code-0.6.2 → ralph_code-0.6.3}/setup.py +1 -1
- {ralph_code-0.6.2 → ralph_code-0.6.3}/tests/test_git_manager.py +55 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/LICENSE +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/MANIFEST.in +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph/__main__.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph/app.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph/claude_runner.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph/colors.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph/config.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph/harness.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph/harness_runner.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph/prd_manager.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph/schemas/ralph_tasks_schema.json +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph/schemas/task_schema.json +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph/spinner.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph/storage.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph/tasks.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph/user_stories.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph/workflow.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph_code.egg-info/SOURCES.txt +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph_code.egg-info/dependency_links.txt +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph_code.egg-info/entry_points.txt +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph_code.egg-info/requires.txt +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/ralph_code.egg-info/top_level.txt +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/setup.cfg +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/tests/test_app.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/tests/test_app_integration.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/tests/test_colors.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/tests/test_config.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/tests/test_harness.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/tests/test_harness_runner.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/tests/test_prd_manager.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/tests/test_spinner.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/tests/test_storage.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/tests/test_tasks.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/tests/test_user_stories.py +0 -0
- {ralph_code-0.6.2 → ralph_code-0.6.3}/tests/test_workflow.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ralph-code
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.3
|
|
4
4
|
Summary: Automated task implementation with Claude Code and Codex
|
|
5
5
|
Author: Ralph Coding
|
|
6
6
|
License: MIT
|
|
@@ -61,6 +61,12 @@ ralph [OPTIONS] [DIRECTORY]
|
|
|
61
61
|
|
|
62
62
|
## Recent changes
|
|
63
63
|
|
|
64
|
+
Version `0.6.3` includes:
|
|
65
|
+
- Safer git integration for staged-file commit checks
|
|
66
|
+
- Correct staged diff generation
|
|
67
|
+
- Deduplicated unstaged file reporting
|
|
68
|
+
- Clearer errors when `git` is not available
|
|
69
|
+
|
|
64
70
|
Version `0.6.2` includes:
|
|
65
71
|
- Bounded non-interactive harness execution with timeout and turn limits
|
|
66
72
|
- Structured `tasks.json` generation for more reliable PRD conversion
|
|
@@ -24,6 +24,12 @@ ralph [OPTIONS] [DIRECTORY]
|
|
|
24
24
|
|
|
25
25
|
## Recent changes
|
|
26
26
|
|
|
27
|
+
Version `0.6.3` includes:
|
|
28
|
+
- Safer git integration for staged-file commit checks
|
|
29
|
+
- Correct staged diff generation
|
|
30
|
+
- Deduplicated unstaged file reporting
|
|
31
|
+
- Clearer errors when `git` is not available
|
|
32
|
+
|
|
27
33
|
Version `0.6.2` includes:
|
|
28
34
|
- Bounded non-interactive harness execution with timeout and turn limits
|
|
29
35
|
- Structured `tasks.json` generation for more reliable PRD conversion
|
|
@@ -26,6 +26,8 @@ class GitManager:
|
|
|
26
26
|
check=check,
|
|
27
27
|
)
|
|
28
28
|
return result
|
|
29
|
+
except FileNotFoundError as e:
|
|
30
|
+
raise GitError("Git executable not found on PATH") from e
|
|
29
31
|
except subprocess.CalledProcessError as e:
|
|
30
32
|
raise GitError(f"Git command failed: git {' '.join(args)}\n{e.stderr}")
|
|
31
33
|
|
|
@@ -241,19 +243,22 @@ class GitManager:
|
|
|
241
243
|
Returns files that have changes not yet added to the staging area.
|
|
242
244
|
This includes both modified tracked files and new untracked files.
|
|
243
245
|
"""
|
|
244
|
-
files = []
|
|
246
|
+
files: list[str] = []
|
|
247
|
+
seen: set[str] = set()
|
|
245
248
|
|
|
246
249
|
# Get modified but unstaged files
|
|
247
250
|
result = self._run_git("diff", "--name-only")
|
|
248
251
|
for f in result.stdout.strip().split("\n"):
|
|
249
|
-
if f:
|
|
252
|
+
if f and f not in seen:
|
|
250
253
|
files.append(f)
|
|
254
|
+
seen.add(f)
|
|
251
255
|
|
|
252
256
|
# Get untracked files
|
|
253
257
|
result = self._run_git("ls-files", "--others", "--exclude-standard")
|
|
254
258
|
for f in result.stdout.strip().split("\n"):
|
|
255
|
-
if f:
|
|
259
|
+
if f and f not in seen:
|
|
256
260
|
files.append(f)
|
|
261
|
+
seen.add(f)
|
|
257
262
|
|
|
258
263
|
return files
|
|
259
264
|
|
|
@@ -264,7 +269,7 @@ class GitManager:
|
|
|
264
269
|
|
|
265
270
|
def get_diff(self, staged: bool = False) -> str:
|
|
266
271
|
"""Get the current diff for stageable files only."""
|
|
267
|
-
files = self.get_stageable_files()
|
|
272
|
+
files = self.get_staged_files() if staged else self.get_stageable_files()
|
|
268
273
|
if not files:
|
|
269
274
|
return ""
|
|
270
275
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ralph-code
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.3
|
|
4
4
|
Summary: Automated task implementation with Claude Code and Codex
|
|
5
5
|
Author: Ralph Coding
|
|
6
6
|
License: MIT
|
|
@@ -61,6 +61,12 @@ ralph [OPTIONS] [DIRECTORY]
|
|
|
61
61
|
|
|
62
62
|
## Recent changes
|
|
63
63
|
|
|
64
|
+
Version `0.6.3` includes:
|
|
65
|
+
- Safer git integration for staged-file commit checks
|
|
66
|
+
- Correct staged diff generation
|
|
67
|
+
- Deduplicated unstaged file reporting
|
|
68
|
+
- Clearer errors when `git` is not available
|
|
69
|
+
|
|
64
70
|
Version `0.6.2` includes:
|
|
65
71
|
- Bounded non-interactive harness execution with timeout and turn limits
|
|
66
72
|
- Structured `tasks.json` generation for more reliable PRD conversion
|
|
@@ -8,7 +8,7 @@ from setuptools import setup, find_packages # type: ignore[import-untyped]
|
|
|
8
8
|
|
|
9
9
|
setup(
|
|
10
10
|
name="ralph-code",
|
|
11
|
-
version="0.6.
|
|
11
|
+
version="0.6.3",
|
|
12
12
|
description="Automated task implementation with Claude Code and Codex",
|
|
13
13
|
author="Ralph Coding",
|
|
14
14
|
packages=find_packages(),
|
|
@@ -18,6 +18,18 @@ class TestGitManagerInit:
|
|
|
18
18
|
assert manager.project_dir == tmp_path
|
|
19
19
|
|
|
20
20
|
|
|
21
|
+
class TestRunGit:
|
|
22
|
+
"""Tests for low-level git command execution."""
|
|
23
|
+
|
|
24
|
+
@patch("ralph.git_manager.subprocess.run", side_effect=FileNotFoundError())
|
|
25
|
+
def test_run_git_handles_missing_git(self, _mock_run: MagicMock, tmp_path: Path) -> None:
|
|
26
|
+
"""Test a missing git executable raises GitError."""
|
|
27
|
+
manager = GitManager(tmp_path)
|
|
28
|
+
|
|
29
|
+
with pytest.raises(GitError, match="Git executable not found on PATH"):
|
|
30
|
+
manager._run_git("status")
|
|
31
|
+
|
|
32
|
+
|
|
21
33
|
class TestIsGitRepo:
|
|
22
34
|
"""Tests for is_git_repo method."""
|
|
23
35
|
|
|
@@ -386,6 +398,49 @@ class TestGetDiff:
|
|
|
386
398
|
|
|
387
399
|
assert "modified content here" in diff
|
|
388
400
|
|
|
401
|
+
def test_get_diff_staged_only_uses_staged_files(self, tmp_path: Path) -> None:
|
|
402
|
+
"""Test staged diffs ignore separate unstaged changes."""
|
|
403
|
+
subprocess.run(["git", "init"], cwd=tmp_path, capture_output=True)
|
|
404
|
+
subprocess.run(["git", "config", "user.email", "test@test.com"], cwd=tmp_path, capture_output=True)
|
|
405
|
+
subprocess.run(["git", "config", "user.name", "Test"], cwd=tmp_path, capture_output=True)
|
|
406
|
+
|
|
407
|
+
staged_file = tmp_path / "staged.py"
|
|
408
|
+
unstaged_file = tmp_path / "unstaged.py"
|
|
409
|
+
staged_file.write_text("before staged")
|
|
410
|
+
unstaged_file.write_text("before unstaged")
|
|
411
|
+
subprocess.run(["git", "add", "."], cwd=tmp_path, capture_output=True)
|
|
412
|
+
subprocess.run(["git", "commit", "-m", "Initial"], cwd=tmp_path, capture_output=True)
|
|
413
|
+
|
|
414
|
+
staged_file.write_text("after staged")
|
|
415
|
+
unstaged_file.write_text("after unstaged")
|
|
416
|
+
subprocess.run(["git", "add", "staged.py"], cwd=tmp_path, capture_output=True)
|
|
417
|
+
|
|
418
|
+
manager = GitManager(tmp_path)
|
|
419
|
+
diff = manager.get_diff(staged=True)
|
|
420
|
+
|
|
421
|
+
assert "after staged" in diff
|
|
422
|
+
assert "after unstaged" not in diff
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
class TestGetUnstagedFiles:
|
|
426
|
+
"""Tests for get_unstaged_files method."""
|
|
427
|
+
|
|
428
|
+
def test_get_unstaged_files_deduplicates_results(self, tmp_path: Path) -> None:
|
|
429
|
+
"""Test duplicate file names are collapsed while preserving order."""
|
|
430
|
+
manager = GitManager(tmp_path)
|
|
431
|
+
|
|
432
|
+
with patch.object(
|
|
433
|
+
manager,
|
|
434
|
+
"_run_git",
|
|
435
|
+
side_effect=[
|
|
436
|
+
MagicMock(stdout="a.py\nb.py\n"),
|
|
437
|
+
MagicMock(stdout="b.py\nc.py\n"),
|
|
438
|
+
],
|
|
439
|
+
):
|
|
440
|
+
files = manager.get_unstaged_files()
|
|
441
|
+
|
|
442
|
+
assert files == ["a.py", "b.py", "c.py"]
|
|
443
|
+
|
|
389
444
|
|
|
390
445
|
class TestGetLastCommitMessage:
|
|
391
446
|
"""Tests for get_last_commit_message method."""
|
|
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
|