@pellux/goodvibes-tui 0.18.12 → 0.18.13

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 (157) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +1 -1
  3. package/docs/foundation-artifacts/operator-contract.json +1 -1
  4. package/package.json +2 -2
  5. package/src/config/index.ts +1 -138
  6. package/src/config/subscription-providers.ts +1 -127
  7. package/src/core/conversation-rendering.ts +3 -3
  8. package/src/core/conversation.ts +176 -423
  9. package/src/core/history.ts +45 -0
  10. package/src/core/orchestrator.ts +3 -735
  11. package/src/core/system-message-router.ts +19 -58
  12. package/src/input/handler-content-actions.ts +2 -2
  13. package/src/input/handler-feed.ts +1 -1
  14. package/src/input/handler-modal-token-routes.ts +1 -1
  15. package/src/input/handler-ui-state.ts +1 -1
  16. package/src/input/handler.ts +1 -1
  17. package/src/input/search.ts +1 -1
  18. package/src/input/selection.ts +2 -2
  19. package/src/main.ts +1 -1
  20. package/src/panels/agent-inspector-panel.ts +3 -3
  21. package/src/panels/agent-logs-panel.ts +3 -3
  22. package/src/panels/approval-panel.ts +2 -2
  23. package/src/panels/automation-control-panel.ts +3 -3
  24. package/src/panels/base-panel.ts +14 -14
  25. package/src/panels/builtin/operations.ts +1 -1
  26. package/src/panels/builtin/session.ts +1 -1
  27. package/src/panels/builtin/shared.ts +3 -3
  28. package/src/panels/cockpit-panel.ts +2 -2
  29. package/src/panels/communication-panel.ts +3 -3
  30. package/src/panels/context-visualizer-panel.ts +2 -2
  31. package/src/panels/control-plane-panel.ts +3 -3
  32. package/src/panels/cost-tracker-panel.ts +3 -3
  33. package/src/panels/debug-panel.ts +2 -2
  34. package/src/panels/diff-panel.ts +2 -2
  35. package/src/panels/docs-panel.ts +1 -1
  36. package/src/panels/eval-panel.ts +2 -2
  37. package/src/panels/file-explorer-panel.ts +3 -3
  38. package/src/panels/file-preview-panel.ts +3 -3
  39. package/src/panels/forensics-panel.ts +2 -2
  40. package/src/panels/git-panel.ts +1 -1
  41. package/src/panels/hooks-panel.ts +3 -3
  42. package/src/panels/incident-review-panel.ts +1 -1
  43. package/src/panels/intelligence-panel.ts +2 -2
  44. package/src/panels/knowledge-panel.ts +1 -1
  45. package/src/panels/local-auth-panel.ts +2 -2
  46. package/src/panels/marketplace-panel.ts +1 -1
  47. package/src/panels/mcp-panel.ts +3 -3
  48. package/src/panels/memory-panel.ts +1 -1
  49. package/src/panels/ops-control-panel.ts +3 -3
  50. package/src/panels/ops-strategy-panel.ts +2 -2
  51. package/src/panels/orchestration-panel.ts +2 -2
  52. package/src/panels/panel-list-panel.ts +6 -6
  53. package/src/panels/plan-dashboard-panel.ts +1 -1
  54. package/src/panels/plugins-panel.ts +2 -2
  55. package/src/panels/policy-panel.ts +2 -2
  56. package/src/panels/polish.ts +3 -3
  57. package/src/panels/provider-accounts-panel.ts +2 -2
  58. package/src/panels/provider-health-panel.ts +2 -2
  59. package/src/panels/provider-stats-panel.ts +3 -3
  60. package/src/panels/remote-panel.ts +3 -3
  61. package/src/panels/routes-panel.ts +3 -3
  62. package/src/panels/sandbox-panel.ts +2 -2
  63. package/src/panels/schedule-panel.ts +1 -1
  64. package/src/panels/security-panel.ts +2 -2
  65. package/src/panels/services-panel.ts +2 -2
  66. package/src/panels/session-browser-panel.ts +2 -2
  67. package/src/panels/settings-sync-panel.ts +2 -2
  68. package/src/panels/skills-panel.ts +6 -6
  69. package/src/panels/subscription-panel.ts +2 -2
  70. package/src/panels/symbol-outline-panel.ts +3 -3
  71. package/src/panels/system-messages-panel.ts +4 -4
  72. package/src/panels/tasks-panel.ts +2 -2
  73. package/src/panels/thinking-panel.ts +3 -3
  74. package/src/panels/token-budget-panel.ts +1 -1
  75. package/src/panels/tool-inspector-panel.ts +3 -3
  76. package/src/panels/types.ts +5 -5
  77. package/src/panels/watchers-panel.ts +3 -3
  78. package/src/panels/welcome-panel.ts +1 -1
  79. package/src/panels/worktree-panel.ts +2 -2
  80. package/src/panels/wrfc-panel.ts +3 -3
  81. package/src/permissions/prompt.ts +3 -22
  82. package/src/plugins/loader.ts +15 -304
  83. package/src/renderer/agent-detail-modal.ts +1 -1
  84. package/src/renderer/autocomplete-overlay.ts +2 -2
  85. package/src/renderer/bookmark-modal.ts +1 -1
  86. package/src/renderer/bottom-bar.ts +2 -2
  87. package/src/renderer/buffer.ts +1 -1
  88. package/src/renderer/code-block.ts +2 -2
  89. package/src/renderer/compositor.ts +2 -2
  90. package/src/renderer/context-inspector.ts +1 -1
  91. package/src/renderer/conversation-layout.ts +2 -2
  92. package/src/renderer/conversation-overlays.ts +1 -1
  93. package/src/renderer/conversation-surface.ts +2 -2
  94. package/src/renderer/diff-view.ts +2 -2
  95. package/src/renderer/diff.ts +1 -1
  96. package/src/renderer/file-picker-overlay.ts +2 -2
  97. package/src/renderer/file-tree.ts +2 -2
  98. package/src/renderer/help-overlay.ts +1 -1
  99. package/src/renderer/history-search-overlay.ts +2 -2
  100. package/src/renderer/live-tail-modal.ts +1 -1
  101. package/src/renderer/markdown.ts +2 -2
  102. package/src/renderer/modal-factory.ts +3 -3
  103. package/src/renderer/model-picker-overlay.ts +2 -2
  104. package/src/renderer/overlay-box.ts +2 -2
  105. package/src/renderer/panel-composite.ts +1 -1
  106. package/src/renderer/panel-picker-overlay.ts +2 -2
  107. package/src/renderer/panel-tab-bar.ts +1 -1
  108. package/src/renderer/panel-workspace-bar.ts +1 -1
  109. package/src/renderer/process-indicator.ts +2 -2
  110. package/src/renderer/process-modal.ts +1 -1
  111. package/src/renderer/profile-picker-modal.ts +2 -2
  112. package/src/renderer/progress.ts +2 -2
  113. package/src/renderer/search-overlay.ts +2 -2
  114. package/src/renderer/selection-modal-overlay.ts +2 -2
  115. package/src/renderer/session-picker-modal.ts +2 -2
  116. package/src/renderer/settings-modal.ts +2 -2
  117. package/src/renderer/shell-surface.ts +1 -1
  118. package/src/renderer/system-message.ts +1 -1
  119. package/src/renderer/tab-strip.ts +2 -2
  120. package/src/renderer/text-layout.ts +1 -1
  121. package/src/renderer/thinking.ts +1 -1
  122. package/src/renderer/tool-call.ts +2 -2
  123. package/src/renderer/ui-factory.ts +2 -2
  124. package/src/runtime/bootstrap-command-context.ts +4 -5
  125. package/src/runtime/bootstrap-command-parts.ts +1 -3
  126. package/src/runtime/bootstrap-core.ts +3 -2
  127. package/src/runtime/bootstrap-hook-bridge.ts +15 -174
  128. package/src/runtime/bootstrap-shell.ts +4 -4
  129. package/src/runtime/bootstrap.ts +1 -1
  130. package/src/runtime/context.ts +4 -20
  131. package/src/runtime/diagnostics/panels/index.ts +1 -1
  132. package/src/runtime/diagnostics/panels/ops.ts +1 -1
  133. package/src/runtime/diagnostics/panels/panel-resources.ts +118 -0
  134. package/src/runtime/perf/panel-contracts.ts +32 -0
  135. package/src/runtime/perf/panel-health-monitor.ts +18 -0
  136. package/src/runtime/services.ts +4 -4
  137. package/src/runtime/store/domains/conversation.ts +1 -181
  138. package/src/runtime/store/domains/permissions.ts +1 -143
  139. package/src/runtime/store/helpers/reducers/conversation.ts +1 -228
  140. package/src/runtime/store/helpers/reducers/lifecycle.ts +1 -440
  141. package/src/runtime/store/selectors/index.ts +11 -6
  142. package/src/runtime/store/state.ts +12 -4
  143. package/src/runtime/ui-events.ts +46 -0
  144. package/src/runtime/ui-services.ts +1 -1
  145. package/src/shell/ui-openers.ts +1 -1
  146. package/src/tools/index.ts +1 -186
  147. package/src/types/grid.ts +48 -0
  148. package/src/utils/clipboard.ts +21 -0
  149. package/src/utils/splash-lines.ts +1 -1
  150. package/src/utils/terminal-width.ts +185 -0
  151. package/src/version.ts +1 -1
  152. package/src/daemon/facade-composition.ts +0 -398
  153. package/src/daemon/facade.ts +0 -638
  154. package/src/daemon/surface-policy.ts +0 -60
  155. package/src/daemon/types.ts +0 -191
  156. package/src/runtime/ui-read-models-core.ts +0 -95
  157. package/src/runtime/ui-read-models-operations.ts +0 -203
