Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
529e00c
fix: remove stale user_name field from ServerConfig in TUI
freesig Mar 30, 2026
281ab2e
fix: show tree panel by default when opening a spec in TUI
freesig Mar 30, 2026
676b029
fix: standardize data directory to ~/.spec-forest across all crates
freesig Mar 30, 2026
cfdb42b
feat: replace text input with tree-based directory explorer for seed …
freesig Mar 30, 2026
8c13c0d
feat: add depth picker when seeding spec from directory
freesig Mar 30, 2026
d01dad1
feat: display candidate answers in TUI main panel for user selection
freesig Mar 30, 2026
7489c29
feat: add mode/locality picker to TUI spec creation flows
freesig Mar 30, 2026
c221bd3
feat: add config menu with username setting to TUI
freesig Mar 30, 2026
68b2227
feat: add feature and question creation to TUI spec view
freesig Mar 30, 2026
27238c0
fix: persist username to local DB when set via TUI config menu
freesig Mar 30, 2026
606df3b
feat: add ad-hoc codesigning to macOS build script
freesig Mar 30, 2026
da57f43
feat: show sync disconnection indicator in TUI footer
freesig Mar 30, 2026
7d38d85
feat: add spec settings screen with active directory management
freesig Mar 30, 2026
b997cf3
fix: use hyphenated names for spec-forest DB path and app name
freesig Mar 30, 2026
38453ac
fix: replace eprintln with tracing to prevent TUI display corruption
freesig Mar 30, 2026
25d0306
feat: add toggleable log panel to TUI spec view
freesig Mar 30, 2026
e9e4aa4
feat: improve TUI answer candidate UX with full visibility and editor…
freesig Mar 30, 2026
b1fd7ec
feat: add node deletion to TUI with press-twice confirmation
freesig Mar 30, 2026
939b38c
fix: make tree the source of truth for TUI node selection
freesig Mar 31, 2026
23dfd52
feat: add toggleable auto-explore setting to TUI config
freesig Mar 31, 2026
d320558
feat: add tracing for Claude CLI response model and size
freesig Mar 31, 2026
cca35bc
refactor: remove spec-forest-db runtime dependency from TUI
freesig Mar 31, 2026
ae8ef05
fix: show explore keys in TUI candidates footer
freesig Mar 31, 2026
2a72304
feat: display full node and spec IDs in TUI for easy copying
freesig Mar 31, 2026
d8acf9c
fix: make TUI node edit load both question and answer
freesig Mar 31, 2026
ed1ebf3
fix: display tracing structured fields in TUI log panel
freesig Mar 31, 2026
f5c21c3
fix: preserve section markers when stripping comments in TUI editor
freesig Mar 31, 2026
ff9fa0c
feat: add simulation mode for interactive spec-driven software simula…
freesig Mar 31, 2026
144a2bd
fix: use Shift+Enter instead of Ctrl+Enter for simulation input submit
freesig Mar 31, 2026
dba261e
fix: show loading spinner in simulation channel panes during initial …
freesig Mar 31, 2026
749fbe8
fix: correct MCP config schema and display simulation errors in statu…
freesig Mar 31, 2026
22a95b7
feat: add shadow answer support to TUI for implementation status review
freesig Mar 31, 2026
1eb5804
fix: add Ctrl+S as alternative submit binding for simulation input
freesig Mar 31, 2026
a420f1d
fix: reinforce JSON output format on simulation resume turns
freesig Mar 31, 2026
cacbca5
feat: focus simulation context on selected node with ancestors and de…
freesig Mar 31, 2026
2a40108
fix: strengthen simulation prompt to enforce spec node references and…
freesig Mar 31, 2026
94577b2
feat: add cursor navigation and arrow key support to simulation inser…
freesig Mar 31, 2026
8393986
feat: add scenario input screen to simulation launch flow
freesig Mar 31, 2026
e7de8bc
feat: make simulation reports show explanation overlay instead of rep…
freesig Mar 31, 2026
d042d23
fix: stop continuous candidate polling in TUI while background tasks …
freesig Mar 31, 2026
ecdc9f6
fix: include spec_gap field in simulation prompt JSON schema so LLM a…
freesig Mar 31, 2026
b61cf2e
feat: allow updating simulation scenario mid-session and add log pane…
freesig Mar 31, 2026
e974f53
feat: add explicit decisions list, multiple spec gaps, and multi-digi…
freesig Mar 31, 2026
92e60a5
feat: add regenerate_feature MCP tool to update feature descriptions …
freesig Mar 31, 2026
1d23b9c
feat: add [R] Regen keypress in TUI to regenerate a feature from dire…
freesig Mar 31, 2026
30a64ee
fix: run feature regeneration in the project directory so Claude can …
freesig Mar 31, 2026
87161f7
feat: add depth picker modal for full exploration and end on answer
freesig Mar 31, 2026
7a53a49
fix: use JSON output format for Claude CLI to prevent tool output con…
freesig Mar 31, 2026
1ee7038
fix: rewrite simulation prompts to prevent AI from hallucinating unsp…
freesig Mar 31, 2026
8df5e46
feat: add consume whole spec toggle to simulation channel picker
freesig Mar 31, 2026
99145b4
fix: rebalance simulation prompts — render interactively but flag all…
freesig Mar 31, 2026
d5fbd19
fix: reframe simulation prompts from spec audit to faithful implement…
freesig Mar 31, 2026
1c0e123
feat: display captured key representations in simulation input
freesig Mar 31, 2026
8c209fe
feat: capture mouse left-clicks as input tokens in simulation insert …
freesig Mar 31, 2026
cfa61c8
feat: add explore code toggle to simulation channel picker
freesig Mar 31, 2026
793694a
refactor: unify MCP answer/update tools with api::answer_node
freesig Mar 31, 2026
2bf4fcc
fix: scope mouse capture to simulation insert mode only
freesig Mar 31, 2026
b65a81a
feat: auto-refresh TUI when ops are applied via MCP or sync
freesig Mar 31, 2026
ab34691
fix: convert MCP tool handlers to async to prevent runtime deadlock
freesig Mar 31, 2026
9a421cc
debug: add tracing to MCP tool call path to diagnose hang
freesig Mar 31, 2026
5f7a652
chore: reduce debug tracing to lightweight debug-level logs
freesig Mar 31, 2026
1cf0c3d
fix: use floor_char_boundary to prevent UTF-8 slicing panic in error …
freesig Mar 31, 2026
c8f9b54
feat: add persistent simulation notification system with session back…
freesig Mar 31, 2026
aec5353
fix: show notification bar whenever background sims exist, not just o…
freesig Mar 31, 2026
4b06bc0
feat: add Alt+S keybinding to regenerate shadow answers from TUI
freesig Mar 31, 2026
8a337ba
feat: add ? help popup and clean up footer key hints
freesig Mar 31, 2026
f0fed6e
feat: expose simulation mode via 10 MCP tools for agent-driven intera…
freesig Mar 31, 2026
eb24264
feat: add explore_code param to sim_start for code-aware simulation mode
freesig Mar 31, 2026
7d4c707
feat: pre-computed interaction tree for instant simulation responses
freesig Apr 1, 2026
ed88960
feat: show predicted interactions in TUI simulation view
freesig Apr 1, 2026
ae8ec65
feat: deeper interaction tree with back navigation, eager pregenerati…
freesig Apr 1, 2026
1514550
feat: add game mode for spec-updating play-through simulation
freesig Apr 1, 2026
ffb4e39
feat: prioritize high-entropy interactions in game mode prompts
freesig Apr 1, 2026
e79b1f2
feat: add breadcrumb navigation trail for simulation interactions
freesig Apr 1, 2026
627e1c4
fix: stricter JSON-only prompts and DRY up response parsing
freesig Apr 1, 2026
9eb87f6
feat: switch simulation runner to stream-json for tool call visibility
freesig Apr 1, 2026
108730b
fix: add --verbose flag required by stream-json output format
freesig Apr 1, 2026
7fb3744
feat: stream Claude CLI stdout for real-time tool call logging
freesig Apr 1, 2026
27ffd27
fix: use char-boundary-safe truncation for stream event logging
freesig Apr 1, 2026
2da051f
feat: flatten simulation tree JSON to nodes+edges adjacency list
freesig Apr 1, 2026
2ea6381
feat: add members screen to TUI for spec access management
freesig Apr 1, 2026
9fea765
feat: add lean game mode with DAG-based simulation navigation
freesig Apr 1, 2026
07edbf2
fix: restrict lean game AI to read-only spec tools
freesig Apr 1, 2026
2d148d1
feat: add delete spec from gallery with double-press confirmation
freesig Apr 1, 2026
20cca4f
fix: lean game back-nav during generation, auto-pregen on leaf nodes,…
freesig Apr 1, 2026
3eaf536
feat: lean game spec updates use AI to find best placement across who…
freesig Apr 1, 2026
8aba3ea
feat: replace background spec updates with manual send-actions flow
freesig Apr 1, 2026
062666c
fix: lean game modify updates display, send actions shows edge labels
freesig Apr 2, 2026
bca11f0
fix: lean game frontier indicator and auto-pregen after leaf navigation
freesig Apr 2, 2026
763a4a5
feat: lean send-actions prompt treats player journey as spec truth
freesig Apr 2, 2026
79a034f
fix: refresh spec nodes when returning from LeanGame/Simulation screens
freesig Apr 2, 2026
b8b3851
fix: prevent spec questions from leaking into lean game simulation ou…
freesig Apr 2, 2026
dcf0ad6
feat: preserve full navigation history for lean game send-actions
freesig Apr 2, 2026
57150e6
fix: eager pregen when navigating to frontier nodes in lean game
freesig Apr 2, 2026
3919b73
fix: display interactions when navigating to existing nodes in lean game
freesig Apr 2, 2026
9a58d93
fix: lean game spec updates now cover all features, not just UI
freesig Apr 2, 2026
d5c1c47
fix: add spec fidelity instructions to lean game system prompt
freesig Apr 2, 2026
9bf504b
feat: add warmup interactions while lean game loads
freesig Apr 2, 2026
c54c6a7
feat: scenario-driven spec gap exploration in lean game
freesig Apr 2, 2026
a6e9f82
feat: add TUI rendering and input handling for lean game warmup
freesig Apr 2, 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
2 changes: 2 additions & 0 deletions Cargo.lock

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

