viberadar 0.3.210 → 0.3.212

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.
@@ -1782,8 +1782,6 @@ let loadSavedScripts = []; // [{ name, date, script }]
1782
1782
  let loadRuns = []; // saved k6 run history
1783
1783
  let loadScriptNameDraft = ''; // save name input draft
1784
1784
  let loadBaseUrlDraft = 'http://localhost:5000';
1785
- let loadVusDraft = 10;
1786
- let loadDurationDraft = '30s';
1787
1785
  let loadDataDirDraft = '';
1788
1786
  let loadResultDirDraft = '';
1789
1787
  let loadView = 'library'; // 'library' | 'editor'
@@ -7759,18 +7757,12 @@ function loadStatusLabel(status) {
7759
7757
  function applyLoadConfigToFields(cfg) {
7760
7758
  if (!cfg) return;
7761
7759
  loadBaseUrlDraft = cfg.baseUrl || loadBaseUrlDraft;
7762
- loadVusDraft = cfg.vus || loadVusDraft;
7763
- loadDurationDraft = cfg.duration || loadDurationDraft;
7764
7760
  loadDataDirDraft = cfg.dataDir || loadDataDirDraft;
7765
7761
  loadResultDirDraft = cfg.resultDir || loadResultDirDraft;
7766
7762
  const baseEl = document.getElementById('loadBaseUrl');
7767
- const vusEl = document.getElementById('loadVus');
7768
- const durEl = document.getElementById('loadDuration');
7769
7763
  const dataEl = document.getElementById('loadDataDir');
7770
7764
  const resultEl = document.getElementById('loadResultDir');
7771
7765
  if (baseEl) baseEl.value = loadBaseUrlDraft;
7772
- if (vusEl) vusEl.value = loadVusDraft;
7773
- if (durEl) durEl.value = loadDurationDraft;
7774
7766
  if (dataEl) dataEl.value = loadDataDirDraft;
7775
7767
  if (resultEl) resultEl.value = loadResultDirDraft;
7776
7768
  }
@@ -7807,7 +7799,7 @@ function renderLoad(c) {
7807
7799
  const cards = loadSavedScripts.map(s => `
7808
7800
  <div class="load-library-card" data-sname="${escapeHtml(s.name)}">
7809
7801
  <div class="load-library-card-name">${escapeHtml(s.name)}</div>
7810
- <div class="load-library-card-meta">${escapeHtml(s.date)} · ${s.vus || 10} VU · ${escapeHtml(s.duration || '30s')}</div>
7802
+ <div class="load-library-card-meta">${escapeHtml(s.date)}${s.dataDir ? ' · data: ' + escapeHtml(s.dataDir) : ''}</div>
7811
7803
  </div>`).join('');
7812
7804
  const runRows = loadRuns.slice(0, 12).map(r => {
7813
7805
  const summary = r.summary || {};
@@ -7816,7 +7808,7 @@ function renderLoad(c) {
7816
7808
  return `<div class="load-run-item" data-run-id="${escapeHtml(r.runId)}">
7817
7809
  <div class="load-run-main">
7818
7810
  <div class="load-run-name">${escapeHtml(r.scriptName || 'Без названия')}</div>
7819
- <div class="load-run-meta">${formatLoadRunDate(r.createdAt || r.startTime)} · ${cfg.vus || '—'} VU · ${escapeHtml(cfg.duration || '')} · ${loadStatusLabel(r.status)}</div>
7811
+ <div class="load-run-meta">${formatLoadRunDate(r.createdAt || r.startTime)} · ${escapeHtml(cfg.executionMode || 'auto')} · ${loadStatusLabel(r.status)}</div>
7820
7812
  </div>
7821
7813
  <div class="load-run-kpi" title="${escapeHtml(cfg.resultPath || '')}">${summary.rps != null ? Number(summary.rps || 0).toFixed(1) : '—'} RPS</div>
7822
7814
  <div class="load-run-kpi">p95 ${summary.p95Duration != null ? Math.round(summary.p95Duration || 0) + 'ms' : '—'}</div>
@@ -7834,12 +7826,12 @@ function renderLoad(c) {
7834
7826
  </div>
7835
7827
 
7836
7828
  ${loadSavedScripts.length === 0
7837
- ? `<div class="load-library-empty">
7838
- <div style="font-size:32px;margin-bottom:12px">📋</div>
7839
- <div style="font-size:14px;font-weight:500;margin-bottom:6px">Нет сохранённых тестов</div>
7840
- <div style="font-size:12px;color:var(--muted);margin-bottom:16px">Создай первый тест напиши k6 скрипт или сгенерируй через AI</div>
7841
- <button class="load-btn load-btn-run" onclick="loadNewTest()">+ Создать первый тест</button>
7842
- </div>`
7829
+ ? `<div class="load-library-empty">
7830
+ <div style="font-size:32px;margin-bottom:12px">📋</div>
7831
+ <div style="font-size:14px;font-weight:500;margin-bottom:6px">Нет сохранённых тестов</div>
7832
+ <div style="font-size:12px;color:var(--muted);margin-bottom:16px">Вставь готовый k6-скрипт и укажи папку с data-файлами при необходимости</div>
7833
+ <button class="load-btn load-btn-run" onclick="loadNewTest()">+ Создать первый тест</button>
7834
+ </div>`
7843
7835
  : `<div class="load-library-grid">${cards}</div>`
7844
7836
  }
7845
7837
 
@@ -7863,10 +7855,10 @@ function renderLoad(c) {
7863
7855
  const features = (D && D.features) || [];
7864
7856
  const featureOptions = features.map(f =>
7865
7857
  `<option value="${f.key}">${f.label || f.key}</option>`
7866
- ).join('');
7867
-
7858
+ ).join('');
7859
+
7868
7860
  if (!loadScriptDraft) {
7869
- loadScriptDraft = buildDefaultScript({ baseUrl: loadBaseUrlDraft, vus: loadVusDraft, duration: loadDurationDraft, endpoints: ['/'] });
7861
+ loadScriptDraft = buildDefaultScript({ baseUrl: loadBaseUrlDraft, endpoints: ['/'] });
7870
7862
  }
7871
7863
 
7872
7864
  const statusBadge = !loadState || loadState.status === 'idle' ? '' :
@@ -7887,21 +7879,13 @@ function renderLoad(c) {
7887
7879
 
7888
7880
  <div class="load-section">
7889
7881
  <div class="load-section-title">Конфигурация ${loadK6Version ? `<span style="color:var(--dim);font-weight:400">${escapeHtml(loadK6Version)}</span>` : ''}</div>
7890
- <div class="load-config-row">
7891
- <div class="load-config-field" style="flex:1;min-width:200px">
7882
+ <div class="load-config-row">
7883
+ <div class="load-config-field" style="flex:1;min-width:200px">
7892
7884
  <label>Base URL</label>
7893
7885
  <input id="loadBaseUrl" type="text" value="${escapeHtml(loadBaseUrlDraft)}" placeholder="http://localhost:5000" />
7894
7886
  </div>
7895
- <div class="load-config-field">
7896
- <label>VUs</label>
7897
- <input id="loadVus" type="number" value="${escapeHtml(String(loadVusDraft))}" min="1" max="10000" style="width:80px" />
7898
- </div>
7899
- <div class="load-config-field">
7900
- <label>Duration</label>
7901
- <input id="loadDuration" type="text" value="${escapeHtml(loadDurationDraft)}" style="width:80px" placeholder="30s" />
7902
- </div>
7903
7887
  </div>
7904
- <div class="load-config-hint">VUs и Duration применяются через CLI k6 и переопределяют значения из <code>export const options</code>. Base URL доступен в скрипте как <code>__ENV.BASE_URL</code>.</div>
7888
+ <div class="load-config-hint">Нагрузка, scenarios, thresholds и env-имена остаются в k6-скрипте. VibeRadar только передаёт <code>__ENV.BASE_URL</code>, файлы данных и сохраняет результаты.</div>
7905
7889
  <div class="load-config-row" style="margin-top:8px">
7906
7890
  <div class="load-config-field" style="flex:1;min-width:260px">
7907
7891
  <label>Data dir / file <span style="color:var(--dim);font-weight:400">(для <code>open('./users.csv')</code> и локальных lib)</span></label>
@@ -7918,30 +7902,12 @@ function renderLoad(c) {
7918
7902
  <label>Bearer Token <span style="color:var(--dim);font-weight:400;font-size:11px">(→ <code style="background:var(--bg2);padding:1px 4px;border-radius:3px">__ENV.TOKEN</code>)</span></label>
7919
7903
  <input id="loadToken" type="password" placeholder="Вставь Bearer-токен (необязательно)" style="font-family:monospace;font-size:12px" oninput="localStorage.setItem('vr_load_token', this.value)" />
7920
7904
  </div>
7921
- ${featureOptions ? `<div class="load-config-field">
7922
- <label>Фича (шаблон)</label>
7923
- <select id="loadFeature" style="width:150px">
7924
- <option value="">— выбрать —</option>
7925
- ${featureOptions}
7926
- </select>
7927
- </div>` : ''}
7928
- </div>
7929
- <div class="load-btns">
7930
- <button class="load-btn" onclick="loadGenerateScript()">⚙ Сгенерировать скрипт</button>
7931
- <button class="load-btn load-btn-run" id="loadRunBtn" onclick="runLoadTest()" ${isRunning ? 'disabled' : ''}>▶ Запустить</button>
7932
- <button class="load-btn load-btn-stop" id="loadStopBtn" onclick="stopLoadTest()" ${!isRunning ? 'disabled' : ''}>■ Стоп</button>
7933
- </div>
7934
- </div>
7935
-
7936
- <div class="load-section">
7937
- <div class="load-section-title">🤖 AI генерация скрипта</div>
7938
- <div style="font-size:11px;color:var(--muted);margin-bottom:6px">Опиши сценарий — агент найдёт эндпоинты в коде и сгенерирует k6-скрипт</div>
7939
- <div class="load-ai-prompt-wrap">
7940
- <textarea class="load-ai-prompt" id="loadAiPrompt" placeholder="Например: загрузка аудио .mp3 на /api/transcribe с полем language=ru, нужна авторизация Bearer-токеном, тестировать 20 VU 1 минуту&#10;&#10;Или: чат с RAG — POST /api/chat с body {message, knowledge_base_id, workspace_id}, stream:false">${escapeHtml(loadAiPromptDraft)}</textarea>
7941
- <button class="load-btn load-btn-ai" id="loadAiGenBtn" onclick="loadAiGenerateScript()" ${agentRunning ? 'disabled' : ''}>🤖 Сгенерировать<br>через AI</button>
7942
- </div>
7943
- <div class="load-ai-status" id="loadAiStatus">${loadAiGenerating ? '⏳ Агент генерирует скрипт… следи в терминале ↓' : ''}</div>
7944
- </div>
7905
+ </div>
7906
+ <div class="load-btns">
7907
+ <button class="load-btn load-btn-run" id="loadRunBtn" onclick="runLoadTest()" ${isRunning ? 'disabled' : ''}>▶ Запустить</button>
7908
+ <button class="load-btn load-btn-stop" id="loadStopBtn" onclick="stopLoadTest()" ${!isRunning ? 'disabled' : ''}>■ Стоп</button>
7909
+ </div>
7910
+ </div>
7945
7911
 
7946
7912
  <div class="load-section">
7947
7913
  <div class="load-section-title">k6 скрипт <span style="font-weight:400;color:var(--dim)">(редактируемый)</span></div>
@@ -8000,31 +7966,12 @@ function renderLoad(c) {
8000
7966
  const ta = document.getElementById('loadScriptEditor');
8001
7967
  if (ta) { ta.addEventListener('input', () => { loadScriptDraft = ta.value; }); }
8002
7968
  const baseInput = document.getElementById('loadBaseUrl');
8003
- const vusInput = document.getElementById('loadVus');
8004
- const durationInput = document.getElementById('loadDuration');
8005
7969
  const dataInput = document.getElementById('loadDataDir');
8006
7970
  const resultInput = document.getElementById('loadResultDir');
8007
7971
  if (baseInput) baseInput.addEventListener('input', () => { loadBaseUrlDraft = baseInput.value || 'http://localhost:5000'; });
8008
- if (vusInput) vusInput.addEventListener('input', () => { loadVusDraft = parseInt(vusInput.value || '10', 10) || 10; });
8009
- if (durationInput) durationInput.addEventListener('input', () => { loadDurationDraft = durationInput.value || '30s'; });
8010
7972
  if (dataInput) dataInput.addEventListener('input', () => { loadDataDirDraft = dataInput.value || ''; });
8011
7973
  if (resultInput) resultInput.addEventListener('input', () => { loadResultDirDraft = resultInput.value || ''; });
8012
7974
 
8013
- // Feature selector auto-generates script
8014
- const featSel = document.getElementById('loadFeature');
8015
- if (featSel) {
8016
- featSel.addEventListener('change', () => {
8017
- const fk = featSel.value;
8018
- if (!fk) return;
8019
- const script = generateScriptFromFeature(fk);
8020
- if (script) {
8021
- loadScriptDraft = script;
8022
- const ta2 = document.getElementById('loadScriptEditor');
8023
- if (ta2) ta2.value = script;
8024
- }
8025
- });
8026
- }
8027
-
8028
7975
  // Draw charts if we have data
8029
7976
  if (loadBuckets && loadBuckets.length > 0) {
8030
7977
  requestAnimationFrame(drawLoadCharts);
@@ -8044,8 +7991,6 @@ function loadOpenScript(name) {
8044
7991
  loadScriptDraft = s.script;
8045
7992
  loadScriptNameDraft = s.name;
8046
7993
  if (s.baseUrl) loadBaseUrlDraft = s.baseUrl;
8047
- if (s.vus) loadVusDraft = s.vus;
8048
- if (s.duration) loadDurationDraft = s.duration;
8049
7994
  loadDataDirDraft = s.dataDir || loadDataDirDraft;
8050
7995
  loadResultDirDraft = s.resultDir || loadResultDirDraft;
8051
7996
  loadView = 'editor';
@@ -8073,14 +8018,10 @@ async function runLoadTest() {
8073
8018
  const script = ta ? ta.value : loadScriptDraft;
8074
8019
  if (!script.trim()) { alert('Скрипт пустой — сначала сгенерируйте или напишите k6-скрипт'); return; }
8075
8020
  const baseUrl = (document.getElementById('loadBaseUrl')?.value || loadBaseUrlDraft || 'http://localhost:5000').trim();
8076
- const vus = parseInt(document.getElementById('loadVus')?.value || String(loadVusDraft || 10), 10) || 10;
8077
- const duration = (document.getElementById('loadDuration')?.value || loadDurationDraft || '30s').trim();
8078
8021
  const scriptName = (document.getElementById('loadScriptName')?.value || loadScriptNameDraft || 'Новый тест').trim();
8079
8022
  const dataDir = (document.getElementById('loadDataDir')?.value || loadDataDirDraft || '').trim();
8080
8023
  const resultDir = (document.getElementById('loadResultDir')?.value || loadResultDirDraft || '').trim();
8081
8024
  loadBaseUrlDraft = baseUrl;
8082
- loadVusDraft = vus;
8083
- loadDurationDraft = duration;
8084
8025
  loadScriptNameDraft = scriptName;
8085
8026
  loadDataDirDraft = dataDir;
8086
8027
  loadResultDirDraft = resultDir;
@@ -8095,7 +8036,7 @@ async function runLoadTest() {
8095
8036
  const r = await fetch('/api/load/run', {
8096
8037
  method: 'POST',
8097
8038
  headers: { 'Content-Type': 'application/json' },
8098
- body: JSON.stringify({ script, vus, duration, baseUrl, scriptName, dataDir, resultDir, envVars }),
8039
+ body: JSON.stringify({ script, baseUrl, scriptName, dataDir, resultDir, envVars }),
8099
8040
  });
8100
8041
  const d = await r.json();
8101
8042
  if (!r.ok) { alert('Ошибка запуска: ' + (d.error || r.status)); return; }
@@ -8176,7 +8117,7 @@ ${featureList || '(нет данных)'}
8176
8117
  **Шаг 2 — составь k6 скрипт.**
8177
8118
  Требования:
8178
8119
  1. Валидный JavaScript для k6 (import from 'k6/http', 'k6', 'k6/data')
8179
- 2. VUs и duration задаёт VibeRadar через CLI, поэтому не хардкодь нагрузку как единственный источник истины; если добавляешь \`export const options\`, оставь там только thresholds/summaryTrendStats или безопасные дефолты
8120
+ 2. Можно использовать \`options.scenarios\`; тогда VibeRadar в Auto-режиме не будет передавать \`--vus/--duration\`, а прокинет значения UI в \`__ENV.SMOKE_VUS\` и \`__ENV.SMOKE_DURATION\`
8180
8121
  3. \`export default function() { ... }\` с проверками \`check()\`
8181
8122
  4. Base URL бери из \`__ENV.BASE_URL || '${baseUrl}'\`
8182
8123
  5. Если нужна авторизация — добавь заголовок Authorization (Bearer-токен как переменную __ENV.TOKEN)
@@ -8293,21 +8234,17 @@ async function loadSaveScript() {
8293
8234
  const script = taEl ? taEl.value : loadScriptDraft;
8294
8235
  if (!script.trim()) { alert('Скрипт пустой'); return; }
8295
8236
  const baseUrl = (document.getElementById('loadBaseUrl')?.value || loadBaseUrlDraft || 'http://localhost:5000').trim();
8296
- const vus = parseInt(document.getElementById('loadVus')?.value || String(loadVusDraft || 10), 10) || 10;
8297
- const duration = (document.getElementById('loadDuration')?.value || loadDurationDraft || '30s').trim();
8298
8237
  const dataDir = (document.getElementById('loadDataDir')?.value || loadDataDirDraft || '').trim();
8299
8238
  const resultDir = (document.getElementById('loadResultDir')?.value || loadResultDirDraft || '').trim();
8300
8239
  loadScriptNameDraft = name;
8301
8240
  loadBaseUrlDraft = baseUrl;
8302
- loadVusDraft = vus;
8303
- loadDurationDraft = duration;
8304
8241
  loadDataDirDraft = dataDir;
8305
8242
  loadResultDirDraft = resultDir;
8306
8243
  try {
8307
8244
  const r = await fetch('/api/load/scripts', {
8308
8245
  method: 'POST',
8309
8246
  headers: { 'Content-Type': 'application/json' },
8310
- body: JSON.stringify({ name, script, baseUrl, vus, duration, dataDir, resultDir }),
8247
+ body: JSON.stringify({ name, script, baseUrl, dataDir, resultDir }),
8311
8248
  });
8312
8249
  if (!r.ok) { const d = await r.json().catch(() => ({})); alert('Ошибка: ' + (d.error || r.status)); return; }
8313
8250
  await loadRefreshScripts();
@@ -8323,8 +8260,6 @@ async function loadLoadScript(name) {
8323
8260
  loadScriptDraft = s.script;
8324
8261
  loadScriptNameDraft = s.name;
8325
8262
  if (s.baseUrl) loadBaseUrlDraft = s.baseUrl;
8326
- if (s.vus) loadVusDraft = s.vus;
8327
- if (s.duration) loadDurationDraft = s.duration;
8328
8263
  loadDataDirDraft = s.dataDir || loadDataDirDraft;
8329
8264
  loadResultDirDraft = s.resultDir || loadResultDirDraft;
8330
8265
  const ta = document.getElementById('loadScriptEditor');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viberadar",
3
- "version": "0.3.210",
3
+ "version": "0.3.212",
4
4
  "description": "Live module map with test coverage for vibecoding projects",
5
5
  "main": "./dist/cli.js",
6
6
  "bin": {