feat(statusfile): render the ambient drift line when idle

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-05 21:41:24 -04:00
parent 7507cc6d28
commit 4b2cb4242f
2 changed files with 52 additions and 22 deletions
+27 -18
View File
@@ -34,12 +34,15 @@ func DefaultPath() (string, error) {
}
// Render produces the single status line for the harness envelope, dispatching
// on the active mode. An idle harness ("") renders "idle"; an unknown kind
// renders a generic fallback so a future mode degrades gracefully rather than
// rendering nothing.
func Render(env mode.Envelope, now time.Time) string {
// on the active mode. An idle harness ("") renders the ambient coaching line as
// "⚠ <line>" when one is present, else "idle"; an unknown kind renders a generic
// fallback so a future mode degrades gracefully.
func Render(env mode.Envelope, ambientLine string, now time.Time) string {
switch env.ActiveMode {
case "":
if line := strings.TrimSpace(ambientLine); line != "" {
return "⚠ " + line
}
return "idle"
case "focus":
st, ok := env.Mode.(focus.State)
@@ -121,22 +124,24 @@ func remaining(st focus.State, now time.Time) string {
return fmt.Sprintf("%dm", mins)
}
// Writer periodically renders the harness envelope and writes it to a file,
// rewriting only when the line changes.
// Writer periodically renders the harness envelope (plus the ambient line) and
// writes it to a file, rewriting only when the line changes.
type Writer struct {
path string
state func() mode.Envelope
now func() time.Time
wake chan struct{}
path string
state func() mode.Envelope
ambient func() string
now func() time.Time
wake chan struct{}
last string
wrote bool
}
// NewWriter builds a Writer for path, reading the harness envelope via the given
// accessor (typically harness.State).
func NewWriter(path string, state func() mode.Envelope) *Writer {
return &Writer{path: path, state: state, now: time.Now, wake: make(chan struct{}, 1)}
// NewWriter builds a Writer for path, reading the harness envelope via state and
// the ambient coaching line via ambient (either may be supplied; a nil ambient
// is treated as "" by write).
func NewWriter(path string, state func() mode.Envelope, ambient func() string) *Writer {
return &Writer{path: path, state: state, ambient: ambient, now: time.Now, wake: make(chan struct{}, 1)}
}
// Wake asks the writer to re-render now rather than at the next tick. It is the
@@ -174,14 +179,18 @@ func (w *Writer) Run(ctx context.Context) {
}
func (w *Writer) write() {
line := Render(w.state(), w.now())
if w.wrote && line == w.last {
line := ""
if w.ambient != nil {
line = w.ambient()
}
rendered := Render(w.state(), line, w.now())
if w.wrote && rendered == w.last {
return
}
if err := os.WriteFile(w.path, []byte(line), 0o644); err != nil {
if err := os.WriteFile(w.path, []byte(rendered), 0o644); err != nil {
log.Printf("statusfile: write %s: %v", w.path, err)
return
}
w.last = line
w.last = rendered
w.wrote = true
}