@pellux/goodvibes-tui 1.16.1 → 1.17.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 (219) hide show
  1. package/CHANGELOG.md +89 -9
  2. package/README.md +1 -1
  3. package/docs/foundation-artifacts/operator-contract.json +1091 -271
  4. package/package.json +7 -7
  5. package/src/cli/completions/generate.ts +5 -4
  6. package/src/cli/config-overrides.ts +51 -11
  7. package/src/cli/doctor.ts +4 -5
  8. package/src/cli/entrypoint.ts +13 -8
  9. package/src/cli/help.ts +7 -6
  10. package/src/cli/launch-auto-update.ts +214 -0
  11. package/src/cli/parser.ts +5 -0
  12. package/src/cli/status.ts +13 -0
  13. package/src/cli/surface-command.ts +5 -5
  14. package/src/cli/tui-startup.ts +60 -97
  15. package/src/cli/types.ts +2 -0
  16. package/src/config/index.ts +1 -1
  17. package/src/config/tui-extension-settings.ts +33 -0
  18. package/src/core/composer-state.ts +1 -1
  19. package/src/core/conversation-line-cache.ts +3 -3
  20. package/src/core/conversation-rendering.ts +4 -4
  21. package/src/core/conversation.ts +2 -2
  22. package/src/core/long-task-notifier.ts +7 -7
  23. package/src/core/stream-event-wiring.ts +8 -6
  24. package/src/core/system-message-noise.ts +1 -1
  25. package/src/core/system-message-router.ts +6 -6
  26. package/src/core/turn-cancellation.ts +1 -1
  27. package/src/core/turn-event-wiring.ts +8 -8
  28. package/src/daemon/cli.ts +20 -5
  29. package/src/daemon/lifecycle.ts +41 -0
  30. package/src/daemon/service-commands.ts +5 -5
  31. package/src/export/cost-utils.ts +128 -6
  32. package/src/input/autocomplete.ts +2 -2
  33. package/src/input/command-registry.ts +34 -9
  34. package/src/input/commands/ci-runtime.ts +5 -1
  35. package/src/input/commands/codebase-runtime.ts +6 -6
  36. package/src/input/commands/cost-runtime.ts +1 -1
  37. package/src/input/commands/health-runtime.ts +2 -2
  38. package/src/input/commands/intelligence-runtime.ts +1 -1
  39. package/src/input/commands/local-auth-runtime.ts +1 -1
  40. package/src/input/commands/local-provider-runtime.ts +49 -10
  41. package/src/input/commands/local-runtime.ts +53 -5
  42. package/src/input/commands/memory.ts +2 -2
  43. package/src/input/commands/operator-panel-runtime.ts +5 -5
  44. package/src/input/commands/permissions-provenance.ts +1 -1
  45. package/src/input/commands/permissions-runtime.ts +99 -8
  46. package/src/input/commands/planning-runtime.ts +3 -3
  47. package/src/input/commands/platform-sandbox-runtime.ts +1 -1
  48. package/src/input/commands/provider-accounts-runtime.ts +71 -6
  49. package/src/input/commands/provider.ts +7 -5
  50. package/src/input/commands/recall-files-git.ts +13 -51
  51. package/src/input/commands/recall-files.ts +8 -11
  52. package/src/input/commands/recall-review.ts +2 -2
  53. package/src/input/commands/relay-runtime.ts +1 -1
  54. package/src/input/commands/remote-runtime.ts +1 -1
  55. package/src/input/commands/runtime-services.ts +4 -4
  56. package/src/input/commands/schedule-runtime.ts +14 -7
  57. package/src/input/commands/services-runtime.ts +1 -1
  58. package/src/input/commands/session-workflow.ts +2 -2
  59. package/src/input/commands/settings-sync-runtime.ts +2 -2
  60. package/src/input/commands/share-runtime.ts +1 -1
  61. package/src/input/commands/shell-core.ts +46 -68
  62. package/src/input/commands/subscription-runtime.ts +1 -1
  63. package/src/input/commands/update-runtime.ts +153 -96
  64. package/src/input/commands/work-plan-runtime.ts +1 -1
  65. package/src/input/commands/workstream-runtime.ts +2 -2
  66. package/src/input/commands.ts +0 -2
  67. package/src/input/config-modal-types.ts +3 -3
  68. package/src/input/config-modal.ts +10 -11
  69. package/src/input/feature-unit-layout.ts +93 -82
  70. package/src/input/feed-context-factory.ts +2 -2
  71. package/src/input/handler-command-route.ts +2 -2
  72. package/src/input/handler-content-actions.ts +1 -1
  73. package/src/input/handler-feed-routes.ts +7 -7
  74. package/src/input/handler-feed.ts +4 -4
  75. package/src/input/handler-interactions.ts +3 -2
  76. package/src/input/handler-modal-routes.ts +12 -4
  77. package/src/input/handler-modal-token-routes.ts +1 -1
  78. package/src/input/handler-onboarding-daemon-adopt.ts +2 -2
  79. package/src/input/handler-onboarding.ts +3 -2
  80. package/src/input/handler-picker-routes.ts +26 -13
  81. package/src/input/handler-shortcuts.ts +6 -6
  82. package/src/input/handler.ts +2 -2
  83. package/src/input/keybindings.ts +2 -2
  84. package/src/input/onboarding/onboarding-feature-units.ts +34 -27
  85. package/src/input/onboarding/onboarding-provider-key-fields.ts +112 -0
  86. package/src/input/onboarding/onboarding-wizard-apply.ts +22 -21
  87. package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +17 -0
  88. package/src/input/onboarding/onboarding-wizard-network-adopt.ts +2 -2
  89. package/src/input/onboarding/onboarding-wizard-steps.ts +30 -42
  90. package/src/input/panel-integration-actions.ts +2 -2
  91. package/src/input/panel-mouse-geometry.ts +1 -1
  92. package/src/input/panel-paste-flood-guard.ts +1 -1
  93. package/src/input/provider-key-intake.ts +167 -0
  94. package/src/input/sandbox-exec-config.ts +2 -2
  95. package/src/input/selection-modal.ts +1 -1
  96. package/src/input/settings-modal-activation.ts +5 -0
  97. package/src/input/settings-modal-adjustment.ts +4 -31
  98. package/src/input/settings-modal-data.ts +22 -21
  99. package/src/input/settings-modal-mutations.ts +12 -68
  100. package/src/input/settings-modal-types.ts +23 -16
  101. package/src/input/settings-modal.ts +74 -55
  102. package/src/main.ts +48 -48
  103. package/src/panels/agent-inspector-shared.ts +4 -4
  104. package/src/panels/base-panel.ts +2 -2
  105. package/src/panels/builtin/agent.ts +4 -4
  106. package/src/panels/builtin/development.ts +4 -4
  107. package/src/panels/builtin/knowledge.ts +1 -1
  108. package/src/panels/builtin/operations.ts +29 -10
  109. package/src/panels/builtin/session.ts +5 -5
  110. package/src/panels/builtin/shared.ts +4 -4
  111. package/src/panels/builtin-modals.ts +10 -10
  112. package/src/panels/builtin-panels.ts +1 -1
  113. package/src/panels/cost-tracker-panel.ts +124 -7
  114. package/src/panels/diff-panel.ts +5 -5
  115. package/src/panels/eval-registry.ts +2 -2
  116. package/src/panels/fleet-deep-link.ts +1 -1
  117. package/src/panels/fleet-panel-format.ts +44 -8
  118. package/src/panels/fleet-panel.ts +16 -16
  119. package/src/panels/fleet-read-model.ts +52 -13
  120. package/src/panels/fleet-steer.ts +2 -2
  121. package/src/panels/fleet-stop.ts +3 -3
  122. package/src/panels/fleet-tabs.ts +13 -14
  123. package/src/panels/fleet-transcript.ts +5 -5
  124. package/src/panels/git-panel.ts +2 -2
  125. package/src/panels/index.ts +4 -1
  126. package/src/panels/local-auth-panel.ts +1 -1
  127. package/src/panels/modals/hooks-modal.ts +1 -1
  128. package/src/panels/modals/keybindings-modal.ts +2 -2
  129. package/src/panels/modals/knowledge-modal.ts +1 -1
  130. package/src/panels/modals/marketplace-modal.ts +4 -4
  131. package/src/panels/modals/memory-modal.ts +4 -4
  132. package/src/panels/modals/modal-surface-helpers.ts +1 -1
  133. package/src/panels/modals/modal-theme.ts +1 -1
  134. package/src/panels/modals/pairing-modal.ts +2 -2
  135. package/src/panels/modals/planning-modal.ts +2 -2
  136. package/src/panels/modals/plugins-modal.ts +1 -1
  137. package/src/panels/modals/policy-modal.ts +1 -1
  138. package/src/panels/modals/security-modal.ts +1 -1
  139. package/src/panels/modals/skills-modal.ts +1 -1
  140. package/src/panels/modals/work-plan-modal.ts +3 -3
  141. package/src/panels/notifications-feed.ts +127 -0
  142. package/src/panels/notifications-panel.ts +160 -0
  143. package/src/panels/panel-manager.ts +9 -9
  144. package/src/panels/plugins-panel.ts +4 -4
  145. package/src/panels/project-planning-answer-actions.ts +1 -1
  146. package/src/panels/provider-health-routes.ts +2 -2
  147. package/src/panels/skills-panel.ts +4 -5
  148. package/src/panels/token-budget-panel.ts +11 -3
  149. package/src/panels/types.ts +5 -5
  150. package/src/permissions/broker-approval-card.ts +201 -0
  151. package/src/permissions/hunk-selection.ts +28 -4
  152. package/src/permissions/prompt.ts +244 -29
  153. package/src/renderer/autocomplete-overlay.ts +107 -54
  154. package/src/renderer/code-block.ts +2 -2
  155. package/src/renderer/compaction-history-modal.ts +1 -1
  156. package/src/renderer/compaction-preview.ts +1 -1
  157. package/src/renderer/compaction-quality.ts +1 -1
  158. package/src/renderer/compositor.ts +2 -2
  159. package/src/renderer/config-modal.ts +1 -1
  160. package/src/renderer/conversation-overlays.ts +1 -1
  161. package/src/renderer/footer-tips.ts +3 -3
  162. package/src/renderer/hint-grammar.ts +1 -1
  163. package/src/renderer/modal-factory.ts +1 -1
  164. package/src/renderer/model-picker-overlay.ts +1 -1
  165. package/src/renderer/model-workspace.ts +7 -2
  166. package/src/renderer/panel-composite.ts +2 -2
  167. package/src/renderer/panel-workspace-bar.ts +1 -1
  168. package/src/renderer/process-indicator.ts +1 -1
  169. package/src/renderer/selection-modal-overlay.ts +1 -1
  170. package/src/renderer/session-picker-modal.ts +2 -2
  171. package/src/renderer/settings-modal-helpers.ts +14 -5
  172. package/src/renderer/settings-modal.ts +127 -39
  173. package/src/renderer/shell-surface.ts +3 -0
  174. package/src/renderer/terminal-bg-probe.ts +1 -1
  175. package/src/renderer/theme.ts +3 -3
  176. package/src/renderer/tool-call.ts +1 -1
  177. package/src/renderer/tool-result-summary.ts +1 -1
  178. package/src/renderer/turn-injection.ts +7 -6
  179. package/src/renderer/ui-factory.ts +6 -1
  180. package/src/runtime/bootstrap-command-context.ts +4 -1
  181. package/src/runtime/bootstrap-command-parts.ts +6 -4
  182. package/src/runtime/bootstrap-core.ts +35 -35
  183. package/src/runtime/bootstrap-hook-bridge.ts +1 -1
  184. package/src/runtime/bootstrap-shell.ts +6 -5
  185. package/src/runtime/bootstrap.ts +34 -32
  186. package/src/runtime/channel-composition.ts +46 -0
  187. package/src/runtime/code-index-services.ts +3 -4
  188. package/src/runtime/daemon-attach-notices.ts +120 -0
  189. package/src/runtime/durability-services.ts +55 -0
  190. package/src/runtime/embedded-service-factories.ts +40 -0
  191. package/src/runtime/feature-settings.ts +147 -0
  192. package/src/runtime/index.ts +4 -21
  193. package/src/runtime/legacy-daemon-migration.ts +29 -19
  194. package/src/runtime/memory-fold.ts +1 -1
  195. package/src/runtime/notification-dispatch.ts +110 -0
  196. package/src/runtime/onboarding/apply.ts +3 -29
  197. package/src/runtime/onboarding/fast-path.ts +39 -6
  198. package/src/runtime/onboarding/provider-key-capture.ts +126 -0
  199. package/src/runtime/onboarding/snapshot.ts +0 -1
  200. package/src/runtime/onboarding/types.ts +9 -3
  201. package/src/runtime/provider-fallback.ts +55 -0
  202. package/src/runtime/provider-optimizer-wiring.ts +55 -0
  203. package/src/runtime/release-artifacts.ts +19 -103
  204. package/src/runtime/resume-notice.ts +1 -1
  205. package/src/runtime/services.ts +81 -82
  206. package/src/runtime/session-continuity-hints.ts +38 -0
  207. package/src/runtime/surface-feature-flags.ts +40 -9
  208. package/src/runtime/terminal-output-guard.ts +2 -2
  209. package/src/runtime/trust/workspace-registration.ts +10 -2
  210. package/src/runtime/trust/workspace-trust.ts +58 -31
  211. package/src/runtime/ui-services.ts +3 -1
  212. package/src/runtime/update-check.ts +15 -69
  213. package/src/runtime/workstream-services.ts +2 -2
  214. package/src/shell/blocking-input.ts +102 -6
  215. package/src/shell/ui-openers.ts +38 -6
  216. package/src/utils/format-duration.ts +1 -1
  217. package/src/verification/verification-ledger.ts +21 -4
  218. package/src/version.ts +1 -1
  219. package/src/input/commands/flags-runtime.ts +0 -328
