first draft enhancement 2
This commit is contained in:
		
							parent
							
								
									c267681e7d
								
							
						
					
					
						commit
						99117e8e7a
					
				
							
								
								
									
										21
									
								
								.env.example
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								.env.example
									
									
									
									
									
								
							@ -190,19 +190,22 @@ FORENSIC_AUDIT_RETENTION_HOURS=24
 | 
			
		||||
FORENSIC_AUDIT_MAX_ENTRIES=50
 | 
			
		||||
 | 
			
		||||
# ============================================================================
 | 
			
		||||
# 10. QUALITY CONTROL & BIAS DETECTION (ADVANCED)
 | 
			
		||||
# 10. CONFIDENCE SCORING SYSTEM (Enhancement 2)
 | 
			
		||||
# ============================================================================
 | 
			
		||||
 | 
			
		||||
# Confidence scoring weights (must sum to 1.0)
 | 
			
		||||
CONFIDENCE_EMBEDDINGS_WEIGHT=0.3
 | 
			
		||||
CONFIDENCE_CONSENSUS_WEIGHT=0.25
 | 
			
		||||
CONFIDENCE_DOMAIN_MATCH_WEIGHT=0.25
 | 
			
		||||
CONFIDENCE_FRESHNESS_WEIGHT=0.2
 | 
			
		||||
# Confidence component weights (must sum to 1.0)
 | 
			
		||||
CONFIDENCE_EMBEDDINGS_WEIGHT=0.3      # Weight for vector similarity quality
 | 
			
		||||
CONFIDENCE_CONSENSUS_WEIGHT=0.25      # Weight for micro-task agreement  
 | 
			
		||||
CONFIDENCE_DOMAIN_MATCH_WEIGHT=0.25   # Weight for domain alignment
 | 
			
		||||
CONFIDENCE_FRESHNESS_WEIGHT=0.2       # Weight for tool freshness/maintenance
 | 
			
		||||
 | 
			
		||||
# Confidence thresholds (0-100)
 | 
			
		||||
CONFIDENCE_MINIMUM_THRESHOLD=40
 | 
			
		||||
CONFIDENCE_MEDIUM_THRESHOLD=60
 | 
			
		||||
CONFIDENCE_HIGH_THRESHOLD=80
 | 
			
		||||
CONFIDENCE_MINIMUM_THRESHOLD=40        # Below this = weak recommendation
 | 
			
		||||
CONFIDENCE_MEDIUM_THRESHOLD=60         # 40-59 = weak, 60-79 = moderate  
 | 
			
		||||
CONFIDENCE_HIGH_THRESHOLD=80           # 80+ = strong recommendation
 | 
			
		||||
 | 
			
		||||
# Domain keywords for confidence scoring (domain:keyword1,keyword2|domain:keyword3,keyword4)
 | 
			
		||||
CONFIDENCE_DOMAIN_KEYWORDS="incident-response:incident,breach,attack,compromise,response|malware-analysis:malware,virus,trojan,reverse,analysis|network-forensics:network,traffic,packet,pcap,wireshark|mobile-forensics:mobile,android,ios,phone,app|cloud-forensics:cloud,aws,azure,saas,paas"
 | 
			
		||||
 | 
			
		||||
# ============================================================================
 | 
			
		||||
# PERFORMANCE TUNING PRESETS
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										102
									
								
								check-unused-css.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								check-unused-css.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,102 @@
 | 
			
		||||
#!/usr/bin/env node
 | 
			
		||||
// find-unused-css.js
 | 
			
		||||
// Usage: node find-unused-css <cssFile> <sourceRoot> [--verbose]
 | 
			
		||||
 | 
			
		||||
import fs from 'fs/promises';
 | 
			
		||||
import path from 'path';
 | 
			
		||||
import fg from 'fast-glob';
 | 
			
		||||
import pc from 'picocolors';
 | 
			
		||||
import postcss from 'postcss';
 | 
			
		||||
import safeParser from 'postcss-safe-parser';
 | 
			
		||||
 | 
			
		||||
const [,, cssPath, srcRoot = '.', ...rest] = process.argv;
 | 
			
		||||
const verbose = rest.includes('--verbose');
 | 
			
		||||
