From d71b837c160dbeaf763940518ea58c9b7768032c Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 7 Jan 2026 17:26:37 -0400 Subject: [PATCH] feat: Add --new flag to UI with prefill options for title, template, participants, context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Opens new discussion dialog on launch with optional pre-filled values. Enables integration with development-hub for launching discussions from todos. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- src/discussions/cli.py | 25 ++++++++++++++- src/discussions/ui/gui.py | 65 +++++++++++++++++++++++++++++++++------ 2 files changed, 79 insertions(+), 11 deletions(-) diff --git a/src/discussions/cli.py b/src/discussions/cli.py index 064aafc..092f069 100644 --- a/src/discussions/cli.py +++ b/src/discussions/cli.py @@ -372,6 +372,15 @@ def cmd_ui(args) -> int: else: directory = path + # Parse prefill options + show_new = getattr(args, 'new', False) + prefill_title = getattr(args, 'title', None) + prefill_template = getattr(args, 'template', None) + prefill_context = getattr(args, 'context', None) + prefill_participants = None + if getattr(args, 'participants', None): + prefill_participants = [p.strip().lstrip('@') for p in args.participants.split(',')] + if args.tui: # Launch TUI (urwid-based) try: @@ -380,6 +389,7 @@ def cmd_ui(args) -> int: print("Error: TUI requires urwid. Install with: pip install urwid") print(f"Details: {e}") return 1 + # TUI doesn't support --new yet, just launch normally tui_main(directory, open_file=open_file) else: # Launch GUI (Dear PyGui-based) @@ -395,7 +405,15 @@ def cmd_ui(args) -> int: print(f"TUI also unavailable: {e2}") return 1 return 0 - gui_main(directory, open_file=open_file) + gui_main( + directory, + open_file=open_file, + show_new_dialog=show_new, + prefill_title=prefill_title, + prefill_template=prefill_template, + prefill_participants=prefill_participants, + prefill_context=prefill_context, + ) return 0 @@ -461,6 +479,11 @@ def main(argv: list[str] = None) -> int: p_ui = subparsers.add_parser("ui", help="Launch interactive UI") p_ui.add_argument("path", nargs="?", help="Discussion file (.md) or directory to browse") p_ui.add_argument("--tui", action="store_true", help="Use terminal UI instead of graphical UI") + p_ui.add_argument("--new", "-n", action="store_true", help="Open new discussion dialog on launch") + p_ui.add_argument("--title", help="Pre-fill title in new discussion dialog (requires --new)") + p_ui.add_argument("--template", help="Pre-select template in new discussion dialog (requires --new)") + p_ui.add_argument("--participants", help="Pre-select participants, comma-separated (requires --new)") + p_ui.add_argument("--context", help="Pre-fill context/description in new discussion dialog (requires --new)") p_ui.set_defaults(func=cmd_ui) args = parser.parse_args(argv) diff --git a/src/discussions/ui/gui.py b/src/discussions/ui/gui.py index 6878376..2eb643e 100644 --- a/src/discussions/ui/gui.py +++ b/src/discussions/ui/gui.py @@ -2454,8 +2454,16 @@ class DiscussionGUI: ("pragmatist", "AI-Pragmatist") ] - def _show_new_discussion_dialog(self): - """Show dialog for creating a new discussion.""" + def _show_new_discussion_dialog(self, prefill_title: str = None, prefill_template: str = None, + prefill_participants: list[str] = None, prefill_context: str = None): + """Show dialog for creating a new discussion. + + Args: + prefill_title: Pre-fill title field + prefill_template: Pre-select template + prefill_participants: Pre-select participants (list of aliases) + prefill_context: Pre-fill context/description field + """ window_tag = "new_discussion_dialog" if dpg.does_item_exist(window_tag): dpg.delete_item(window_tag) @@ -2463,9 +2471,10 @@ class DiscussionGUI: templates = self._get_templates() participants = self._get_participants() - # State for the dialog + # State for the dialog - use prefill if provided, otherwise defaults + default_participants = prefill_participants if prefill_participants else ["architect", "security", "pragmatist"] dialog_state = { - 'selected_participants': ["architect", "security", "pragmatist"], + 'selected_participants': list(default_participants), } def toggle_participant(sender, app_data, user_data): @@ -2545,7 +2554,8 @@ class DiscussionGUI: width=550, height=550, pos=[400, 150], no_collapse=True): dpg.add_text("Title:", color=(150, 200, 255)) - dpg.add_input_text(tag="new_disc_title", width=-1, hint="Enter discussion title") + dpg.add_input_text(tag="new_disc_title", width=-1, hint="Enter discussion title", + default_value=prefill_title or "") dpg.add_spacer(height=5) dpg.add_text("Location:", color=(150, 200, 255)) @@ -2561,10 +2571,15 @@ class DiscussionGUI: dpg.add_spacer(height=10) dpg.add_text("Template:", color=(150, 200, 255)) template_items = templates + ["+ Create New Template..."] + # Use prefill template if valid, otherwise first template or 'feature' + if prefill_template and prefill_template in templates: + default_template = prefill_template + else: + default_template = templates[0] if templates else "feature" dpg.add_combo( items=template_items, tag="new_disc_template", - default_value=templates[0] if templates else "feature", + default_value=default_template, width=-1, callback=on_template_change ) @@ -2582,10 +2597,10 @@ class DiscussionGUI: with dpg.child_window(height=150, border=True): for alias, display_name in participants: - is_default = alias in ["architect", "security", "pragmatist"] + is_selected = alias in dialog_state['selected_participants'] dpg.add_checkbox( label=f"@{alias} ({display_name})", - default_value=is_default, + default_value=is_selected, callback=toggle_participant, user_data=alias ) @@ -2597,7 +2612,8 @@ class DiscussionGUI: multiline=True, width=-1, height=100, - hint="Describe what this discussion is about..." + hint="Describe what this discussion is about...", + default_value=prefill_context or "" ) dpg.add_spacer(height=15) @@ -4139,6 +4155,17 @@ final = json.dumps(parsed)''', self._open_discussion(self._pending_open_file) self._pending_open_file = None + # Show new discussion dialog if requested + if getattr(self, '_pending_new_dialog', None): + prefill = self._pending_new_dialog + self._show_new_discussion_dialog( + prefill_title=prefill.get('title'), + prefill_template=prefill.get('template'), + prefill_participants=prefill.get('participants'), + prefill_context=prefill.get('context'), + ) + self._pending_new_dialog = None + # Manual render loop with background task polling while dpg.is_dearpygui_running(): # Poll for updates from background threads (output, turn completion) @@ -4150,12 +4177,19 @@ final = json.dumps(parsed)''', dpg.destroy_context() -def main(discussions_dir: str = None, open_file: str = None): +def main(discussions_dir: str = None, open_file: str = None, show_new_dialog: bool = False, + prefill_title: str = None, prefill_template: str = None, + prefill_participants: list[str] = None, prefill_context: str = None): """Entry point for GUI. Args: discussions_dir: Directory to browse for discussions open_file: Specific discussion file to open immediately + show_new_dialog: Show new discussion dialog on launch + prefill_title: Pre-fill title in new discussion dialog + prefill_template: Pre-select template in new discussion dialog + prefill_participants: Pre-select participants in new discussion dialog + prefill_context: Pre-fill context in new discussion dialog """ dir_path = Path(discussions_dir) if discussions_dir else None app = DiscussionGUI(dir_path) @@ -4166,6 +4200,17 @@ def main(discussions_dir: str = None, open_file: str = None): else: app._pending_open_file = None + # If new dialog was requested, store prefill data + if show_new_dialog: + app._pending_new_dialog = { + 'title': prefill_title, + 'template': prefill_template, + 'participants': prefill_participants, + 'context': prefill_context, + } + else: + app._pending_new_dialog = None + app.run()