@@ -10,11 +10,11 @@
10
10
  * - Footer hints: [Tab] Category [↑↓] Navigate [Enter] Edit/Toggle [Esc] Close
11
11
  */
12
12
 
13
- import type { Line } from '@pellux/goodvibes-sdk/platform/types/grid';
13
+ import type { Line } from '../types/grid.ts';
14
14
  import { ModalFactory } from './modal-factory.ts';
15
15
  import type { SettingsModal, SettingEntry, FlagEntry, McpEntry, SubscriptionEntry } from '../input/settings-modal.ts';
16
16
  import { SETTINGS_CATEGORIES } from '../input/settings-modal.ts';
17
- import { fitDisplay, truncateDisplay } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
17
+ import { fitDisplay, truncateDisplay } from '../utils/terminal-width.ts';
18
18
  import { getOverlaySurfaceMetrics, getStableOverlayContentRows } from './overlay-viewport.ts';
19
19
  import { getVisibleWindow } from './surface-layout.ts';
20
20
 
@@ -1,4 +1,4 @@
1
- import type { Line } from '@pellux/goodvibes-sdk/platform/types/grid';
1
+ import type { Line } from '../types/grid.ts';
2
2
  import { renderProcessIndicator } from './process-indicator.ts';
3
3
  import { UIFactory } from './ui-factory.ts';
4
4
 
@@ -1,4 +1,4 @@
1
- import { type Line } from '@pellux/goodvibes-sdk/platform/types/grid';
1
+ import { type Line } from '../types/grid.ts';
2
2
  import { BORDERS, COLORS } from './layout.ts';
3
3
  import { renderConversationNotice } from './conversation-surface.ts';
4
4
 
@@ -1,5 +1,5 @@
1
- import type { Line } from '@pellux/goodvibes-sdk/platform/types/grid';
2
- import { getDisplayWidth } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
1
+ import type { Line } from '../types/grid.ts';
2
+ import { getDisplayWidth } from '../utils/terminal-width.ts';
3
3
  import { buildStyledPanelLine, type StyledPanelSegment } from '../panels/polish.ts';
4
4
 
