Merge "idle" into "waiting"
"Idle" was set by SessionStart and by nothing else, and there was no path back into it. So it never meant "sitting unused" -- it meant "opened and never asked anything yet", a state a few seconds long that you would almost never catch. Meanwhile a session that finished an hour ago and was forgotten showed as waiting, which is correct but leaves the fourth state with nothing to describe. A session that has just opened is waiting for your first prompt exactly as one that finished a turn is waiting for your next. They are the same thing, and now they are the same state. Three glyphs instead of four, which also gives the remaining three more room to be told apart in a monochrome panel. Files written by the previous hook still say "idle", and a session open across the upgrade must not disappear, so unrecognised states now read as waiting rather than being treated as unknown. Covered by a test that feeds an "idle" file to the store and asserts it comes back as waiting, sorted by age among the others. The "hide when nothing is running" setting goes with it. Its condition was "no sessions, or all of them idle"; with idle gone the second half is unreachable and the first was already unconditional, so the switch could no longer change anything. A control that does nothing is worse than no control. The compaction test also got stronger in passing: it now checks that a mid-turn SessionStart leaves a *busy* session alone, which is the case that matters. It used to assert from waiting, where the state it was guarding against happened to be the state already stored.
This commit is contained in:
+4
-3
@@ -42,9 +42,10 @@ export function drawState(cr, state, width, height, color) {
|
||||
cr.stroke();
|
||||
break;
|
||||
default:
|
||||
// Idle: same ring as "working", but dashed and dimmed. Reading as a
|
||||
// fainter version of a state you already know is the point -- nobody
|
||||
// is waiting on it.
|
||||
// Fallback for a state this build does not know, which should not
|
||||
// happen: sessions.js normalises anything unrecognised to "waiting".
|
||||
// Drawn dashed and dim so an unknown state looks uncertain rather than
|
||||
// impersonating one of the three real ones.
|
||||
cr.setDash([2, 2], 0);
|
||||
cr.setSourceRGBA(r, g, b, a * 0.5);
|
||||
cr.arc(cx, cy, radius, 0, 2 * Math.PI);
|
||||
|
||||
+7
-9
@@ -23,7 +23,6 @@ function stateLabel(state) {
|
||||
case 'blocked': return _('needs an answer');
|
||||
case 'waiting': return _('waiting for input');
|
||||
case 'busy': return _('working');
|
||||
case 'idle': return _('idle');
|
||||
default: return state;
|
||||
}
|
||||
}
|
||||
@@ -93,10 +92,9 @@ class ClaudeStatusIndicator extends PanelMenu.Button {
|
||||
});
|
||||
|
||||
// The panel is monochrome, so shape alone carries the state:
|
||||
// disc inside a ring — blocked on a permission prompt;
|
||||
// filled disc — turn finished, waiting for input;
|
||||
// ring — working;
|
||||
// dashed, dimmed — idle.
|
||||
// disc inside a ring — asking you something;
|
||||
// filled disc — input line free, your move;
|
||||
// ring — working.
|
||||
// Colour is left to the shell's own accents; an indicator that paints
|
||||
// its own red competes with them and stops matching the theme.
|
||||
const dot = new St.DrawingArea({
|
||||
@@ -164,7 +162,6 @@ class ClaudeStatusIndicator extends PanelMenu.Button {
|
||||
}
|
||||
|
||||
_updatePanel(sessions) {
|
||||
const hideWhenIdle = this._settings.get_boolean('hide-when-idle');
|
||||
const showAge = this._settings.get_boolean('show-age');
|
||||
const abbreviate = this._settings.get_boolean('abbreviate-names');
|
||||
|
||||
@@ -180,13 +177,14 @@ class ClaudeStatusIndicator extends PanelMenu.Button {
|
||||
? this._chipLabels.get(session.sessionId)
|
||||
: projectName(session.cwd);
|
||||
|
||||
const busy = sessions.some(s => s.state !== 'idle');
|
||||
this.visible = sessions.length > 0 && !(hideWhenIdle && !busy);
|
||||
// Nothing running means nothing to say; the button disappears rather
|
||||
// than sitting there empty.
|
||||
this.visible = sessions.length > 0;
|
||||
|
||||
// Age rides on the first chip only. Sessions are sorted by urgency, so
|
||||
// that is the one whose age decides anything; five ages side by side
|
||||
// would just be a wide row of numbers.
|
||||
const ageOnFirst = showAge && busy;
|
||||
const ageOnFirst = showAge && sessions.length > 0;
|
||||
const signature = sessions
|
||||
.map(s => `${s.sessionId}:${s.state}:${labelFor(s)}`)
|
||||
.join('|') + `|${ageOnFirst}`;
|
||||
|
||||
+5
-2
@@ -16,7 +16,7 @@ Gio._promisify(Gio.File.prototype, 'load_contents_async');
|
||||
|
||||
// Aggregation order: a session blocked on a permission prompt is the only one
|
||||
// that is actually stuck, so it outranks one that merely finished its turn.
|
||||
export const STATES = ['blocked', 'waiting', 'busy', 'idle'];
|
||||
export const STATES = ['blocked', 'waiting', 'busy'];
|
||||
|
||||
const KNOWN = new Set(STATES);
|
||||
const LIVENESS_INTERVAL = 20; // seconds
|
||||
@@ -200,7 +200,10 @@ export const SessionStore = GObject.registerClass({
|
||||
return null;
|
||||
}
|
||||
|
||||
const state = KNOWN.has(raw.state) ? raw.state : 'idle';
|
||||
// Anything unrecognised reads as "waiting", which also migrates files
|
||||
// left on disk by the older hook: those still say "idle", and a
|
||||
// session open since before the upgrade must not vanish from the panel.
|
||||
const state = KNOWN.has(raw.state) ? raw.state : 'waiting';
|
||||
return {
|
||||
sessionId: String(raw.session_id ?? name.replace(/\.json$/, '')),
|
||||
state,
|
||||
|
||||
Reference in New Issue
Block a user