Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
4e9c516
feat(01-01): create tui module with TerminalGuard
BinaryMuse Feb 14, 2026
f665bc5
feat(01-01): create event types and async event loop
BinaryMuse Feb 14, 2026
a3ad163
feat(01-01): wire up tui module and integrate panic hook
BinaryMuse Feb 14, 2026
0ba697f
feat(01-02): create block state machine
BinaryMuse Feb 14, 2026
c5f3e51
feat(01-02): create App struct with state management
BinaryMuse Feb 14, 2026
892ec73
feat(01-02): integrate keyboard handling with App
BinaryMuse Feb 14, 2026
56458ec
feat(01-03): replace InlineUi with TerminalGuard and integrate EventLoop
BinaryMuse Feb 14, 2026
37018cc
refactor(01-03): clean up and apply clippy fixes
BinaryMuse Feb 14, 2026
c1ece6a
feat(02-01): create render module with block rendering functions
BinaryMuse Feb 14, 2026
b9a5886
feat(02-01): integrate theme loading and render module into inline.rs
BinaryMuse Feb 14, 2026
2b6c36a
docs(03): create phase plan for command generation
BinaryMuse Feb 14, 2026
7da7060
feat(03-01): add error block rendering with retry support
BinaryMuse Feb 14, 2026
3908ee1
feat(03-01): add exit mode configuration with --keep flag
BinaryMuse Feb 14, 2026
e95eb9c
docs(04): create phase plan for SSE streaming and conversation
BinaryMuse Feb 14, 2026
cdb2b91
chore(04-01): add SSE and markdown dependencies
BinaryMuse Feb 14, 2026
38e84f6
feat(04-01): add Streaming block state and app mode
BinaryMuse Feb 14, 2026
60d4163
feat(04-01): implement SSE streaming in event loop
BinaryMuse Feb 14, 2026
70dd427
feat(04-02): add markdown_to_spans() function
BinaryMuse Feb 14, 2026
8a83bcd
feat(04-02): implement edit mode transition and conversation flow
BinaryMuse Feb 14, 2026
60d300f
docs(04-02): complete markdown rendering and edit mode plan
BinaryMuse Feb 14, 2026
5b92f9d
docs(04.1): create phase plan for pure state architecture refactor
BinaryMuse Feb 15, 2026
9ffb979
Remove old planning docs from git
BinaryMuse Feb 15, 2026
275e07e
feat(04.1-01): add domain state types in state.rs
BinaryMuse Feb 15, 2026
66783d8
feat(04.1-01): add view model types in view_model.rs
BinaryMuse Feb 15, 2026
03c4873
feat(04.1-01): wire state and view_model modules into tui
BinaryMuse Feb 15, 2026
9a93de3
feat(04.1-02): add state transition methods to AppState
BinaryMuse Feb 15, 2026
3658a69
feat(04.1-02): rewrite app.rs as thin wrapper with compatibility layer
BinaryMuse Feb 15, 2026
2f4830a
feat(04.1-03): update render.rs to derive view model from state
BinaryMuse Feb 15, 2026
f99da7c
feat(04.1-03): update inline.rs to use new App/AppState API
BinaryMuse Feb 15, 2026
22fc61c
feat(04.1-03): remove old blocks module and clean up
BinaryMuse Feb 15, 2026
e6038b3
fix(tui): fix spinner and streaming text display issues
BinaryMuse Feb 15, 2026
af1558a
refactor(tui): change Block.content to Vec<Content>
BinaryMuse Feb 15, 2026
bb27df3
feat(tui): event-based state model and debug tooling
BinaryMuse Feb 16, 2026
92ae1fa
feat(04.1.1-01): extend AppState with session and status tracking
BinaryMuse Feb 16, 2026
1c14dfa
feat(04.1.1-01): migrate to unified /api/cli/chat endpoint
BinaryMuse Feb 16, 2026
5996d45
feat(04.1.1-01): update keyboard handling for cancel
BinaryMuse Feb 16, 2026
4268a15
chore(04.1.1-01): update comment to remove old endpoint reference
BinaryMuse Feb 16, 2026
9096cdc
feat(04.1.1-02): status-aware spinner and context-dependent footer
BinaryMuse Feb 16, 2026
c28f1b9
feat(04.1.1-02): implement 200ms spinner delay
BinaryMuse Feb 16, 2026
1c8c8bf
fix(05): revise plans based on checker feedback
BinaryMuse Feb 18, 2026
9a99592
feat(05-01): add WarningKind enum and Content::Warning variant
BinaryMuse Feb 18, 2026
cbb2416
feat(05-01): add confirmation_pending state and helpers
BinaryMuse Feb 18, 2026
12bc92a
feat(05-01): derive warnings in Blocks::from_state and update footer
BinaryMuse Feb 18, 2026
7709e54
feat(05-03): add Content::ToolStatus variant with spinner/checkmark r…
BinaryMuse Feb 18, 2026
c735b3f
feat(05-02): implement double-Enter confirmation and 'f' keybind
BinaryMuse Feb 18, 2026
470bbfc
fix(05-02): fix clippy warnings and verify full test suite passes
BinaryMuse Feb 18, 2026
fbeb4a1
docs(05-03): complete tool status display and code block rendering plan
BinaryMuse Feb 18, 2026
e31f5f4
feat(05-04): fix separator rendering to use proper box-drawing charac…
BinaryMuse Feb 18, 2026
54265ef
feat(05-04): add indicator column alignment for text content
BinaryMuse Feb 18, 2026
6c47a82
feat(05-04): add blank line spacing between content items within blocks
BinaryMuse Feb 18, 2026
45a0bf2
fix(tui): UI corrections for padding, wrap indent, and tool status
BinaryMuse Feb 18, 2026
26d3683
fix(tui): additional UI corrections for blank lines and tool status
BinaryMuse Feb 18, 2026
532812d
refactor(tui): use ratatui native wrapping instead of custom implemen…
BinaryMuse Feb 18, 2026
a08a30e
fix(05): accurate height calculation and leading spacing
BinaryMuse Feb 18, 2026
d8cf87a
test(05): add visual render test cases and runner script
BinaryMuse Feb 18, 2026
2b89ed7
feat(05): add --debug-state flag for state logging
BinaryMuse Feb 18, 2026
5e0ff1d
feat(05): add replay-states.sh for debug state visualization
BinaryMuse Feb 18, 2026
edfdbe1
fix(05): trim leading whitespace from LLM responses
BinaryMuse Feb 18, 2026
402904d
feat(ai): dynamic viewport sizing and streaming fixes
BinaryMuse Feb 19, 2026
09feebe
feat(ai): integrate tui-textarea for proper cursor and wrapping
BinaryMuse Feb 19, 2026
b335efb
Fix various bugs with wrapped input rendering
BinaryMuse Feb 19, 2026
3fd0368
Switch to Review mode immediately when receiving a suggest_command to…
BinaryMuse Feb 19, 2026
54e175b
Decouple spinner and app ticks
BinaryMuse Feb 19, 2026
644fe49
Clean up dangerous command warnings
BinaryMuse Feb 19, 2026
613cf72
Add bash and fish integration to atuin-ai
BinaryMuse Feb 19, 2026
236abff
Clippy
BinaryMuse Feb 19, 2026
5a529b4
Fix terminal resizing
BinaryMuse Feb 19, 2026
bf1e59c
Fix bug in danger flagging
BinaryMuse Feb 19, 2026
89e9082
Allow 'med' in addition to 'medium'
BinaryMuse Feb 19, 2026
30b32dd
Fix mkdocs live-reload not working
BinaryMuse Feb 20, 2026
c5ea6a1
Stream until end to catch session ID
BinaryMuse Feb 20, 2026
7ba5f2e
Add AI settings
BinaryMuse Feb 20, 2026
742d467
Derive default for AI settings
BinaryMuse Feb 20, 2026
11d26cd
Add docs for Atuin AI
BinaryMuse Feb 20, 2026
fff2360
typo
BinaryMuse Feb 20, 2026
fddd43b
Detect current shell in 'atuin ai init'
BinaryMuse Feb 20, 2026
e069f64
Remove the rest of .planning
BinaryMuse Feb 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
result
publish.sh
.envrc
.planning/

