@aemonge-dev/pi-stardeck 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -2
- package/packages/pi-stardeck/README.md +33 -66
- package/packages/pi-stardeck/index.ts +39 -202
- package/packages/pi-stardeck/src/deck.ts +15 -64
- package/packages/pi-stardeck/src/gauge.ts +1 -40
- package/packages/status/README.md +4 -4
- package/packages/status/index.ts +25 -321
- package/packages/status/src/active-work.ts +2 -58
- package/packages/status/src/ledger.ts +1 -3
- package/packages/status/src/openspec.ts +14 -8
- package/packages/status/src/publisher.ts +6 -76
- package/packages/status/src/reducer.ts +1 -19
- package/packages/status/src/types.ts +0 -1
- package/packages/work-state/README.md +33 -0
- package/packages/work-state/index.ts +160 -0
- package/packages/work-state/package.json +33 -0
- package/packages/work-state/src/focus.ts +100 -0
- package/src/index.ts +2 -0
|
@@ -5,7 +5,6 @@ import type { LspCapability, McpCapability } from './capabilities.ts';
|
|
|
5
5
|
import type {
|
|
6
6
|
FooterTelemetrySnapshot,
|
|
7
7
|
GitStatusSummary,
|
|
8
|
-
HeaderActivity,
|
|
9
8
|
HeaderSnapshot,
|
|
10
9
|
PiStatusSnapshot,
|
|
11
10
|
VimMode,
|
|
@@ -279,82 +278,34 @@ function spanTreeRows(state: HeaderDeckState, width: number, theme: Theme): stri
|
|
|
279
278
|
});
|
|
280
279
|
}
|
|
281
280
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
implementation: 'implementing',
|
|
290
|
-
'change-review': 'reviewing change',
|
|
291
|
-
regression: 'testing',
|
|
292
|
-
verification: 'checking',
|
|
293
|
-
'result-review': 'reviewing result',
|
|
294
|
-
answering: 'answering',
|
|
295
|
-
recovery: 'recovering',
|
|
296
|
-
'awaiting-validation': 'validation',
|
|
297
|
-
'awaiting-input': 'input',
|
|
298
|
-
'operation-aborted': 'stopped',
|
|
299
|
-
};
|
|
300
|
-
|
|
301
|
-
function activityLabel(state: HeaderDeckState): string {
|
|
302
|
-
const pathActivity = state.header?.work?.activityPath?.at(-1);
|
|
303
|
-
const pathLabel = safeText(pathActivity?.compact || pathActivity?.label || '');
|
|
304
|
-
if (pathLabel) return pathLabel;
|
|
305
|
-
const activity = state.header?.work?.activity;
|
|
306
|
-
// `awaiting-*` kinds are the rest face — they never speak for the band
|
|
307
|
-
// (a focused session still retires; quiet-activity-row amendment).
|
|
308
|
-
if (!activity || activity.kind.startsWith('awaiting-')) return '';
|
|
309
|
-
return ACTIVITY_LABELS[activity.kind];
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/** `editing deck.ts` / `reading schema.yaml` / `subagent: scout`. */
|
|
281
|
+
/** The band speaks only when an observed activity is live — one of the
|
|
282
|
+
* five title-state classes (editing/reading/grepping/bash/subagent).
|
|
283
|
+
* Fabricated phase words (`interpreting`, `planning`, …), the legacy
|
|
284
|
+
* activity projection, and the `awaiting Human` placeholder are gone
|
|
285
|
+
* (Human-directed simplify-deck-defaults): Pi's restored native working
|
|
286
|
+
* indicator owns mid-turn liveness, and the deck narrates only observed
|
|
287
|
+
* reality. */
|
|
313
288
|
function titleActivityLabel(activity: { class: string; target: string }): string {
|
|
314
289
|
return activity.class === 'subagent'
|
|
315
290
|
? `subagent: ${activity.target}`
|
|
316
291
|
: `${activity.class} ${activity.target}`;
|
|
317
292
|
}
|
|
318
293
|
|
|
319
|
-
/** The
|
|
320
|
-
*
|
|
321
|
-
* cost tokens or time. Both idle (`awaiting Human` + `— · 0 tok` or
|
|
322
|
-
* no meter) is zero activity — the band and its seam retire
|
|
323
|
-
* (Human-directed 2026-10-20, quiet-activity-row). */
|
|
324
|
-
/** Live phase word from the header's kind-based activity projection —
|
|
325
|
-
* fills the gaps between tools (thinking, planning, checking) so the
|
|
326
|
-
* band never claims `awaiting Human` mid-turn. The `awaiting-*` kinds
|
|
327
|
-
* are the REST face (awaiting Human review/input after settle): they
|
|
328
|
-
* never speak for the band, or a focused session would never rest
|
|
329
|
-
* (quiet-activity-row amendment). */
|
|
330
|
-
function liveKindLabel(state: HeaderDeckState): string {
|
|
331
|
-
const activity = state.header?.activity ?? null;
|
|
332
|
-
if (!activity || activity.kind.startsWith('awaiting-')) return '';
|
|
333
|
-
return ACTIVITY_LABELS[activity.kind] ?? '';
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/** The band's current left label: the precise title-state activity when a
|
|
337
|
-
* tool is observed, else the live phase word; empty when truly idle. */
|
|
294
|
+
/** The band's current label: the live observed activity; empty when
|
|
295
|
+
* nothing is observed — the band then retires wholesale. */
|
|
338
296
|
function observedActivityLabel(state: HeaderDeckState): string {
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
return title.activity ? titleActivityLabel(title.activity) : liveKindLabel(state);
|
|
342
|
-
}
|
|
343
|
-
return activityLabel(state) || liveKindLabel(state);
|
|
297
|
+
const activity = state.header?.title?.activity ?? null;
|
|
298
|
+
return activity ? titleActivityLabel(activity) : '';
|
|
344
299
|
}
|
|
345
300
|
|
|
346
301
|
function activityBandSpeaks(state: HeaderDeckState): boolean {
|
|
347
|
-
|
|
348
|
-
const turn = state.header?.turn ?? null;
|
|
349
|
-
const costSpeaks = turn !== null && (turn.tokens > 0 || turn.elapsedMs > 0);
|
|
350
|
-
return activitySpeaks || costSpeaks;
|
|
302
|
+
return observedActivityLabel(state) !== '';
|
|
351
303
|
}
|
|
352
304
|
|
|
353
305
|
function activityTile(state: HeaderDeckState, theme: Theme): string {
|
|
354
|
-
// Line 3 left: the observed activity owns the slot
|
|
355
|
-
//
|
|
356
|
-
|
|
357
|
-
return label ? color(theme, 'text', label) : color(theme, 'dim', 'awaiting Human');
|
|
306
|
+
// Line 3 left: the observed activity owns the slot; the turn cluster
|
|
307
|
+
// rides its right side and retires with it.
|
|
308
|
+
return color(theme, 'text', observedActivityLabel(state));
|
|
358
309
|
}
|
|
359
310
|
|
|
360
311
|
function turnCostTile(state: HeaderDeckState, theme: Theme): string {
|
|
@@ -96,12 +96,7 @@ export type HeaderWork = {
|
|
|
96
96
|
activityPath?: HeaderActivitySegment[];
|
|
97
97
|
};
|
|
98
98
|
|
|
99
|
-
export const HEADER_SELECTION_SOURCES = [
|
|
100
|
-
'openspec',
|
|
101
|
-
'session-work',
|
|
102
|
-
'subject',
|
|
103
|
-
'legacy',
|
|
104
|
-
] as const;
|
|
99
|
+
export const HEADER_SELECTION_SOURCES = ['openspec', 'subject', 'legacy'] as const;
|
|
105
100
|
|
|
106
101
|
export type HeaderSelection = {
|
|
107
102
|
source: (typeof HEADER_SELECTION_SOURCES)[number];
|
|
@@ -191,40 +186,6 @@ export const HEADER_PRESENTATION = {
|
|
|
191
186
|
locationColor: 'success',
|
|
192
187
|
} as const;
|
|
193
188
|
|
|
194
|
-
export const IDLE_HEADER_WORK: HeaderWork = {
|
|
195
|
-
lifecycle: 'listening',
|
|
196
|
-
titles: ['no focused task'],
|
|
197
|
-
color: 'accent',
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
export function displayedHeaderWork(work: HeaderWork | null | undefined): {
|
|
201
|
-
work: HeaderWork;
|
|
202
|
-
idle: boolean;
|
|
203
|
-
} {
|
|
204
|
-
return work ? { work, idle: false } : { work: IDLE_HEADER_WORK, idle: true };
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
export function runtimeHeaderWork(
|
|
208
|
-
work: HeaderWork | null | undefined,
|
|
209
|
-
agentBusy: boolean,
|
|
210
|
-
): { work: HeaderWork; idle: boolean } {
|
|
211
|
-
const displayed = displayedHeaderWork(work);
|
|
212
|
-
if (!agentBusy || !displayed.idle) return displayed;
|
|
213
|
-
return {
|
|
214
|
-
work: {
|
|
215
|
-
lifecycle: 'understanding',
|
|
216
|
-
titles: ['no focus'],
|
|
217
|
-
color: 'accent',
|
|
218
|
-
activity: { kind: 'understanding' },
|
|
219
|
-
},
|
|
220
|
-
idle: false,
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
export function lifecycleStatusLabel(work: HeaderWork | null | undefined): string {
|
|
225
|
-
return work ? `⟩ ${work.lifecycle}` : '⟩';
|
|
226
|
-
}
|
|
227
|
-
|
|
228
189
|
export type ContextGauge = {
|
|
229
190
|
percent: number;
|
|
230
191
|
percentText: string;
|
|
@@ -90,10 +90,10 @@ branch entry. The agent-callable `openspec_focus` tool shares the command's `sta
|
|
|
90
90
|
safeguarded `set`, deliberate `replace`, validating `validate`, and persistent `clear`
|
|
91
91
|
transitions; the `awaitingValidation` flag marks a focused task as awaiting Human
|
|
92
92
|
validation and auto-clears on the next `set`, `replace`, or `clear`. The
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
sessions
|
|
93
|
+
retired `work_focus`, `stage`, and `title` instruments are gone: stages
|
|
94
|
+
derive from events and Taskflow phases, the focus row falls back to the
|
|
95
|
+
native session name (named by `pi-title`) and then to legacy `session-subject`
|
|
96
|
+
entries from old sessions, read defensively and fail-soft.
|
|
97
97
|
|
|
98
98
|
Global routing belongs to native Ramona policy rather than this status package. This
|
|
99
99
|
package does not inject parent routing prompts, block parent tools, create Session Work
|