Files
summercms/.planning/phases/01-framework-kernel-foundation/01-03-PLAN.md
2026-09-16 12:30:05 +02:00

12 KiB

phase: 01-framework-kernel-foundation plan: 03 type: execute wave: 3 depends_on: ["01-02"] files_modified: - internal/build/build.go - internal/build/manifest.go - internal/build/scaffold.go - internal/dev/watch.go - cmd/summer/main.go - bonfire/root.go - bonfire/command.go - bonfire/output.go - bonfire/widgets.go - bonfire/prompts.go - bonfire/output_test.go - bonfire/prompts_test.go - internal/build/build_test.go - internal/dev/watch_test.go - examples/hello/plugins/greeter/plugin.go - go.mod - go.sum autonomous: true requirements: [KERN-04, KERN-09, CLI-01] must_haves: truths: - "D-01 D-03 D-04 D-05: summer make:plugin scaffolds a compiling plugin and summer plugin:add adds it to the ordered manifest/workspace; summer build regenerates imports and a separate app binary." - "D-14: Spinner, progress, table, ask/confirm/choice/secret prompts and color policy use standard library plus x/term, with deterministic non-TTY output." - "D-15 D-17: Tool and app commands use colon-style names; plugin command metadata, flags, arguments and injected Output are wrapped by the shared cobra kernel." - "D-16: summer dev watches sources/config/manifests, debounces, calls the same build function, restarts the app only after successful build, and prints measured rebuild latency." artifacts: - path: internal/build/scaffold.go provides: Minimal plugin scaffold and manifest/workspace registration - path: bonfire/widgets.go provides: Spinner, progress and table rendering - path: bonfire/prompts.go provides: Prompt handling and non-TTY fallback - path: internal/dev/watch.go provides: Built-in watch rebuild loop key_links: - from: cmd/summer/main.go to: internal/build/scaffold.go via: make:plugin and plugin:add tool commands - from: internal/dev/watch.go to: internal/build/build.go via: One shared build function - from: bonfire/root.go to: bonfire/output.go via: Output injection into plugin commands As a framework developer, I can add a plugin, rebuild, see useful CLI output, and keep an app running while editing source, so compiled plugins have a practical development loop.

Purpose: Complete the Phase 1 tool experience around the already bootable hello app. Output: make:plugin, plugin:add, rich CLI output and built-in summer dev watch loop.

