diff --git a/src/project_manager.py b/src/project_manager.py index a003909..66f6f1c 100644 --- a/src/project_manager.py +++ b/src/project_manager.py @@ -424,3 +424,36 @@ def calculate_track_progress(tickets: list) -> dict: "todo": todo } + +def branch_discussion(project_dict: dict, source_id: str, new_id: str, message_index: int) -> None: + """ + Creates a new discussion in project_dict['discussion']['discussions'] by copying + the history from source_id up to (and including) message_index, and sets active to new_id. + """ + if "discussion" not in project_dict or "discussions" not in project_dict["discussion"]: + return + if source_id not in project_dict["discussion"]["discussions"]: + return + + source_disc = project_dict["discussion"]["discussions"][source_id] + new_disc = default_discussion() + new_disc["git_commit"] = source_disc.get("git_commit", "") + # Copy history up to and including message_index + new_disc["history"] = source_disc["history"][:message_index + 1] + + project_dict["discussion"]["discussions"][new_id] = new_disc + project_dict["discussion"]["active"] = new_id + +def promote_take(project_dict: dict, take_id: str, new_id: str) -> None: + """Renames a take_id to new_id in the discussions dict.""" + if "discussion" not in project_dict or "discussions" not in project_dict["discussion"]: + return + if take_id not in project_dict["discussion"]["discussions"]: + return + + disc = project_dict["discussion"]["discussions"].pop(take_id) + project_dict["discussion"]["discussions"][new_id] = disc + + # If the take was active, update the active pointer + if project_dict["discussion"].get("active") == take_id: + project_dict["discussion"]["active"] = new_id diff --git a/tests/test_discussion_takes.py b/tests/test_discussion_takes.py new file mode 100644 index 0000000..7acfdc2 --- /dev/null +++ b/tests/test_discussion_takes.py @@ -0,0 +1,50 @@ +import unittest +from src import project_manager + +class TestDiscussionTakes(unittest.TestCase): + def setUp(self): + self.project_dict = project_manager.default_project("test_branching") + # Populate initial history in 'main' + self.project_dict["discussion"]["discussions"]["main"]["history"] = [ + "User: Message 0", + "AI: Response 0", + "User: Message 1", + "AI: Response 1", + "User: Message 2" + ] + + def test_branch_discussion_creates_new_take(self): + """Verify that branch_discussion copies history up to index and sets active.""" + source_id = "main" + new_id = "take_1" + message_index = 1 + + # This will fail with AttributeError until implemented in project_manager.py + project_manager.branch_discussion(self.project_dict, source_id, new_id, message_index) + + # Asserts + self.assertIn(new_id, self.project_dict["discussion"]["discussions"]) + new_history = self.project_dict["discussion"]["discussions"][new_id]["history"] + self.assertEqual(len(new_history), 2) + self.assertEqual(new_history[0], "User: Message 0") + self.assertEqual(new_history[1], "AI: Response 0") + self.assertEqual(self.project_dict["discussion"]["active"], new_id) + + def test_promote_take_renames_discussion(self): + """Verify that promote_take renames a discussion key.""" + take_id = "take_experimental" + self.project_dict["discussion"]["discussions"][take_id] = project_manager.default_discussion() + self.project_dict["discussion"]["discussions"][take_id]["history"] = ["User: Experimental"] + + new_id = "feature_refined" + + # This will fail with AttributeError until implemented in project_manager.py + project_manager.promote_take(self.project_dict, take_id, new_id) + + # Asserts + self.assertNotIn(take_id, self.project_dict["discussion"]["discussions"]) + self.assertIn(new_id, self.project_dict["discussion"]["discussions"]) + self.assertEqual(self.project_dict["discussion"]["discussions"][new_id]["history"], ["User: Experimental"]) + +if __name__ == "__main__": + unittest.main()