viberadar 0.3.225 → 0.3.226

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.
@@ -8473,7 +8473,7 @@ function updateLoadLiveStats() {
8473
8473
  }
8474
8474
 
8475
8475
  function formatLoadMetricMs(value) {
8476
- return value == null || !Number.isFinite(Number(value)) ? '' : `${Math.round(Number(value))} ms`;
8476
+ return value == null || !Number.isFinite(Number(value)) ? '-' : `${Math.round(Number(value))} ms`;
8477
8477
  }
8478
8478
 
8479
8479
  function loadEndpointLatencyColor(endpoint, summary) {
@@ -8525,33 +8525,40 @@ function renderLoadEndpointBreakdown(summary) {
8525
8525
  </div>`;
8526
8526
  }
8527
8527
 
8528
- async function copyLoadLog(btn) {
8529
- const text = (loadLogLines || []).join('\n');
8530
- if (!text.trim()) return;
8528
+ async function copyTextToClipboard(text) {
8529
+ if (navigator.clipboard && window.isSecureContext) {
8530
+ await navigator.clipboard.writeText(text);
8531
+ return;
8532
+ }
8533
+ const ta = document.createElement('textarea');
8534
+ ta.value = text;
8535
+ ta.style.position = 'fixed';
8536
+ ta.style.left = '-9999px';
8537
+ document.body.appendChild(ta);
8538
+ ta.focus();
8539
+ ta.select();
8540
+ document.execCommand('copy');
8541
+ ta.remove();
8542
+ }
8543
+
8544
+ async function copyLoadText(btn, text, fallbackLabel, errorPrefix) {
8545
+ if (!String(text || '').trim()) return;
8531
8546
  const original = btn ? btn.textContent : '';
8532
8547
  try {
8533
- if (navigator.clipboard && window.isSecureContext) {
8534
- await navigator.clipboard.writeText(text);
8535
- } else {
8536
- const ta = document.createElement('textarea');
8537
- ta.value = text;
8538
- ta.style.position = 'fixed';
8539
- ta.style.left = '-9999px';
8540
- document.body.appendChild(ta);
8541
- ta.focus();
8542
- ta.select();
8543
- document.execCommand('copy');
8544
- ta.remove();
8545
- }
8548
+ await copyTextToClipboard(text);
8546
8549
  if (btn) {
8547
8550
  btn.textContent = 'Скопировано';
8548
- setTimeout(() => { btn.textContent = original || 'Копировать лог'; }, 1400);
8551
+ setTimeout(() => { btn.textContent = original || fallbackLabel; }, 1400);
8549
8552
  }
8550
8553
  } catch (e) {
8551
- alert('Не удалось скопировать лог: ' + e.message);
8554
+ alert(errorPrefix + ': ' + e.message);
8552
8555
  }
8553
8556
  }
8554
8557
 
8558
+ async function copyLoadLog(btn) {
8559
+ await copyLoadText(btn, (loadLogLines || []).join('\n'), 'Копировать лог', 'Не удалось скопировать лог');
8560
+ }
8561
+
8555
8562
  function drawLoadChart(id, buckets, valFn, color, label) {
8556
8563
  const canvas = document.getElementById(id);
8557
8564
  if (!canvas) return;
@@ -9070,6 +9077,7 @@ function renderLoad(c) {
9070
9077
  </div>
9071
9078
  ${renderLoadEndpointBreakdown(summary)}
9072
9079
  <div class="load-btns" style="margin-top:12px">
9080
+ <button class="load-btn" onclick="copyLoadAnalysisPrompt(this)">Копировать отчёт для агента</button>
9073
9081
  <button class="load-btn" style="background:#1a2a3a;border-color:var(--blue);color:var(--blue)" onclick="loadAiAnalysis()">🤖 AI-анализ результатов</button>
9074
9082
  </div>
9075
9083
  </div>` : ''}
@@ -9191,32 +9199,31 @@ async function runLoadTest() {
9191
9199
  }
9192
9200
  }
9193
9201
 
9194
- async function stopLoadTest() {
9195
- try { await fetch('/api/load/stop', { method: 'POST' }); } catch {}
9196
- }
9197
-
9198
- async function loadAiAnalysis() {
9199
- if (!loadState || !loadState.summary) return;
9202
+ async function stopLoadTest() {
9203
+ try { await fetch('/api/load/stop', { method: 'POST' }); } catch {}
9204
+ }
9205
+
9206
+ function buildLoadAnalysisPrompt() {
9207
+ if (!loadState || !loadState.summary) return '';
9200
9208
  const summary = loadState.summary;
9201
9209
  const logs = loadState.logs || [];
9202
9210
  const totalRequests = Number(summary.totalRequests || loadState.totalRequests || 0);
9203
9211
  if (totalRequests <= 0 && logs.length === 0) {
9204
- alert('Для AI-анализа нет данных: в выбранном прогоне 0 запросов и пустой лог k6. Открой завершённый run с результатами или скопируй лог ошибки вручную.');
9205
- return;
9212
+ return '';
9206
9213
  }
9207
9214
  const endpointLines = Array.isArray(summary.endpoints) && summary.endpoints.length
9208
9215
  ? summary.endpoints.slice(0, 30).map(endpoint =>
9209
- `- ${endpoint.endpoint}: requests=${Math.round(endpoint.requests || 0)}, errors=${endpoint.errorPct == null ? '' : Number(endpoint.errorPct || 0).toFixed(2) + '%'}, avg=${Math.round(endpoint.avgDuration || 0)}ms, p90=${Math.round(endpoint.p90Duration || 0)}ms, p95=${Math.round(endpoint.p95Duration || 0)}ms, p99=${Math.round(endpoint.p99Duration || 0)}ms, max=${Math.round(endpoint.maxDuration || 0)}ms`
9216
+ `- ${endpoint.endpoint}: requests=${Math.round(endpoint.requests || 0)}, errors=${endpoint.errorPct == null ? '-' : Number(endpoint.errorPct || 0).toFixed(2) + '%'}, avg=${Math.round(endpoint.avgDuration || 0)}ms, p90=${Math.round(endpoint.p90Duration || 0)}ms, p95=${Math.round(endpoint.p95Duration || 0)}ms, p99=${Math.round(endpoint.p99Duration || 0)}ms, max=${Math.round(endpoint.maxDuration || 0)}ms`
9210
9217
  ).join('\n')
9211
9218
  : '(нет разбивки: в k6-скрипте нет тега endpoint или metrics.ndjson недоступен)';
9212
- const prompt = `Проанализируй результаты нагрузочного тестирования k6:
9219
+ return `Проанализируй результаты нагрузочного тестирования k6:
9213
9220
 
9214
- Run ID: ${loadState.runId || ''}
9215
- Status: ${loadState.status || ''}
9216
- Result path: ${loadState.config?.resultPath || ''}
9217
- Script: ${loadState.config?.scriptName || ''}
9218
- VUs: ${loadState.config?.vus || ''}
9219
- Duration: ${loadState.config?.duration || ''}
9221
+ Run ID: ${loadState.runId || '-'}
9222
+ Status: ${loadState.status || '-'}
9223
+ Result path: ${loadState.config?.resultPath || '-'}
9224
+ Script: ${loadState.config?.scriptName || '-'}
9225
+ VUs: ${loadState.config?.vus || '-'}
9226
+ Duration: ${loadState.config?.duration || '-'}
9220
9227
 
9221
9228
  RPS: ${(summary.rps||0).toFixed(2)}
9222
9229
  avg latency: ${Math.round(summary.avgDuration||0)}ms
@@ -9225,8 +9232,8 @@ p95 latency: ${Math.round(summary.p95Duration||0)}ms
9225
9232
  p99 latency: ${Math.round(summary.p99Duration||0)}ms
9226
9233
  Total requests: ${totalRequests}
9227
9234
  Error rate: ${(summary.errorPct||0).toFixed(2)}%
9228
- Checks failed: ${summary.checksFailed ?? ''}
9229
- Exit code: ${summary.exitCode ?? ''}
9235
+ Checks failed: ${summary.checksFailed ?? '-'}
9236
+ Exit code: ${summary.exitCode ?? '-'}
9230
9237
 
9231
9238
  Разбивка по endpoint:
9232
9239
  ${endpointLines}
@@ -9235,9 +9242,26 @@ ${endpointLines}
9235
9242
  ${logs.slice(-120).join('\n') || '(лог пустой)'}
9236
9243
 
9237
9244
  Оцени: производительность, узкие места, рекомендации по оптимизации.`;
9238
-
9239
- // Open agent terminal and send task
9240
- document.getElementById('agentPanel').classList.add('open');
9245
+ }
9246
+
9247
+ async function copyLoadAnalysisPrompt(btn) {
9248
+ const prompt = buildLoadAnalysisPrompt();
9249
+ if (!prompt) {
9250
+ alert('Для копирования нет данных: в выбранном прогоне 0 запросов и пустой лог k6. Открой завершённый run с результатами или скопируй лог ошибки вручную.');
9251
+ return;
9252
+ }
9253
+ await copyLoadText(btn, prompt, 'Копировать отчёт для агента', 'Не удалось скопировать отчёт');
9254
+ }
9255
+
9256
+ async function loadAiAnalysis() {
9257
+ const prompt = buildLoadAnalysisPrompt();
9258
+ if (!prompt) {
9259
+ alert('Для AI-анализа нет данных: в выбранном прогоне 0 запросов и пустой лог k6. Открой завершённый run с результатами или скопируй лог ошибки вручную.');
9260
+ return;
9261
+ }
9262
+
9263
+ // Open agent terminal and send task
9264
+ document.getElementById('agentPanel').classList.add('open');
9241
9265
  document.getElementById('termBtn').classList.add('term-active');
9242
9266
 
9243
9267
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viberadar",
3
- "version": "0.3.225",
3
+ "version": "0.3.226",
4
4
  "description": "Live module map with test coverage for vibecoding projects",
5
5
  "main": "./dist/cli.js",
6
6
  "bin": {