@aemonge-dev/pi-stardeck 0.0.0-stage → 0.5.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.
Files changed (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +239 -2
  3. package/demo/pi-stardeck.tape +59 -0
  4. package/docs/architecture.md +103 -0
  5. package/docs/assets/pi-stardeck.gif +0 -0
  6. package/docs/development.md +128 -0
  7. package/licenses/README.md +17 -0
  8. package/licenses/pi-fancy-footer-LICENSE +21 -0
  9. package/licenses/pi-vim-LICENSE +21 -0
  10. package/package.json +81 -4
  11. package/packages/pi-fancy-footer-full-palette/LICENSE +21 -0
  12. package/packages/pi-fancy-footer-full-palette/LOCAL-CHANGES.md +41 -0
  13. package/packages/pi-fancy-footer-full-palette/README.md +468 -0
  14. package/packages/pi-fancy-footer-full-palette/package.json +52 -0
  15. package/packages/pi-fancy-footer-full-palette/src/api.ts +204 -0
  16. package/packages/pi-fancy-footer-full-palette/src/config-editor.ts +634 -0
  17. package/packages/pi-fancy-footer-full-palette/src/config.ts +852 -0
  18. package/packages/pi-fancy-footer-full-palette/src/data-widgets.ts +259 -0
  19. package/packages/pi-fancy-footer-full-palette/src/git.ts +130 -0
  20. package/packages/pi-fancy-footer-full-palette/src/index.ts +479 -0
  21. package/packages/pi-fancy-footer-full-palette/src/layout.ts +309 -0
  22. package/packages/pi-fancy-footer-full-palette/src/provider-status.ts +1466 -0
  23. package/packages/pi-fancy-footer-full-palette/src/render.ts +1061 -0
  24. package/packages/pi-fancy-footer-full-palette/src/shared.ts +903 -0
  25. package/packages/pi-stardeck/README.md +219 -0
  26. package/packages/pi-stardeck/index.ts +691 -0
  27. package/packages/pi-stardeck/package.json +32 -0
  28. package/packages/pi-stardeck/src/activity-age.ts +184 -0
  29. package/packages/pi-stardeck/src/capabilities.ts +105 -0
  30. package/packages/pi-stardeck/src/deck.ts +807 -0
  31. package/packages/pi-stardeck/src/gauge.ts +1323 -0
  32. package/packages/pi-stardeck/src/git-refresh.ts +5 -0
  33. package/packages/pi-stardeck/src/process-resources.ts +428 -0
  34. package/packages/pi-stardeck/src/title-state.ts +195 -0
  35. package/packages/pi-stardeck/src/title.ts +443 -0
  36. package/packages/pi-vim-top-border/LICENSE +21 -0
  37. package/packages/pi-vim-top-border/LOCAL-CHANGES.md +71 -0
  38. package/packages/pi-vim-top-border/README.md +577 -0
  39. package/packages/pi-vim-top-border/clipboard-mirror.ts +451 -0
  40. package/packages/pi-vim-top-border/clipboard-policy.ts +23 -0
  41. package/packages/pi-vim-top-border/cursor-shape.ts +131 -0
  42. package/packages/pi-vim-top-border/index.ts +4195 -0
  43. package/packages/pi-vim-top-border/input-keys.ts +49 -0
  44. package/packages/pi-vim-top-border/mode-change-command.ts +120 -0
  45. package/packages/pi-vim-top-border/mode-colors.ts +97 -0
  46. package/packages/pi-vim-top-border/mode-label.ts +62 -0
  47. package/packages/pi-vim-top-border/motions.ts +297 -0
  48. package/packages/pi-vim-top-border/package.json +47 -0
  49. package/packages/pi-vim-top-border/prompt-external-editor.ts +152 -0
  50. package/packages/pi-vim-top-border/prompt-rail.ts +334 -0
  51. package/packages/pi-vim-top-border/prompt-status.ts +131 -0
  52. package/packages/pi-vim-top-border/settings.ts +287 -0
  53. package/packages/pi-vim-top-border/text-objects.ts +389 -0
  54. package/packages/pi-vim-top-border/types.ts +51 -0
  55. package/packages/pi-vim-top-border/visual.ts +65 -0
  56. package/packages/pi-vim-top-border/word-boundary-cache.ts +196 -0
  57. package/packages/status/README.md +398 -0
  58. package/packages/status/index.ts +1717 -0
  59. package/packages/status/package.json +33 -0
  60. package/packages/status/src/active-work.ts +235 -0
  61. package/packages/status/src/config.ts +218 -0
  62. package/packages/status/src/diagnostics.ts +238 -0
  63. package/packages/status/src/goal-block.ts +377 -0
  64. package/packages/status/src/goal.ts +170 -0
  65. package/packages/status/src/ledger.ts +101 -0
  66. package/packages/status/src/openspec.ts +394 -0
  67. package/packages/status/src/orchestration.ts +237 -0
  68. package/packages/status/src/publisher.ts +1294 -0
  69. package/packages/status/src/reducer.ts +190 -0
  70. package/packages/status/src/runtime-runs.ts +267 -0
  71. package/packages/status/src/state.ts +178 -0
  72. package/packages/status/src/title-activity.ts +224 -0
  73. package/packages/status/src/title-state.ts +218 -0
  74. package/packages/status/src/turn-cost.ts +63 -0
  75. package/packages/status/src/types.ts +228 -0
  76. package/src/deck-surface.ts +46 -0
  77. package/src/health.ts +228 -0
  78. package/src/index.ts +28 -0
  79. package/src/pi-status.ts +334 -0
@@ -0,0 +1,219 @@
1
+ # pi-stardeck
2
+
3
+ A dependency-free Pi extension that coordinates the prompt information architecture
4
+ through Pi's supported widget and event APIs.
5
+
6
+ ```text
7
+ ─ 󰠭 › ─────────────────────────────────────────────────────────────────────
8
+ ( 3 ›  2 · 00:05'12) working ⟩ checking Stabilize runtime and focus · step 3/5  task 1/2 ›  stps 3/5
9
+ 󰓾 Stabilize runtime and focus in the cockpit
10
+ ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
11
+ [󰆧]  ~/projects/example  main ⟩  clean
12
+ ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
13
+ 󰚩 Opus › high ⟩ 󰾆 42% › 󰎞 2  10% › 󰜦 $0.10 ⟩  12% ›  375M ›  3/3
14
+ ─ 󰏫 ─────────────────────────────────────────────────────────────── ‹ 󰠭 ─
15
+ ```
16
+
17
+ The preferred editor-deck surface keeps two stable semantic rows. The first is a
18
+ left-packed operational strip: runtime capsule, lifecycle, activity, controlled next
19
+ action, and Task/Step progress. The second is a full-width explicit selection canvas
20
+ that wraps to at most two lines. Every slot remains present; zero, idle, unavailable,
21
+ and unselected states are dim instead of appearing or disappearing. Long content may
22
+ wrap responsively, but runtime state never changes the deck topology. Decorative rails
23
+ remain slim and contain no telemetry.
24
+
25
+ The editor deck uses blue for the active runtime capsule, the bold lifecycle anchor,
26
+ and regular-weight explicit selection. Ordinary active activity remains neutral, except
27
+ that `recovering` and its ordinary suggestion are blue together while only the lifecycle
28
+ is bold. Other ordinary suggestions remain green. Incomplete Task/Step progress is
29
+ neutral until each counter completes and stays right-aligned without a major boundary.
30
+ The lifecycle/activity boundary and rails remain purple; minor separators are dim.
31
+ Human-input and validation cues stay yellow, blockers stay red, and every inactive value
32
+ stays dim.
33
+
34
+ The legacy above-editor widget owns only current work identity and preserves the
35
+ ` ready ⟩ no focused task` idle row when no work is selected. The leading icon is
36
+ runtime-authoritative: `` while Pi is busy in an active lifecycle and `` while
37
+ settled, waiting, blocked, listening, or aborted. Internal lifecycle states render as
38
+ short readable verbs. The Ramona loop remains exact: `understand`, `work`, `assure`,
39
+ `learn`, and `answer`. Runtime boundaries are `wait`, `blocked`, `ready`, or `stopped`.
40
+ The title has four styled groups: lifecycle, a structured active ancestry, focus, and
41
+ optional focus detail. Each activity-path segment receives the blue minor `›`; the
42
+ violet-pink major `⟩` divides runtime ancestry from the green narrative focus. Human
43
+ prompt text is never converted into focus automatically. OpenSpec may add its exact Task
44
+ after another green `›`. Focus selection prefers an exact OpenSpec Task, then Goal, then
45
+ Session Work. Active turns without a selection use the explicit `OpenSpec › no focus`,
46
+ `no OpenSpec`, or `no focus` state supplied by the status producer; `Direct response` is
47
+ never presented as a focus. Empty states are dim while real focus remains bold semantic
48
+ green.
49
+
50
+ Wide rows render lifecycle → active ancestry → optional focus → optional focus detail,
51
+ for example `assure › checking quality › assuring tests ⟩ Implement global flow`. The
52
+ renderer generates every separator. Empty or rejected paths leave no separator or
53
+ placeholder whitespace. As width falls it tries full labels, compact labels, a collapsed
54
+ `… › deepest` ancestry, and finally compact lifecycle plus the deepest active segment.
55
+ Narrative focus disappears before meaningful active ancestry. Terminal display-cell
56
+ measurement and final truncation remain Unicode- and Nerd-Font-aware.
57
+
58
+ Runtime anchor and lifecycle are bold blue `#076678`; activity ancestry and its minor
59
+ `›` are regular blue; the major `⟩` is purple; focus is bold semantic success green; and
60
+ optional focus hierarchy is regular success green. Dim is reserved for the two empty
61
+ focus fallbacks; muted, text, cyan, yellow, and gray are never used in the title.
62
+
63
+ The extension hides Pi's separate built-in `Working...` loader row with
64
+ `ctx.ui.setWorkingVisible(false)`, including its vertical space. The header therefore
65
+ uses its complete width for lifecycle, bounded activity, and focus. Runtime age is
66
+ published for the bottom prompt rail as an eight-cell chronometer measuring time since
67
+ the most recent observed foreground provider, assistant, or tool event. It stays
68
+ fixed-width as it advances: `00:00'00`, `00:00'45`, `00:12'30`, or `12:34'56`; hour/day
69
+ fallbacks also remain eight cells. Active timing uses the high-contrast deep-cyan
70
+ `accent` color; settled states display dim `00:00'00` rather than repeating the header's
71
+ `wait`, `ready`, or other lifecycle word. A session-scoped ticker publishes only when
72
+ the formatted chronometer changes and is cleared on shutdown. No message content,
73
+ thinking, reasoning, prompts, tool arguments, or child-agent output enters the widget.
74
+
75
+ The additive header protocol projects selection independently from live work:
76
+
77
+ ```ts
78
+ selection: {
79
+ source: 'openspec' | 'goal' | 'session-work';
80
+ titles: string[]; // one or two bounded, normalized titles
81
+ color: HeaderColor;
82
+ } | null;
83
+ suggestion: HeaderSuggestion | null; // controlled enum, never generated prose
84
+ ```
85
+
86
+ Selection priority remains exact OpenSpec Task, Goal, then Session Work. Older
87
+ protocol-1 events may use sanitized non-placeholder work titles as a legacy selection;
88
+ explicit malformed selection is rejected rather than borrowing a fallback. The
89
+ suggestion vocabulary is producer-owned, appears only in waiting, blocked, approval,
90
+ or aborted states, and is bounded to reporting cues such as
91
+ `requesting validation or redirection`, `awaiting continuation`, and
92
+ `requesting redirection`. While work is active, the same slot reports the current
93
+ WHAT: the focused task title with live step progress.
94
+
95
+ The preferred activity contract is a structured path that never stores separators:
96
+
97
+ ```ts
98
+ work.activityPath?: Array<{
99
+ id: string; // lowercase letters, digits, and hyphens; at most 48 code points
100
+ label: string; // one line; normalized to at most 48 code points
101
+ compact?: string; // normalized to at most 24 code points
102
+ current?: number;
103
+ total?: number;
104
+ }>; // at most six unique segments; lifecycle is not duplicated here
105
+ ```
106
+
107
+ An explicit valid array, including `[]`, takes precedence. A malformed array is rejected
108
+ as a whole and falls back to the legacy allowlisted `work.activity` field. Legacy
109
+ activity is normalized to one internal segment, preserving existing producers until they
110
+ migrate. Progress is bounded to `0..9,999` and appended as `current/total` only when
111
+ both values are valid.
112
+
113
+ The consumer removes ANSI escapes and control characters, normalizes whitespace, rejects
114
+ empty labels and malformed or duplicate IDs, and fails soft. Semantic safety remains a
115
+ producer obligation: labels must be bounded display vocabulary, never prompts, commands,
116
+ paths, secrets, generated paragraphs, or tool output. The consumer cannot infer those
117
+ semantics from arbitrary text. The future global-flow producer selects one primary
118
+ active path; completed, skipped, sibling, and parallel aggregation remain out of scope.
119
+
120
+ The legacy `work.activity` enum remains temporarily supported. Its renderer-owned labels
121
+ convert operation starts such as `inspection` and `mutation` into
122
+ `inspecting project context` and `updating selected files`. Their bounded completion
123
+ transitions render as `finalizing current request`, `reviewing applied changes`, or
124
+ `reviewing check results`; unknown kinds and raw activity text remain omitted.
125
+
126
+ The extension refreshes bounded local Git branch and status data at session start, after
127
+ successful mutating tools, and when the agent settles. Footer row one keeps project
128
+ identity on the left and work scope on the right. The bold PWD is shown in full relative
129
+ to home (`/home/aemonge/projects/example` → `~/projects/example`) and yields ANSI-safely
130
+ only when the terminal cannot preserve both aligned groups. Git branch and state follow
131
+ a blue minor `›`. Outside a repository, one dim responsive `›  (no Git)` state fills
132
+ the otherwise missing project slot and yields before core project/work information on
133
+ narrow terminals. Slash-prefixed Git branches collapse the prefix to its initial and cap
134
+ display at 30 cells with `...` (`feat/persist-versioned-prompts-in-duckdb` →
135
+ `f/persist-versioned-prompts...`). The right side shows compact OpenSpec Plan/Task
136
+ progress, or the simple Goal, Focus, or `no OpenSpec` fallback when no OpenSpec
137
+ portfolio is available. The footer reserves a four-cell visual split between alignment
138
+ groups. OpenSpec uses icons instead of repeated labels: task-list `` for Plans and
139
+ notebook `` for Tasks, with minor `›` between them. Their Nerd Font glyphs exactly
140
+ match Starship: ``, ``, ``, ``, and ``. When `DEVBOX_PROJECT_ROOT` is present, the
141
+ PWD begins `[󰆧]  ~/project`; the boxed Devbox marker precedes the folder icon without
142
+ exposing the variable's value. The top prompt rail may prepend MCP availability to work
143
+ progress as ` healthy/total ⟩  Plans ›  Tasks`. MCP status comes only from the live
144
+ `pi-mcp-adapter/status/v1` feed; lazy cached or not-yet-connected servers remain
145
+ available, while failed or authentication-blocked servers reduce the numerator. This is
146
+ availability telemetry, not a tool-call counter. Before the first valid snapshot, or
147
+ when status is empty or malformed, the segment remains visible as dim ` 0/0`. The
148
+ entire segment yields before right-aligned work progress is truncated. Neovim LSP
149
+ inventory is intentionally neither collected nor shown because it does not establish an
150
+ agent-usable LSP capability. Plugin and extension inventory is not shown without a
151
+ trustworthy runtime health source. Adjacent left and right segments use the same Gruvbox
152
+ colors as the configured Starship prompts: blue `#076678`, green `#79740e`, bright green
153
+ `#689d6a`, aqua `#427b58`, yellow `#b57614`, orange `#af3a03`, major-separator Gruvbox
154
+ purple `#b16286`, blue-violet `#5c5ca8`, and red `#9d0006`. Project, Git, work-scope,
155
+ model, quota, and local telemetry avoid generic gray; only missing Git and the runtime
156
+ chronometer are deliberately dim. PWD and model identity share the same blue anchor
157
+ color; reasoning retains its own level color. The single footer row keeps PWD and Git on
158
+ the left and model, reasoning, and quota on the right. Other bounded widget snapshots
159
+ feed the prompt rails: mode alone on the left and optional MCP availability plus work
160
+ progress on the right of the top rail; chronometer left and context, compactions,
161
+ memory, CPU, and cost right on the bottom rail. A major separator distinguishes model
162
+ context from process resources. On wide terminals the footer ends with the dedicated
163
+ five-cell avatar tail `⟨ 󰠭`: a purple left-pointing boundary, violet ladybug, and one
164
+ blank cell to her right. Each rail aligns its own groups independently, so the header is
165
+ never padded for cross-row alignment. CPU is normalized against Pi's available logical
166
+ CPU capacity and capped at 100%, so the number reads as whole-machine share rather than
167
+ one-core units. CPU and RAM are blue normally and independently turn yellow only for
168
+ sustained CPU pressure above 80% or unusually high session memory; one resource warning
169
+ does not recolor its neighbors. Pink and red are never used in these three telemetry
170
+ groups. In the title, lifecycle and bounded activity are blue; the major boundary is
171
+ purple; real focus and optional Task hierarchy are green; empty focus fallbacks and the
172
+ footer runtime age/state are dim. Persistent cache-hit presentation is disabled, while
173
+ Fancy Footer retains its internal cache accounting. Compaction count is hidden at zero.
174
+ The first deck row always begins with the compact runtime capsule
175
+ `( children ›  subagents · 00:00'00)`. Each zero count and the settled timer remain
176
+ dim in place; a live count or timer changes color without moving neighboring content.
177
+ The active-run aggregate no longer appears in the lower resource row. Final
178
+ narrow-width fitting remains ANSI-aware and removes exposed trailing separators. The
179
+ renderer never shows the main Pi process, historical worker totals, completed-file
180
+ progress, queued subagent placeholders, or runtime identity and output fields.
181
+ Quota is reduced to the most constrained provider-reported percentage with no weekly
182
+ analysis. Cost is Pi's native estimated session cost in USD, rendered without trailing
183
+ fractional zeros; its preceding `⟩` retains the shared purple major-boundary color while
184
+ the value remains blue. No local daily aggregation or currency conversion is performed.
185
+ No center group or gauges are used. The local Fancy Footer fork expands its widget
186
+ protocol to accept these native theme tokens. The narrative lifecycle header begins with
187
+ its active/passive terminal icon; the prompt border keeps only its right-aligned vi-mode
188
+ glyph. Concurrent Git refreshes coalesce without polling.
189
+
190
+ Agent-environment, context, CPU, RAM, and compaction widgets use the same Fancy Footer
191
+ protocol, including producer-requested bold text for the PWD. Every three seconds on
192
+ Linux, the extension discovers only Pi descendants through bounded
193
+ `/proc/<pid>/task/<pid>/children` reads, then reads their `stat` and `status` records
194
+ without shelling out or retaining process names, arguments, or paths. Memory sums
195
+ private anonymous resident pages (`RssAnon`) instead of counting shared file-backed
196
+ pages once per process. Individual status-read failures fall back to that process's RSS;
197
+ unavailable `/proc` falls back honestly to current-process CPU and RSS. Sampling,
198
+ smoothing, publication, timers, and resource widgets are session-scoped and cleaned up
199
+ on shutdown. The local Fancy Footer fork owns cache, quota, and session-cost collection.
200
+ When the footer reports quota windows, the compact telemetry row paints icon-native
201
+ tiles in cost, long-window, coding-window order — `󰜦 $5.21 ⟩ 󰃰 12% ⟩ 󰈸 62% › 󰅐 1:45`.
202
+ The flame is the coding window's permanent icon and always carries the clock
203
+ countdown; 80% used turns a tile's accent color into a warning. Without windows the
204
+ slot degrades to the single footer-reported percent, and without telemetry it stays a
205
+ dim dash.
206
+ Unavailable temperature and unsupported environment claims are hidden; environment
207
+ classification defaults honestly to `host` unless an explicit supported marker exists.
208
+
209
+ ## Test
210
+
211
+ ```sh
212
+ npm install
213
+ npm run check
214
+ ```
215
+
216
+ ## Remove
217
+
218
+ Delete `./packages/pi-stardeck` from `.pi/agent/settings.json`, remove this
219
+ directory, and run `/reload`.