Add a separate e2e Go module that validates the shell integrations
against real shells instead of only asserting generated script text:
- layer 1: generate the init script per shell and feature-config
overlay (base, transient, rprompt, tooltips, full) and validate it
with the shell's own parser
- layer 2: boot each shell interactively in a pty (ConPTY on Windows,
creack/pty elsewhere) with a vt10x screen emulator, assert the
prompt renders and the session exits cleanly
- layer 3: feature scenarios asserting exit-code propagation,
transient prompt replacement, and rprompt right-alignment
Covers bash, zsh, fish, pwsh, and nu; tests skip cleanly when a shell
binary is absent or the platform cannot drive it faithfully. The
harness answers PSReadLine's DSR cursor queries on Unix ptys and
isolates sessions from the host's cache and nu vendor autoloads.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 8a75c4edb40b
Built on the ConfiguredLanguage engine, this exposes it directly to
users: a `type: "language"` segment configured with a `name` and a
`tools` list (executable, args, regex, version_url_template) needs
no dedicated Go file at all. Intended for one-off or less common
tools that don't warrant a built-in segment.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Entire-Checkpoint: 7daa163ced91
Most language segments were ~20-30 line Go files that only declared
file extensions, an executable name, and a version regex before
delegating to the shared Language base. Every new simple language
(e.g. the recent GCC PR) meant another one-off struct, test file,
and registration to review and maintain.
Replace fortran, ruby, clojure, crystal, elixir, julia, kotlin, lua,
nim, ocaml, perl, php, r, rust, swift, v, vala, zig, and dart with a
single ConfiguredLanguage engine driven by a built-in preset table.
Public config surface (segment type strings, all existing options)
is unchanged; this is purely an internal consolidation.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Entire-Checkpoint: 6d449f3da816
The multiline_keepprompt feature uses `zsh -n` to decide whether the
buffer is a complete command. With SHORT_LOOPS (on by default) `zsh -n`
accepts a bare loop header - `for i in 1 2`, `while true`, or the
`for i in 1 2 do;` form - as a complete empty loop, even though the line
editor keeps waiting for the body. The keep-prompt loop then exits early
and the transient prompt takes over mid-command.
Detect the disguised open header by re-parsing with an explicit
`do : done` appended and SHORT_LOOPS off: an open for/while/until/select/
repeat header absorbs it into a valid loop, while every genuinely
complete command - including the `for x (...) cmd` and `repeat n cmd`
short forms - orphans the `do` into a syntax error and is left untouched.
foreach is unaffected: it uses `end`, not do/done, and is already
reported incomplete.
Fish already exposes omp_repaint_prompt for scripts that need the
prompt re-rendered without running a command (theme reloads, custom
key bindings). Bring the same capability to zsh (omp_repaint_prompt,
also registered as a zle widget for bindkey) and PowerShell
(Invoke-PoshPromptRepaint).
Closes#7427
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: f87bb49a5f6b
Render palette values containing a Go template at resolution time,
with access to the global template properties (.Segments, .Env, ...).
A template can resolve to any color value, including another palette
reference, which then follows the existing recursive resolution and
its depth limit. Rendering is guarded by a cheap substring check so
static palettes are unaffected.
Closes#7572
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: e29966ae2d7f
Shells already report whether a command ran before the current prompt
via --no-status, but templates could not access it, so segments kept
showing the previous exit code after pressing enter on an empty line.
Expose the flag as the global .Executed boolean so templates can hide
stale command metadata, and route it through the data file replay with
the same flag precedence as the other env keys.
Closes#7679
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 0dcae3896550
merge() treated a bool/int field the source never mentioned the same
as one explicitly set to its zero value, so extending a config could
silently reset a base config's true/nonzero field back to false/0.
Uint/float fields had the opposite bug: an explicit zero override was
ignored. Both are fixed by tracking which keys were actually present
in the decoded source and consulting that during merge, falling back
to the previous behavior for configs built without going through the
decoder (e.g. existing tests), so no existing merge semantics change.
Entire-Checkpoint: 166050784b12
The legacy mapped_locations regex path replaced the first textual
occurrence of the captured substring anywhere in the path, not the
occurrence the regex actually matched, so a path with the captured
text appearing twice (e.g. re:.*/(src)/deep against
/home/src/project/src/deep) rewrote the wrong copy.
Entire-Checkpoint: de9bd63bb3e0
The color cycle is shared across every block in render order, so a
block always continued from wherever the previous block's segment
count left the rotation. restart_cycle re-points a block at the
cycle's first color, useful for a second prompt line that should
always start fresh.
Closes#5442
Entire-Checkpoint: cdb5e9d96343
A re: mapped_locations value could only reference the first capture
group, with the rest of the matched path left untouched. This adds an
opt-in mode that expands $1, $2, and ${name} references against the
full regex match, so a value can be built from multiple capture
groups. Default behavior is unchanged.
Closes#6334
Entire-Checkpoint: 116e27a41b09
Multi-level extends chains already resolved correctly, but a circular
chain (A extends B extends A) hung forever instead of erroring, and a
relative extends path inside a non-top-level config resolved against
the first config's directory instead of its own.
Closes#7531
Entire-Checkpoint: 352a31511f53
When a directory has files for multiple project types (e.g. both
package.json and composer.json), the fixed detection order always
picked the same one with no way to change it.
Closes#7594
Entire-Checkpoint: 3fc26ec17f3e
The worktree hasWorktree() function parses the reverse gitdir admin file
(worktrees/<id>/gitdir) using strings.TrimSuffix(content, ".git\n"),
which assumes the file always ends with a trailing newline. When the file
is missing its trailing newline (e.g., written by a third-party tool or
manual editing), the .git suffix is not stripped and remains in the
resolved repoRootDir path. This causes git commands to fail with:
fatal: cannot change to '.../.git': Not a directory
Fix by trimming trailing whitespace before stripping the .git suffix,
matching Git's own approach in read_gitfile_gently() which strips
trailing newlines with a while loop before parsing.
FixesJanDeDobbeleer/oh-my-posh#7267
goreleaser's --clean flag wipes the dist directory before building,
deleting the deps tarball that was written there beforehand. Move the
packaging step after goreleaser so the tarball survives into the
uploaded release artifacts.
Fixes#7668
Entire-Checkpoint: d7ecded13dbf
Extend the OSC 133;C emission with the just-submitted command line,
percent-encoded as kitty's cmdline_url= shell-integration extension.
Terminals and multiplexers no longer need process-tree inspection to
know what command a pane runs - a primitive Windows lacks entirely.
Encoding happens in-shell with builtins only, so no extra process
spawn per prompt; terminals that ignore the parameter still see the
bare mark.
Closes#7536
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 7f155fd83428
Vale CI lints AGENTS.md and .agents/skills at error level, while
markdownlint-cli2 never matches dot-directories - skill docs pass one
gate invisibly and fail the other locally. Capture that in the
project-knowledge codebase topic so the next docs change checks the
right gates.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 9040f7c63ee0
The Vale workflow still pointed at .github/skills, which moved to
.agents/skills - the run failed on the missing path. Point it at the
new location and resolve the error-level findings that surfaces in the
project-knowledge skill: reword three pwsh.md entries and allow
"dynamic scoping" in zsh.md, the proper name of the zsh feature,
via a file-scoped override like the existing ones.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: a1dfa73dfc62
AGENTS.md and .github/copilot-instructions.md drifted apart, each
holding sections the other lacked. Merge the Copilot file's richer
content (project overview, key commands, exploration rule, src/ layout,
shell integration, CLI commands, caching guardrail) into AGENTS.md and
reduce the Copilot file to a pointer, so guidance lives in one place
for every tool.
Also corrects the segment interface name (SegmentWriter, per
src/config/segment_types.go) and the artifact count (five, the list
already said so).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 46ce85fd9728
.agents/skills is the vendor-neutral Agent Skills location that Copilot,
Codex, Claude Code, and most other agents discover automatically, while
.github/skills is read by Copilot alone. Move the embedded skills there
and add project-knowledge, a committed per-topic memory of verified
gotchas (codebase, shells, terminal, testing).
The directory stays gitignored for apm-managed skills; only the three
embedded skills are allowlisted, mirroring the former .github/skills
pattern. AGENTS.md now tells agents to read the relevant topic before
starting work and to commit new findings alongside the change they
relate to.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 70fe8f468dbe
zsh-vi-mode wraps the zle-line-init widget, so its own line-init ran
only after .recursive-edit had consumed the entire editing session.
Every line accepted or interrupted from normal mode then left ZVM_MODE
out of sync with the active keymap, and zvm_select_vi_mode's same-mode
early return made the desync permanent: ESC could never switch back to
normal mode.
Run zvm_zle-line-init up front so keymap and mode bookkeeping are
aligned before editing starts, and shadow zvm_widget_wrapper's rawfunc
local so zvm_reset_prompt cannot resolve it dynamically and re-enter
this widget.
Fixes#5992
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 9c904da30dbe
Store cached segment writers as gob-encoded snapshots instead of
JSON strings. Restoring decodes the snapshot into the writer
initialized by MapSegmentWithWriter, so its unexported runtime state
(env, options) survives. Replacing the writer instance dropped that
state, and any method relying on it panicked after a restore,
crashing the prompt process until the cache entry expired.
The snapshot also keeps cached state immutable: storing the live
writer would share one mutable object between render passes and the
cache. Legacy JSON entries are deleted on first read and re-cached
in the new format.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: d710d5fd0af3
Plastic shadowed Base.Init without setting Base.Segment, a leftover
from before the base writer carried per-segment state. Any enabled
plastic segment then panicked with a nil pointer dereference as soon
as the prompt rendered and called SetText. Drop the override so the
promoted Base.Init runs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: eea3a34195eb
When a .csproj/.fsproj/.vbproj (or the project matched via a
solution) doesn't define a TargetFramework directly, MSBuild pulls it
from a Directory.Build.props further up the tree. The project segment
didn't account for that, so centrally-configured solutions showed no
version.
resolves#7670
Entire-Checkpoint: 55d5cdc9f52a
Adds a right_template option to the transient prompt, rendered
right-aligned at the end of the line. Supported in zsh (via RPROMPT)
and pwsh (via cursor save/restore, mirroring writePrimaryRightPrompt).
When a filler is configured it now fills the gap between both parts.
Also guards shouldFill against a negative padding length which would
panic in strings.Repeat.
resolves#4822
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>