5
5
  export interface TabStripItem {
@@ -1,4 +1,4 @@
1
- import { getDisplayWidth, truncateDisplay, wrapText } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
1
+ import { getDisplayWidth, truncateDisplay, wrapText } from '../utils/terminal-width.ts';
2
2
 
3
3
  export function wrapWithHangingIndent(
4
4
  text: string,
@@ -1,4 +1,4 @@
1
- import { type Line } from '@pellux/goodvibes-sdk/platform/types/grid';
1
+ import { type Line } from '../types/grid.ts';
2
2
  import { BORDERS, COLORS } from './layout.ts';
3
3
  import { renderConversationNotice } from './conversation-surface.ts';
4
4
 
@@ -1,6 +1,6 @@
1
- import { type Line, createStyledCell, createEmptyLine } from '@pellux/goodvibes-sdk/platform/types/grid';
1
+ import { type Line, createStyledCell, createEmptyLine } from '../types/grid.ts';
2
2
  import { LAYOUT, TOOL_STATUS } from './layout.ts';
3
- import { getDisplayWidth, truncateDisplay } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
3
+ import { getDisplayWidth, truncateDisplay } from '../utils/terminal-width.ts';
4
4
  import type { ToolCall } from '@pellux/goodvibes-sdk/platform/types/tools';
5
5
 
6
6
  const TOOL_NAME_MIN_WIDTH = 8;
@@ -1,7 +1,7 @@
1
- import { type Line, type Cell, createEmptyLine, createEmptyCell } from '@pellux/goodvibes-sdk/platform/types/grid';
1
+ import { type Line, type Cell, createEmptyLine, createEmptyCell } from '../types/grid.ts';
2
2
  import { LAYOUT } from './layout.ts';
3
3
  import { VERSION } from '../version.ts';
4
- import { fitDisplay, getDisplayWidth, truncateDisplay, wrapText, interpolateColor } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
4
+ import { fitDisplay, getDisplayWidth, truncateDisplay, wrapText, interpolateColor } from '../utils/terminal-width.ts';
5
5
  import type { GitHeaderInfo } from './git-status.ts';
6
6
  import { renderConversationFragment, renderConversationStatusLine, type ConversationStatusSegment } from './conversation-surface.ts';
7
7
  import { GLYPHS } from './ui-primitives.ts';
@@ -7,8 +7,8 @@ import type { McpApi } from '@pellux/goodvibes-sdk/platform/mcp/mcp-api';
7
7
  import type { PanelManager } from '../panels/panel-manager.ts';
8
8
  import type { ProviderApi } from '@pellux/goodvibes-sdk/platform/providers/provider-api';
9
9
  import type { OpsApi } from '@pellux/goodvibes-sdk/platform/runtime/ops-api';
10
+ import type { MutableRuntimeState } from '@pellux/goodvibes-sdk/platform/runtime/mutable-runtime-state';
10
11
  import type { ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers/registry';
11
- import type { MutableRuntimeState } from './context.ts';
12
12
  import type { CommandContext } from '../input/command-registry.ts';
13
13
  import type { KeybindingsManager } from '../input/keybindings.ts';
14
14
  import type { PermissionRequestHandler } from '@pellux/goodvibes-sdk/platform/permissions/prompt';
@@ -22,7 +22,6 @@ import type { IntegrationHelperService } from '@pellux/goodvibes-sdk/platform/ru
22
22
  import type { KnowledgeService } from '@pellux/goodvibes-sdk/platform/knowledge/index';
23
23
  import type { PluginManager } from '@pellux/goodvibes-sdk/platform/plugins/manager';
24
24
  import type { HookWorkbench } from '@pellux/goodvibes-sdk/platform/hooks/workbench';
25
- import type { PanelHealthMonitor } from '@pellux/goodvibes-sdk/platform/runtime/perf/panel-health-monitor';
26
25
  import type { WorktreeRegistry } from '@pellux/goodvibes-sdk/platform/runtime/worktree/registry';
27
26
  import type { SandboxSessionRegistry } from '@pellux/goodvibes-sdk/platform/runtime/sandbox/session-registry';
28
27
  import type { UiReadModels } from './ui-read-models.ts';
@@ -101,13 +100,13 @@ export type CreateBootstrapCommandContextOptions = {
101
100
  opsApi?: OpsApi;
102
101
  directTransport?: DirectTransport;
103
102
  panelManager: PanelManager;
104
- panelHealthMonitor: PanelHealthMonitor;
105
103
  worktreeRegistry: WorktreeRegistry;
106
104
  sandboxSessionRegistry: SandboxSessionRegistry;
107
105
  loadSystemPrompt: () => string;
108
106
  activatePlan: (planId: string, task: string) => void;
109
107
  completeModelSelectionSideEffect?: () => void;
110
108
  sessionLineageTracker?: import('@pellux/goodvibes-sdk/platform/core/session-lineage').SessionLineageTracker;
109
+ componentHealthMonitor: import('@pellux/goodvibes-sdk/platform/runtime/perf/component-health-monitor').ComponentHealthMonitor;
111
110
  };
112
111
 
113
112
  export function createBootstrapCommandContext(
@@ -166,12 +165,12 @@ export function createBootstrapCommandContext(
166
165
  opsApi,
167
166
  directTransport,
168
167
  panelManager,
169
- panelHealthMonitor,
170
168
  worktreeRegistry,
171
169
  sandboxSessionRegistry,
172
170
  loadSystemPrompt,
173
171
  activatePlan,
174
172
  completeModelSelectionSideEffect,
173
+ componentHealthMonitor,
175
174
  } = options;
176
175
 
177
176
  const shellServices = createBootstrapCommandShellServices({
@@ -182,7 +181,7 @@ export function createBootstrapCommandContext(
182
181
  adaptivePlanner,
183
182
  sessionOrchestration,
184
183
  shellPaths,
185
- panelHealthMonitor,
184
+ componentHealthMonitor,
186
185
  worktreeRegistry,
187
186
  sandboxSessionRegistry,
188
187
  readModels,
@@ -8,8 +8,8 @@ import type { McpApi } from '@pellux/goodvibes-sdk/platform/mcp/mcp-api';
8
8
  import type { PanelManager } from '../panels/panel-manager.ts';
9
9
  import type { ProviderApi } from '@pellux/goodvibes-sdk/platform/providers/provider-api';
10
10
  import type { OpsApi } from '@pellux/goodvibes-sdk/platform/runtime/ops-api';
11
+ import type { MutableRuntimeState } from '@pellux/goodvibes-sdk/platform/runtime/mutable-runtime-state';
11
12
  import type { ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers/registry';
12
- import type { MutableRuntimeState } from './context.ts';
13
13
  import type { CommandContext } from '../input/command-registry.ts';
14
14
  import type { KeybindingsManager } from '../input/keybindings.ts';
15
15
  import type { PermissionRequestHandler } from '@pellux/goodvibes-sdk/platform/permissions/prompt';
@@ -23,7 +23,6 @@ import type { IntegrationHelperService } from '@pellux/goodvibes-sdk/platform/ru
23
23
  import type { KnowledgeService } from '@pellux/goodvibes-sdk/platform/knowledge/index';
24
24
  import type { PluginManager } from '@pellux/goodvibes-sdk/platform/plugins/manager';
25
25
  import type { HookWorkbench } from '@pellux/goodvibes-sdk/platform/hooks/workbench';
26
- import type { PanelHealthMonitor } from '@pellux/goodvibes-sdk/platform/runtime/perf/panel-health-monitor';
27
26
  import type { WorktreeRegistry } from '@pellux/goodvibes-sdk/platform/runtime/worktree/registry';
28
27
  import type { SandboxSessionRegistry } from '@pellux/goodvibes-sdk/platform/runtime/sandbox/session-registry';
29
28
  import type { UiReadModels } from './ui-read-models.ts';
@@ -117,7 +116,6 @@ export interface BootstrapCommandSectionOptions {
117
116
  readonly mcpApi?: McpApi;
118
117
  readonly opsApi?: OpsApi;
119
118
  readonly directTransport?: DirectTransport;
120
- readonly panelHealthMonitor: PanelHealthMonitor;
121
119
  readonly worktreeRegistry: WorktreeRegistry;
122
120
  readonly sandboxSessionRegistry: SandboxSessionRegistry;
123
121
  }
@@ -11,7 +11,8 @@ import type { PermissionRequestHandler } from '@pellux/goodvibes-sdk/platform/pe
11
11
  import type { SystemMessageRouter } from '../core/system-message-router.ts';
12
12
  import type { ConversationFollowUpItem } from '@pellux/goodvibes-sdk/platform/core/conversation-follow-ups';
13
13
  import type { ControlPlaneRecentEvent } from '@pellux/goodvibes-sdk/platform/control-plane/gateway';
14
- import type { BootstrapOptions, MutableRuntimeState } from './context.ts';
14
+ import type { MutableRuntimeState } from '@pellux/goodvibes-sdk/platform/runtime/mutable-runtime-state';
15
+ import type { BootstrapOptions } from './context.ts';
15
16
  import { createFeatureFlagManager } from '@pellux/goodvibes-sdk/platform/runtime/feature-flags/index';
16
17
  import { RuntimeEventBus } from '@pellux/goodvibes-sdk/platform/runtime/events/index';
17
18
  import { createRuntimeStore, createDomainDispatch, type RuntimeStore } from './store/index.ts';
@@ -20,7 +21,7 @@ import {
20
21
  generateUserSessionId,
21
22
  } from '@pellux/goodvibes-sdk/platform/runtime/session-persistence';
22
23
  import { loadBootstrapSystemPrompt, syncConfiguredServices } from '@pellux/goodvibes-sdk/platform/runtime/bootstrap-helpers';
23
- import { registerBootstrapHookBridge } from './bootstrap-hook-bridge.ts';
24
+ import { registerBootstrapHookBridge } from '@pellux/goodvibes-sdk/platform/runtime/bootstrap-hook-bridge';
24
25
  import { registerBootstrapRuntimeEvents } from '@pellux/goodvibes-sdk/platform/runtime/bootstrap-runtime-events';
25
26
  import { createRuntimeServices, type RuntimeServices } from './services.ts';
26
27
  import { createUiRuntimeServices, type UiRuntimeServices } from './ui-services.ts';
@@ -1,8 +1,8 @@
1
1
  import type { ConversationManager } from '../core/conversation';
2
2
  import type { HookDispatcher } from '@pellux/goodvibes-sdk/platform/hooks/index';
3
- import type { HookCategory, HookEventPath, HookPhase } from '@pellux/goodvibes-sdk/platform/hooks/types';
4
- import type { MutableRuntimeState } from './context.ts';
5
- import type { AgentEvent, OpsEvent, RuntimeEventBus, WorkflowEvent } from '@pellux/goodvibes-sdk/platform/runtime/events/index';
3
+ import type { MutableRuntimeState } from '@pellux/goodvibes-sdk/platform/runtime/mutable-runtime-state';
4
+ import { registerBootstrapHookBridge } from '@pellux/goodvibes-sdk/platform/runtime/bootstrap-hook-bridge';
5
+ import type { RuntimeEventBus } from '@pellux/goodvibes-sdk/platform/runtime/events/index';
6
6
  import { logger } from '@pellux/goodvibes-sdk/platform/utils/logger';
7
7
  import { emitSessionResumed } from '@pellux/goodvibes-sdk/platform/runtime/emitters/index';
8
8
  import { HelperModel } from '@pellux/goodvibes-sdk/platform/config/helper-model';
@@ -14,30 +14,6 @@ import type { PanelManager } from '../panels/panel-manager.ts';
14
14
  import type { ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers/registry';
15
15
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils/error-display';
16
16
 
17
- interface FireHookOptions {
18
- readonly hookDispatcher: HookDispatcher;
19
- readonly runtime: MutableRuntimeState;
20
- }
21
-
22
- function fireHook(
23
- options: FireHookOptions,
24
- path: HookEventPath,
25
- phase: HookPhase,
26
- category: HookCategory,
27
- specific: string,
28
- payload: Record<string, unknown>,
29
- ): void {
30
- options.hookDispatcher.fire({
31
- path,
32
- phase,
33
- category,
34
- specific,
35
- sessionId: options.runtime.sessionId,
36
- timestamp: Date.now(),
37
- payload,
38
- }).catch((err: unknown) => logger.debug('Hook bridge fire error', { path, error: summarizeError(err) }));
39
- }
40
-
41
17
  export interface ResumeSessionOptions {
42
18
  readonly runtimeBus: RuntimeEventBus;
43
19
  readonly runtime: MutableRuntimeState;
@@ -54,10 +30,6 @@ export interface ResumeSessionOptions {
54
30
  }
55
31
 
56
32
  export function createResumeSessionHandler(options: ResumeSessionOptions): (sessionId: string) => void {
57
- const fireOptions: FireHookOptions = {
58
- hookDispatcher: options.hookDispatcher,
59
- runtime: options.runtime,
60
- };
61
33
  return (sessionId: string): void => {
62
34
  try {
63
35
  const { messages, meta } = options.sessionManager.load(sessionId);
@@ -119,7 +91,18 @@ export function createResumeSessionHandler(options: ResumeSessionOptions): (sess
119
91
  });
120
92
  }
121
93
  }
122
- fireHook(fireOptions, 'Lifecycle:session:load', 'Lifecycle', 'session', 'load', { sessionId });
94
+ options.hookDispatcher.fire({
95
+ path: 'Lifecycle:session:load',
96
+ phase: 'Lifecycle',
97
+ category: 'session',
98
+ specific: 'load',
99
+ sessionId: options.runtime.sessionId,
100
+ timestamp: Date.now(),
101
+ payload: { sessionId },
102
+ }).catch((err: unknown) => logger.debug('Hook bridge fire error', {
103
+ path: 'Lifecycle:session:load',
104
+ error: summarizeError(err),
105
+ }));
123
106
  } catch (error) {
124
107
  logger.debug('resumeSession failed', { error: summarizeError(error) });
125
108
  options.conversation.log('Failed to resume session.', { fg: '#ef4444' });
@@ -127,145 +110,3 @@ export function createResumeSessionHandler(options: ResumeSessionOptions): (sess
127
110
  options.requestRender();
128
111
  };
129
112
  }
130
-
131
- export interface HookBridgeRegistrationOptions {
132
- readonly runtimeBus: RuntimeEventBus;
133
- readonly hookDispatcher: HookDispatcher;
134
- readonly runtime: MutableRuntimeState;
135
- }
136
-
137
- export function registerBootstrapHookBridge(
138
- options: HookBridgeRegistrationOptions,
139
- ): Array<() => void> {
140
- const fireOptions: FireHookOptions = {
141
- hookDispatcher: options.hookDispatcher,
142
- runtime: options.runtime,
143
- };
144
- const unsubs: Array<() => void> = [];
145
- const { runtimeBus } = options;
146
-
147
- unsubs.push(runtimeBus.on<Extract<AgentEvent, { type: 'AGENT_SPAWNING' }>>('AGENT_SPAWNING', ({ payload }) => {
148
- fireHook(fireOptions, 'Lifecycle:agent:spawned', 'Lifecycle', 'agent', 'spawned', { agentId: payload.agentId, task: payload.task });
149
- }));
150
- unsubs.push(runtimeBus.on<Extract<AgentEvent, { type: 'AGENT_COMPLETED' }>>('AGENT_COMPLETED', ({ payload }) => {
151
- fireHook(fireOptions, 'Lifecycle:agent:completed', 'Lifecycle', 'agent', 'completed', {
152
- agentId: payload.agentId,
153
- result: {
154
- durationMs: payload.durationMs,
155
- ...(payload.output !== undefined ? { output: payload.output } : {}),
156
- ...(payload.toolCallsMade !== undefined ? { toolCallsMade: payload.toolCallsMade } : {}),
157
- },
158
- });
159
- }));
160
- unsubs.push(runtimeBus.on<Extract<AgentEvent, { type: 'AGENT_FAILED' }>>('AGENT_FAILED', ({ payload }) => {
161
- const specific = payload.error === 'Agent cancelled' || payload.error.includes('cancelled') ? 'cancelled' : 'failed';
162
- fireHook(fireOptions, `Lifecycle:agent:${specific}` as HookEventPath, 'Lifecycle', 'agent', specific, { agentId: payload.agentId, error: payload.error });
163
- }));
164
-
165
- unsubs.push(runtimeBus.on<Extract<WorkflowEvent, { type: 'WORKFLOW_CHAIN_CREATED' }>>('WORKFLOW_CHAIN_CREATED', ({ payload }) => {
166
- fireHook(fireOptions, 'Lifecycle:workflow:started', 'Lifecycle', 'workflow', 'started', { chainId: payload.chainId, task: payload.task });
167
- }));
168
- unsubs.push(runtimeBus.on<Extract<WorkflowEvent, { type: 'WORKFLOW_CHAIN_PASSED' }>>('WORKFLOW_CHAIN_PASSED', ({ payload }) => {
169
- fireHook(fireOptions, 'Lifecycle:workflow:completed', 'Lifecycle', 'workflow', 'completed', { chainId: payload.chainId });
170
- }));
171
- unsubs.push(runtimeBus.on<Extract<WorkflowEvent, { type: 'WORKFLOW_CHAIN_FAILED' }>>('WORKFLOW_CHAIN_FAILED', ({ payload }) => {
172
- fireHook(fireOptions, 'Lifecycle:workflow:failed', 'Lifecycle', 'workflow', 'failed', { chainId: payload.chainId, reason: payload.reason });
173
- }));
174
- unsubs.push(runtimeBus.on<Extract<WorkflowEvent, { type: 'WORKFLOW_REVIEW_COMPLETED' }>>('WORKFLOW_REVIEW_COMPLETED', ({ payload }) => {
175
- fireHook(fireOptions, 'Lifecycle:workflow:reviewed', 'Lifecycle', 'workflow', 'reviewed', {
176
- chainId: payload.chainId,
177
- score: payload.score,
178
- passed: payload.passed,
179
- });
180
- }));
181
- unsubs.push(runtimeBus.on<Extract<WorkflowEvent, { type: 'WORKFLOW_FIX_ATTEMPTED' }>>('WORKFLOW_FIX_ATTEMPTED', ({ payload }) => {
182
- fireHook(fireOptions, 'Lifecycle:workflow:fix-attempted', 'Lifecycle', 'workflow', 'fix-attempted', {
183
- chainId: payload.chainId,
184
- attempt: payload.attempt,
185
- maxAttempts: payload.maxAttempts,
186
- });
187
- }));
188
- unsubs.push(runtimeBus.on<Extract<WorkflowEvent, { type: 'WORKFLOW_GATE_RESULT' }>>('WORKFLOW_GATE_RESULT', ({ payload }) => {
189
- fireHook(fireOptions, 'Lifecycle:workflow:gate-result', 'Lifecycle', 'workflow', 'gate-result', {
190
- chainId: payload.chainId,
191
- gate: payload.gate,
192
- passed: payload.passed,
193
- });
194
- }));
195
- unsubs.push(runtimeBus.on<Extract<import('@pellux/goodvibes-sdk/platform/runtime/events/orchestration').OrchestrationEvent, { type: 'ORCHESTRATION_GRAPH_CREATED' }>>('ORCHESTRATION_GRAPH_CREATED', ({ payload }) => {
196
- fireHook(fireOptions, 'Lifecycle:orchestration:graph-created', 'Lifecycle', 'orchestration', 'graph-created', {
197
- graphId: payload.graphId,
198
- title: payload.title,
199
- mode: payload.mode,
200
- });
201
- }));
202
- unsubs.push(runtimeBus.on<Extract<import('@pellux/goodvibes-sdk/platform/runtime/events/orchestration').OrchestrationEvent, { type: 'ORCHESTRATION_NODE_STARTED' }>>('ORCHESTRATION_NODE_STARTED', ({ payload }) => {
203
- fireHook(fireOptions, 'Lifecycle:orchestration:node-started', 'Lifecycle', 'orchestration', 'node-started', {
204
- graphId: payload.graphId,
205
- nodeId: payload.nodeId,
206
- ...(payload.taskId !== undefined ? { taskId: payload.taskId } : {}),
207
- ...(payload.agentId !== undefined ? { agentId: payload.agentId } : {}),
208
- });
209
- }));
210
- unsubs.push(runtimeBus.on<Extract<import('@pellux/goodvibes-sdk/platform/runtime/events/orchestration').OrchestrationEvent, { type: 'ORCHESTRATION_NODE_COMPLETED' }>>('ORCHESTRATION_NODE_COMPLETED', ({ payload }) => {
211
- fireHook(fireOptions, 'Lifecycle:orchestration:node-completed', 'Lifecycle', 'orchestration', 'node-completed', {
212
- graphId: payload.graphId,
213
- nodeId: payload.nodeId,
214
- ...(payload.summary !== undefined ? { summary: payload.summary } : {}),
215
- });
216
- }));
217
- unsubs.push(runtimeBus.on<Extract<import('@pellux/goodvibes-sdk/platform/runtime/events/orchestration').OrchestrationEvent, { type: 'ORCHESTRATION_NODE_FAILED' }>>('ORCHESTRATION_NODE_FAILED', ({ payload }) => {
218
- fireHook(fireOptions, 'Lifecycle:orchestration:node-failed', 'Lifecycle', 'orchestration', 'node-failed', {
219
- graphId: payload.graphId,
220
- nodeId: payload.nodeId,
221
- error: payload.error,
222
- });
223
- }));
224
- unsubs.push(runtimeBus.on<Extract<import('@pellux/goodvibes-sdk/platform/runtime/events/orchestration').OrchestrationEvent, { type: 'ORCHESTRATION_RECURSION_GUARD_TRIGGERED' }>>('ORCHESTRATION_RECURSION_GUARD_TRIGGERED', ({ payload }) => {
225
- fireHook(fireOptions, 'Change:orchestration:recursion-guard', 'Change', 'orchestration', 'recursion-guard', {
226
- graphId: payload.graphId,
227
- ...(payload.nodeId !== undefined ? { nodeId: payload.nodeId } : {}),
228
- depth: payload.depth,
229
- activeAgents: payload.activeAgents,
230
- reason: payload.reason,
231
- });
232
- }));
233
- unsubs.push(runtimeBus.on<Extract<import('@pellux/goodvibes-sdk/platform/runtime/events/communication').CommunicationEvent, { type: 'COMMUNICATION_SENT' }>>('COMMUNICATION_SENT', ({ payload }) => {
234
- fireHook(fireOptions, 'Lifecycle:communication:sent', 'Lifecycle', 'communication', 'sent', {
235
- messageId: payload.messageId,
236
- fromId: payload.fromId,
237
- toId: payload.toId,
238
- scope: payload.scope,
239
- kind: payload.kind,
240
- ...(payload.fromRole !== undefined ? { fromRole: payload.fromRole } : {}),
241
- ...(payload.toRole !== undefined ? { toRole: payload.toRole } : {}),
242
- });
243
- }));
244
- unsubs.push(runtimeBus.on<Extract<import('@pellux/goodvibes-sdk/platform/runtime/events/communication').CommunicationEvent, { type: 'COMMUNICATION_DELIVERED' }>>('COMMUNICATION_DELIVERED', ({ payload }) => {
245
- fireHook(fireOptions, 'Lifecycle:communication:delivered', 'Lifecycle', 'communication', 'delivered', {
246
- messageId: payload.messageId,
247
- fromId: payload.fromId,
248
- toId: payload.toId,
249
- scope: payload.scope,
250
- kind: payload.kind,
251
- });
252
- }));
253
- unsubs.push(runtimeBus.on<Extract<import('@pellux/goodvibes-sdk/platform/runtime/events/communication').CommunicationEvent, { type: 'COMMUNICATION_BLOCKED' }>>('COMMUNICATION_BLOCKED', ({ payload }) => {
254
- fireHook(fireOptions, 'Change:communication:blocked', 'Change', 'communication', 'blocked', {
255
- messageId: payload.messageId,
256
- fromId: payload.fromId,
257
- toId: payload.toId,
258
- scope: payload.scope,
259
- kind: payload.kind,
260
- reason: payload.reason,
261
- ...(payload.fromRole !== undefined ? { fromRole: payload.fromRole } : {}),
262
- ...(payload.toRole !== undefined ? { toRole: payload.toRole } : {}),
263
- });
264
- }));
265
- unsubs.push(runtimeBus.on<Extract<OpsEvent, { type: 'OPS_CONTEXT_WARNING' }>>('OPS_CONTEXT_WARNING', ({ payload: { usage, threshold } }) => {
266
- const specific = usage >= threshold ? 'exceeded' : 'warning';
267
- fireHook(fireOptions, `Change:budget:${specific}` as HookEventPath, 'Change', 'budget', specific, { usage, threshold });
268
- }));
269
-
270
- return unsubs;
271
- }
@@ -2,9 +2,9 @@ import type { ConversationManager } from '../core/conversation';
2
2
  import type { Orchestrator } from '../core/orchestrator';
3
3
  import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config/manager';
4
4
  import type { RuntimeEventBus } from '@pellux/goodvibes-sdk/platform/runtime/events/index';
5
+ import type { MutableRuntimeState } from '@pellux/goodvibes-sdk/platform/runtime/mutable-runtime-state';
5
6
  import type { RuntimeStore } from './store/index.ts';
6
7
  import type { RuntimeServices } from './services.ts';
7
- import type { MutableRuntimeState } from './context.ts';
8
8
  import type { CommandContext } from '../input/command-registry.ts';
9
9
  import type { OpsControlPlane } from '@pellux/goodvibes-sdk/platform/runtime/ops/control-plane';
10
10
  import { CommandRegistry } from '../input/command-registry.ts';
@@ -86,7 +86,7 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
86
86
  completeModelSelectionSideEffect,
87
87
  } = options;
88
88
 
89
- const systemMessagesPanel = new SystemMessagesPanel(configManager, services.panelHealthMonitor);
89
+ const systemMessagesPanel = new SystemMessagesPanel(configManager, services.componentHealthMonitor);
90
90
  const resumeSession = createResumeSessionHandler({
91
91
  runtimeBus,
92
92
  runtime,
@@ -119,7 +119,7 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
119
119
  automationManager: services.automationManager,
120
120
  getControlPlaneRecentEvents,
121
121
  tokenAuditor: services.tokenAuditor,
122
- panelHealthMonitor: services.panelHealthMonitor,
122
+ componentHealthMonitor: services.componentHealthMonitor,
123
123
  worktreeRegistry: services.worktreeRegistry,
124
124
  sandboxSessionRegistry: services.sandboxSessionRegistry,
125
125
  systemMessagesPanel,
@@ -224,7 +224,6 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
224
224
  opsApi,
225
225
  directTransport,
226
226
  panelManager: services.panelManager,
227
- panelHealthMonitor: services.panelHealthMonitor,
228
227
  worktreeRegistry: services.worktreeRegistry,
229
228
  sandboxSessionRegistry: services.sandboxSessionRegistry,
230
229
  loadSystemPrompt: () => loadBootstrapSystemPrompt(configManager),
@@ -236,6 +235,7 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
236
235
  }, 50);
237
236
  },
238
237
  completeModelSelectionSideEffect,
238
+ componentHealthMonitor: services.componentHealthMonitor,
239
239
  });
240
240
 
241
241
  const gitStatusProvider = new GitStatusProvider(services.workingDirectory);
@@ -407,7 +407,7 @@ export async function bootstrapRuntime(
407
407
  permissions: permissionManager,
408
408
  toolRegistry,
409
409
  providerRegistry,
410
- panelHealthMonitor: services.panelHealthMonitor,
410
+ componentHealthMonitor: services.componentHealthMonitor,
411
411
  worktreeRegistry: services.worktreeRegistry,
412
412
  sandboxSessionRegistry: services.sandboxSessionRegistry,
413
413
  hookDispatcher,
@@ -16,29 +16,13 @@ import type { ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers/
16
16
  import type { RuntimeStore } from './store/index.ts';
17
17
  import type { RuntimeEventBus } from '@pellux/goodvibes-sdk/platform/runtime/events/index';
18
18
  import type { FeatureFlagManager } from '@pellux/goodvibes-sdk/platform/runtime/feature-flags/index';
19
+ import type { MutableRuntimeState } from '@pellux/goodvibes-sdk/platform/runtime/mutable-runtime-state';
19
20
  import type { SessionSnapshot } from '@pellux/goodvibes-sdk/platform/runtime/session-persistence';
20
21
  import type { RuntimeServices } from './services.ts';
21
- import type { PanelHealthMonitor } from '@pellux/goodvibes-sdk/platform/runtime/perf/panel-health-monitor';
22
+ import type { ComponentHealthMonitor } from './perf/panel-health-monitor.ts';
22
23
  import type { WorktreeRegistry } from '@pellux/goodvibes-sdk/platform/runtime/worktree/registry';
23
24
  import type { SandboxSessionRegistry } from '@pellux/goodvibes-sdk/platform/runtime/sandbox/session-registry';
24
25
 
25
- /**
26
- * Mutable runtime state that may be changed by slash commands or model-picker events.
27
- * Kept as a plain object so event handlers can close over it by reference.
28
- *
29
- * Named `MutableRuntimeState` to avoid a name collision with `RuntimeState` in
30
- * `src/runtime/store/state.ts`.
31
- */
32
- export interface MutableRuntimeState {
33
- model: string;
34
- provider: string;
35
- debugMode: boolean;
36
- systemPrompt: string;
37
- /** Empty string if not configured. */
38
- reasoningEffort: string;
39
- sessionId: string;
40
- }
41
-
42
26
  /**
43
27
  * Options accepted by bootstrapRuntime().
44
28
  */
@@ -103,8 +87,8 @@ export interface RuntimeContext {
103
87
  /** Shared provider registry owned by the runtime services graph. */
104
88
  providerRegistry: ProviderRegistry;
105
89
 
106
- /** Shared panel-health monitor owned by the runtime services graph. */
107
- panelHealthMonitor: PanelHealthMonitor;
90
+ /** Shared component-health monitor owned by the runtime services graph. */
91
+ componentHealthMonitor: ComponentHealthMonitor;
108
92
 
109
93
  /** Shared worktree registry owned by the runtime services graph. */
110
94
  worktreeRegistry: WorktreeRegistry;
@@ -19,6 +19,6 @@ export { TransportPanel } from '@pellux/goodvibes-sdk/platform/runtime/diagnosti
19
19
  export type { TransportPanelSnapshot } from '@pellux/goodvibes-sdk/platform/runtime/diagnostics/panels/transport';
20
20
  export { OpsPanel } from './ops.ts';
21
21
  export type { OpsAuditEntry } from './ops.ts';
22
- export { PanelResourcesPanel } from '@pellux/goodvibes-sdk/platform/runtime/diagnostics/panels/panel-resources';
22
+ export { PanelResourcesPanel } from './panel-resources.ts';
23
23
  export { SecurityPanel } from '@pellux/goodvibes-sdk/platform/runtime/diagnostics/panels/security';
24
24
  export type { SecurityPanelSnapshot } from '@pellux/goodvibes-sdk/platform/runtime/diagnostics/panels/security';
@@ -13,7 +13,7 @@ import type { PanelConfig } from '@pellux/goodvibes-sdk/platform/runtime/diagnos
13
13
  import { DEFAULT_PANEL_CONFIG, appendBounded, applyFilter } from '@pellux/goodvibes-sdk/platform/runtime/diagnostics/types';
14
14
  import type { DiagnosticFilter } from '@pellux/goodvibes-sdk/platform/runtime/diagnostics/types';
15
15
  import type { OpsInterventionReason, OpsEvent } from '@pellux/goodvibes-sdk/platform/runtime/events/ops';
16
- import type { UiEventFeed } from '@pellux/goodvibes-sdk/platform/runtime/ui-events';
16
+ import type { UiEventFeed } from '../../ui-events.ts';
17
17
 
18
18
  // ---------------------------------------------------------------------------
19
19
  // Audit entry
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Panel resource diagnostics panel data provider.
3
+ *
4
+ * Polls the shared TUI-owned ComponentHealthMonitor and produces PanelResourceSnapshot
5
+ * values for the diagnostics panel to render.
6
+ */
7
+ import type { ComponentHealthMonitor } from '../../perf/panel-health-monitor.ts';
8
+ import type {
9
+ ComponentResourceEntry,
10
+ ComponentResourceSnapshot,
11
+ } from '@pellux/goodvibes-sdk/platform/runtime/diagnostics/types';
12
+
13
+ const DEFAULT_POLL_INTERVAL_MS = 500;
14
+
15
+ const HEALTH_ORDER: Record<string, number> = {
16
+ overloaded: 0,
17
+ warning: 1,
18
+ healthy: 2,
19
+ };
20
+
21
+ export class PanelResourcesPanel {
22
+ private readonly _pollIntervalMs: number;
23
+ private readonly _monitor: ComponentHealthMonitor;
24
+ private _current: ComponentResourceSnapshot;
25
+ private _timerId: ReturnType<typeof setInterval> | null = null;
26
+ private readonly _subscribers = new Set<() => void>();
27
+
28
+ constructor(monitor: ComponentHealthMonitor, pollIntervalMs: number = DEFAULT_POLL_INTERVAL_MS) {
29
+ this._monitor = monitor;
30
+ this._pollIntervalMs = pollIntervalMs;
31
+ this._current = this._buildSnapshot(Date.now());
32
+ }
33
+
34
+ start(): void {
35
+ if (this._timerId !== null) return;
36
+ this._timerId = setInterval(() => {
37
+ this._current = this._buildSnapshot(Date.now());
38
+ this._notify();
39
+ }, this._pollIntervalMs);
40
+ }
41
+
42
+ stop(): void {
43
+ if (this._timerId !== null) {
44
+ clearInterval(this._timerId);
45
+ this._timerId = null;
46
+ }
47
+ }
48
+
49
+ getSnapshot(): ComponentResourceSnapshot {
50
+ return this._current;
51
+ }
52
+
53
+ refresh(now: number = Date.now()): ComponentResourceSnapshot {
54
+ this._current = this._buildSnapshot(now);
55
+ return this._current;
56
+ }
57
+
58
+ subscribe(callback: () => void): () => void {
59
+ this._subscribers.add(callback);
60
+ return () => this._subscribers.delete(callback);
61
+ }
62
+
63
+ dispose(): void {
64
+ this.stop();
65
+ this._subscribers.clear();
66
+ }
67
+
68
+ private _buildSnapshot(capturedAt: number): ComponentResourceSnapshot {
69
+ const healthStates = this._monitor.getAllHealth();
70
+
71
+ const panels: ComponentResourceEntry[] = healthStates.map((health) => {
72
+ const contract = this._monitor.getContract(health.componentId);
73
+ return {
74
+ componentId: health.componentId,
75
+ throttleStatus: health.throttleStatus,
76
+ healthStatus: health.healthStatus,
77
+ renderP95Ms: health.renderP95Ms,
78
+ maxRenderMs: contract?.maxRenderMs ?? 0,
79
+ rendersInWindow: health.rendersInWindow,
80
+ maxUpdatesPerSecond: contract?.maxUpdatesPerSecond ?? 0,
81
+ consecutiveViolations: health.consecutiveViolations,
82
+ totalSuppressed: health.totalSuppressed,
83
+ totalPermitted: health.totalPermitted,
84
+ lastRenderAt: health.lastRenderAt,
85
+ nextAllowedAt: health.nextAllowedAt,
86
+ };
87
+ });
88
+
89
+ panels.sort((left, right) => {
90
+ const diff = (HEALTH_ORDER[left.healthStatus] ?? 2) - (HEALTH_ORDER[right.healthStatus] ?? 2);
91
+ return diff !== 0 ? diff : left.componentId.localeCompare(right.componentId);
92
+ });
93
+
94
+ const overloadedCount = panels.filter((panel) => panel.healthStatus === 'overloaded').length;
95
+ const warningCount = panels.filter((panel) => panel.healthStatus === 'warning').length;
96
+ const healthyCount = panels.filter((panel) => panel.healthStatus === 'healthy').length;
97
+ const totalSuppressed = panels.reduce((sum, panel) => sum + panel.totalSuppressed, 0);
98
+
99
+ return {
100
+ panels,
101
+ overloadedCount,
102
+ warningCount,
103
+ healthyCount,
104
+ totalSuppressed,
105
+ capturedAt,
106
+ };
107
+ }
108
+
109
+ private _notify(): void {
110
+ for (const callback of this._subscribers) {
111
+ try {
112
+ callback();
113
+ } catch {
114
+ // Subscriber failures must not take down diagnostics polling.
115
+ }
116
+ }
117
+ }
118
+ }