viberadar 0.3.211 → 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,13 +1782,8 @@ 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
- let loadExecutionModeDraft = 'auto';
1790
- let loadVusEnvNameDraft = 'SMOKE_VUS';
1791
- let loadDurationEnvNameDraft = 'SMOKE_DURATION';
1792
1787
  let loadView = 'library'; // 'library' | 'editor'
1793
1788
 
1794
1789
  function toggleObsHint(id) {
@@ -7762,29 +7757,14 @@ function loadStatusLabel(status) {
7762
7757
  function applyLoadConfigToFields(cfg) {
7763
7758
  if (!cfg) return;
7764
7759
  loadBaseUrlDraft = cfg.baseUrl || loadBaseUrlDraft;
7765
- loadVusDraft = cfg.vus || loadVusDraft;
7766
- loadDurationDraft = cfg.duration || loadDurationDraft;
7767
7760
  loadDataDirDraft = cfg.dataDir || loadDataDirDraft;
7768
7761
  loadResultDirDraft = cfg.resultDir || loadResultDirDraft;
7769
- loadExecutionModeDraft = cfg.executionMode || loadExecutionModeDraft;
7770
- loadVusEnvNameDraft = cfg.vusEnvName || loadVusEnvNameDraft;
7771
- loadDurationEnvNameDraft = cfg.durationEnvName || loadDurationEnvNameDraft;
7772
7762
  const baseEl = document.getElementById('loadBaseUrl');
7773
- const vusEl = document.getElementById('loadVus');
7774
- const durEl = document.getElementById('loadDuration');
7775
7763
  const dataEl = document.getElementById('loadDataDir');
7776
7764
  const resultEl = document.getElementById('loadResultDir');
7777
- const modeEl = document.getElementById('loadExecutionMode');
7778
- const vusEnvEl = document.getElementById('loadVusEnvName');
7779
- const durationEnvEl = document.getElementById('loadDurationEnvName');
7780
7765
  if (baseEl) baseEl.value = loadBaseUrlDraft;
7781
- if (vusEl) vusEl.value = loadVusDraft;
7782
- if (durEl) durEl.value = loadDurationDraft;
7783
7766
  if (dataEl) dataEl.value = loadDataDirDraft;
7784
7767
  if (resultEl) resultEl.value = loadResultDirDraft;
7785
- if (modeEl) modeEl.value = loadExecutionModeDraft;
7786
- if (vusEnvEl) vusEnvEl.value = loadVusEnvNameDraft;
7787
- if (durationEnvEl) durationEnvEl.value = loadDurationEnvNameDraft;
7788
7768
  }
7789
7769
 
7790
7770
  function renderLoad(c) {
@@ -7819,7 +7799,7 @@ function renderLoad(c) {
7819
7799
  const cards = loadSavedScripts.map(s => `
7820
7800
  <div class="load-library-card" data-sname="${escapeHtml(s.name)}">
7821
7801
  <div class="load-library-card-name">${escapeHtml(s.name)}</div>
7822
- <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>
7823
7803
  </div>`).join('');
7824
7804
  const runRows = loadRuns.slice(0, 12).map(r => {
7825
7805
  const summary = r.summary || {};
@@ -7828,7 +7808,7 @@ function renderLoad(c) {
7828
7808
  return `<div class="load-run-item" data-run-id="${escapeHtml(r.runId)}">
7829
7809
  <div class="load-run-main">
7830
7810
  <div class="load-run-name">${escapeHtml(r.scriptName || 'Без названия')}</div>
7831
- <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>
7832
7812
  </div>
7833
7813
  <div class="load-run-kpi" title="${escapeHtml(cfg.resultPath || '')}">${summary.rps != null ? Number(summary.rps || 0).toFixed(1) : '—'} RPS</div>
7834
7814
  <div class="load-run-kpi">p95 ${summary.p95Duration != null ? Math.round(summary.p95Duration || 0) + 'ms' : '—'}</div>
@@ -7846,12 +7826,12 @@ function renderLoad(c) {
7846
7826
  </div>
7847
7827
 
7848
7828
  ${loadSavedScripts.length === 0
7849
- ? `<div class="load-library-empty">
7850
- <div style="font-size:32px;margin-bottom:12px">📋</div>
7851
- <div style="font-size:14px;font-weight:500;margin-bottom:6px">Нет сохранённых тестов</div>
7852
- <div style="font-size:12px;color:var(--muted);margin-bottom:16px">Создай первый тест напиши k6 скрипт или сгенерируй через AI</div>
7853
- <button class="load-btn load-btn-run" onclick="loadNewTest()">+ Создать первый тест</button>
7854
- </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>`
7855
7835
  : `<div class="load-library-grid">${cards}</div>`
7856
7836
  }
7857
7837
 
@@ -7875,10 +7855,10 @@ function renderLoad(c) {
7875
7855
  const features = (D && D.features) || [];
7876
7856
  const featureOptions = features.map(f =>
7877
7857
  `<option value="${f.key}">${f.label || f.key}</option>`
7878
- ).join('');
7879
-
7858
+ ).join('');
7859
+
7880
7860
  if (!loadScriptDraft) {
7881
- loadScriptDraft = buildDefaultScript({ baseUrl: loadBaseUrlDraft, vus: loadVusDraft, duration: loadDurationDraft, endpoints: ['/'] });
7861
+ loadScriptDraft = buildDefaultScript({ baseUrl: loadBaseUrlDraft, endpoints: ['/'] });
7882
7862
  }
7883
7863
 
7884
7864
  const statusBadge = !loadState || loadState.status === 'idle' ? '' :
@@ -7899,40 +7879,13 @@ function renderLoad(c) {
7899
7879
 
7900
7880
  <div class="load-section">
7901
7881
  <div class="load-section-title">Конфигурация ${loadK6Version ? `<span style="color:var(--dim);font-weight:400">${escapeHtml(loadK6Version)}</span>` : ''}</div>
7902
- <div class="load-config-row">
7903
- <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">
7904
7884
  <label>Base URL</label>
7905
7885
  <input id="loadBaseUrl" type="text" value="${escapeHtml(loadBaseUrlDraft)}" placeholder="http://localhost:5000" />
7906
7886
  </div>
7907
- <div class="load-config-field">
7908
- <label>VUs</label>
7909
- <input id="loadVus" type="number" value="${escapeHtml(String(loadVusDraft))}" min="1" max="10000" style="width:80px" />
7910
- </div>
7911
- <div class="load-config-field">
7912
- <label>Duration</label>
7913
- <input id="loadDuration" type="text" value="${escapeHtml(loadDurationDraft)}" style="width:80px" placeholder="30s" />
7914
- </div>
7915
7887
  </div>
7916
- <div class="load-config-hint">VUs и Duration применяются через CLI k6 и переопределяют значения из <code>export const options</code>. Base URL доступен в скрипте как <code>__ENV.BASE_URL</code>.</div>
7917
- <div class="load-config-row" style="margin-top:8px">
7918
- <div class="load-config-field">
7919
- <label>Execution</label>
7920
- <select id="loadExecutionMode" style="width:150px">
7921
- <option value="auto" ${loadExecutionModeDraft === 'auto' ? 'selected' : ''}>Auto</option>
7922
- <option value="cli" ${loadExecutionModeDraft === 'cli' ? 'selected' : ''}>CLI override</option>
7923
- <option value="script" ${loadExecutionModeDraft === 'script' ? 'selected' : ''}>Script scenarios</option>
7924
- </select>
7925
- </div>
7926
- <div class="load-config-field">
7927
- <label>VUs env</label>
7928
- <input id="loadVusEnvName" type="text" value="${escapeHtml(loadVusEnvNameDraft)}" style="width:130px" placeholder="SMOKE_VUS" />
7929
- </div>
7930
- <div class="load-config-field">
7931
- <label>Duration env</label>
7932
- <input id="loadDurationEnvName" type="text" value="${escapeHtml(loadDurationEnvNameDraft)}" style="width:150px" placeholder="SMOKE_DURATION" />
7933
- </div>
7934
- </div>
7935
- <div class="load-config-hint">Auto: если скрипт содержит <code>options.scenarios</code>, VibeRadar не передаёт <code>--vus/--duration</code>, а кладёт значения в env-переменные, например <code>SMOKE_VUS</code> и <code>SMOKE_DURATION</code>.</div>
7888
+ <div class="load-config-hint">Нагрузка, scenarios, thresholds и env-имена остаются в k6-скрипте. VibeRadar только передаёт <code>__ENV.BASE_URL</code>, файлы данных и сохраняет результаты.</div>
7936
7889
  <div class="load-config-row" style="margin-top:8px">
7937
7890
  <div class="load-config-field" style="flex:1;min-width:260px">
7938
7891
  <label>Data dir / file <span style="color:var(--dim);font-weight:400">(для <code>open('./users.csv')</code> и локальных lib)</span></label>
@@ -7949,30 +7902,12 @@ function renderLoad(c) {
7949
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>
7950
7903
  <input id="loadToken" type="password" placeholder="Вставь Bearer-токен (необязательно)" style="font-family:monospace;font-size:12px" oninput="localStorage.setItem('vr_load_token', this.value)" />
7951
7904
  </div>
7952
- ${featureOptions ? `<div class="load-config-field">
7953
- <label>Фича (шаблон)</label>
7954
- <select id="loadFeature" style="width:150px">
7955
- <option value="">— выбрать —</option>
7956
- ${featureOptions}
7957
- </select>
7958
- </div>` : ''}
7959
- </div>
7960
- <div class="load-btns">
7961
- <button class="load-btn" onclick="loadGenerateScript()">⚙ Сгенерировать скрипт</button>
7962
- <button class="load-btn load-btn-run" id="loadRunBtn" onclick="runLoadTest()" ${isRunning ? 'disabled' : ''}>▶ Запустить</button>
7963
- <button class="load-btn load-btn-stop" id="loadStopBtn" onclick="stopLoadTest()" ${!isRunning ? 'disabled' : ''}>■ Стоп</button>
7964
- </div>
7965
- </div>
7966
-
7967
- <div class="load-section">
7968
- <div class="load-section-title">🤖 AI генерация скрипта</div>
7969
- <div style="font-size:11px;color:var(--muted);margin-bottom:6px">Опиши сценарий — агент найдёт эндпоинты в коде и сгенерирует k6-скрипт</div>
7970
- <div class="load-ai-prompt-wrap">
7971
- <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>
7972
- <button class="load-btn load-btn-ai" id="loadAiGenBtn" onclick="loadAiGenerateScript()" ${agentRunning ? 'disabled' : ''}>🤖 Сгенерировать<br>через AI</button>
7973
- </div>
7974
- <div class="load-ai-status" id="loadAiStatus">${loadAiGenerating ? '⏳ Агент генерирует скрипт… следи в терминале ↓' : ''}</div>
7975
- </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>
7976
7911
 
7977
7912
  <div class="load-section">
7978
7913
  <div class="load-section-title">k6 скрипт <span style="font-weight:400;color:var(--dim)">(редактируемый)</span></div>
@@ -8031,36 +7966,11 @@ function renderLoad(c) {
8031
7966
  const ta = document.getElementById('loadScriptEditor');
8032
7967
  if (ta) { ta.addEventListener('input', () => { loadScriptDraft = ta.value; }); }
8033
7968
  const baseInput = document.getElementById('loadBaseUrl');
8034
- const vusInput = document.getElementById('loadVus');
8035
- const durationInput = document.getElementById('loadDuration');
8036
7969
  const dataInput = document.getElementById('loadDataDir');
8037
7970
  const resultInput = document.getElementById('loadResultDir');
8038
- const modeInput = document.getElementById('loadExecutionMode');
8039
- const vusEnvInput = document.getElementById('loadVusEnvName');
8040
- const durationEnvInput = document.getElementById('loadDurationEnvName');
8041
7971
  if (baseInput) baseInput.addEventListener('input', () => { loadBaseUrlDraft = baseInput.value || 'http://localhost:5000'; });
8042
- if (vusInput) vusInput.addEventListener('input', () => { loadVusDraft = parseInt(vusInput.value || '10', 10) || 10; });
8043
- if (durationInput) durationInput.addEventListener('input', () => { loadDurationDraft = durationInput.value || '30s'; });
8044
7972
  if (dataInput) dataInput.addEventListener('input', () => { loadDataDirDraft = dataInput.value || ''; });
8045
7973
  if (resultInput) resultInput.addEventListener('input', () => { loadResultDirDraft = resultInput.value || ''; });
8046
- if (modeInput) modeInput.addEventListener('change', () => { loadExecutionModeDraft = modeInput.value || 'auto'; });
8047
- if (vusEnvInput) vusEnvInput.addEventListener('input', () => { loadVusEnvNameDraft = vusEnvInput.value || 'SMOKE_VUS'; });
8048
- if (durationEnvInput) durationEnvInput.addEventListener('input', () => { loadDurationEnvNameDraft = durationEnvInput.value || 'SMOKE_DURATION'; });
8049
-
8050
- // Feature selector auto-generates script
8051
- const featSel = document.getElementById('loadFeature');
8052
- if (featSel) {
8053
- featSel.addEventListener('change', () => {
8054
- const fk = featSel.value;
8055
- if (!fk) return;
8056
- const script = generateScriptFromFeature(fk);
8057
- if (script) {
8058
- loadScriptDraft = script;
8059
- const ta2 = document.getElementById('loadScriptEditor');
8060
- if (ta2) ta2.value = script;
8061
- }
8062
- });
8063
- }
8064
7974
 
8065
7975
  // Draw charts if we have data
8066
7976
  if (loadBuckets && loadBuckets.length > 0) {
@@ -8081,13 +7991,8 @@ function loadOpenScript(name) {
8081
7991
  loadScriptDraft = s.script;
8082
7992
  loadScriptNameDraft = s.name;
8083
7993
  if (s.baseUrl) loadBaseUrlDraft = s.baseUrl;
8084
- if (s.vus) loadVusDraft = s.vus;
8085
- if (s.duration) loadDurationDraft = s.duration;
8086
7994
  loadDataDirDraft = s.dataDir || loadDataDirDraft;
8087
7995
  loadResultDirDraft = s.resultDir || loadResultDirDraft;
8088
- loadExecutionModeDraft = s.executionMode || loadExecutionModeDraft;
8089
- loadVusEnvNameDraft = s.vusEnvName || loadVusEnvNameDraft;
8090
- loadDurationEnvNameDraft = s.durationEnvName || loadDurationEnvNameDraft;
8091
7996
  loadView = 'editor';
8092
7997
  renderContent();
8093
7998
  }
@@ -8113,24 +8018,13 @@ async function runLoadTest() {
8113
8018
  const script = ta ? ta.value : loadScriptDraft;
8114
8019
  if (!script.trim()) { alert('Скрипт пустой — сначала сгенерируйте или напишите k6-скрипт'); return; }
8115
8020
  const baseUrl = (document.getElementById('loadBaseUrl')?.value || loadBaseUrlDraft || 'http://localhost:5000').trim();
8116
- const vus = parseInt(document.getElementById('loadVus')?.value || String(loadVusDraft || 10), 10) || 10;
8117
- const duration = (document.getElementById('loadDuration')?.value || loadDurationDraft || '30s').trim();
8118
8021
  const scriptName = (document.getElementById('loadScriptName')?.value || loadScriptNameDraft || 'Новый тест').trim();
8119
8022
  const dataDir = (document.getElementById('loadDataDir')?.value || loadDataDirDraft || '').trim();
8120
8023
  const resultDir = (document.getElementById('loadResultDir')?.value || loadResultDirDraft || '').trim();
8121
- const executionModeRaw = (document.getElementById('loadExecutionMode')?.value || loadExecutionModeDraft || 'auto').trim();
8122
- const executionMode = executionModeRaw === 'auto' ? undefined : executionModeRaw;
8123
- const vusEnvName = (document.getElementById('loadVusEnvName')?.value || loadVusEnvNameDraft || 'SMOKE_VUS').trim();
8124
- const durationEnvName = (document.getElementById('loadDurationEnvName')?.value || loadDurationEnvNameDraft || 'SMOKE_DURATION').trim();
8125
8024
  loadBaseUrlDraft = baseUrl;
8126
- loadVusDraft = vus;
8127
- loadDurationDraft = duration;
8128
8025
  loadScriptNameDraft = scriptName;
8129
8026
  loadDataDirDraft = dataDir;
8130
8027
  loadResultDirDraft = resultDir;
8131
- loadExecutionModeDraft = executionModeRaw;
8132
- loadVusEnvNameDraft = vusEnvName;
8133
- loadDurationEnvNameDraft = durationEnvName;
8134
8028
 
8135
8029
  loadLogLines = [];
8136
8030
  loadBuckets = [];
@@ -8142,7 +8036,7 @@ async function runLoadTest() {
8142
8036
  const r = await fetch('/api/load/run', {
8143
8037
  method: 'POST',
8144
8038
  headers: { 'Content-Type': 'application/json' },
8145
- body: JSON.stringify({ script, vus, duration, baseUrl, scriptName, dataDir, resultDir, executionMode, vusEnvName, durationEnvName, envVars }),
8039
+ body: JSON.stringify({ script, baseUrl, scriptName, dataDir, resultDir, envVars }),
8146
8040
  });
8147
8041
  const d = await r.json();
8148
8042
  if (!r.ok) { alert('Ошибка запуска: ' + (d.error || r.status)); return; }
@@ -8340,27 +8234,17 @@ async function loadSaveScript() {
8340
8234
  const script = taEl ? taEl.value : loadScriptDraft;
8341
8235
  if (!script.trim()) { alert('Скрипт пустой'); return; }
8342
8236
  const baseUrl = (document.getElementById('loadBaseUrl')?.value || loadBaseUrlDraft || 'http://localhost:5000').trim();
8343
- const vus = parseInt(document.getElementById('loadVus')?.value || String(loadVusDraft || 10), 10) || 10;
8344
- const duration = (document.getElementById('loadDuration')?.value || loadDurationDraft || '30s').trim();
8345
8237
  const dataDir = (document.getElementById('loadDataDir')?.value || loadDataDirDraft || '').trim();
8346
8238
  const resultDir = (document.getElementById('loadResultDir')?.value || loadResultDirDraft || '').trim();
8347
- const executionMode = (document.getElementById('loadExecutionMode')?.value || loadExecutionModeDraft || 'auto').trim();
8348
- const vusEnvName = (document.getElementById('loadVusEnvName')?.value || loadVusEnvNameDraft || 'SMOKE_VUS').trim();
8349
- const durationEnvName = (document.getElementById('loadDurationEnvName')?.value || loadDurationEnvNameDraft || 'SMOKE_DURATION').trim();
8350
8239
  loadScriptNameDraft = name;
8351
8240
  loadBaseUrlDraft = baseUrl;
8352
- loadVusDraft = vus;
8353
- loadDurationDraft = duration;
8354
8241
  loadDataDirDraft = dataDir;
8355
8242
  loadResultDirDraft = resultDir;
8356
- loadExecutionModeDraft = executionMode;
8357
- loadVusEnvNameDraft = vusEnvName;
8358
- loadDurationEnvNameDraft = durationEnvName;
8359
8243
  try {
8360
8244
  const r = await fetch('/api/load/scripts', {
8361
8245
  method: 'POST',
8362
8246
  headers: { 'Content-Type': 'application/json' },
8363
- body: JSON.stringify({ name, script, baseUrl, vus, duration, dataDir, resultDir, executionMode, vusEnvName, durationEnvName }),
8247
+ body: JSON.stringify({ name, script, baseUrl, dataDir, resultDir }),
8364
8248
  });
8365
8249
  if (!r.ok) { const d = await r.json().catch(() => ({})); alert('Ошибка: ' + (d.error || r.status)); return; }
8366
8250
  await loadRefreshScripts();
@@ -8376,13 +8260,8 @@ async function loadLoadScript(name) {
8376
8260
  loadScriptDraft = s.script;
8377
8261
  loadScriptNameDraft = s.name;
8378
8262
  if (s.baseUrl) loadBaseUrlDraft = s.baseUrl;
8379
- if (s.vus) loadVusDraft = s.vus;
8380
- if (s.duration) loadDurationDraft = s.duration;
8381
8263
  loadDataDirDraft = s.dataDir || loadDataDirDraft;
8382
8264
  loadResultDirDraft = s.resultDir || loadResultDirDraft;
8383
- loadExecutionModeDraft = s.executionMode || loadExecutionModeDraft;
8384
- loadVusEnvNameDraft = s.vusEnvName || loadVusEnvNameDraft;
8385
- loadDurationEnvNameDraft = s.durationEnvName || loadDurationEnvNameDraft;
8386
8265
  const ta = document.getElementById('loadScriptEditor');
8387
8266
  if (ta) { ta.value = s.script; ta.style.borderColor = 'var(--blue)'; setTimeout(() => { ta.style.borderColor = ''; }, 1500); }
8388
8267
  const nameEl = document.getElementById('loadScriptName');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viberadar",
3
- "version": "0.3.211",
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": {