crackerjack 0.31.10__py3-none-any.whl → 0.31.12__py3-none-any.whl

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.

Potentially problematic release.


This version of crackerjack might be problematic. Click here for more details.

Files changed (155) hide show
  1. crackerjack/CLAUDE.md +288 -705
  2. crackerjack/__main__.py +22 -8
  3. crackerjack/agents/__init__.py +0 -3
  4. crackerjack/agents/architect_agent.py +0 -43
  5. crackerjack/agents/base.py +1 -9
  6. crackerjack/agents/coordinator.py +2 -148
  7. crackerjack/agents/documentation_agent.py +109 -81
  8. crackerjack/agents/dry_agent.py +122 -97
  9. crackerjack/agents/formatting_agent.py +3 -16
  10. crackerjack/agents/import_optimization_agent.py +1174 -130
  11. crackerjack/agents/performance_agent.py +956 -188
  12. crackerjack/agents/performance_helpers.py +229 -0
  13. crackerjack/agents/proactive_agent.py +1 -48
  14. crackerjack/agents/refactoring_agent.py +516 -246
  15. crackerjack/agents/refactoring_helpers.py +282 -0
  16. crackerjack/agents/security_agent.py +393 -90
  17. crackerjack/agents/test_creation_agent.py +1776 -120
  18. crackerjack/agents/test_specialist_agent.py +59 -15
  19. crackerjack/agents/tracker.py +0 -102
  20. crackerjack/api.py +145 -37
  21. crackerjack/cli/handlers.py +48 -30
  22. crackerjack/cli/interactive.py +11 -11
  23. crackerjack/cli/options.py +66 -4
  24. crackerjack/code_cleaner.py +808 -148
  25. crackerjack/config/global_lock_config.py +110 -0
  26. crackerjack/config/hooks.py +43 -64
  27. crackerjack/core/async_workflow_orchestrator.py +247 -97
  28. crackerjack/core/autofix_coordinator.py +192 -109
  29. crackerjack/core/enhanced_container.py +46 -63
  30. crackerjack/core/file_lifecycle.py +549 -0
  31. crackerjack/core/performance.py +9 -8
  32. crackerjack/core/performance_monitor.py +395 -0
  33. crackerjack/core/phase_coordinator.py +281 -94
  34. crackerjack/core/proactive_workflow.py +9 -58
  35. crackerjack/core/resource_manager.py +501 -0
  36. crackerjack/core/service_watchdog.py +490 -0
  37. crackerjack/core/session_coordinator.py +4 -8
  38. crackerjack/core/timeout_manager.py +504 -0
  39. crackerjack/core/websocket_lifecycle.py +475 -0
  40. crackerjack/core/workflow_orchestrator.py +343 -209
  41. crackerjack/dynamic_config.py +47 -6
  42. crackerjack/errors.py +3 -4
  43. crackerjack/executors/async_hook_executor.py +63 -13
  44. crackerjack/executors/cached_hook_executor.py +14 -14
  45. crackerjack/executors/hook_executor.py +100 -37
  46. crackerjack/executors/hook_lock_manager.py +856 -0
  47. crackerjack/executors/individual_hook_executor.py +120 -86
  48. crackerjack/intelligence/__init__.py +0 -7
  49. crackerjack/intelligence/adaptive_learning.py +13 -86
  50. crackerjack/intelligence/agent_orchestrator.py +15 -78
  51. crackerjack/intelligence/agent_registry.py +12 -59
  52. crackerjack/intelligence/agent_selector.py +31 -92
  53. crackerjack/intelligence/integration.py +1 -41
  54. crackerjack/interactive.py +9 -9
  55. crackerjack/managers/async_hook_manager.py +25 -8
  56. crackerjack/managers/hook_manager.py +9 -9
  57. crackerjack/managers/publish_manager.py +57 -59
  58. crackerjack/managers/test_command_builder.py +6 -36
  59. crackerjack/managers/test_executor.py +9 -61
  60. crackerjack/managers/test_manager.py +17 -63
  61. crackerjack/managers/test_manager_backup.py +77 -127
  62. crackerjack/managers/test_progress.py +4 -23
  63. crackerjack/mcp/cache.py +5 -12
  64. crackerjack/mcp/client_runner.py +10 -10
  65. crackerjack/mcp/context.py +64 -6
  66. crackerjack/mcp/dashboard.py +14 -11
  67. crackerjack/mcp/enhanced_progress_monitor.py +55 -55
  68. crackerjack/mcp/file_monitor.py +72 -42
  69. crackerjack/mcp/progress_components.py +103 -84
  70. crackerjack/mcp/progress_monitor.py +122 -49
  71. crackerjack/mcp/rate_limiter.py +12 -12
  72. crackerjack/mcp/server_core.py +16 -22
  73. crackerjack/mcp/service_watchdog.py +26 -26
  74. crackerjack/mcp/state.py +15 -0
  75. crackerjack/mcp/tools/core_tools.py +95 -39
  76. crackerjack/mcp/tools/error_analyzer.py +6 -32
  77. crackerjack/mcp/tools/execution_tools.py +1 -56
  78. crackerjack/mcp/tools/execution_tools_backup.py +35 -131
  79. crackerjack/mcp/tools/intelligence_tool_registry.py +0 -36
  80. crackerjack/mcp/tools/intelligence_tools.py +2 -55
  81. crackerjack/mcp/tools/monitoring_tools.py +308 -145
  82. crackerjack/mcp/tools/proactive_tools.py +12 -42
  83. crackerjack/mcp/tools/progress_tools.py +23 -15
  84. crackerjack/mcp/tools/utility_tools.py +3 -40
  85. crackerjack/mcp/tools/workflow_executor.py +40 -60
  86. crackerjack/mcp/websocket/app.py +0 -3
  87. crackerjack/mcp/websocket/endpoints.py +206 -268
  88. crackerjack/mcp/websocket/jobs.py +213 -66
  89. crackerjack/mcp/websocket/server.py +84 -6
  90. crackerjack/mcp/websocket/websocket_handler.py +137 -29
  91. crackerjack/models/config_adapter.py +3 -16
  92. crackerjack/models/protocols.py +162 -3
  93. crackerjack/models/resource_protocols.py +454 -0
  94. crackerjack/models/task.py +3 -3
  95. crackerjack/monitoring/__init__.py +0 -0
  96. crackerjack/monitoring/ai_agent_watchdog.py +25 -71
  97. crackerjack/monitoring/regression_prevention.py +28 -87
  98. crackerjack/orchestration/advanced_orchestrator.py +44 -78
  99. crackerjack/orchestration/coverage_improvement.py +10 -60
  100. crackerjack/orchestration/execution_strategies.py +16 -16
  101. crackerjack/orchestration/test_progress_streamer.py +61 -53
  102. crackerjack/plugins/base.py +1 -1
  103. crackerjack/plugins/managers.py +22 -20
  104. crackerjack/py313.py +65 -21
  105. crackerjack/services/backup_service.py +467 -0
  106. crackerjack/services/bounded_status_operations.py +627 -0
  107. crackerjack/services/cache.py +7 -9
  108. crackerjack/services/config.py +35 -52
  109. crackerjack/services/config_integrity.py +5 -16
  110. crackerjack/services/config_merge.py +542 -0
  111. crackerjack/services/contextual_ai_assistant.py +17 -19
  112. crackerjack/services/coverage_ratchet.py +44 -73
  113. crackerjack/services/debug.py +25 -39
  114. crackerjack/services/dependency_monitor.py +52 -50
  115. crackerjack/services/enhanced_filesystem.py +14 -11
  116. crackerjack/services/file_hasher.py +1 -1
  117. crackerjack/services/filesystem.py +1 -12
  118. crackerjack/services/git.py +71 -47
  119. crackerjack/services/health_metrics.py +31 -27
  120. crackerjack/services/initialization.py +276 -428
  121. crackerjack/services/input_validator.py +760 -0
  122. crackerjack/services/log_manager.py +16 -16
  123. crackerjack/services/logging.py +7 -6
  124. crackerjack/services/metrics.py +43 -43
  125. crackerjack/services/pattern_cache.py +2 -31
  126. crackerjack/services/pattern_detector.py +26 -63
  127. crackerjack/services/performance_benchmarks.py +20 -45
  128. crackerjack/services/regex_patterns.py +2887 -0
  129. crackerjack/services/regex_utils.py +537 -0
  130. crackerjack/services/secure_path_utils.py +683 -0
  131. crackerjack/services/secure_status_formatter.py +534 -0
  132. crackerjack/services/secure_subprocess.py +605 -0
  133. crackerjack/services/security.py +47 -10
  134. crackerjack/services/security_logger.py +492 -0
  135. crackerjack/services/server_manager.py +109 -50
  136. crackerjack/services/smart_scheduling.py +8 -25
  137. crackerjack/services/status_authentication.py +603 -0
  138. crackerjack/services/status_security_manager.py +442 -0
  139. crackerjack/services/thread_safe_status_collector.py +546 -0
  140. crackerjack/services/tool_version_service.py +1 -23
  141. crackerjack/services/unified_config.py +36 -58
  142. crackerjack/services/validation_rate_limiter.py +269 -0
  143. crackerjack/services/version_checker.py +9 -40
  144. crackerjack/services/websocket_resource_limiter.py +572 -0
  145. crackerjack/slash_commands/__init__.py +52 -2
  146. crackerjack/tools/__init__.py +0 -0
  147. crackerjack/tools/validate_input_validator_patterns.py +262 -0
  148. crackerjack/tools/validate_regex_patterns.py +198 -0
  149. {crackerjack-0.31.10.dist-info → crackerjack-0.31.12.dist-info}/METADATA +197 -12
  150. crackerjack-0.31.12.dist-info/RECORD +178 -0
  151. crackerjack/cli/facade.py +0 -104
  152. crackerjack-0.31.10.dist-info/RECORD +0 -149
  153. {crackerjack-0.31.10.dist-info → crackerjack-0.31.12.dist-info}/WHEEL +0 -0
  154. {crackerjack-0.31.10.dist-info → crackerjack-0.31.12.dist-info}/entry_points.txt +0 -0
  155. {crackerjack-0.31.10.dist-info → crackerjack-0.31.12.dist-info}/licenses/LICENSE +0 -0
@@ -4,11 +4,14 @@ from pathlib import Path
4
4
  from fastapi import FastAPI
5
5
  from fastapi.responses import HTMLResponse
6
6
 
7
+ from ...services.secure_status_formatter import (
8
+ format_secure_status,
9
+ get_secure_status_formatter,
10
+ )
7
11
  from .jobs import JobManager
8
12
 
9
13
 
10
14
  def _build_job_list(job_manager: JobManager, progress_dir: Path) -> list[dict]:
11
- """Build list of jobs from progress files."""
12
15
  jobs = []
13
16
  if not progress_dir.exists():
14
17
  return jobs
@@ -32,13 +35,12 @@ def _build_job_list(job_manager: JobManager, progress_dir: Path) -> list[dict]:
32
35
 
33
36
 
34
37
  def _build_status_response(job_manager: JobManager, jobs: list[dict]) -> dict:
35
- """Build the status response dictionary."""
36
38
  return {
37
39
  "status": "running",
38
40
  "message": "Crackerjack WebSocket Server",
39
41
  "active_connections": len(job_manager.active_connections),
40
42
  "jobs": jobs[:10],
41
- "websocket_url": "ws://localhost:8675/ws/progress/{job_id}",
43
+ "websocket_url": "ws://[INTERNAL_URL]/ws/progress/{job_id}",
42
44
  "endpoints": {
43
45
  "status": "/",
44
46
  "latest_job": "/latest",
@@ -49,8 +51,150 @@ def _build_status_response(job_manager: JobManager, jobs: list[dict]) -> dict:
49
51
  }
50
52
 
51
53
 
54
+ def _get_monitor_html(job_id: str) -> str:
55
+ """Generate secure HTML for job monitoring page."""
56
+ return f"""
57
+ <!DOCTYPE html>
58
+ <html>
59
+ <head>
60
+ <title>Job Monitor - {job_id}</title>
61
+ <meta charset="UTF-8">
62
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
63
+ <style>
64
+ body {{
65
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
66
+ margin: 0;
67
+ padding: 20px;
68
+ background-color: #f5f5f5;
69
+ }}
70
+ .container {{
71
+ max-width: 800px;
72
+ margin: 0 auto;
73
+ background: white;
74
+ padding: 30px;
75
+ border-radius: 10px;
76
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
77
+ }}
78
+ .header {{
79
+ text-align: center;
80
+ margin-bottom: 30px;
81
+ padding-bottom: 20px;
82
+ border-bottom: 2px solid #eee;
83
+ }}
84
+ .job-id {{
85
+ font-family: 'Courier New', monospace;
86
+ background: #f0f0f0;
87
+ padding: 5px 10px;
88
+ border-radius: 5px;
89
+ color: #666;
90
+ }}
91
+ .status {{
92
+ margin: 20px 0;
93
+ padding: 15px;
94
+ border-radius: 5px;
95
+ font-weight: bold;
96
+ }}
97
+ .status.running {{ background-color: #e3f2fd; color: #1976d2; }}
98
+ .status.completed {{ background-color: #e8f5e8; color: #388e3c; }}
99
+ .status.failed {{ background-color: #ffebee; color: #d32f2f; }}
100
+ .status.connecting {{ background-color: #fff3e0; color: #f57c00; }}
101
+ .log {{
102
+ margin: 20px 0;
103
+ padding: 15px;
104
+ background: #1e1e1e;
105
+ color: #fff;
106
+ font-family: 'Courier New', monospace;
107
+ border-radius: 5px;
108
+ max-height: 300px;
109
+ overflow-y: auto;
110
+ font-size: 12px;
111
+ line-height: 1.4;
112
+ }}
113
+ .connection-status {{
114
+ position: fixed;
115
+ top: 10px;
116
+ right: 10px;
117
+ padding: 5px 10px;
118
+ border-radius: 15px;
119
+ font-size: 12px;
120
+ font-weight: bold;
121
+ }}
122
+ .connected {{ background: #4caf50; color: white; }}
123
+ .disconnected {{ background: #f44336; color: white; }}
124
+ </style>
125
+ </head>
126
+ <body>
127
+ <div class="connection-status" id="connectionStatus">Connecting...</div>
128
+ <div class="container">
129
+ <div class="header">
130
+ <h1>🚀 Crackerjack Job Monitor</h1>
131
+ <p>Job ID: <span class="job-id">{job_id}</span></p>
132
+ </div>
133
+ <div class="status connecting" id="status">
134
+ Status: Connecting to job...
135
+ </div>
136
+ <div class="log" id="log">
137
+ <div>Connecting to WebSocket...</div>
138
+ </div>
139
+ </div>
140
+
141
+ <script>
142
+ const jobId = '{job_id}';
143
+ const wsUrl = `ws://[INTERNAL_URL]/ws/progress/${{jobId}}`;
144
+ let ws = null;
145
+
146
+ function updateConnectionStatus(status) {{
147
+ const elem = document.getElementById('connectionStatus');
148
+ elem.className = 'connection-status ' + status;
149
+ elem.textContent = status === 'connected' ? '🟢 Connected' : '🔴 Disconnected';
150
+ }}
151
+
152
+ function addLogEntry(message) {{
153
+ const log = document.getElementById('log');
154
+ const timestamp = new Date().toLocaleTimeString();
155
+ const entry = document.createElement('div');
156
+ entry.textContent = `[${{timestamp}}] ${{message}}`;
157
+ log.appendChild(entry);
158
+ log.scrollTop = log.scrollHeight;
159
+ }}
160
+
161
+ function connect() {{
162
+ ws = new WebSocket(wsUrl);
163
+
164
+ ws.onopen = function() {{
165
+ updateConnectionStatus('connected');
166
+ addLogEntry('Connected to WebSocket');
167
+ }};
168
+
169
+ ws.onmessage = function(event) {{
170
+ try {{
171
+ const data = JSON.parse(event.data);
172
+ addLogEntry(data.message || 'Progress update');
173
+ }} catch (e) {{
174
+ addLogEntry('Received: ' + event.data);
175
+ }}
176
+ }};
177
+
178
+ ws.onclose = function() {{
179
+ updateConnectionStatus('disconnected');
180
+ addLogEntry('WebSocket connection closed');
181
+ }};
182
+
183
+ ws.onerror = function() {{
184
+ updateConnectionStatus('disconnected');
185
+ addLogEntry('WebSocket error occurred');
186
+ }};
187
+ }}
188
+
189
+ // Start connection
190
+ connect();
191
+ </script>
192
+ </body>
193
+ </html>
194
+ """
195
+
196
+
52
197
  def _get_test_html() -> str:
53
- """Generate HTML content for test page."""
54
198
  return """
55
199
  <!DOCTYPE html>
56
200
  <html>
@@ -78,7 +222,7 @@ def _get_test_html() -> str:
78
222
  border-radius: 5px;
79
223
  }
80
224
  button {
81
- background: #007acc;
225
+ background: #007cba;
82
226
  color: white;
83
227
  border: none;
84
228
  padding: 10px 20px;
@@ -86,7 +230,9 @@ def _get_test_html() -> str:
86
230
  cursor: pointer;
87
231
  margin: 5px;
88
232
  }
89
- button:hover { background: #005999; }
233
+ button:hover {
234
+ background: #005a8b;
235
+ }
90
236
  input[type="text"] {
91
237
  padding: 8px;
92
238
  border: 1px solid #ddd;
@@ -100,12 +246,21 @@ def _get_test_html() -> str:
100
246
  border-radius: 5px;
101
247
  font-weight: bold;
102
248
  }
103
- .success { background: #d4edda; color: #155724; }
104
- .error { background: #f8d7da; color: #721c24; }
105
- .info { background: #d1ecf1; color: #0c5460; }
249
+ .success {
250
+ background: #d4edda;
251
+ color: #155724;
252
+ }
253
+ .error {
254
+ background: #f8d7da;
255
+ color: #721c24;
256
+ }
257
+ .info {
258
+ background: #d1ecf1;
259
+ color: #0c5460;
260
+ }
106
261
  #log {
107
262
  background: #1e1e1e;
108
- color: #ffffff;
263
+ color: #fff;
109
264
  padding: 15px;
110
265
  border-radius: 5px;
111
266
  font-family: 'Courier New', monospace;
@@ -260,246 +415,6 @@ def _get_test_html() -> str:
260
415
  """
261
416
 
262
417
 
263
- def _get_monitor_html(job_id: str) -> str:
264
- """Generate HTML content for job monitor page."""
265
- return f"""
266
- <!DOCTYPE html>
267
- <html>
268
- <head>
269
- <title>Job Monitor - {job_id}</title>
270
- <meta charset="UTF-8">
271
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
272
- <style>
273
- body {{
274
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
275
- margin: 0;
276
- padding: 20px;
277
- background-color: #f5f5f5;
278
- }}
279
- .container {{
280
- max-width: 800px;
281
- margin: 0 auto;
282
- background: white;
283
- padding: 30px;
284
- border-radius: 10px;
285
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
286
- }}
287
- .header {{
288
- text-align: center;
289
- margin-bottom: 30px;
290
- padding-bottom: 20px;
291
- border-bottom: 2px solid #007acc;
292
- }}
293
- .job-id {{
294
- font-family: 'Courier New', monospace;
295
- background: #f0f8ff;
296
- padding: 5px 10px;
297
- border-radius: 5px;
298
- color: #007acc;
299
- }}
300
- .status {{
301
- margin: 20px 0;
302
- padding: 15px;
303
- border-radius: 5px;
304
- font-weight: bold;
305
- }}
306
- .status.running {{ background-color: #fff3cd; color: #856404; }}
307
- .status.completed {{ background-color: #d4edda; color: #155724; }}
308
- .status.failed {{ background-color: #f8d7da; color: #721c24; }}
309
- .status.connecting {{ background-color: #cce7ff; color: #004085; }}
310
- .progress-bar {{
311
- width: 100%;
312
- height: 20px;
313
- background-color: #e9ecef;
314
- border-radius: 10px;
315
- overflow: hidden;
316
- margin: 10px 0;
317
- }}
318
- .progress-fill {{
319
- height: 100%;
320
- background-color: #007acc;
321
- width: 0%;
322
- transition: width 0.3s ease;
323
- }}
324
- .details {{
325
- margin: 20px 0;
326
- padding: 15px;
327
- background: #f8f9fa;
328
- border-radius: 5px;
329
- border-left: 4px solid #007acc;
330
- }}
331
- .log {{
332
- margin: 20px 0;
333
- padding: 15px;
334
- background: #1e1e1e;
335
- color: #ffffff;
336
- font-family: 'Courier New', monospace;
337
- border-radius: 5px;
338
- max-height: 300px;
339
- overflow-y: auto;
340
- font-size: 12px;
341
- line-height: 1.4;
342
- }}
343
- .connection-status {{
344
- position: fixed;
345
- top: 10px;
346
- right: 10px;
347
- padding: 5px 10px;
348
- border-radius: 15px;
349
- font-size: 12px;
350
- font-weight: bold;
351
- }}
352
- .connected {{ background: #d4edda; color: #155724; }}
353
- .disconnected {{ background: #f8d7da; color: #721c24; }}
354
- .reconnecting {{ background: #fff3cd; color: #856404; }}
355
- </style>
356
- </head>
357
- <body>
358
- <div class="connection-status" id="connectionStatus">Connecting...</div>
359
-
360
- <div class="container">
361
- <div class="header">
362
- <h1>🚀 Crackerjack Job Monitor</h1>
363
- <p>Job ID: <span class="job-id">{job_id}</span></p>
364
- </div>
365
-
366
- <div class="status connecting" id="status">
367
- Status: Connecting to job...
368
- </div>
369
-
370
- <div class="progress-bar">
371
- <div class="progress-fill" id="progressFill"></div>
372
- </div>
373
- <div id="progressText">Progress: 0%</div>
374
-
375
- <div class="details" id="details">
376
- <strong>Current Stage:</strong> <span id="currentStage">Initializing</span><br>
377
- <strong>Iteration:</strong> <span id="iteration">0</span> / <span id="maxIterations">10</span><br>
378
- <strong>Message:</strong> <span id="message">Connecting...</span>
379
- </div>
380
-
381
- <div class="log" id="log">
382
- <div>Connecting to WebSocket...</div>
383
- </div>
384
- </div>
385
-
386
- <script>
387
- const jobId = '{job_id}';
388
- const wsUrl = `ws://localhost:8675/ws/progress/${{jobId}}`;
389
- let ws = null;
390
- let reconnectAttempts = 0;
391
- const maxReconnectAttempts = 10;
392
-
393
- const elements = {{
394
- status: document.getElementById('status'),
395
- progressFill: document.getElementById('progressFill'),
396
- progressText: document.getElementById('progressText'),
397
- currentStage: document.getElementById('currentStage'),
398
- iteration: document.getElementById('iteration'),
399
- maxIterations: document.getElementById('maxIterations'),
400
- message: document.getElementById('message'),
401
- log: document.getElementById('log'),
402
- connectionStatus: document.getElementById('connectionStatus')
403
- }};
404
-
405
- function updateConnectionStatus(status) {{
406
- elements.connectionStatus.className = 'connection-status ' + status;
407
- elements.connectionStatus.textContent = {{
408
- 'connected': '🟢 Connected',
409
- 'disconnected': '🔴 Disconnected',
410
- 'reconnecting': '🟡 Reconnecting...'
411
- }}[status] || '⚪ Unknown';
412
- }}
413
-
414
- function addLogEntry(message, type = 'info') {{
415
- const timestamp = new Date().toLocaleTimeString();
416
- const logEntry = document.createElement('div');
417
- logEntry.textContent = `[${{timestamp}}] ${{message}}`;
418
- if (type === 'error') logEntry.style.color = '#ff6b6b';
419
- if (type === 'success') logEntry.style.color = '#51cf66';
420
- elements.log.appendChild(logEntry);
421
- elements.log.scrollTop = elements.log.scrollHeight;
422
- }}
423
-
424
- function updateProgress(data) {{
425
- const progress = data.overall_progress || 0;
426
- const status = data.status || 'unknown';
427
-
428
- elements.progressFill.style.width = progress + '%';
429
- elements.progressText.textContent = `Progress: ${{progress}}%`;
430
-
431
- elements.status.textContent = `Status: ${{status}}`;
432
- elements.status.className = 'status ' + status.toLowerCase();
433
-
434
- elements.currentStage.textContent = data.current_stage || 'Unknown';
435
- elements.iteration.textContent = data.iteration || 0;
436
- elements.maxIterations.textContent = data.max_iterations || 10;
437
- elements.message.textContent = data.message || 'No message';
438
-
439
- addLogEntry(`${{data.current_stage || 'Unknown stage'}}: ${{data.message || 'No message'}}`,
440
- status === 'failed' ? 'error' : status === 'completed' ? 'success' : 'info');
441
- }}
442
-
443
- function connect() {{
444
- if (ws && ws.readyState === WebSocket.OPEN) return;
445
-
446
- updateConnectionStatus('reconnecting');
447
- addLogEntry('Connecting to WebSocket...');
448
-
449
- ws = new WebSocket(wsUrl);
450
-
451
- ws.onopen = function() {{
452
- updateConnectionStatus('connected');
453
- addLogEntry('Connected to WebSocket', 'success');
454
- reconnectAttempts = 0;
455
- }};
456
-
457
- ws.onmessage = function(event) {{
458
- try {{
459
- const data = JSON.parse(event.data);
460
- updateProgress(data);
461
- }} catch (e) {{
462
- addLogEntry('Error parsing message: ' + e.message, 'error');
463
- }}
464
- }};
465
-
466
- ws.onclose = function() {{
467
- updateConnectionStatus('disconnected');
468
- addLogEntry('WebSocket connection closed');
469
- if (reconnectAttempts < maxReconnectAttempts) {{
470
- setTimeout(() => {{
471
- reconnectAttempts++;
472
- addLogEntry(`Attempting to reconnect (${{reconnectAttempts}}/${{maxReconnectAttempts}})...`);
473
- connect();
474
- }}, 2000);
475
- }} else {{
476
- addLogEntry('Maximum reconnection attempts reached', 'error');
477
- }}
478
- }};
479
-
480
- ws.onerror = function(error) {{
481
- addLogEntry('WebSocket error occurred', 'error');
482
- updateConnectionStatus('disconnected');
483
- }};
484
- }}
485
-
486
- // Start connection
487
- connect();
488
-
489
- // Periodically check connection health
490
- setInterval(() => {{
491
- if (!ws || ws.readyState !== WebSocket.OPEN) {{
492
- if (reconnectAttempts < maxReconnectAttempts) {{
493
- connect();
494
- }}
495
- }}
496
- }}, 5000);
497
- </script>
498
- </body>
499
- </html>
500
- """
501
-
502
-
503
418
  def register_endpoints(
504
419
  app: FastAPI,
505
420
  job_manager: JobManager,
@@ -508,10 +423,25 @@ def register_endpoints(
508
423
  @app.get("/")
509
424
  async def get_status():
510
425
  try:
426
+ # Build raw status response
511
427
  jobs = _build_job_list(job_manager, progress_dir)
512
- return _build_status_response(job_manager, jobs)
428
+ raw_status = _build_status_response(job_manager, jobs)
429
+
430
+ # Apply secure formatting
431
+ secure_status = format_secure_status(
432
+ raw_status,
433
+ project_root=progress_dir.parent,
434
+ user_context="websocket_client",
435
+ )
436
+
437
+ return secure_status
513
438
  except Exception as e:
514
- return {"status": "error", "message": str(e)}
439
+ # Use secure error formatting
440
+ formatter = get_secure_status_formatter()
441
+ error_response = formatter.format_error_response(
442
+ str(e),
443
+ )
444
+ return error_response
515
445
 
516
446
  @app.get("/latest")
517
447
  async def get_latest_job():
@@ -519,31 +449,39 @@ def register_endpoints(
519
449
  latest_job_id = job_manager.get_latest_job_id()
520
450
 
521
451
  if not latest_job_id:
522
- return {
452
+ raw_response = {
523
453
  "status": "no_jobs",
524
454
  "message": "No jobs found",
525
455
  "job_id": None,
526
456
  "progress": None,
527
457
  }
458
+ else:
459
+ progress_data = job_manager.get_job_progress(latest_job_id)
460
+ raw_response = {
461
+ "status": "success",
462
+ "message": f"Latest job: {latest_job_id}",
463
+ "job_id": latest_job_id,
464
+ "progress": progress_data,
465
+ "websocket_url": f"ws://[INTERNAL_URL]/ws/progress/{latest_job_id}",
466
+ "monitor_url": f"http://[INTERNAL_URL]/monitor/{latest_job_id}",
467
+ }
528
468
 
529
- progress_data = job_manager.get_job_progress(latest_job_id)
469
+ # Apply secure formatting
470
+ secure_response = format_secure_status(
471
+ raw_response,
472
+ project_root=progress_dir.parent,
473
+ user_context="websocket_client",
474
+ )
530
475
 
531
- return {
532
- "status": "success",
533
- "message": f"Latest job: {latest_job_id}",
534
- "job_id": latest_job_id,
535
- "progress": progress_data,
536
- "websocket_url": f"ws://localhost:8675/ws/progress/{latest_job_id}",
537
- "monitor_url": f"http://localhost:8675/monitor/{latest_job_id}",
538
- }
476
+ return secure_response
539
477
 
540
478
  except Exception as e:
541
- return {
542
- "status": "error",
543
- "message": f"Failed to get latest job: {e}",
544
- "job_id": None,
545
- "progress": None,
546
- }
479
+ # Use secure error formatting
480
+ formatter = get_secure_status_formatter()
481
+ error_response = formatter.format_error_response(
482
+ f"Failed to get latest job: {e}",
483
+ )
484
+ return error_response
547
485
 
548
486
  @app.get("/monitor/{job_id}")
549
487
  async def get_job_monitor_page(job_id: str):