Skip to content

fix(api): prevent excessive padding from blank lines and large lists - #113

Merged
moshloop merged 4 commits into
mainfrom
feat/pluggable-live-renderer
Jun 9, 2026
Merged

fix(api): prevent excessive padding from blank lines and large lists#113
moshloop merged 4 commits into
mainfrom
feat/pluggable-live-renderer

Conversation

@moshloop

@moshloop moshloop commented Jun 9, 2026

Copy link
Copy Markdown
Member

What

  • Strip blank lines and trailing whitespace from tree node labels via normalizeTreeLabel()
  • Stack large description lists (>3 items or >terminal width) one pair per line instead of inline
  • Add TypedFilter interface to allow filters to override their lookup type independently of flag type

Why

  • Prevents lipgloss from rendering stray gutter-only lines and padding sibling lines with thousands of trailing spaces
  • Avoids single multi-thousand-character lines forcing excessive padding in tree output
  • Enables date-math and similar flags to advertise appropriate UI controls

Notes

  • Includes comprehensive test coverage for tree label normalization, description list stacking, and filter type overrides

Summary by CodeRabbit

  • New Features

    • Live-renderer hook to customize live task output and final summary.
    • CLI docs generation command, Markdown site scaffolding and UI-surface catalog.
    • Filters may declare explicit lookup types surfaced in lookup metadata.
    • Exposed parameter role helper for richer surface docs.
  • Bug Fixes

    • Drop connector-only gutter lines from multi-line tree labels.
    • Description lists now wrap/stack large lists to avoid overly wide lines.
  • Tests

    • Expanded coverage for tree normalization, live renderer, description lists, docs pipeline, and filter lookup metadata.

moshloop added 2 commits June 9, 2026 13:10
Add a LiveRenderer interface and SetLiveRenderer hook so a caller can
render its own block (e.g. a status table) through clicky's task manager
instead of hand-rolling an ANSI redraw. The manager keeps owning the TTY,
ClearLines line accounting, and the logger serializer that prevents
concurrent log lines from corrupting the in-place frame; only the rendered
api.Text content is swapped.

Wired into the three render entry points: interactiveRender (live tick),
PlainRender (non-interactive flush, whole block), and renderFinal (post
summary). When no renderer is installed the default task-tree formatting is
unchanged.
…sts from causing excessive padding

Add normalizeTreeLabel() to strip blank lines and trailing whitespace from multi-line tree node labels. This prevents lipgloss from rendering stray gutter-only lines and right-padding all sibling lines with thousands of trailing spaces.

Modify DescriptionList.String() and ANSI() to stack large lists (>3 items or >terminal width) one pair per line instead of joining inline. This prevents single multi-thousand-character lines from forcing excessive padding in tree output.

Add TypedFilter interface to allow filters to override their lookup type independently of the flag type, enabling date-math and similar flags to advertise appropriate UI controls.

Includes comprehensive test coverage for tree label normalization, description list stacking behavior, and filter type overrides.
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9cbd31ea-a32f-4f4f-b4dd-d443c7ab5a6a

📥 Commits

Reviewing files that changed from the base of the PR and between 959e6cf and dc3a3ee.

📒 Files selected for processing (11)
  • .gitignore
  • docs/cobra_walk.go
  • docs/command.go
  • docs/config.go
  • docs/docs_test.go
  • docs/pages.go
  • docs/provider.go
  • docs/scaffold.go
  • entity.go
  • entity_filters_test.go
  • extensions/cobra.go
🚧 Files skipped from review as they are similar to previous changes (10)
  • .gitignore
  • entity.go
  • extensions/cobra.go
  • docs/provider.go
  • docs/scaffold.go
  • docs/config.go
  • docs/command.go
  • docs/cobra_walk.go
  • docs/pages.go
  • docs/docs_test.go

Walkthrough

Normalizes multi-line tree labels to drop blank lines, makes DescriptionList render stacked when too wide, adds TypedFilter to override lookup types, introduces a LiveRenderer hook for task rendering, and adds a docs generation subsystem with model, renderers, scaffold, CLI command, and tests.

