implementing -i flag where user can drop inside of a new session. similar to -p but interactive instead

hems created

Change summary

internal/cmd/root.go                          |  7 ++
internal/tui/components/chat/editor/editor.go | 13 +++++
internal/tui/page/chat/chat.go                | 50 ++++++++++++++++----
internal/tui/tui.go                           |  4 
4 files changed, 59 insertions(+), 15 deletions(-)

Detailed changes

internal/cmd/root.go 🔗

@@ -43,6 +43,9 @@ to assist developers in writing, debugging, and understanding code directly from
   # Run a single non-interactive prompt with JSON output format
   crush -p "Explain the use of context in Go" -f json
 
+  # Start interactive session with initial prompt
+  crush -i "Explain the use of context in Go"
+
   # Run in dangerous mode (auto-accept all permissions)
   crush -y
   `,
@@ -52,6 +55,7 @@ to assist developers in writing, debugging, and understanding code directly from
 		debug, _ := cmd.Flags().GetBool("debug")
 		cwd, _ := cmd.Flags().GetString("cwd")
 		prompt, _ := cmd.Flags().GetString("prompt")
+		initial, _ := cmd.Flags().GetString("initial")
 		quiet, _ := cmd.Flags().GetBool("quiet")
 		yolo, _ := cmd.Flags().GetBool("yolo")
 
@@ -107,7 +111,7 @@ to assist developers in writing, debugging, and understanding code directly from
 
 		// Set up the TUI.
 		program := tea.NewProgram(
-			tui.New(app),
+			tui.New(app, initial),
 			tea.WithAltScreen(),
 			tea.WithContext(ctx),
 			tea.WithMouseCellMotion(),            // Use cell motion instead of all motion to reduce event flooding
@@ -141,6 +145,7 @@ func init() {
 	rootCmd.Flags().BoolP("help", "h", false, "Help")
 	rootCmd.Flags().BoolP("debug", "d", false, "Debug")
 	rootCmd.Flags().StringP("prompt", "p", "", "Prompt to run in non-interactive mode")
+	rootCmd.Flags().StringP("initial", "i", "", "Initial prompt to start interactive session with")
 	rootCmd.Flags().BoolP("yolo", "y", false, "Automatically accept all permissions (dangerous mode)")
 
 	// Add quiet flag to hide spinner in non-interactive mode

internal/tui/components/chat/editor/editor.go 🔗

@@ -37,6 +37,7 @@ type Editor interface {
 	SetSession(session session.Session) tea.Cmd
 	IsCompletionsOpen() bool
 	Cursor() *tea.Cursor
+	SendMessage() tea.Cmd
 }
 
 type FileCompletionItem struct {
@@ -442,7 +443,11 @@ func (c *editorCmp) IsCompletionsOpen() bool {
 	return c.isCompletionsOpen
 }
 
-func New(app *app.App) Editor {
+func (c *editorCmp) SendMessage() tea.Cmd {
+	return c.send()
+}
+
+func New(app *app.App, initialPrompt string) Editor {
 	t := styles.CurrentTheme()
 	ta := textarea.New()
 	ta.SetStyles(t.S().TextArea)
@@ -462,6 +467,12 @@ func New(app *app.App) Editor {
 	ta.SetVirtualCursor(false)
 	ta.Focus()
 
+	// Set initial prompt if provided
+	if initialPrompt != "" {
+		ta.SetValue(initialPrompt)
+		ta.MoveToEnd()
+	}
+
 	return &editorCmp{
 		// TODO: remove the app instance from here
 		app:      app,

internal/tui/page/chat/chat.go 🔗

@@ -110,19 +110,32 @@ type chatPage struct {
 	splashFullScreen bool
 	isOnboarding     bool
 	isProjectInit    bool
+	
+	// Initial prompt to send automatically
+	initialPrompt string
 }
 
-func New(app *app.App) ChatPage {
-	return &chatPage{
-		app:         app,
-		keyMap:      DefaultKeyMap(),
-		header:      header.New(app.LSPClients),
-		sidebar:     sidebar.New(app.History, app.LSPClients, false),
-		chat:        chat.New(app),
-		editor:      editor.New(app),
-		splash:      splash.New(),
-		focusedPane: PanelTypeSplash,
+func New(app *app.App, initialPrompt string) ChatPage {
+	chatPage := &chatPage{
+		app:           app,
+		keyMap:        DefaultKeyMap(),
+		header:        header.New(app.LSPClients),
+		sidebar:       sidebar.New(app.History, app.LSPClients, false),
+		chat:          chat.New(app),
+		editor:        editor.New(app, initialPrompt),
+		splash:        splash.New(),
+		focusedPane:   PanelTypeSplash,
+		initialPrompt: initialPrompt,
 	}
+
+	// If we have an initial prompt and the app is configured, focus the editor
+	if initialPrompt != "" && config.HasInitialDataConfig() {
+		if b, _ := config.ProjectNeedsInitialization(); !b {
+			chatPage.focusedPane = PanelTypeEditor
+		}
+	}
+
+	return chatPage
 }
 
 func (p *chatPage) Init() tea.Cmd {
@@ -132,6 +145,8 @@ func (p *chatPage) Init() tea.Cmd {
 	p.forceCompact = compact
 	p.sidebar.SetCompactMode(p.compact)
 
+	var cmds []tea.Cmd
+
 	// Set splash state based on config
 	if !config.HasInitialDataConfig() {
 		// First-time setup: show model selection
@@ -147,15 +162,22 @@ func (p *chatPage) Init() tea.Cmd {
 		// Ready to chat: focus editor, splash in background
 		p.focusedPane = PanelTypeEditor
 		p.splashFullScreen = false
+		
+		// If we have an initial prompt, automatically send it
+		if p.initialPrompt != "" {
+			cmds = append(cmds, p.editor.SendMessage())
+		}
 	}
 
-	return tea.Batch(
+	cmds = append(cmds,
 		p.header.Init(),
 		p.sidebar.Init(),
 		p.chat.Init(),
 		p.editor.Init(),
 		p.splash.Init(),
 	)
+
+	return tea.Batch(cmds...)
 }
 
 func (p *chatPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
@@ -270,6 +292,12 @@ func (p *chatPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 		p.isOnboarding = false
 		p.isProjectInit = false
 		p.focusedPane = PanelTypeEditor
+		
+		// If we have an initial prompt, automatically send it after onboarding completes
+		if p.initialPrompt != "" {
+			return p, tea.Batch(p.SetSize(p.width, p.height), p.editor.SendMessage())
+		}
+		
 		return p, p.SetSize(p.width, p.height)
 	case tea.KeyPressMsg:
 		switch {

internal/tui/tui.go 🔗

@@ -493,8 +493,8 @@ func (a *appModel) View() tea.View {
 }
 
 // New creates and initializes a new TUI application model.
-func New(app *app.App) tea.Model {
-	chatPage := chat.New(app)
+func New(app *app.App, initialPrompt string) tea.Model {
+	chatPage := chat.New(app, initialPrompt)
 	keyMap := DefaultKeyMap()
 	keyMap.pageBindings = chatPage.Bindings()