Skip to content

Conversation

@pyramation
Copy link
Contributor

@pyramation pyramation commented Dec 25, 2025

Summary

This PR adds two major features to create-gen-app:

  1. Optional prompter parameter - Allows callers to pass an existing Inquirerer instance to Templatizer.process() instead of creating a new one internally. This addresses the "two instances on stdin" problem that causes double-echoed keystrokes.

  2. TemplateScaffolder orchestrator class - A high-level API that combines CacheManager, GitCloner, and Templatizer into a single, easy-to-use class. This was the "missing top-level API" that downstream tools like pgpm were reimplementing.

Ownership semantics for prompter:

  • If prompter is provided: caller retains ownership and must close it
  • If prompter is not provided: a new instance is created and closed automatically (existing behavior)

New promptUser signature:

promptUser(extractedVariables, argv?, existingPrompter?, noTty?)

Updates since last revision

  • Added inspect() method to TemplateScaffolder that clones/caches a template and reads its .boilerplate.json configuration without scaffolding
  • New InspectOptions and InspectResult types exported from scaffolder module
  • This enables metadata-driven workflows where callers can read the template's type field before deciding how to handle scaffolding (e.g., pgpm can now use pgpm init <anything> and branch based on template type)
  • Added inspectLocal() and inspectRemote() private methods that mirror the scaffold methods but skip the templatizer step

Review & Testing Checklist for Human

  • inspect() method correctness: The inspectLocal and inspectRemote methods duplicate cache/clone logic from scaffoldFromLocal/scaffoldFromRemote - verify they stay in sync and both correctly resolve paths via .boilerplates.json
  • No tests for inspect(): The new method was added without dedicated tests - consider if this is acceptable or if tests should be added before merge
  • TemplateScaffolder path resolution: Verify the resolveFromPath logic correctly handles: (1) direct paths, (2) .boilerplates.json dir-based resolution, (3) fallback behavior
  • No pgpm-specific code: Ensure no pgpm-specific strings/constants leaked into create-gen-app (e.g., "workspace", "module", "PGPM_*")
  • Prompter threading: Verify TemplateScaffolder.scaffold() correctly passes the prompter through to Templatizer.process()

Test plan:

  1. After publishing a new version, test with the companion PR in constructive repo that updates pgpm/cli to use inspectTemplate() for metadata-driven init
  2. Run pgpm init workspace and pgpm init module end-to-end - verify the template's type field is correctly read and the appropriate flow is triggered
  3. Test both local template paths and remote git URLs with caching

Notes

This PR is part of a two-PR solution:

  • PR 1 (this): Add TemplateScaffolder, inspect() method, and prompter pass-through to create-gen-app
  • PR 2 (constructive): Refactor pgpm init to single entry point using metadata-driven flow

Important: The constructive PR depends on the inspect() method added here. A new version of create-gen-app must be published before the constructive PR can build.

Link to Devin run: https://app.devin.ai/sessions/48555739db3d4f1b9e9edfa9ea1e559a
Requested by: Dan Lynch (@pyramation)

Allow callers to pass an existing Inquirerer instance to promptUser() and
Templatizer.process() instead of creating a new one internally.

This enables CLI tools that already have an Inquirerer instance to reuse it
when calling scaffoldTemplate/Templatizer, avoiding the 'two instances on
stdin' problem that causes double-echoed keystrokes.

Ownership semantics:
- If prompter is provided: caller retains ownership and must close it
- If prompter is not provided: a new instance is created and closed automatically

Changes:
- Add optional 'prompter' field to ProcessOptions interface
- Update promptUser() to accept optional existingPrompter parameter
- Update Templatizer.prompt() to pass through the prompter
- Add JSDoc documentation explaining ownership semantics
@devin-ai-integration
Copy link

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Move noTty parameter to the last position as it's less commonly used.
New signature: promptUser(extracted, argv, existingPrompter?, noTty?)

This makes the API more developer-friendly since noTty is rarely needed
while existingPrompter is the new feature being added.
devin-ai-integration bot pushed a commit to constructive-io/constructive that referenced this pull request Dec 25, 2025
…nces

Add optional 'prompter' parameter to ScaffoldTemplateOptions that gets passed
through to create-gen-app's Templatizer. This allows CLI tools to reuse their
existing Inquirerer instance instead of create-gen-app creating a new one.

Changes:
- Add 'inquirerer' dependency to @pgpmjs/core for the type
- Add optional 'prompter' field to ScaffoldTemplateOptions interface
- Pass prompter through to templatizer.process() in both code paths
- Update workspace.ts to pass prompter instead of calling close() before scaffold

This eliminates the 'two instances on stdin' problem that caused double-echoed
keystrokes when running 'pgpm init workspace'.

Requires: constructive-io/dev-utils#33
Add a high-level TemplateScaffolder class that combines CacheManager,
GitCloner, and Templatizer into a single, easy-to-use API.

Features:
- Handles both local directories and remote git repositories
- Automatic caching with configurable TTL
- Supports .boilerplates.json convention for multi-template repos
- Supports .boilerplate.json for per-template configuration
- Threads prompter through for single-instance stdin handling

This provides the 'batteries included' API that was missing from
create-gen-app while keeping the modular building blocks available.
@devin-ai-integration devin-ai-integration bot changed the title feat(create-gen-app): add optional prompter parameter for reuse feat(create-gen-app): add TemplateScaffolder orchestrator and prompter pass-through Dec 25, 2025
@pyramation pyramation merged commit adc7ae5 into main Dec 25, 2025
34 checks passed
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