Changes

Rendering and Filter Enhancements

Layer / File(s) Summary
Tree label normalization across formatters
api/meta.go, formatters/tree_formatter.go, api/meta_tree_normalize_test.go, formatters/tree_formatter_test.go
New normalizeTreeLabel helpers remove blank lines and trailing whitespace from multi-line tree node labels; tree rendering now normalizes labels to avoid blank gutter connector lines; tests validate normalization and rendering.
Description list width-aware rendering
api/text.go, api/keyvalue_test.go
DescriptionList.String() and DescriptionList.ANSI() collect per-item parts and use joinDescriptionParts to choose inline comma-joined or stacked one-per-line rendering based on terminal width; a test verifies stacking behavior for large maps.
Filter explicit type system
entity.go, entity_filters_test.go
Adds TypedFilter[T] with LookupType() so filters can explicitly specify lookup metadata Type; resolveLookup applies this override when present; tests include amountEntityFilter returning "number".
Live renderer hook and task integration
task/render_hook.go, task/manager.go, task/manager_lifecycle.go, task/render.go, task/render_hook_test.go
Introduces LiveRenderer interface and SetLiveRenderer installer; Manager stores the renderer and rendering paths (PlainRender, interactiveRender, renderFinal) prefer the live renderer when installed; tests cover invocation, fallback, final rendering, and log-line accounting.
Docs generation subsystem
docs/*, examples/enitity/main.go, extensions/cobra.go, rpc/openapi.go, .gitignore
Adds docs package (model, markdown builder, reference/surfaces renderers, scaffold, CLI command, provider/pages) with extensive tests and example wiring; integrates docs commands into extensions and exports rpc.ParamRole; .gitignore updated to ignore go.work.sum.

Possibly related PRs:

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 39.58% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: preventing excessive padding via blank-line normalization and large-list stacking.
Description check ✅ Passed The description covers What/Why/Notes sections with clear explanations, but is missing explicit Type of Change, Testing, and Checklist sections from the template.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/pluggable-live-renderer
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/pluggable-live-renderer

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Gavel summary

Source Pass Fail Skip Duration
(unknown) 0 1 0 -
ai 9 0 0 384.698µs
api 125 0 12 31ms
clicky 98 0 0 12.9s
examples/enitity 1 0 0 -
exec 68 0 1 3.2s
flags 20 0 0 4ms
formatters 26 0 0 13ms
github.com/flanksource/clicky 48 0 0 13.0s
github.com/flanksource/clicky/ai 10 0 0 -
github.com/flanksource/clicky/api 235 0 0 120ms
github.com/flanksource/clicky/api/tailwind 427 0 0 -
github.com/flanksource/clicky/docs 19 0 0 -
github.com/flanksource/clicky/exec 3 0 0 310ms
github.com/flanksource/clicky/flags 26 0 0 40ms
github.com/flanksource/clicky/formatters 50 0 0 -
github.com/flanksource/clicky/formatters/http 38 0 0 -
github.com/flanksource/clicky/formatters/pdf 0 0 1 -
github.com/flanksource/clicky/formatters/tests 202 0 1 7.2s
github.com/flanksource/clicky/internal/gumchoose 2 0 0 -
github.com/flanksource/clicky/lint 4 0 0 -
github.com/flanksource/clicky/mcp 34 0 0 30ms
github.com/flanksource/clicky/middleware 31 0 0 -
github.com/flanksource/clicky/rpc 188 0 1 -
github.com/flanksource/clicky/task 81 0 0 8.7s
lint 6 0 0 7.6s
metrics 7 0 0 3ms
middleware 38 0 0 1ms
tests 11 0 47 4ms
text 78 0 0 307ms
valkey 4 0 0 9ms

Totals: 1889 passed · 1 failed · 63 skipped · 53.4s

Failing tests

ginkgo Execution

✓ test-cancellation 10 of 10 100ms     
✓ test-rapid 20 of 20 100ms     
✓ test-no-double-close 3 of 3 100ms     
✓ test-goroutine-lifecycle 10 of 10 100ms     
... (47 more lines truncated)```

[View full results](https://github.com/flanksource/clicky/actions/runs/27221696292/artifacts/7514397763)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
entity_filters_test.go (1)

350-352: ⚡ Quick win

Add a regression test for typed overrides through LiftFilters.

Current assertion validates the direct-filter path only. Please add a case where an inner filter implementing LookupType() is wrapped with LiftFilters[...], then assert lookup.Filters[...].Type still reflects the override.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@entity_filters_test.go` around lines 350 - 352, Add a regression case that
exercises typed overrides via LiftFilters: create or reuse an inner filter type
that implements LookupType() returning "number", wrap that instance with
LiftFilters[...] and use it in the same lookup construction path being tested,
then assert that lookup.Filters["amount"].Type == "number". Specifically, ensure
the test wraps the filter with LiftFilters, invokes whatever function builds the
lookup (as in the surrounding test), and replaces or adds the assertion
following the existing direct-filter check so it verifies the wrapped-filter
path (referencing symbols LiftFilters, LookupType, and
lookup.Filters["amount"]).
formatters/tree_formatter.go (1)

138-156: 💤 Low value

Consider consolidating duplicate normalization logic.

This function duplicates normalizeTreeLabel from api/meta.go with a subtle difference: this version doesn't strip ANSI codes before checking for blank lines, while the api version does. Both implementations are correct for their contexts (this one normalizes before styling, the api one after), but maintaining two similar functions increases the risk of inconsistent bug fixes or divergent behavior over time.

Potential consolidation approach

You could extract the common logic to a shared location with an optional parameter:

// In a shared utility package or the api package:
func normalizeTreeLabel(s string, stripANSI bool) string {
	if !strings.Contains(s, "\n") {
		return s
	}
	lines := strings.Split(s, "\n")
	out := make([]string, 0, len(lines))
	for _, line := range lines {
		toCheck := line
		if stripANSI {
			toCheck = ansi.Strip(toCheck)
		}
		if strings.TrimSpace(toCheck) == "" {
			continue
		}
		out = append(out, strings.TrimRight(line, " \t"))
	}
	return strings.Join(out, "\n")
}

Then both packages could call it with the appropriate flag.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@formatters/tree_formatter.go` around lines 138 - 156, The normalizeTreeLabel
implementation in formatters/tree_formatter.go duplicates logic found in
api/meta.go but differs on ANSI stripping; extract the common logic into a
shared utility function (e.g., normalizeTreeLabel(s string, stripANSI bool) or
similar) and update both callers to call that shared function with
stripANSI=false from formatters/tree_formatter.go's usage and stripANSI=true
from api/meta.go's usage; ensure the new helper preserves the current behavior
(trim trailing spaces, drop blank lines after optional ANSI strip) and replace
the local normalizeTreeLabel with calls to the shared helper.
task/manager_lifecycle.go (1)

156-189: 💤 Low value

Consider using snapshotTasks() for consistency.

Lines 165-167 manually create the task snapshot with the same logic that snapshotTasks() (in render_hook.go) encapsulates. Using tm.snapshotTasks() would eliminate the duplication and ensure consistent snapshot behavior across all rendering paths.

♻️ Proposed refactor
 func (tm *Manager) renderFinal() {
 	if tm.noRender.Load() {
 		return
 	}
-	tm.mu.RLock()
-	if len(tm.tasks) == 0 {
-		tm.mu.RUnlock()
+	taskSnapshot := tm.snapshotTasks()
+	if len(taskSnapshot) == 0 {
 		return
 	}
-	taskSnapshot := make([]*Task, len(tm.tasks))
-	copy(taskSnapshot, tm.tasks)
-	tm.mu.RUnlock()
 
 	var rendered api.Text
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@task/manager_lifecycle.go` around lines 156 - 189, The renderFinal method
duplicates task snapshot logic; replace the manual snapshot creation in
renderFinal with a call to tm.snapshotTasks() (the helper in render_hook.go) to
avoid duplication and ensure consistent snapshot semantics across render paths —
locate renderFinal and swap the block that creates taskSnapshot (the make/copy
and mutex calls around tm.tasks) to use taskSnapshot := tm.snapshotTasks(),
preserving subsequent use of taskSnapshot and existing bufferMutex/renderer
logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@entity.go`:
- Around line 1514-1516: The TypedFilter[T] type assertion is currently done
against the outer filter value, so when filters have been wrapped by LiftFilters
(i.e., values of type liftedFilter[Outer, Inner]) the inner filter's
LookupType() is ignored and meta.Type falls back to reflection; update the logic
around the TypedFilter[T] check to detect a liftedFilter wrapper
(liftedFilter[Outer, Inner]) and, if present, extract its inner filter and, when
that inner implements TypedFilter[T], call inner.LookupType() and assign
meta.Type accordingly (or alternatively implement LookupType() on liftedFilter
to forward to its inner filter) so typed lookup overrides are preserved.

---

Nitpick comments:
In `@entity_filters_test.go`:
- Around line 350-352: Add a regression case that exercises typed overrides via
LiftFilters: create or reuse an inner filter type that implements LookupType()
returning "number", wrap that instance with LiftFilters[...] and use it in the
same lookup construction path being tested, then assert that
lookup.Filters["amount"].Type == "number". Specifically, ensure the test wraps
the filter with LiftFilters, invokes whatever function builds the lookup (as in
the surrounding test), and replaces or adds the assertion following the existing
direct-filter check so it verifies the wrapped-filter path (referencing symbols
LiftFilters, LookupType, and lookup.Filters["amount"]).

In `@formatters/tree_formatter.go`:
- Around line 138-156: The normalizeTreeLabel implementation in
formatters/tree_formatter.go duplicates logic found in api/meta.go but differs
on ANSI stripping; extract the common logic into a shared utility function
(e.g., normalizeTreeLabel(s string, stripANSI bool) or similar) and update both
callers to call that shared function with stripANSI=false from
formatters/tree_formatter.go's usage and stripANSI=true from api/meta.go's
usage; ensure the new helper preserves the current behavior (trim trailing
spaces, drop blank lines after optional ANSI strip) and replace the local
normalizeTreeLabel with calls to the shared helper.

In `@task/manager_lifecycle.go`:
- Around line 156-189: The renderFinal method duplicates task snapshot logic;
replace the manual snapshot creation in renderFinal with a call to
tm.snapshotTasks() (the helper in render_hook.go) to avoid duplication and
ensure consistent snapshot semantics across render paths — locate renderFinal
and swap the block that creates taskSnapshot (the make/copy and mutex calls
around tm.tasks) to use taskSnapshot := tm.snapshotTasks(), preserving
subsequent use of taskSnapshot and existing bufferMutex/renderer logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 12939824-ea51-48c4-910c-f43d7768cad5

📥 Commits

Reviewing files that changed from the base of the PR and between 8a19ef2 and a792e3d.

📒 Files selected for processing (13)
  • api/keyvalue_test.go
  • api/meta.go
  • api/meta_tree_normalize_test.go
  • api/text.go
  • entity.go
  • entity_filters_test.go
  • formatters/tree_formatter.go
  • formatters/tree_formatter_test.go
  • task/manager.go
  • task/manager_lifecycle.go
  • task/render.go
  • task/render_hook.go
  • task/render_hook_test.go

Comment thread entity.go
…alog

Introduce a comprehensive docs generation system that creates markdown CLI references and clicky-ui surface catalogs from a CLI's command tree. Features include:

- New `docs` command group with `generate` subcommand supporting multiple output formats (markdown, json, yaml)
- Configurable docs site scaffolding for Astro Starlight with write-once starter pages and regenerated reference pages
- Per-controller documentation pages with depth-limiting to control command hierarchy inclusion
- UI surface catalog generation from clicky metadata with parameter role classification
- Integration with CobraExtensions for easy wiring into host CLIs
- Comprehensive test coverage for model building, rendering, and scaffolding

Expose ParamRole function in rpc package for reuse by docs generator. Update example to demonstrate docs configuration.

Refs: docs generation feature

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/cobra_walk.go`:
- Around line 65-69: nonEmptyDefault currently treats any DefValue == "false" as
empty, which drops string defaults that are literally "false"; change
nonEmptyDefault to only treat "false" as empty when the flag is a boolean flag.
Update the function nonEmptyDefault(flag *pflag.Flag) to check the flag's type
via flag.Value.Type() or equivalent (or use flag.Value.IsBoolFlag() if
available) and only return nil for DefValue == "false" when the flag is boolean;
otherwise return flag.DefValue unchanged.

In `@docs/command.go`:
- Around line 64-73: Add an explicit conflict check that returns an error if
both outputDir and outputFile are set: before choosing between scaffolding and
single-file flows (the block that calls runScaffold and the other branch around
RenderSingleFile/writeSingle), detect if outputDir != "" && outputFile != "" and
return a clear error (e.g., fmt.Errorf("flags --output and --output-dir cannot
be used together")). Update the logic around runScaffold, RenderSingleFile, and
writeSingle so the conflict is handled early and both locations perform the same
validation.

In `@docs/config.go`:
- Around line 39-44: The depth() logic contradicts the docs by treating c.Depth
== 0 as default; change it so depth() returns defaultDepth only when c is nil,
and treat both c.Depth == 0 and c.Depth < 0 as unlimited by returning
unlimitedDepth; update the conditional order in depth() to check c == nil first,
then c.Depth == 0 || c.Depth < 0 -> unlimitedDepth, otherwise return the
explicit c.Depth (use the existing symbols c.Depth, defaultDepth,
unlimitedDepth, and the depth() function).

In `@docs/provider.go`:
- Around line 54-57: The cleanBasePath function currently normalizes separators
but does not prevent path traversal; update cleanBasePath to split the
normalized path (e.g., strings.Split(p, "/")) and reject or return an
error/empty string if any segment equals "." or "..", and ensure callers that
use basePath for output path construction (where basePath is passed into
scaffolding/writes) check the cleaned result and refuse to use paths containing
those invalid segments; reference the cleanBasePath function and the code paths
where basePath is used for writing output so you validate and fail early when
traversal segments are present.

In `@docs/scaffold.go`:
- Around line 29-31: The code trusts provider.RelPath(page) and uses rel to
build abs (filepath.Join(dir, rel)) which allows absolute paths or “..” to
escape dir; before calling os.MkdirAll or os.WriteFile validate and canonicalize
the target: compute abs via filepath.Join(dir, rel), then call filepath.Clean
and filepath.Abs (or filepath.Join + filepath.Clean + filepath.Rel) and verify
that the resulting path has dir as its prefix (e.g., filepath.Rel(dir, abs) does
not start with ".." and is not an absolute escape); if the check fails, return
an error and skip MkdirAll/WriteFile. Apply the same containment check where
rel/abs are used around the MkdirAll/WriteFile blocks (lines referenced around
provider.RelPath, rel, abs, MkdirAll, WriteFile).

In `@extensions/cobra.go`:
- Around line 62-63: AllWithConfig() currently diverges from All() by not
attaching the DocsCommand, causing configured setups to miss docs registration;
update the fluent chain in AllWithConfig() (the method that composes
OpenAPICommand(), MCPCommand(), etc.) to also call DocsCommand() before
returning so its behavior matches All()—i.e., ensure the chain includes
OpenAPICommand().MCPCommand().DocsCommand() (or equivalent ordering) using the
same command-building helpers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ef969187-9372-47ea-927c-58bd937fbaa3

📥 Commits

Reviewing files that changed from the base of the PR and between a792e3d and f855c0b.

📒 Files selected for processing (15)
  • docs/cobra_walk.go
  • docs/command.go
  • docs/config.go
  • docs/docs_test.go
  • docs/markdown.go
  • docs/model.go
  • docs/pages.go
  • docs/provider.go
  • docs/reference.go
  • docs/render.go
  • docs/scaffold.go
  • docs/surfaces.go
  • examples/enitity/main.go
  • extensions/cobra.go
  • rpc/openapi.go

Comment thread docs/cobra_walk.go
Comment thread docs/command.go
Comment thread docs/config.go
Comment on lines +39 to +44
if c == nil || c.Depth == 0 {
return defaultDepth
}
if c.Depth < 0 {
return unlimitedDepth
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Depth == 0 behavior contradicts documented semantics.

The struct docs state “Depth 0 means unlimited,” but depth() maps 0 to defaultDepth (Line 39–40). This makes unlimited mode unreachable via the documented config value.

Suggested patch
 func (c *DocsConfig) depth() int {
-	if c == nil || c.Depth == 0 {
+	if c == nil {
 		return defaultDepth
 	}
-	if c.Depth < 0 {
+	if c.Depth == 0 || c.Depth < 0 {
 		return unlimitedDepth
 	}
 	return c.Depth
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if c == nil || c.Depth == 0 {
return defaultDepth
}
if c.Depth < 0 {
return unlimitedDepth
}
if c == nil {
return defaultDepth
}
if c.Depth == 0 || c.Depth < 0 {
return unlimitedDepth
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/config.go` around lines 39 - 44, The depth() logic contradicts the docs
by treating c.Depth == 0 as default; change it so depth() returns defaultDepth
only when c is nil, and treat both c.Depth == 0 and c.Depth < 0 as unlimited by
returning unlimitedDepth; update the conditional order in depth() to check c ==
nil first, then c.Depth == 0 || c.Depth < 0 -> unlimitedDepth, otherwise return
the explicit c.Depth (use the existing symbols c.Depth, defaultDepth,
unlimitedDepth, and the depth() function).

Comment thread docs/provider.go Outdated
Comment thread docs/scaffold.go Outdated
Comment thread extensions/cobra.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/scaffold.go`:
- Around line 36-37: Validate the page key before joining paths: ensure page.Key
(used by pageRelPath) does not contain path separators or traversal segments
(e.g., '/', '\\', or "..") and that the cleaned relative path equals the
original relative path; if validation fails, return an error or skip the page
instead of calling filepath.Join(dir, rel) to build abs. Target the code around
pageRelPath, rel and the filepath.Join(dir, rel) call and add the check there
(or inside pageRelPath) to defensively reject unsafe keys.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 98b88709-8e4b-4af4-975b-ae3b8e22ad72

📥 Commits

Reviewing files that changed from the base of the PR and between f855c0b and 959e6cf.

📒 Files selected for processing (7)
  • .gitignore
  • docs/command.go
  • docs/config.go
  • docs/docs_test.go
  • docs/pages.go
  • docs/provider.go
  • docs/scaffold.go
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/pages.go

Comment thread docs/scaffold.go
… instead of scaffolding provider-based sites

Remove the provider abstraction (astro, base-path, etc.) and simplify docs generation to write one markdown file per controller directly into the output directory as plain markdown without frontmatter.

Changes:
- Remove Provider interface and astroProvider implementation
- Remove --provider and --base-path CLI flags
- Remove DefaultProvider from DocsConfig
- Simplify Scaffold() to write flat files with pageRelPath() instead of provider.RelPath()
- Update command help text and examples to reflect new flat output structure
- Add assertNoPathCollisions() to prevent filename collisions between controllers and starter pages
- Update tests to verify flat file output without frontmatter

BREAKING CHANGE: --output-dir now writes one markdown file per controller directly into the directory instead of scaffolding a provider-based docs site. The --provider and --base-path flags are removed. Generated files no longer include YAML frontmatter.
@moshloop
moshloop force-pushed the feat/pluggable-live-renderer branch from 959e6cf to dc3a3ee Compare June 9, 2026 16:48
@moshloop
moshloop merged commit ef73ee7 into main Jun 9, 2026
12 of 13 checks passed
@moshloop
moshloop deleted the feat/pluggable-live-renderer branch June 9, 2026 16:54
@flankbot

flankbot commented Jun 9, 2026

Copy link
Copy Markdown

🎉 This PR is included in version 1.21.17

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.

2 participants