viberadar 0.3.200 → 0.3.202

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.
@@ -2697,20 +2697,33 @@ function updateAgentRightsInfo() {
2697
2697
  const el = document.getElementById('headerAgentRights');
2698
2698
  if (!el || !D) return;
2699
2699
  const runtime = D.agentRuntime || {};
2700
- const sandbox = runtime.codexSandboxMode || 'read-only';
2701
- const approval = runtime.approvalPolicy || 'never';
2702
-
2703
- if (D.agent === 'codex') {
2704
- el.textContent = `🔐 Codex: ${sandbox}, approval: ${approval}`;
2705
- el.title = 'Права/режим выполнения Codex';
2706
- return;
2707
- }
2700
+ const sandbox = runtime.codexSandboxMode || 'read-only';
2701
+ const approval = runtime.approvalPolicy || 'never';
2702
+
2703
+ if (D.agent === 'codex') {
2704
+ const cached = window._codexAccount;
2705
+ const account = cached ? ` · ${cached}` : '';
2706
+ el.textContent = `🔐 Codex${account}: ${sandbox}, approval: ${approval}`;
2707
+ el.title = cached
2708
+ ? `Codex аккаунт: ${cached}. Права: ${sandbox}, approval: ${approval}`
2709
+ : 'Загружаю аккаунт Codex…';
2710
+ if (!cached) {
2711
+ fetch('/api/agent-whoami?agent=codex').then(r => r.json()).then(d => {
2712
+ window._codexAccount = d.email || d.name || d.accountId || d.raw || 'неизвестно';
2713
+ updateAgentRightsInfo();
2714
+ }).catch(() => {
2715
+ window._codexAccount = 'неизвестно';
2716
+ updateAgentRightsInfo();
2717
+ });
2718
+ }
2719
+ return;
2720
+ }
2708
2721
  if (D.agent === 'claude') {
2709
2722
  const cached = window._claudeAccount;
2710
2723
  el.textContent = cached ? `🔐 ${cached}` : '🔐 Claude';
2711
2724
  el.title = cached ? `Claude аккаунт: ${cached}` : 'Загружаю аккаунт…';
2712
2725
  if (!cached) {
2713
- fetch('/api/agent-whoami').then(r => r.json()).then(d => {
2726
+ fetch('/api/agent-whoami?agent=claude').then(r => r.json()).then(d => {
2714
2727
  window._claudeAccount = d.email || d.raw?.split('\n')[0] || 'неизвестно';
2715
2728
  updateAgentRightsInfo();
2716
2729
  }).catch(() => {});
@@ -4694,9 +4707,10 @@ function renderObsGlobalDetail(c, filterFeatureKey) {
4694
4707
  }).join('') || '<div class="obs-sub">Шумных паттернов не обнаружено</div>';
4695
4708
 
4696
4709
  // ── Missing critical logs (V2: grouped by risk tier with failure points) ──
4697
- const v2Data = missingV2.filter(m => m.failurePoints.length > 0);
4698
- window.__obsMissingV2 = v2Data;
4699
- const fpTypeLabels = {
4710
+ const v2Data = missingV2.filter(m => m.failurePoints.length > 0);
4711
+ window.__obsMissingV2 = v2Data;
4712
+ window.__obsMissingGroupMeta = {};
4713
+ const fpTypeLabels = {
4700
4714
  'empty-catch':'пустой catch','catch-no-log':'catch без лога','promise-catch-no-log':'.catch без лога',
4701
4715
  'http-no-error-handling':'HTTP без обработки','db-no-error-handling':'DB без обработки',
4702
4716
  'throw-no-log':'throw без лога','error-check-no-log':'if(err) без лога',
@@ -4706,11 +4720,19 @@ function renderObsGlobalDetail(c, filterFeatureKey) {
4706
4720
  const tierLabels = { critical:'Критичные', important:'Важные', normal:'Обычные' };
4707
4721
  const tiers = ['critical','important','normal'];
4708
4722
  const tierSections = tiers.map(tier => {
4709
- const items = v2Data.filter(m => m.riskTier === tier);
4710
- if (!items.length) return '';
4711
- const groupId = 'missing-' + tier;
4712
- const expandBtn = hasAgent ? `<button class="obs-expand-btn" onclick="event.stopPropagation();toggleObsDetail('${groupId}')">▼</button>` : '';
4713
- const totalFPs = items.reduce((s,m) => s + m.failurePoints.length, 0);
4723
+ const items = v2Data.filter(m => m.riskTier === tier);
4724
+ if (!items.length) return '';
4725
+ const groupId = 'missing-' + tier;
4726
+ const groupIndices = items
4727
+ .map(m => (o.missingCriticalLogsV2 || []).indexOf(m))
4728
+ .filter(idx => idx >= 0);
4729
+ window.__obsMissingGroupMeta[groupId] = {
4730
+ missingLogIndices: groupIndices,
4731
+ recommendationType: 'add event',
4732
+ };
4733
+ const expandBtn = hasAgent ? `<button class="obs-expand-btn" onclick="event.stopPropagation();toggleObsDetail('${groupId}')">▼</button>` : '';
4734
+ const copyGroupBtn = `<button class="obs-copy-btn" title="Скопировать prompt для всей группы" onclick="event.stopPropagation();obsCopyPrompt('obs-fix-selected',window.__obsMissingGroupMeta['${groupId}'])">📋 Промпт</button>`;
4735
+ const totalFPs = items.reduce((s,m) => s + m.failurePoints.length, 0);
4714
4736
  const detailItems = items.map(m => {
4715
4737
  const globalIdx = (o.missingCriticalLogsV2 || []).indexOf(m); // index in full unfiltered array — must match server's missingCriticalLogsV2
4716
4738
  const fpCount = m.failurePoints.length;
@@ -4740,10 +4762,11 @@ function renderObsGlobalDetail(c, filterFeatureKey) {
4740
4762
  const _blTier = _bl?.tiers?.[tier];
4741
4763
  return `<div class="obs-tier-group">
4742
4764
  <div class="obs-tier-group-header">
4743
- <span class="obs-tier-badge obs-tier-${tier}">${tierLabels[tier]}</span>
4744
- <span>${items.length}${_d(items.length, _blTier?.modules)} модулей, ${totalFPs}${_d(totalFPs, _blTier?.fps)} точек отказа</span>
4745
- ${expandBtn}
4746
- </div>
4765
+ <span class="obs-tier-badge obs-tier-${tier}">${tierLabels[tier]}</span>
4766
+ <span>${items.length}${_d(items.length, _blTier?.modules)} модулей, ${totalFPs}${_d(totalFPs, _blTier?.fps)} точек отказа</span>
4767
+ ${copyGroupBtn}
4768
+ ${expandBtn}
4769
+ </div>
4747
4770
  ${detail}
4748
4771
  </div>`;
4749
4772
  }).join('');
@@ -4752,12 +4775,18 @@ function renderObsGlobalDetail(c, filterFeatureKey) {
4752
4775
  missingSection = '<div class="obs-sub" style="color:var(--green)">Критичные сценарии покрыты</div>';
4753
4776
  }
4754
4777
 
4755
- const fieldGaps = fieldGapsData;
4756
- const fieldGapEntries = Object.entries(fieldGaps).filter(([,v]) => v > 0).sort((a,b) => b[1] - a[1]);
4757
- const fieldGapRows = fieldGapEntries.map(([name, count]) => {
4758
- const groupId = 'field-' + name.replace(/[^a-z0-9]/gi, '_');
4759
- const affectedItems = catalog.filter(c => (c.missingFields||[]).includes(name));
4760
- const expandBtn = hasAgent ? `<button class="obs-expand-btn" onclick="event.stopPropagation();toggleObsDetail('${groupId}')">▼</button>` : '';
4778
+ const fieldGaps = fieldGapsData;
4779
+ window.__obsFieldGroupMeta = {};
4780
+ const fieldGapEntries = Object.entries(fieldGaps).filter(([,v]) => v > 0).sort((a,b) => b[1] - a[1]);
4781
+ const fieldGapRows = fieldGapEntries.map(([name, count]) => {
4782
+ const groupId = 'field-' + name.replace(/[^a-z0-9]/gi, '_');
4783
+ const affectedItems = catalog.filter(c => (c.missingFields||[]).includes(name));
4784
+ window.__obsFieldGroupMeta[groupId] = {
4785
+ fieldName: name,
4786
+ catalogPaths: affectedItems.map(c => c.modulePath),
4787
+ };
4788
+ const expandBtn = hasAgent ? `<button class="obs-expand-btn" onclick="event.stopPropagation();toggleObsDetail('${groupId}')">▼</button>` : '';
4789
+ const copyFieldBtn = `<button class="obs-copy-btn" title="Скопировать prompt для всех модулей с этим полем" onclick="event.stopPropagation();obsCopyPrompt('obs-fix-selected',window.__obsFieldGroupMeta['${groupId}'])">📋 Промпт</button>`;
4761
4790
  const detailItems = affectedItems.map(ci => {
4762
4791
  const catIdx = catalog.indexOf(ci);
4763
4792
  const otherMissing = (ci.missingFields||[]).filter(f => f !== name);
@@ -4776,10 +4805,11 @@ function renderObsGlobalDetail(c, filterFeatureKey) {
4776
4805
  </div>` : '';
4777
4806
  return `<div>
4778
4807
  <div class="obs-list-item">
4779
- <span><code>${escapeHtml(name)}</code></span>
4780
- <strong style="color:${count > 20 ? 'var(--red)' : count > 5 ? 'var(--yellow)' : 'var(--muted)'}">${count} пропусков в ${affectedItems.length} модул${affectedItems.length === 1 ? 'е' : affectedItems.length < 5 ? 'ях' : 'ях'}</strong>
4781
- ${expandBtn}
4782
- </div>
4808
+ <span><code>${escapeHtml(name)}</code></span>
4809
+ <strong style="color:${count > 20 ? 'var(--red)' : count > 5 ? 'var(--yellow)' : 'var(--muted)'}">${count} пропусков в ${affectedItems.length} модул${affectedItems.length === 1 ? 'е' : affectedItems.length < 5 ? 'ях' : 'ях'}</strong>
4810
+ ${copyFieldBtn}
4811
+ ${expandBtn}
4812
+ </div>
4783
4813
  ${detail}
4784
4814
  </div>`;
4785
4815
  }).join('') || '<div class="obs-sub" style="color:var(--green)">Все обязательные поля на месте</div>';
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "viberadar",
3
- "version": "0.3.200",
3
+ "version": "0.3.202",
4
4
  "description": "Live module map with test coverage for vibecoding projects",
5
5
  "main": "./dist/cli.js",
6
6
  "bin": {
7
- "viberadar": "./viberadar.js"
7
+ "viberadar": "viberadar.js"
8
8
  },
9
9
  "scripts": {
10
10
  "build": "tsc && node scripts/bundle-ui.js",