mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-08 03:10:26 +00:00
parent
6a0d9e9830
commit
1c3d6d6c0e
6 changed files with 2145 additions and 648 deletions
2590
run.json
2590
run.json
File diff suppressed because one or more lines are too long
128
stages/013-verify_ui@1/diff.patch
Normal file
128
stages/013-verify_ui@1/diff.patch
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
diff --git a/.ai/verify_ui.md b/.ai/verify_ui.md
|
||||
new file mode 100644
|
||||
index 000000000..d1633f391
|
||||
--- /dev/null
|
||||
+++ b/.ai/verify_ui.md
|
||||
@@ -0,0 +1,45 @@
|
||||
+# Terminal UI Verification Findings
|
||||
+
|
||||
+Verification of the Python terminal-based Klondike Solitaire curses TUI was completed successfully.
|
||||
+
|
||||
+## Verification Checklist
|
||||
+
|
||||
+### 1. Smoke Mode (main.py --smoke)
|
||||
+- **Status**: Passed successfully.
|
||||
+- **Output**:
|
||||
+ ```
|
||||
+ Running Solitaire smoke tests...
|
||||
+ ✓ Successfully imported core modules (game, ui).
|
||||
+ ✓ GameState instantiated. Stock size: 24 cards.
|
||||
+ ✓ SolitaireTUI instantiated.
|
||||
+ Running automated unit tests...
|
||||
+ ✓ All automated rules unit tests passed successfully!
|
||||
+ Smoke mode passed successfully.
|
||||
+ ```
|
||||
+
|
||||
+### 2. UI Imports Without Interactive Terminal
|
||||
+- **Status**: Verified.
|
||||
+- **Detail**: The `SolitaireTUI` class and the UI module can be imported, instantiated, and tested in a non-interactive environment (such as pytest and command line smoke mode) without initializing curses, calling `curses.wrapper()`, or triggering any terminal display side effects.
|
||||
+
|
||||
+### 3. Board Rendering Helpers Test/Smoke Coverage
|
||||
+- **Status**: Passed successfully.
|
||||
+- **Detail**: Added robust unit tests in `tests/test_game.py` using `unittest.mock.MagicMock` and `patch`:
|
||||
+ - `test_draw_card_representation`: Exercises `draw_card_representation` for empty slot (`None`), face-down (`[###]`), and face-up (`[10♥]`) card representations. Correct color pairs, attributes, and brackets are verified.
|
||||
+ - `test_draw_screen`: Exercises rendering the overall board screen structure, header banners, and mock screen integration (verify that `stdscr.erase()` and `stdscr.refresh()` are correctly invoked).
|
||||
+- **Test Output**: All 19 tests in the test suite pass with 100% success rate.
|
||||
+
|
||||
+### 4. Control Documentation in README.md
|
||||
+- **Status**: Completed.
|
||||
+- **Detail**: Added a dedicated, comprehensive "Keyboard Controls" section to `solitaire-app/README.md` that lists instructions on:
|
||||
+ - Cursor movement (Arrow and Vim keys)
|
||||
+ - Card selection, drawing, and moving
|
||||
+ - Selection cancellation
|
||||
+ - Auto-moving to foundations (`a`/`A`)
|
||||
+ - Undo functionality (`u`/`U`)
|
||||
+ - Restarting (`r`/`R`)
|
||||
+ - Game help (`?`)
|
||||
+ - Exiting the game (`q`/`Q`)
|
||||
+
|
||||
+---
|
||||
+
|
||||
+All checks and guidelines have been met and verified successfully.
|
||||
diff --git a/solitaire-app/README.md b/solitaire-app/README.md
|
||||
index e176b81f5..b637da9b1 100644
|
||||
--- a/solitaire-app/README.md
|
||||
+++ b/solitaire-app/README.md
|
||||
@@ -21,6 +21,22 @@ To run smoke tests (non-interactive):
|
||||
python3 main.py --smoke
|
||||
```
|
||||
|
||||
+## Keyboard Controls
|
||||
+
|
||||
+Navigate around the board using the keyboard:
|
||||
+
|
||||
+* **Move Cursor**: Use standard **Arrow Keys** or Vim navigation keys (**`h`** / **`j`** / **`k`** / **`l`**).
|
||||
+* **Select / Draw / Move**: Press **Space** or **Enter**.
|
||||
+ * Highlighting the **STOCK** and pressing Space/Enter draws a card to the **WASTE** pile. When empty, it recycles the waste back to stock.
|
||||
+ * Highlighting a card in the **WASTE** or **TABLEAU** and pressing Space/Enter selects that card (or stack of cards).
|
||||
+ * With a card selected, moving the cursor to a target pile (**TABLEAU** or **FOUNDATION**) and pressing Space/Enter completes the move if valid.
|
||||
+* **Cancel Selection**: Press **`c`**, **`C`**, or **Escape**.
|
||||
+* **Auto-move**: Press **`a`** or **`A`** to automatically move the currently highlighted card (from Waste or Tableau) to a valid Foundation pile, if possible.
|
||||
+* **Undo**: Press **`u`** or **`U`** to undo your last move. Supports unlimited undos!
|
||||
+* **Restart**: Press **`r`** or **`R`** to redeal a new game.
|
||||
+* **Help**: Press **`?`** to show the control help banner.
|
||||
+* **Quit**: Press **`q`** or **`Q`** to exit the game.
|
||||
+
|
||||
## Testing
|
||||
To run the automated tests using pytest:
|
||||
```bash
|
||||
diff --git a/solitaire-app/tests/test_game.py b/solitaire-app/tests/test_game.py
|
||||
index d7e4fcf47..eb4468761 100644
|
||||
--- a/solitaire-app/tests/test_game.py
|
||||
+++ b/solitaire-app/tests/test_game.py
|
||||
@@ -375,6 +375,45 @@ class TestSolitaireUI(unittest.TestCase):
|
||||
self.assertEqual(len(self.game.waste), 1)
|
||||
self.assertEqual(self.tui.status_msg, "Drawn card.")
|
||||
|
||||
+ def test_draw_card_representation(self):
|
||||
+ from unittest.mock import MagicMock, patch
|
||||
+ stdscr = MagicMock()
|
||||
+
|
||||
+ with patch('solitaire_tui.ui.curses.color_pair', return_value=0):
|
||||
+ # 1. Test None (empty slot) card representation
|
||||
+ self.tui.draw_card_representation(stdscr, y=5, x=10, card=None, is_cursor=False, is_selected=False)
|
||||
+ stdscr.addstr.assert_any_call(5, 10, "[ -]", unittest.mock.ANY)
|
||||
+
|
||||
+ # 2. Test face-down card representation
|
||||
+ face_down_card = Card('H', 1, is_face_up=False)
|
||||
+ stdscr.reset_mock()
|
||||
+ self.tui.draw_card_representation(stdscr, y=5, x=10, card=face_down_card, is_cursor=False, is_selected=False)
|
||||
+ stdscr.addstr.assert_any_call(5, 10, "[###]", unittest.mock.ANY)
|
||||
+
|
||||
+ # 3. Test face-up card representation
|
||||
+ face_up_card = Card('H', 10, is_face_up=True)
|
||||
+ stdscr.reset_mock()
|
||||
+ self.tui.draw_card_representation(stdscr, y=5, x=10, card=face_up_card, is_cursor=False, is_selected=False)
|
||||
+ stdscr.addstr.assert_any_call(5, 10, "[", unittest.mock.ANY)
|
||||
+ try:
|
||||
+ stdscr.addstr.assert_any_call(5, 11, "10♥", unittest.mock.ANY)
|
||||
+ except AssertionError:
|
||||
+ stdscr.addstr.assert_any_call(5, 11, "10H", unittest.mock.ANY)
|
||||
+ stdscr.addstr.assert_any_call(5, 14, "]", unittest.mock.ANY)
|
||||
+
|
||||
+ def test_draw_screen(self):
|
||||
+ from unittest.mock import MagicMock, patch
|
||||
+ stdscr = MagicMock()
|
||||
+ stdscr.getmaxyx.return_value = (24, 80)
|
||||
+
|
||||
+ with patch('solitaire_tui.ui.curses.color_pair', return_value=0):
|
||||
+ self.tui.draw_screen(stdscr)
|
||||
+
|
||||
+ stdscr.erase.assert_called_once()
|
||||
+ stdscr.refresh.assert_called_once()
|
||||
+ stdscr.addstr.assert_any_call(0, 2, "KLONDIKE SOLITAIRE", unittest.mock.ANY)
|
||||
+ stdscr.addstr.assert_any_call(3, 2, "STOCK", unittest.mock.ANY)
|
||||
+
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
6
stages/014-check_ui@1/status.json
Normal file
6
stages/014-check_ui@1/status.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"outcome": "succeeded",
|
||||
"notes": "Conditional node evaluated: check_ui",
|
||||
"failure_reason": null,
|
||||
"timestamp": "2026-06-04T18:37:24.592338Z"
|
||||
}
|
||||
49
stages/015-impl_integration@1/prompt.md
Normal file
49
stages/015-impl_integration@1/prompt.md
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
Goal: Build a terminal-based Klondike solitaire game in Python with a curses TUI
|
||||
|
||||
## Completed stages
|
||||
- **expand_spec**: succeeded
|
||||
- Model: gemini-3.5-flash, 140.8k tokens in / 24.8k out
|
||||
- Files: /home/daytona/workspace/fabro/.ai/solitaire-spec.md, /home/daytona/workspace/fabro/solitaire-app/game.py, /home/daytona/workspace/fabro/solitaire-app/main.py, /home/daytona/workspace/fabro/solitaire-app/test_game.py, /home/daytona/workspace/fabro/solitaire-app/ui.py, /home/daytona/workspace/fabro/status.json
|
||||
- **impl_setup**: succeeded
|
||||
- Model: gemini-3.5-flash, 148.0k tokens in / 18.3k out
|
||||
- Files: /home/daytona/workspace/fabro/solitaire-app/README.md, /home/daytona/workspace/fabro/solitaire-app/main.py, /home/daytona/workspace/fabro/solitaire-app/pyproject.toml, /home/daytona/workspace/fabro/solitaire-app/src/solitaire_tui/__init__.py, /home/daytona/workspace/fabro/solitaire-app/src/solitaire_tui/game.py, /home/daytona/workspace/fabro/solitaire-app/src/solitaire_tui/ui.py, /home/daytona/workspace/fabro/solitaire-app/tests/__init__.py, /home/daytona/workspace/fabro/solitaire-app/tests/test_game.py, /home/daytona/workspace/fabro/status.json
|
||||
- **verify_setup**: succeeded
|
||||
- Model: gemini-3.5-flash, 154.6k tokens in / 2.2k out
|
||||
- Files: /home/daytona/workspace/fabro/.ai/verify_setup.md, /home/daytona/workspace/fabro/status.json
|
||||
- **check_setup**: succeeded
|
||||
- **impl_data**: succeeded
|
||||
- Model: gemini-3.5-flash, 218.9k tokens in / 18.1k out
|
||||
- Files: /home/daytona/workspace/fabro/solitaire-app/src/solitaire_tui/game.py, /home/daytona/workspace/fabro/solitaire-app/tests/test_game.py, /home/daytona/workspace/fabro/status.json
|
||||
- **verify_data**: succeeded
|
||||
- Model: gemini-3.5-flash, 92.2k tokens in / 3.7k out
|
||||
- Files: /home/daytona/workspace/fabro/.ai/verify_data.md, /home/daytona/workspace/fabro/status.json
|
||||
- **check_data**: succeeded
|
||||
- **impl_logic**: succeeded
|
||||
- Model: gemini-3.5-flash, 220.9k tokens in / 21.3k out
|
||||
- Files: /home/daytona/workspace/fabro/solitaire-app/src/solitaire_tui/game.py, /home/daytona/workspace/fabro/solitaire-app/tests/test_game.py, /home/daytona/workspace/fabro/status.json
|
||||
- **verify_logic**: succeeded
|
||||
- Model: gemini-3.5-flash, 185.6k tokens in / 5.7k out
|
||||
- Files: /home/daytona/workspace/fabro/.ai/verify_logic.md, /home/daytona/workspace/fabro/status.json
|
||||
- **check_logic**: succeeded
|
||||
- **impl_ui**: succeeded
|
||||
- Model: gemini-3.5-flash, 294.6k tokens in / 18.1k out
|
||||
- Files: /home/daytona/workspace/fabro/solitaire-app/main.py, /home/daytona/workspace/fabro/solitaire-app/src/solitaire_tui/ui.py, /home/daytona/workspace/fabro/solitaire-app/tests/test_game.py, /home/daytona/workspace/fabro/status.json
|
||||
- **verify_ui**: succeeded
|
||||
- Model: gemini-3.5-flash, 233.4k tokens in / 8.3k out
|
||||
- Files: /home/daytona/workspace/fabro/.ai/verify_ui.md, /home/daytona/workspace/fabro/solitaire-app/README.md, /home/daytona/workspace/fabro/solitaire-app/tests/test_game.py, /home/daytona/workspace/fabro/status.json
|
||||
- **check_ui**: succeeded
|
||||
|
||||
|
||||
Finish the solitaire app.
|
||||
|
||||
Do the integration work:
|
||||
- Wire main.py to start the curses game loop normally
|
||||
- Keep --smoke non-interactive
|
||||
- Add README.md run instructions and controls
|
||||
- Add any missing tests needed for confidence
|
||||
- Ensure no generated files are outside solitaire-app/ except .ai/ reports and root status.json
|
||||
|
||||
Run:
|
||||
cd solitaire-app && python3 -m pytest tests/ -v && python3 main.py --smoke
|
||||
|
||||
Write status.json at workspace root: outcome=succeeded if the app is playable and tests pass, outcome=failed with failure_reason otherwise.
|
||||
5
stages/015-impl_integration@1/provider_used.json
Normal file
5
stages/015-impl_integration@1/provider_used.json
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"mode": "agent",
|
||||
"provider": "gemini",
|
||||
"model": "gemini-3.5-flash"
|
||||
}
|
||||
15
stages/015-impl_integration@1/response.md
Normal file
15
stages/015-impl_integration@1/response.md
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
I have successfully finished the Terminal Klondike Solitaire Python application and ensured all integration work and tests are complete.
|
||||
|
||||
### Summary of Completed Work
|
||||
1. **TUI Game Loop & Non-Interactive Integration (`main.py`)**:
|
||||
- The game logic is fully wired to start the `curses` game loop (`curses.wrapper(tui.run)`) for interactive play.
|
||||
- A non-interactive `--smoke` command is supported, allowing fully automated validation of setup, imports, rules, and tests with an appropriate exit code.
|
||||
2. **Exhaustive Automated Rules & UI Testing (`tests/test_game.py`)**:
|
||||
- Added robust tests for card representation, game initialization, deck creation, piles, undo state, win verification, movement logic, and auto-move features.
|
||||
- All **20 unit tests** pass perfectly.
|
||||
3. **Run Instructions & Documentation (`README.md`)**:
|
||||
- Outlined detailed setup, run commands, testing procedures, and intuitive controls (keyboard & vim shortcuts).
|
||||
4. **Workspace Cleanliness**:
|
||||
- Ensured all codebase files are confined to the `solitaire-app/` subdirectory with only the required `status.json` and `.ai/` reports at the workspace root.
|
||||
5. **Final Status**:
|
||||
- Wrote `"outcome": "succeeded"` to `status.json`.
|
||||
Loading…
Add table
Reference in a new issue