Skip to content

feat(template): template new authoring wizard + scaffold builder (spec 23) - #81

Merged
gustavobertoi merged 1 commit into
mainfrom
feat/template-authoring
Jun 30, 2026
Merged

feat(template): template new authoring wizard + scaffold builder (spec 23)#81
gustavobertoi merged 1 commit into
mainfrom
feat/template-authoring

Conversation

@gustavobertoi

Copy link
Copy Markdown
Contributor

Implements feature #15 / spec 23 — interactive template & Dockerfile authoring. Built in a parallel worktree, integrated + verified locally (make ci + determinism green, smoke-tested end-to-end).

What's here

  • internal/template/scaffold (new, distinct from the workspace internal/scaffold): Spec/Bundle/Build(Spec)(Bundle,error) — pure & deterministic. App emits service.build + build/Dockerfile (+ entrypoint.sh), no provides; engine emits image: + provides/exports/defaultPort + volumes:, no build/. App-vs-engine is a compile-time switch with a Validate() guard. Meta as literal YAML (ordered goccy MapSlice, sorted params); [[ ]] only under service/build. WriteBundle re-implements the atomic temp+rename+0644 pattern with no-clobber + --force backup.
  • Three authoring lints (net-new; LintResolved was compose-go-only): meta-templating ([[ ]] in a meta key → hard error), delimiter-collision (bad action in a build/ file → warn), param-type (default doesn't parse as type → warn) — shared by both template new preview and template lint.
  • template new (internal/cli/template_new.go): full flag surface incl. --from/--print-spec (byte-identical round-trip), --kind/--param name:type[:default]/--entrypoint/--golden/--regold/--dry-run/--force. template init unchanged.
  • Bubble Tea v2 wizard (template_new_tui.go): kind/name/extends pickers, params loop, live preview via the real ResolveLintResolved, confirm — gated by prompt.IsInteractive && !hasFlags.

Verified

make ci + make determinism green; CGO=0 4-target cross-build clean; no new deps (huh/v2 already vendored). Smoke: template new --print-spec--from round-trip writes the bundle; template lint/template test pass on the authored template; bare non-TTY template new degrades (no hang).

Manual TTY wizard keystrokes still warrant a quick hands-on check (bubbletea can't be driven headlessly; the degrade gate + the builder it feeds are fully tested).

🤖 Generated with Claude Code

…pec 23)

Add `devstack template new` — the interactive sibling of `template init` that
authors a complete template bundle (template.yaml + optional build/ tree +
golden) through one deterministic builder fed by two front-ends.

- internal/template/scaffold: pure, deterministic Build(Spec)->Bundle (app vs
  engine is a compile-time branch; meta emitted as literal YAML via ordered
  goccy MapSlice; actions only under service:/build); WriteBundle atomic +
  no-clobber/--force backup; PreviewSource for the real Resolve+LintResolved
  preview.
- Three authoring lints (meta-templating hard error; delimiter-collision and
  param-type warnings) shared by `template new` preview AND wired into
  `template lint` (template.ParseCheck added for collision detection).
- CLI: newTemplateNewCmd with the full flag surface (--kind/--name/--from/
  --extends/--base-image/--param/--port/--provides/--exports/--entrypoint/
  --golden/--regold/--dir/--dry-run/--force/--print-spec) + a Bubble Tea v2
  wizard gated on prompt.IsInteractive so --json/--quiet/--no-input/non-TTY/CI
  never enter bubbletea. --print-spec ⇒ --from is a byte-identical round-trip.
- template.ValidRef exported for name validation; `template init` unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gustavobertoi
gustavobertoi merged commit eaf4694 into main Jun 30, 2026
4 checks passed
@gustavobertoi
gustavobertoi deleted the feat/template-authoring branch June 30, 2026 23:00
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.

1 participant