How 'Fill' Width Behavior Works in Horizontal Containers in CLI‑Anything
TL;DR: In CLI‑Anything, a width: 'fill' declaration inside a horizontal container resolves to a fixed 300 px fallback rather than stretching to fill available space, because the intrinsicSize helper lacks parent width context during horizontal stack measurement.
The CLI‑Anything layout engine, located in sketch/agent-harness/src/layout.js, handles dimension calculations for terminal UI components. Understanding how the 'fill' width token behaves in horizontal containers is critical for building responsive CLI interfaces that don't break unexpectedly.
The Core 'Fill' Width Logic
The 'fill' width behavior is implemented in the intrinsicSize helper function. When processing a layer's dimensions, the engine checks for the 'fill' string in two locations:
// layout.js – intrinsic size handling
// https://github.com/HKUDS/CLI-Anything/blob/main/sketch/agent-harness/src/layout.js#L52-L57
if (w === 'fill') w = parentWidth || 300;
if (!w && layer._resolvedStyle?.width === 'fill') w = parentWidth || 300;
This logic reveals two critical characteristics:
'fill'requiresparentWidthto resolve dynamically- Without parent context, it falls back to a hardcoded
300pixels
Why Horizontal Stacks Break 'Fill' Expectations
The horizontal container implementation in layoutHorizontalStack does not propagate parent width to child measurements:
// layout.js – horizontal-stack layout
// https://github.com/HKUDS/CLI-Anything/blob/main/sketch/agent-harness/src/layout.js#L33-L41
function layoutHorizontalStack(layers, config, containerWidth, containerHeight) {
const padH = config.paddingHorizontal || 0;
const padLeft = config.paddingLeft || padH;
// ...
const totalChildWidth = sizes.reduce((s, sz) => s + sz.width, 0);
// ...
}
When measuring children, the engine calls intrinsicSize(l, undefined) — passing undefined as the parent width. This triggers the 300 px fallback for any 'fill' declaration.
The Layout Calculation Flow
- Measure phase: Each child calls
intrinsicSizewithout parent width context - 'fill' resolution: Converts to
300px instead of remaining space - Position phase: Children are laid out left-to-right using resolved widths
- Container sizing: Total width equals sum of child widths plus gaps and padding
Practical Code Example
// Example: horizontal container with mixed width declarations
const layout = {
type: 'horizontal-stack',
paddingHorizontal: 10,
gap: 5,
};
const layers = [
{ type: 'rectangle', width: 120, height: 40 }, // fixed 120 px
{ type: 'rectangle', width: 'fill', height: 40 } // resolves to 300 px
];
const result = computeLayout(layers, layout, 0, 0);
console.log(result);
Output structure:
| index | x | y | width | height |
|---|---|---|---|---|
| 0 | 10 | 0 | 120 | 40 |
| 1 | 135 | 0 | 300 | 40 |
The second rectangle receives 300 px despite the 'fill' declaration, because layoutHorizontalStack provides no parentWidth during measurement.
Working Around the Limitation
Since CLI‑Anything's horizontal containers don't support true fill-to-available-space behavior, consider these alternatives:
- Pre-calculate widths: Compute remaining space manually before passing to the layout engine
- Use vertical containers: The
'fill'height behavior may resolve more predictably invertical-stacklayouts - Fixed layouts: Specify explicit pixel widths for all horizontal children
- Nested groups: Wrap children in groups that provide explicit
parentWidthcontext through_resolvedStyle
Key Source Files
| File | Purpose |
|---|---|
sketch/agent-harness/src/layout.js |
Core layout engine with intrinsicSize and layoutHorizontalStack |
sketch/agent-harness/src/builder.js |
Layer object construction and _resolvedStyle handling |
sketch/agent-harness/src/primitives.js |
Primitive layer type definitions |
Summary
'fill'width requiresparentWidthto resolve dynamically in CLI‑Anything- Horizontal containers pass
undefinedas parent width during child measurement - 300 px fallback is applied universally when parent context is missing
- Container width equals sum of resolved child widths, not a constraint that children fill
Frequently Asked Questions
Why doesn't 'fill' width stretch to fill remaining space in horizontal stacks?
The layoutHorizontalStack function calls intrinsicSize(l, undefined) for each child, providing no parent width context. Without this context, the intrinsicSize helper cannot calculate proportional fill and defaults to 300 px. This is an implementation limitation in the current layout engine.
Can I force a child to fill remaining horizontal space?
Not natively. You must pre-calculate the available width (container width minus fixed children and gaps) and assign that value explicitly. The layout engine does not support flex-style growth factors or剩余空间分配 in horizontal containers.
Does 'fill' height behave the same way in vertical containers?
The vertical stack implementation (layoutVerticalStack) likely faces similar constraints, though the specific resolution path depends on whether containerHeight is propagated during measurement. Check the intrinsicSize calls in your specific version of layout.js to confirm.
Where is the 300 px fallback value defined?
The fallback appears twice in intrinsicSize at lines 52–57 of sketch/agent-harness/src/layout.js: once for direct layer.width checks and once for layer._resolvedStyle.width checks. Both use parentWidth || 300 as the resolution formula.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →