4runr-os 1.0.23 → 1.0.36

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 (235) hide show
  1. package/dist/collectors/collector_assets.d.ts +19 -0
  2. package/dist/collectors/collector_assets.d.ts.map +1 -0
  3. package/dist/collectors/collector_assets.js +72 -0
  4. package/dist/collectors/collector_assets.js.map +1 -0
  5. package/dist/collectors/collector_capabilities.d.ts +19 -0
  6. package/dist/collectors/collector_capabilities.d.ts.map +1 -0
  7. package/dist/collectors/collector_capabilities.js +61 -0
  8. package/dist/collectors/collector_capabilities.js.map +1 -0
  9. package/dist/collectors/collector_feed.d.ts +30 -0
  10. package/dist/collectors/collector_feed.d.ts.map +1 -0
  11. package/dist/collectors/collector_feed.js +78 -0
  12. package/dist/collectors/collector_feed.js.map +1 -0
  13. package/dist/collectors/collector_geo.d.ts +12 -0
  14. package/dist/collectors/collector_geo.d.ts.map +1 -0
  15. package/dist/collectors/collector_geo.js +248 -0
  16. package/dist/collectors/collector_geo.js.map +1 -0
  17. package/dist/collectors/collector_network.d.ts +22 -0
  18. package/dist/collectors/collector_network.d.ts.map +1 -0
  19. package/dist/collectors/collector_network.js +83 -0
  20. package/dist/collectors/collector_network.js.map +1 -0
  21. package/dist/collectors/collector_posture.d.ts +25 -0
  22. package/dist/collectors/collector_posture.d.ts.map +1 -0
  23. package/dist/collectors/collector_posture.js +207 -0
  24. package/dist/collectors/collector_posture.js.map +1 -0
  25. package/dist/collectors/collector_resources.d.ts +21 -0
  26. package/dist/collectors/collector_resources.d.ts.map +1 -0
  27. package/dist/collectors/collector_resources.js +87 -0
  28. package/dist/collectors/collector_resources.js.map +1 -0
  29. package/dist/collectors/helpers.d.ts +21 -0
  30. package/dist/collectors/helpers.d.ts.map +1 -0
  31. package/dist/collectors/helpers.js +49 -0
  32. package/dist/collectors/helpers.js.map +1 -0
  33. package/dist/core/collectorRegistry.d.ts +43 -0
  34. package/dist/core/collectorRegistry.d.ts.map +1 -0
  35. package/dist/core/collectorRegistry.js +76 -0
  36. package/dist/core/collectorRegistry.js.map +1 -0
  37. package/dist/core/constants.d.ts +25 -0
  38. package/dist/core/constants.d.ts.map +1 -0
  39. package/dist/core/constants.js +33 -0
  40. package/dist/core/constants.js.map +1 -0
  41. package/dist/core/eventBus.d.ts +36 -0
  42. package/dist/core/eventBus.d.ts.map +1 -0
  43. package/dist/core/eventBus.js +52 -0
  44. package/dist/core/eventBus.js.map +1 -0
  45. package/dist/core/types.d.ts +128 -0
  46. package/dist/core/types.d.ts.map +1 -0
  47. package/dist/core/types.js +6 -0
  48. package/dist/core/types.js.map +1 -0
  49. package/dist/events.d.ts +35 -0
  50. package/dist/events.d.ts.map +1 -0
  51. package/dist/events.js +89 -0
  52. package/dist/events.js.map +1 -0
  53. package/dist/index.js +301 -36
  54. package/dist/index.js.map +1 -1
  55. package/dist/models.d.ts +74 -0
  56. package/dist/models.d.ts.map +1 -0
  57. package/dist/models.js +7 -0
  58. package/dist/models.js.map +1 -0
  59. package/dist/state/getCollectorResults.d.ts +18 -0
  60. package/dist/state/getCollectorResults.d.ts.map +1 -0
  61. package/dist/state/getCollectorResults.js +25 -0
  62. package/dist/state/getCollectorResults.js.map +1 -0
  63. package/dist/state/historyStore.d.ts +35 -0
  64. package/dist/state/historyStore.d.ts.map +1 -0
  65. package/dist/state/historyStore.js +58 -0
  66. package/dist/state/historyStore.js.map +1 -0
  67. package/dist/state/uiStateBuilder.d.ts +12 -0
  68. package/dist/state/uiStateBuilder.d.ts.map +1 -0
  69. package/dist/state/uiStateBuilder.js +169 -0
  70. package/dist/state/uiStateBuilder.js.map +1 -0
  71. package/dist/state/uiStateScheduler.d.ts +43 -0
  72. package/dist/state/uiStateScheduler.d.ts.map +1 -0
  73. package/dist/state/uiStateScheduler.js +118 -0
  74. package/dist/state/uiStateScheduler.js.map +1 -0
  75. package/dist/store.d.ts +3 -1
  76. package/dist/store.d.ts.map +1 -1
  77. package/dist/store.js +2 -0
  78. package/dist/store.js.map +1 -1
  79. package/dist/system-state.d.ts +96 -0
  80. package/dist/system-state.d.ts.map +1 -0
  81. package/dist/system-state.js +273 -0
  82. package/dist/system-state.js.map +1 -0
  83. package/dist/ui/boot/sequence.d.ts +10 -0
  84. package/dist/ui/boot/sequence.d.ts.map +1 -0
  85. package/dist/ui/boot/sequence.js +173 -0
  86. package/dist/ui/boot/sequence.js.map +1 -0
  87. package/dist/ui/constraints/layoutSpec.d.ts +47 -0
  88. package/dist/ui/constraints/layoutSpec.d.ts.map +1 -0
  89. package/dist/ui/constraints/layoutSpec.js +60 -0
  90. package/dist/ui/constraints/layoutSpec.js.map +1 -0
  91. package/dist/ui/constraints/unknownHandling.d.ts +29 -0
  92. package/dist/ui/constraints/unknownHandling.d.ts.map +1 -0
  93. package/dist/ui/constraints/unknownHandling.js +60 -0
  94. package/dist/ui/constraints/unknownHandling.js.map +1 -0
  95. package/dist/ui/drilldowns/feed.d.ts +11 -0
  96. package/dist/ui/drilldowns/feed.d.ts.map +1 -0
  97. package/dist/ui/drilldowns/feed.js +68 -0
  98. package/dist/ui/drilldowns/feed.js.map +1 -0
  99. package/dist/ui/drilldowns/index.d.ts +7 -0
  100. package/dist/ui/drilldowns/index.d.ts.map +1 -0
  101. package/dist/ui/drilldowns/index.js +8 -0
  102. package/dist/ui/drilldowns/index.js.map +1 -0
  103. package/dist/ui/drilldowns/posture.d.ts +11 -0
  104. package/dist/ui/drilldowns/posture.d.ts.map +1 -0
  105. package/dist/ui/drilldowns/posture.js +74 -0
  106. package/dist/ui/drilldowns/posture.js.map +1 -0
  107. package/dist/ui/intelligence-posture-view.d.ts +22 -0
  108. package/dist/ui/intelligence-posture-view.d.ts.map +1 -0
  109. package/dist/ui/intelligence-posture-view.js +169 -0
  110. package/dist/ui/intelligence-posture-view.js.map +1 -0
  111. package/dist/ui/navigation/keymaps.d.ts +26 -0
  112. package/dist/ui/navigation/keymaps.d.ts.map +1 -0
  113. package/dist/ui/navigation/keymaps.js +135 -0
  114. package/dist/ui/navigation/keymaps.js.map +1 -0
  115. package/dist/ui/navigation/palette.d.ts +10 -0
  116. package/dist/ui/navigation/palette.d.ts.map +1 -0
  117. package/dist/ui/navigation/palette.js +133 -0
  118. package/dist/ui/navigation/palette.js.map +1 -0
  119. package/dist/ui/navigation/state.d.ts +47 -0
  120. package/dist/ui/navigation/state.d.ts.map +1 -0
  121. package/dist/ui/navigation/state.js +84 -0
  122. package/dist/ui/navigation/state.js.map +1 -0
  123. package/dist/ui/navigation/types.d.ts +38 -0
  124. package/dist/ui/navigation/types.d.ts.map +1 -0
  125. package/dist/ui/navigation/types.js +36 -0
  126. package/dist/ui/navigation/types.js.map +1 -0
  127. package/dist/ui/panels/active-assets.d.ts +12 -0
  128. package/dist/ui/panels/active-assets.d.ts.map +1 -0
  129. package/dist/ui/panels/active-assets.js +83 -0
  130. package/dist/ui/panels/active-assets.js.map +1 -0
  131. package/dist/ui/panels/capability-flags.d.ts +12 -0
  132. package/dist/ui/panels/capability-flags.d.ts.map +1 -0
  133. package/dist/ui/panels/capability-flags.js +59 -0
  134. package/dist/ui/panels/capability-flags.js.map +1 -0
  135. package/dist/ui/panels/command-surface.d.ts +12 -0
  136. package/dist/ui/panels/command-surface.d.ts.map +1 -0
  137. package/dist/ui/panels/command-surface.js +55 -0
  138. package/dist/ui/panels/command-surface.js.map +1 -0
  139. package/dist/ui/panels/network-origin.d.ts +12 -0
  140. package/dist/ui/panels/network-origin.d.ts.map +1 -0
  141. package/dist/ui/panels/network-origin.js +79 -0
  142. package/dist/ui/panels/network-origin.js.map +1 -0
  143. package/dist/ui/panels/operations-feed.d.ts +12 -0
  144. package/dist/ui/panels/operations-feed.d.ts.map +1 -0
  145. package/dist/ui/panels/operations-feed.js +90 -0
  146. package/dist/ui/panels/operations-feed.js.map +1 -0
  147. package/dist/ui/panels/posture.d.ts +12 -0
  148. package/dist/ui/panels/posture.d.ts.map +1 -0
  149. package/dist/ui/panels/posture.js +84 -0
  150. package/dist/ui/panels/posture.js.map +1 -0
  151. package/dist/ui/panels/resources.d.ts +11 -0
  152. package/dist/ui/panels/resources.d.ts.map +1 -0
  153. package/dist/ui/panels/resources.js +88 -0
  154. package/dist/ui/panels/resources.js.map +1 -0
  155. package/dist/ui/primitives/Panel.d.ts +25 -0
  156. package/dist/ui/primitives/Panel.d.ts.map +1 -0
  157. package/dist/ui/primitives/Panel.js +59 -0
  158. package/dist/ui/primitives/Panel.js.map +1 -0
  159. package/dist/ui/rendering/metricRenderer.d.ts +24 -0
  160. package/dist/ui/rendering/metricRenderer.d.ts.map +1 -0
  161. package/dist/ui/rendering/metricRenderer.js +86 -0
  162. package/dist/ui/rendering/metricRenderer.js.map +1 -0
  163. package/dist/ui/runtime/hub.d.ts +12 -0
  164. package/dist/ui/runtime/hub.d.ts.map +1 -0
  165. package/dist/ui/runtime/hub.js +468 -0
  166. package/dist/ui/runtime/hub.js.map +1 -0
  167. package/dist/ui/runtime/hubValidation.d.ts +23 -0
  168. package/dist/ui/runtime/hubValidation.d.ts.map +1 -0
  169. package/dist/ui/runtime/hubValidation.js +90 -0
  170. package/dist/ui/runtime/hubValidation.js.map +1 -0
  171. package/dist/ui/runtime/index.d.ts +29 -0
  172. package/dist/ui/runtime/index.d.ts.map +1 -0
  173. package/dist/ui/runtime/index.js +299 -0
  174. package/dist/ui/runtime/index.js.map +1 -0
  175. package/dist/ui/runtime/no-tui.d.ts +12 -0
  176. package/dist/ui/runtime/no-tui.d.ts.map +1 -0
  177. package/dist/ui/runtime/no-tui.js +77 -0
  178. package/dist/ui/runtime/no-tui.js.map +1 -0
  179. package/dist/ui/runtime/state-builder.d.ts +13 -0
  180. package/dist/ui/runtime/state-builder.d.ts.map +1 -0
  181. package/dist/ui/runtime/state-builder.js +114 -0
  182. package/dist/ui/runtime/state-builder.js.map +1 -0
  183. package/dist/ui/runtime/terminalSizeCheck.d.ts +10 -0
  184. package/dist/ui/runtime/terminalSizeCheck.d.ts.map +1 -0
  185. package/dist/ui/runtime/terminalSizeCheck.js +51 -0
  186. package/dist/ui/runtime/terminalSizeCheck.js.map +1 -0
  187. package/dist/ui/runtime/tuiLogGate.d.ts +22 -0
  188. package/dist/ui/runtime/tuiLogGate.d.ts.map +1 -0
  189. package/dist/ui/runtime/tuiLogGate.js +68 -0
  190. package/dist/ui/runtime/tuiLogGate.js.map +1 -0
  191. package/dist/ui/state/types.d.ts +72 -0
  192. package/dist/ui/state/types.d.ts.map +1 -0
  193. package/dist/ui/state/types.js +6 -0
  194. package/dist/ui/state/types.js.map +1 -0
  195. package/dist/ui/theme/borders.d.ts +20 -0
  196. package/dist/ui/theme/borders.d.ts.map +1 -0
  197. package/dist/ui/theme/borders.js +55 -0
  198. package/dist/ui/theme/borders.js.map +1 -0
  199. package/dist/ui/theme/tokens.d.ts +28 -0
  200. package/dist/ui/theme/tokens.d.ts.map +1 -0
  201. package/dist/ui/theme/tokens.js +50 -0
  202. package/dist/ui/theme/tokens.js.map +1 -0
  203. package/dist/ui/theme/typography.d.ts +14 -0
  204. package/dist/ui/theme/typography.d.ts.map +1 -0
  205. package/dist/ui/theme/typography.js +30 -0
  206. package/dist/ui/theme/typography.js.map +1 -0
  207. package/dist/ui/widgets/flagRow.d.ts +25 -0
  208. package/dist/ui/widgets/flagRow.d.ts.map +1 -0
  209. package/dist/ui/widgets/flagRow.js +57 -0
  210. package/dist/ui/widgets/flagRow.js.map +1 -0
  211. package/dist/ui/widgets/index.d.ts +9 -0
  212. package/dist/ui/widgets/index.d.ts.map +1 -0
  213. package/dist/ui/widgets/index.js +9 -0
  214. package/dist/ui/widgets/index.js.map +1 -0
  215. package/dist/ui/widgets/meter.d.ts +18 -0
  216. package/dist/ui/widgets/meter.d.ts.map +1 -0
  217. package/dist/ui/widgets/meter.js +38 -0
  218. package/dist/ui/widgets/meter.js.map +1 -0
  219. package/dist/ui/widgets/miniMap.d.ts +26 -0
  220. package/dist/ui/widgets/miniMap.d.ts.map +1 -0
  221. package/dist/ui/widgets/miniMap.js +94 -0
  222. package/dist/ui/widgets/miniMap.js.map +1 -0
  223. package/dist/ui/widgets/sparkline.d.ts +17 -0
  224. package/dist/ui/widgets/sparkline.d.ts.map +1 -0
  225. package/dist/ui/widgets/sparkline.js +63 -0
  226. package/dist/ui/widgets/sparkline.js.map +1 -0
  227. package/dist/ui-primitives.d.ts +5 -2
  228. package/dist/ui-primitives.d.ts.map +1 -1
  229. package/dist/ui-primitives.js +22 -9
  230. package/dist/ui-primitives.js.map +1 -1
  231. package/package.json +5 -4
  232. package/dist/ui/home-view.d.ts +0 -27
  233. package/dist/ui/home-view.d.ts.map +0 -1
  234. package/dist/ui/home-view.js +0 -127
  235. package/dist/ui/home-view.js.map +0 -1
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Panel Primitive
3
+ * Phase 1: Reusable panel component with consistent styling
4
+ */
5
+ import blessed from 'neo-blessed';
6
+ import { getBorderStyle } from '../theme/borders.js';
7
+ import { renderPanelTitle } from '../theme/typography.js';
8
+ // Type assertion for blessed (neo-blessed doesn't have full TypeScript support)
9
+ const blessedLib = blessed;
10
+ /**
11
+ * Create a consistent panel widget
12
+ */
13
+ export function createPanel(screen, options) {
14
+ const { title, top, left, width, height, content = [], focused = false, panelId, severity = 'NEUTRAL', } = options;
15
+ // Get border style (Phase 7: glow system)
16
+ const borderStyle = getBorderStyle(panelId || 'POSTURE', focused, severity);
17
+ // Render title with typography standard
18
+ const titleText = renderPanelTitle(title, focused);
19
+ const panel = blessedLib.box({
20
+ top,
21
+ left,
22
+ width,
23
+ height,
24
+ border: {
25
+ type: borderStyle.borderType,
26
+ },
27
+ style: {
28
+ border: {
29
+ fg: borderStyle.borderColor,
30
+ },
31
+ },
32
+ tags: true,
33
+ });
34
+ // Title area (top border label)
35
+ const titleBox = blessedLib.box({
36
+ top: 0,
37
+ left: 1,
38
+ width: title.length + 4, // Account for padding
39
+ height: 1,
40
+ content: titleText,
41
+ tags: true,
42
+ });
43
+ panel.append(titleBox);
44
+ // Content area
45
+ if (content.length > 0) {
46
+ const contentText = content.slice(0, height - 2).join('\n');
47
+ const contentBox = blessedLib.box({
48
+ top: 1,
49
+ left: 1,
50
+ width: width - 2,
51
+ height: height - 2,
52
+ content: contentText,
53
+ tags: true,
54
+ });
55
+ panel.append(contentBox);
56
+ }
57
+ return panel;
58
+ }
59
+ //# sourceMappingURL=Panel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Panel.js","sourceRoot":"","sources":["../../../src/ui/primitives/Panel.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,OAAO,MAAM,aAAa,CAAC;AAGlC,OAAO,EAAE,cAAc,EAAoB,MAAM,qBAAqB,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAG1D,gFAAgF;AAChF,MAAM,UAAU,GAAQ,OAAO,CAAC;AAiBhC;;GAEG;AACH,MAAM,UAAU,WAAW,CACzB,MAAsB,EACtB,OAAqB;IAErB,MAAM,EACJ,KAAK,EACL,GAAG,EACH,IAAI,EACJ,KAAK,EACL,MAAM,EACN,OAAO,GAAG,EAAE,EACZ,OAAO,GAAG,KAAK,EACf,OAAO,EACP,QAAQ,GAAG,SAAS,GACrB,GAAG,OAAO,CAAC;IAEZ,0CAA0C;IAC1C,MAAM,WAAW,GAAG,cAAc,CAChC,OAAO,IAAI,SAAS,EACpB,OAAO,EACP,QAAQ,CACT,CAAC;IAEF,wCAAwC;IACxC,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAEnD,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC;QAC3B,GAAG;QACH,IAAI;QACJ,KAAK;QACL,MAAM;QACN,MAAM,EAAE;YACN,IAAI,EAAE,WAAW,CAAC,UAAU;SAC7B;QACD,KAAK,EAAE;YACL,MAAM,EAAE;gBACN,EAAE,EAAE,WAAW,CAAC,WAAW;aAC5B;SACF;QACD,IAAI,EAAE,IAAI;KACX,CAAC,CAAC;IAEH,gCAAgC;IAChC,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC;QAC9B,GAAG,EAAE,CAAC;QACN,IAAI,EAAE,CAAC;QACP,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,sBAAsB;QAC/C,MAAM,EAAE,CAAC;QACT,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,IAAI;KACX,CAAC,CAAC;IAEH,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAEvB,eAAe;IACf,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5D,MAAM,UAAU,GAAG,UAAU,CAAC,GAAG,CAAC;YAChC,GAAG,EAAE,CAAC;YACN,IAAI,EAAE,CAAC;YACP,KAAK,EAAE,KAAK,GAAG,CAAC;YAChB,MAAM,EAAE,MAAM,GAAG,CAAC;YAClB,OAAO,EAAE,WAAW;YACpB,IAAI,EAAE,IAAI;SACX,CAAC,CAAC;QACH,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC3B,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Metric Renderer
3
+ * Phase 9: UI rendering guardrail - no raw values
4
+ */
5
+ import type { CollectorResult } from '../../core/types.js';
6
+ /**
7
+ * Render a metric with status awareness
8
+ *
9
+ * Behavior:
10
+ * - LIVE → show value
11
+ * - STALE → show value + STALE (Xm)
12
+ * - UNAVAILABLE → show UNAVAILABLE + message + action
13
+ * - DISABLED → show DISABLED + action
14
+ */
15
+ export declare function renderMetric(label: string, collectorResult: CollectorResult<any>, valuePath: string | ((data: any) => string), options?: {
16
+ labelWidth?: number;
17
+ valueColor?: string;
18
+ formatValue?: (value: any) => string;
19
+ }): string;
20
+ /**
21
+ * Helper to format timestamp as relative time
22
+ */
23
+ export declare function formatRelativeTime(ts: number): string;
24
+ //# sourceMappingURL=metricRenderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metricRenderer.d.ts","sourceRoot":"","sources":["../../../src/ui/rendering/metricRenderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAmB,MAAM,qBAAqB,CAAC;AAI5E;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,eAAe,EAAE,eAAe,CAAC,GAAG,CAAC,EACrC,SAAS,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,KAAK,MAAM,CAAC,EAC3C,OAAO,GAAE;IACP,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,MAAM,CAAC;CACjC,GACL,MAAM,CAiDR;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAerD"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Metric Renderer
3
+ * Phase 9: UI rendering guardrail - no raw values
4
+ */
5
+ import { getBlessedColor } from '../theme/tokens.js';
6
+ import { formatValue } from '../constraints/unknownHandling.js';
7
+ /**
8
+ * Render a metric with status awareness
9
+ *
10
+ * Behavior:
11
+ * - LIVE → show value
12
+ * - STALE → show value + STALE (Xm)
13
+ * - UNAVAILABLE → show UNAVAILABLE + message + action
14
+ * - DISABLED → show DISABLED + action
15
+ */
16
+ export function renderMetric(label, collectorResult, valuePath, options = {}) {
17
+ const { labelWidth = 12, valueColor, formatValue: customFormatter } = options;
18
+ const status = collectorResult.status;
19
+ const data = collectorResult.data;
20
+ // Extract value from data
21
+ let value;
22
+ if (typeof valuePath === 'function') {
23
+ value = data ? valuePath(data) : undefined;
24
+ }
25
+ else {
26
+ // Simple path access (e.g., "cpuPercent")
27
+ value = data ? data[valuePath] : undefined;
28
+ }
29
+ // Format value
30
+ const formatter = customFormatter || ((v) => formatValue(v));
31
+ const formattedValue = value !== undefined ? formatter(value) : undefined;
32
+ // Build output based on status
33
+ let output;
34
+ let statusColor = getBlessedColor('mutedGrey');
35
+ if (status === 'LIVE') {
36
+ // LIVE → show value
37
+ const displayValue = formattedValue || 'UNKNOWN';
38
+ const color = valueColor || getBlessedColor('accentCyan');
39
+ output = `${label.padEnd(labelWidth)}: {${color}-fg}${displayValue}{/}`;
40
+ }
41
+ else if (status === 'STALE') {
42
+ // STALE → show value + STALE (Xm)
43
+ const ageMinutes = Math.floor((Date.now() - collectorResult.asOf) / 60000);
44
+ const displayValue = formattedValue || 'UNKNOWN';
45
+ const color = valueColor || getBlessedColor('warnAmber');
46
+ output = `${label.padEnd(labelWidth)}: {${color}-fg}${displayValue}{/} {${getBlessedColor('warnAmber')}-fg}STALE (${ageMinutes}m){/}`;
47
+ }
48
+ else if (status === 'UNAVAILABLE') {
49
+ // UNAVAILABLE → show UNAVAILABLE + message + action
50
+ const reason = collectorResult.message || collectorResult.reasonCode || 'Unknown reason';
51
+ const action = collectorResult.action ? ` (run: ${collectorResult.action})` : '';
52
+ output = `${label.padEnd(labelWidth)}: {${getBlessedColor('criticalRed')}-fg}UNAVAILABLE{/} — ${reason}${action}`;
53
+ }
54
+ else if (status === 'DISABLED') {
55
+ // DISABLED → show DISABLED + action
56
+ const action = collectorResult.action ? ` (run: ${collectorResult.action})` : '';
57
+ output = `${label.padEnd(labelWidth)}: {${getBlessedColor('mutedGrey')}-fg}DISABLED{/}${action}`;
58
+ }
59
+ else {
60
+ // Fallback
61
+ output = `${label.padEnd(labelWidth)}: {${getBlessedColor('mutedGrey')}-fg}UNKNOWN{/}`;
62
+ }
63
+ return output;
64
+ }
65
+ /**
66
+ * Helper to format timestamp as relative time
67
+ */
68
+ export function formatRelativeTime(ts) {
69
+ const ageMs = Date.now() - ts;
70
+ const ageMinutes = Math.floor(ageMs / 60000);
71
+ const ageHours = Math.floor(ageMinutes / 60);
72
+ const ageDays = Math.floor(ageHours / 24);
73
+ if (ageDays > 0) {
74
+ return `${ageDays}d`;
75
+ }
76
+ else if (ageHours > 0) {
77
+ return `${ageHours}h`;
78
+ }
79
+ else if (ageMinutes > 0) {
80
+ return `${ageMinutes}m`;
81
+ }
82
+ else {
83
+ return '<1m';
84
+ }
85
+ }
86
+ //# sourceMappingURL=metricRenderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metricRenderer.js","sourceRoot":"","sources":["../../../src/ui/rendering/metricRenderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAEhE;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAC1B,KAAa,EACb,eAAqC,EACrC,SAA2C,EAC3C,UAII,EAAE;IAEN,MAAM,EAAE,UAAU,GAAG,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC;IAE9E,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC;IACtC,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC;IAElC,0BAA0B;IAC1B,IAAI,KAAU,CAAC;IACf,IAAI,OAAO,SAAS,KAAK,UAAU,EAAE,CAAC;QACpC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7C,CAAC;SAAM,CAAC;QACN,0CAA0C;QAC1C,KAAK,GAAG,IAAI,CAAC,CAAC,CAAE,IAAY,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACtD,CAAC;IAED,eAAe;IACf,MAAM,SAAS,GAAG,eAAe,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAClE,MAAM,cAAc,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE1E,+BAA+B;IAC/B,IAAI,MAAc,CAAC;IACnB,IAAI,WAAW,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAE/C,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,oBAAoB;QACpB,MAAM,YAAY,GAAG,cAAc,IAAI,SAAS,CAAC;QACjD,MAAM,KAAK,GAAG,UAAU,IAAI,eAAe,CAAC,YAAY,CAAC,CAAC;QAC1D,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,KAAK,OAAO,YAAY,KAAK,CAAC;IAC1E,CAAC;SAAM,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QAC9B,kCAAkC;QAClC,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,eAAe,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;QAC3E,MAAM,YAAY,GAAG,cAAc,IAAI,SAAS,CAAC;QACjD,MAAM,KAAK,GAAG,UAAU,IAAI,eAAe,CAAC,WAAW,CAAC,CAAC;QACzD,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,KAAK,OAAO,YAAY,QAAQ,eAAe,CAAC,WAAW,CAAC,cAAc,UAAU,OAAO,CAAC;IACxI,CAAC;SAAM,IAAI,MAAM,KAAK,aAAa,EAAE,CAAC;QACpC,oDAAoD;QACpD,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,IAAI,eAAe,CAAC,UAAU,IAAI,gBAAgB,CAAC;QACzF,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACjF,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,eAAe,CAAC,aAAa,CAAC,wBAAwB,MAAM,GAAG,MAAM,EAAE,CAAC;IACpH,CAAC;SAAM,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;QACjC,oCAAoC;QACpC,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACjF,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,eAAe,CAAC,WAAW,CAAC,kBAAkB,MAAM,EAAE,CAAC;IACnG,CAAC;SAAM,CAAC;QACN,WAAW;QACX,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,eAAe,CAAC,WAAW,CAAC,gBAAgB,CAAC;IACzF,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,EAAU;IAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;IAC9B,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,EAAE,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,EAAE,CAAC,CAAC;IAE1C,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,OAAO,GAAG,OAAO,GAAG,CAAC;IACvB,CAAC;SAAM,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO,GAAG,QAAQ,GAAG,CAAC;IACxB,CAAC;SAAM,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;QAC1B,OAAO,GAAG,UAAU,GAAG,CAAC;IAC1B,CAAC;SAAM,CAAC;QACN,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Hub Grid Layout
3
+ * Phase 3: Render from UiState snapshot (no direct system calls)
4
+ */
5
+ import type { Widgets } from 'neo-blessed';
6
+ import type { UiState } from '../../core/types.js';
7
+ /**
8
+ * Render hub grid layout
9
+ * Phase 9: Validates hub snapshot before rendering
10
+ */
11
+ export declare function renderHub(screen: Widgets.Screen, uiState: UiState, focusedPanelId?: string): void;
12
+ //# sourceMappingURL=hub.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hub.d.ts","sourceRoot":"","sources":["../../../src/ui/runtime/hub.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAanD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAuEjG"}
@@ -0,0 +1,468 @@
1
+ /**
2
+ * Hub Grid Layout
3
+ * Phase 3: Render from UiState snapshot (no direct system calls)
4
+ */
5
+ import { statusToSeverity } from '../theme/borders.js';
6
+ import { LINE_BUDGETS } from '../constraints/layoutSpec.js';
7
+ import { validateHubSnapshot, renderSafeHoldScreen } from './hubValidation.js';
8
+ /**
9
+ * Render hub grid layout
10
+ * Phase 9: Validates hub snapshot before rendering
11
+ */
12
+ export function renderHub(screen, uiState, focusedPanelId) {
13
+ // Phase 9: Validate hub snapshot before rendering
14
+ const validation = validateHubSnapshot(uiState);
15
+ if (!validation.valid) {
16
+ // Show safe hold screen
17
+ const blessed = require('neo-blessed');
18
+ const blessedLib = blessed;
19
+ const { getBlessedColor } = require('../theme/tokens.js');
20
+ screen.children.forEach((child) => child.destroy());
21
+ const safeHoldBox = blessedLib.box({
22
+ top: 0,
23
+ left: 0,
24
+ width: screen.width,
25
+ height: screen.height,
26
+ border: { type: 'line' },
27
+ style: {
28
+ border: { fg: getBlessedColor('criticalRed') },
29
+ },
30
+ tags: true,
31
+ });
32
+ const content = renderSafeHoldScreen(validation.errors);
33
+ safeHoldBox.setContent(content.join('\n'));
34
+ screen.append(safeHoldBox);
35
+ screen.render();
36
+ return;
37
+ }
38
+ const screenWidth = screen.width;
39
+ const screenHeight = screen.height;
40
+ // Calculate panel dimensions
41
+ const leftWidth = Math.floor(screenWidth * 0.3);
42
+ const leftPanelHeight = Math.floor((screenHeight - 2) / 3);
43
+ const centerWidth = Math.floor(screenWidth * 0.4);
44
+ const centerHeight = screenHeight - 2;
45
+ const rightWidth = screenWidth - leftWidth - centerWidth;
46
+ const rightPanelHeight = Math.floor((screenHeight - 2) / 2);
47
+ // Get severity for posture panel
48
+ const postureSeverity = statusToSeverity(uiState.posture.posture);
49
+ // Panel 1: POSTURE (Left top)
50
+ const panel1 = renderPosturePanelFromUiState(screen, 0, 0, leftWidth, leftPanelHeight, uiState, focusedPanelId === "POSTURE", postureSeverity);
51
+ screen.append(panel1);
52
+ // Panel 2: RESOURCES (Left middle)
53
+ const panel2 = renderResourcesPanelFromUiState(screen, leftPanelHeight, 0, leftWidth, leftPanelHeight, uiState, focusedPanelId === "RESOURCES");
54
+ screen.append(panel2);
55
+ // Panel 3: ACTIVE ASSETS (Left bottom)
56
+ const panel3 = renderActiveAssetsPanelFromUiState(screen, leftPanelHeight * 2, 0, leftWidth, leftPanelHeight, uiState, focusedPanelId === "ASSETS");
57
+ screen.append(panel3);
58
+ // Panel 4: OPERATIONS FEED (Center main)
59
+ const panel4 = renderOperationsFeedPanelFromUiState(screen, 0, leftWidth, centerWidth, centerHeight, uiState, focusedPanelId === "FEED");
60
+ screen.append(panel4);
61
+ // Panel 5: GEO INTEL (Right top) - Phase 5
62
+ const panel5 = renderGeoIntelPanelFromUiState(screen, 0, leftWidth + centerWidth, rightWidth, rightPanelHeight, uiState, focusedPanelId === "NETWORK");
63
+ screen.append(panel5);
64
+ // Panel 6: CAPABILITY FLAGS (Right bottom)
65
+ const panel6 = renderCapabilityFlagsPanelFromUiState(screen, rightPanelHeight, leftWidth + centerWidth, rightWidth, rightPanelHeight, uiState, focusedPanelId === "CAPABILITIES");
66
+ screen.append(panel6);
67
+ // Panel 7: COMMAND SURFACE + STATUS STRIP (Bottom)
68
+ const panel7 = renderCommandSurfaceFromUiState(screen, screenHeight - 1, 0, screenWidth, 1, uiState);
69
+ screen.append(panel7);
70
+ }
71
+ /**
72
+ * Helper: Render posture panel from UiState
73
+ */
74
+ function renderPosturePanelFromUiState(screen, top, left, width, height, uiState, focused = false, severity = 'NEUTRAL') {
75
+ const { createPanel } = require('../primitives/Panel.js');
76
+ const { getBlessedColor } = require('../theme/tokens.js');
77
+ const { formatLabelValue } = require('../theme/typography.js');
78
+ const { formatValue } = require('../constraints/unknownHandling.js');
79
+ const { statusToSeverity: statusToSev } = require('../theme/borders.js');
80
+ const content = [];
81
+ content.push(''); // Blank line after title
82
+ // Phase 8: Enforce line budget (max 6 content lines for small panels)
83
+ const maxLines = LINE_BUDGETS.SMALL_PANEL;
84
+ const posture = formatValue(uiState.posture.posture);
85
+ const postureSeverity = statusToSev(uiState.posture.posture);
86
+ const postureColor = postureSeverity === 'OK' ? getBlessedColor('successGreen') :
87
+ postureSeverity === 'CRITICAL' ? getBlessedColor('criticalRed') :
88
+ postureSeverity === 'WARNING' ? getBlessedColor('warnAmber') : getBlessedColor('mutedGrey');
89
+ content.push(formatLabelValue('POSTURE', posture, 12, postureColor));
90
+ const risk = formatValue(uiState.posture.risk);
91
+ const riskSeverity = risk === 'LOW' ? 'OK' : risk === 'HIGH' ? 'CRITICAL' : 'WARNING';
92
+ const riskColor = riskSeverity === 'OK' ? getBlessedColor('successGreen') :
93
+ riskSeverity === 'CRITICAL' ? getBlessedColor('criticalRed') :
94
+ riskSeverity === 'WARNING' ? getBlessedColor('warnAmber') : getBlessedColor('mutedGrey');
95
+ content.push(formatLabelValue('RISK', risk, 12, riskColor));
96
+ const connected = uiState.posture.connected === true ? 'YES' :
97
+ uiState.posture.connected === false ? 'NO' : formatValue(uiState.posture.connected);
98
+ const target = uiState.posture.target !== 'UNKNOWN' ? ` (${formatValue(uiState.posture.target)})` : '';
99
+ const connectedColor = connected === 'YES' ? getBlessedColor('successGreen') : getBlessedColor('warnAmber');
100
+ content.push(formatLabelValue('CONNECTED', `${connected}${target}`, 12, connectedColor));
101
+ const lastChange = uiState.posture.lastChange !== 'UNKNOWN'
102
+ ? new Date(uiState.posture.lastChange).toLocaleTimeString()
103
+ : formatValue(uiState.posture.lastChange);
104
+ content.push(formatLabelValue('LAST CHANGE', lastChange, 12));
105
+ if (uiState.posture.cause !== 'UNKNOWN' && uiState.posture.posture !== 'OPERATIONAL') {
106
+ content.push(formatLabelValue('CAUSE', formatValue(uiState.posture.cause), 12, getBlessedColor('warnAmber')));
107
+ }
108
+ // Enforce line budget
109
+ if (content.length > maxLines + 1) { // +1 for blank line
110
+ content.splice(maxLines + 1);
111
+ }
112
+ return createPanel(screen, {
113
+ title: 'POSTURE',
114
+ top,
115
+ left,
116
+ width,
117
+ height,
118
+ content,
119
+ focused,
120
+ panelId: 'POSTURE',
121
+ severity,
122
+ });
123
+ }
124
+ /**
125
+ * Helper: Render resources panel from UiState
126
+ */
127
+ function renderResourcesPanelFromUiState(screen, top, left, width, height, uiState, focused = false) {
128
+ const { createPanel } = require('../primitives/Panel.js');
129
+ const { getBlessedColor } = require('../theme/tokens.js');
130
+ const { renderSparkline } = require('../widgets/index.js');
131
+ const content = [];
132
+ // CPU with sparkline
133
+ const cpuValue = uiState.resources.cpuPercent;
134
+ const cpuLabel = typeof cpuValue === 'number' ? `${cpuValue}%` : 'UNKNOWN';
135
+ const cpuSamples = uiState.history?.cpu || [];
136
+ const cpuSparkline = renderSparkline({
137
+ samples: cpuSamples,
138
+ min: 0,
139
+ max: 100,
140
+ width: Math.min(24, width - 15), // Leave room for label
141
+ });
142
+ content.push(`CPU: {${getBlessedColor('accentCyan')}-fg}${cpuLabel}{/} ${cpuSparkline}`);
143
+ content.push(`LOAD: ${uiState.resources.load1m}`);
144
+ // RAM with sparkline
145
+ const ramUsed = uiState.resources.ramUsedMb;
146
+ const ramTotal = uiState.resources.ramTotalMb;
147
+ let ramLabel;
148
+ let ramPercent = null;
149
+ if (typeof ramUsed === 'number' && typeof ramTotal === 'number') {
150
+ ramPercent = (ramUsed / ramTotal) * 100;
151
+ ramLabel = `${(ramUsed / 1024).toFixed(1)}/${(ramTotal / 1024).toFixed(1)}GB (${ramPercent.toFixed(0)}%)`;
152
+ }
153
+ else {
154
+ ramLabel = `${ramUsed}M / ${ramTotal}M`;
155
+ }
156
+ const ramSamples = uiState.history?.ram || [];
157
+ const ramSparkline = renderSparkline({
158
+ samples: ramSamples,
159
+ min: 0,
160
+ max: 100,
161
+ width: Math.min(24, width - 20), // Leave room for label
162
+ });
163
+ content.push(`RAM: {${getBlessedColor('accentCyan')}-fg}${ramLabel}{/} ${ramSparkline}`);
164
+ content.push(`DISK: ${uiState.resources.diskUsedGb}G / ${uiState.resources.diskTotalGb}G`);
165
+ const uptimeSec = uiState.resources.uptimeSec;
166
+ const uptime = typeof uptimeSec === 'number'
167
+ ? `${Math.floor(uptimeSec / 3600)}h ${Math.floor((uptimeSec % 3600) / 60)}m`
168
+ : 'UNKNOWN';
169
+ content.push(`UPTIME: ${uptime}`);
170
+ content.push(`PROCS: ${uiState.resources.procCount}`);
171
+ return createPanel(screen, {
172
+ title: 'RESOURCES',
173
+ top,
174
+ left,
175
+ width,
176
+ height,
177
+ content,
178
+ focused,
179
+ panelId: 'RESOURCES',
180
+ });
181
+ }
182
+ /**
183
+ * Helper: Render active assets panel from UiState
184
+ */
185
+ function renderActiveAssetsPanelFromUiState(screen, top, left, width, height, uiState, focused = false) {
186
+ const { createPanel } = require('../primitives/Panel.js');
187
+ const { getBlessedColor } = require('../theme/tokens.js');
188
+ const blessed = require('neo-blessed');
189
+ const content = [];
190
+ content.push(`TOTAL: {${getBlessedColor('accentCyan')}-fg}${uiState.assets.total}{/}`);
191
+ const activeColor = uiState.assets.active !== 'UNKNOWN' && uiState.assets.active > 0
192
+ ? getBlessedColor('successGreen')
193
+ : getBlessedColor('mutedGrey');
194
+ content.push(`ACTIVE: {${activeColor}-fg}${uiState.assets.active}{/}`);
195
+ content.push(`IDLE: {${getBlessedColor('mutedGrey')}-fg}${uiState.assets.idle}{/}`);
196
+ const errorColor = uiState.assets.error !== 'UNKNOWN' && typeof uiState.assets.error === 'number' && uiState.assets.error > 0
197
+ ? getBlessedColor('criticalRed')
198
+ : getBlessedColor('mutedGrey');
199
+ content.push(`ERROR: {${errorColor}-fg}${uiState.assets.error}{/}`);
200
+ // Activity meter
201
+ const { renderMeter } = require('../widgets/index.js');
202
+ const total = uiState.assets.total;
203
+ const active = uiState.assets.active;
204
+ let activityValue = "UNKNOWN";
205
+ let activityLabel = '';
206
+ if (typeof total === 'number' && typeof active === 'number' && total > 0) {
207
+ activityValue = (active / total) * 100; // Percentage
208
+ activityLabel = `A:${active} I:${uiState.assets.idle} E:${uiState.assets.error}`;
209
+ }
210
+ const activityMeter = renderMeter({
211
+ value: activityValue,
212
+ min: 0,
213
+ max: 100,
214
+ width: 10,
215
+ labelLeft: 'ACTIVITY',
216
+ labelRight: activityLabel,
217
+ });
218
+ content.push(`{${getBlessedColor('accentCyan')}-fg}${activityMeter}{/}`);
219
+ if (uiState.assets.highlight !== 'UNKNOWN') {
220
+ content.push(`HIGHLIGHT: {${getBlessedColor('accentCyan')}-fg}${uiState.assets.highlight}{/}`);
221
+ }
222
+ else {
223
+ content.push(`HIGHLIGHT: {${getBlessedColor('mutedGrey')}-fg}NONE{/}`);
224
+ }
225
+ content.push(`LAST ACTION: {${getBlessedColor('accentCyan')}-fg}${uiState.assets.lastAction}{/}`);
226
+ return createPanel(screen, {
227
+ title: 'ACTIVE ASSETS',
228
+ top,
229
+ left,
230
+ width,
231
+ height,
232
+ content,
233
+ focused,
234
+ panelId: 'ASSETS',
235
+ });
236
+ }
237
+ /**
238
+ * Helper: Render operations feed panel from UiState
239
+ */
240
+ function renderOperationsFeedPanelFromUiState(screen, top, left, width, height, uiState, focused = false) {
241
+ const { createPanel } = require('../primitives/Panel.js');
242
+ const { getBlessedColor } = require('../theme/tokens.js');
243
+ const blessed = require('neo-blessed');
244
+ const content = [];
245
+ if (uiState.feed.events.length > 0) {
246
+ uiState.feed.events.slice(0, height - 2).forEach(event => {
247
+ const time = new Date(event.ts).toLocaleTimeString();
248
+ const color = event.tag === 'SEC' || event.tag === 'DB'
249
+ ? getBlessedColor('criticalRed')
250
+ : event.tag === 'NET'
251
+ ? getBlessedColor('warnAmber')
252
+ : getBlessedColor('accentCyan');
253
+ content.push(`{${color}-fg}[${time}] [${event.tag}] ${event.msg}{/}`);
254
+ });
255
+ }
256
+ else {
257
+ content.push(`{${getBlessedColor('mutedGrey')}-fg}NO RECENT OPERATIONS{/}`);
258
+ }
259
+ return createPanel(screen, {
260
+ title: 'OPERATIONS FEED',
261
+ top,
262
+ left,
263
+ width,
264
+ height,
265
+ content,
266
+ focused,
267
+ panelId: 'FEED',
268
+ });
269
+ }
270
+ /**
271
+ * Helper: Render network/origin panel from UiState
272
+ */
273
+ function renderNetworkOriginPanelFromUiState(screen, top, left, width, height, uiState) {
274
+ const { createPanel } = require('../primitives/Panel.js');
275
+ const { getBlessedColor } = require('../theme/tokens.js');
276
+ const blessed = require('neo-blessed');
277
+ const content = [];
278
+ content.push(`ORIGIN: {${getBlessedColor('accentCyan')}-fg}${uiState.network.originRegion} (${uiState.network.originClass}){/}`);
279
+ content.push(`GATEWAY: {${getBlessedColor('accentCyan')}-fg}${uiState.network.gatewayRegion}{/}`);
280
+ content.push(`DATABASE: {${getBlessedColor('accentCyan')}-fg}${uiState.network.dbRegion}{/}`);
281
+ // Latency with meter
282
+ const latencyClass = uiState.network.latencyClass;
283
+ const latencyMs = uiState.network.latencyMs;
284
+ const latencyColor = latencyClass === 'LOW' ? getBlessedColor('successGreen') :
285
+ latencyClass === 'HIGH' ? getBlessedColor('criticalRed') :
286
+ latencyClass === 'MEDIUM' ? getBlessedColor('warnAmber') : getBlessedColor('mutedGrey');
287
+ const { renderMeter } = require('../widgets/index.js');
288
+ const latencyLabel = latencyMs !== 'UNKNOWN' ? `${latencyMs}ms` : 'UNKNOWN';
289
+ const latencyMeter = renderMeter({
290
+ value: latencyMs !== 'UNKNOWN' ? latencyMs : 'UNKNOWN',
291
+ min: 0,
292
+ max: 300, // 300ms max for meter
293
+ width: 10,
294
+ labelLeft: 'LAT',
295
+ labelRight: latencyLabel,
296
+ });
297
+ content.push(`{${latencyColor}-fg}${latencyMeter}{/}`);
298
+ content.push(`PUBLIC IP: {${getBlessedColor('mutedGrey')}-fg}${uiState.network.publicIpMasked}{/}`);
299
+ return createPanel(screen, {
300
+ title: 'NETWORK / ORIGIN',
301
+ top,
302
+ left,
303
+ width,
304
+ height,
305
+ content,
306
+ });
307
+ }
308
+ /**
309
+ * Helper: Render GEO INTEL panel from UiState
310
+ * Phase 5: Geographic situational awareness
311
+ */
312
+ function renderGeoIntelPanelFromUiState(screen, top, left, width, height, uiState, focused = false) {
313
+ const { createPanel } = require('../primitives/Panel.js');
314
+ const { getBlessedColor } = require('../theme/tokens.js');
315
+ const { renderMiniMap } = require('../widgets/index.js');
316
+ const content = [];
317
+ const geo = uiState.geo;
318
+ if (!geo || (geo.originLabel === "UNKNOWN" && geo.gatewayRegion === "UNKNOWN" && geo.dbRegion === "UNKNOWN")) {
319
+ // All geo fields unknown
320
+ content.push(`GEO: {${getBlessedColor('mutedGrey')}-fg}UNAVAILABLE{/}`);
321
+ content.push(`REASON: {${getBlessedColor('mutedGrey')}-fg}NO_SOURCE_DATA{/}`);
322
+ }
323
+ else {
324
+ // ORIGIN
325
+ content.push(`ORIGIN: {${getBlessedColor('accentCyan')}-fg}${geo.originLabel}{/}`);
326
+ // ROUTE
327
+ content.push(`ROUTE: {${getBlessedColor('accentCyan')}-fg}${geo.routeLabel}{/}`);
328
+ // GATEWAY
329
+ content.push(`GW: {${getBlessedColor('accentCyan')}-fg}${geo.gatewayRegion}{/}`);
330
+ // DATABASE
331
+ content.push(`DB: {${getBlessedColor('accentCyan')}-fg}${geo.dbRegion}{/}`);
332
+ // PING
333
+ const pingLabel = geo.pingMs !== "UNKNOWN"
334
+ ? `${geo.pingMs}ms ${geo.pingClass}`
335
+ : 'UNKNOWN';
336
+ const pingColor = geo.pingClass === 'LOW' ? getBlessedColor('successGreen') :
337
+ geo.pingClass === 'HIGH' ? getBlessedColor('criticalRed') :
338
+ geo.pingClass === 'MEDIUM' ? getBlessedColor('warnAmber') : getBlessedColor('mutedGrey');
339
+ content.push(`PING: {${pingColor}-fg}${pingLabel}{/}`);
340
+ }
341
+ // Mini-map (optional, only if enabled and coordinates known)
342
+ const enableMiniMap = process.env.ENABLE_MINIMAP === '1';
343
+ if (enableMiniMap && geo && geo.originLatLon && geo.originLatLon !== "UNKNOWN" &&
344
+ geo.gatewayLatLon && geo.gatewayLatLon !== "UNKNOWN" &&
345
+ typeof geo.originLatLon === 'object' && typeof geo.gatewayLatLon === 'object') {
346
+ const mapWidth = Math.min(20, width - 2);
347
+ const mapHeight = Math.min(10, height - content.length - 2);
348
+ if (mapHeight > 0 && mapWidth > 0) {
349
+ const mapLines = renderMiniMap({
350
+ width: mapWidth,
351
+ height: mapHeight,
352
+ origin: geo.originLatLon,
353
+ gateway: geo.gatewayLatLon,
354
+ db: geo.dbLatLon && geo.dbLatLon !== "UNKNOWN" && typeof geo.dbLatLon === 'object' ? geo.dbLatLon : undefined,
355
+ });
356
+ content.push(''); // Blank line separator
357
+ content.push(...mapLines);
358
+ }
359
+ }
360
+ // Ensure max 5 lines (or more if mini-map enabled)
361
+ const maxLines = enableMiniMap ? height - 2 : 5;
362
+ const finalContent = content.slice(0, maxLines);
363
+ return createPanel(screen, {
364
+ title: 'GEO INTEL',
365
+ top,
366
+ left,
367
+ width,
368
+ height,
369
+ content: finalContent,
370
+ focused,
371
+ panelId: 'NETWORK',
372
+ });
373
+ }
374
+ /**
375
+ * Helper: Render capability flags panel from UiState
376
+ */
377
+ function renderCapabilityFlagsPanelFromUiState(screen, top, left, width, height, uiState, focused = false) {
378
+ const { createPanel } = require('../primitives/Panel.js');
379
+ const { getBlessedColor } = require('../theme/tokens.js');
380
+ const blessed = require('neo-blessed');
381
+ const content = [];
382
+ // Build flags
383
+ const { renderFlagRow, capabilityToLevel, getFlagColorToken } = require('../widgets/index.js');
384
+ const flags = [
385
+ {
386
+ key: 'GW',
387
+ value: uiState.capabilities.gateway,
388
+ level: capabilityToLevel(uiState.capabilities.gateway, 'gateway'),
389
+ },
390
+ {
391
+ key: 'DB',
392
+ value: uiState.capabilities.database,
393
+ level: capabilityToLevel(uiState.capabilities.database, 'database'),
394
+ },
395
+ {
396
+ key: 'MEM',
397
+ value: uiState.capabilities.memory,
398
+ level: capabilityToLevel(uiState.capabilities.memory, 'memory'),
399
+ },
400
+ {
401
+ key: 'SEC',
402
+ value: uiState.capabilities.security,
403
+ level: capabilityToLevel(uiState.capabilities.security, 'security'),
404
+ },
405
+ {
406
+ key: 'RL',
407
+ value: uiState.capabilities.rateLimit,
408
+ level: capabilityToLevel(uiState.capabilities.rateLimit, 'rateLimit'),
409
+ },
410
+ ];
411
+ // Render flag row with colors
412
+ const flagRow = renderFlagRow(flags, 5);
413
+ const coloredParts = [];
414
+ const parts = flagRow.split(' ');
415
+ parts.forEach((part, idx) => {
416
+ const flag = flags[idx];
417
+ if (flag) {
418
+ const colorToken = getFlagColorToken(flag.level);
419
+ const color = getBlessedColor(colorToken);
420
+ coloredParts.push(`{${color}-fg}${part}{/}`);
421
+ }
422
+ else {
423
+ coloredParts.push(part);
424
+ }
425
+ });
426
+ content.push(coloredParts.join(' '));
427
+ return createPanel(screen, {
428
+ title: 'CAPABILITY FLAGS',
429
+ top,
430
+ left,
431
+ width,
432
+ height,
433
+ content,
434
+ focused,
435
+ panelId: 'CAPABILITIES',
436
+ });
437
+ }
438
+ /**
439
+ * Helper: Render command surface from UiState
440
+ */
441
+ function renderCommandSurfaceFromUiState(screen, top, left, width, height, uiState) {
442
+ const blessed = require('neo-blessed');
443
+ const blessedLib = blessed;
444
+ const { getBlessedColor } = require('../theme/tokens.js');
445
+ const commands = 'start deploy inspect metrics system';
446
+ const commandText = `{${getBlessedColor('accentCyan')}-fg}${commands}{/}`;
447
+ const mode = uiState.posture.connected === true ? 'REMOTE' :
448
+ uiState.posture.connected === false ? 'OFFLINE' : 'UNKNOWN';
449
+ const connect = uiState.posture.connected === true ? 'CONNECTED' : 'DISCONNECTED';
450
+ const posture = uiState.posture.posture;
451
+ const activeRuns = typeof uiState.assets.active === 'number' ? uiState.assets.active : 0;
452
+ const lastCmd = 'posture';
453
+ const statusParts = [mode, connect, posture, `${activeRuns}`, lastCmd];
454
+ const statusText = statusParts.join(' | ');
455
+ const fullText = `${commandText} | {${getBlessedColor('mutedGrey')}-fg}${statusText}{/}`;
456
+ return blessedLib.box({
457
+ top,
458
+ left,
459
+ width,
460
+ height,
461
+ content: fullText,
462
+ tags: true,
463
+ style: {
464
+ fg: getBlessedColor('standardWhite'),
465
+ },
466
+ });
467
+ }
468
+ //# sourceMappingURL=hub.js.map