Detailed changes
@@ -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
@@ -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,
@@ -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 {
@@ -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()