Repository navigation
feat(session): record active prompt name and source - #228
Conversation
|
Please fix conflicts; for the rest, it's ready to be merged |
532c16f to
272345c
Compare
The session file never recorded which prompt shaped it, even though a prompt's %%mode= directive now drives permission enforcement. Add Session.prompt: Option<PromptRef> (name plus built-in vs user-file source), written at startup prompt resolution and kept in sync on every runtime prompt switch, with the last one winning. Old session files load unchanged via serde(default). The source is decided by content, not by file existence: ensure_global() seeds every embedded prompt into the global prompts dir on first run, so code.md being present there says nothing about whether the user touched it. source_of() reads the highest-precedence on-disk copy, mirroring load()'s last-writer-wins order, and reports UserFile only when that text differs from the compiled-in one or has no compiled-in counterpart.
272345c to
0b2d2bb
Compare
|
Conflicts fixed (rebased onto current While rebasing I found a defect in this PR worth fixing before merge, so the force-push also changes behavior. It now compares content instead: read the highest-precedence on-disk copy (mirroring |
Closes #227
Current behavior
The prompt shaping a session lives only in memory, on
ContextFiles::current_prompt_name. It is set at startup fromdefault_promptor--load-prompt, and updated at runtime throughapply_prompt_modeplus a few direct assignment sites. It surfaces in exactly one place, the status bar. The session file has no field for it, so a saved session cannot say whether it ran undercode,plan,review, or a user prompt file, even though a prompt's%%mode=directive now drives permission enforcement.What changes
Sessiongains#[serde(default)] pub prompt: Option<PromptRef>, wherePromptRefis{ name, source }andsourceisBuiltInorUserFile.context::promptsgainssource_of(name), a small helper that checks the same override directoriesload()already walks (global prompts dir, the project'sdata/prompts/,.zerostack/prompts/) to classify a resolved prompt's origin, without changingload()'sHashMap<String, String>return shape.default_promptblock and the--load-promptblock.apply_prompt_modenow takes the session and writes the field, so its five call sites (/prompt <name>,/review, chain phase transitions, both dot-prefix branches) pick it up by construction. The three sites that assigncurrent_prompt_namedirectly instead of going throughapply_prompt_mode(/prompt default, and the two dot-prefix restore paths) get the same treatment.#[serde(default)]keeps existing session files loading withprompt: None.Tests
src/session/mod.rsschema plus a save/load round trip test and a test that a session file written before this field existed still loads, withprompt: None.src/context/prompts.rs:source_ofunit tests for a built-in prompt, a user file shadowing a built-in name, and a prompt that only exists as a user file.src/tests/prompt_mode_tests.rs:apply_prompt_modenow asserts the session's recorded prompt name and source, including that an unknown prompt name is a no-op that leaves the previous record untouched, and that switching twice leaves the record reflecting the prompt active last.Verified with
cargo fmt --checkandcargo clippy --all-targets --all-features -- -D warnings, both clean.