feat: implement remaining PRD features (10 beads)
Complete the PRD feature set with shell gating pipeline, cache
improvements, layout enhancements, and diagnostics:
- Shell: exec_gated with allowlist/denylist, circuit breaker, env merge
- Shell: parallel prefetch via std::thread::scope for cold renders
- Cache: TTL jitter (FNV-1a), config hash namespace, garbage collection
- Cache: diagnostic tracking (hit/miss, age) for dump-state
- Layout: gradual drop strategy (one-by-one vs tiered)
- Layout: render budget timer with graceful priority-based degradation
- Layout: breakpoint hysteresis to prevent preset toggling
- Width: detection source tracking for diagnostics
- CLI: --no-cache, --no-shell, --clear-cache, env var overrides
- Diagnostics: enhanced --dump-state with section timing and cache stats
Closes: bd-3oy, bd-62g, bd-khk, bd-3q1, bd-ywx, bd-3l2,
bd-2vm, bd-1if, bd-2qr, bd-30o, bd-3ax, bd-3uw, bd-4b1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -13,18 +13,24 @@ pub fn render(ctx: &RenderContext) -> Option<SectionOutput> {
|
||||
return None;
|
||||
}
|
||||
|
||||
// --no-shell: serve stale cache only
|
||||
if ctx.no_shell {
|
||||
return render_from_cache(ctx, ctx.cache.get_stale("beads_summary")?);
|
||||
}
|
||||
|
||||
let ttl = Duration::from_secs(ctx.config.sections.beads.ttl);
|
||||
let timeout = Duration::from_millis(200);
|
||||
|
||||
let cached = ctx.cache.get("beads_summary", ttl);
|
||||
let summary = cached.or_else(|| {
|
||||
// Run br ready to get count of ready items
|
||||
let out = shell::exec_with_timeout(
|
||||
"br",
|
||||
&["ready", "--json"],
|
||||
Some(ctx.project_dir.to_str()?),
|
||||
timeout,
|
||||
)?;
|
||||
// Use prefetched result if available, otherwise exec
|
||||
let out = ctx.shell_results.get("beads").cloned().unwrap_or_else(|| {
|
||||
shell::exec_gated(
|
||||
ctx.shell_config,
|
||||
"br",
|
||||
&["ready", "--json"],
|
||||
Some(ctx.project_dir.to_str()?),
|
||||
)
|
||||
})?;
|
||||
// Count JSON array items (simple: count opening braces at indent level 1)
|
||||
let count = out.matches("\"id\"").count();
|
||||
let summary = format!("{count}");
|
||||
@@ -46,3 +52,17 @@ pub fn render(ctx: &RenderContext) -> Option<SectionOutput> {
|
||||
|
||||
Some(SectionOutput { raw, ansi })
|
||||
}
|
||||
|
||||
fn render_from_cache(ctx: &RenderContext, summary: String) -> Option<SectionOutput> {
|
||||
let count: usize = summary.trim().parse().unwrap_or(0);
|
||||
if count == 0 {
|
||||
return None;
|
||||
}
|
||||
let raw = format!("{count} ready");
|
||||
let ansi = if ctx.color_enabled {
|
||||
format!("{}{raw}{}", color::DIM, color::RESET)
|
||||
} else {
|
||||
raw.clone()
|
||||
};
|
||||
Some(SectionOutput { raw, ansi })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user