Commit Graph
3 Commits
Author SHA1 Message Date
PierrunoYTandClaude Sonnet 5 5658a36627 fix(tools): flag piped POSIX utilities before running on Windows (#412)
* fix(tools): flag piped POSIX utilities (head/tail/grep/...) before running on Windows

Zero always executes the bash tool through native cmd.exe on Windows
(shellExecutable() in bash.go), but the pre-flight Windows-syntax
detector only caught bash-style `cd /...` and bare `ls`. Anything
piped into head/tail/grep/wc/awk/sed/cut/xargs/tr — very common in
model-generated commands like `git log ... | head` — ran straight
through to cmd.exe, which has no such builtins, wasting a turn on a
guaranteed failure. Reported in the wild via `git log ... | head`
and a `git blame ... | grep` pipeline.

detectShellCommandIssue now also flags these before the command
runs, with the same "translate to cmd.exe / use Zero's native tools"
guidance already used for the cd/ls cases.

Note: the existing detectShellOutputIssue path (matching cmd.exe's
error text post-execution) only recognizes English strings and will
miss this on non-English Windows locales — the pre-flight check
above is locale-independent since it inspects the model-generated
command text rather than cmd.exe's translated error output.

Co-Authored-By: Claude Sonnet 5 <[email protected]>

* fix(tools): require whitespace/end after POSIX utility name, not just \b

CodeRabbit review on PR #412: windowsPosixUtilityPattern used \b after
the utility alternation, but \b only requires a non-word character
next — so tail-log.sh, grep-cli, and sed.exe would all false-positive
(the hyphen/dot satisfies \b without being a real command boundary).
Match windowsLSCommandPattern's existing convention: require
whitespace or end-of-string after the utility name instead.

Co-Authored-By: Claude Sonnet 5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 5 <[email protected]>
2026-07-04 08:09:22 +08:00
KRATOS b776a9281f fix(sandbox): grant ancestor metadata so cd into the workspace works (#302)
* fix(sandbox): grant ancestor metadata so cd into the workspace works

macOS seatbelt granted file-read* on each read root via (subpath "<root>"),
which covers the root and its descendants but NOT its parent directories. An
absolute cd (and any path the kernel canonicalises) must stat each ancestor to
traverse to a deeply-nested workspace like /Users/me/Downloads/app — those
parents weren't granted, so seatbelt denied the chdir and surfaced it as the
misleading 'cd: <path>: Not a directory' (ENOTDIR). This blocked the agent from
cd-ing into its own workspace (e.g. 'cd /abs/workspace && go test').

Fix: grant file-read-metadata + file-test-existence on the path-ancestors of
each read root (metadata only — ancestor contents stay unreadable). Same pattern
already used for /opt/homebrew, /usr/local, /System/Volumes/Data/private.

Verified end-to-end: 'cd /abs/workspace && ...' now succeeds under the real
generated profile. go build/vet/test green.

* fix(sandbox): skip path-ancestors for filesystem roots (invalid SBPL)

Follow-up to the ancestor-metadata traversal fix. A read root of "/" has no
ancestors, and (path-ancestors "/") is invalid SBPL — sandbox-exec aborts with
exit 65 and the sandboxed command can't launch at all. This was reachable via the
compat builder (ReadRoots=["/"] flipped to restricted under EnforceWorkspace) and
any degenerate "/" workspace.

seatbeltAncestorMetadataRule now skips any root that is its own parent
(filepath.Dir(clean)==clean), neutralizing "/" and volume roots regardless of
entry point. Verified: the compat profile now compiles under sandbox-exec (exit
0). Found by adversarial verification of the prior commit.

* fix(sandbox): grant the CLT toolchain so git/clang/make work

On macOS, /usr/bin/git (and clang, make, etc.) are thin stubs that resolve the
real binary under the active developer dir — usually
/Library/Developer/CommandLineTools. The sandbox's platform read roots didn't
include it, so the stub couldn't reach the real tool and failed with the
misleading 'xcode-select: No developer tools were found' error. Add
/Library/Developer (read-only) to the platform read roots.

* fix(sandbox): allow reading the user's global git config

git reads identity/config from the user's global git config, but the sandbox
confines reads away from HOME, so it failed with 'unable to access ~/.gitconfig:
Operation not permitted'. Grant read-only on the git config FILES specifically
(~/.gitconfig and ~/.config/git/config) — not the ~/.config/git directory, which
can hold an XDG credential store — so git runs while credentials and the rest of
HOME stay unreadable. The path-ancestors traversal grant covers reaching them.

* fix(sandbox): let the agent terminate user-owned processes on request

The seatbelt profile only allowed signaling the agent's own process group
((target self) (target pgrp)), so a process started by a PREVIOUS session — e.g.
a dev server still listening on a port — was in a different group and could not
be killed. The agent would thrash through kill/pkill/osascript/sudo, all denied,
and never stop the process the user asked it to terminate.

Relax to (allow signal). The kernel still enforces UID ownership: a sandboxed
command runs as the user, so it can only signal the user's own processes, never
root's or another user's. Verified end-to-end: a sandboxed command now kills a
different-group user-owned process under the real generated profile.

* fix(sandbox): let the agent find processes + guide it to working tools

Pairs with the signal fix (8b5018d). Two more gaps blocked process management:
- process-info was scoped to (target same-sandbox), so the agent couldn't even
  inspect processes outside its own sandbox. Relaxed to (allow process-info*).
- `ps` is setuid root and macOS sandbox-exec refuses to exec setuid binaries
  (privilege-escalation guard) — unfixable via profile. `pgrep` needs a blocked
  system service. So the agent kept thrashing on ps/pgrep/os.kill.

Add macOS shell guidance pointing the model at the tools that DO work: lsof to
find a process, kill to stop it. With the signal grant, lsof+kill now manages
processes reliably (verified end-to-end).

* fix(sandbox): grant git config at the seatbelt rule, not the shared profile

The git-config read paths (~/.gitconfig, ~/.config/git/config) were added to the
cross-platform permissionProfileReadRoots, so they leaked HOME-dependent absolute
paths into the platform-agnostic 'sandbox policy --json' snapshot and broke the
golden test on every OS (machine-specific paths + Windows separators).

Move the grant to seatbeltReadRule (macOS only, where reads are actually
confined): the PermissionProfile stays platform-agnostic so the golden is stable,
and the seatbelt profile still grants the config files + their ancestor metadata
for traversal. Verified: golden test green, full 'go test ./...' green, and git
still reads ~/.gitconfig under the real generated profile.

* fix(sandbox): grant ancestor metadata for platform read roots too

Addresses CodeRabbit review on #302. seatbeltAncestorMetadataRule was passed only
fs.ReadRoots + gitConfig, on the assumption that platform read roots are top-level
or already covered. /Library/Developer (the CLT toolchain) breaks that: it needs
/Library stat-able as an ancestor, so a chdir-style traversal into it (cd
/Library/Developer/CommandLineTools) failed with ENOTDIR even though reads
succeeded (exec doesn't require ancestor-stat the way chdir does).

Include the platform read roots in ancestorRoots when IncludePlatformRoots is set.
Verified: cd into the CLT toolchain now succeeds under the real profile; golden +
sandbox tests green. Regression test added.
2026-06-23 11:12:11 +05:30
6fb0231df8 TUI scrollback re-architecture, Lime chat surface, and deep-audit fixes (#158)
* docs(design): add Lime TUI prototype and rebuild spec

* tui: remove the zeroline skin system

One design remains in the tree ahead of the Lime rebuild: the zeroline
package, its TUI view/skin plumbing (Options.Skin/ThemeVariant/ThemeDark,
model skin branches, theme picker), and the zeroline CLI subcommand are
gone. /theme keeps its shell-only message.

* tui: replace the cyan palette with the Lime token table

theme.go is rebuilt around the Lime design tokens (docs/design/
zero_tui_lime.html): near-black panels, one lime accent, solid tint
stand-ins for the prototype's rgba overlays. Existing render sites map
onto the new role styles (ink/line/userPrompt/toolName/toolArg) without
layout changes; no hex exists outside theme.go.

* tui: build the Lime chat-surface components

Title bar with brand badge + context window, empty state replacing the
deleted splash (block-art 0, tagline, 1-3 starter suggestions), stream
blocks (user prompt gutter, muted interim with cursor, final-answer
accent rail, done line, bordered notes), tool cards with diff/read/
bash/grep bodies and MiniDot run spinner, borderless composer with
run-state hints, and the grouped status line. Final answers are marked
at append time; resolved tool calls collapse into their result cards.

* tui: fix Stage 2 review findings

Adversarial review of the chat-surface commit confirmed 15 issues, all
fixed here:
- wrapPlainText sliced wide runes by rune count: CJK/emoji prose could
  panic the TUI or emit lines ~2x the measure; split at width instead
- a cancelled run's streamingText leaked into the next turn's interim
  block; cancelRun now clears it
- orphaned tool-call cards (cancelled/errored turns) re-animated with
  the spinner on any later run; the glyph is now scoped to the call's
  own runID
- starter-suggestion digit capture was active while the chips were off
  screen (/clear mid-run); the guard now mirrors the render condition
- prompt submits while a deferred Ctrl+C quit is draining could start a
  run the quit would orphan; submission is blocked while exiting
- the running placeholder advertised ctrl+c (which quits) as the
  interrupt key; it now says esc
- read-card parser expected 'N: text' but read_file emits 'N | text',
  so the gutter and L-range never rendered on real output
- toolCard borders were one column short of the body rows
- diff tint bands now span the full row; NEW FILE renders green on
  addBg; preamble/no-newline lines are unnumbered meta and no longer
  shift hunk numbering
- card bodies and system notes paint the panel surface; the head gains
  the separate faintest arg column (grep target + pattern)
- title-bar overflow now truncates the minimal candidate instead of
  rendering the deleted design's 'ZERO … READY' line
- untracked the stray snake-game.html (left on disk, ignored)

* tui: restyle the interactive surfaces for Lime

Permission prompts render as the amber permission card (PERMISSION
badge, risk readout, key chips); resolved prompts collapse to one line
(allowed once/always/denied · tool) and unprompted allows fold into the
tool card's [auto] tag. Ask-user and spec-review prompts share the card
language with line borders. Autocomplete and picker overlays move onto
the panel/selection tints with the accent ❯ marker; model-picker rows
gain the provider dot and ctx · KEY_ENV metadata from the registry and
provider catalog. /resume renders its list as stacked session cards
(id + age, title, meta). Key handling is untouched everywhere.

* tui: adaptive width tiers, doc updates, final polish

Width tiers re-evaluate from the live width: ≥100 renders the full
spec; 80–99 drops the tool-arg column, header ctx, and the status
'interactive' group; 58–79 drops the diff/read gutters, bares the
badge, and keeps provider+tokens+mode; <58 renders a single-segment
header, rail-less cards, and a mode-only status line. Table-driven
tests cover {58,70,80,100,120} plus a frame-wide invariant that no
emitted line exceeds the terminal at any tier. Card bodies expand tabs
so width math holds. Dead splash-chip machinery (startupCommandNames,
startupOrder) is gone; README's TUI section now describes Lime.

* tui: fix final-review findings across Stages 3-4

A second adversarial review confirmed 14 issues, all addressed:
- permission collapse and tool-card pairing are now run-scoped (rcKey):
  providers with repeating synthetic ToolCallIDs (Gemini gemini_tool_N)
  could attribute a decision or result to a different run's call
- rehydrated always-grants no longer mislabel as 'allowed once'
  (GrantMatched fallback)
- the width invariant now actually holds everywhere: empty-state
  tagline/hint, ask-user rows, permission detail blobs, pending image
  chips, and the sessions trailing hint are wrapped or fitted; the
  invariant test renders the empty state and all of those rows at
  widths 24-120
- every card (permission, ask-user, spec-review, sessions, notes)
  drops side borders on tiny terminals, not just tool cards
- /resume card fields are sanitized against separator bytes from
  user-controlled titles
- the picker's selected row paints its gap so the selBg band is solid
- dead splash helpers (normalizedStartupWidth, countLines, nonEmpty,
  unreachable rowWelcome branch) and stale /theme comments are gone
- README no longer claims transcript scrolling keys or Tab-accept
  behavior that never existed; chatWidth documents its 24-col floor

Tag tui-lime-s4 moves to this commit.

* audit: deep-audit report, TUI scrollback re-architecture, and cross-module fixes

TUI: settled-row flush frontier prints history to native terminal
scrollback (tea.Println, ordered + ack-serialized); View() renders only
the live tail. Full diffs (400-line flush cap) and OSC 8 file:// links
land in history; streamed interim text, cancellation markers, ask_user
exchanges, and composer input history are preserved; run-scoped dedup
keys fix Gemini's repeating tool-call ids; /exit, Ctrl+C-after-Esc, and
cross-session late flushes no longer orphan or contaminate checkpoints.

Cross-module: zero search panic + offset mapping, usage report
robustness, 529 retry, SSE keep-alive watchdog, registry corrections,
update --check on dev builds, MCP ping + mcp list --json secret
redaction, sandbox.network config knob, doctor apiKey presence, atomic
config writes, C1-safe notifications, rune-safe truncation everywhere,
gofmt + vet CI gates, dead glamour dependency dropped.

Full audit report: docs/audit/2026-06-10-deep-audit.md (175 findings).

Co-Authored-By: Claude Fable 5 <[email protected]>

* tui: hide malformed ask_user tool errors

* fix tui malformed tool retries

* fix max-turn finalization

* upgrade tui agent guardrails

* fix coderabbit guardrail findings

---------

Co-authored-by: Claude Fable 5 <[email protected]>
Co-authored-by: Vasanthdev2004 <[email protected]>
2026-06-10 17:18:30 +05:30