jsgui3-server 0.0.148 → 0.0.150

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 (154) hide show
  1. package/.github/agents/Mobile Developer.agent.md +89 -0
  2. package/.github/workflows/control-scan-manifest-check.yml +31 -0
  3. package/AGENTS.md +4 -0
  4. package/README.md +215 -3
  5. package/admin-ui/client.js +81 -51
  6. package/admin-ui/v1/admin_auth_service.js +197 -0
  7. package/admin-ui/v1/admin_user_store.js +71 -0
  8. package/admin-ui/v1/client.js +17 -0
  9. package/admin-ui/v1/controls/admin_shell.js +1399 -0
  10. package/admin-ui/v1/controls/group_box.js +84 -0
  11. package/admin-ui/v1/controls/stat_card.js +125 -0
  12. package/admin-ui/v1/server.js +658 -0
  13. package/admin-ui/v1/utils/formatters.js +68 -0
  14. package/dev-status.svg +139 -0
  15. package/docs/admin-extension-guide.md +345 -0
  16. package/docs/api-reference.md +301 -43
  17. package/docs/books/adaptive-control-improvements/01-control-candidate-matrix.md +122 -0
  18. package/docs/books/adaptive-control-improvements/02-tier-1-layout-playbooks.md +207 -0
  19. package/docs/books/adaptive-control-improvements/03-tier-2-navigation-form-overlay.md +140 -0
  20. package/docs/books/adaptive-control-improvements/04-cross-cutting-platform-functionality.md +141 -0
  21. package/docs/books/adaptive-control-improvements/05-styling-theming-density-upgrades.md +114 -0
  22. package/docs/books/adaptive-control-improvements/06-testing-quality-gates.md +97 -0
  23. package/docs/books/adaptive-control-improvements/07-delivery-roadmap-and-ownership.md +137 -0
  24. package/docs/books/adaptive-control-improvements/08-appendix-tier1-acceptance-and-pr-templates.md +261 -0
  25. package/docs/books/adaptive-control-improvements/README.md +66 -0
  26. package/docs/books/admin-ui-authentication/01-threat-model-and-goals.md +124 -0
  27. package/docs/books/admin-ui-authentication/02-session-model-and-token-model.md +75 -0
  28. package/docs/books/admin-ui-authentication/03-auth-middleware-patterns.md +77 -0
  29. package/docs/books/admin-ui-authentication/README.md +25 -0
  30. package/docs/books/creating-a-new-admin-ui/01-introduction-and-vision.md +130 -0
  31. package/docs/books/creating-a-new-admin-ui/02-architecture-and-data-flow.md +298 -0
  32. package/docs/books/creating-a-new-admin-ui/03-server-introspection.md +381 -0
  33. package/docs/books/creating-a-new-admin-ui/04-admin-module-adapter-layer.md +592 -0
  34. package/docs/books/creating-a-new-admin-ui/05-domain-controls-stat-cards-and-gauges.md +513 -0
  35. package/docs/books/creating-a-new-admin-ui/06-domain-controls-process-manager.md +544 -0
  36. package/docs/books/creating-a-new-admin-ui/07-domain-controls-resource-pool-inspector.md +493 -0
  37. package/docs/books/creating-a-new-admin-ui/08-domain-controls-route-table-and-api-explorer.md +586 -0
  38. package/docs/books/creating-a-new-admin-ui/09-domain-controls-log-viewer-and-activity-feed.md +490 -0
  39. package/docs/books/creating-a-new-admin-ui/10-domain-controls-build-status-and-bundle-inspector.md +526 -0
  40. package/docs/books/creating-a-new-admin-ui/11-domain-controls-configuration-panel.md +808 -0
  41. package/docs/books/creating-a-new-admin-ui/12-admin-shell-layout-sidebar-navigation.md +210 -0
  42. package/docs/books/creating-a-new-admin-ui/13-telemetry-integration.md +556 -0
  43. package/docs/books/creating-a-new-admin-ui/14-realtime-sse-observable-integration.md +485 -0
  44. package/docs/books/creating-a-new-admin-ui/15-styling-theming-aero-design-system.md +521 -0
  45. package/docs/books/creating-a-new-admin-ui/16-testing-and-quality-assurance.md +147 -0
  46. package/docs/books/creating-a-new-admin-ui/17-next-steps-process-resource-roadmap.md +356 -0
  47. package/docs/books/creating-a-new-admin-ui/README.md +68 -0
  48. package/docs/books/device-adaptive-composition/01-platform-feature-audit.md +177 -0
  49. package/docs/books/device-adaptive-composition/02-responsive-composition-model.md +187 -0
  50. package/docs/books/device-adaptive-composition/03-data-model-vs-view-model.md +231 -0
  51. package/docs/books/device-adaptive-composition/04-styling-theme-breakpoints.md +234 -0
  52. package/docs/books/device-adaptive-composition/05-showcase-app-multi-device-assessment.md +193 -0
  53. package/docs/books/device-adaptive-composition/06-implementation-patterns-and-apis.md +346 -0
  54. package/docs/books/device-adaptive-composition/07-testing-harness-and-quality-gates.md +265 -0
  55. package/docs/books/device-adaptive-composition/08-roadmap-and-adoption-plan.md +250 -0
  56. package/docs/books/device-adaptive-composition/README.md +47 -0
  57. package/docs/books/jsgui3-bundling-research-book/00-table-of-contents.md +35 -0
  58. package/docs/books/jsgui3-bundling-research-book/01-pipeline-and-runtime-semantics.md +34 -0
  59. package/docs/books/jsgui3-bundling-research-book/02-javascript-bundling-core.md +36 -0
  60. package/docs/books/jsgui3-bundling-research-book/03-style-extraction-and-css-compilation.md +35 -0
  61. package/docs/books/jsgui3-bundling-research-book/04-static-publishing-and-delivery.md +39 -0
  62. package/docs/books/jsgui3-bundling-research-book/05-current-limits-and-size-bloat-vectors.md +25 -0
  63. package/docs/books/jsgui3-bundling-research-book/06-unused-module-elimination-strategy.md +77 -0
  64. package/docs/books/jsgui3-bundling-research-book/07-jsgui3-html-control-and-mixin-pruning.md +63 -0
  65. package/docs/books/jsgui3-bundling-research-book/08-test-and-verification-methodology.md +43 -0
  66. package/docs/books/jsgui3-bundling-research-book/09-roadmap-and-rollout.md +42 -0
  67. package/docs/books/jsgui3-bundling-research-book/10-further-research-strategies-and-upgrades.md +211 -0
  68. package/docs/books/jsgui3-bundling-research-book/README.md +35 -0
  69. package/docs/bundling-system-deep-dive.md +9 -4
  70. package/docs/comparison-report-express-plex-cpanel.md +549 -0
  71. package/docs/comprehensive-documentation.md +49 -18
  72. package/docs/configuration-reference.md +152 -27
  73. package/docs/core/README.md +19 -0
  74. package/docs/core/jsgui3-server-core-book/00-table-of-contents.md +21 -0
  75. package/docs/core/jsgui3-server-core-book/01-startup-readiness-state-machine.md +41 -0
  76. package/docs/core/jsgui3-server-core-book/02-resource-abstraction-and-lifecycle.md +92 -0
  77. package/docs/core/jsgui3-server-core-book/03-resource-pool-and-event-topology.md +47 -0
  78. package/docs/core/jsgui3-server-core-book/04-sse-publisher-semantics.md +41 -0
  79. package/docs/core/jsgui3-server-core-book/05-serve-factory-resource-wiring.md +46 -0
  80. package/docs/core/jsgui3-server-core-book/06-e2e-testing-methodology.md +48 -0
  81. package/docs/core/jsgui3-server-core-book/07-defect-detection-and-hardening-loop.md +47 -0
  82. package/docs/designs/server-admin-interface-aero.svg +611 -0
  83. package/docs/publishers-guide.md +59 -4
  84. package/docs/resources-guide.md +184 -35
  85. package/docs/simple-server-api-design.md +72 -17
  86. package/docs/system-architecture.md +18 -14
  87. package/docs/troubleshooting.md +84 -53
  88. package/examples/controls/15) window, observable SSE/server.js +6 -1
  89. package/examples/controls/19) window, auto observable ui/server.js +9 -0
  90. package/examples/controls/20) window, task manager app/README.md +133 -0
  91. package/examples/controls/20) window, task manager app/client.js +797 -0
  92. package/examples/controls/20) window, task manager app/server.js +178 -0
  93. package/examples/controls/6) window, color_palette/client.js +165 -68
  94. package/examples/controls/9) window, date picker/client.js +362 -76
  95. package/examples/controls/9b) window, shared data.model mirrored date pickers/client.js +104 -83
  96. package/examples/jsgui3-html/06) theming/client.js +22 -1
  97. package/examples/jsgui3-html/10) binding-debugger/client.js +137 -1
  98. package/http/responders/static/Static_Route_HTTP_Responder.js +52 -34
  99. package/lab/experiments/capture-color-controls.js +196 -0
  100. package/lab/results/screenshots/color-controls/full_page.png +0 -0
  101. package/lab/results/screenshots/color-controls/section_1_color_grid_12x12.png +0 -0
  102. package/lab/results/screenshots/color-controls/section_2_color_grid_4x2.png +0 -0
  103. package/lab/results/screenshots/color-controls/section_3_color_palette.png +0 -0
  104. package/lab/results/screenshots/color-controls/section_4_palette_comparison.png +0 -0
  105. package/lab/results/screenshots/color-controls/section_5_raw_swatches.png +0 -0
  106. package/lab/results/screenshots/color-controls/section_6_optimized_crayola.png +0 -0
  107. package/lab/results/screenshots/color-controls/section_7_pastel_palette.png +0 -0
  108. package/lab/results/screenshots/color-controls/section_8_extended_144.png +0 -0
  109. package/lab/screenshot-utils.js +248 -0
  110. package/module.js +12 -0
  111. package/package.json +12 -2
  112. package/publishers/Publishers.js +4 -3
  113. package/publishers/helpers/assigners/static-compressed-response-buffers/Single_Control_Webpage_Server_Static_Compressed_Response_Buffers_Assigner.js +5 -5
  114. package/publishers/http-sse-publisher.js +341 -0
  115. package/resources/process-resource.js +950 -0
  116. package/resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild.js +129 -33
  117. package/resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild.js +18 -7
  118. package/resources/processors/bundlers/js/esbuild/JSGUI3_HTML_Control_Optimizer.js +829 -0
  119. package/resources/remote-process-resource.js +355 -0
  120. package/resources/server-resource-pool.js +354 -41
  121. package/serve-factory.js +442 -259
  122. package/server.js +288 -13
  123. package/tests/README.md +71 -4
  124. package/tests/admin-ui-jsgui-controls.test.js +581 -0
  125. package/tests/admin-ui-render.test.js +24 -0
  126. package/tests/assigners.test.js +56 -40
  127. package/tests/bundling-default-control-elimination.puppeteer.test.js +260 -0
  128. package/tests/configuration-validation.test.js +21 -18
  129. package/tests/content-analysis.test.js +7 -6
  130. package/tests/control-optimizer-cache-behavior.test.js +52 -0
  131. package/tests/control-scan-manifest-regression.test.js +144 -0
  132. package/tests/end-to-end.test.js +15 -14
  133. package/tests/error-handling.test.js +222 -179
  134. package/tests/fixtures/bundling-default-button-client.js +37 -0
  135. package/tests/fixtures/bundling-default-window-client.js +34 -0
  136. package/tests/fixtures/control_scan_manifest_expectations.json +48 -0
  137. package/tests/fixtures/resource-monitor-client.js +319 -0
  138. package/tests/helpers/puppeteer-e2e-harness.js +317 -0
  139. package/tests/http-sse-publisher.test.js +136 -0
  140. package/tests/performance.test.js +69 -65
  141. package/tests/process-resource.test.js +138 -0
  142. package/tests/publishers.test.js +7 -7
  143. package/tests/remote-process-resource.test.js +160 -0
  144. package/tests/sass-controls.e2e.test.js +7 -1
  145. package/tests/serve-resources.test.js +270 -0
  146. package/tests/serve.test.js +120 -50
  147. package/tests/server-resource-pool.test.js +106 -0
  148. package/tests/small-controls-bundle-size.test.js +252 -0
  149. package/tests/test-runner.js +14 -1
  150. package/tests/window-examples.puppeteer.test.js +204 -1
  151. package/tests/window-resource-integration.puppeteer.test.js +585 -0
  152. package/tests/temp_invalid.js +0 -7
  153. package/tests/temp_invalid_utf8.js +0 -1
  154. package/tests/temp_malformed.js +0 -10
@@ -0,0 +1,544 @@
1
+ # Chapter 6: Domain Controls — Process Manager Panel
2
+
3
+ ## Overview
4
+
5
+ The Process Manager Panel is a group-box control that visualizes the server's process tree: the main Node.js process at the top, with fork arrows pointing down to child processes. Each process displays its name, state, PID, and memory usage.
6
+
7
+ In the design reference, this appears as the "Processes" group box on the left side of the dashboard, showing:
8
+ - A large main server process bar with a blue accent strip
9
+ - Fork arrows (`fork()`) connecting to child process cards
10
+ - Each child card has a distinctive color (purple for Bundle Builder, amber for Compiler, cyan for File Watcher)
11
+ - Health indicators (green dots) on each process
12
+
13
+ ---
14
+
15
+ ## Process_Panel Control
16
+
17
+ ### Spec
18
+
19
+ ```javascript
20
+ {
21
+ __type_name: 'process_panel',
22
+ title: 'Processes', // Group box label
23
+ processes: { // Data from /api/admin/processes
24
+ main: { pid, state, uptime_seconds, memory },
25
+ children: [
26
+ { name, pid, state, memory, restart_count, type }
27
+ ]
28
+ }
29
+ }
30
+ ```
31
+
32
+ ### Visual Anatomy
33
+
34
+ ```
35
+ ┌─ Processes ────────────────────────────────────────────┐
36
+ │ │
37
+ │ ┌════════════════════════════════════════════════════┐ │
38
+ │ │▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ (blue bar) │ │
39
+ │ │ ● Main Server Process [RUNNING] │ │
40
+ │ │ HTTP Server · Router · SSR Engine PID 7824 │ │
41
+ │ │ 128 MB │ │
42
+ │ └═══════════════════╤═══════════╤══════════╤════════┘ │
43
+ │ │ │ │ │
44
+ │ fork() fork() fork() │
45
+ │ │ │ │ │
46
+ │ ┌──────────────┐ ┌──────────┐ ┌──────────┐ │
47
+ │ │ ▔▔ (purple) │ │ ▔▔(amber)│ │ ▔▔(cyan) │ │
48
+ │ │ ● Bundle │ │ ●Compiler│ │ ● File │ │
49
+ │ │ Builder │ │ │ │ Watcher │ │
50
+ │ │ PID 7830 │ │ PID 7836 │ │ PID 7842 │ │
51
+ │ │ 86 MB │ │ 64 MB │ │ 24 MB │ │
52
+ │ └──────────────┘ └──────────┘ └──────────┘ │
53
+ │ │
54
+ │ Total memory: 302 MB across 4 processes │
55
+ └────────────────────────────────────────────────────────┘
56
+ ```
57
+
58
+ ### Constructor
59
+
60
+ ```javascript
61
+ class Process_Panel extends jsgui.Control {
62
+ constructor(spec = {}) {
63
+ spec.__type_name = spec.__type_name || 'process_panel';
64
+ super(spec);
65
+ const { context } = this;
66
+ this._processes = spec.processes || { main: null, children: [] };
67
+
68
+ const compose = () => {
69
+ // Group box wrapper
70
+ const group = new Group_Box({
71
+ context,
72
+ title: spec.title || 'Processes'
73
+ });
74
+ this.add(group);
75
+ this._group = group;
76
+
77
+ this._render_processes();
78
+ };
79
+
80
+ if (!spec.el) { compose(); }
81
+ }
82
+
83
+ _render_processes() {
84
+ const { context } = this;
85
+ const data = this._processes;
86
+
87
+ // Main process card
88
+ if (data.main) {
89
+ const main_card = new Process_Card({
90
+ context,
91
+ name: 'Main Server Process',
92
+ description: 'HTTP Server · Router · SSR Engine · API Publisher',
93
+ pid: data.main.pid,
94
+ state: data.main.state,
95
+ memory_bytes: data.main.memory?.rss,
96
+ accent: 'blue',
97
+ is_main: true
98
+ });
99
+ this._group.add(main_card);
100
+ this._main_card = main_card;
101
+ }
102
+
103
+ // Fork arrows + children
104
+ if (data.children && data.children.length > 0) {
105
+ const fork_row = new controls.div({ context, class: 'fork-row' });
106
+ this._group.add(fork_row);
107
+
108
+ const children_row = new controls.div({ context, class: 'children-row' });
109
+ this._group.add(children_row);
110
+
111
+ const accent_colors = ['purple', 'amber', 'cyan', 'green', 'pink'];
112
+
113
+ data.children.forEach((child, i) => {
114
+ // Fork arrow
115
+ const arrow = new controls.div({ context, class: 'fork-arrow' });
116
+ const arrow_label = new controls.span({ context, class: 'fork-label' });
117
+ arrow_label.add('fork()');
118
+ arrow.add(arrow_label);
119
+ fork_row.add(arrow);
120
+
121
+ // Child card
122
+ const child_card = new Process_Card({
123
+ context,
124
+ name: child.name,
125
+ description: child.description || '',
126
+ pid: child.pid,
127
+ state: child.state,
128
+ memory_bytes: child.memory?.rss_bytes,
129
+ accent: accent_colors[i % accent_colors.length],
130
+ restart_count: child.restart_count
131
+ });
132
+ children_row.add(child_card);
133
+ });
134
+ }
135
+
136
+ // Total memory line
137
+ const total_memory = this._calculate_total_memory(data);
138
+ const total_line = new controls.div({ context, class: 'process-total' });
139
+ total_line.add(
140
+ `Total memory: ${format_bytes(total_memory)} across ${1 + (data.children?.length || 0)} processes`
141
+ );
142
+ this._group.add(total_line);
143
+ }
144
+
145
+ _calculate_total_memory(data) {
146
+ let total = data.main?.memory?.rss || 0;
147
+ if (data.children) {
148
+ data.children.forEach(c => {
149
+ total += c.memory?.rss_bytes || 0;
150
+ });
151
+ }
152
+ return total;
153
+ }
154
+
155
+ update(processes_data) {
156
+ this._processes = processes_data;
157
+ // Client-side: clear and re-render
158
+ if (this._group && this._group.el) {
159
+ // Clear children
160
+ while (this._group.el.firstChild) {
161
+ this._group.el.removeChild(this._group.el.firstChild);
162
+ }
163
+ this._render_processes();
164
+ }
165
+ }
166
+ }
167
+ ```
168
+
169
+ ---
170
+
171
+ ## Process_Card Sub-Control
172
+
173
+ An individual process card within the panel.
174
+
175
+ ### Spec
176
+
177
+ ```javascript
178
+ {
179
+ __type_name: 'process_card',
180
+ name: 'Bundle Builder',
181
+ description: 'JS bundling · CSS extraction',
182
+ pid: 7830,
183
+ state: 'running',
184
+ memory_bytes: 90177536,
185
+ accent: 'purple', // 'blue', 'purple', 'amber', 'cyan', 'green'
186
+ is_main: false,
187
+ restart_count: 0
188
+ }
189
+ ```
190
+
191
+ ### Constructor
192
+
193
+ ```javascript
194
+ class Process_Card extends jsgui.Control {
195
+ constructor(spec = {}) {
196
+ spec.__type_name = spec.__type_name || 'process_card';
197
+ super(spec);
198
+ const { context } = this;
199
+
200
+ const compose = () => {
201
+ // Accent bar at top
202
+ const accent = new controls.div({
203
+ context,
204
+ class: `process-accent accent-${spec.accent || 'blue'}`
205
+ });
206
+ this.add(accent);
207
+
208
+ // Health dot + name
209
+ const header = new controls.div({ context, class: 'process-header' });
210
+ this.add(header);
211
+
212
+ const health = new Health_Badge({
213
+ context,
214
+ state: spec.state || 'unknown'
215
+ });
216
+ header.add(health);
217
+ this._health = health;
218
+
219
+ const name_el = new controls.span({ context, class: 'process-name' });
220
+ name_el.add(spec.name || 'Unknown');
221
+ header.add(name_el);
222
+
223
+ // Status badge (if main)
224
+ if (spec.is_main) {
225
+ const status_badge = new controls.div({
226
+ context,
227
+ class: `process-status-badge badge-${spec.state || 'unknown'}`
228
+ });
229
+ status_badge.add(spec.state?.toUpperCase() || 'UNKNOWN');
230
+ header.add(status_badge);
231
+ }
232
+
233
+ // Description
234
+ if (spec.description) {
235
+ const desc = new controls.div({ context, class: 'process-desc' });
236
+ desc.add(spec.description);
237
+ this.add(desc);
238
+ }
239
+
240
+ // Footer: PID + memory
241
+ const footer = new controls.div({ context, class: 'process-footer' });
242
+ this.add(footer);
243
+
244
+ const pid_el = new controls.span({ context, class: 'process-pid' });
245
+ pid_el.add(spec.pid ? `PID ${spec.pid}` : '—');
246
+ footer.add(pid_el);
247
+
248
+ const mem_el = new controls.span({ context, class: 'process-mem' });
249
+ mem_el.add(spec.memory_bytes ? format_bytes(spec.memory_bytes) : '—');
250
+ footer.add(mem_el);
251
+ };
252
+
253
+ if (!spec.el) { compose(); }
254
+ }
255
+ }
256
+ ```
257
+
258
+ ### CSS
259
+
260
+ ```css
261
+ .process_card {
262
+ border-radius: 4px;
263
+ border: 1px solid #B0A898;
264
+ overflow: hidden;
265
+ background: linear-gradient(to bottom, #F4F8FD, #D8E4F0 45%, #C0D4E8 55%, #CCDDEE);
266
+ }
267
+
268
+ .process_card.process-main {
269
+ width: 100%;
270
+ }
271
+
272
+ .process-accent {
273
+ height: 4px;
274
+ border-radius: 2px 2px 0 0;
275
+ }
276
+
277
+ .accent-blue { background: linear-gradient(to right, #7AACE0, #5090D0); }
278
+ .accent-purple { background: #9070C0; }
279
+ .accent-amber { background: #D8A020; }
280
+ .accent-cyan { background: #4098B8; }
281
+ .accent-green { background: #48B848; }
282
+
283
+ .process-header {
284
+ display: flex;
285
+ align-items: center;
286
+ gap: 8px;
287
+ padding: 8px 12px 4px;
288
+ }
289
+
290
+ .process-name {
291
+ font-size: 11px;
292
+ font-weight: 600;
293
+ color: #1A3060;
294
+ flex: 1;
295
+ }
296
+
297
+ .process-status-badge {
298
+ font-size: 8px;
299
+ font-weight: 500;
300
+ padding: 2px 10px;
301
+ border-radius: 3px;
302
+ }
303
+
304
+ .badge-running {
305
+ background: rgba(72, 184, 72, 0.15);
306
+ border: 0.5px solid #48B848;
307
+ color: #2A6A2A;
308
+ }
309
+
310
+ .badge-stopped {
311
+ background: rgba(128, 128, 128, 0.15);
312
+ border: 0.5px solid #808080;
313
+ color: #606060;
314
+ }
315
+
316
+ .badge-crashed {
317
+ background: rgba(204, 68, 68, 0.15);
318
+ border: 0.5px solid #CC4444;
319
+ color: #992222;
320
+ }
321
+
322
+ .process-desc {
323
+ font-size: 8px;
324
+ color: #808080;
325
+ padding: 0 12px 4px;
326
+ }
327
+
328
+ .process-footer {
329
+ display: flex;
330
+ justify-content: space-between;
331
+ padding: 4px 12px 8px;
332
+ font-size: 8px;
333
+ color: #908888;
334
+ }
335
+
336
+ /* Fork visualization */
337
+ .fork-row {
338
+ display: flex;
339
+ justify-content: space-around;
340
+ padding: 4px 60px;
341
+ }
342
+
343
+ .fork-arrow {
344
+ display: flex;
345
+ flex-direction: column;
346
+ align-items: center;
347
+ }
348
+
349
+ .fork-arrow::before {
350
+ content: '';
351
+ width: 1px;
352
+ height: 16px;
353
+ background: #7090B0;
354
+ }
355
+
356
+ .fork-arrow::after {
357
+ content: '';
358
+ width: 0;
359
+ height: 0;
360
+ border-left: 4px solid transparent;
361
+ border-right: 4px solid transparent;
362
+ border-top: 6px solid #7090B0;
363
+ }
364
+
365
+ .fork-label {
366
+ font-size: 8px;
367
+ color: #7090B0;
368
+ margin: 2px 0;
369
+ }
370
+
371
+ .children-row {
372
+ display: flex;
373
+ gap: 12px;
374
+ padding: 0 16px;
375
+ flex-wrap: wrap;
376
+ }
377
+
378
+ .children-row .process_card {
379
+ flex: 1 1 120px;
380
+ min-width: 110px;
381
+ }
382
+
383
+ .process-total {
384
+ font-size: 8px;
385
+ color: #908888;
386
+ padding: 12px 4px 4px;
387
+ }
388
+
389
+ /* Child card accent colors */
390
+ .process_card[data-accent="purple"] {
391
+ background: linear-gradient(to bottom, #E8E0F0, #D8D0E8);
392
+ border-color: #A090C0;
393
+ }
394
+
395
+ .process_card[data-accent="amber"] {
396
+ background: linear-gradient(to bottom, #FFF0D0, #F0E4C0);
397
+ border-color: #C0A860;
398
+ }
399
+
400
+ .process_card[data-accent="cyan"] {
401
+ background: linear-gradient(to bottom, #D8F0F8, #C8E4F0);
402
+ border-color: #70A8C0;
403
+ }
404
+ ```
405
+
406
+ ---
407
+
408
+ ## Group_Box Control
409
+
410
+ A classic Windows-style group box with an inset label. Used by Process_Panel, Resource_Table, and other group-level controls.
411
+
412
+ ### Spec
413
+
414
+ ```javascript
415
+ {
416
+ __type_name: 'group_box',
417
+ title: 'Processes'
418
+ }
419
+ ```
420
+
421
+ ### Constructor
422
+
423
+ ```javascript
424
+ class Group_Box extends jsgui.Control {
425
+ constructor(spec = {}) {
426
+ spec.__type_name = spec.__type_name || 'group_box';
427
+ super(spec);
428
+ const { context } = this;
429
+
430
+ const compose = () => {
431
+ // Title overlay (positioned to interrupt the border)
432
+ if (spec.title) {
433
+ const title = new controls.div({ context, class: 'group-box-title' });
434
+ title.add(spec.title);
435
+ this.add(title);
436
+ }
437
+
438
+ // Content container
439
+ const content = new controls.div({ context, class: 'group-box-content' });
440
+ this.add(content);
441
+ this._content = content;
442
+ };
443
+
444
+ if (!spec.el) { compose(); }
445
+ }
446
+
447
+ // Override add to route children into content area
448
+ add_child(child) {
449
+ if (this._content) {
450
+ return this._content.add(child);
451
+ }
452
+ return super.add(child);
453
+ }
454
+ }
455
+
456
+ Group_Box.css = `
457
+ .group_box {
458
+ position: relative;
459
+ border: 1px solid #B0A898;
460
+ border-radius: 4px;
461
+ background: linear-gradient(to bottom, #FFFFFF, #F4F2EC);
462
+ padding: 20px 16px 12px;
463
+ box-shadow: 0 1px 3px rgba(0,0,0,0.12);
464
+ }
465
+
466
+ .group-box-title {
467
+ position: absolute;
468
+ top: -8px;
469
+ left: 10px;
470
+ background: linear-gradient(to bottom, #F0EDE6, #E8E4DC);
471
+ padding: 0 6px;
472
+ font-size: 11px;
473
+ font-weight: 600;
474
+ color: #2A4060;
475
+ }
476
+
477
+ .group-box-content {
478
+ display: flex;
479
+ flex-direction: column;
480
+ gap: 8px;
481
+ }
482
+ `;
483
+ ```
484
+
485
+ ---
486
+
487
+ ## Process Data Mapping
488
+
489
+ The Process_Panel maps data from the `/api/admin/processes` endpoint:
490
+
491
+ | API Field | Process_Card Spec | Notes |
492
+ |-----------|-------------------|-------|
493
+ | `main.pid` | `pid: data.main.pid` | Always available |
494
+ | `main.state` | `state: 'running'` | Derived from server._started |
495
+ | `main.memory.rss` | `memory_bytes: data.main.memory.rss` | From `process.memoryUsage()` |
496
+ | `main.uptime_seconds` | Not shown in card | Shown in status bar |
497
+ | `children[].name` | `name: child.name` | Resource name |
498
+ | `children[].pid` | `pid: child.pid` | From Process_Resource.pid |
499
+ | `children[].state` | `state: child.state` | Lifecycle state |
500
+ | `children[].memory.rss_bytes` | `memory_bytes: child.memory.rss_bytes` | From Process_Resource.memory_usage |
501
+ | `children[].restart_count` | `restart_count: child.restart_count` | Auto-restart counter |
502
+
503
+ ---
504
+
505
+ ## Actions
506
+
507
+ The Process_Panel will eventually support interactive actions:
508
+
509
+ | Action | UI Element | API Call |
510
+ |--------|-----------|----------|
511
+ | Restart child | Button on card (hover) | `POST /api/admin/action { "action":"restart_resource", "target": name }` |
512
+ | Stop child | Button on card (hover) | `POST /api/admin/action { "action":"stop_resource", "target": name }` |
513
+ | View stdout | Click on card | Opens Log_Viewer filtered to process |
514
+
515
+ These are Phase 2 features — the initial implementation is display-only.
516
+
517
+ ---
518
+
519
+ ## Real-Time Updates
520
+
521
+ The Process_Panel subscribes to SSE events for live state changes:
522
+
523
+ ```javascript
524
+ // In activate()
525
+ const event_source = new EventSource('/api/admin/events');
526
+
527
+ event_source.addEventListener('resource_state_change', (e) => {
528
+ const data = JSON.parse(e.data);
529
+ // Find matching child process card and update health badge
530
+ this._update_child_state(data.resourceName, data.to);
531
+ });
532
+
533
+ event_source.addEventListener('crashed', (e) => {
534
+ const data = JSON.parse(e.data);
535
+ this._update_child_state(data.resourceName, 'crashed');
536
+ });
537
+
538
+ event_source.addEventListener('recovered', (e) => {
539
+ const data = JSON.parse(e.data);
540
+ this._update_child_state(data.resourceName, 'running');
541
+ });
542
+ ```
543
+
544
+ This means the process panel never needs to poll — state changes are pushed instantly.