Skip to content

feat(tern-cli): migrate scaffolding UX to Ink and normalize framework templates#11

Open
Prateek32177 wants to merge 4 commits intomainfrom
codex/fix-and-enhance-tern-dev-cli-m881jl
Open

feat(tern-cli): migrate scaffolding UX to Ink and normalize framework templates#11
Prateek32177 wants to merge 4 commits intomainfrom
codex/fix-and-enhance-tern-dev-cli-m881jl

Conversation

@Prateek32177
Copy link
Copy Markdown
Contributor

Motivation

  • Replace the clack-based scaffolding UX with an Ink-rendered terminal UI for a cleaner, composable CLI experience.
  • Harden and standardize scaffold templates and support files so generated projects follow canonical layouts for Next.js, Express, Hono and Cloudflare Workers and include reliability + alerting guidance.
  • Make scaffolding idempotent and safer by generating .env, src/env.ts, framework entry points, router index files, and package scripts automatically.

Description

  • Replaced the interactive clack bootstrap with an Ink entrypoint and UI components: Banner, Step, EnvBlock, and Done under packages/tern-cli/src/ui/, and wired them via packages/tern-cli/src/cli.tsx.
  • Introduced a dedicated scaffold command module packages/tern-cli/src/commands/scaffold.ts to centralize generator flow and produce support artifacts.
  • Reworked template generation in packages/tern-cli/src/templates.ts to include reliability comment blocks (queue: false default + QStash guidance), alerting examples (Slack/Discord), and canonical handlers for Next.js, Express, Hono, and Cloudflare Workers.
  • Rewrote file-generation logic in packages/tern-cli/src/files.ts to: create src/routes/webhooks/index.ts, src/index.ts, src/env.ts, generate/merge .env and .gitignore entries, and set framework-appropriate package.json scripts and a Node tsconfig.json when needed.
  • Removed the @clack/prompts runtime dependency from the scaffolding flow and moved wizard input collection to argument-based parsing in packages/tern-cli/src/wizard.ts (using minimist), simplifying automation and testability.
  • Updated packages/tern-cli/package.json and tsconfig.json to support Ink/React usage (ink, react, @types/react) and JSX compilation (jsx: react-jsx, include .tsx).

Testing

  • Ran template/path sanity checks with npx tsx -e to validate output of getTemplate, getFilePath, and getWebhookPath; these checks succeeded and confirmed presence of queue: false, QStash vars and correct target paths.
  • Searched repo for clack references to confirm migration away from clack prompts; the grep checks succeeded.
  • Attempted npm install in packages/tern-cli but the install failed due to environment registry policy (403 Forbidden), so dependencies (react, ink, types) could not be fetched and installed.
  • Ran npm run typecheck in packages/tern-cli; it failed because react/ink typings are unavailable in this environment until npm install succeeds.

Codex Task

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1338015ef6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

return
}
const current = fs.readFileSync(fullPath, 'utf8')
if (current !== content) fs.writeFileSync(fullPath, content, 'utf8')
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Prevent silent overwrite of existing scaffold targets

createHandlerFile now overwrites any existing file whenever the generated content differs, with no confirmation or --force gate. Since run() invokes this for primary handlers and support files (src/index.ts, src/routes/webhooks/index.ts, src/env.ts), rerunning scaffold in an existing Express/Hono/Cloudflare codebase can silently replace user-maintained entrypoints and routes, which is a destructive regression from the previous confirm-before-overwrite behavior.

Useful? React with 👍 / 👎.

{ status: 200 }
)
function cloudflareTemplate(p: string): string {
return `import { createWebhookHandler } from '@hookflo/tern/cloudflare'\n\n// ─── Reliability ─────────────────────────────────────────────────────────────\n// queue: false → direct execution\n// queue: true → not supported on Workers — use Cloudflare Queues for guaranteed delivery\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface Env {\n WEBHOOK_SECRET: string\n // QSTASH_TOKEN: string\n // QSTASH_CURRENT_SIGNING_KEY: string\n // QSTASH_NEXT_SIGNING_KEY: string\n // SLACK_WEBHOOK_URL: string\n // DISCORD_WEBHOOK_URL: string\n [key: string]: unknown\n}\n\nexport default {\n async fetch(request: Request, env: Env): Promise<Response> {\n const url = new URL(request.url)\n\n if (url.pathname === '/') {\n return Response.json({ status: 'ok', framework: 'cloudflare-workers' })\n }\n\n if (url.pathname === '/webhooks/${p}' && request.method === 'POST') {\n const handler = createWebhookHandler({\n platform: '${p}',\n secret: env.WEBHOOK_SECRET,\n handler: async (payload) => {\n console.log('✅ ${p} webhook verified. Event:', payload?.type)\n return { received: true }\n },\n })\n\n return handler(request, env)\n }\n\n return Response.json({ error: 'Not found' }, { status: 404 })\n },\n}\n`
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Use selected secret env var in Cloudflare template

The Cloudflare scaffold hardcodes secret: env.WEBHOOK_SECRET, but the generator computes and documents a platform-specific secret key (for example STRIPE_WEBHOOK_SECRET) via ENV_VARS and .env creation. For non-other platforms this produces a mismatched configuration: users fill the generated variable, while runtime verification reads a different one, causing webhook validation to fail unless they add an undocumented WEBHOOK_SECRET.

Useful? React with 👍 / 👎.

const platform = (args.platform ?? 'stripe') as Platform
const framework = (args.framework ?? 'nextjs') as Framework
const action = (args.action ?? 'both') as Action
const port = String(args.port ?? '3000')
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Validate --port input before accepting CLI args

askQuestions() now accepts --port verbatim with no numeric/range checks, so invalid values (e.g. --port abc or out-of-range numbers) flow into config and tunnel startup. This leads to invalid tern.config.json output ("port": NaN) and runtime failures when launching the tunnel. The previous wizard guarded this with 1–65535 validation, so the CLI-arg path should enforce equivalent checks.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant