@aemonge-dev/pi-stardeck 0.7.0 → 0.8.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 +1 -1
- package/packages/pi-stardeck/src/deck.ts +65 -47
package/package.json
CHANGED
|
@@ -421,7 +421,15 @@ function companionIconColor(text: string | undefined, active: boolean): string {
|
|
|
421
421
|
: 'accent';
|
|
422
422
|
}
|
|
423
423
|
|
|
424
|
-
function
|
|
424
|
+
function identityCluster(
|
|
425
|
+
state: HeaderDeckState,
|
|
426
|
+
theme: Theme,
|
|
427
|
+
): { text: string; trailingBare: boolean } {
|
|
428
|
+
// Line-1 corner identity: devbox lead chip, then the companion chips.
|
|
429
|
+
// Returns the assembled text plus whether the last chip is bare — bare
|
|
430
|
+
// chips keep the wide gap to their right (0.7.1 amendment: the major
|
|
431
|
+
// separator rides double-spaced after a bare trailing chip, matching
|
|
432
|
+
// the bare→bare chip spacing).
|
|
425
433
|
const texts = new Map<string, string>();
|
|
426
434
|
for (const item of state.piStatus?.nativeStatuses ?? []) {
|
|
427
435
|
if (item.key === 'goal' || texts.has(item.key)) continue;
|
|
@@ -452,14 +460,14 @@ function extensionStatusCodes(state: HeaderDeckState, theme: Theme): string {
|
|
|
452
460
|
),
|
|
453
461
|
});
|
|
454
462
|
}
|
|
455
|
-
let
|
|
456
|
-
let
|
|
463
|
+
let text = '';
|
|
464
|
+
let trailingBare = false;
|
|
457
465
|
for (const part of parts) {
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
466
|
+
text +=
|
|
467
|
+
text === '' ? part.text : `${trailingBare && part.bare ? ' ' : ' '}${part.text}`;
|
|
468
|
+
trailingBare = part.bare;
|
|
461
469
|
}
|
|
462
|
-
return
|
|
470
|
+
return { text, trailingBare };
|
|
463
471
|
}
|
|
464
472
|
|
|
465
473
|
const BLOCKED_NOTICE = '\u26d4 blocked';
|
|
@@ -521,9 +529,10 @@ function noticeTile(state: HeaderDeckState, theme: Theme): string {
|
|
|
521
529
|
}
|
|
522
530
|
|
|
523
531
|
function telemetryRowLeft(state: HeaderDeckState, theme: Theme): string {
|
|
524
|
-
// Line 4 left (
|
|
525
|
-
// thinking, then
|
|
526
|
-
//
|
|
532
|
+
// Line 4 left (deck-corner-context amendment): the global group —
|
|
533
|
+
// engine › thinking, then the long-horizon quota — owns the row's left
|
|
534
|
+
// end; the notice slot owns the right end (Task 3). Context and
|
|
535
|
+
// compaction live in the line-1 corner now.
|
|
527
536
|
return modelGroupLeft(state, theme);
|
|
528
537
|
}
|
|
529
538
|
|
|
@@ -532,10 +541,11 @@ export function machineCornerSegments(
|
|
|
532
541
|
theme: Theme,
|
|
533
542
|
nowMs = Date.now(),
|
|
534
543
|
): string[] {
|
|
535
|
-
// Machine corner (deck-machine-corner): icon-led
|
|
536
|
-
// the line-1 corner — coding quota flame with its
|
|
537
|
-
// memory, MCP availability,
|
|
538
|
-
//
|
|
544
|
+
// Machine corner (deck-machine-corner; deck-corner-context): icon-led
|
|
545
|
+
// machine readings for the line-1 corner — coding quota flame with its
|
|
546
|
+
// countdown, CPU, memory, MCP availability, context percent, summary
|
|
547
|
+
// (compaction) count, global cost — in that frozen order, joined by
|
|
548
|
+
// minor separators. Segments yield right-to-left on narrow frames.
|
|
539
549
|
const segments: string[] = [];
|
|
540
550
|
const flame = windowQuotaTiles(state, theme, nowMs);
|
|
541
551
|
if (flame !== '') segments.push(flame);
|
|
@@ -557,6 +567,23 @@ export function machineCornerSegments(
|
|
|
557
567
|
if (state.mcp) {
|
|
558
568
|
segments.push(color(theme, 'accent', `${state.mcp.healthy}/${state.mcp.total}`));
|
|
559
569
|
}
|
|
570
|
+
// deck-corner-context: context and summary counts ride the corner.
|
|
571
|
+
// Context wears warning at ≥ 85% (the threshold it carried engine-left);
|
|
572
|
+
// the summary count follows the context color as before.
|
|
573
|
+
const ctxColor =
|
|
574
|
+
state.contextPercent !== undefined && state.contextPercent >= 85
|
|
575
|
+
? 'warning'
|
|
576
|
+
: state.contextPercent === undefined
|
|
577
|
+
? 'dim'
|
|
578
|
+
: 'accent';
|
|
579
|
+
if (state.contextPercent !== undefined) {
|
|
580
|
+
segments.push(
|
|
581
|
+
color(theme, ctxColor, `\u{F0F86} ${formatDeckPercent(state.contextPercent)}`),
|
|
582
|
+
);
|
|
583
|
+
}
|
|
584
|
+
if (state.compactionCount > 0) {
|
|
585
|
+
segments.push(color(theme, ctxColor, `\u{F039E} ${state.compactionCount}`));
|
|
586
|
+
}
|
|
560
587
|
const cost = costTile(state, theme);
|
|
561
588
|
if (cost !== '') segments.push(cost);
|
|
562
589
|
return segments;
|
|
@@ -569,49 +596,37 @@ function deckCornerRight(
|
|
|
569
596
|
nowMs = Date.now(),
|
|
570
597
|
): string {
|
|
571
598
|
// Line 1 corner: the identity cluster (devbox lead, companion chips)
|
|
572
|
-
// split from the machine group by one major separator.
|
|
573
|
-
//
|
|
574
|
-
//
|
|
575
|
-
//
|
|
576
|
-
|
|
599
|
+
// split from the machine group by one major separator. A bare trailing
|
|
600
|
+
// chip keeps the wide gap before the separator (0.7.1 amendment);
|
|
601
|
+
// machine segments yield right-to-left (cost first) before the path
|
|
602
|
+
// truncates below a 20-column floor; the identity cluster never drops
|
|
603
|
+
// (always-visible contract).
|
|
604
|
+
const identity = identityCluster(state, theme);
|
|
577
605
|
const segments = machineCornerSegments(state, theme, nowMs);
|
|
578
606
|
const pathFloor = 20;
|
|
607
|
+
const cornerGap = identity.trailingBare ? ' ' : ' ';
|
|
579
608
|
for (let keep = segments.length; keep >= 0; keep -= 1) {
|
|
580
609
|
const tail = segments.slice(0, keep).join(` ${minorSeparator(theme)} `);
|
|
581
610
|
const corner =
|
|
582
|
-
tail === ''
|
|
611
|
+
tail === ''
|
|
612
|
+
? identity.text
|
|
613
|
+
: `${identity.text}${cornerGap}${semanticSeparator(theme)} ${tail}`;
|
|
583
614
|
if (keep === 0 || width - visibleWidth(corner) - 1 >= pathFloor) {
|
|
584
615
|
return corner;
|
|
585
616
|
}
|
|
586
617
|
}
|
|
587
|
-
return identity;
|
|
618
|
+
return identity.text;
|
|
588
619
|
}
|
|
589
620
|
|
|
590
621
|
function modelGroupLeft(state: HeaderDeckState, theme: Theme): string {
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
? 'dim'
|
|
596
|
-
: 'accent';
|
|
597
|
-
const segments: string[] = [];
|
|
598
|
-
if (state.contextPercent !== undefined) {
|
|
599
|
-
segments.push(
|
|
600
|
-
color(theme, 'accent', ` ${formatDeckPercent(state.contextPercent)}`),
|
|
601
|
-
);
|
|
602
|
-
}
|
|
603
|
-
if (state.compactionCount > 0) {
|
|
604
|
-
segments.push(color(theme, ctxColor, ` ${state.compactionCount}`));
|
|
605
|
-
}
|
|
622
|
+
// Line 4 left (deck-corner-context): fully global — model › thinking,
|
|
623
|
+
// then the long-horizon quota (weekly calendar, or whole-session
|
|
624
|
+
// percent when no windows exist). Context and compaction moved to the
|
|
625
|
+
// line-1 corner.
|
|
606
626
|
const quota = simpleQuotaTile(state, theme);
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
: [
|
|
611
|
-
globalLeft(state, theme),
|
|
612
|
-
semanticSeparator(theme),
|
|
613
|
-
segments.join(` ${minorSeparator(theme, ctxColor)} `),
|
|
614
|
-
].join(' ');
|
|
627
|
+
return quota
|
|
628
|
+
? [globalLeft(state, theme), semanticSeparator(theme), quota].join(' ')
|
|
629
|
+
: globalLeft(state, theme);
|
|
615
630
|
}
|
|
616
631
|
|
|
617
632
|
function simpleQuotaTile(state: HeaderDeckState, theme: Theme): string {
|
|
@@ -802,12 +817,15 @@ export function renderHeaderDeck(
|
|
|
802
817
|
// row's left end; the right end is notice-only. The machine group moved
|
|
803
818
|
// to the line-1 corner, so notices can no longer starve machine
|
|
804
819
|
// readings — the old wholesale yield is gone with the group itself.
|
|
820
|
+
// 0.7.1 amendment: a clean notice slot renders the dim `healthy`
|
|
821
|
+
// placeholder instead of trailing silence — it yields like a notice
|
|
822
|
+
// when the engine group needs the width.
|
|
805
823
|
const engineGroup = telemetryRowLeft(state, theme);
|
|
806
824
|
const noticeGroup = noticeTile(state, theme);
|
|
825
|
+
const rightGroup = noticeGroup !== '' ? noticeGroup : color(theme, 'dim', 'healthy');
|
|
807
826
|
const telemetryRow =
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
? alignedSingleRow(engineGroup, noticeGroup, boundedWidth)
|
|
827
|
+
visibleWidth(engineGroup) + 1 + visibleWidth(rightGroup) <= boundedWidth
|
|
828
|
+
? alignedSingleRow(engineGroup, rightGroup, boundedWidth)
|
|
811
829
|
: fit(engineGroup, boundedWidth);
|
|
812
830
|
|
|
813
831
|
// Band adjacency (Human-directed, accepted mockups; third 2.4
|