6 changes: 3 additions & 3 deletions crates/spec-forest-app/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ async fn static_handler(uri: Uri) -> Response {
fn default_db_path() -> String {
let dir = dirs::home_dir()
.expect("could not determine home directory")
.join(".spec_forest");
.join(".spec-forest");
std::fs::create_dir_all(&dir).expect("could not create ~/.spec_forest directory");
dir.join("spec_forest.db").to_string_lossy().into_owned()
dir.join("spec-forest.db").to_string_lossy().into_owned()
}

#[derive(Parser)]
#[command(
name = "spec_forest-app",
name = "spec-forest-app",
about = "Spec Forest server with embedded web UI"
)]
struct Cli {
Expand Down
19 changes: 19 additions & 0 deletions crates/spec-forest-db/src/op_apply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,16 @@ pub fn apply_op_to_conn(conn: &Connection, op: &SpecOp) -> Result<()> {
Ok(())
}

SpecOp::UpdateFeature { node_id, content, embedding: emb } => {
let now = crate::util::now_iso8601();
conn.execute(
"UPDATE nodes SET question = ?1, updated_at = ?2 WHERE id = ?3",
rusqlite::params![content, now, node_id],
)?;
embedding::upsert_embedding(conn, node_id, emb)?;
Ok(())
}

SpecOp::CreateContextNode { spec_id, node_id, question, embedding } => {
let now = crate::util::now_iso8601();
conn.execute(
Expand Down Expand Up @@ -343,6 +353,15 @@ pub fn apply_op_to_conn_no_embed(conn: &Connection, op: &SpecOp) -> Result<()> {
Ok(())
}

SpecOp::UpdateFeature { node_id, content, .. } => {
let now = crate::util::now_iso8601();
conn.execute(
"UPDATE nodes SET question = ?1, updated_at = ?2 WHERE id = ?3",
rusqlite::params![content, now, node_id],
)?;
Ok(())
}

SpecOp::CreateContextNode { spec_id, node_id, question, .. } => {
let now = crate::util::now_iso8601();
conn.execute(
Expand Down
6 changes: 6 additions & 0 deletions crates/spec-forest-protocol/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ pub enum SpecOp {
RemoveFeature {
node_id: String,
},
UpdateFeature {
node_id: String,
content: String,
embedding: Vec<f32>,
},
CreateContextNode {
spec_id: String,
node_id: String,
Expand Down Expand Up @@ -170,6 +175,7 @@ impl SpecOp {
| SpecOp::UpdateQuestion { node_id, .. }
| SpecOp::AddFeature { node_id, .. }
| SpecOp::RemoveFeature { node_id, .. }
| SpecOp::UpdateFeature { node_id, .. }
| SpecOp::CreateContextNode { node_id, .. }
| SpecOp::UpdateResidualEntropy { node_id, .. }
| SpecOp::ClearCandidates { node_id, .. }
Expand Down
2 changes: 1 addition & 1 deletion crates/spec-forest-sync/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ struct Cli {

fn default_db_path() -> String {
dirs::home_dir()
.map(|p| p.join(".spec_forest").join("sync.db"))
.map(|p| p.join(".spec-forest").join("sync.db"))
.unwrap_or_else(|| std::path::PathBuf::from("sync.db"))
.to_string_lossy()
.to_string()
Expand Down
4 changes: 3 additions & 1 deletion crates/spec-forest-tui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ edition = "2024"

[dependencies]
spec-forest = { path = "../spec-forest" }
spec-forest-db = { path = "../spec-forest-db" }
ratatui = "0.29"
crossterm = { version = "0.28", features = ["event-stream"] }
futures = "0.3"
Expand All @@ -18,6 +17,9 @@ tempfile = "3"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["fmt", "env-filter"] }
tracing-appender = "0.2"
uuid = { version = "1", features = ["v4"] }
serde_json = "1"

[dev-dependencies]
spec-forest-db = { path = "../spec-forest-db" }
tempfile = "3"
162 changes: 160 additions & 2 deletions crates/spec-forest-tui/src/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ pub enum Action {

// Spec list
OpenCreateSpec,
OpenSeedFromFile,
OpenSeedFromDir,
OpenSyncConfig,
OpenModelConfig,
DeleteSpec,

// Text input (shared across InputName, InputFile, SyncPasswordInput)
// Text input (shared across InputName, SyncPasswordInput)
TypeChar(char),
DeleteChar,
Cancel,
Expand All @@ -29,13 +30,40 @@ pub enum Action {
TogglePause,
CancelExplore,
EditNextQuestion,
AddFeature,
RegenerateFeature,
AddQuestion,
DeleteNode,

// Tree navigation
ExpandOrCollapseTreeNode,
CollapseTreeNode,
TreeUp,
TreeDown,
EditTreeNode,
SiblingUp,
SiblingDown,

// Directory browser
DirBrowserUp,
DirBrowserDown,
DirBrowserExpand,
DirBrowserCollapse,
DirBrowserGoToParent,
DirBrowserSelect,
DirBrowserCancel,

// Depth picker
DepthPickerUp,
DepthPickerDown,
DepthPickerConfirm,
DepthPickerCancel,

// Spec options picker (mode + locality)
SpecOptionsUp,
SpecOptionsDown,
SpecOptionsConfirm,
SpecOptionsCancel,

// Sync
SyncLogin,
Expand All @@ -44,5 +72,135 @@ pub enum Action {
// Model
SelectModel,

// Config
OpenConfig,
SetUsername,
ToggleAutoExplore,

// Spec settings
OpenSpecSettings,
SetSpecDirectory,
ClearSpecDirectory,

// Candidates
CandidateNext,
CandidatePrev,
AcceptCandidate,
EditCandidate,

// Log panel
ToggleLog,
LogScrollUp,
LogScrollDown,
LogScrollLineUp,
LogScrollLineDown,

// Shadow answers
GenerateShadow,
RegenerateShadow,

// Simulation - launch
LaunchSimulation,

// Simulation - channel picker
SimChannelUp,
SimChannelDown,
SimChannelToggle,
SimChannelToggleWholeSpec,
SimChannelToggleExploreCode,
SimChannelToggleGameMode,
SimChannelToggleLeanMode,
SimChannelConfirm,
SimChannelCancel,

// Simulation - scenario input
SimScenarioChar(char),
SimScenarioBackspace,
SimScenarioNewline,
SimScenarioConfirm,
SimScenarioCancel,

// Simulation - screen
SimEnterInsert,
SimExitToNormal,
SimBackgroundSimulation,
SimEndSimulation,
SimCaptureKey(crate::simulation::CapturedKey),
SimDeleteChar,
SimSubmitInput,
SimCycleChannel,
SimCycleLayout,
SimEnterReport,
SimEditScenario,
SimOpenRef(String),
SimRefDigit(char),
SimSelectInteraction(usize),
SimInteractionUp,
SimInteractionDown,
SimConfirmInteraction,
SimNavigateBack,
SimBreadcrumbFocus,
SimBreadcrumbLeft,
SimBreadcrumbRight,
SimBreadcrumbSelect,
SimBreadcrumbCancel,
SimCloseOverlay,
SimMouseClick { column: u16, row: u16 },

// Game mode
GameGroupUp,
GameGroupDown,
GameOutcomeLeft,
GameOutcomeRight,
GameConfirmChoice,
GameRejectOutcome,
GameRejectChar(char),
GameRejectBackspace,
GameRejectSubmit,
GameRejectCancel,
GameToggleUpdateLog,

// Lean game mode
LeanSelectUp,
LeanSelectDown,
LeanConfirm,
LeanGoBack,
LeanEnterQuery,
LeanEnterModify,
LeanEnterSendActions,
LeanEnterWarmupRespond,
LeanToggleUpdateLog,
LeanScrollUp,
LeanScrollDown,
LeanInputChar(char),
LeanInputBackspace,
LeanInputSubmit,
LeanInputCancel,
LeanInputNewline,
LeanBackground,
LeanEnd,

// Notification / session picker
OpenSessionPicker,
SessionPickerUp,
SessionPickerDown,
SessionPickerSelect,
SessionPickerDismiss,
DismissNotification,

// Members screen
OpenMembers,
MembersActivateInput,
MembersDeactivateInput,
MembersRemoveMember,
MembersInputChar(char),
MembersInputBackspace,
MembersInputSubmit,
MembersUp,
MembersDown,

// Help
ToggleHelp,

Noop,
}
Loading