ui/backend/target
ui/backend/gen
Expand Down
83 changes: 83 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ features = ["ansi", "fmt", "registry", "env-filter"]

[workspace.dependencies.reqwest]
version = "0.13"
features = ["json", "rustls-no-provider"]
features = ["json", "rustls-no-provider", "stream"]
default-features = false

[workspace.dependencies.sqlx]
Expand Down
13 changes: 10 additions & 3 deletions crates/atuin-ai/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "atuin-ai"
edition = "2024"
description = "ai library for atuin"
description = "AI integration for Atuin CLI"

rust-version = { workspace = true }
version = { workspace = true }
Expand Down Expand Up @@ -30,8 +30,15 @@ tracing-appender = "0.2.4"
reqwest = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
crossterm = { workspace = true, features = ["use-dev-tty"] }
ratatui = { workspace = true }
crossterm = { workspace = true, features = ["use-dev-tty", "event-stream"] }
ratatui = { workspace = true, features = ["unstable-rendered-line-info"] }
futures = "0.3"
eventsource-stream = "0.2"
pulldown-cmark = "0.13.0"
async-stream = "0.3"
uuid = { workspace = true }
tui-textarea-2 = "0.9.1"
unicode-width = "0.2"

[dev-dependencies]
pretty_assertions = { workspace = true }
34 changes: 34 additions & 0 deletions crates/atuin-ai/render-tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/bin/bash
# Render all test cases from test-renders.json
# Usage: ./render-tests.sh [test_name]
# With no args: renders all tests
# With arg: renders only matching test (e.g., ./render-tests.sh 05)

set -e
cd "$(dirname "$0")"

JSON_FILE="test-renders.json"
FILTER="${1:-}"

# Build once
cargo build -p atuin-ai --quiet

# Count tests
TOTAL=$(jq length "$JSON_FILE")

for i in $(seq 0 $((TOTAL - 1))); do
NAME=$(jq -r ".[$i].name" "$JSON_FILE")
DESC=$(jq -r ".[$i].description" "$JSON_FILE")
STATE=$(jq -c ".[$i].state" "$JSON_FILE")

# Skip if filter provided and doesn't match
if [[ -n "$FILTER" && ! "$NAME" =~ $FILTER ]]; then
continue
fi

echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "[$NAME] $DESC"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "$STATE" | cargo run -p atuin-ai --quiet -- debug-render -f plain
echo ""
done
101 changes: 101 additions & 0 deletions crates/atuin-ai/replay-states.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#!/bin/bash
# Replay state snapshots from a debug state JSONL file
# Usage: ./replay-states.sh <state-file.jsonl> [entry-number]
# With no entry: renders all frames in sequence (press Enter to advance)
# With entry number: renders just that frame

set -e
# cd "$(dirname "$0")"

STATE_FILE="${1:-}"
ENTRY_FILTER="${2:-}"

if [[ -z "$STATE_FILE" ]]; then
echo "Usage: $0 <state-file.jsonl> [entry-number]"
echo ""
echo "Examples:"
echo " $0 /tmp/state.jsonl # Interactive replay of all frames"
echo " $0 /tmp/state.jsonl 15 # Show just entry 15"
exit 1
fi

if [[ ! -f "$STATE_FILE" ]]; then
echo "Error: File not found: $STATE_FILE"
exit 1
fi

# Build once
cargo build -p atuin-ai --quiet

# Count entries
TOTAL=$(wc -l < "$STATE_FILE" | tr -d ' ')

if [[ -n "$ENTRY_FILTER" ]]; then
# Show single entry
LINE=$(sed -n "${ENTRY_FILTER}p" "$STATE_FILE")
if [[ -z "$LINE" ]]; then
echo "Error: Entry $ENTRY_FILTER not found (file has $TOTAL entries)"
exit 1
fi

ENTRY=$(echo "$LINE" | jq -r '.entry')
LABEL=$(echo "$LINE" | jq -r '.label')
STATE=$(echo "$LINE" | jq -c '.state')

echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "[$ENTRY/$TOTAL] $LABEL"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "$STATE" | cargo run -p atuin-ai --quiet -- debug-render -f plain
else
# Interactive replay
echo "Replaying $TOTAL frames from $STATE_FILE"
echo "Press Enter to advance, 'q' to quit, or number+Enter to jump"
echo ""

CURRENT=1
while [[ $CURRENT -le $TOTAL ]]; do
LINE=$(sed -n "${CURRENT}p" "$STATE_FILE")
ENTRY=$(echo "$LINE" | jq -r '.entry')
LABEL=$(echo "$LINE" | jq -r '.label')
STATE=$(echo "$LINE" | jq -c '.state')

clear
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "[$CURRENT/$TOTAL] $LABEL"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "$STATE" | cargo run -p atuin-ai --quiet -- debug-render -f plain
echo ""
echo "[Enter: next] [p: prev] [number: jump] [s: show state JSON] [q: quit]"

read -r INPUT
case "$INPUT" in
q|Q)
break
;;
p|P)
if [[ $CURRENT -gt 1 ]]; then
CURRENT=$((CURRENT - 1))
fi
;;
s|S)
echo ""
echo "State JSON:"
echo "$STATE" | jq .
echo ""
echo "Press Enter to continue..."
read -r
;;
''|' ')
CURRENT=$((CURRENT + 1))
;;
*[0-9]*)
if [[ "$INPUT" =~ ^[0-9]+$ ]] && [[ "$INPUT" -ge 1 ]] && [[ "$INPUT" -le $TOTAL ]]; then
CURRENT=$INPUT
else
echo "Invalid entry number (1-$TOTAL)"
sleep 1
fi
;;
esac
done
fi
Loading