@@ -11,7 +11,7 @@ import type { ProcessCostState, ProcessNode, ProcessUsage } from '@pellux/goodvi
11
11
  import type { Line } from '../types/grid.ts';
12
12
  import { formatAgentCost } from './agent-inspector-shared.ts';
13
13
  import { buildPanelLine, DEFAULT_PANEL_PALETTE, type ColumnSpec, type PanelPalette } from './polish.ts';
14
- import { fleetUsageTokens, hasFleetCost, type FleetStateTone } from './fleet-read-model.ts';
14
+ import { fleetAttentionText, fleetNodeAttention, fleetStallMarker, fleetUsageTokens, hasFleetCost, type FleetStateTone } from './fleet-read-model.ts';
15
15
  import { fleetStateDisplay } from './fleet-stop.ts';
16
16
  import { formatElapsed } from '../utils/format-elapsed.ts';
17
17
  import { truncateDisplay } from '../utils/terminal-width.ts';
@@ -96,16 +96,39 @@ export function renderFleetRowLine(
96
96
  ? ` [attempt ${node.attemptGroup.index + 1}/${node.attemptGroup.total}${node.attemptGroup.held ? ', held' : ''}]`
97
97
  : '';
98
98
  const label = `${row.treePrefix}${node.label}${attemptBadge}`;
99
- // Activity column doubles as the badge slot: 'blocked on you' shouts the
100
- // wait louder than the raw currentActivity text ('awaiting approval …').
99
+ // Activity column doubles as the badge slot, in priority order:
100
+ // stopping > waiting-on-human text ('blocked on you' / 'needs your input')
101
+ // > the read-model HEADLINE (derived from task/phase identity only —
102
+ // replaced in place, never a scrolling feed) with the stall marker
103
+ // ('quiet Nm') appended when the node has gone observably silent.
104
+ // Nodes without a headline fall back to the live currentActivity text.
105
+ const attention = fleetNodeAttention(node);
106
+ const stallMarker = fleetStallMarker(node);
107
+ const steadyText = node.headline?.text ?? node.currentActivity?.text ?? '';
108
+ // The stall marker must survive the 20-char activity cell: budget the
109
+ // headline around it (the marker is the honesty signal; a stalled node must
110
+ // never render as if it were healthily mid-headline).
111
+ const steadyWithStall = stallMarker
112
+ ? (steadyText
113
+ ? `${truncateDisplay(steadyText, Math.max(1, ACTIVITY_W - stallMarker.length - 3))} · ${stallMarker}`
114
+ : stallMarker)
115
+ : steadyText;
101
116
  const activity = stopping
102
117
  ? disp.label
103
118
  : blocked
104
- ? 'blocked on you'
119
+ ? fleetAttentionText(attention ?? { reason: 'approval' })
105
120
  : badge
106
- ? `${steerBadgeGlyph(badge.status)} ${node.currentActivity?.text ?? ''}`.trimEnd()
107
- : (node.currentActivity?.text ?? '');
108
- const activityColor = stopping ? color : blocked ? color : badge ? steerBadgeTone(badge.status, C) : C.dim;
121
+ ? `${steerBadgeGlyph(badge.status)} ${steadyWithStall}`.trimEnd()
122
+ : steadyWithStall;
123
+ const activityColor = stopping
124
+ ? color
125
+ : blocked
126
+ ? color
127
+ : badge
128
+ ? steerBadgeTone(badge.status, C)
129
+ : stallMarker
130
+ ? (C.warn ?? DEFAULT_PANEL_PALETTE.warn)
131
+ : C.dim;
109
132
 
110
133
  return buildAlignedRow(
111
134
  width,
@@ -160,6 +183,19 @@ export function renderFleetDetailLines(
160
183
  [' cost ', C.label],
161
184
  [formatFleetCost(node.costUsd, node.costState), C.value],
162
185
  ]);
186
+ // The headline (task/phase identity, replaced in place) gets its own row
187
+ // when present, with the stall marker appended — the detail block mirrors
188
+ // exactly what the tree row's steady slot shows.
189
+ const stallMarker = fleetStallMarker(node);
190
+ const headlineText = node.headline
191
+ ? `${node.headline.text}${stallMarker ? ` · ${stallMarker}` : ''}`
192
+ : stallMarker;
193
+ const headlineLine = headlineText
194
+ ? [buildPanelLine(width, [
195
+ [' headline ', C.label],
196
+ [truncateDisplay(headlineText, Math.max(0, width - 11)), stallMarker ? (C.warn ?? DEFAULT_PANEL_PALETTE.warn) : C.value],
197
+ ])]
198
+ : [];
163
199
  const activityText = node.currentActivity
164
200
  ? `${node.currentActivity.kind}: ${node.currentActivity.text}`
165
201
  : '(no recent activity)';
@@ -170,5 +206,5 @@ export function renderFleetDetailLines(
170
206
  // Approval history attaches here once session tabs land.
171
207
  const line4 = buildPanelLine(width, [[' approvals ', C.label], ['—', C.dim]]);
172
208
  const isolationDetail = node.kind === 'work-item' ? formatWorkItemIsolationDetailFromRaw(node.raw) : null;
173
- return [line1, line2, line3, line4, ...(isolationDetail ? [buildPanelLine(width, [[' isolation ', C.label], [isolationDetail, C.dim]])] : [])];
209
+ return [line1, line2, ...headlineLine, line3, line4, ...(isolationDetail ? [buildPanelLine(width, [[' isolation ', C.label], [isolationDetail, C.dim]])] : [])];
174
210
  }
@@ -1,14 +1,14 @@
1
1
  // ---------------------------------------------------------------------------
2
2
  // fleet-panel.ts
3
3
  //
4
- // W2.2 — FleetPanel: the live unified observability tree. Renders the
4
+ // — FleetPanel: the live unified observability tree. Renders the
5
5
  // registered process fleet (agents incl. WRFC roles, WRFC chains/subtasks,
6
6
  // workflow-tool FSMs, watchers, background processes) as a depth-first tree
7
- // with a selected-row detail region. Session tabs (W3.1 Part C): Enter on an
7
+ // with a selected-row detail region. Session tabs (Part C): Enter on an
8
8
  // attachable node (agent/wrfc-chain) opens a tab with that process's
9
9
  // transcript/member summary — see fleet-tabs.ts + fleet-transcript.ts. This
10
10
  // file owns input dispatch and layout; fleet-deep-link.ts owns the
11
- // cross-panel jump target (DEBT-5 item 4).
11
+ // cross-panel jump target (item 4).
12
12
  // ---------------------------------------------------------------------------
13
13
 
14
14
  import { readFile } from 'node:fs/promises';
@@ -21,7 +21,7 @@ import { PanelConfirmOverlay } from './panel-confirm-overlay.ts';
21
21
  import { isPanelSearchBackspace, isPanelSearchCancel, isPanelSearchCommit, isPanelSearchPrintable } from './search-focus.ts';
22
22
  import { buildKeyboardHints, buildPanelWorkspace, buildSearchInputLine, DEFAULT_PANEL_PALETTE, getPanelWorkspaceContentBudget, type PanelPalette } from './polish.ts';
23
23
  import {
24
- isBlockedOnUserState,
24
+ isBlockedOnUserNode,
25
25
  isRunningProcessState,
26
26
  isTerminalProcessState,
27
27
  type FleetReadModel,
@@ -105,7 +105,7 @@ export class FleetPanel extends ScrollableListPanel<FleetTreeRow> {
105
105
  */
106
106
  private selectedNodeId: string | null = null;
107
107
 
108
- /** d1 (W6.2): the "stopping…" write-window overlay tracker (see fleet-stop.ts). */
108
+ /** d1: the "stopping…" write-window overlay tracker (see fleet-stop.ts). */
109
109
  private readonly stopTracker = new FleetStopTracker();
110
110
 
111
111
  public constructor(
@@ -114,7 +114,7 @@ export class FleetPanel extends ScrollableListPanel<FleetTreeRow> {
114
114
  private readonly configManager: ConfigManager | null = null,
115
115
  ) {
116
116
  super('fleet', 'Fleet', '⊟', 'runtime-ops');
117
- this.showSelectionGutter = true; // W0.8: visible ▸ focus indicator
117
+ this.showSelectionGutter = true; // visible ▸ focus indicator
118
118
  this.actions = { ...NOOP_ACTIONS, ...actions };
119
119
  this.confirmOverlay = new PanelConfirmOverlay(() => this.markDirty());
120
120
  this.unsub = readModel.subscribe(() => {
@@ -232,10 +232,10 @@ export class FleetPanel extends ScrollableListPanel<FleetTreeRow> {
232
232
  }
233
233
 
234
234
  /**
235
- * W3.3 (cross-restart honesty): a restart always starts from an empty
235
+ * (cross-restart honesty): a restart always starts from an empty
236
236
  * `AgentManager` Map (no bridge from a prior TUI/daemon registry), so a
237
237
  * completed process from a previous session can never reappear here — a
238
- * real, permanent limitation (W3.3 brief point 5), documented rather than
238
+ * real, permanent limitation (brief point 5), documented rather than
239
239
  * silently implying "nothing has ever run" or that a restart brings it back.
240
240
  */
241
241
  protected override getEmptyStateActions(): Array<{ command: string; summary: string }> {
@@ -303,7 +303,7 @@ export class FleetPanel extends ScrollableListPanel<FleetTreeRow> {
303
303
  return this.getItems().find((row) => row.node.id === nodeId)?.node ?? null;
304
304
  }
305
305
 
306
- /** DEBT-5 item 4 (see fleet-deep-link.ts). */
306
+ /** item 4 (see fleet-deep-link.ts). */
307
307
  public receiveDeepLink(target: { readonly id: string; readonly kind?: string }): void {
308
308
  const idx = resolveFleetDeepLinkIndex(this.getItems(), target);
309
309
  if (idx < 0) { this.setError('node no longer present.'); return; }
@@ -391,7 +391,7 @@ export class FleetPanel extends ScrollableListPanel<FleetTreeRow> {
391
391
  // owns EVERY key (same full-priority-while-composing contract as
392
392
  // git-panel.ts's commitMessage entry) until Enter (submit) or Esc
393
393
  // (cancel) — a burst/paste and single hotkeys like 'j'/'s'/'[' all land
394
- // in the draft, never as tree/tab navigation (W0.8 focus rule).
394
+ // in the draft, never as tree/tab navigation (focus rule).
395
395
  const composingTab = activeFleetTab(this.tabsState);
396
396
  if (composingTab && composingTab.steerDraft !== null) {
397
397
  return this.handleSteerInput(composingTab, key);
@@ -491,7 +491,7 @@ export class FleetPanel extends ScrollableListPanel<FleetTreeRow> {
491
491
  id: node.id,
492
492
  label: `${node.kind} ${shortId}${suffix}`,
493
493
  verb: 'Kill',
494
- // d1 (W6.2): mark 'stopping…' only once the kill is confirmed, not while
494
+ // d1: mark 'stopping…' only once the kill is confirmed, not while
495
495
  // the confirm overlay is merely armed.
496
496
  onConfirm: () => {
497
497
  this.actions.kill(node.id, { cascade: true });
@@ -501,7 +501,7 @@ export class FleetPanel extends ScrollableListPanel<FleetTreeRow> {
501
501
  return true;
502
502
  }
503
503
 
504
- // d2 (W6.2): 'p' toggles pause<->resume by the selected node's state (see
504
+ // d2: 'p' toggles pause<->resume by the selected node's state (see
505
505
  // toggleFleetPause in fleet-stop.ts).
506
506
  if (key === 'p') {
507
507
  if (!selected) return false;
@@ -621,7 +621,7 @@ export class FleetPanel extends ScrollableListPanel<FleetTreeRow> {
621
621
 
622
622
  /**
623
623
  * Submit a composed steer message. Returns whether it was queued so the caller
624
- * clears the draft only on a confirmed send (WO UX-A item 4): a refusal (target
624
+ * clears the draft only on a confirmed send (WO item 4): a refusal (target
625
625
  * went idle while composing) PRESERVES the typed text and suggests which agents
626
626
  * ARE steerable, instead of silently discarding the draft. On a successful queue
627
627
  * the ⧗ badge line is the immediate honest acknowledgment.
@@ -644,7 +644,7 @@ export class FleetPanel extends ScrollableListPanel<FleetTreeRow> {
644
644
  // Display-only overrides (stopping wins, then blocked-on-user) are derived
645
645
  // here from panel state and passed into the pure row renderer.
646
646
  const stopping = this.stopTracker.isStopping(row.node.id);
647
- const blocked = !stopping && isBlockedOnUserState(row.node.state);
647
+ const blocked = !stopping && isBlockedOnUserNode(row.node);
648
648
  return renderFleetRowLine(row, width, stopping, blocked, this.steerBadgeForNode(row.node.id), C);
649
649
  }
650
650
 
@@ -658,7 +658,7 @@ export class FleetPanel extends ScrollableListPanel<FleetTreeRow> {
658
658
  // Mirror the tree row's display-only overrides (stopping wins, then blocked)
659
659
  // so the detail's literal state text never contradicts the row glyph.
660
660
  const stopping = this.stopTracker.isStopping(node.id);
661
- const blocked = !stopping && isBlockedOnUserState(node.state);
661
+ const blocked = !stopping && isBlockedOnUserNode(node);
662
662
  return renderFleetDetailLines(node, width, stopping, blocked, C);
663
663
  }
664
664
 
@@ -718,7 +718,7 @@ export class FleetPanel extends ScrollableListPanel<FleetTreeRow> {
718
718
 
719
719
  if (tab.kind === 'wrfc-chain') {
720
720
  const memberRows = snapshotRows.filter((row) => row.node.parentId === tab.nodeId);
721
- // d3 (W6.2): a completed chain prunes its wrapper node, so an empty member
721
+ // d3: a completed chain prunes its wrapper node, so an empty member
722
722
  // list can mean "finished", not "not started yet". Absent (pruned) OR
723
723
  // terminal => the honest "completed" wording; present + non-terminal with
724
724
  // no members yet => the "not started" wording.
@@ -1,14 +1,14 @@
1
1
  // ---------------------------------------------------------------------------
2
2
  // fleet-read-model.ts
3
3
  //
4
- // W2.2 (Fleet tree panel) — pure, testable read-model over the SDK's live
4
+ // (Fleet tree panel) — pure, testable read-model over the SDK's live
5
5
  // process registry (@pellux/goodvibes-sdk/platform/runtime/fleet, landed on
6
- // SDK main as W2.1). No BasePanel/rendering dependency: this module owns the
6
+ // SDK main as). No BasePanel/rendering dependency: this module owns the
7
7
  // flat ProcessNode[] -> tree transformation, the honest cost/token
8
8
  // aggregates, and the state->glyph/tone mapping that FleetPanel renders.
9
9
  //
10
10
  // Design notes:
11
- // - The W2.2 brief predates the real SDK API and sketched a bespoke
11
+ // - The brief predates the real SDK API and sketched a bespoke
12
12
  // FleetRegistryNode/FleetRegistry adapter pair. The real
13
13
  // createProcessRegistry() ProcessNode already carries elapsedMs,
14
14
  // usage, costUsd, costState, and currentActivity directly, so no
@@ -30,6 +30,7 @@
30
30
 
31
31
  import type {
32
32
  ArchivableProcessRegistry,
33
+ ProcessAttention,
33
34
  ProcessCostState,
34
35
  ProcessKind,
35
36
  ProcessNode,
@@ -136,13 +137,11 @@ const STATE_TONES: Record<ProcessState, FleetStateTone> = {
136
137
  const TERMINAL_STATES = new Set<ProcessState>(['done', 'failed', 'killed', 'interrupted']);
137
138
 
138
139
  /**
139
- * States that mean "this node is waiting on ME right now" — a user approval or
140
- * user input. Today the registry derives exactly one such state,
141
- * `awaiting-approval` (an agent parked at a permission prompt). This is the
142
- * single place that mapping lives, so if the SDK adds a distinct
143
- * awaiting-user-input state later it joins here and every "blocked on me"
144
- * surface (badge, sort, jump) picks it up for free. Kept as a set for that
145
- * forward-compatibility, not because more than one state qualifies today.
140
+ * States that mean "this node is waiting on ME right now" via the state field
141
+ * alone. The registry now also publishes the canonical `needsAttention`
142
+ * projection (reason 'approval' | 'input' — see fleetNodeAttention below),
143
+ * which every surface prefers; this set remains only as the fallback mapping
144
+ * for nodes without the projection, so nothing regresses on older registries.
146
145
  */
147
146
  const BLOCKED_ON_USER_STATES = new Set<ProcessState>(['awaiting-approval']);
148
147
 
@@ -195,8 +194,48 @@ export function isBlockedOnUserState(state: ProcessState): boolean {
195
194
  return BLOCKED_ON_USER_STATES.has(state);
196
195
  }
197
196
 
197
+ /**
198
+ * The node's waiting-on-human classification, preferring the SDK's canonical
199
+ * `needsAttention` projection (reason 'approval' | 'input' — broader than the
200
+ * awaiting-approval state alone: it also covers a session waiting on user
201
+ * input). Falls back to the state-derived mapping for registries that predate
202
+ * the projection, so nothing regresses. This is THE membership every
203
+ * "blocked on me" surface (badge, sort, jump) derives from.
204
+ */
205
+ export function fleetNodeAttention(node: ProcessNode): ProcessAttention | null {
206
+ if (node.needsAttention) return node.needsAttention;
207
+ if (isBlockedOnUserState(node.state)) return { reason: 'approval' };
208
+ return null;
209
+ }
210
+
211
+ /** True when the node is waiting on the operator right now (approval or input). */
212
+ export function isBlockedOnUserNode(node: ProcessNode): boolean {
213
+ return fleetNodeAttention(node) !== null;
214
+ }
215
+
216
+ /** The literal badge text for a waiting-on-human node, by reason. */
217
+ export function fleetAttentionText(attention: ProcessAttention): string {
218
+ return attention.reason === 'input' ? 'needs your input' : 'blocked on you';
219
+ }
220
+
221
+ /**
222
+ * The stall marker for a row — 'quiet Nm' (or 'quiet NhMm' past an hour),
223
+ * derived from the read-model's stall tell (pure timestamp comparison on the
224
+ * registry side; a live node whose last observable output is older than the
225
+ * threshold). Null when the node is not stalled-quiet.
226
+ */
227
+ export function fleetStallMarker(node: ProcessNode): string | null {
228
+ const stall = node.stall;
229
+ if (!stall) return null;
230
+ const minutes = Math.max(1, Math.floor(stall.quietForMs / 60_000));
231
+ if (minutes < 60) return `quiet ${minutes}m`;
232
+ const hours = Math.floor(minutes / 60);
233
+ const rest = minutes % 60;
234
+ return rest > 0 ? `quiet ${hours}h${rest}m` : `quiet ${hours}h`;
235
+ }
236
+
198
237
  // ---------------------------------------------------------------------------
199
- // Honest usage/cost helpers (W0.9 convention, ported from agent-inspector-shared.ts)
238
+ // Honest usage/cost helpers (convention, ported from agent-inspector-shared.ts)
200
239
  // ---------------------------------------------------------------------------
201
240
 
202
241
  /**
@@ -261,7 +300,7 @@ function collectBlockedSubtrees(
261
300
  if (cached !== undefined) return cached;
262
301
  if (visiting.has(node.id)) return false; // cycle guard
263
302
  visiting.add(node.id);
264
- let has = isBlockedOnUserState(node.state);
303
+ let has = isBlockedOnUserNode(node);
265
304
  for (const child of childrenByParent.get(node.id) ?? []) {
266
305
  if (dfs(child)) has = true;
267
306
  }
@@ -458,7 +497,7 @@ export function buildFleetSnapshot(nodes: readonly ProcessNode[], capturedAt: nu
458
497
  // Blocked ids in display (row) order so the panel's jump key steps through
459
498
  // them top-to-bottom exactly as they appear on screen.
460
499
  const blockedNodeIds = rows
461
- .filter((row) => isBlockedOnUserState(row.node.state))
500
+ .filter((row) => isBlockedOnUserNode(row.node))
462
501
  .map((row) => row.node.id);
463
502
 
464
503
  return { rows, totalCost, totalTokens, runningCount, blockedNodeIds, capturedAt };
@@ -34,7 +34,7 @@ export function steerBadgeTone(status: SteerBadgeStatus, palette: PanelPalette):
34
34
  }
35
35
  }
36
36
 
37
- /** Labels of the currently live, steerable agent nodes other than `excludeNodeId` — offered when a steer target has gone inactive (WO UX-A item 4). */
37
+ /** Labels of the currently live, steerable agent nodes other than `excludeNodeId` — offered when a steer target has gone inactive (WO item 4). */
38
38
  export function liveSteerableLabels(nodes: readonly ProcessNode[], excludeNodeId: string): string[] {
39
39
  return nodes
40
40
  .filter((node) => node.id !== excludeNodeId && node.kind === 'agent' && node.capabilities.steerable && !isTerminalProcessState(node.state))
@@ -49,7 +49,7 @@ export function steerRefusalMessage(reason: string, siblingLabels: readonly stri
49
49
  return `${reason}.${suggestion}`;
50
50
  }
51
51
 
52
- /** One-line honest status for a tab's steer badge; the queued line names the target and points at the ⧗ delivery badge (WO UX-A item 4). */
52
+ /** One-line honest status for a tab's steer badge; the queued line names the target and points at the ⧗ delivery badge (WO item 4). */
53
53
  export function renderSteerBadgeLine(badge: SteerBadge, width: number, palette: PanelPalette, targetLabel?: string): Line {
54
54
  const glyph = steerBadgeGlyph(badge.status);
55
55
  const tone = steerBadgeTone(badge.status, palette);
@@ -1,7 +1,7 @@
1
1
  // ---------------------------------------------------------------------------
2
2
  // fleet-stop.ts
3
3
  //
4
- // d1 (W6.2) — the "stopping…" write-window overlay, split out of fleet-panel.ts
4
+ // d1 — the "stopping…" write-window overlay, split out of fleet-panel.ts
5
5
  // to keep that file under the architecture 800-line gate (same rationale as
6
6
  // fleet-steer.ts). FleetPanel owns nothing here beyond a FleetStopTracker
7
7
  // instance; all the state->display logic lives in these pure helpers.
@@ -80,7 +80,7 @@ export interface FleetPauseDeps {
80
80
  }
81
81
 
82
82
  /**
83
- * d2 (W6.2): 'p' toggles pause<->resume by the node's state. A `paused`
83
+ * d2: 'p' toggles pause<->resume by the node's state. A `paused`
84
84
  * resumable node is resumed (interrupt's inverse); a live pausable node is
85
85
  * paused via the registry's interrupt() (its disable path). Honest refusal for
86
86
  * non-resumable/non-pausable kinds. Returns true when the key is consumed,
@@ -152,7 +152,7 @@ export function buildFleetTreeHints(
152
152
  return hints;
153
153
  }
154
154
 
155
- /** K-confirm descendant stats (UX-C item 6): total = every non-terminal descendant (what a cascade kill takes down); active = the individually-killable subset. Was "active only" in an earlier version, undercounting a mixed subtree. */
155
+ /** K-confirm descendant stats (item 6): total = every non-terminal descendant (what a cascade kill takes down); active = the individually-killable subset. Was "active only" in an earlier version, undercounting a mixed subtree. */
156
156
  export function countDescendantStats(rows: readonly FleetTreeRow[], nodeId: string): { total: number; active: number } {
157
157
  const byParent = new Map<string, string[]>();
158
158
  for (const row of rows) {
@@ -91,17 +91,16 @@ export function appendSteerText(draft: string, ch: string): string {
91
91
  * One attached session tab. `agentId` is the SDK attach handle for
92
92
  * `AgentManager.getConversationSnapshot(agentId)` — populated only for
93
93
  * 'agent' tabs (agent.ts sets ProcessNode.id = record.id, so node.id IS the
94
- * agentId; see the W3.1 brief's C2 note). 'wrfc-chain' tabs render a live
95
- * member-summary instead of a transcript (a chain has no single conversation
96
- * of its own — see fleet-transcript.ts renderFleetChainSummary) and carry an
97
- * empty agentId, unused.
94
+ * agentId). 'wrfc-chain' tabs render a live member-summary instead of a
95
+ * transcript (a chain has no single conversation of its own — see
96
+ * fleet-transcript.ts renderFleetChainSummary) and carry an empty agentId,
97
+ * unused.
98
98
  *
99
- * `lineCache` is a PER-TAB `MessageLineCache` (C5 backpressure): switching
100
- * tabs must never invalidate or thrash the main session's own cache, and a
101
- * background (non-focused) tab must render nothing beyond its existing
102
- * tree-row, so its cache simply stays empty (size 0) until the tab is
103
- * focused. Disposed (`.clear()`) on detach so a closed tab's rendered
104
- * Line[] are not retained (brief risk #8).
99
+ * `lineCache` is a PER-TAB `MessageLineCache`: switching tabs must never
100
+ * invalidate or thrash the main session's own cache, and a background
101
+ * (non-focused) tab must render nothing beyond its existing tree-row, so its
102
+ * cache simply stays empty (size 0) until the tab is focused. Disposed
103
+ * (`.clear()`) on detach so a closed tab's rendered Line[] are not retained.
105
104
  */
106
105
  export interface FleetTab {
107
106
  readonly nodeId: string;
@@ -111,10 +110,10 @@ export interface FleetTab {
111
110
  readonly lineCache: MessageLineCache;
112
111
  /**
113
112
  * Cached parsed ledger fallback for a terminal agent whose conversation
114
- * snapshot has been evicted from the SDK's retention ring (C6 degraded
115
- * path). `null` = not yet loaded/attempted; `[]` = loaded and empty (or
116
- * the load failed) — both render the same honest "no transcript" state
117
- * once loaded is true.
113
+ * snapshot has been evicted from the SDK's retention ring (the degraded
114
+ * fallback path). `null` = not yet loaded/attempted; `[]` = loaded and
115
+ * empty (or the load failed) — both render the same honest "no transcript"
116
+ * state once loaded is true.
118
117
  */
119
118
  ledgerEntries: Record<string, unknown>[] | null;
120
119
  ledgerLoadStarted: boolean;
@@ -59,7 +59,7 @@ function toneColor(tone: FleetStateTone, palette: PanelPalette): string {
59
59
  }
60
60
 
61
61
  // ---------------------------------------------------------------------------
62
- // Agent transcript (C6 live/frozen split)
62
+ // Agent transcript (live/frozen split)
63
63
  // ---------------------------------------------------------------------------
64
64
 
65
65
  export type FleetTranscriptMode = 'live' | 'frozen' | 'unavailable';
@@ -70,7 +70,7 @@ export interface FleetTranscriptRender {
70
70
  }
71
71
 
72
72
  /**
73
- * W3.3 (design point 4) — a 'frozen' transcript is a static capture of a
73
+ * (design point 4) — a 'frozen' transcript is a static capture of a
74
74
  * completed process, not something that will change on the next render. The
75
75
  * distinction matters because this wave also introduced kill/interrupt
76
76
  * display bugs (elapsed/usage briefly climbing after a terminal state
@@ -157,7 +157,7 @@ export function renderFleetAgentTranscript(
157
157
  }
158
158
 
159
159
  // ---------------------------------------------------------------------------
160
- // Chain summary — 'wrfc-chain' tabs have no single conversation (C2/C6)
160
+ // Chain summary — 'wrfc-chain' tabs have no single conversation
161
161
  // ---------------------------------------------------------------------------
162
162
 
163
163
  /**
@@ -197,7 +197,7 @@ export function renderFleetChainSummary(
197
197
 
198
198
  // ---------------------------------------------------------------------------
199
199
  // Ledger fallback — degraded activity view for a terminal agent whose
200
- // full-fidelity snapshot is unavailable (C6 "honest fallback")
200
+ // full-fidelity snapshot is unavailable (an honest fallback)
201
201
  // ---------------------------------------------------------------------------
202
202
 
203
203
  /**
@@ -257,7 +257,7 @@ function renderLedgerEntry(width: number, entry: Record<string, unknown>, palett
257
257
  const toolName = typeof entry['toolName'] === 'string' ? entry['toolName'] : 'tool';
258
258
  const success = entry['success'] !== false;
259
259
  const bad = palette.bad ?? DEFAULT_PANEL_PALETTE.bad;
260
- // W3.3: the writer already truncates this to 500 chars (session.ts's
260
+ // the writer already truncates this to 500 chars (session.ts's
261
261
  // resultPreview field) — passed through verbatim (collapsed to one
262
262
  // line), never re-summarized or fabricated, then tail-truncated again
263
263
  // to fit the row.
@@ -77,7 +77,7 @@ const C = extendPalette(DEFAULT_PANEL_PALETTE, {
77
77
  commitAuthor: '244',
78
78
  selected: '#1c1c1c',
79
79
  selectedFg: '#ffffff',
80
- diffMeta: DIFF_TONES.hunk, // WO-204: shared diff-hunk token, was a local literal
80
+ diffMeta: DIFF_TONES.hunk, // shared diff-hunk token, was a local literal
81
81
  diffNeutral: '250',
82
82
  // Reuses the existing workflow accent token rather than adding a new hex
83
83
  // literal (architecture gate ratchets the raw-hex-literal count).
@@ -626,7 +626,7 @@ export class GitPanel extends BasePanel {
626
626
  { keys: 'r', label: 'refresh' },
627
627
  ], DEFAULT_PANEL_PALETTE),
628
628
  ];
629
- const emptyStateLines = buildEmptyState(width, ' No git rows', 'This repository has no staged or unstaged changes and no commits to display yet.', [{ command: 'r', summary: 'refresh working-tree status in this panel, or stage changes to populate this view' }], DEFAULT_PANEL_PALETTE); // WO-160: was '/git status' (chat-only, never touches this panel)
629
+ const emptyStateLines = buildEmptyState(width, ' No git rows', 'This repository has no staged or unstaged changes and no commits to display yet.', [{ command: 'r', summary: 'refresh working-tree status in this panel, or stage changes to populate this view' }], DEFAULT_PANEL_PALETTE); // was '/git status' (chat-only, never touches this panel)
630
630
  const rows: Line[] = [];
631
631
  for (let i = 0; i < this.items.length; i++) {
632
632
  const item = this.items[i];
@@ -7,7 +7,7 @@ export { CostTrackerPanel } from './cost-tracker-panel.ts';
7
7
  export { GitPanel } from './git-panel.ts';
8
8
  export { registerBuiltinPanels } from './builtin-panels.ts';
9
9
  export type { BuiltinPanelDeps } from './builtin-panels.ts';
10
- // W6.1 (the purge) — group B: plugins/skills panels are register-retired but
10
+ // (the purge) — group B: plugins/skills panels are register-retired but
11
11
  // their modules are retained for shared non-class exports (PluginManagerControls;
12
12
  // discoverSkills + SkillRecord/SkillOrigin, consumed by command runtimes and the
13
13
  // skills modal). The other group-A and group-B panel classes are deleted outright
@@ -16,3 +16,6 @@ export { PluginsPanel } from './plugins-panel.ts';
16
16
  export { SkillsPanel } from './skills-panel.ts';
17
17
  export { FleetPanel } from './fleet-panel.ts';
18
18
  export type { FleetActionCallbacks } from './fleet-panel.ts';
19
+ export { NotificationsPanel } from './notifications-panel.ts';
20
+ export { PanelNotificationFeed, getSharedNotificationFeed } from './notifications-feed.ts';
21
+ export type { PanelFeedEntry } from './notifications-feed.ts';
@@ -21,7 +21,7 @@ import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
21
21
  import { type ConfirmState, handleConfirmInput } from './confirm-state.ts';
22
22
 
23
23
  // Base chrome only — state colors and text tokens come straight from
24
- // DEFAULT_PANEL_PALETTE (WO-002).
24
+ // DEFAULT_PANEL_PALETTE.
25
25
  const C = DEFAULT_PANEL_PALETTE;
26
26
 
27
27
  function formatRoles(roles: readonly string[]): string {
@@ -16,7 +16,7 @@ import type {
16
16
  } from '../../input/config-modal-types.ts';
17
17
 
18
18
  // ---------------------------------------------------------------------------
19
- // Hooks → config-modal surface (W6.1 group-B port). Two tabs: 'Hooks' (active
19
+ // Hooks → config-modal surface (group-B port). Two tabs: 'Hooks' (active
20
20
  // registrations + contract posture) and 'Activity' (recent runtime activity +
21
21
  // managed authoring + last simulation — the panel's expand-activity view, now a
22
22
  // dedicated tab). All sources are in-memory (dispatcher/workbench/tracker hold
@@ -9,7 +9,7 @@ import type {
9
9
  import { KeybindingsManager } from '../../input/keybindings.ts';
10
10
 
11
11
  // ---------------------------------------------------------------------------
12
- // Docs + Shortcuts → 'keybindings' config-modal surface (W6.1 group-B port).
12
+ // Docs + Shortcuts → 'keybindings' config-modal surface (group-B port).
13
13
  // A MERGE of the retired DocsPanel (tools/models/shortcuts) and the
14
14
  // shortcuts-overlay reference. Three tabs: 'Tools', 'Models', and 'Shortcuts'
15
15
  // (the categorized keyboard reference — driven live off keybindingsManager so
@@ -112,7 +112,7 @@ class KeybindingsModalSurface implements ConfigModalSurface {
112
112
  if (id === 'refresh') { ctx.setStatus('Docs & shortcuts are read live.'); ctx.requestRender(); return; }
113
113
  if (id !== 'activate') return;
114
114
  if (ctx.tabId === 'tools') {
115
- // DEBT-5 item 4: pass the tool name through as a deep-link target.
115
+ // item 4: pass the tool name through as a deep-link target.
116
116
  // Honest caveat (documented, not a bug to silently paper over): fleet's
117
117
  // ProcessKind set has no 'tool' node — a docs Tools row names a static
118
118
  // tool DEFINITION, not a live process, so FleetPanel.receiveDeepLink
@@ -9,7 +9,7 @@ import type {
9
9
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
10
10
 
11
11
  // ---------------------------------------------------------------------------
12
- // Knowledge (graph) → config-modal surface (W6.1 group-B port). Two tabs:
12
+ // Knowledge (graph) → config-modal surface (group-B port). Two tabs:
13
13
  // 'Browse' (sources/nodes/issues + schedules) and 'Review' (the open-issue
14
14
  // queue) — the panel's browse/review toggle, now host tabs. Issue review
15
15
  // mutations (accept/reject/resolve/reopen) route to the `/knowledge
@@ -38,14 +38,14 @@ interface MarketplaceRow {
38
38
  const KINDS: readonly EcosystemEntryKind[] = ['plugin', 'skill', 'hook-pack', 'policy-pack'];
39
39
 
40
40
  /**
41
- * Marketplace → config-modal surface (W6.1 group-B port). Local-first
41
+ * Marketplace → config-modal surface (group-B port). Local-first
42
42
  * publish/import catalog (NOT a remote store) with provenance, compatibility,
43
43
  * and install posture. Disk catalog loads happen in refresh() (never in
44
44
  * buildView), mirroring the panel's explicit render()/refresh() split.
45
45
  * Install/uninstall route to the `/marketplace` command path (charter: no
46
46
  * destructive confirm folded into a modal).
47
47
  *
48
- * B30 (honest empty-state): the panel's original "No curated marketplace
48
+ * Honest empty-state: the panel's original "No curated marketplace
49
49
  * entries found yet." copy implied a curated remote catalog. It isn't one —
50
50
  * loadEcosystemCatalog only ever reads .goodvibes/ecosystem/<kind>s.json under
51
51
  * the project/home, populated solely by `/marketplace publish` and
@@ -118,7 +118,7 @@ class MarketplaceModalSurface implements ConfigModalSurface {
118
118
  const snapshot = this.deps.readModel?.getSnapshot();
119
119
  const rows: ConfigModalRow[] = [];
120
120
 
121
- // Honest empty / degraded state (B30). loadError → degraded banner.
121
+ // Honest empty / degraded state. loadError → degraded banner.
122
122
  if (this.loadError) {
123
123
  return { title: 'Marketplace', degraded: this.loadError, tabs: [{ id: 'catalog', label: 'Catalog', rows: [] }] };
124
124
  }
@@ -205,7 +205,7 @@ export function createMarketplaceModalSurface(deps: MarketplaceModalDeps): Confi
205
205
  * Deterministic golden fixture: catalog roots wired at a fresh tmp path that is
206
206
  * removed immediately (loadEcosystemCatalog/listInstalledEcosystemEntries guard
207
207
  * missing paths with existsSync → [], so refresh() finds nothing and renders the
208
- * B30 honest empty-state copy). The random tmp path never appears in the
208
+ * honest empty-state copy). The random tmp path never appears in the
209
209
  * rendered lines (the empty-state copy is static), so the golden is byte-stable.
210
210
  */
211
211
  export function marketplaceModalGoldenSurface(): ConfigModalSurface {
@@ -9,7 +9,7 @@ import type {
9
9
  import { memoryRecordTemporalStatus } from '@pellux/goodvibes-sdk/platform/state';
10
10
 
11
11
  // ---------------------------------------------------------------------------
12
- // Memory → config-modal surface (W6.1 group-B port). Two tabs: 'All Records'
12
+ // Memory → config-modal surface (group-B port). Two tabs: 'All Records'
13
13
  // (the full record list) and 'Review Queue' (the operator review queue) — the
14
14
  // same split the panel toggled with Tab, now real host tabs. Review-state
15
15
  // mutations (reviewed/stale/contradicted/fresh) and record delete route to the
@@ -227,9 +227,9 @@ export async function memoryModalGoldenSurface(): Promise<ConfigModalSurface> {
227
227
  const records: readonly MemoryRecordLike[] = [
228
228
  {
229
229
  id: 'mem-0000001a', scope: 'project', cls: 'decision',
230
- summary: 'Wave-6 batches panel retirements behind modal builders.',
231
- detail: 'Applies to KNOWLEDGE, MEMORY, WORK-PLAN in WO-B.',
232
- tags: ['wave-6', 'modals'], reviewState: 'reviewed', confidence: 90,
230
+ summary: 'Panel retirements are batched behind modal builders.',
231
+ detail: 'Applies to the knowledge, memory, and work-plan modals.',
232
+ tags: ['panels', 'modals'], reviewState: 'reviewed', confidence: 90,
233
233
  reviewedAt: FIXED_CREATED_AT + 3600000, reviewedBy: 'operator', createdAt: FIXED_CREATED_AT,
234
234
  provenance: [{ kind: 'session', ref: 'session-fixed-1' }],
235
235
  },
@@ -3,7 +3,7 @@ import type { ModalSectionStyle } from '../../renderer/modal-factory.ts';
3
3
  import type { ConfigModalRow } from '../../input/config-modal-types.ts';
4
4
 
5
5
  /**
6
- * Shared formatting helpers for W6.1 config-modal surfaces. Row styling reuses
6
+ * Shared formatting helpers for config-modal surfaces. Row styling reuses
7
7
  * DEFAULT_PANEL_PALETTE (the retired panels' palette) so a migrated modal reads
8
8
  * as the same surface it replaced — the goldens stay panel-consistent.
9
9
  */
@@ -1,7 +1,7 @@
1
1
  import { activeUiTones, registerThemeRefresh } from '../../renderer/theme.ts';
2
2
 
3
3
  // ---------------------------------------------------------------------------
4
- // Semantic tone tokens for the W6.1 group-B config modals.
4
+ // Semantic tone tokens for the group-B config modals.
5
5
  //
6
6
  // Derived entirely from the chrome token set so the builders carry NO raw hex
7
7
  // color literals (architecture: no-raw-hex-literal-growth). Rebuilt IN PLACE