Skip to content

Prompt to initialize app when no config is found#654

Merged
phinze merged 3 commits intomainfrom
phinze/mir-518-deploy-ux-prompt-init-and-infer-name-when-missing
Mar 10, 2026
Merged

Prompt to initialize app when no config is found#654
phinze merged 3 commits intomainfrom
phinze/mir-518-deploy-ux-prompt-init-and-infer-name-when-missing

Conversation

@phinze
Copy link
Copy Markdown
Contributor

@phinze phinze commented Mar 9, 2026

Running any app command without a .miren/app.toml used to give you a pretty unhelpful "app is required" error. Now it meets you where you are — if you're on a TTY, it infers an app name from your directory, offers to run miren init for you, and gets on with it. In CI or piped contexts, the error message tells you what to do next.

The init logic got pulled into shared inferAppName and initApp helpers so both the miren init command and the AppCentric.Validate prompt go through the same path. This lives in Validate rather than just Deploy, so every app command gets the zero-config onramp for free.

UX Demo

Interactive (TTY) — no config, first deploy:

~/my-cool-app $ miren deploy
  Looks like this directory isn't set up yet. Run 'miren init' to create app "my-cool-app" here? (Y/n)
Deploying my-cool-app...

Non-interactive (CI/piped) — clear guidance:

$ miren deploy 2>&1
error: no app configuration found — run 'miren init' to get started, or pass -a <name>

Already initialized — no change, works as before:

~/my-cool-app $ cat .miren/app.toml
name = "my-cool-app"
~/my-cool-app $ miren deploy
Deploying my-cool-app...

Closes MIR-518

When any AppCentric command runs without an app name and no
.miren/app.toml, we now infer a name from the directory and offer
to run init inline. In non-interactive contexts, the error message
points users to `miren init` or the -a flag instead of the old
bare "app is required".

Extracted inferAppName and initApp helpers from the Init command
so both the interactive Validate prompt and the Init command share
the same logic.
@phinze phinze requested a review from a team as a code owner March 9, 2026 20:58
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 9, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 94766231-21bb-44cd-9558-a3cfa8502da0

📥 Commits

Reviewing files that changed from the base of the PR and between bb78ddf and 196f800.

📒 Files selected for processing (1)
  • cli/commands/app.go

📝 Walkthrough

Walkthrough

When no app name is provided, the command now infers a name from the working directory and may prompt to initialize an app in that directory. App initialization logic was extracted into inferAppName (sanitizes directory names) and initApp (creates .miren/app.toml, errors on preexisting config, ensures runtime dir). Init was refactored to use these helpers. Tests were added/updated for inferAppName and error messaging.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
cli/commands/app_test.go (1)

21-40: Consider adding edge case tests for inferAppName.

The test covers common cases well, but some edge cases are missing that could cause unexpected behavior:

  • Empty directory string
  • Root path "/"
  • Paths ending with trailing slash (e.g., "/home/user/my-app/")
  • Paths with consecutive special characters (e.g., "my--app", "my__app")

These edge cases could reveal issues with filepath.Base behavior or the sanitization logic.

🧪 Suggested additional test cases
 	tests := []struct {
 		dir  string
 		want string
 	}{
 		{"/home/user/my-app", "my-app"},
 		{"/home/user/My App", "my-app"},
 		{"/home/user/my_app", "my-app"},
 		{"/home/user/MyApp", "myapp"},
 		{"/home/user/HELLO", "hello"},
+		{"/home/user/my-app/", "my-app"},
+		{"/home/user/my--app", "my--app"},
+		{"/home/user/my__app", "my--app"},
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cli/commands/app_test.go` around lines 21 - 40, Extend TestInferAppName to
add edge-case table entries for inferAppName: include an empty string dir (""),
root path ("/"), a path with trailing slash (e.g., "/home/user/my-app/"), and
names with consecutive special characters (e.g., "/home/user/my--app" and
"/home/user/my__app"); update the tests to assert the expected normalized
outputs for these cases so inferAppName's handling of filepath.Base and
sanitization is verified.
cli/commands/app.go (1)

77-84: Prompt cancellation and error both return same generic message.

When the user declines the prompt (!confirmed) or an error occurs (err != nil), they get the same error message. Consider distinguishing these cases: a user explicitly declining might warrant a different message than an unexpected prompt error.

💡 Suggested differentiation
 			confirmed, err := ui.Confirm(
 				ui.WithMessage(fmt.Sprintf("No app configuration found. Initialize app %q in this directory?", appName)),
 				ui.WithDefault(true),
 				ui.WithIndent("  "),
 			)
-			if err != nil || !confirmed {
-				return fmt.Errorf("no app configured; run 'miren init' to set up your app, or use -a <name>")
+			if err != nil {
+				return fmt.Errorf("prompt failed: %w", err)
+			}
+			if !confirmed {
+				return fmt.Errorf("initialization declined; run 'miren init' to set up your app later, or use -a <name>")
 			}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cli/commands/app.go` around lines 77 - 84, Differentiate between a user
cancellation and an actual prompt error in the ui.Confirm handling: check err
first and return a wrapped/explicit error (including err) when ui.Confirm
returns an error, and return a different user-friendly cancellation message when
confirmed is false (e.g., "operation cancelled by user; run 'miren init' to set
up your app or use -a <name>"). Update the block around ui.Confirm (variables:
ui.Confirm, confirmed, err, appName) so the two branches produce distinct
messages and preserve original guidance.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cli/commands/app.go`:
- Around line 90-100: The reload logic after initialization uses a.Dir checks
that differ from the earlier initial load and may not match the actual directory
used by initApp (workDir); update the reload to use the exact same location used
during init by calling appconfig.LoadAppConfigUnder(workDir) (or otherwise use
the same conditional that was used for the initial load) so that the config is
consistently reloaded from the true working directory; reference the variables
a.Dir and workDir and the functions appconfig.LoadAppConfigUnder and
appconfig.LoadAppConfig when making this change.

---

Nitpick comments:
In `@cli/commands/app_test.go`:
- Around line 21-40: Extend TestInferAppName to add edge-case table entries for
inferAppName: include an empty string dir (""), root path ("/"), a path with
trailing slash (e.g., "/home/user/my-app/"), and names with consecutive special
characters (e.g., "/home/user/my--app" and "/home/user/my__app"); update the
tests to assert the expected normalized outputs for these cases so
inferAppName's handling of filepath.Base and sanitization is verified.

In `@cli/commands/app.go`:
- Around line 77-84: Differentiate between a user cancellation and an actual
prompt error in the ui.Confirm handling: check err first and return a
wrapped/explicit error (including err) when ui.Confirm returns an error, and
return a different user-friendly cancellation message when confirmed is false
(e.g., "operation cancelled by user; run 'miren init' to set up your app or use
-a <name>"). Update the block around ui.Confirm (variables: ui.Confirm,
confirmed, err, appName) so the two branches produce distinct messages and
preserve original guidance.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8d8e4097-8eef-4d54-939f-23c9d5509de3

📥 Commits

Reviewing files that changed from the base of the PR and between 1920774 and 266422e.

📒 Files selected for processing (3)
  • cli/commands/app.go
  • cli/commands/app_test.go
  • cli/commands/init.go

phinze added 2 commits March 9, 2026 16:22
workDir is already resolved to an absolute path, so use
LoadAppConfigUnder(workDir) directly instead of re-checking a.Dir
with slightly different conditions than the initial load.
Make the prompt and error messages more conversational — "Looks like
this directory isn't set up yet" instead of "No app configuration
found", and make it clear we're running miren init for them.
@phinze phinze merged commit bf32d4b into main Mar 10, 2026
13 checks passed
@phinze phinze deleted the phinze/mir-518-deploy-ux-prompt-init-and-infer-name-when-missing branch March 10, 2026 14:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants