Skip to content

feat(gnovm): add interactive gno init wizard#5557

Open
davd-gzl wants to merge 31 commits intognolang:masterfrom
davd-gzl:feat/mod-init-template
Open

feat(gnovm): add interactive gno init wizard#5557
davd-gzl wants to merge 31 commits intognolang:masterfrom
davd-gzl:feat/mod-init-template

Conversation

@davd-gzl
Copy link
Copy Markdown
Member

@davd-gzl davd-gzl commented Apr 20, 2026

Promote 'gno init' to a top-level command with an interactive wizard that scaffolds realm, package, or run script projects with template files. Supports --bare flag for gnomod.toml-only creation, non-TTY fallback, and input validation with retry loops.

Related: #5460

Next step will be gnokey maketx wizard

Promote 'gno init' to a top-level command with an interactive wizard
that scaffolds realm, package, or run script projects with template
files. Supports --bare flag for gnomod.toml-only creation, non-TTY
fallback, go-back navigation with '<', and input validation with
retry loops.

Assisted-By: Claude (OpenCode)
@Gno2D2
Copy link
Copy Markdown
Collaborator

Gno2D2 commented Apr 20, 2026

🛠 PR Checks Summary

🔴 Pending initial approval by a review team member, or review from tech-staff

Manual Checks (for Reviewers):
  • IGNORE the bot requirements for this PR (force green CI check)
Read More

🤖 This bot helps streamline PR reviews by verifying automated checks and providing guidance for contributors and reviewers.

✅ Automated Checks (for Contributors):

🟢 Maintainers must be able to edit this pull request (more info)
🔴 Pending initial approval by a review team member, or review from tech-staff

☑️ Contributor Actions:
  1. Fix any issues flagged by automated checks.
  2. Follow the Contributor Checklist to ensure your PR is ready for review.
    • Add new tests, or document why they are unnecessary.
    • Provide clear examples/screenshots, if necessary.
    • Update documentation, if required.
    • Ensure no breaking changes, or include BREAKING CHANGE notes.
    • Link related issues/PRs, where applicable.
☑️ Reviewer Actions:
  1. Complete manual checks for the PR, including the guidelines and additional checks if applicable.
📚 Resources:
Debug
Automated Checks
Maintainers must be able to edit this pull request (more info)

If

🟢 Condition met
└── 🟢 And
    ├── 🟢 The base branch matches this pattern: ^master$
    └── 🟢 The pull request was created from a fork (head branch repo: davd-gzl/gno)

Then

🟢 Requirement satisfied
└── 🟢 Maintainer can modify this pull request

Pending initial approval by a review team member, or review from tech-staff

If

🟢 Condition met
└── 🟢 And
    ├── 🟢 The base branch matches this pattern: ^master$
    └── 🟢 Not (🔴 Pull request author is a member of the team: tech-staff)

Then

🔴 Requirement not satisfied
└── 🔴 If
    ├── 🔴 Condition
    │   └── 🔴 Or
    │       ├── 🔴 At least one of these user(s) reviewed the pull request: [aronpark1007 davd-gzl jefft0 notJoon omarsy MikaelVallenet] (with state "APPROVED")
    │       ├── 🔴 At least 1 user(s) of the team tech-staff reviewed pull request
    │       └── 🔴 This pull request is a draft
    └── 🔴 Else
        └── 🔴 And
            ├── 🟢 This label is applied to pull request: review/triage-pending
            └── 🔴 On no pull request

Manual Checks
**IGNORE** the bot requirements for this PR (force green CI check)

If

🟢 Condition met
└── 🟢 On every pull request

Can be checked by

  • Any user with comment edit permission

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 20, 2026

Codecov Report

❌ Patch coverage is 78.67925% with 113 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
gnovm/cmd/gno/init.go 77.45% 70 Missing and 15 partials ⚠️
gnovm/cmd/gno/mod_init_templates.go 45.65% 17 Missing and 8 partials ⚠️
tm2/pkg/commands/prompt.go 97.53% 2 Missing ⚠️
gnovm/cmd/gno/mod.go 96.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@alexiscolin
Copy link
Copy Markdown
Member

@davd-gzl, could you please tag a/ux in your PRs and link the related UX issues?

@alexiscolin alexiscolin added the a/ux User experience, product, marketing community, developer experience team label Apr 21, 2026
Allow 'gno init p/nt/hello' and 'gno init r/demo/foo' as shortcuts
for their fully-qualified gno.land equivalents.

Assisted-By: Claude (OpenCode)
Add reusable prompt primitives in tm2/pkg/commands/ that work with
the existing IO interface and require zero new dependencies:

- PromptString, PromptChoice, PromptSelect, PromptConfirm
- ErrGoBack sentinel for back-navigation
- Choice and SelectItem types for structured input

28 test cases covering normal flows, edge cases, and ErrGoBack.
…e flag

- Replace local prompt/readLine/isTerminal/errGoBack with shared
  PromptString/PromptChoice/ErrGoBack from tm2/pkg/commands
- Add --template flag for non-interactive template selection
  (e.g. gno init --template dao gno.land/r/demo/foo)
- Add resolveTemplate() with case-insensitive lookup and helpful
  error messages listing available template names
- Add mutual exclusion check: --bare and --template cannot combine
- Fix writeGnomod to return WriteFile error instead of ignoring it
- Fix realm template Render(path) → Render(_) (unused param lint)
- Add how-to-add-template doc comment to mod_init_templates.go
- Simplify mod_test.go: remove dead fields, extract testIO helpers,
  add TestResolveTemplate, TestModInitWithTemplateFlag,
  TestModInitBareAndTemplateExclusive
- Alias tm2/pkg/errors as terrors to avoid shadowing stdlib errors
- Use errors.Is() for ErrGoBack sentinel checks
Rename prxxxx_mod_init_template.md → pr5557_mod_init_template.md.
Update content to document shared prompt primitives, external TUI
library alternative considered and rejected, and updated key files.
@github-actions github-actions Bot added the 📦 🌐 tendermint v2 Issues or PRs tm2 related label Apr 21, 2026
davd-gzl and others added 6 commits April 21, 2026 19:34
- initTemplate uses Dir field instead of SourcePath/TestPath;
  renderTemplateDir walks the directory, renders all .tmpl files,
  and uses filename (minus .tmpl) as Go template for output name
  (e.g. {{.PkgName}}.gno.tmpl → <pkg>.gno). Supports complex
  multi-file templates without special-casing.
- Rename template files: source.gno.tmpl → {{.PkgName}}.gno.tmpl,
  test.gno.tmpl → {{.PkgName}}_test.gno.tmpl,
  run source.gno.tmpl → main.gno.tmpl
- Remove ErrGoBack sentinel and go-back navigation from wizard.
  Backspace cannot be detected in line-buffered terminal mode, and
  alternative go-back keys conflict with valid PromptString input.
  Wizard is now a linear flow; Ctrl+C to restart.
- Simplify execModInit: replace step-machine loop with straight-line code.
- Update ADR with directory-based template docs and ErrGoBack rejection.
- execInitRun now prompts for script name (default derived from
  directory name), producing e.g. run/create_proposal.gno instead
  of hardcoded run/main.gno
- Run template filename uses {{.ScriptName}}.gno.tmpl
- Template comment shows full gnokey maketx run command with the
  script path (e.g. ./create_proposal.gno)
- Add ScriptName field to templateData
- Extract validateName as a top-level function
- Error on file conflict in writeModule and execInitRun
…n, bare+gno exclusive

- execInitRunScript now accepts initTemplate param and uses the
  template registry + --template flag instead of hardcoding
  runTemplatesFS
- Write all rendered files (not just the first) in execInitRunScript
- Error on --bare + .gno argument (mutually exclusive)
- Remove dead kindRun branch in argument path (kindFromPath
  never returns kindRun)
- Sort map keys for deterministic output in writeModule,
  execInitRun, execInitRunScript
- Fix display path (filepath.Join instead of string concat)
- Add TestModInitBareAndGnoExclusive test
- Update ADR to reflect current state
@@ -0,0 +1,168 @@
// Interactive prompt primitives for CLI wizard flows.
Copy link
Copy Markdown
Member Author

@davd-gzl davd-gzl Apr 21, 2026

Choose a reason for hiding this comment

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

This will be reused in a future PR (wizard gnokey maketx)

davd-gzl and others added 8 commits April 21, 2026 16:42
- PromptChoice: choices is map[string]Choice, returns key string,
  defaultKey string param (empty = no default)
- PromptSelect: keeps []SelectItem (order matters — first item is
  default/most important), returns Name string
- Both return string keys instead of int indices — callers switch
  on key instead of indexing parallel slices
- Remove ChoiceMenu, SelectItem.IsDefault, strings.ToLower
- Add package-level doc comment
- Add ScriptPath to templateData (e.g. run/create_proposal.gno)
  so template comment shows the full runnable path
- Fix gnokey flags: single-dash (Go flag convention), not --
- Use 1000000ugnot instead of 1gnot for gas-fee
- Template shows ./run/<name>.gno paths for both gno run and gnokey
…solidate run script funcs

- Non-interactive mode now scaffolds template files when a module path is
  provided (only --bare skips templates). Previously non-interactive + path
  only created gnomod.toml, making the feature useless in CI/scripts.
- Add validateGnoPath: rejects absolute paths, path traversal (..), and
  empty/invalid script names in .gno arguments.
- Consolidate execInitRunScript + execInitRun into single writeRunScript
  function; execInitRun now just prompts for script name and delegates.
- Resolve template before writing gnomod.toml to prevent partial writes
  on unknown template errors.
- Pre-allocate created slices (fix prealloc lint warnings).
- Remove terrors alias (only one usage, replaced with fmt.Errorf).
- Fix prompt capitalization: [P]ackage → [p]ackage.
- Use path.Join instead of filepath.Join in mod_init_templates.go
  (embedded FS always uses forward slashes).
- Remove PromptConfirm from ADR key functions list (was removed earlier).
- Add tests: TestValidateGnoPath, TestModInitBareNoPath,
  TestModInitUnknownTemplateNoPartialWrite, update TestModInitNonInteractive
  and TestModInitWithTemplateFlag to verify template files are created.

Assisted-By: Claude (OpenCode)
…ate conflict

- Add 'init' to the auto-generated subcommand list in gnovm/cmd/gno/README.md
  so 'make generate' is clean (unblocks CI 'main / build').
- Extract renderModuleFiles() to pre-check template file conflicts before
  writing gnomod.toml. Previously, if a rendered target file already existed
  on disk, gnomod.toml was written first and then writeModule returned an
  error, leaving an orphan gnomod.toml. All three non-bare paths
  (non-interactive-with-arg, interactive-with-arg, full-wizard) now render
  and validate templates before any disk write.
- Add TestModInitTemplateFileConflictNoPartialWrite regression test.

Assisted-By: Claude (claude-opus-4.7)
- Add 'gno mod init' as a deprecated alias of 'gno init' that forwards
  to execModInit and prints a deprecation warning on stderr. Keeps
  existing scripts, Makefiles, and CI pipelines working.
- Tighten validateGnoPath: check for cleaned == '..' or '../...' prefix
  instead of a plain HasPrefix('..') so legitimate names like
  '..bar/hello.gno' are not false-positived as traversal.
- Rename the namespace prompt label from 'Address or namespace' to
  'Namespace' — validateName only accepts [a-z0-9_]+, so advertising
  addresses was misleading.
- Make insertPathLetter idempotent: if the path already has an '/r/' or
  '/p/' segment after the domain, return it unchanged instead of
  inserting a second letter.
- Add a TODO in renderTemplateDir noting that nested template
  directories are intentionally skipped for v1.
- Extract scaffoldModule / scaffoldModuleWith helpers. The three
  non-bare, non-run code paths (non-interactive-with-arg,
  interactive-with-arg, wizard-end) all did the same
  resolve → render-precheck → writeGnomod → writeModule sequence;
  consolidating removes ~40 lines of duplication and makes the
  invariant (no orphan gnomod.toml) obvious.
- Update ADR: document the deprecation alias and the new non-interactive
  fallback semantics; refresh the 'Key Files' function list.
- Add TestModInitDeprecatedAlias, extra TestInsertPathLetter idempotency
  cases, and a TestValidateGnoPath 'dotdot prefix not traversal' case.

Assisted-By: Claude (claude-opus-4.7)
The default kind is package ('p'), so capitalize it ([P]ackage) so the
default is visually obvious at a glance, consistent with common CLI
conventions.

Assisted-By: Claude (claude-opus-4.7)
davd-gzl and others added 9 commits April 23, 2026 01:13
…irectories

Replace the cargo-new-style subdirectory scaffolding with a simpler model:
'gno init <modpath>' always creates gnomod.toml and template files directly
in the current directory. The only case where 'gno init' creates directories
is the '.gno' run-script branch (e.g. 'gno init run/hello.gno').

This removes prepareTargetDir, the in-place fallback, rollback machinery,
displayDir threading, and all related helpers (joinDisplay, inPlace,
rollbackCreatedDir). Since we only ever write individual files and never
mkdir, a failed init cannot leave orphan directories — no cleanup needed.

- Bail out early if gnomod.toml already exists in CWD.
- validateModulePath runs before any filesystem side effects.
- Pre-render and conflict-check template files before writing gnomod.toml.
- Next-steps hint: 'Next: gno test .' (or generic add-code hint for --bare).
  Uses 'gno test .' rather than './...' because the recursive pattern
  requires a gnowork.toml, which a freshly-scaffolded module lacks.

Tests: drop TestModInitInPlace, simplify TestModInitInvalidPathRejected,
update all path expectations to drop subdir prefixes. Remove in_place.txtar;
rewrite other init txtar files for the new CWD-based layout.

Assisted-By: Claude (claude-opus-4.7)
…init

- gno mod init: preserve original bare behavior, print hint pointing to
  'gno init', drop 'deprecated' wording. The alias never triggers the
  interactive wizard and only writes gnomod.toml.
- Add doc comments on every PR-added function and type.
- Use slices.Sorted(maps.Keys(...)) and drop the sortedKeys helper.
- Replace validateGnoPath manual checks with filepath.IsLocal.
- Use strings.Cut in insertPathLetter.
- Merge duplicate branches in execModInit.
- scaffoldModuleWith renders files once (was rendering twice); absorbs
  the writeModule helper.
- Merge promptModuleKind's two parallel maps into a single source of truth.
- Rename testdata 'mod_init_deprecated.txtar' to 'mod_init_legacy.txtar'
  and update assertions.

Assisted-By: Claude (claude-opus-4.7)
- Merge scaffoldModule and scaffoldModuleWith into one function.
- Factor writeFiles helper (conflict-check + sorted write) reused by
  both module scaffolding and run-script writing.
- Add kindLabel helper and runScriptDir constant.
- Flatten promptModuleKind to a single slice of kind entries (no more
  double-map pattern).
- Linearize execModInit wizard tail via resolveOrPickTemplate helper.
- validateGnoPath now returns the parsed script name, reused by
  writeRunScript instead of recomputing it from the path.
- Rename newModInitDeprecatedCmd to newModInitLegacyCmd to match the
  user-facing wording.

No behavior change. All init txtars and unit tests pass.

Assisted-By: Claude (claude-opus-4.7)
The previous CI run failed in gno.land/pkg/integration with a
'txDispatcher subscription unexpectedly closed' panic in
tm2/pkg/bft/rpc/core/mempool.go:413. This PR does not touch tm2/pkg/bft
or gno.land/pkg/integration; the failure is a test-shutdown race
unrelated to the changes in this PR.

Assisted-By: Claude (claude-opus-4.7)
- Extract ~500 lines of init-related code from mod.go into a new
  gnovm/cmd/gno/init.go so mod.go holds only 'gno mod' subcommands
  (download, graph, tidy, why). Move matching tests into init_test.go.
- Accept bech32 addresses (g1...) as a namespace in the interactive
  prompt via a new validateNamespace/isBech32Address helper.
- In writeRunScript, render templates before calling os.MkdirAll so a
  render failure no longer leaves orphan run/ directories on disk.
- Update ADR Key Files table to reflect the init.go / init_test.go split.

Assisted-By: opencode (claude-opus-4.7)
…naming

'gno mod init' is just a gno mod subcommand that creates a bare gnomod.toml.
It isn't a legacy shim — move it back next to the other mod subcommands and
rename newModInitLegacyCmd to newModInitCmd. Move its test from init_test.go
to mod_test.go accordingly.

Assisted-By: opencode (claude-opus-4.7)
@davd-gzl davd-gzl marked this pull request as ready for review April 22, 2026 22:24
- TestWriteRunScriptNoOrphanDir: verifies that template render failure
  in writeRunScript does not leave behind a stray run/ directory.
- TestModInitBareNoArgsErrors: locks in the new 'module path is required
  with --bare' error for 'gno mod init' called with no arguments
  (previously silently created gnomod.toml with empty module).
- TestModInitRunTemplateFlag: verifies --template is honored on the
  .gno shorthand path (basic succeeds; unknown template fails cleanly
  without creating the run/ directory).

Assisted-By: opencode (claude-opus-4.7)
@Gno2D2 Gno2D2 added the review/triage-pending PRs opened by external contributors that are waiting for the 1st review label Apr 22, 2026
Two of the three regression tests from the previous commit belong at the
CLI layer — replace them with txtar scenarios under testdata/init/:

- mod_init_no_args.txtar: `gno mod init` with no args must error.
- run_template_flag.txtar: `--template basic` on .gno shorthand succeeds.
- run_unknown_template_no_orphan.txtar: unknown --template fails without
  creating an orphan run/ directory.

Keep TestWriteRunScriptNoOrphanDir as a Go test because it needs to
inject a broken initTemplate into writeRunScript — unreachable via CLI.

Also rename mod_init_legacy.txtar to mod_init.txtar and drop the 'legacy'
wording from its header to match the newModInitCmd rename.

Assisted-By: opencode (claude-opus-4.7)
Drop 13 Go tests from init_test.go and one from mod_test.go that
duplicated CLI behavior already exercised by txtar scenarios. Keep
Go tests only for helpers, prompts, and internal injection cases
(e.g. writeRunScript render failure).

Add three txtars to plug the resulting gaps:
- gno_file_conflict.txtar
- bare_and_gno_exclusive.txtar
- bare_no_args.txtar

Assisted-By: opencode (claude-opus-4.7)
@davd-gzl davd-gzl changed the title feat(gnovm): add interactive gno init wizard with template scaffolding feat(gnovm): add interactive gno init wizard Apr 22, 2026
@davd-gzl davd-gzl changed the title feat(gnovm): add interactive gno init wizard feat(gnovm): add interactive gno init wizard Apr 22, 2026
davd-gzl added a commit to davd-gzl/gno that referenced this pull request Apr 23, 2026
… wizard

- Rename quickstart.md → cheatsheet.md
- Add categories: Developer & Contributor
- Developer: add airgap transaction, gnokey query auth/accounts, gnodev flags
- Contributor: build/test Go, start a local chain (gnoland start), update golden
  files, lint/format Go
- Reference gno init wizard (gnolang#5557)
- Reference one-line installer (gnolang#5492)
- Add default gnodev test account mnemonic

Assisted-By: OpenCode (claude-opus-4.6)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a/ux User experience, product, marketing community, developer experience team 📦 🌐 tendermint v2 Issues or PRs tm2 related 📦 🤖 gnovm Issues or PRs gnovm related review/triage-pending PRs opened by external contributors that are waiting for the 1st review

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants