Commit Graph
160 Commits
Author SHA1 Message Date
KRATOSandClaude Opus 4.8 2ee03ac854 audit2: cli + modelregistry + dead-code cleanup (2 med, rest low)
cli: --reasoning-effort notice evaluates the EFFECTIVE model (works without --model) (MED); unsafe warning fires for --auto high too (MED); --auto value validated even with --skip-permissions-unsafe (LOW); DefaultRegistry built once per exec, not 3x (LOW); --profile kept as intentional legacy-compat accept-and-ignore (contested finding resolved, doc-commented). modelregistry: removed dead FallbackFor. tools: removed dead TaskNonInteractiveMessage + dead OnSandboxDecision hook (no setter anywhere); fixed the now-stale loop.go comment. TDD where behavioral; build/vet/full-suite green.

Refs #102

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 10:21:36 +05:30
KRATOSandClaude Opus 4.8 956724e8ef audit2: tui + mcp + skills fixes (2 med, 3 low)
tui: Ctrl+C now flushes the in-flight run's checkpoint session events before quitting (no orphaned blobs / broken rewind), mirroring Esc-cancel (MED); removed dead permission-modal MouseMsg branch (mouse capture is intentionally off) + its test (MED); /model//mode//effort//theme pickers refuse to open mid-run with a clear message instead of opening then refusing the selection (LOW). mcp: RegisterTools is atomic — stages all servers and commits only if all succeed, so a later server failure no longer leaves dead tools (LOW). skills: duplicate frontmatter names resolve deterministically (lexicographically-first dir wins) + Duplicates() surfaces collisions (LOW). TDD incl -race; build/vet/full-suite green.

Refs #102

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 10:14:24 +05:30
KRATOSandClaude Opus 4.8 ae5e40831f audit2: agent-loop fixes (1 med, 1 low)
executeTask propagates OnUsage into the child run so sub-agent token usage is counted (cost telemetry; activity callbacks stay nil) (MED); repeated-failure guard Stop mid-turn now appends aborted-placeholder tool results for unexecuted calls so result.Messages stays structurally valid (every tool_use answered) (LOW). The 'dead AgentEventType' finding was rejected — it's an intended TUI/headless/sessions contract, not dead code. TDD incl -race; build/vet/full-suite green.

Refs #102

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 10:05:22 +05:30
KRATOSandClaude Opus 4.8 4427152b83 audit2: tools fixes (4 high, 1 med)
grep no longer follows in-workspace symlinks to files outside the root (confinement) and computes clean workspace-relative match paths under a symlinked root (HIGH x2); apply_patch ChangedFiles + MutationTargets are workspace-relative when cwd!="." (HIGH); aliasedStringArg(allowEmpty) skips an empty primary so a populated alias wins — no more write_file content/path data loss (HIGH); registry.Without isolates a fresh update_plan for sub-agents so a task child can't clobber the parent's plan (MED). TDD incl -race; build/vet/full-suite green.

Refs #102

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 10:01:26 +05:30
KRATOSandClaude Opus 4.8 d04c42efab audit2: providers + runtime + zenline fixes (3 med, 7 low)
providers: OpenAI requests stream_options.include_usage (usage no longer 0); terminal finish/stop reason surfaced via CollectedStream.FinishReason+Truncated() across OpenAI/Anthropic/Gemini; Gemini emits ToolCallDropped for nameless functionCall; OpenAI max_completion_tokens wired; OpenAI uses providerio SSE (multi-line data join). runtime: empty-id delta-before-start no longer orphans args. zenline: overlay suppressed under permission prompt (PermLayout agreement) + overlay height capped; clip() display-width-aware; dead detailLines removed. TDD; build/vet/full-suite green.

Refs #102

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 09:55:00 +05:30
KRATOSandClaude Opus 4.8 a9655a6ad3 audit2: sandbox + sessions fixes (2 high, 2 med, 6 low)
sandbox: quoted-root rm -rf bypass (HIGH); interactive-detector quote/escape-in-token + segment-boundary false positives; chmod single-file not destructive. sessions: Fork copies checkpoint blobs so fork rewind works (HIGH); ApplyRewind atomic under one lock; pruneOrphanBlobs+capture race fixed under lock (verified real); restore preserves file mode; size-cap int64 (no 32-bit overflow); sessionLocks growth documented. TDD incl -race; build/vet/full-suite green.

Refs #102

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 09:41:38 +05:30
KRATOSandClaude Opus 4.8 0990971b30 Remove brainstorming process specs from the repo (keep local)
docs/superpowers/specs/*.md are local brainstorming/design process output, not shipped project docs (unlike PRD.md/INSTALL.md). Untrack (local copies kept) + gitignore docs/superpowers/. confirmation_policy.md is intentionally kept — it is go:embed'd into the agent loop.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 09:10:59 +05:30
KRATOSandClaude Opus 4.8 aa43970db8 Remove accidentally-committed audit doc from the repo (lives in issue #102)
docs/audit-2026-06-07-deep-audit.md was swept in by the same stray 'git add -A' as shop.html (18108b8). Its content is already tracked as GitHub issue #102, so it doesn't belong in the tree. Untracked (local copy kept) + gitignored.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 09:07:51 +05:30
KRATOSandClaude Opus 4.8 6dec2bf2ac Remove accidentally-committed shop.html test artifact + gitignore it
shop.html (a local test artifact) was inadvertently swept into 18108b8 by a 'git add -A'. Untrack it (file kept on disk) and add it to .gitignore so it stays out of the PR. Net diff no longer contains shop.html.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 08:50:37 +05:30
KRATOS 7c2d184b1d Merge branch 'zenline-runtime-work' into audit-fixes 2026-06-07 08:33:44 +05:30
KRATOSandClaude Opus 4.8 0372f0095e address PR #101 review (CodeRabbit): registry validation + test error checks
modelregistry: ModelEntry.Validate now requires DefaultReasoningEffort to be a member of ReasoningEfforts (not just a valid constant); NewRegistry adds a cross-entry pass verifying every Deprecation.FallbackID resolves to a known model so a misconfigured rule fails at startup instead of being silently ignored by ResolveWithFallback. sessions: checkpoint_test setup uses mustWriteFile/mustCapture/mustAppend helpers that check errors, so a setup failure is diagnosed at its source (errcheck-clean). The rewind double-count comment is already addressed by PR #103. Build/vet/-race/full-suite green.

Refs #102

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 08:33:14 +05:30
KRATOSandClaude Opus 4.8 18108b8b09 address PR #103 review (CodeRabbit): OnUsage, multi-cancel flush, unsafe-toggle guard, hitbox clamp
loop.go: keep OnUsage on the reactive retry (drop only OnText) so token telemetry counts the retry. tui: flushRunID -> flushRunIDs set so a second cancel before the first goroutine returns doesn't lose the first run's checkpoint flush; shift+tab now toggles Auto<->Ask only (Unsafe is no longer reachable by a casual keypress since it disables permission prompts). zenline: PermLayout returns inactive geometry when the button row is clipped at small heights so clicks can't resolve to allow/deny on non-button rows. providerio_test: check pw.Close (errcheck). Tests added; build/vet/-race/full-suite green.

Refs #102

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 08:28:30 +05:30
KRATOSandClaude Opus 4.8 4bc58e143e audit: document plugin/skills extension wiring as discovery-only (deferred lows)
The two remaining low findings (plugin manifest tools/hooks/prompts/skills parsed but unwired; plugin skill dirs not merged into the skill tool) are intentionally discovery-only for now — documented in code so the parsed-but-unconsumed fields aren't mistaken for dead code. Runtime wiring is tracked as a separate feature.

Refs #102

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 02:42:52 +05:30
KRATOSandClaude Opus 4.8 a180c32646 audit fixes: tui + cli (H5,H7,H8,M11 + lows)
Cancelled runs now flush in-flight session events incl. checkpoints so /rewind works + no orphaned blobs (H5); shift+tab cycles permission mode Auto/Ask/Unsafe (H7); interactive TUI defaults to Ask so write/edit/bash/apply_patch are advertised + gate through the permission prompt (H8 — VERIFY LIVE); zenline skin renders the ask_user questionnaire instead of a spinner when a prompt is pending (M11); applyExecMode runs before filter validation + --list-tools (low); mode-model deprecation notice surfaced via the shared --model path (low); zenline listed in --help (low). TDD incl. -race; build/vet/full-suite green.

Refs #102

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 02:41:17 +05:30
KRATOSandClaude Opus 4.8 1af7d22fb8 audit fixes: agent loop (M1,M2 + lows)
Redact intercepted ask_user/task outputs through the same boundary as the registry so secrets don't reach the transcript unredacted (M1); reactive mid-stream compaction retry drops OnText/OnUsage so text isn't double-streamed (M2); removed dead taskFallbackResult nil-provider branch (low); reactiveAttempted set only on a successful shrink so a no-op recover doesn't burn the one-shot budget (low); surface DroppedToolCalls even when a valid call is also present (low). TDD incl. -race; full-suite green.

Refs #102

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 02:26:23 +05:30
KRATOSandClaude Opus 4.8 ca39c857ef audit fixes: tools (H1,M3 + lows)
MutationTargets resolves path/patch via the same alias lists the tools use, so aliased writes get checkpointed and /rewind works (H1); updatePlanTool guards currentPlan with a mutex against the agent/TUI goroutine race (M3); optional path/cwd args (grep/glob/list_directory) treat an explicit "" as the default instead of erroring (low); deleted dead stringSliceArg (low). TDD incl. -race; full-suite green.

Refs #102

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 02:18:15 +05:30
KRATOSandClaude Opus 4.8 7a3ccff907 audit fixes: zenline render (M8,M9,M10)
Bound+reset the glamour renderer cache mdCache (M8); clip glamour output lines to frame width with ANSI-aware truncate so long URLs/code don't break the fixed-height layout (M9); PermLayout hit-test mirrors RenderChat's width/height clamps + overlay subtraction so mouse clicks land on the modal buttons (M10). TDD; full-suite green.

Refs #102

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 02:14:36 +05:30
KRATOSandClaude Opus 4.8 c2dacc802d audit fixes: mcp + providers + zeroruntime (H6,H9,M4 + lows)
mcp: schema conversion recurses Items/Properties/Required (H6); client.request runs a reader goroutine + selects on ctx, no blocking under lock (H9); connect/initialize timeout + ctx-aware Serve reads (low). providers: Anthropic+Gemini get the OpenAI-style idle watchdog via providerio.ScanSSEDataWithContext (M4); Gemini emitDone pointer receiver (low); Anthropic emits ToolCallDropped for nameless tool_use (low); OpenAI delegates to providerio error/redact, 503/529 classified (low). zeroruntime: toolCallCollector emits in start order + doesn't merge distinct empty-id calls / clobber names (lows). TDD; build/vet/-race/full-suite green.

Refs #102

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 02:06:42 +05:30
KRATOSandClaude Opus 4.8 634ec189b8 audit fixes: sandbox + sessions (H2,H3,H4,M5,M6,M7 + lows)
sandbox: Classify resolves command across command/cmd/script/shell (H4 destructive-gate alias bypass); rm -rf quoted/braced $HOME match (M6); firstProgram skip-list + sh -c/bash -c recursion + sudo/env option skipping (M7); piped-installer regex incl |sh/|zsh (low); chmod combined-flag/octal + rm -- (low). sessions: RestoreToSequence applies only the closest-to-target checkpoint per path (H2 + double-count low); resolveWithinWorkspace resolves symlinks to block in-workspace escape (H3); per-session flock across processes (M5); readBlob verifies sha256 (low); writeMetadata unique tmp suffix (low). TDD; build/vet/full-suite green.

Refs #102

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 01:51:25 +05:30
KRATOSandClaude Opus 4.8 29fe8e0c32 Batch 4: plugin manifest enrichment + skills system (PRD F9/F15)
Plugins: LoadedPlugin gains optional Author/License/Keywords/Homepage/Interface metadata (omitempty, non-breaking, best-effort parse) surfaced in 'zero plugins'. Skills: new internal/skills package loads */SKILL.md (hand-parsed frontmatter, no YAML dep) from ZERO_SKILLS_DIR or the XDG data dir; a read-only 'skill' tool lets the agent load a named skill's content on demand (registered in CoreReadOnlyTools); 'zero skills' lists them (+--json). Build/vet/-race/full-suite green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 00:58:28 +05:30
KRATOSandClaude Opus 4.8 956f71ddf9 Batch 3: subagents — task tool spawns isolated sub-agent runs (PRD F11)
agent.Options gains Provider (auto-injected in Run) + Depth. A 'task' tool is intercepted in executeToolCall (like ask_user): it spawns agent.Run as a child with Depth+1, a registry filtered via new Registry.Without("task","ask_user") (no infinite nesting, no interactive prompts), inherited Sandbox/PermissionMode/Autonomy but all interactive callbacks nil, sharing ctx for cancellation; the child's final answer becomes the tool result. Depth guard (maxTaskDepth=2) refuses deeper nesting with a clear message. Synchronous; async task output/stop deferred. Build/vet/-race/full-suite green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 00:51:06 +05:30
KRATOSandClaude Opus 4.8 7a5bb7f3f6 Batch 2: slash-command autocomplete + interactive pickers (TUI)
Typing '/' surfaces a filtered, navigable command list (Tab/↑↓ cycle, Enter/Tab complete, Esc dismiss) in both default and zenline skins — purely additive UI state that never disturbs the permission/ask_user/zenline/submit key precedence. Bare /model, /effort, /mode (and /theme in zenline) open an interactive selector overlay that routes the choice through the existing handlers. Build/vet/-race/full-suite green; existing key tests unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 00:45:30 +05:30
KRATOSandClaude Opus 4.8 33025186ba Zenline rendering tier: markdown + syntax-highlighted code + colored diffs (PRD F4)
Assistant messages now render through glamour (CommonMark + chroma-highlighted fenced code), themed to the active palette and sitting on the full-bleed bg. edit_file/apply_patch results render as colored, guttered unified diffs (green add / red del / dim context, 40-line cap). Rendered markdown is cached per (text,theme,width) with a 512-entry bound so RenderChat (called every spinner tick/keystroke) doesn't re-run glamour each frame. Streaming text stays plain (partial markdown renders badly). Adds glamour v1.0.0 + chroma v2 (offline from cache). Build/vet/-race/full-suite green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 00:34:12 +05:30
KRATOSandClaude Opus 4.8 a457ea3a7c Coerce bool/int tool args from string/number forms (weak-model tolerance)
boolArg accepts true/false/yes/no/on/off/1/0 (string or number); intArg accepts whole-number strings. Fixes minimax-m3's 'overwrite must be a boolean' and string-number args. Genuinely uncoercible values still error. Completes the arg-tolerance layer alongside string aliases.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 00:14:59 +05:30
KRATOSandClaude Opus 4.8 96f191e129 Zenline home/boot: uniform full-bleed themed background (no terminal-bg card)
Home/boot text used foreground-only styles, so content cells showed the TERMINAL's own background while lipgloss filled the surrounding whitespace with the theme bg — a visible two-tone 'card'. Added newCanvasStyles (foreground + theme background) for the full-bleed surfaces (home + boot), and set the theme bg on the input box and the centered-content wrappers, so the whole screen is one uniform themed background filling the terminal. Chat status bars keep the bg-free styles (they compose inside Panel-colored segments) so they're unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 00:11:35 +05:30
KRATOSandClaude Opus 4.8 2f0c6d54b2 Add repeated-tool-failure guard so no model loops on a bad tool call
guardState tracks consecutive same-error failures per tool: after 2 identical failures it injects a one-shot corrective hint (the tool's JSON arg schema + the exact error) so the model self-corrects; after 4 it halts the run with a clear message instead of burning turns to maxTurns. A successful call resets that tool's streak; the hint takes priority over plan reminders. Complements the arg-tolerance layer: tolerance prevents most mis-shapes, the guard backstops any that remain (any model, any tool). Build/vet/-race/full-suite green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-07 00:03:04 +05:30
KRATOSandClaude Opus 4.8 4eb8c0f389 Add shared model-agnostic tool-arg tolerance layer (aliases) for all models
internal/tools/argtolerance.go adds aliasedStringArg (alias-aware, type-strict, primary-key errors) and coerceStringSlice (best-effort list coercion). Every tool now accepts the key variants models emit: read_file/write_file/edit_file path->file/file_path/filename; content->contents/text/body/data; old_string->old/search/find; new_string->new/replace/replacement; apply_patch patch->diff; grep pattern->query/regex/search + path->dir/directory; glob pattern->glob/match/query + cwd->dir/path; list_directory path->directory/dir; bash command->cmd/script/shell. ask_user options/question coercion unified onto the shared helper. Type-strictness preserved (content:42 still errors). Serves the diverse multi-model userbase; build/vet/full-suite green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-06 23:59:20 +05:30
KRATOSandClaude Opus 4.8 76e6d74b8e Fix TUI: stop capturing the mouse so click/select/copy/paste work natively
Removed tea.WithMouseCellMotion() from the zenline program: mouse cell-motion reporting routed clicks to the app and broke the terminal's native text selection + copy (and made paste flaky). The permission modal is keyboard-driven (a/y/d/Esc), so capturing the mouse cost core UX for little gain. Click-to-select, Cmd/Ctrl+C copy, and Cmd/Ctrl+V paste now behave like a normal terminal.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-06 23:42:16 +05:30
KRATOSandClaude Opus 4.8 1bdbb46779 Harden ask_user + write_file arg parsing for weak models (minimax-m3)
ask_user: coerce options from objects ({label|value|text|...})/scalars/newline-strings instead of erroring 'options must be an array of strings'; accept bare-string question items and prompt/text/q/title aliases for the question. write_file: read content from contents/text/body/data/file_content aliases (minimax mis-keys 'content'); present-but-non-string still rejected. Same weak-model tolerance already applied to update_plan. Tests added; build/vet/-race green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-06 23:32:30 +05:30
KRATOSandClaude Opus 4.8 fa7cdef14d Slice 8: compaction execution — LLM-driven history compaction for long sessions
Proactive compaction at 80% of the model context window + reactive recovery on context-limit errors: summarizes the oldest middle messages into one user-role summary, preserves system + recent suffix. Pure Compact() (injectable Summarizer), low-water-mark guard against churn, suffix walked back to an assistant boundary so no consecutive-user/dangling-tool-result sequences, recover() gated on enabled. Disabled (no-op) when ContextWindow==0 — wired from the resolved model's context window in CLI+TUI. Build/vet/-race green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-06 23:19:59 +05:30
KRATOSandClaude Opus 4.8 45be88a6d8 Slice 7: agent modes — --mode flag + /mode command presets
Data-driven presets (smart/deep/fast/large/precise) bundling model + reasoning effort + max turns (+ optional tool filter), resolved through the registry. --mode seeds only unset exec options so explicit --model/-r/--max-turns still win; /mode lists/switches in the TUI. Build/vet/test green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-06 23:03:43 +05:30
KRATOSandClaude Opus 4.8 4c5fc2fc0e Slice 6: ask_user tool — agent asks clarifying questions mid-run
New read-only ask_user tool (questions[] with options/multiSelect); the loop intercepts it like permissions and routes to Options.OnAskUser. TUI shows an async questionnaire (buffered channel + ctx.Done select, mirroring the permission flow — no deadlock); headless leaves OnAskUser nil so it degrades gracefully to 'proceed with assumptions'. Build/vet/-race green; 13 new tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-06 22:55:37 +05:30
KRATOSandClaude Opus 4.8 af74523363 Slice 5: agent guardrails — no-output guard + plan-enforcement reminders
Stops a run after 3 consecutive empty turns (no text/tool calls) instead of burning to maxTurns; one-shot not-called reminder (by turn 3 if a multi-step task skipped update_plan) and stale reminder (after 10 tool calls since last update_plan). Dropped-call turns excluded from the empty counter. Build/vet/-race green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-06 22:44:35 +05:30
KRATOSandClaude Opus 4.8 7634c08c1c Slice 4: sandbox depth — interactive/destructive command safety + confirmation policy
Pre-exec interactive-command detection (editors/pagers/REPLs/ssh/git-rebase-i) hardened against absolute-path, quoted, and $()/backtick-substitution bypasses; destructive-pattern hardening (fork bombs, block-device writes, rm -rf root variants); structured violation annotation on blocked bash; CONFIRMATION_POLICY embedded + appended to the system prompt; 'zero sandbox policy --effective'. Full 4-action permission-engine / 5x3 autonomy matrix deferred. Build/vet/-race green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-06 22:37:55 +05:30
KRATOSandClaude Opus 4.8 30545b4417 Slice 3: model registry depth — regex aliases, deprecation fallback, reasoning defaults
Resolve()/ResolveWithFallback()/FallbackFor() + DefaultReasoningEffort/EffectiveReasoningEffort wired into CLI --model and TUI /model (deprecated models auto-redirect with a notice; unknown ids like minimax-m3 pass through unchanged). zero models renders an aligned table; catalog entries decorated with match patterns/default efforts/deprecation rules. Provider reasoning-effort propagation deferred (needs request-schema change). Build/vet/test green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-06 22:16:33 +05:30
KRATOSandClaude Opus 4.8 80d817045d Zenline TUI + runtime-core reliability + session file checkpoints
Local development snapshot of one session's intertwined workstreams. Committed together because changes span shared files (provider.go, model.go, loop.go, types.go, streamjson) and can't be cleanly split without interactive hunk staging. Build + vet + full -race suite green.

Zenline TUI skin: Zen home / Statusline chat / permission-modal surfaces, 5 themes (Phosphor/Cyan/Sage/Violet/Mono), boot splash, mouse support, and a headless --snapshot mode (internal/zenline, cli/zenline.go, tui/zenline_view.go).

OpenAI provider: streaming tool-call accumulation hardening plus an idle-timeout watchdog (reader goroutine + context cancel) so a stalled upstream surfaces an error instead of hanging the agent forever.

Agent reliability: update_plan schema makes id optional/auto-numbered with an advertised item schema; malformed (nameless) tool calls feed a retry to the model instead of silently ending the turn; secret scrubbing at the registry boundary (covers agent loop AND MCP); structured ToolResult (changedFiles/display/redacted) surfaced via stream-json.

Session file checkpoints + safe rewind: before-mutation content snapshots (content-addressed, deduped, size-capped, 0600) captured on write/edit/apply_patch in TUI and headless; RestoreToSequence + ApplyRewind (path-traversal-guarded, session-locked); /rewind in TUI and 'zero sessions rewind' headless; stream-json checkpoint/restore events.

Design specs under docs/superpowers/specs/.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-06 21:41:38 +05:30
Anandan 2d41e24a5e Polish update target output (#99) 2026-06-06 16:49:40 +05:30
Vasanth T ef343643ae feat(tui): polish command output (#98)
* feat(tui): polish command output

* fix(tui): address command output review
2026-06-06 16:20:44 +05:30
Anandan 699df010e2 feat(update): verify release metadata by target (#97)
* Add update check target selection

* Reject empty update target flag
2026-06-06 15:58:41 +05:30
Anandan 3e4add95ab feat(update): expose release check target options (#96)
* Expose update check target options

* Reject non-positive update timeouts
2026-06-06 15:28:50 +05:30
Vasanth T 52fbb6d9e7 feat: add runtime permission decisions (#95) 2026-06-06 15:26:33 +05:30
Anandan 90b3cf1093 Add sandbox backend capability reporting (#94) 2026-06-06 15:04:20 +05:30
0c77dad190 feat(zerocommands): add typed sandbox policy, risk, violation, and decision snapshots (#92)
* feat(zerocommands): add typed sandbox policy, risk, violation, and decision snapshots

The merged permission and verification event contracts (#82) added
typed snapshots for config, providers, models, and sessions, and
PR #89 added the typed snapshot for the persistent sandbox grant
store, but the live sandbox policy, the live risk classification,
the live violation, and the live decision were still exposed as
the raw backend structs. The TUI render path, the headless
'zero sandbox policy --json' and 'zero sandbox decide' commands,
the audit log, and PR/CI automation all need typed snapshots so
they do not hand-roll map[string]any payloads and so they do not
have to re-implement the runtime default-mode translation
themselves.

This commit adds five typed snapshot constructors and a bundled
plan snapshot to internal/zerocommands.

SandboxPolicySnapshot
  - mode, network, enforceWorkspace, denyDestructiveShell, and
    allowPolicyOnlyRunner are copied verbatim from the underlying
    sandbox.Policy.
  - effectiveMode is the resolved policy mode. An empty Mode in
    the input falls back to ModeEnforce, which is the runtime
    default. Consumers can read EffectiveMode to render the 'what
    is actually in effect' line without re-implementing the
    default.
  - effectiveMode is JSON-omitted when empty so the snapshot
    shape stays stable for downstream consumers.

SandboxRiskSnapshot
  - level, categories, reason.
  - categories is copied and sorted alphabetically so the JSON
    output is deterministic.
  - reason is trimmed.

SandboxViolationSnapshot
  - code, toolName, action, path, reason, recoverable.
  - The pointer-returning helper returns nil for a nil input so
    callers can chain it through SandboxDecisionSnapshot without
    nil checks at the call site.

SandboxBackendSnapshot
  - name, available, platform, fallback, commandWrapping,
    nativeIsolation, executable, message.
  - executable and message are trimmed.

SandboxPlanSnapshot
  - bundles policy, backend, restrictions, and workspaceRoot into
    one payload so 'zero sandbox policy --json' can return one
    typed result describing the full sandbox posture.
  - each entry of restrictions is trimmed, whitespace-only
    entries are dropped, and the result is sorted alphabetically.
  - workspaceRoot is trimmed and JSON-omitted when empty.

SandboxDecisionSnapshot
  - action, reason, risk, grantMatched, grant, violation.
  - The optional grant pointer is converted with
    SandboxGrantSnapshotFromGrant (from PR #89) so the JSON shape
    matches the persistent-grant snapshot exactly.
  - The optional violation pointer is converted with
    SandboxViolationSnapshotFromViolation so the snapshot always
    carries the same shape regardless of the decision outcome.
  - When grant or violation is nil, the field is JSON-omitted.

Tests
  - TestSandboxPolicySnapshotFromPolicyFillsEffectiveMode:
    verifies EffectiveMode is enforced for an empty Mode, set
    to ModeDisabled for an explicit disabled mode, and
    preserved for an explicit enforced mode.
  - TestSandboxRiskSnapshotFromRiskSortsCategoriesAndTrimsReason:
    verifies alphabetical sort, trimmed reason, and that a nil
    Categories input produces a nil output (no spurious empty
    slice).
  - TestSandboxViolationSnapshotFromViolationHandlesNilAndTrims:
    verifies the nil-input contract and the trim behaviour for
    every string field.
  - TestSandboxBackendSnapshotFromBackendCopiesAllFields:
    verifies the boolean and string fields round-trip and the
    trim behaviour for the executable and message.
  - TestSandboxPlanSnapshotFromPlanSortsRestrictionsAndTrimsRoot:
    verifies alphabetical sort, per-entry trim, and workspaceRoot
    trim.
  - TestSandboxDecisionSnapshotFromDecisionAllowBranchHasNoViolation:
    verifies the allow path has no grant and no violation.
  - TestSandboxDecisionSnapshotFromDecisionPersistentDenyCarriesGrantAndViolation:
    verifies the deny path carries both the resolved grant and
    the violation, and that the grant snapshot matches the
    persistent-grant snapshot shape from PR #89.
  - TestSandboxDecisionSnapshotJSONShapeIsStable: verifies the
    stable keys and the nil-pointer omission.
  - TestSandboxPolicySnapshotJSONOmitsEmptyEffectiveMode:
    verifies the omitempty tag.

Verification
  - go build ./...
  - go vet ./...
  - go test -count=1 -p 1 ./internal/zerocommands/... \
           ./internal/sandbox/... ./internal/redaction/...

DRI: Gnanam (runtime core owner per WORK_SPLIT_PRD.md §4). Closes
the typed-snapshot gap for the live sandbox surface that the TUI
render path, the 'zero sandbox' headless commands, the audit log,
and PR/CI automation consume.

* fix(npmwrapper): make copyWrapperFixture create package.json with type:module

This ensures the isolated wrapper .js fixture is always treated as ESM (matching real package installs).

Previously, without it, Node treated the .js as CJS on some platforms/runners (especially Windows), causing SyntaxError before the missing-native console.error path.

This was causing TestNodeWrapperReportsMissingNativeBinary to get empty output + timeout on windows-latest smoke jobs (e.g. in PR 92).

The test now reliably hits the error path and captures the expected message on all platforms.

Also improves robustness of the npm wrapper smoke test added in #88.

---------

Co-authored-by: Gnanam <gnanam@local>
Co-authored-by: KRATOS <[email protected]>
2026-06-06 14:50:01 +05:30
Vasanth T 5b1b7edf74 feat(tui): surface sandbox permission events (#93)
* feat(tui): surface sandbox permission events

* fix(tui): stream permission rows live
2026-06-06 14:18:36 +05:30
KRATOSandGnanam 1ddbe9def0 feat(zerocommands): add typed MCP, hooks, and plugins snapshots (#90)
* feat(zerocommands): add typed MCP, hooks, and plugins snapshots

The merged permission and verification event contracts added typed
snapshots for config, providers, models, sessions, and the sandbox
grant store, but the MCP server config, hooks config, and loaded
plugin manifests still expose only the raw backend structs. The TUI
render path, the headless 'zero mcp', 'zero hooks', and
'zero plugins' commands, and PR/CI automation all need typed
snapshots so they do not hand-roll map[string]any payloads and do
not accidentally leak the secret material that lives in MCP
server Env and Headers.

This commit adds three typed snapshot constructors plus a bundled
backend lifecycle snapshot to internal/zerocommands.

MCPServerSnapshot
  - name, type, identity, url, command are copied verbatim and
    trimmed. They are non-secret metadata the operator needs to
    see when triaging an MCP failure.
  - argCount, envKeyCount, headerCount replace the slices and maps
    with counts. Secret material in Env and Headers is never
    serialized.
  - toolCount, allowGranted, denyGranted are optional runtime
    counts that the snapshot can carry when the caller has a live
    tool registry and a live permission store. A nil counts
    struct leaves the snapshot at zero.

HookSnapshot
  - id, name, event, matcher, command, args, enabled, source.
  - command and args are run through the standard redaction
    pipeline. Whitespace-only args are dropped so JSON output is
    tight.

PluginSnapshot
  - id, name, version, description, enabled, source, root,
    pluginDir, manifestPath are copied verbatim and trimmed so the
    operator can see where the manifest came from.
  - toolCount, promptCount, skillCount, hookCount replace the
    full extension slices with counts so the headless JSON output
    stays small.

BackendLifecycleSnapshot
  - bundles the three slices into a single payload so 'zero
    doctor' and 'zero config' can return one typed result that
    describes the full extensibility surface.
  - all three inner slices are always non-nil, so JSON output is
    always '[]' and never 'null'.

Tests
  - TestMCPServerSnapshotFromServerStripsSecretsAndCountsMaps:
    verifies env and header values never appear in the JSON
    output, and that the count fields record the maps' sizes.
  - TestMCPServerSnapshotWithCountsMergesRuntimeCounts: verifies
    the optional counts bundle is merged and that a nil bundle
    leaves the snapshot at zero.
  - TestMCPServerSnapshotsSortsAndReturnsEmptySliceForEmptyInput:
    verifies alphabetical sort and that nil input returns a
    non-nil empty slice whose JSON encoding is '[]'.
  - TestHookSnapshotFromDefinitionRedactsCommandAndTrimsFields:
    verifies command and args are redacted, and the surrounding
    fields are trimmed.
  - TestHookSnapshotsSortsByIDAndEvent: verifies the deterministic
    (id, event) ordering.
  - TestHookSnapshotsWithSourceTagsEverySnapshot: verifies the
    helper that tags every snapshot with the same source string.
  - TestPluginSnapshotFromPluginCollapsesSlicesToCounts: verifies
    the path fields are preserved verbatim and the count fields
    record the slices' sizes.
  - TestPluginSnapshotsSortsByIDAndReturnsEmptySliceForEmptyInput:
    verifies id-based sort and empty-slice stability.
  - TestNewBackendLifecycleSnapshotBundlesAndDefaultsNilsToEmpty:
    verifies the bundled payload, that nil inputs produce empty
    slices in the JSON, and that a populated input round-trips.

Verification
  - go build ./...
  - go vet ./...
  - go test -count=1 -p 1 ./internal/zerocommands/... \
           ./internal/mcp/... ./internal/hooks/... \
           ./internal/plugins/... ./internal/redaction/...

DRI: Gnanam (runtime core owner per WORK_SPLIT_PRD.md §4). Closes
the typed-snapshot gap for the three backend surfaces in §7.E
that the TUI render path, the headless commands, and PR/CI
automation consume.

* fix(zerocommands): strip URL credentials and preserve redacted arg position

Addresses the three actionable review items left on PR #90 by
CodeRabbit.

1. MCPServerSnapshotFromServer now strips userinfo from the URL
   field so credentials embedded in an MCP server URL
   (https://user:token@host) never reach the headless JSON output.
   The new stripURLCredentialsFromURL helper uses net/url.Parse to
   remove the User field, then returns the sanitized URL. A URL
   that fails to parse is returned trimmed (not empty) so the
   operator still sees the configured endpoint when triaging a
   malformed MCP configuration. A blank input returns blank.

2. redactStringSlice now preserves position. Previously the helper
   appended to the output slice and skipped any element whose
   redacted value was empty, which meant a fully-redacted secret
   in the middle of a hook command line would shift every
   following argument by one position. The helper now allocates
   the output slice to the input length and assigns each element
   by index, so a fully-redacted element becomes an empty string
   in the output rather than disappearing. Whitespace-only inputs
   also become empty strings by index, which matches the previous
   drop behaviour but without shifting positions. A nil or
   empty input still returns nil so the JSON output omits the
   field entirely.

3. Test coverage is extended for both changes:
   - TestHookSnapshotFromDefinitionRedactsCommandAndTrimsFields
     now asserts len(snapshot.Args) == len(def.Args) so a future
     regression that drops or shifts redacted args is caught.
   - TestHookSnapshotFromDefinitionPreservesPositionForRedactedArgs
     verifies that a secret in the middle of an arg list ends up
     as an empty-string element at the same index, while the
     surrounding non-secret args round-trip verbatim.
   - TestMCPServerSnapshotStripsURLCredentials verifies that an
     https://admin:secret123@host URL becomes the credential-free
     form and that the username, password, and the '@' separator
     do not appear anywhere in the snapshot.
   - TestMCPServerSnapshotPreservesURLWithoutCredentials verifies
     that a URL without userinfo passes through unchanged.
   - TestMCPServerSnapshotKeepsUnparseableURLInsteadOfEmpty
     verifies the tolerance contract: a malformed URL is returned
     trimmed rather than empty, so the operator still sees the
     configured endpoint when triaging a broken configuration.

Verification
  - go build ./...
  - go vet ./...
  - go test -count=1 -p 1 ./internal/zerocommands/... \
           ./internal/mcp/... ./internal/hooks/... \
           ./internal/plugins/... ./internal/redaction/...

DRI: Gnanam.

---------

Co-authored-by: Gnanam <gnanam@local>
2026-06-06 14:04:36 +05:30
Anandan 442f24c7de Remove Bun installer test dependency (#91)
* Remove Bun installer test dependency

* Harden installer smoke tests

* Stabilize npm wrapper subprocess tests

* Make npm wrapper fixture explicit ESM
2026-06-06 13:58:08 +05:30
KRATOSandGnanam b70fea7d6f feat(zerocommands): add typed SandboxGrantSnapshot contract (#89)
The merged permission and verification event contracts added typed
snapshots for config, providers, models, and sessions, but the
persistent sandbox grant store (internal/sandbox/grants.go) still
exposes only sandbox.Grant directly. The TUI render path, the
headless 'zero sandbox' command, and PR/CI automation all need a
typed snapshot so they do not hand-roll map[string]any payloads and
do not accidentally leak grant reasons that contain API keys or
tokens.

This commit adds SandboxGrantSnapshot alongside the existing
ProviderSnapshot, ModelSnapshot, SessionSnapshot, and
SessionTreeSnapshot in internal/zerocommands. The snapshot mirrors
the format of the existing typed contracts:

  - ToolName, Decision, MaxAutonomy, ApprovedAt are copied verbatim
    from the underlying grant. They are non-secret metadata.
  - Reason is run through the standard redaction pipeline before it
    is copied, so any secret material the user typed when granting
    is masked before the snapshot leaves the runtime.
  - All string fields are trimmed. An empty or whitespace-only
    Reason becomes an empty Reason in the snapshot so JSON output
    omits the field.

Two constructors are provided:

  - SandboxGrantSnapshotFromGrant(grant) for a single grant.
  - SandboxGrantSnapshots(grants) for a slice. Output is sorted
    alphabetically by ToolName so consumers (TUI, headless, JSON
    output) see a deterministic ordering. An empty input returns
    a non-nil empty slice so JSON output is always '[]' and never
    'null'.

A matched/unmatched helper is also added:

  - SandboxGrantMatchSnapshotFromLookup(toolName, lookup) pairs the
    typed snapshot with a Matched boolean. When the lookup did not
    match, the returned snapshot has Matched=false and a nil Grant
    pointer, so consumers can render the absence without inspecting
    an error or a typed zero value.

Tests
  - TestSandboxGrantSnapshotFromGrantRedactsReasonAndTrimsFields:
    verifies the secret in the reason is masked and the surrounding
    fields are trimmed.
  - TestSandboxGrantSnapshotFromGrantEmptyReasonBecomesEmpty:
    verifies whitespace-only reasons normalize to the empty string.
  - TestSandboxGrantSnapshotsSortsByToolNameAndReturnsEmptySliceForEmptyInput:
    verifies alphabetical sort and that nil input returns a non-nil
    empty slice whose JSON encoding is '[]'.
  - TestSandboxGrantMatchSnapshotFromLookupMatchedAndUnmatched:
    verifies the matched and unmatched code paths.
  - TestSandboxGrantSnapshotJSONShapeIsStable:
    verifies every JSON key is present so downstream consumers can
    rely on the shape.

Verification
  - go build ./...
  - go vet ./...
  - go test -count=1 -p 1 ./internal/zerocommands/... \
           ./internal/sandbox/... ./internal/redaction/...

DRI: Gnanam (runtime core owner per WORK_SPLIT_PRD.md §4).
Connects: 'zero sandbox' command rendering, TUI grants panel, and
PR/CI automation consumers to the persistent grant store without
leaking grant reasons.

Co-authored-by: Gnanam <gnanam@local>
2026-06-06 13:28:17 +05:30
Anandan ce8dec087d Replace npm wrapper with Node entrypoint (#88)
* Replace npm wrapper with Node entrypoint

* Fix npm wrapper test portability
2026-06-06 13:21:57 +05:30
Vasanth T 4f4f96511e feat(tui): premium splash + working-view redesign (#83)
* feat(tui): premium splash + working-view redesign

Centralized truecolor theme and a visual-first session UI.

Splash:
- Two-tone ANSI Shadow ZERO wordmark (bright blocks / dim shadow)
- Replace Enter/Tab/Ctrl+C keycaps with a permission-mode status line
- Rounded boxes for header and prompt

Working view (3 zones):
- Header bar: cwd, git branch, provider/model, run state
- Role-gutter rows (you / zero), tool rows with ok/err status and arg hints
- Colorized diff cards for patch/edit output
- Pinned status line: mode (left) + model, tokens, cost (right)

Internals:
- Centralized palette in theme.go (role/status/diff/mode styles)
- Enrich transcriptRow with tool/status/detail for structured rendering
- gitBranch resolves .git/HEAD including worktrees

* fix: stabilize tui startup rendering

* fix: preserve tui tool row metadata

* test: document tui event rendering contract
2026-06-06 13:14:15 +05:30
KRATOSandKRATOS 34ad21a551 Add runtime permission and verification event contracts (#82)
* feat: add runtime permission event contract

* feat: stream permission events from exec

* feat: add runtime command snapshots

* feat: add session rewind compaction plans

* feat: add verification event contracts

* fix: harden runtime contract review gaps

* test: assert approved exec stderr contract

* fix: address CodeRabbit CHANGES_REQUESTED items for #82

- Make OnSandboxDecision callback async + panic-safe (non-blocking, recovered) in tools/registry.go per CR.
- Add explicit regression test for ConfigSnapshot when ResolveRuntimeMetadata errors (no secret leak in Message/BaseURL).
- (Many prior items like shapedPayloadPreview for permission/tool events, dual-target conflict test, stderr empty on approved path, Kind/Framework preservation, redactCommand empty slice, etc. were already landed on this branch.)

All relevant tests now pass.

* fix(agent): make sandbox decision available synchronously on Result for permission events

The recent change to invoke OnSandboxDecision asynchronously (to satisfy non-blocking requirement) broke the agent's immediate capture of the decision for building PermissionEvent after registry.RunWithOptions.

- Add SandboxDecision *sandbox.Decision to tools.Result (not serialized).
- Populate it on all sandbox-involved return paths in registry.RunWithOptions (sync, before/while firing async callback for observers).
- In agent executeToolCall, use result.SandboxDecision for buildPermissionEvent (reliable ordering) instead of side-effect capture via the callback.
- The async callback is still supported for any external OnSandboxDecision consumers.

This fixes the two failing agent tests that were causing the cross-platform 'Smoke' CI jobs to fail on this PR:
- TestRunEmitsPermissionEventForPersistentSandboxGrant
- TestRunAppliesSandboxEvenInUnsafeMode

All go tests now pass.

---------

Co-authored-by: KRATOS <[email protected]>
2026-06-06 13:13:08 +05:30