<execution_context> @$HOME/.codex/get-shit-done/workflows/execute-plan.md @$HOME/.codex/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/REQUIREMENTS.md @.planning/phases/01-framework-kernel-foundation/01-CONTEXT.md @.planning/phases/01-framework-kernel-foundation/01-RESEARCH.md @.planning/phases/01-framework-kernel-foundation/01-VALIDATION.md @.planning/phases/01-framework-kernel-foundation/01-02-SUMMARY.md @../modules/summer-bonfire/PLAN.md Task 1: Add and rebuild a compiling plugin from the tool internal/build/build.go, internal/build/manifest.go, internal/build/scaffold.go, internal/build/build_test.go, cmd/summer/main.go internal/build/build.go, internal/build/manifest.go, internal/build/scaffold.go, internal/build/build_test.go, cmd/summer/main.go, examples/hello/summer.yaml, examples/hello/go.mod, examples/hello/plugins.gen.go, examples/hello/plugins/base/plugin.go, go.work, .planning/phases/01-framework-kernel-foundation/01-CONTEXT.md, .planning/phases/01-framework-kernel-foundation/01-RESEARCH.md Complete D-01/D-03/D-04/D-05 using `summer.yaml` as the sole ordered source of plugin IDs and module paths. `summer make:plugin ` scaffolds `plugins//go.mod` with module path `/plugins/` and `toolchain go1.27.0`, `plugin.go` implementing ID/Requires/Register/Boot and `init(){ party.Register(...) }`, plus an empty `config/` placeholder; no model/migration/controller/command stubs. `summer plugin:add ` reads the module path from that directory's `go.mod`, validates the ID and module path, adds the plugin once to `summer.yaml`, updates the nearest app `go.work` with `go work use`, and updates app `go.mod` as needed for a portable dependency graph. Preserve manifest order and reject conflicting IDs. `summer build` must regenerate both app files from the updated manifest and print elapsed build time; no map iteration controls output. Keep tool source independent of app/plugin imports. Exercise the commands on a temporary copy of `examples/hello` so the permanent testbed stays small. go test ./internal/build ./cmd/summer && (cd examples/hello && go test ./...) - `make:plugin golem15.demo` produces a compiling plugin module with only `go.mod`, `plugin.go` and `config/`. - `plugin:add` adds one manifest entry and workspace module; repeating it is idempotent. - `summer build` produces byte-stable `main.go` and `plugins.gen.go` from the updated manifest. - The framework tool has no import of an app-specific plugin package. A new local plugin can be scaffolded, added and compiled into the hello app. Task 2: Give tool and plugin commands deterministic rich output bonfire/root.go, bonfire/command.go, bonfire/output.go, bonfire/widgets.go, bonfire/prompts.go, bonfire/output_test.go, bonfire/prompts_test.go, cmd/summer/main.go, examples/hello/plugins/greeter/plugin.go, go.mod, go.sum bonfire/root.go, bonfire/command.go, bonfire/output.go, bonfire/widgets.go, bonfire/prompts.go, bonfire/output_test.go, bonfire/prompts_test.go, cmd/summer/main.go, examples/hello/plugins/greeter/plugin.go, go.mod, go.sum, ../modules/summer-bonfire/PLAN.md, .planning/phases/01-framework-kernel-foundation/01-CONTEXT.md, .planning/phases/01-framework-kernel-foundation/01-RESEARCH.md Implement D-14/D-15/D-17 with stdlib formatting and `golang.org/x/term` v0.46.0 only for terminal capability/raw/password primitives. `bonfire.Output` is constructed once from injected stdin/stdout/stderr and terminal/color policy; the cobra adapter passes `ctx`, parsed `Input`, and that Output to every `bonfire.Command`. Command metadata defines arguments and flags without duplicating root wiring; reject plugin command names without `:`, while kernel tool commands are `make:plugin`, `plugin:add`, `build`, `dev`. Implement braille spinner and gradient progress for TTY, box-drawing table, ask/confirm/choice/secret prompts. For non-TTY: spinner prints one `[...] message`; progress prints `[N/M] pct%` at 10% steps; table is tab-separated; ask/choice/secret read stdin lines; confirm uses its default. `NO_COLOR` or `TERM=dumb` disables ANSI; `FORCE_COLOR` enables it only when neither disable condition is present. `secret` uses `term.ReadPassword` on TTY and a plain stdin line otherwise. Make the hello plugin command exercise table and one prompt without hanging when stdin is closed. go test ./bonfire ./cmd/summer && (cd examples/hello && go test ./...) - `summer make:plugin --help` and the app's `greeter:hello --help` are generated through the shared `bonfire` cobra adapter. - Non-TTY output has no ANSI when `NO_COLOR=1` or `TERM=dumb` and uses the exact spinner/progress/table fallback shapes above. - Injected streams let tests capture Output and feed prompt answers without a real TTY. - Plugin command names without `:` fail registration with a named error. Both binaries expose namespaced commands and usable output in interactive and CI environments. Task 3: Rebuild and restart the hello binary during source edits internal/dev/watch.go, internal/dev/watch_test.go, internal/build/build.go, cmd/summer/main.go, go.mod, go.sum internal/build/build.go, internal/dev/watch.go, internal/dev/watch_test.go, cmd/summer/main.go, go.mod, go.sum, examples/hello/summer.yaml, .planning/phases/01-framework-kernel-foundation/01-CONTEXT.md, .planning/phases/01-framework-kernel-foundation/01-RESEARCH.md Implement `summer dev` with `github.com/fsnotify/fsnotify` v1.10.1 (D-16). Watch app workspace directories recursively by walking them and adding new directories on Create; include `.go`, `.yaml`, `.yml`, `.env`, `go.mod`, `go.work` and plugin manifests. Ignore `.git`, `bin`, temp build outputs and generated app files to prevent loops. Debounce bursts (for example 200ms) and serialize builds. Call the exact `internal/build` function used by `summer build`; after success stop and reap the old child, start the new app binary with inherited streams, and print `rebuild: ` measured from build start to completion. On build failure keep the old process running and print the build error; on context cancellation stop/reap the child and close the watcher. Do not execute manifest-derived shell commands. Add a smoke test with a temporary workspace to assert one restart after a source edit, no restart after ignored generated output and a latency line. go test ./internal/dev ./internal/build ./cmd/summer && (cd examples/hello && go test ./...) - Editing a watched hello plugin `.go` file causes one debounced rebuild and successful restart. - Build failure leaves the last successful child running; cancellation reaps it. - A generated `plugins.gen.go` write does not cause an infinite rebuild loop. - Every rebuild cycle prints measured elapsed time, including the cycle after a single-plugin edit. The local development loop rebuilds and restarts without an external watcher install.

<threat_model>

Trust Boundaries

Boundary Description
CLI plugin input → filesystem Plugin ID and directory values select paths and module names.
Filesystem event → build/restart File changes trigger local tool execution and process replacement.
Prompt → terminal Secret values may be echoed or captured if mode detection is wrong.

STRIDE Threat Register

Threat ID Category Component Disposition Mitigation Plan
T-01-06 Tampering make:plugin and plugin:add paths mitigate Validate lowercase vendor.plugin ID and keep generated paths under the app root; reject traversal and duplicate/conflicting entries.
T-01-07 Denial of service summer dev watcher mitigate Debounce, ignore output dirs, serialize builds, and reap child processes on cancellation.
T-01-08 Information disclosure bonfire secret prompt mitigate Use term.ReadPassword for TTY and document plain stdin fallback; never log answers.
</threat_model>
- After each task commit, run `go vet ./... && go test ./...` in root and hello modules. - Smoke-test `make:plugin`, `plugin:add`, `build` and `dev` against temporary copies of `examples/hello`. - Capture non-TTY output with pipes; manually inspect one TTY command during phase verification.

<success_criteria>

  • A new plugin is scaffolded, registered and built using only the framework tool.
  • CLI output degrades predictably without a TTY.
  • A plugin source change triggers a measured rebuild and app restart. </success_criteria>
Create `.planning/phases/01-framework-kernel-foundation/01-03-SUMMARY.md` after completion.