if (!cssPath) {
 | 
			
		||||
  console.error('Usage: node find-unused-css <cssFile> <sourceRoot>');
 | 
			
		||||
  process.exit(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* -------------------------------------------------- */
 | 
			
		||||
/* 1.  Parse the CSS and harvest class/id tokens       */
 | 
			
		||||
/* -------------------------------------------------- */
 | 
			
		||||
const cssRaw = await fs.readFile(cssPath, 'utf8');
 | 
			
		||||
const root   = postcss().process(cssRaw, { parser: safeParser }).root;
 | 
			
		||||
 | 
			
		||||
const selectorTokens = new Map();          // selector → Set('.foo', '#bar')
 | 
			
		||||
const CLASS = /\.([\w-]+)/g;
 | 
			
		||||
const ID    = /#([\w-]+)/g;
 | 
			
		||||
 | 
			
		||||
root.walkRules(rule => {
 | 
			
		||||
  rule.selectors.forEach(sel => {
 | 
			
		||||
    const tokens = new Set();
 | 
			
		||||
    sel.replace(CLASS, (_, c) => tokens.add('.'+c));
 | 
			
		||||
    sel.replace(ID,    (_, i) => tokens.add('#'+i));
 | 
			
		||||
    if (tokens.size) selectorTokens.set(sel, tokens);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* -------------------------------------------------- */
 | 
			
		||||
/* 2.  Dynamic classes you add via JS (safe keep)      */
 | 
			
		||||
/* -------------------------------------------------- */
 | 
			
		||||
const dynamicAllow = new Set([
 | 
			
		||||
  'hidden', 'active', 'loading', 'open', 'closed'
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
/* -------------------------------------------------- */
 | 
			
		||||
/* 3.  Read every source file once                     */
 | 
			
		||||
/* -------------------------------------------------- */
 | 
			
		||||
const files = await fg([
 | 
			
		||||
  `${srcRoot}/**/*.{html,htm,js,jsx,ts,tsx,vue,svelte,astro}`,
 | 
			
		||||
  `!${srcRoot}/**/node_modules/**`
 | 
			
		||||
]);
 | 
			
		||||
const sources = await Promise.all(files.map(f => fs.readFile(f, 'utf8')));
 | 
			
		||||
 | 
			
		||||
/* -------------------------------------------------- */
 | 
			
		||||
/* 4.  Fast search helpers                             */
 | 
			
		||||
/* -------------------------------------------------- */
 | 
			
		||||
const makeClassRE = cls =>
 | 
			
		||||
  new RegExp(
 | 
			
		||||
    `(class|className)=['"][^'"]*\\b${cls}\\b[^'"]*['"]|['"\`]${cls}['"\`]`,
 | 
			
		||||
    'i'
 | 
			
		||||
  );
 | 
			
		||||
const makeIdRE = id =>
 | 
			
		||||
  new RegExp(`id=['"]${id}['"]|['"\`]${id}['"\`]`, 'i');
 | 
			
		||||
 | 
			
		||||
const tokenInSources = token => {
 | 
			
		||||
  // dynamic allow-list
 | 
			
		||||
  if (dynamicAllow.has(token)) return true;
 | 
			
		||||
 | 
			
		||||
  const re = token.startsWith('.')
 | 
			
		||||
    ? makeClassRE(token.slice(1))
 | 
			
		||||
    : makeIdRE(token.slice(1));
 | 
			
		||||
 | 
			
		||||
  return sources.some(txt => re.test(txt));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* -------------------------------------------------- */
 | 
			
		||||
/* 5.  Decide used vs unused                           */
 | 
			
		||||
/* -------------------------------------------------- */
 | 
			
		||||
const used   = [];
 | 
			
		||||
const unused = [];
 | 
			
		||||
 | 
			
		||||
for (const [selector, tokens] of selectorTokens.entries()) {
 | 
			
		||||
  const isUsed = [...tokens].some(tokenInSources); // **ANY** token keeps rule
 | 
			
		||||
  (isUsed ? used : unused).push(selector);
 | 
			
		||||
  if (verbose) {
 | 
			
		||||
    console.log(isUsed ? pc.green('✓ '+selector) : pc.red('✗ '+selector));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* -------------------------------------------------- */
 | 
			
		||||
/* 6.  Report & write list                             */
 | 
			
		||||
/* -------------------------------------------------- */
 | 
			
		||||
console.log(
 | 
			
		||||
  `\n${pc.bold(pc.blue('🎯 CSS usage summary'))}\n` +
 | 
			
		||||
  `  selectors total : ${selectorTokens.size}\n` +
 | 
			
		||||
  `  still used       : ${pc.green(used.length)}\n` +
 | 
			
		||||
  `  maybe unused     : ${pc.red(unused.length)}\n`
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
const outFile = path.resolve('unused-selectors.txt');
 | 
			
		||||
await fs.writeFile(outFile, unused.join('\n'));
 | 
			
		||||
console.log(`📝  Unused selector list → ${pc.yellow(outFile)}\n`);
 | 
			
		||||
@ -20,7 +20,11 @@
 | 
			
		||||
    "zod": "^3.25.76"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@types/js-yaml": "^4.0.9"
 | 
			
		||||
    "@types/js-yaml": "^4.0.9",
 | 
			
		||||
    "fast-glob": "^3.3.3",
 | 
			
		||||
    "picocolors": "^1.1.1",
 | 
			
		||||
    "postcss": "^8.5.6",
 | 
			
		||||
    "postcss-safe-parser": "^7.0.1"
 | 
			
		||||
  },
 | 
			
		||||
  "engines": {
 | 
			
		||||
    "node": ">=18.0.0"
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
---
 | 
			
		||||
import { getToolsData } from '../utils/dataService.js';
 | 
			
		||||
import { isToolHosted } from '../utils/toolHelpers.js';
 | 
			
		||||
 | 
			
		||||
const data = await getToolsData();
 | 
			
		||||
const tools = data.tools;
 | 
			
		||||
@ -698,7 +699,10 @@ class AIQueryInterface {
 | 
			
		||||
        if (fullTool) {
 | 
			
		||||
          toolsByPhase[recTool.phase].push({
 | 
			
		||||
            ...fullTool,
 | 
			
		||||
            recommendation: recTool
 | 
			
		||||
            recommendation: recTool,
 | 
			
		||||
            confidence: recTool.confidence,
 | 
			
		||||
            justification: recTool.justification,
 | 
			
		||||
            priority: recTool.priority
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
@ -999,6 +1003,151 @@ class AIQueryInterface {
 | 
			
		||||
    return String(data);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  renderConfidenceIndicator(confidence) {
 | 
			
		||||
    if (!confidence || typeof confidence.overall !== 'number') return '';
 | 
			
		||||
    
 | 
			
		||||
    const confidenceColor = confidence.overall >= 80 ? 'var(--color-accent)' : 
 | 
			
		||||
                           confidence.overall >= 60 ? 'var(--color-warning)' : 'var(--color-error)';
 | 
			
		||||
    
 | 
			
		||||
    const strengthText = confidence.overall >= 80 ? 'HOCH' : 
 | 
			
		||||
                        confidence.overall >= 60 ? 'MITTEL' : 'NIEDRIG';
 | 
			
		||||
    
 | 
			
		||||
    return `
 | 
			
		||||
      <div class="confidence-indicator-integrated" style="display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.75rem;">
 | 
			
		||||
        <div class="confidence-bar-wrapper" style="flex: 1; height: 4px; background-color: var(--color-bg-tertiary); border-radius: 2px; overflow: hidden;">
 | 
			
		||||
          <div class="confidence-bar-fill" style="width: ${confidence.overall}%; height: 100%; background-color: ${confidenceColor}; transition: var(--transition-fast);"></div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="confidence-badge-compact" style="display: flex; align-items: center; gap: 0.375rem;">
 | 
			
		||||
          <span class="badge badge-mini" style="background-color: ${confidenceColor}; color: white; font-weight: 600; font-size: 0.625rem;">
 | 
			
		||||
            ${confidence.overall}%
 | 
			
		||||
          </span>
 | 
			
		||||
          <button class="btn-icon" style="width: 16px; height: 16px; padding: 0.125rem; font-size: 0.625rem;" onclick="this.parentElement.nextElementSibling.style.display = this.parentElement.nextElementSibling.style.display === 'none' ? 'block' : 'none'; this.textContent = this.textContent === 'ℹ️' ? '✕' : 'ℹ️';" title="Vertrauens-Details">ℹ️</button>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div style="display: none; position: absolute; z-index: 20; background: var(--color-bg); border: 1px solid var(--color-border); border-radius: 0.5rem; padding: 1rem; margin-top: 6rem; right: 0; min-width: 320px; box-shadow: var(--shadow-lg);" class="confidence-details-popup">
 | 
			
		||||
          <div style="margin-bottom: 0.75rem;">
 | 
			
		||||
            <div style="display: flex; justify-content: between; align-items: center; margin-bottom: 0.5rem;">
 | 
			
		||||
              <strong class="text-sm">Vertrauens-Komponenten</strong>
 | 
			
		||||
              <span class="badge badge-mini" style="background-color: ${confidenceColor}; color: white;">${strengthText}</span>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; font-size: 0.75rem;">
 | 
			
		||||
              <div style="display: flex; justify-content: space-between; padding: 0.25rem; background: var(--color-bg-secondary); border-radius: 0.25rem;">
 | 
			
		||||
                <span>Ähnlichkeit:</span>
 | 
			
		||||
                <span class="font-semibold">${confidence.embeddingsQuality}%</span>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div style="display: flex; justify-content: space-between; padding: 0.25rem; background: var(--color-bg-secondary); border-radius: 0.25rem;">
 | 
			
		||||
                <span>Domain:</span>
 | 
			
		||||
                <span class="font-semibold">${confidence.domainAlignment}%</span>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div style="display: flex; justify-content: space-between; padding: 0.25rem; background: var(--color-bg-secondary); border-radius: 0.25rem;">
 | 
			
		||||
                <span>Konsens:</span>
 | 
			
		||||
                <span class="font-semibold">${confidence.consensus}%</span>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div style="display: flex; justify-content: space-between; padding: 0.25rem; background: var(--color-bg-secondary); border-radius: 0.25rem;">
 | 
			
		||||
                <span>Aktualität:</span>
 | 
			
		||||
                <span class="font-semibold">${confidence.freshness}%</span>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
          
 | 
			
		||||
          ${confidence.strengthIndicators && confidence.strengthIndicators.length > 0 ? `
 | 
			
		||||
            <div style="margin-bottom: 0.75rem;">
 | 
			
		||||
              <strong class="text-accent" style="font-size: 0.75rem;">✓ Stärken:</strong>
 | 
			
		||||
              <ul style="font-size: 0.6875rem; margin-top: 0.25rem; padding-left: 1rem; line-height: 1.3;">
 | 
			
		||||
                ${confidence.strengthIndicators.slice(0, 2).map(strength => `<li style="margin-bottom: 0.25rem;">${this.sanitizeText(strength)}</li>`).join('')}
 | 
			
		||||
              </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
          ` : ''}
 | 
			
		||||
          
 | 
			
		||||
          ${confidence.uncertaintyFactors && confidence.uncertaintyFactors.length > 0 ? `
 | 
			
		||||
            <div style="padding-top: 0.75rem; border-top: 1px solid var(--color-border);">
 | 
			
		||||
              <strong class="text-warning" style="font-size: 0.75rem;">⚠ Unsicherheiten:</strong>
 | 
			
		||||
              <ul style="font-size: 0.6875rem; margin-top: 0.25rem; padding-left: 1rem; line-height: 1.3;">
 | 
			
		||||
                ${confidence.uncertaintyFactors.slice(0, 2).map(factor => `<li style="margin-bottom: 0.25rem;">${this.sanitizeText(factor)}</li>`).join('')}
 | 
			
		||||
              </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
          ` : ''}
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    `;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  renderWorkflowTool(tool) {
 | 
			
		||||
    const hasValidProjectUrl = isToolHosted(tool);
 | 
			
		||||
    const priorityColors = {
 | 
			
		||||
      high: 'var(--color-error)',
 | 
			
		||||
      medium: 'var(--color-warning)', 
 | 
			
		||||
      low: 'var(--color-accent)'
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return `
 | 
			
		||||
      <div class="tool-recommendation ${this.getToolClass(tool, 'recommendation')}" onclick="window.showToolDetails('${tool.name}')" style="position: relative;">
 | 
			
		||||
        <div class="tool-rec-header">
 | 
			
		||||
          <h4 class="tool-rec-name">
 | 
			
		||||
            ${tool.icon ? `<span style="margin-right: 0.5rem;">${tool.icon}</span>` : ''}
 | 
			
		||||
            ${tool.name}
 | 
			
		||||
          </h4>
 | 
			
		||||
          <div class="flex items-center gap-2">
 | 
			
		||||
            <span class="tool-rec-priority ${tool.recommendation ? tool.recommendation.priority : tool.priority}" 
 | 
			
		||||
                  style="background-color: ${priorityColors[tool.recommendation ? tool.recommendation.priority : tool.priority]}; color: white; padding: 0.25rem 0.5rem; border-radius: 1rem; font-size: 0.75rem;">
 | 
			
		||||
              ${tool.recommendation ? tool.recommendation.priority : tool.priority}
 | 
			
		||||
            </span>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        
 | 
			
		||||
        ${tool.confidence ? this.renderConfidenceIndicator(tool.confidence) : ''}
 | 
			
		||||
        
 | 
			
		||||
        <div class="tool-rec-justification" style="background-color: var(--color-bg-tertiary); padding: 0.75rem; border-radius: 0.375rem; border-left: 3px solid var(--color-primary); margin: 0.75rem 0; font-style: italic; white-space: pre-wrap; word-wrap: break-word;">
 | 
			
		||||
          "${this.sanitizeText(tool.justification || (tool.recommendation && tool.recommendation.justification) || `Empfohlen für ${tool.phase}`)}"
 | 
			
		||||
        </div>
 | 
			
		||||
        
 | 
			
		||||
        <div style="font-size: 0.75rem; color: var(--color-text-secondary);">
 | 
			
		||||
          ${this.renderToolBadges(tool)}
 | 
			
		||||
          <div style="margin-top: 0.5rem;">
 | 
			
		||||
            ${tool.type === 'method' ? 'Methode' : tool.platforms.join(', ') + ' • ' + tool.license}
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    `;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  renderDetailedTool(tool, recommendation, rank) {
 | 
			
		||||
    const rankColors = { 1: 'var(--color-accent)', 2: 'var(--color-primary)', 3: 'var(--color-warning)' };
 | 
			
		||||
    const suitabilityColors = { high: 'var(--color-accent)', medium: 'var(--color-warning)', low: 'var(--color-text-secondary)' };
 | 
			
		||||
    
 | 
			
		||||
    return `
 | 
			
		||||
      <div class="card ${this.getToolClass(tool, 'card')}" style="cursor: pointer; position: relative;" onclick="window.showToolDetails('${tool.name}')">
 | 
			
		||||
        <div style="position: absolute; top: -8px; right: -8px; width: 32px; height: 32px; background-color: ${rankColors[rank]}; color: white; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 1.125rem;">
 | 
			
		||||
          ${rank}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div style="margin-bottom: 1rem;">
 | 
			
		||||
          <h3 style="margin: 0 0 0.5rem 0;">${tool.name}</h3>
 | 
			
		||||
          <div style="display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 0.75rem;">
 | 
			
		||||
            <span class="badge" style="background-color: ${suitabilityColors[recommendation.suitability_score]}; color: white;">
 | 
			
		||||
              ${this.getSuitabilityText(recommendation.suitability_score)}
 | 
			
		||||
            </span>
 | 
			
		||||
            ${this.renderToolBadges(tool)}
 | 
			
		||||
          </div>
 | 
			
		||||
          ${recommendation.confidence ? this.renderConfidenceIndicator(recommendation.confidence) : ''}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div style="margin-bottom: 1.5rem;">
 | 
			
		||||
          <h4 style="margin: 0.8rem 0 0.75rem 0; color: var(--color-accent);">Warum diese Methode?</h4>
 | 
			
		||||
          <div style="margin: 0; line-height: 1.6; white-space: pre-wrap; word-wrap: break-word;">${this.sanitizeText(recommendation.detailed_explanation)}</div>
 | 
			
		||||
          
 | 
			
		||||
          ${recommendation.implementation_approach ? `
 | 
			
		||||
            <h4 style="margin: 0.8rem 0 0.75rem 0; color: var(--color-primary);">Anwendungsansatz</h4>
 | 
			
		||||
            <div style="margin: 0; line-height: 1.6; white-space: pre-wrap; word-wrap: break-word;">${this.sanitizeText(recommendation.implementation_approach)}</div>
 | 
			
		||||
          ` : ''}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        ${this.renderProsAndCons(recommendation.pros, recommendation.cons)}
 | 
			
		||||
        ${this.renderToolMetadata(tool)}
 | 
			
		||||
        ${recommendation.alternatives ? this.renderAlternatives(recommendation.alternatives) : ''}
 | 
			
		||||
      </div>
 | 
			
		||||
    `;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  renderHeader(title, query) {
 | 
			
		||||
    return `
 | 
			
		||||
      <div style="text-align: center; margin-bottom: 2rem; padding: 1.5rem; background: linear-gradient(135deg, var(--color-primary) 0%, #525252 100%); color: white; border-radius: 0.75rem;">
 | 
			
		||||
@ -1099,7 +1248,7 @@ class AIQueryInterface {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  renderWorkflowTool(tool) {
 | 
			
		||||
    const hasValidProjectUrl = this.isToolHosted(tool);
 | 
			
		||||
    const hasValidProjectUrl = isToolHosted(tool);
 | 
			
		||||
    const priorityColors = {
 | 
			
		||||
      high: 'var(--color-error)',
 | 
			
		||||
      medium: 'var(--color-warning)', 
 | 
			
		||||
@ -1142,7 +1291,10 @@ class AIQueryInterface {
 | 
			
		||||
          const fullTool = tools.find(t => t.name === toolRec.name);
 | 
			
		||||
          if (!fullTool) return '';
 | 
			
		||||
          
 | 
			
		||||
          return this.renderDetailedTool(fullTool, toolRec, index + 1);
 | 
			
		||||
          return this.renderDetailedTool(fullTool, {
 | 
			
		||||
            ...toolRec,
 | 
			
		||||
            confidence: toolRec.confidence 
 | 
			
		||||
          }, index + 1);
 | 
			
		||||
        }).join('')}
 | 
			
		||||
      </div>
 | 
			
		||||
    `;
 | 
			
		||||
@ -1256,7 +1408,7 @@ class AIQueryInterface {
 | 
			
		||||
 | 
			
		||||
  renderToolBadges(tool) {
 | 
			
		||||
    const isMethod = tool.type === 'method';
 | 
			
		||||
    const hasValidProjectUrl = this.isToolHosted(tool);
 | 
			
		||||
    const hasValidProjectUrl = isToolHosted(tool);
 | 
			
		||||
    
 | 
			
		||||
    let badges = '';
 | 
			
		||||
    if (isMethod) {
 | 
			
		||||
@ -1300,16 +1452,9 @@ class AIQueryInterface {
 | 
			
		||||
      .trim();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  isToolHosted(tool) {
 | 
			
		||||
    return tool.projectUrl !== undefined && 
 | 
			
		||||
           tool.projectUrl !== null && 
 | 
			
		||||
           tool.projectUrl !== "" && 
 | 
			
		||||
           tool.projectUrl.trim() !== "";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getToolClass(tool, context = 'card') {
 | 
			
		||||
    const isMethod = tool.type === 'method';
 | 
			
		||||
    const hasValidProjectUrl = this.isToolHosted(tool);
 | 
			
		||||
    const hasValidProjectUrl = isToolHosted(tool);
 | 
			
		||||
    
 | 
			
		||||
    if (context === 'recommendation') {
 | 
			
		||||
      if (isMethod) return 'method';
 | 
			
		||||
@ -1402,5 +1547,6 @@ document.addEventListener('DOMContentLoaded', () => {
 | 
			
		||||
      aiInterface.hideError();
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  window.isToolHosted = window.isToolHosted || isToolHosted
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
@ -144,20 +144,11 @@ a:hover {
 | 
			
		||||
  margin: 0 auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.container-wide {
 | 
			
		||||
  max-width: 1400px;
 | 
			
		||||
  margin: 0 auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Section Utilities */
 | 
			
		||||
.section {
 | 
			
		||||
  padding: 2rem 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.section-sm {
 | 
			
		||||
  padding: 1rem 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.section-lg {
 | 
			
		||||
  padding: 3rem 0;
 | 
			
		||||
}
 | 
			
		||||
@ -2218,6 +2209,10 @@ input[type="checkbox"] {
 | 
			
		||||
  border-color: var(--color-method);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tool-recommendation:hover .confidence-bar-fill {
 | 
			
		||||
  box-shadow: 0 0 8px rgba(0,0,0,0.1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tool-rec-header {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
@ -2264,6 +2259,57 @@ input[type="checkbox"] {
 | 
			
		||||
  color: var(--color-text-secondary);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ===================================================================
 | 
			
		||||
   CONFIDENCE INTEGRATION STYLES
 | 
			
		||||
   ================================================================= */
 | 
			
		||||
 | 
			
		||||
.confidence-indicator-integrated {
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.confidence-bar-wrapper {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  background-color: var(--color-bg-tertiary);
 | 
			
		||||
  border-radius: 2px;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  border: 1px solid var(--color-border);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.confidence-bar-fill {
 | 
			
		||||
  transition: width 0.6s ease-out;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.confidence-bar-fill::after {
 | 
			
		||||
  content: '';
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  background: linear-gradient(45deg, transparent 25%, rgba(255,255,255,0.1) 25%, rgba(255,255,255,0.1) 50%, transparent 50%, transparent 75%, rgba(255,255,255,0.1) 75%);
 | 
			
		||||
  background-size: 8px 8px;
 | 
			
		||||
  animation: confidence-shimmer 2s linear infinite;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.confidence-badge-compact .btn-icon {
 | 
			
		||||
  transition: var(--transition-fast);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.confidence-badge-compact .btn-icon:hover {
 | 
			
		||||
  background-color: var(--color-bg-secondary);
 | 
			
		||||
  transform: scale(1.1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.confidence-details-popup {
 | 
			
		||||
  animation: confidence-popup-in 0.2s ease-out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Hover effect for confidence bars */
 | 
			
		||||
.confidence-indicator-integrated:hover .confidence-bar-fill {
 | 
			
		||||
  filter: brightness(1.1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ===================================================================
 | 
			
		||||
   18. APPROACH SELECTION (CONSOLIDATED)
 | 
			
		||||
   ================================================================= */
 | 
			
		||||
@ -2665,11 +2711,26 @@ footer {
 | 
			
		||||
  animation: ai-spotlight-pulse 0.4s ease-out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@keyframes confidence-shimmer {
 | 
			
		||||
  0% { transform: translateX(-8px); }
 | 
			
		||||
  100% { transform: translateX(8px); }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@keyframes confidence-popup-in {
 | 
			
		||||
  from {
 | 
			
		||||
    opacity: 0;
 | 
			
		||||
    transform: translateY(-8px);
 | 
			
		||||
  }
 | 
			
		||||
  to {
 | 
			
		||||
    opacity: 1;
 | 
			
		||||
    transform: translateY(0);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ===================================================================
 | 
			
		||||
   21. SMART PROMPTING INTERFACE (MISSING STYLES ADDED BACK)
 | 
			
		||||
   ================================================================= */
 | 
			
		||||
 | 
			
		||||
/* Smart Prompting Container */
 | 
			
		||||
.smart-prompting-container {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  animation: smartPromptSlideIn 0.4s cubic-bezier(0.4, 0, 0.2, 1);
 | 
			
		||||
@ -3599,6 +3660,26 @@ footer {
 | 
			
		||||
    width: 14px;
 | 
			
		||||
    height: 14px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .confidence-details-popup {
 | 
			
		||||
    position: fixed !important;
 | 
			
		||||
    top: 50% !important;
 | 
			
		||||
    left: 50% !important;
 | 
			
		||||
    transform: translate(-50%, -50%) !important;
 | 
			
		||||
    margin: 0 !important;
 | 
			
		||||
    width: 90vw !important;
 | 
			
		||||
    max-width: 300px !important;
 | 
			
		||||
    z-index: 1000 !important;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  .confidence-indicator-integrated {
 | 
			
		||||
    margin-bottom: 0.5rem;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  .confidence-badge-compact .btn-icon {
 | 
			
		||||
    width: 18px;
 | 
			
		||||
    height: 18px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media (width <= 640px) {
 | 
			
		||||
@ -3924,28 +4005,6 @@ footer {
 | 
			
		||||
  background: linear-gradient(to bottom, var(--color-border) 0%, transparent 100%);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.confidence-indicator {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.confidence-indicator::after {
 | 
			
		||||
  content: '';
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  background: linear-gradient(45deg, transparent 25%, rgba(255,255,255,0.1) 25%, rgba(255,255,255,0.1) 50%, transparent 50%, transparent 75%, rgba(255,255,255,0.1) 75%);
 | 
			
		||||
  background-size: 4px 4px;
 | 
			
		||||
  animation: confidence-shimmer 2s linear infinite;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@keyframes confidence-shimmer {
 | 
			
		||||
  0% { transform: translateX(-4px); }
 | 
			
		||||
  100% { transform: translateX(4px); }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.toggle-icon {
 | 
			
		||||
  transition: transform 0.2s ease;
 | 
			
		||||
}
 | 
			
		||||
@ -4000,7 +4059,4 @@ footer {
 | 
			
		||||
    gap: 0.5rem;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  .confidence-indicator {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -3,6 +3,7 @@
 | 
			
		||||
import { getCompressedToolsDataForAI } from './dataService.js';
 | 
			
		||||
import { embeddingsService, type EmbeddingData } from './embeddings.js';
 | 
			
		||||
import { AI_PROMPTS, getPrompt } from '../config/prompts.js';
 | 
			
		||||
import { isToolHosted } from './toolHelpers.js';
 | 
			
		||||
 | 
			
		||||
interface AIConfig {
 | 
			
		||||
  endpoint: string;
 | 
			
		||||
@ -67,6 +68,16 @@ interface SimilarityResult extends EmbeddingData {
 | 
			
		||||
  similarity: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface ConfidenceMetrics {
 | 
			
		||||
  overall: number;           // 0-100: Combined confidence score
 | 
			
		||||
  embeddingsQuality: number; // How well embeddings matched
 | 
			
		||||
  domainAlignment: number;   // How well tools match scenario domain
 | 
			
		||||
  consensus: number;         // How much micro-tasks agree
 | 
			
		||||
  freshness: number;         // How recent/up-to-date the selection is
 | 
			
		||||
  uncertaintyFactors: string[]; // What could make this wrong
 | 
			
		||||
  strengthIndicators: string[]; // What makes this recommendation strong
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ImprovedMicroTaskAIPipeline {
 | 
			
		||||
  private config: AIConfig;
 | 
			
		||||
@ -92,6 +103,16 @@ class ImprovedMicroTaskAIPipeline {
 | 
			
		||||
    detailLevel: 'minimal' | 'standard' | 'verbose';
 | 
			
		||||
    retentionHours: number;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  private confidenceConfig: {
 | 
			
		||||
    embeddingsWeight: number;
 | 
			
		||||
    consensusWeight: number;
 | 
			
		||||
    domainMatchWeight: number;
 | 
			
		||||
    freshnessWeight: number;
 | 
			
		||||
    minimumThreshold: number;
 | 
			
		||||
    mediumThreshold: number;
 | 
			
		||||
    highThreshold: number;
 | 
			
		||||
  };
 | 
			
		||||
  
 | 
			
		||||
  private tempAuditEntries: AuditEntry[] = [];
 | 
			
		||||
 | 
			
		||||
@ -131,6 +152,21 @@ class ImprovedMicroTaskAIPipeline {
 | 
			
		||||
      noEmbeddingsLimits: `${this.noEmbeddingsToolLimit || 'unlimited'} tools, ${this.noEmbeddingsConceptLimit || 'unlimited'} concepts`,
 | 
			
		||||
      auditEnabled: this.auditConfig.enabled
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    this.confidenceConfig = {
 | 
			
		||||
      embeddingsWeight: parseFloat(process.env.CONFIDENCE_EMBEDDINGS_WEIGHT || '0.3'),
 | 
			
		||||
      consensusWeight: parseFloat(process.env.CONFIDENCE_CONSENSUS_WEIGHT || '0.25'), 
 | 
			
		||||
      domainMatchWeight: parseFloat(process.env.CONFIDENCE_DOMAIN_MATCH_WEIGHT || '0.25'),
 | 
			
		||||
      freshnessWeight: parseFloat(process.env.CONFIDENCE_FRESHNESS_WEIGHT || '0.2'),
 | 
			
		||||
      minimumThreshold: parseInt(process.env.CONFIDENCE_MINIMUM_THRESHOLD || '40', 10),
 | 
			
		||||
      mediumThreshold: parseInt(process.env.CONFIDENCE_MEDIUM_THRESHOLD || '60', 10),
 | 
			
		||||
      highThreshold: parseInt(process.env.CONFIDENCE_HIGH_THRESHOLD || '80', 10)
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    console.log('[AI PIPELINE] Confidence scoring enabled:', {
 | 
			
		||||
      weights: `E:${this.confidenceConfig.embeddingsWeight} C:${this.confidenceConfig.consensusWeight} D:${this.confidenceConfig.domainMatchWeight} F:${this.confidenceConfig.freshnessWeight}`,
 | 
			
		||||
      thresholds: `${this.confidenceConfig.minimumThreshold}/${this.confidenceConfig.mediumThreshold}/${this.confidenceConfig.highThreshold}`
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private getEnv(key: string): string {
 | 
			
		||||
@ -662,6 +698,40 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private calculateRecommendationConfidence(
 | 
			
		||||
    tool: any, 
 | 
			
		||||
    embeddingsSimilarity: number,
 | 
			
		||||
    domainMatch: boolean,
 | 
			
		||||
    microTaskAgreement: number,
 | 
			
		||||
    context: AnalysisContext
 | 
			
		||||
  ): ConfidenceMetrics {
 | 
			
		||||
    
 | 
			
		||||
    const embeddingsQuality = Math.min(100, embeddingsSimilarity * 100 * 2); // Scale 0.5 similarity to 100%
 | 
			
		||||
    const domainAlignment = domainMatch ? 90 : (tool.domains?.length > 0 ? 60 : 30);
 | 
			
		||||
    const consensus = Math.min(100, microTaskAgreement * 100);
 | 
			
		||||
    const freshness = this.calculateToolFreshness(tool);
 | 
			
		||||
    
 | 
			
		||||
    const overall = (
 | 
			
		||||
      embeddingsQuality * this.confidenceConfig.embeddingsWeight +
 | 
			
		||||
      domainAlignment * this.confidenceConfig.domainMatchWeight +
 | 
			
		||||
      consensus * this.confidenceConfig.consensusWeight +
 | 
			
		||||
      freshness * this.confidenceConfig.freshnessWeight
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const uncertaintyFactors = this.identifyUncertaintyFactors(tool, context, overall);
 | 
			
		||||
    const strengthIndicators = this.identifyStrengthIndicators(tool, context, overall);
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      overall: Math.round(overall),
 | 
			
		||||
      embeddingsQuality: Math.round(embeddingsQuality),
 | 
			
		||||
      domainAlignment: Math.round(domainAlignment), 
 | 
			
		||||
      consensus: Math.round(consensus),
 | 
			
		||||
      freshness: Math.round(freshness),
 | 
			
		||||
      uncertaintyFactors,
 | 
			
		||||
      strengthIndicators
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async analyzeScenario(context: AnalysisContext): Promise<MicroTaskResult> {
 | 
			
		||||
    const isWorkflow = context.mode === 'workflow';
 | 
			
		||||
    const prompt = getPrompt('scenarioAnalysis', isWorkflow, context.userQuery);
 | 
			
		||||
@ -1010,6 +1080,124 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private calculateToolFreshness(tool: any): number {
 | 
			
		||||
    // Base freshness score
 | 
			
		||||
    let freshness = 70; // Default for tools without specific freshness data
 | 
			
		||||
    
 | 
			
		||||
    // Boost for tools with knowledge base (more maintained)
 | 
			
		||||
    if (tool.knowledgebase === true) freshness += 20;
 | 
			
		||||
    
 | 
			
		||||
    // Boost for hosted tools (actively maintained)
 | 
			
		||||
    if (isToolHosted(tool)) freshness += 15;
 | 
			
		||||
    
 | 
			
		||||
    // Slight boost for open source (community maintained)
 | 
			
		||||
    if (tool.license && tool.license !== 'Proprietary') freshness += 5;
 | 
			
		||||
    
 | 
			
		||||
    return Math.min(100, freshness);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private checkDomainMatch(tool: any, userQuery: string): boolean {
 | 
			
		||||
    if (!tool.domains || tool.domains.length === 0) return false;
 | 
			
		||||
    
 | 
			
		||||
    const queryLower = userQuery.toLowerCase();
 | 
			
		||||
    
 | 
			
		||||
    const domainKeywordsEnv = process.env.CONFIDENCE_DOMAIN_KEYWORDS || '';
 | 
			
		||||
    
 | 
			
		||||
    const domainKeywords = domainKeywordsEnv.split('|').reduce((acc, pair) => {
 | 
			
		||||
      const [domain, keywords] = pair.split(':');
 | 
			
		||||
      acc[domain] = keywords.split(',');
 | 
			
		||||
      return acc;
 | 
			
		||||
    }, {});
 | 
			
		||||
    
 | 
			
		||||
    return tool.domains.some(domain => {
 | 
			
		||||
      const keywords = domainKeywords[domain] || [domain.replace('-', ' ')];
 | 
			
		||||
      return keywords.some(keyword => queryLower.includes(keyword));
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private getMicroTaskAgreement(toolName: string, context: AnalysisContext): number {
 | 
			
		||||
    // Check how many micro-tasks selected this tool
 | 
			
		||||
    const microTaskEntries = context.auditTrail.filter(entry => 
 | 
			
		||||
      entry.phase === 'micro-task' && 
 | 
			
		||||
      entry.action.includes('selection') &&
 | 
			
		||||
      entry.output && 
 | 
			
		||||
      typeof entry.output === 'object' &&
 | 
			
		||||
      Array.isArray(entry.output.selectedTools) &&
 | 
			
		||||
      entry.output.selectedTools.includes(toolName)
 | 
			
		||||
    );
 | 
			
		||||
    
 | 
			
		||||
    const totalMicroTasks = context.auditTrail.filter(entry => 
 | 
			
		||||
      entry.phase === 'micro-task' && entry.action.includes('selection')
 | 
			
		||||
    ).length;
 | 
			
		||||
    
 | 
			
		||||
    return totalMicroTasks > 0 ? microTaskEntries.length / totalMicroTasks : 0.8; // Default high agreement
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private getEmbeddingsSimilarity(toolName: string, context: AnalysisContext): number {
 | 
			
		||||
    // Extract similarity from audit trail embeddings entry
 | 
			
		||||
    const embeddingsEntry = context.auditTrail.find(entry => 
 | 
			
		||||
      entry.phase === 'retrieval' && entry.action === 'embeddings-search'
 | 
			
		||||
    );
 | 
			
		||||
    
 | 
			
		||||
    if (!embeddingsEntry || !embeddingsEntry.output) return 0.5; // Default medium similarity
 | 
			
		||||
    
 | 
			
		||||
    // Look for similarity data in the output (implementation specific)
 | 
			
		||||
    // This would need to be populated during embeddings search
 | 
			
		||||
    return 0.7; // Placeholder - would need actual similarity data from embeddings
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private identifyUncertaintyFactors(tool: any, context: AnalysisContext, confidence: number): string[] {
 | 
			
		||||
    const factors: string[] = [];
 | 
			
		||||
    
 | 
			
		||||
    if (confidence < this.confidenceConfig.mediumThreshold) {
 | 
			
		||||
      factors.push('Low overall confidence - consider manual validation');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (!this.checkDomainMatch(tool, context.userQuery)) {
 | 
			
		||||
      factors.push('Domain mismatch detected - tool may not be specifically designed for this scenario');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (tool.skillLevel === 'expert' && /rapid|quick|urgent|triage/i.test(context.userQuery)) {
 | 
			
		||||
      factors.push('Expert-level tool for rapid scenario - may be overcomplicated');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (tool.type === 'software' && !isToolHosted(tool) && !tool.url) {
 | 
			
		||||
      factors.push('Limited access information - availability uncertain');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (tool.skillLevel === 'novice' && /complex|advanced|deep/i.test(context.userQuery)) {
 | 
			
		||||
      factors.push('Novice-level tool for complex scenario - may lack required capabilities');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return factors;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private identifyStrengthIndicators(tool: any, context: AnalysisContext, confidence: number): string[] {
 | 
			
		||||
    const indicators: string[] = [];
 | 
			
		||||
    
 | 
			
		||||
    if (confidence >= this.confidenceConfig.highThreshold) {
 | 
			
		||||
      indicators.push('High confidence recommendation based on multiple factors');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (this.checkDomainMatch(tool, context.userQuery)) {
 | 
			
		||||
      indicators.push('Strong domain alignment with scenario requirements');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (tool.knowledgebase === true) {
 | 
			
		||||
      indicators.push('Documentation and knowledge base available for guidance');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (isToolHosted(tool)) {
 | 
			
		||||
      indicators.push('Hosted solution available for immediate access');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (tool.type === 'method' && /methodology|approach|process/i.test(context.userQuery)) {
 | 
			
		||||
      indicators.push('Methodological approach matches procedural inquiry');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return indicators;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private buildRecommendation(context: AnalysisContext, mode: string, finalContent: string): any {
 | 
			
		||||
    const isWorkflow = mode === 'workflow';
 | 
			
		||||
    
 | 
			
		||||
@ -1025,20 +1213,71 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (isWorkflow) {
 | 
			
		||||
      return {
 | 
			
		||||
        ...base,
 | 
			
		||||
        recommended_tools: context.selectedTools?.map(st => ({
 | 
			
		||||
      const recommendedToolsWithConfidence = context.selectedTools?.map(st => {
 | 
			
		||||
        // Calculate confidence for each tool
 | 
			
		||||
        const confidence = this.calculateRecommendationConfidence(
 | 
			
		||||
          st.tool,
 | 
			
		||||
          this.getEmbeddingsSimilarity(st.tool.name, context),
 | 
			
		||||
          this.checkDomainMatch(st.tool, context.userQuery),
 | 
			
		||||
          this.getMicroTaskAgreement(st.tool.name, context),
 | 
			
		||||
          context
 | 
			
		||||
        );
 | 
			
		||||
        
 | 
			
		||||
        // Add audit entry for confidence calculation
 | 
			
		||||
        this.addAuditEntry(context, 'validation', 'confidence-scoring',
 | 
			
		||||
          { toolName: st.tool.name, phase: st.phase },
 | 
			
		||||
          { 
 | 
			
		||||
            overall: confidence.overall,
 | 
			
		||||
            components: {
 | 
			
		||||
              embeddings: confidence.embeddingsQuality,
 | 
			
		||||
              domain: confidence.domainAlignment,
 | 
			
		||||
              consensus: confidence.consensus,
 | 
			
		||||
              freshness: confidence.freshness
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          confidence.overall,
 | 
			
		||||
          Date.now(),
 | 
			
		||||
          { uncertaintyCount: confidence.uncertaintyFactors.length }
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
          name: st.tool.name,
 | 
			
		||||
          phase: st.phase,
 | 
			
		||||
          priority: st.priority,
 | 
			
		||||
          justification: st.justification || `Empfohlen für ${st.phase}`
 | 
			
		||||
        })) || [],
 | 
			
		||||
          justification: st.justification || `Empfohlen für ${st.phase}`,
 | 
			
		||||
          confidence: confidence,
 | 
			
		||||
          recommendationStrength: confidence.overall >= this.confidenceConfig.highThreshold ? 'strong' : 
 | 
			
		||||
                                confidence.overall >= this.confidenceConfig.mediumThreshold ? 'moderate' : 'weak'
 | 
			
		||||
        };
 | 
			
		||||
      }) || [];
 | 
			
		||||
 | 
			
		||||
      return {
 | 
			
		||||
        ...base,
 | 
			
		||||
        recommended_tools: recommendedToolsWithConfidence,
 | 
			
		||||
        workflow_suggestion: finalContent
 | 
			
		||||
      };
 | 
			
		||||
    } else {
 | 
			
		||||
      return {
 | 
			
		||||
        ...base,
 | 
			
		||||
        recommended_tools: context.selectedTools?.map(st => ({
 | 
			
		||||
      const recommendedToolsWithConfidence = context.selectedTools?.map(st => {
 | 
			
		||||
        const confidence = this.calculateRecommendationConfidence(
 | 
			
		||||
          st.tool,
 | 
			
		||||
          this.getEmbeddingsSimilarity(st.tool.name, context),
 | 
			
		||||
          this.checkDomainMatch(st.tool, context.userQuery),
 | 
			
		||||
          this.getMicroTaskAgreement(st.tool.name, context),
 | 
			
		||||
          context
 | 
			
		||||
        );
 | 
			
		||||
        
 | 
			
		||||
        this.addAuditEntry(context, 'validation', 'confidence-scoring',
 | 
			
		||||
          { toolName: st.tool.name, rank: st.tool.evaluation?.rank || 1 },
 | 
			
		||||
          { 
 | 
			
		||||
            overall: confidence.overall,
 | 
			
		||||
            suitabilityAlignment: st.priority === 'high' && confidence.overall >= this.confidenceConfig.highThreshold
 | 
			
		||||
          },
 | 
			
		||||
          confidence.overall,
 | 
			
		||||
          Date.now(),
 | 
			
		||||
          { strengthCount: confidence.strengthIndicators.length }
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
          name: st.tool.name,
 | 
			
		||||
          rank: st.tool.evaluation?.rank || 1,
 | 
			
		||||
          suitability_score: st.priority,
 | 
			
		||||
@ -1046,8 +1285,16 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
 | 
			
		||||
          implementation_approach: st.tool.evaluation?.implementation_approach || '',
 | 
			
		||||
          pros: st.tool.evaluation?.pros || [],
 | 
			
		||||
          cons: st.tool.evaluation?.cons || [],
 | 
			
		||||
          alternatives: st.tool.evaluation?.alternatives || ''
 | 
			
		||||
        })) || [],
 | 
			
		||||
          alternatives: st.tool.evaluation?.alternatives || '',
 | 
			
		||||
          confidence: confidence,
 | 
			
		||||
          recommendationStrength: confidence.overall >= this.confidenceConfig.highThreshold ? 'strong' : 
 | 
			
		||||
                                confidence.overall >= this.confidenceConfig.mediumThreshold ? 'moderate' : 'weak'
 | 
			
		||||
        };
 | 
			
		||||
      }) || [];
 | 
			
		||||
 | 
			
		||||
      return {
 | 
			
		||||
        ...base,
 | 
			
		||||
        recommended_tools: recommendedToolsWithConfidence,
 | 
			
		||||
        additional_considerations: finalContent
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										89
									
								
								unused-selectors.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								unused-selectors.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,89 @@
 | 
			
		||||
.container-wide
 | 
			
		||||
.section-sm
 | 
			
		||||
.section-lg
 | 
			
		||||
.flex-center
 | 
			
		||||
.flex-start
 | 
			
		||||
.flex-end
 | 
			
		||||
.grid-3
 | 
			
		||||
.grid-auto-fit-sm
 | 
			
		||||
.grid-auto-fit-lg
 | 
			
		||||
.gap-6
 | 
			
		||||
.m-1
 | 
			
		||||
.m-2
 | 
			
		||||
.m-3
 | 
			
		||||
.m-4
 | 
			
		||||
.m-6
 | 
			
		||||
.m-8
 | 
			
		||||
.mt-0
 | 
			
		||||
.mt-6
 | 
			
		||||
.mt-8
 | 
			
		||||
.mr-1
 | 
			
		||||
.mr-4
 | 
			
		||||
.ml-1
 | 
			
		||||
.ml-3
 | 
			
		||||
.ml-4
 | 
			
		||||
.p-0
 | 
			
		||||
.p-1
 | 
			
		||||
.px-1
 | 
			
		||||
.px-2
 | 
			
		||||
.py-1
 | 
			
		||||
.py-3
 | 
			
		||||
.py-4
 | 
			
		||||
.py-6
 | 
			
		||||
.pb-2
 | 
			
		||||
.content-narrow
 | 
			
		||||
.content-wide
 | 
			
		||||
.card-info-md
 | 
			
		||||
.card-info-lg
 | 
			
		||||
.info-text
 | 
			
		||||
.info-text-center
 | 
			
		||||
.grid-auto-300
 | 
			
		||||
.grid-auto-400
 | 
			
		||||
.grid-auto-500
 | 
			
		||||
.pros-cons-section
 | 
			
		||||
.tool-metadata
 | 
			
		||||
.text-left
 | 
			
		||||
.font-normal
 | 
			
		||||
.font-bold
 | 
			
		||||
.text-error
 | 
			
		||||
.inline-block
 | 
			
		||||
.relative
 | 
			
		||||
.absolute
 | 
			
		||||
.sticky
 | 
			
		||||
.top-0
 | 
			
		||||
.left-0
 | 
			
		||||
.z-10
 | 
			
		||||
.z-100
 | 
			
		||||
.overflow-auto
 | 
			
		||||
.rounded-md
 | 
			
		||||
.rounded-2xl
 | 
			
		||||
.bg-tertiary
 | 
			
		||||
.h-12
 | 
			
		||||
.nav-link
 | 
			
		||||
.nav-link:hover
 | 
			
		||||
.btn-xs
 | 
			
		||||
.card-sm
 | 
			
		||||
.card-lg
 | 
			
		||||
.card-gradient
 | 
			
		||||
.card-hero
 | 
			
		||||
.card-concept
 | 
			
		||||
.badge-accent
 | 
			
		||||
.tool-chip
 | 
			
		||||
.tool-chip:hover
 | 
			
		||||
.phase-grid
 | 
			
		||||
.phase-chip
 | 
			
		||||
.phase-chip:hover
 | 
			
		||||
.filter-row
 | 
			
		||||
.phase-card
 | 
			
		||||
.phase-card::before
 | 
			
		||||
.phase-card:hover
 | 
			
		||||
.tool-rec-metadata
 | 
			
		||||
.stat-unit
 | 
			
		||||
.share-btn--small
 | 
			
		||||
.collaboration-tool-compact
 | 
			
		||||
.collaboration-tool-compact:hover
 | 
			
		||||
.domain-phase-container
 | 
			
		||||
.card-info-xl
 | 
			
		||||
.text-3xl
 | 
			
		||||
.audit-progress-step
 | 
			
		||||
.audit-progress-step::before
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user