change tools->meToCo

This commit is contained in:
overcuriousity 2025-08-04 21:52:10 +02:00
parent f00e2d3cfd
commit 223d28f094
27 changed files with 366 additions and 366 deletions

View File

@ -315,7 +315,7 @@ PUBLIC_BASE_URL=http://localhost:4321
Die Tools werden in `src/data/tools.yaml` verwaltet. Vollständiges Beispiel: Die Tools werden in `src/data/tools.yaml` verwaltet. Vollständiges Beispiel:
```yaml ```yaml
tools: meToCo:
- name: Autopsy - name: Autopsy
type: software # software|method|concept type: software # software|method|concept
description: >- description: >-
@ -431,7 +431,7 @@ phases:
domain-agnostic-software: domain-agnostic-software:
- id: collaboration-general - id: collaboration-general
name: Übergreifend & Kollaboration name: Übergreifend & Kollaboration
description: Cross-cutting tools and collaboration platforms description: Cross-cutting meToCo and collaboration platforms
- id: specific-os - id: specific-os
name: Betriebssysteme name: Betriebssysteme
description: Operating Systems which focus on forensics description: Operating Systems which focus on forensics

View File

@ -158,7 +158,7 @@
text-align: center; text-align: center;
} }
.tools-grid { .meToCo-grid {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px; gap: 20px;
@ -370,7 +370,7 @@
.stats-grid { .stats-grid {
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
} }
.tools-grid { .meToCo-grid {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
.checkbox-group { .checkbox-group {
@ -396,12 +396,12 @@
<div class="container"> <div class="container">
<div class="header"> <div class="header">
<h1>🔧 DFIR Tools YAML Editor</h1> <h1>🔧 DFIR Tools YAML Editor</h1>
<p>Enhanced editor for Digital Forensics and Incident Response tools, methods, and concepts</p> <p>Enhanced editor for Digital Forensics and Incident Response meToCo, methods, and concepts</p>
</div> </div>
<div class="tabs"> <div class="tabs">
<div class="tab active" onclick="showTab('overview')">📊 Overview</div> <div class="tab active" onclick="showTab('overview')">📊 Overview</div>
<div class="tab" onclick="showTab('tools')">🛠️ Tools & Concepts</div> <div class="tab" onclick="showTab('meToCo')">🛠️ Tools & Concepts</div>
<div class="tab" onclick="showTab('editor')">✏️ Editor</div> <div class="tab" onclick="showTab('editor')">✏️ Editor</div>
<div class="tab" onclick="showTab('bulk')">📋 Bulk Edit</div> <div class="tab" onclick="showTab('bulk')">📋 Bulk Edit</div>
<div class="tab" onclick="showTab('knowledge')">📚 Knowledge Generator</div> <div class="tab" onclick="showTab('knowledge')">📚 Knowledge Generator</div>
@ -413,7 +413,7 @@
<div style="background: var(--light); padding: 20px; border-radius: 10px; margin-bottom: 20px; border: 2px dashed var(--border); text-align: center;"> <div style="background: var(--light); padding: 20px; border-radius: 10px; margin-bottom: 20px; border: 2px dashed var(--border); text-align: center;">
<h3>📁 Load YAML File</h3> <h3>📁 Load YAML File</h3>
<input type="file" id="fileInput" accept=".yaml,.yml" onchange="loadFile()"> <input type="file" id="fileInput" accept=".yaml,.yml" onchange="loadFile()">
<p>Select a YAML file to load existing tools data</p> <p>Select a YAML file to load existing meToCo data</p>
</div> </div>
<div id="stats" class="stats-grid"></div> <div id="stats" class="stats-grid"></div>
@ -430,7 +430,7 @@
</div> </div>
<!-- Tools Tab with Enhanced Search --> <!-- Tools Tab with Enhanced Search -->
<div id="tools" class="tab-content"> <div id="meToCo" class="tab-content">
<div class="search-container"> <div class="search-container">
<h3>🔍 Search & Filter Tools</h3> <h3>🔍 Search & Filter Tools</h3>
<input type="text" <input type="text"
@ -460,7 +460,7 @@
<button class="btn btn-secondary" onclick="clearFilters()">Clear All</button> <button class="btn btn-secondary" onclick="clearFilters()">Clear All</button>
</div> </div>
</div> </div>
<div id="toolsGrid" class="tools-grid"></div> <div id="meToCoGrid" class="meToCo-grid"></div>
</div> </div>
<!-- Enhanced Editor Tab --> <!-- Enhanced Editor Tab -->
@ -645,7 +645,7 @@
<div class="bulk-section"> <div class="bulk-section">
<h3>📋 Bulk Operations</h3> <h3>📋 Bulk Operations</h3>
<div id="selectionInfo" style="margin-bottom: 15px; padding: 15px; background: white; border-radius: 8px; font-weight: 600; text-align: center; border: 2px solid var(--primary);"> <div id="selectionInfo" style="margin-bottom: 15px; padding: 15px; background: white; border-radius: 8px; font-weight: 600; text-align: center; border: 2px solid var(--primary);">
No tools selected No meToCo selected
</div> </div>
<div class="bulk-controls"> <div class="bulk-controls">
@ -702,7 +702,7 @@
<button class="btn btn-danger" onclick="bulkDelete()">💀 Delete Selected Tools</button> <button class="btn btn-danger" onclick="bulkDelete()">💀 Delete Selected Tools</button>
</div> </div>
</div> </div>
<div id="bulkToolsGrid" class="tools-grid"></div> <div id="bulkToolsGrid" class="meToCo-grid"></div>
</div> </div>
<!-- Knowledge Generator Tab --> <!-- Knowledge Generator Tab -->
@ -755,7 +755,7 @@
// Initialize with correct YAML structure including scenarios // Initialize with correct YAML structure including scenarios
function init() { function init() {
yamlData = { yamlData = {
tools: [], meToCo: [],
domains: [ domains: [
{ id: 'incident-response', name: 'Incident Response & Breach-Untersuchung' }, { id: 'incident-response', name: 'Incident Response & Breach-Untersuchung' },
{ id: 'static-investigations', name: 'Datenträgerforensik & Ermittlungen' }, { id: 'static-investigations', name: 'Datenträgerforensik & Ermittlungen' },
@ -773,7 +773,7 @@
{ id: 'reporting', name: 'Bericht & Präsentation', description: 'Documentation, Visualization, Presentation Tools' } { id: 'reporting', name: 'Bericht & Präsentation', description: 'Documentation, Visualization, Presentation Tools' }
], ],
'domain-agnostic-software': [ 'domain-agnostic-software': [
{ id: 'collaboration-general', name: 'Übergreifend & Kollaboration', description: 'Cross-cutting tools and collaboration platforms' }, { id: 'collaboration-general', name: 'Übergreifend & Kollaboration', description: 'Cross-cutting meToCo and collaboration platforms' },
{ id: 'specific-os', name: 'Betriebssysteme', description: 'Operating Systems which focus on forensics' } { id: 'specific-os', name: 'Betriebssysteme', description: 'Operating Systems which focus on forensics' }
], ],
scenarios: [ scenarios: [
@ -801,7 +801,7 @@
document.getElementById(tabName).classList.add('active'); document.getElementById(tabName).classList.add('active');
event.target.classList.add('active'); event.target.classList.add('active');
if (tabName === 'tools') renderToolsGrid(); if (tabName === 'meToCo') renderToolsGrid();
else if (tabName === 'bulk') renderBulkGrid(); else if (tabName === 'bulk') renderBulkGrid();
else if (tabName === 'knowledge') updateKnowledgeToolSelect(); else if (tabName === 'knowledge') updateKnowledgeToolSelect();
} }
@ -811,11 +811,11 @@
applyFilters(); applyFilters();
} }
function searchTools(tools, searchTerm) { function searchTools(meToCo, searchTerm) {
if (!searchTerm) return tools; if (!searchTerm) return meToCo;
const term = searchTerm.toLowerCase(); const term = searchTerm.toLowerCase();
return tools.filter(tool => { return meToCo.filter(tool => {
// Search in name // Search in name
if (tool.name && tool.name.toLowerCase().includes(term)) return true; if (tool.name && tool.name.toLowerCase().includes(term)) return true;
@ -946,15 +946,15 @@
} }
function updateStats() { function updateStats() {
if (!yamlData?.tools) return; if (!yamlData?.meToCo) return;
const stats = { const stats = {
total: yamlData.tools.length, total: yamlData.meToCo.length,
software: yamlData.tools.filter(t => t.type === 'software' || !t.type).length, software: yamlData.meToCo.filter(t => t.type === 'software' || !t.type).length,
methods: yamlData.tools.filter(t => t.type === 'method').length, methods: yamlData.meToCo.filter(t => t.type === 'method').length,
concepts: yamlData.tools.filter(t => t.type === 'concept').length, concepts: yamlData.meToCo.filter(t => t.type === 'concept').length,
withKnowledgebase: yamlData.tools.filter(t => t.knowledgebase).length, withKnowledgebase: yamlData.meToCo.filter(t => t.knowledgebase).length,
withRelatedSoftware: yamlData.tools.filter(t => t.related_software && t.related_software.length > 0).length withRelatedSoftware: yamlData.meToCo.filter(t => t.related_software && t.related_software.length > 0).length
}; };
document.getElementById('stats').innerHTML = ` document.getElementById('stats').innerHTML = `
@ -1042,8 +1042,8 @@
function saveTool() { function saveTool() {
try { try {
if (!yamlData) yamlData = { tools: [] }; if (!yamlData) yamlData = { meToCo: [] };
if (!yamlData.tools) yamlData.tools = []; if (!yamlData.meToCo) yamlData.meToCo = [];
const toolType = document.getElementById('toolType').value; const toolType = document.getElementById('toolType').value;
const tool = { const tool = {
@ -1104,11 +1104,11 @@
} }
if (currentEditingIndex >= 0) { if (currentEditingIndex >= 0) {
yamlData.tools[currentEditingIndex] = tool; yamlData.meToCo[currentEditingIndex] = tool;
showMessage('Tool updated successfully!'); showMessage('Tool updated successfully!');
currentEditingIndex = -1; currentEditingIndex = -1;
} else { } else {
yamlData.tools.push(tool); yamlData.meToCo.push(tool);
showMessage('Tool added successfully!'); showMessage('Tool added successfully!');
} }
@ -1146,7 +1146,7 @@
} }
function editTool(index) { function editTool(index) {
const tool = yamlData.tools[index]; const tool = yamlData.meToCo[index];
currentEditingIndex = index; currentEditingIndex = index;
// Populate form fields // Populate form fields
@ -1208,7 +1208,7 @@
function deleteTool(index) { function deleteTool(index) {
if (confirm('Are you sure you want to delete this tool?')) { if (confirm('Are you sure you want to delete this tool?')) {
yamlData.tools.splice(index, 1); yamlData.meToCo.splice(index, 1);
showMessage('Tool deleted successfully!'); showMessage('Tool deleted successfully!');
updateStats(); updateStats();
renderToolsGrid(); renderToolsGrid();
@ -1217,12 +1217,12 @@
} }
function renderToolsGrid() { function renderToolsGrid() {
const container = document.getElementById('toolsGrid'); const container = document.getElementById('meToCoGrid');
container.innerHTML = ''; container.innerHTML = '';
if (!yamlData?.tools) return; if (!yamlData?.meToCo) return;
let filteredTools = yamlData.tools; let filteredTools = yamlData.meToCo;
// Apply search filter // Apply search filter
const searchTerm = document.getElementById('searchInput')?.value; const searchTerm = document.getElementById('searchInput')?.value;
@ -1243,17 +1243,17 @@
// Update search results info // Update search results info
const searchResults = document.getElementById('searchResults'); const searchResults = document.getElementById('searchResults');
if (searchResults) { if (searchResults) {
const totalTools = yamlData.tools.length; const totalTools = yamlData.meToCo.length;
const filteredCount = filteredTools.length; const filteredCount = filteredTools.length;
if (searchTerm || typeFilter || skillFilter) { if (searchTerm || typeFilter || skillFilter) {
searchResults.textContent = `Showing ${filteredCount} of ${totalTools} tools`; searchResults.textContent = `Showing ${filteredCount} of ${totalTools} meToCo`;
} else { } else {
searchResults.textContent = `Showing all ${totalTools} tools`; searchResults.textContent = `Showing all ${totalTools} meToCo`;
} }
} }
filteredTools.forEach((tool, index) => { filteredTools.forEach((tool, index) => {
const originalIndex = yamlData.tools.indexOf(tool); const originalIndex = yamlData.meToCo.indexOf(tool);
const card = createToolCard(tool, originalIndex); const card = createToolCard(tool, originalIndex);
container.appendChild(card); container.appendChild(card);
}); });
@ -1296,9 +1296,9 @@
const container = document.getElementById('bulkToolsGrid'); const container = document.getElementById('bulkToolsGrid');
container.innerHTML = ''; container.innerHTML = '';
if (!yamlData?.tools) return; if (!yamlData?.meToCo) return;
yamlData.tools.forEach((tool, index) => { yamlData.meToCo.forEach((tool, index) => {
const card = createBulkToolCard(tool, index); const card = createBulkToolCard(tool, index);
container.appendChild(card); container.appendChild(card);
}); });
@ -1350,7 +1350,7 @@
function selectAllTools() { function selectAllTools() {
selectedTools.clear(); selectedTools.clear();
yamlData.tools.forEach((_, index) => selectedTools.add(index)); yamlData.meToCo.forEach((_, index) => selectedTools.add(index));
updateSelectionCount(); updateSelectionCount();
renderBulkGrid(); renderBulkGrid();
} }
@ -1365,7 +1365,7 @@
const count = selectedTools.size; const count = selectedTools.size;
const info = document.getElementById('selectionInfo'); const info = document.getElementById('selectionInfo');
if (count === 0) { if (count === 0) {
info.textContent = 'No tools selected'; info.textContent = 'No meToCo selected';
info.style.background = 'white'; info.style.background = 'white';
info.style.borderColor = 'var(--border)'; info.style.borderColor = 'var(--border)';
} else { } else {
@ -1377,175 +1377,175 @@
// Enhanced bulk operations with scenarios and related software // Enhanced bulk operations with scenarios and related software
function bulkSetType() { function bulkSetType() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
const newType = prompt('Enter new type (software/method/concept):'); const newType = prompt('Enter new type (software/method/concept):');
if (newType && ['software', 'method', 'concept'].includes(newType)) { if (newType && ['software', 'method', 'concept'].includes(newType)) {
selectedTools.forEach(index => yamlData.tools[index].type = newType); selectedTools.forEach(index => yamlData.meToCo[index].type = newType);
showMessage(`Updated type for ${selectedTools.size} tools`); showMessage(`Updated type for ${selectedTools.size} meToCo`);
updateStats(); updateStats();
renderBulkGrid(); renderBulkGrid();
} }
} }
function bulkSetSkillLevel() { function bulkSetSkillLevel() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
const newLevel = prompt('Enter skill level (novice/beginner/intermediate/advanced/expert):'); const newLevel = prompt('Enter skill level (novice/beginner/intermediate/advanced/expert):');
if (newLevel && ['novice', 'beginner', 'intermediate', 'advanced', 'expert'].includes(newLevel)) { if (newLevel && ['novice', 'beginner', 'intermediate', 'advanced', 'expert'].includes(newLevel)) {
selectedTools.forEach(index => yamlData.tools[index].skillLevel = newLevel); selectedTools.forEach(index => yamlData.meToCo[index].skillLevel = newLevel);
showMessage(`Updated skill level for ${selectedTools.size} tools`); showMessage(`Updated skill level for ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
function bulkAddTags() { function bulkAddTags() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
const tags = prompt('Enter tags to add (comma-separated):'); const tags = prompt('Enter tags to add (comma-separated):');
if (tags) { if (tags) {
const tagList = tags.split(',').map(t => t.trim()).filter(t => t); const tagList = tags.split(',').map(t => t.trim()).filter(t => t);
selectedTools.forEach(index => { selectedTools.forEach(index => {
const tool = yamlData.tools[index]; const tool = yamlData.meToCo[index];
tool.tags = [...new Set([...(tool.tags || []), ...tagList])]; tool.tags = [...new Set([...(tool.tags || []), ...tagList])];
}); });
showMessage(`Added tags to ${selectedTools.size} tools`); showMessage(`Added tags to ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
function bulkRemoveTags() { function bulkRemoveTags() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
const tags = prompt('Enter tags to remove (comma-separated):'); const tags = prompt('Enter tags to remove (comma-separated):');
if (tags) { if (tags) {
const tagList = tags.split(',').map(t => t.trim()).filter(t => t); const tagList = tags.split(',').map(t => t.trim()).filter(t => t);
selectedTools.forEach(index => { selectedTools.forEach(index => {
const tool = yamlData.tools[index]; const tool = yamlData.meToCo[index];
if (tool.tags) { if (tool.tags) {
tool.tags = tool.tags.filter(tag => !tagList.includes(tag)); tool.tags = tool.tags.filter(tag => !tagList.includes(tag));
if (tool.tags.length === 0) delete tool.tags; if (tool.tags.length === 0) delete tool.tags;
} }
}); });
showMessage(`Removed tags from ${selectedTools.size} tools`); showMessage(`Removed tags from ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
function bulkReplaceTags() { function bulkReplaceTags() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
const tags = prompt('Enter new tags (comma-separated, will replace all existing tags):'); const tags = prompt('Enter new tags (comma-separated, will replace all existing tags):');
if (tags !== null) { if (tags !== null) {
const tagList = tags.split(',').map(t => t.trim()).filter(t => t); const tagList = tags.split(',').map(t => t.trim()).filter(t => t);
selectedTools.forEach(index => { selectedTools.forEach(index => {
const tool = yamlData.tools[index]; const tool = yamlData.meToCo[index];
if (tagList.length > 0) { if (tagList.length > 0) {
tool.tags = tagList; tool.tags = tagList;
} else { } else {
delete tool.tags; delete tool.tags;
} }
}); });
showMessage(`Replaced tags for ${selectedTools.size} tools`); showMessage(`Replaced tags for ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
function bulkClearTags() { function bulkClearTags() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
if (confirm(`Are you sure you want to clear ALL tags from ${selectedTools.size} selected tools?`)) { if (confirm(`Are you sure you want to clear ALL tags from ${selectedTools.size} selected meToCo?`)) {
selectedTools.forEach(index => { selectedTools.forEach(index => {
delete yamlData.tools[index].tags; delete yamlData.meToCo[index].tags;
}); });
showMessage(`Cleared tags from ${selectedTools.size} tools`); showMessage(`Cleared tags from ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
// Domain operations // Domain operations
function bulkAddDomains() { function bulkAddDomains() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
const domains = prompt('Enter domain IDs to add (comma-separated):'); const domains = prompt('Enter domain IDs to add (comma-separated):');
if (domains) { if (domains) {
const domainList = domains.split(',').map(d => d.trim()).filter(d => d); const domainList = domains.split(',').map(d => d.trim()).filter(d => d);
selectedTools.forEach(index => { selectedTools.forEach(index => {
const tool = yamlData.tools[index]; const tool = yamlData.meToCo[index];
tool.domains = [...new Set([...(tool.domains || []), ...domainList])]; tool.domains = [...new Set([...(tool.domains || []), ...domainList])];
}); });
showMessage(`Added domains to ${selectedTools.size} tools`); showMessage(`Added domains to ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
function bulkRemoveDomains() { function bulkRemoveDomains() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
const domains = prompt('Enter domain IDs to remove (comma-separated):'); const domains = prompt('Enter domain IDs to remove (comma-separated):');
if (domains) { if (domains) {
const domainList = domains.split(',').map(d => d.trim()).filter(d => d); const domainList = domains.split(',').map(d => d.trim()).filter(d => d);
selectedTools.forEach(index => { selectedTools.forEach(index => {
const tool = yamlData.tools[index]; const tool = yamlData.meToCo[index];
if (tool.domains) { if (tool.domains) {
tool.domains = tool.domains.filter(domain => !domainList.includes(domain)); tool.domains = tool.domains.filter(domain => !domainList.includes(domain));
if (tool.domains.length === 0) delete tool.domains; if (tool.domains.length === 0) delete tool.domains;
} }
}); });
showMessage(`Removed domains from ${selectedTools.size} tools`); showMessage(`Removed domains from ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
function bulkClearDomains() { function bulkClearDomains() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
if (confirm(`Are you sure you want to clear ALL domains from ${selectedTools.size} selected tools?`)) { if (confirm(`Are you sure you want to clear ALL domains from ${selectedTools.size} selected meToCo?`)) {
selectedTools.forEach(index => { selectedTools.forEach(index => {
delete yamlData.tools[index].domains; delete yamlData.meToCo[index].domains;
}); });
showMessage(`Cleared domains from ${selectedTools.size} tools`); showMessage(`Cleared domains from ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
// Phase operations // Phase operations
function bulkAddPhases() { function bulkAddPhases() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
const phases = prompt('Enter phase IDs to add (comma-separated):'); const phases = prompt('Enter phase IDs to add (comma-separated):');
if (phases) { if (phases) {
const phaseList = phases.split(',').map(p => p.trim()).filter(p => p); const phaseList = phases.split(',').map(p => p.trim()).filter(p => p);
selectedTools.forEach(index => { selectedTools.forEach(index => {
const tool = yamlData.tools[index]; const tool = yamlData.meToCo[index];
tool.phases = [...new Set([...(tool.phases || []), ...phaseList])]; tool.phases = [...new Set([...(tool.phases || []), ...phaseList])];
}); });
showMessage(`Added phases to ${selectedTools.size} tools`); showMessage(`Added phases to ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
function bulkRemovePhases() { function bulkRemovePhases() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
const phases = prompt('Enter phase IDs to remove (comma-separated):'); const phases = prompt('Enter phase IDs to remove (comma-separated):');
if (phases) { if (phases) {
const phaseList = phases.split(',').map(p => p.trim()).filter(p => p); const phaseList = phases.split(',').map(p => p.trim()).filter(p => p);
selectedTools.forEach(index => { selectedTools.forEach(index => {
const tool = yamlData.tools[index]; const tool = yamlData.meToCo[index];
if (tool.phases) { if (tool.phases) {
tool.phases = tool.phases.filter(phase => !phaseList.includes(phase)); tool.phases = tool.phases.filter(phase => !phaseList.includes(phase));
if (tool.phases.length === 0) delete tool.phases; if (tool.phases.length === 0) delete tool.phases;
} }
}); });
showMessage(`Removed phases from ${selectedTools.size} tools`); showMessage(`Removed phases from ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
function bulkClearPhases() { function bulkClearPhases() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
if (confirm(`Are you sure you want to clear ALL phases from ${selectedTools.size} selected tools?`)) { if (confirm(`Are you sure you want to clear ALL phases from ${selectedTools.size} selected meToCo?`)) {
selectedTools.forEach(index => { selectedTools.forEach(index => {
delete yamlData.tools[index].phases; delete yamlData.meToCo[index].phases;
}); });
showMessage(`Cleared phases from ${selectedTools.size} tools`); showMessage(`Cleared phases from ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
// Scenario operations (work with tags that have scenario: prefix) // Scenario operations (work with tags that have scenario: prefix)
function bulkAddScenarios() { function bulkAddScenarios() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
const scenarios = prompt('Enter scenario IDs to add (comma-separated, e.g., scenario:memory_dump,scenario:registry):'); const scenarios = prompt('Enter scenario IDs to add (comma-separated, e.g., scenario:memory_dump,scenario:registry):');
if (scenarios) { if (scenarios) {
const scenarioList = scenarios.split(',').map(s => { const scenarioList = scenarios.split(',').map(s => {
@ -1553,16 +1553,16 @@
return trimmed.startsWith('scenario:') ? trimmed : `scenario:${trimmed}`; return trimmed.startsWith('scenario:') ? trimmed : `scenario:${trimmed}`;
}).filter(s => s !== 'scenario:'); }).filter(s => s !== 'scenario:');
selectedTools.forEach(index => { selectedTools.forEach(index => {
const tool = yamlData.tools[index]; const tool = yamlData.meToCo[index];
tool.tags = [...new Set([...(tool.tags || []), ...scenarioList])]; tool.tags = [...new Set([...(tool.tags || []), ...scenarioList])];
}); });
showMessage(`Added scenario tags to ${selectedTools.size} tools`); showMessage(`Added scenario tags to ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
function bulkRemoveScenarios() { function bulkRemoveScenarios() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
const scenarios = prompt('Enter scenario IDs to remove (comma-separated):'); const scenarios = prompt('Enter scenario IDs to remove (comma-separated):');
if (scenarios) { if (scenarios) {
const scenarioList = scenarios.split(',').map(s => { const scenarioList = scenarios.split(',').map(s => {
@ -1570,168 +1570,168 @@
return trimmed.startsWith('scenario:') ? trimmed : `scenario:${trimmed}`; return trimmed.startsWith('scenario:') ? trimmed : `scenario:${trimmed}`;
}).filter(s => s !== 'scenario:'); }).filter(s => s !== 'scenario:');
selectedTools.forEach(index => { selectedTools.forEach(index => {
const tool = yamlData.tools[index]; const tool = yamlData.meToCo[index];
if (tool.tags) { if (tool.tags) {
tool.tags = tool.tags.filter(tag => !scenarioList.includes(tag)); tool.tags = tool.tags.filter(tag => !scenarioList.includes(tag));
if (tool.tags.length === 0) delete tool.tags; if (tool.tags.length === 0) delete tool.tags;
} }
}); });
showMessage(`Removed scenario tags from ${selectedTools.size} tools`); showMessage(`Removed scenario tags from ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
function bulkClearScenarios() { function bulkClearScenarios() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
if (confirm(`Are you sure you want to clear ALL scenario tags from ${selectedTools.size} selected tools?`)) { if (confirm(`Are you sure you want to clear ALL scenario tags from ${selectedTools.size} selected meToCo?`)) {
selectedTools.forEach(index => { selectedTools.forEach(index => {
const tool = yamlData.tools[index]; const tool = yamlData.meToCo[index];
if (tool.tags) { if (tool.tags) {
tool.tags = tool.tags.filter(tag => !tag.startsWith('scenario:')); tool.tags = tool.tags.filter(tag => !tag.startsWith('scenario:'));
if (tool.tags.length === 0) delete tool.tags; if (tool.tags.length === 0) delete tool.tags;
} }
}); });
showMessage(`Cleared scenario tags from ${selectedTools.size} tools`); showMessage(`Cleared scenario tags from ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
// Platform operations // Platform operations
function bulkAddPlatforms() { function bulkAddPlatforms() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
const platforms = prompt('Enter platforms to add (comma-separated, e.g., Windows,Linux,macOS):'); const platforms = prompt('Enter platforms to add (comma-separated, e.g., Windows,Linux,macOS):');
if (platforms) { if (platforms) {
const platformList = platforms.split(',').map(p => p.trim()).filter(p => p); const platformList = platforms.split(',').map(p => p.trim()).filter(p => p);
selectedTools.forEach(index => { selectedTools.forEach(index => {
const tool = yamlData.tools[index]; const tool = yamlData.meToCo[index];
tool.platforms = [...new Set([...(tool.platforms || []), ...platformList])]; tool.platforms = [...new Set([...(tool.platforms || []), ...platformList])];
}); });
showMessage(`Added platforms to ${selectedTools.size} tools`); showMessage(`Added platforms to ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
function bulkRemovePlatforms() { function bulkRemovePlatforms() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
const platforms = prompt('Enter platforms to remove (comma-separated):'); const platforms = prompt('Enter platforms to remove (comma-separated):');
if (platforms) { if (platforms) {
const platformList = platforms.split(',').map(p => p.trim()).filter(p => p); const platformList = platforms.split(',').map(p => p.trim()).filter(p => p);
selectedTools.forEach(index => { selectedTools.forEach(index => {
const tool = yamlData.tools[index]; const tool = yamlData.meToCo[index];
if (tool.platforms) { if (tool.platforms) {
tool.platforms = tool.platforms.filter(platform => !platformList.includes(platform)); tool.platforms = tool.platforms.filter(platform => !platformList.includes(platform));
if (tool.platforms.length === 0) delete tool.platforms; if (tool.platforms.length === 0) delete tool.platforms;
} }
}); });
showMessage(`Removed platforms from ${selectedTools.size} tools`); showMessage(`Removed platforms from ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
function bulkClearPlatforms() { function bulkClearPlatforms() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
if (confirm(`Are you sure you want to clear ALL platforms from ${selectedTools.size} selected tools?`)) { if (confirm(`Are you sure you want to clear ALL platforms from ${selectedTools.size} selected meToCo?`)) {
selectedTools.forEach(index => { selectedTools.forEach(index => {
delete yamlData.tools[index].platforms; delete yamlData.meToCo[index].platforms;
}); });
showMessage(`Cleared platforms from ${selectedTools.size} tools`); showMessage(`Cleared platforms from ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
// Related concepts operations // Related concepts operations
function bulkAddRelatedConcepts() { function bulkAddRelatedConcepts() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
const concepts = prompt('Enter related concept names to add (comma-separated):'); const concepts = prompt('Enter related concept names to add (comma-separated):');
if (concepts) { if (concepts) {
const conceptList = concepts.split(',').map(c => c.trim()).filter(c => c); const conceptList = concepts.split(',').map(c => c.trim()).filter(c => c);
selectedTools.forEach(index => { selectedTools.forEach(index => {
const tool = yamlData.tools[index]; const tool = yamlData.meToCo[index];
tool.related_concepts = [...new Set([...(tool.related_concepts || []), ...conceptList])]; tool.related_concepts = [...new Set([...(tool.related_concepts || []), ...conceptList])];
}); });
showMessage(`Added related concepts to ${selectedTools.size} tools`); showMessage(`Added related concepts to ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
function bulkRemoveRelatedConcepts() { function bulkRemoveRelatedConcepts() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
const concepts = prompt('Enter related concept names to remove (comma-separated):'); const concepts = prompt('Enter related concept names to remove (comma-separated):');
if (concepts) { if (concepts) {
const conceptList = concepts.split(',').map(c => c.trim()).filter(c => c); const conceptList = concepts.split(',').map(c => c.trim()).filter(c => c);
selectedTools.forEach(index => { selectedTools.forEach(index => {
const tool = yamlData.tools[index]; const tool = yamlData.meToCo[index];
if (tool.related_concepts) { if (tool.related_concepts) {
tool.related_concepts = tool.related_concepts.filter(concept => !conceptList.includes(concept)); tool.related_concepts = tool.related_concepts.filter(concept => !conceptList.includes(concept));
if (tool.related_concepts.length === 0) delete tool.related_concepts; if (tool.related_concepts.length === 0) delete tool.related_concepts;
} }
}); });
showMessage(`Removed related concepts from ${selectedTools.size} tools`); showMessage(`Removed related concepts from ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
function bulkClearRelatedConcepts() { function bulkClearRelatedConcepts() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
if (confirm(`Are you sure you want to clear ALL related concepts from ${selectedTools.size} selected tools?`)) { if (confirm(`Are you sure you want to clear ALL related concepts from ${selectedTools.size} selected meToCo?`)) {
selectedTools.forEach(index => { selectedTools.forEach(index => {
delete yamlData.tools[index].related_concepts; delete yamlData.meToCo[index].related_concepts;
}); });
showMessage(`Cleared related concepts from ${selectedTools.size} tools`); showMessage(`Cleared related concepts from ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
// NEW: Related software operations // NEW: Related software operations
function bulkAddRelatedSoftware() { function bulkAddRelatedSoftware() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
const software = prompt('Enter related software names to add (comma-separated):'); const software = prompt('Enter related software names to add (comma-separated):');
if (software) { if (software) {
const softwareList = software.split(',').map(s => s.trim()).filter(s => s); const softwareList = software.split(',').map(s => s.trim()).filter(s => s);
selectedTools.forEach(index => { selectedTools.forEach(index => {
const tool = yamlData.tools[index]; const tool = yamlData.meToCo[index];
tool.related_software = [...new Set([...(tool.related_software || []), ...softwareList])]; tool.related_software = [...new Set([...(tool.related_software || []), ...softwareList])];
}); });
showMessage(`Added related software to ${selectedTools.size} tools`); showMessage(`Added related software to ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
function bulkRemoveRelatedSoftware() { function bulkRemoveRelatedSoftware() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
const software = prompt('Enter related software names to remove (comma-separated):'); const software = prompt('Enter related software names to remove (comma-separated):');
if (software) { if (software) {
const softwareList = software.split(',').map(s => s.trim()).filter(s => s); const softwareList = software.split(',').map(s => s.trim()).filter(s => s);
selectedTools.forEach(index => { selectedTools.forEach(index => {
const tool = yamlData.tools[index]; const tool = yamlData.meToCo[index];
if (tool.related_software) { if (tool.related_software) {
tool.related_software = tool.related_software.filter(sw => !softwareList.includes(sw)); tool.related_software = tool.related_software.filter(sw => !softwareList.includes(sw));
if (tool.related_software.length === 0) delete tool.related_software; if (tool.related_software.length === 0) delete tool.related_software;
} }
}); });
showMessage(`Removed related software from ${selectedTools.size} tools`); showMessage(`Removed related software from ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
function bulkClearRelatedSoftware() { function bulkClearRelatedSoftware() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
if (confirm(`Are you sure you want to clear ALL related software from ${selectedTools.size} selected tools?`)) { if (confirm(`Are you sure you want to clear ALL related software from ${selectedTools.size} selected meToCo?`)) {
selectedTools.forEach(index => { selectedTools.forEach(index => {
delete yamlData.tools[index].related_software; delete yamlData.meToCo[index].related_software;
}); });
showMessage(`Cleared related software from ${selectedTools.size} tools`); showMessage(`Cleared related software from ${selectedTools.size} meToCo`);
renderBulkGrid(); renderBulkGrid();
} }
} }
function bulkDelete() { function bulkDelete() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error'); if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
if (confirm(`Are you sure you want to delete ${selectedTools.size} selected tools? This action cannot be undone!`)) { if (confirm(`Are you sure you want to delete ${selectedTools.size} selected meToCo? This action cannot be undone!`)) {
const indicesToDelete = Array.from(selectedTools).sort((a, b) => b - a); const indicesToDelete = Array.from(selectedTools).sort((a, b) => b - a);
indicesToDelete.forEach(index => yamlData.tools.splice(index, 1)); indicesToDelete.forEach(index => yamlData.meToCo.splice(index, 1));
selectedTools.clear(); selectedTools.clear();
showMessage(`Deleted ${indicesToDelete.length} tools successfully!`); showMessage(`Deleted ${indicesToDelete.length} meToCo successfully!`);
updateStats(); updateStats();
renderBulkGrid(); renderBulkGrid();
updateKnowledgeToolSelect(); updateKnowledgeToolSelect();
@ -1743,9 +1743,9 @@
const select = document.getElementById('knowledgeToolSelect'); const select = document.getElementById('knowledgeToolSelect');
select.innerHTML = '<option value="">Choose a tool or concept...</option>'; select.innerHTML = '<option value="">Choose a tool or concept...</option>';
if (!yamlData?.tools) return; if (!yamlData?.meToCo) return;
yamlData.tools.forEach((tool, index) => { yamlData.meToCo.forEach((tool, index) => {
const option = document.createElement('option'); const option = document.createElement('option');
option.value = index; option.value = index;
option.textContent = `${tool.icon ? tool.icon + ' ' : ''}${tool.name} (${tool.type || 'software'})`; option.textContent = `${tool.icon ? tool.icon + ' ' : ''}${tool.name} (${tool.type || 'software'})`;
@ -1762,7 +1762,7 @@
return; return;
} }
const tool = yamlData.tools[index]; const tool = yamlData.meToCo[index];
const template = createCC24MarkdownTemplate(tool); const template = createCC24MarkdownTemplate(tool);
document.getElementById('markdownContent').value = template; document.getElementById('markdownContent').value = template;
@ -1781,10 +1781,10 @@ title: "${tool.name}"
description: "${tool.description.split('\n')[0].trim()}" description: "${tool.description.split('\n')[0].trim()}"
last_updated: ${new Date().toISOString().split('T')[0]} last_updated: ${new Date().toISOString().split('T')[0]}
tool_name: "${tool.name}" tool_name: "${tool.name}"
related_tools: ${JSON.stringify([...(tool.related_concepts || []), ...(tool.related_software || [])])} related_meToCo: ${JSON.stringify([...(tool.related_concepts || []), ...(tool.related_software || [])])}
author: "CC24-Team" author: "CC24-Team"
difficulty: "${tool.skillLevel || 'intermediate'}" difficulty: "${tool.skillLevel || 'intermediate'}"
categories: ${tool.type === 'concept' ? '["concepts"]' : tool.type === 'method' ? '["methods"]' : '["tools"]'} categories: ${tool.type === 'concept' ? '["concepts"]' : tool.type === 'method' ? '["methods"]' : '["meToCo"]'}
tags: ${tool.tags ? JSON.stringify(tool.tags) : '[]'} tags: ${tool.tags ? JSON.stringify(tool.tags) : '[]'}
published: true published: true
--- ---
@ -1871,7 +1871,7 @@ TODO: Füge weitere nützliche Links und Ressourcen hinzu.
const content = document.getElementById('markdownContent').value; const content = document.getElementById('markdownContent').value;
const select = document.getElementById('knowledgeToolSelect'); const select = document.getElementById('knowledgeToolSelect');
const index = parseInt(select.value); const index = parseInt(select.value);
const tool = yamlData.tools[index]; const tool = yamlData.meToCo[index];
const toolSlug = tool.name.toLowerCase() const toolSlug = tool.name.toLowerCase()
.replace(/[^a-z0-9\s-]/g, '') .replace(/[^a-z0-9\s-]/g, '')
@ -1909,13 +1909,13 @@ TODO: Füge weitere nützliche Links und Ressourcen hinzu.
const validationResults = []; const validationResults = [];
// Check required sections // Check required sections
if (!yamlData.tools) validationResults.push('❌ Missing tools section'); if (!yamlData.meToCo) validationResults.push('❌ Missing meToCo section');
if (!yamlData.domains) validationResults.push('❌ Missing domains section'); if (!yamlData.domains) validationResults.push('❌ Missing domains section');
if (!yamlData.phases) validationResults.push('❌ Missing phases section'); if (!yamlData.phases) validationResults.push('❌ Missing phases section');
if (!yamlData.scenarios) validationResults.push('⚠️ Missing scenarios section (for reference)'); if (!yamlData.scenarios) validationResults.push('⚠️ Missing scenarios section (for reference)');
// Validate tools // Validate meToCo
yamlData.tools?.forEach((tool, index) => { yamlData.meToCo?.forEach((tool, index) => {
if (!tool.name) validationResults.push(`❌ Tool ${index + 1}: Missing name`); if (!tool.name) validationResults.push(`❌ Tool ${index + 1}: Missing name`);
if (!tool.description) validationResults.push(`❌ Tool ${index + 1}: Missing description`); if (!tool.description) validationResults.push(`❌ Tool ${index + 1}: Missing description`);
if (!tool.skillLevel) validationResults.push(`❌ Tool ${index + 1}: Missing skillLevel`); if (!tool.skillLevel) validationResults.push(`❌ Tool ${index + 1}: Missing skillLevel`);
@ -1936,9 +1936,9 @@ TODO: Füge weitere nützliche Links und Ressourcen hinzu.
// Validate related_software references // Validate related_software references
if (tool.related_software && tool.related_software.length > 0) { if (tool.related_software && tool.related_software.length > 0) {
tool.related_software.forEach(relatedName => { tool.related_software.forEach(relatedName => {
const exists = yamlData.tools.some(t => t.name === relatedName); const exists = yamlData.meToCo.some(t => t.name === relatedName);
if (!exists) { if (!exists) {
validationResults.push(`⚠️ Tool ${index + 1}: Related software "${relatedName}" not found in tools`); validationResults.push(`⚠️ Tool ${index + 1}: Related software "${relatedName}" not found in meToCo`);
} }
}); });
} }
@ -2000,7 +2000,7 @@ TODO: Füge weitere nützliche Links und Ressourcen hinzu.
const a = document.createElement('a'); const a = document.createElement('a');
a.href = url; a.href = url;
a.download = 'tools.json'; a.download = 'meToCo.json';
document.body.appendChild(a); document.body.appendChild(a);
a.click(); a.click();
document.body.removeChild(a); document.body.removeChild(a);

View File

@ -1,5 +1,5 @@
{ {
"name": "dfir-tools-hub", "name": "forensicpathways",
"type": "module", "type": "module",
"version": "1.0.0", "version": "1.0.0",
"scripts": { "scripts": {

View File

@ -2,7 +2,7 @@
import { getToolsData } from '../utils/dataService.js'; import { getToolsData } from '../utils/dataService.js';
const data = await getToolsData(); const data = await getToolsData();
const tools = data.tools; const meToCo = data.meToCo;
const phases = data.phases; const phases = data.phases;
const domainAgnosticSoftware = data['domain-agnostic-software'] || []; const domainAgnosticSoftware = data['domain-agnostic-software'] || [];
--- ---
@ -176,7 +176,7 @@ const domainAgnosticSoftware = data['domain-agnostic-software'] || [];
<div class="micro-step" data-step="scenario">📋 Problemanalyse</div> <div class="micro-step" data-step="scenario">📋 Problemanalyse</div>
<div class="micro-step" data-step="approach">🎯 Ermittlungsansatz</div> <div class="micro-step" data-step="approach">🎯 Ermittlungsansatz</div>
<div class="micro-step" data-step="considerations">⚠️ Herausforderungen</div> <div class="micro-step" data-step="considerations">⚠️ Herausforderungen</div>
<div class="micro-step" data-step="tools">🔧 Methoden</div> <div class="micro-step" data-step="meToCo">🔧 Methoden</div>
<div class="micro-step" data-step="knowledge">📚 Evaluation</div> <div class="micro-step" data-step="knowledge">📚 Evaluation</div>
<div class="micro-step" data-step="final">✅ Audit-Trail</div> <div class="micro-step" data-step="final">✅ Audit-Trail</div>
</div> </div>
@ -210,7 +210,7 @@ const domainAgnosticSoftware = data['domain-agnostic-software'] || [];
</div> </div>
</section> </section>
<script define:vars={{ tools, phases, domainAgnosticSoftware }}> <script define:vars={{ meToCo, phases, domainAgnosticSoftware }}>
class AIQueryInterface { class AIQueryInterface {
constructor() { constructor() {
@ -626,7 +626,7 @@ class AIQueryInterface {
this.showElement(this.elements.microTaskProgress); this.showElement(this.elements.microTaskProgress);
this.currentMicroTaskStep = 0; this.currentMicroTaskStep = 0;
const steps = ['scenario', 'approach', 'considerations', 'tools', 'knowledge', 'final']; const steps = ['scenario', 'approach', 'considerations', 'meToCo', 'knowledge', 'final'];
const stepElements = this.elements.microTaskProgress.querySelectorAll('.micro-step'); const stepElements = this.elements.microTaskProgress.querySelectorAll('.micro-step');
stepElements.forEach(step => { stepElements.forEach(step => {
@ -681,7 +681,7 @@ class AIQueryInterface {
} }
displayWorkflowResults(recommendation, originalQuery) { displayWorkflowResults(recommendation, originalQuery) {
const toolsByPhase = {}; const meToCoByPhase = {};
const phaseOrder = phases.map(phase => phase.id); const phaseOrder = phases.map(phase => phase.id);
const phaseNames = phases.reduce((acc, phase) => { const phaseNames = phases.reduce((acc, phase) => {
acc[phase.id] = phase.name; acc[phase.id] = phase.name;
@ -689,14 +689,14 @@ class AIQueryInterface {
}, {}); }, {});
phaseOrder.forEach(phase => { phaseOrder.forEach(phase => {
toolsByPhase[phase] = []; meToCoByPhase[phase] = [];
}); });
recommendation.recommended_tools?.forEach(recTool => { recommendation.recommended_meToCo?.forEach(recTool => {
if (toolsByPhase[recTool.phase]) { if (meToCoByPhase[recTool.phase]) {
const fullTool = tools.find(t => t.name === recTool.name); const fullTool = meToCo.find(t => t.name === recTool.name);
if (fullTool) { if (fullTool) {
toolsByPhase[recTool.phase].push({ meToCoByPhase[recTool.phase].push({
...fullTool, ...fullTool,
recommendation: recTool recommendation: recTool
}); });
@ -709,7 +709,7 @@ class AIQueryInterface {
${this.renderHeader('Untersuchungsansatz', originalQuery)} ${this.renderHeader('Untersuchungsansatz', originalQuery)}
${this.renderContextualAnalysis(recommendation, 'workflow')} ${this.renderContextualAnalysis(recommendation, 'workflow')}
${this.renderBackgroundKnowledge(recommendation.background_knowledge)} ${this.renderBackgroundKnowledge(recommendation.background_knowledge)}
${this.renderWorkflowPhases(toolsByPhase, phaseOrder, phaseNames)} ${this.renderWorkflowPhases(meToCoByPhase, phaseOrder, phaseNames)}
${this.renderWorkflowSuggestion(recommendation.workflow_suggestion)} ${this.renderWorkflowSuggestion(recommendation.workflow_suggestion)}
${this.renderAuditTrail(recommendation.auditTrail)} ${this.renderAuditTrail(recommendation.auditTrail)}
</div> </div>
@ -724,7 +724,7 @@ class AIQueryInterface {
${this.renderHeader('Handlungsempfehlung', originalQuery)} ${this.renderHeader('Handlungsempfehlung', originalQuery)}
${this.renderContextualAnalysis(recommendation, 'tool')} ${this.renderContextualAnalysis(recommendation, 'tool')}
${this.renderBackgroundKnowledge(recommendation.background_knowledge)} ${this.renderBackgroundKnowledge(recommendation.background_knowledge)}
${this.renderToolRecommendations(recommendation.recommended_tools)} ${this.renderToolRecommendations(recommendation.recommended_meToCo)}
${this.renderAdditionalConsiderations(recommendation.additional_considerations)} ${this.renderAdditionalConsiderations(recommendation.additional_considerations)}
${this.renderAuditTrail(recommendation.auditTrail)} ${this.renderAuditTrail(recommendation.auditTrail)}
</div> </div>
@ -1076,9 +1076,9 @@ class AIQueryInterface {
`; `;
} }
renderWorkflowPhases(toolsByPhase, phaseOrder, phaseNames) { renderWorkflowPhases(meToCoByPhase, phaseOrder, phaseNames) {
return phaseOrder.map((phase, index) => { return phaseOrder.map((phase, index) => {
const phaseTools = toolsByPhase[phase]; const phaseTools = meToCoByPhase[phase];
if (phaseTools.length === 0) return ''; if (phaseTools.length === 0) return '';
return ` return `
@ -1087,7 +1087,7 @@ class AIQueryInterface {
<div class="phase-number">${index + 1}</div> <div class="phase-number">${index + 1}</div>
<div class="phase-info"> <div class="phase-info">
<h3 class="phase-title">${phaseNames[phase]}</h3> <h3 class="phase-title">${phaseNames[phase]}</h3>
<div class="phase-tools"> <div class="phase-meToCo">
${phaseTools.map(tool => this.renderWorkflowTool(tool)).join('')} ${phaseTools.map(tool => this.renderWorkflowTool(tool)).join('')}
</div> </div>
</div> </div>
@ -1139,7 +1139,7 @@ class AIQueryInterface {
return ` return `
<div class="tool-recommendations-grid" style="display: grid; gap: 1.5rem;"> <div class="tool-recommendations-grid" style="display: grid; gap: 1.5rem;">
${recommendedTools.map((toolRec, index) => { ${recommendedTools.map((toolRec, index) => {
const fullTool = tools.find(t => t.name === toolRec.name); const fullTool = meToCo.find(t => t.name === toolRec.name);
if (!fullTool) return ''; if (!fullTool) return '';
return this.renderDetailedTool(fullTool, toolRec, index + 1); return this.renderDetailedTool(fullTool, toolRec, index + 1);

View File

@ -111,7 +111,7 @@ const displayedScenarios = scenarios.slice(0, maxDisplayed);
clickedChip.classList.add('active'); clickedChip.classList.add('active');
} }
window.scrollToElementById('tools-grid'); window.scrollToElementById('meToCo-grid');
}; };
window.toggleAllScenarios = function() { window.toggleAllScenarios = function() {
@ -159,7 +159,7 @@ const displayedScenarios = scenarios.slice(0, maxDisplayed);
const gridToggle = document.querySelector('.view-toggle[data-view="grid"]'); const gridToggle = document.querySelector('.view-toggle[data-view="grid"]');
if (gridToggle) { if (gridToggle) {
gridToggle.click(); gridToggle.click();
setTimeout(() => window.scrollToElementById('tools-grid'), 200); setTimeout(() => window.scrollToElementById('meToCo-grid'), 200);
} }
} }
}); });

View File

@ -5,13 +5,13 @@ const data = await getToolsData();
const domains = data.domains; const domains = data.domains;
const phases = data.phases; const phases = data.phases;
const skillLevels = [...new Set(data.tools.map(tool => tool.skillLevel))].filter(Boolean).sort(); const skillLevels = [...new Set(data.meToCo.map(tool => tool.skillLevel))].filter(Boolean).sort();
const platforms = [...new Set(data.tools.flatMap(tool => tool.platforms || []))].filter(Boolean).sort(); const platforms = [...new Set(data.meToCo.flatMap(tool => tool.platforms || []))].filter(Boolean).sort();
const licenses = [...new Set(data.tools.map(tool => tool.license))].filter(Boolean).sort(); const licenses = [...new Set(data.meToCo.map(tool => tool.license))].filter(Boolean).sort();
const toolTypes = [...new Set(data.tools.map(tool => tool.type))].filter(Boolean).sort(); const toolTypes = [...new Set(data.meToCo.map(tool => tool.type))].filter(Boolean).sort();
const accessTypes = [...new Set(data.tools.map(tool => tool.accessType))].filter(Boolean).sort(); const accessTypes = [...new Set(data.meToCo.map(tool => tool.accessType))].filter(Boolean).sort();
const tagFrequency = data.tools.reduce((acc: Record<string, number>, tool: any) => { const tagFrequency = data.meToCo.reduce((acc: Record<string, number>, tool: any) => {
tool.tags.forEach((tag: string) => { tool.tags.forEach((tag: string) => {
acc[tag] = (acc[tag] || 0) + 1; acc[tag] = (acc[tag] || 0) + 1;
}); });
@ -282,8 +282,8 @@ const sortedTags = Object.entries(tagFrequency)
</div> </div>
</div> </div>
<script define:vars={{ toolsData: data.tools, tagFrequency, sortedTags }}> <script define:vars={{ meToCoData: data.meToCo, tagFrequency, sortedTags }}>
window.toolsData = toolsData; window.meToCoData = meToCoData;
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const elements = { const elements = {
@ -488,7 +488,7 @@ const sortedTags = Object.entries(tagFrequency)
} }
function updateResultsCounter(count) { function updateResultsCounter(count) {
const total = window.toolsData.length; const total = window.meToCoData.length;
elements.resultsCounter.textContent = count === total elements.resultsCounter.textContent = count === total
? `${total} Tools` ? `${total} Tools`
: `${count} von ${total} Tools`; : `${count} von ${total} Tools`;
@ -508,7 +508,7 @@ const sortedTags = Object.entries(tagFrequency)
const activePhase = selectedPhaseFromSelect || selectedPhase; const activePhase = selectedPhaseFromSelect || selectedPhase;
const filtered = window.toolsData.filter(tool => { const filtered = window.meToCoData.filter(tool => {
if (searchTerm && !( if (searchTerm && !(
tool.name.toLowerCase().includes(searchTerm) || tool.name.toLowerCase().includes(searchTerm) ||
tool.description.toLowerCase().includes(searchTerm) || tool.description.toLowerCase().includes(searchTerm) ||
@ -566,7 +566,7 @@ const sortedTags = Object.entries(tagFrequency)
updateResultsCounter(finalResults.length); updateResultsCounter(finalResults.length);
window.dispatchEvent(new CustomEvent('toolsFiltered', { detail: finalResults })); window.dispatchEvent(new CustomEvent('meToCoFiltered', { detail: finalResults }));
} }
function resetPrimaryFilters() { function resetPrimaryFilters() {
@ -652,8 +652,8 @@ const sortedTags = Object.entries(tagFrequency)
window.dispatchEvent(new CustomEvent('viewChanged', { detail: view })); window.dispatchEvent(new CustomEvent('viewChanged', { detail: view }));
if (view === 'hosted') { if (view === 'hosted') {
const hosted = window.toolsData.filter(tool => isToolHosted(tool)); const hosted = window.meToCoData.filter(tool => isToolHosted(tool));
window.dispatchEvent(new CustomEvent('toolsFiltered', { detail: hosted })); window.dispatchEvent(new CustomEvent('meToCoFiltered', { detail: hosted }));
} else { } else {
filterTools(); filterTools();
} }

View File

@ -6,12 +6,12 @@ const data = await getToolsData();
const domains = data.domains; const domains = data.domains;
const phases = data.phases; const phases = data.phases;
const tools = data.tools; const meToCo = data.meToCo;
const domainAgnosticSoftware = data['domain-agnostic-software'] || []; const domainAgnosticSoftware = data['domain-agnostic-software'] || [];
const domainAgnosticTools = domainAgnosticSoftware.map((section: any) => ({ const domainAgnosticTools = domainAgnosticSoftware.map((section: any) => ({
section, section,
tools: tools.filter((tool: any) => meToCo: meToCo.filter((tool: any) =>
tool['domain-agnostic-software'] && tool['domain-agnostic-software'].includes(section.id) tool['domain-agnostic-software'] && tool['domain-agnostic-software'].includes(section.id)
) )
})); }));
@ -20,7 +20,7 @@ const matrix: Record<string, Record<string, any[]>> = {};
domains.forEach((domain: any) => { domains.forEach((domain: any) => {
matrix[domain.id] = {}; matrix[domain.id] = {};
phases.forEach((phase: any) => { phases.forEach((phase: any) => {
matrix[domain.id][phase.id] = tools.filter((tool: any) => matrix[domain.id][phase.id] = meToCo.filter((tool: any) =>
tool.type !== 'concept' && tool.type !== 'concept' &&
tool.domains && tool.domains.includes(domain.id) && tool.domains && tool.domains.includes(domain.id) &&
tool.phases && tool.phases.includes(phase.id) tool.phases && tool.phases.includes(phase.id)
@ -42,7 +42,7 @@ domains.forEach((domain: any) => {
<h3 class="m-0 text-lg text-accent"> <h3 class="m-0 text-lg text-accent">
{sectionData.section.name} {sectionData.section.name}
<span id={`count-${sectionData.section.id}`} class="badge text-xs" style="background-color: var(--color-text-secondary); color: var(--color-bg); margin-left: 0.5rem;"> <span id={`count-${sectionData.section.id}`} class="badge text-xs" style="background-color: var(--color-text-secondary); color: var(--color-bg); margin-left: 0.5rem;">
{sectionData.tools.length} {sectionData.meToCo.length}
</span> </span>
</h3> </h3>
<div class="collaboration-expand-icon"> <div class="collaboration-expand-icon">
@ -52,8 +52,8 @@ domains.forEach((domain: any) => {
</div> </div>
</div> </div>
<div class="collaboration-content hidden"> <div class="collaboration-content hidden">
<div class="collaboration-tools-compact" id={`domain-agnostic-tools-${sectionData.section.id}`}> <div class="collaboration-meToCo-compact" id={`domain-agnostic-meToCo-${sectionData.section.id}`}>
{sectionData.tools.map((tool: any) => { {sectionData.meToCo.map((tool: any) => {
const hasValidProjectUrl = tool.projectUrl !== undefined && const hasValidProjectUrl = tool.projectUrl !== undefined &&
tool.projectUrl !== null && tool.projectUrl !== null &&
tool.projectUrl !== "" && tool.projectUrl !== "" &&
@ -192,7 +192,7 @@ domains.forEach((domain: any) => {
<div id="tool-links-secondary" class="flex flex-col gap-2"></div> <div id="tool-links-secondary" class="flex flex-col gap-2"></div>
</div> </div>
<script define:vars={{ toolsData: tools, domainAgnosticSoftware, domainAgnosticTools }}> <script define:vars={{ meToCoData: meToCo, domainAgnosticSoftware, domainAgnosticTools }}>
function getSelectedPhase() { function getSelectedPhase() {
const activePhaseChip = document.querySelector('.phase-chip.active'); const activePhaseChip = document.querySelector('.phase-chip.active');
return activePhaseChip ? activePhaseChip.getAttribute('data-phase') : ''; return activePhaseChip ? activePhaseChip.getAttribute('data-phase') : '';
@ -443,7 +443,7 @@ domains.forEach((domain: any) => {
window.toggleDomainAgnosticSection = toggleDomainAgnosticSection; window.toggleDomainAgnosticSection = toggleDomainAgnosticSection;
window.showToolDetails = function(toolName, modalType = 'primary') { window.showToolDetails = function(toolName, modalType = 'primary') {
const tool = toolsData.find(t => t.name === toolName); const tool = meToCoData.find(t => t.name === toolName);
if (!tool) { if (!tool) {
console.error('Tool not found:', toolName); console.error('Tool not found:', toolName);
return; return;
@ -523,7 +523,7 @@ domains.forEach((domain: any) => {
const relatedSoftware = tool.related_software || []; const relatedSoftware = tool.related_software || [];
if (relatedConcepts.length > 0 && modalType === 'primary') { if (relatedConcepts.length > 0 && modalType === 'primary') {
const conceptLinks = relatedConcepts.map(conceptName => { const conceptLinks = relatedConcepts.map(conceptName => {
const concept = toolsData.find(t => t.name === conceptName && t.type === 'concept'); const concept = meToCoData.find(t => t.name === conceptName && t.type === 'concept');
if (concept) { if (concept) {
return `<button class="tag cursor-pointer" style="background-color: var(--color-concept-bg); border: 1px solid var(--color-concept); color: var(--color-concept); transition: var(--transition-fast);" return `<button class="tag cursor-pointer" style="background-color: var(--color-concept-bg); border: 1px solid var(--color-concept); color: var(--color-concept); transition: var(--transition-fast);"
onclick="event.stopPropagation(); window.showToolDetails('${conceptName}', 'secondary')" onclick="event.stopPropagation(); window.showToolDetails('${conceptName}', 'secondary')"
@ -559,7 +559,7 @@ domains.forEach((domain: any) => {
if (relatedSoftware.length > 0 && modalType === 'primary') { if (relatedSoftware.length > 0 && modalType === 'primary') {
const softwareLinks = relatedSoftware.map(softwareName => { const softwareLinks = relatedSoftware.map(softwareName => {
const software = toolsData.find(t => t.name === softwareName && (t.type === 'software' || t.type === 'method')); const software = meToCoData.find(t => t.name === softwareName && (t.type === 'software' || t.type === 'method'));
if (software) { if (software) {
const isHosted = window.isToolHosted(software); const isHosted = window.isToolHosted(software);
const isSoftwareMethod = software.type === 'method'; const isSoftwareMethod = software.type === 'method';
@ -776,14 +776,14 @@ domains.forEach((domain: any) => {
} }
}); });
window.addEventListener('toolsFiltered', (event) => { window.addEventListener('meToCoFiltered', (event) => {
const currentView = document.querySelector('.view-toggle.active')?.getAttribute('data-view'); const currentView = document.querySelector('.view-toggle.active')?.getAttribute('data-view');
if (currentView === 'matrix') { if (currentView === 'matrix') {
setTimeout(updateMatrixHighlighting, 50); setTimeout(updateMatrixHighlighting, 50);
} }
}); });
window.addEventListener('toolsFiltered', (event) => { window.addEventListener('meToCoFiltered', (event) => {
const filtered = event.detail; const filtered = event.detail;
const currentView = document.querySelector('.view-toggle.active')?.getAttribute('data-view'); const currentView = document.querySelector('.view-toggle.active')?.getAttribute('data-view');
@ -795,7 +795,7 @@ domains.forEach((domain: any) => {
domainAgnosticSoftware.forEach(sectionData => { domainAgnosticSoftware.forEach(sectionData => {
const section = document.getElementById(`domain-agnostic-section-${sectionData.id}`); const section = document.getElementById(`domain-agnostic-section-${sectionData.id}`);
const container = document.getElementById(`domain-agnostic-tools-${sectionData.id}`); const container = document.getElementById(`domain-agnostic-meToCo-${sectionData.id}`);
if (!section || !container) return; if (!section || !container) return;
}); });

View File

@ -8,7 +8,7 @@ const knowledgebaseCollection = defineCollection({
last_updated: z.date(), last_updated: z.date(),
tool_name: z.string().optional(), tool_name: z.string().optional(),
related_tools: z.array(z.string()).default([]), related_meToCo: z.array(z.string()).default([]),
author: z.string().default('Anon'), author: z.string().default('Anon'),
difficulty: z.enum(['novice', 'beginner', 'intermediate', 'advanced', 'expert']).optional(), difficulty: z.enum(['novice', 'beginner', 'intermediate', 'advanced', 'expert']).optional(),

View File

@ -48,7 +48,7 @@ Open-Source Android Forensik bietet robuste Alternativen zu kommerziellen Lösun
- USB 3.0+ Anschlüsse - USB 3.0+ Anschlüsse
### Installation ### Installation
1. Download von [SANS SIFT Workstation](https://www.sans.org/tools/sift-workstation/) 1. Download von [SANS SIFT Workstation](https://www.sans.org/meToCo/sift-workstation/)
2. VMware/VirtualBox Import der OVA-Datei 2. VMware/VirtualBox Import der OVA-Datei
3. VM-Konfiguration: 8GB+ RAM, 4+ CPU-Kerne 3. VM-Konfiguration: 8GB+ RAM, 4+ CPU-Kerne
@ -78,10 +78,10 @@ wget https://github.com/sleuthkit/autopsy/releases/latest
### Android Debug Bridge (ADB) ### Android Debug Bridge (ADB)
```bash ```bash
# Ubuntu/Debian # Ubuntu/Debian
sudo apt install android-tools-adb android-tools-fastboot sudo apt install android-meToCo-adb android-meToCo-fastboot
# Windows - Download Android Platform Tools # Windows - Download Android Platform Tools
# https://developer.android.com/studio/releases/platform-tools # https://developer.android.com/studio/releases/platform-meToCo
``` ```
### ALEAPP Installation ### ALEAPP Installation

View File

@ -1,4 +1,4 @@
tools: meToCo:
- name: Autopsy - name: Autopsy
type: software type: software
description: >- description: >-
@ -1051,7 +1051,7 @@ tools:
- path-finding - path-finding
- bloom-visualization - bloom-visualization
- apoc-procedures - apoc-procedures
- import-tools - import-meToCo
related_concepts: related_concepts:
- SQL - SQL
- name: QGIS - name: QGIS
@ -1465,7 +1465,7 @@ tools:
- batch-processing - batch-processing
- cloud-artifacts - cloud-artifacts
- community-driven - community-driven
- free-tools - free-meToCo
- scenario:windows-registry - scenario:windows-registry
- scenario:persistence - scenario:persistence
related_concepts: related_concepts:
@ -1711,7 +1711,7 @@ tools:
domain-agnostic-software: null domain-agnostic-software: null
skillLevel: beginner skillLevel: beginner
accessType: download accessType: download
url: https://www.osforensics.com/tools/mount-disk-images.html url: https://www.osforensics.com/meToCo/mount-disk-images.html
projectUrl: '' projectUrl: ''
license: Proprietary license: Proprietary
knowledgebase: false knowledgebase: false
@ -2629,7 +2629,7 @@ tools:
- network-forensics - network-forensics
- mobile-forensics - mobile-forensics
skillLevel: intermediate skillLevel: intermediate
url: https://www.sans.org/tools/sift-workstation/ url: https://www.sans.org/meToCo/sift-workstation/
icon: 🧰 icon: 🧰
platforms: platforms:
- OS - OS
@ -3109,7 +3109,7 @@ tools:
- examination - examination
- analysis - analysis
skillLevel: advanced skillLevel: advanced
url: https://github.com/microsoft/ics-forensics-tools url: https://github.com/microsoft/ics-forensics-meToCo
icon: 🏭 icon: 🏭
platforms: platforms:
- Windows - Windows
@ -3349,8 +3349,8 @@ tools:
- name: Collabora Online - name: Collabora Online
type: software type: software
description: >- description: >-
Webbasierte OpenSourceOfficeSuite mit kompletter Web-basierte Open-Source-Office-Suite mit kompletter
DokumentenBearbeitung und LiveKollaboration. Dokumenten-Bearbeitung und Live-Kollaboration.
skillLevel: beginner skillLevel: beginner
url: https://www.collaboraonline.com url: https://www.collaboraonline.com
icon: 📝 icon: 📝
@ -3637,7 +3637,7 @@ tools:
platforms: platforms:
- Linux - Linux
accessType: download accessType: download
license: AGPLv3 license: AGPL v3
knowledgebase: false knowledgebase: false
- name: Elasticsearch - name: Elasticsearch
type: software type: software
@ -3744,7 +3744,7 @@ tools:
platforms: platforms:
- Linux - Linux
accessType: download accessType: download
license: GPLv3 license: GPL v3
knowledgebase: false knowledgebase: false
- name: FOCA - name: FOCA
type: software type: software
@ -3778,7 +3778,7 @@ tools:
platforms: platforms:
- Windows - Windows
accessType: download accessType: download
license: GPLv3 license: GPL v3
knowledgebase: false knowledgebase: false
- name: Firmware Analysis Toolkit - name: Firmware Analysis Toolkit
type: software type: software
@ -3817,8 +3817,8 @@ tools:
- name: GCHQ Tools - name: GCHQ Tools
type: software type: software
description: >- description: >-
Sammlung freier GCHQUtilities, allen voran CyberChef\_ das Sammlung freier GCHQ-Utilities, allen voran CyberChef\_ das
„CyberSchweizerTaschenmesser“ für Encoding, Crypto und Datenanalyse. „Cyber-Schweizer-Taschenmesser“ für Encoding, Crypto und Datenanalyse.
skillLevel: beginner skillLevel: beginner
url: https://gchq.github.io/CyberChef url: https://gchq.github.io/CyberChef
icon: 🥄 icon: 🥄
@ -3833,7 +3833,7 @@ tools:
platforms: platforms:
- Web - Web
accessType: download accessType: download
license: Apache2.0 license: Apache 2.0
knowledgebase: false knowledgebase: false
- name: Gephi - name: Gephi
type: software type: software
@ -4073,7 +4073,7 @@ tools:
- Linux - Linux
- Android - Android
accessType: download accessType: download
license: GPLv2 license: GPL v2
knowledgebase: false knowledgebase: false
- name: Loki - name: Loki
type: software type: software
@ -4107,7 +4107,7 @@ tools:
- Windows - Windows
- Linux - Linux
accessType: download accessType: download
license: GPLv3 license: GPL v3
knowledgebase: false knowledgebase: false
- name: Maltego - name: Maltego
type: software type: software
@ -4212,7 +4212,7 @@ tools:
platforms: platforms:
- Linux - Linux
accessType: download accessType: download
license: AGPLv3 license: AGPL v3
knowledgebase: false knowledgebase: false
- name: Oxygen Forensic Suite - name: Oxygen Forensic Suite
type: software type: software
@ -4278,7 +4278,7 @@ tools:
- Linux - Linux
- macOS - macOS
accessType: download accessType: download
license: LGPLv3 license: LGPL v3
knowledgebase: false knowledgebase: false
- name: Rekall - name: Rekall
type: software type: software
@ -4313,7 +4313,7 @@ tools:
- Linux - Linux
- macOS - macOS
accessType: download accessType: download
license: Apache2.0 license: Apache 2.0
knowledgebase: false knowledgebase: false
- name: Suricata - name: Suricata
type: software type: software
@ -4347,7 +4347,7 @@ tools:
- Linux - Linux
- Windows - Windows
accessType: download accessType: download
license: GPLv2 license: GPL v2
knowledgebase: false knowledgebase: false
- name: VirusTotal - name: VirusTotal
type: software type: software
@ -4443,7 +4443,7 @@ tools:
platforms: platforms:
- Windows - Windows
accessType: download accessType: download
license: GPLv2 license: GPL v2
knowledgebase: false knowledgebase: false
- name: Zeek - name: Zeek
type: software type: software
@ -4511,7 +4511,7 @@ tools:
- Windows - Windows
- macOS - macOS
accessType: download accessType: download
license: Apache2.0 license: Apache 2.0
knowledgebase: false knowledgebase: false
- name: tcpdump - name: tcpdump
type: software type: software
@ -4578,20 +4578,20 @@ tools:
platforms: platforms:
- Windows - Windows
accessType: download accessType: download
license: GPLv3 license: GPL v3
knowledgebase: false knowledgebase: false
- name: grep - name: grep
type: software type: software
description: >- description: >-
Klassisches Unix-Werkzeug zur Zeilenfilterung, entwickelt1973 von Klassisches Unix-Werkzeug zur Zeilenfilterung, entwickelt 1973 von
KenThompson zur schnellen Suche nach regulären Ausdrücken in Dateien oder Ken Thompson zur schnellen Suche nach regulären Ausdrücken in Dateien oder
Datenströmen. Der Name leitet sich vom edKommando „g/re/p“ ab und Datenströmen. Der Name leitet sich vom ed-Kommando „g/re/p“ ab und
spiegelt die Funktionsweise wider: globaler Ausdruck, Zeile drucken. spiegelt die Funktionsweise wider: globaler Ausdruck, Zeile drucken.
GNUgrep unterstützt drei RegexDialekte (BRE,ERE,PCRE), GNU grep unterstützt drei Regex-Dialekte (BRE, ERE, PCRE),
FarbHighlighting und ZeroCopyBlockPufferung für Höchstgeschwindigkeit Farb-Highlighting und Zero-Copy-Block-Pufferung für Höchstgeschwindigkeit
auch in riesigen Logs. Dank seiner PipeKompatibilität ist grep auch in riesigen Logs. Dank seiner Pipe-Kompatibilität ist grep
Grundbaustein unzähliger DFIREinzeiler zum Parsen von Artefakten, Grundbaustein unzähliger DFIR-Einzeiler zum Parsen von Artefakten,
NetzwerkFlows und MemoryDumps. Netzwerk-Flows und Memory-Dumps.
skillLevel: beginner skillLevel: beginner
url: https://www.gnu.org/software/grep/ url: https://www.gnu.org/software/grep/
icon: 🔍 icon: 🔍
@ -4618,12 +4618,12 @@ tools:
- name: md5sum / sha256sum - name: md5sum / sha256sum
type: software type: software
description: >- description: >-
Klassische KommandozeilenChecksummengeneratoren aus den GNUcoreutils, Klassische Kommandozeilen-Checksummengeneratoren aus den GNU coreutils,
die schnell kryptografische Prüfsummen (MD5 bzw. SHA256) berechnen und die schnell kryptografische Prüfsummen (MD5 bzw. SHA-256) berechnen und
verifizieren können. Ideal zur Integritätsprüfung von ForensikImages, verifizieren können. Ideal zur Integritätsprüfung von Forensik-Images,
LogArchiven und DownloadArtefakten; auch als StreamFilter einsetzbar Log-Archiven und Download-Artefakten; auch als Stream-Filter einsetzbar
(„cat image.dd | sha256sum“). Minimalistischer Funktionsumfang, aber auf („cat image.dd | sha256sum“). Minimalistischer Funktionsumfang, aber auf
nahezu jeder Unixähnlichen Plattform vorinstalliert und damit überall nahezu jeder Unix-ähnlichen Plattform vorinstalliert und damit überall
verfügbar. verfügbar.
skillLevel: beginner skillLevel: beginner
url: https://www.gnu.org/software/coreutils/ url: https://www.gnu.org/software/coreutils/
@ -4651,11 +4651,11 @@ tools:
- name: hashdeep - name: hashdeep
type: software type: software
description: >- description: >-
Multithreadfähiges AuditWerkzeug, das Dateien rekursiv einliest und Multithread-fähiges Audit-Werkzeug, das Dateien rekursiv einliest und
gleich mehrere HashAlgorithmen (MD5, SHA1, SHA256, Tiger u.a.) erzeugt. gleich mehrere Hash-Algorithmen (MD5, SHA-1, SHA-256, Tiger u.a.) erzeugt.
Unterstützt „baseline auditing“ zum automatischen Wieder­erkennen neuer Unterstützt „baseline auditing“ zum automatischen Wieder­erkennen neuer
oder veränderter Dateien und kann HashListen in NISTNSRL oder oder veränderter Dateien und kann Hash-Listen in NIST-NSRL- oder
CSVFormat ausgeben perfekt für große DatenträgerBatches. CSV-Format ausgeben perfekt für große Datenträger-Batches.
skillLevel: intermediate skillLevel: intermediate
url: https://github.com/jessek/hashdeep url: https://github.com/jessek/hashdeep
icon: 🏷️ icon: 🏷️
@ -4682,9 +4682,9 @@ tools:
description: >- description: >-
Tool zur Berechnung „fuzzy hashes“ (Context Triggered Piecewise Hashing, Tool zur Berechnung „fuzzy hashes“ (Context Triggered Piecewise Hashing,
CTPH) für Ähnlichkeits­analysen von Dateien. Kann binäre CTPH) für Ähnlichkeits­analysen von Dateien. Kann binäre
MalwareVarianten, Dokumentschablonen oder Logs selbst bei nur teilweisen Malware-Varianten, Dokumentschablonen oder Logs selbst bei nur teilweisen
Überschneidungen matchen. AusgabeHashes lassen sich in Datenbanken oder Überschneidungen matchen. Ausgabe-Hashes lassen sich in Datenbanken oder
YARARegeln integrieren. YARA-Regeln integrieren.
skillLevel: intermediate skillLevel: intermediate
url: https://ssdeep-project.github.io/ssdeep/ url: https://ssdeep-project.github.io/ssdeep/
icon: 🔍 icon: 🔍
@ -4707,12 +4707,12 @@ tools:
- name: hashcat - name: hashcat
type: software type: software
description: >- description: >-
Höchstperformanter PasswortRecoveryAccelerator, der CPUs, GPUs, FPGAs Höchstperformanter Passwort-Recovery-Accelerator, der CPUs, GPUs, FPGAs
und sogar ASICs parallel nutzen kann. Unterstützt über 300 HashFormate und sogar ASICs parallel nutzen kann. Unterstützt über 300 Hash-Formate
(u.a. bcrypt, NTLM, Kerberos, WPAPMKID) und besitzt flexible Angriffsmodi (u.a. bcrypt, NTLM, Kerberos, WPA-PMKID) und besitzt flexible Angriffsmodi
(Dictionary, Mask, Hybrid, RuleBased). Dank OpenCLBackend skaliert (Dictionary, Mask, Hybrid, Rule-Based). Dank OpenCL-Backend skaliert
hashcat von LaptopGPU bis zu verteilten Clustern unverzichtbar für hashcat von Laptop-GPU bis zu verteilten Clustern unverzichtbar für
CredentialAudits und IncidentResponse. Credential-Audits und Incident-Response.
skillLevel: advanced skillLevel: advanced
url: https://hashcat.net/hashcat/ url: https://hashcat.net/hashcat/
icon: icon:
@ -4737,10 +4737,10 @@ tools:
- name: Linkurious - name: Linkurious
type: software type: software
description: >- description: >-
Intuitive GraphVisualisierungs und Analyseplattform, die Intuitive Graph-Visualisierungs- und Analyseplattform, die
Graphdatenbanken wie Neo4j überlagert und Ermittler:innen dabei Graphdatenbanken wie Neo4j überlagert und Ermittler:innen dabei
unterstützt, versteckte Beziehungen in Betrugs, AML und unterstützt, versteckte Beziehungen in Betrugs-, AML- und
Sicherheitsfällen aufzudecken. Leistungsstarke Filter, Geo und Sicherheitsfällen aufzudecken. Leistungsstarke Filter, Geo- und
Zeitachsenansichten sowie Automatisierungsvorlagen erleichtern das Hunten Zeitachsenansichten sowie Automatisierungsvorlagen erleichtern das Hunten
komplexer Netzwerke und das Erstellen aussagekräftiger Beweisgrafiken. komplexer Netzwerke und das Erstellen aussagekräftiger Beweisgrafiken.
skillLevel: intermediate skillLevel: intermediate
@ -4767,7 +4767,7 @@ tools:
knowledgebase: false knowledgebase: false
- name: Android Studio - name: Android Studio
type: software type: software
description: "Offizielle IDE von Google für die AndroidEntwicklung, basierend auf JetBrains\_IntelliJ\_IDEA. Integriert ein flexibles GradleBuildsystem, JetpackComposeDesigner, GeräteEmulator, Profiler und DebuggingTools, um mobile Apps effizient zu erstellen, zu testen und zu analysieren auch für forensische RePackaging oder MalwareAnalysen von APKs." description: "Offizielle IDE von Google für die Android-Entwicklung, basierend auf JetBrains\_IntelliJ\_IDEA. Integriert ein flexibles Gradle-Buildsystem, Jetpack-Compose-Designer, Geräte-Emulator, Profiler und Debugging-Tools, um mobile Apps effizient zu erstellen, zu testen und zu analysieren auch für forensische Re-Packaging- oder Malware-Analysen von APKs."
skillLevel: intermediate skillLevel: intermediate
url: https://developer.android.com/studio url: https://developer.android.com/studio
icon: 📱 icon: 📱
@ -4793,13 +4793,13 @@ tools:
- name: ADB - name: ADB
type: software type: software
description: >- description: >-
Vielseitiges ClientServerKommandozeilenwerkzeug, mit dem Fachleute über Vielseitiges Client-Server-Kommandozeilenwerkzeug, mit dem Fachleute über
USB oder Netzwerk mit AndroidGeräten und Emulatoren kommunizieren: Pakete USB oder Netzwerk mit Android-Geräten und Emulatoren kommunizieren: Pakete
installieren, Dateien extrahieren, Logcats erfassen, Ports weiterleiten installieren, Dateien extrahieren, Logcats erfassen, Ports weiterleiten
und logische wie physische Datensicherungen erstellen. Unverzichtbar für und logische wie physische Datensicherungen erstellen. Unverzichtbar für
mobile Forensik, IncidentResponse und AppEntwicklung. mobile Forensik, Incident-Response und App-Entwicklung.
skillLevel: intermediate skillLevel: intermediate
url: https://developer.android.com/tools/adb url: https://developer.android.com/meToCo/adb
icon: 🔌 icon: 🔌
domains: domains:
- mobile-forensics - mobile-forensics
@ -4822,7 +4822,7 @@ tools:
knowledgebase: false knowledgebase: false
- name: dc3dd - name: dc3dd
type: software type: software
description: "dc3dd ist eine forensisch erweiterte Variante des klassischen UnixBefehls dd. Sie unterstützt das gleichzeitige Berechnen mehrerer HashWerte (MD5,SHA1,SHA256,SHA512) während der ImageErstellung, führt ein detailliertes Log mit Prüfsummen und Fehlerblöcken und zeigt einen Fortschrittsbalken an. Weitere Funktionen sind das Splitten großer Abbilder, das gezielte Überschreiben von Mustern zum sicheren Löschen\_und die Möglichkeit, Fehlersektoren separat auszugeben, was besonders bei defekten Medien hilfreich ist." description: "dc3dd ist eine forensisch erweiterte Variante des klassischen Unix-Befehls dd. Sie unterstützt das gleichzeitige Berechnen mehrerer Hash-Werte (MD5, SHA-1, SHA-256, SHA-512) während der Image-Erstellung, führt ein detailliertes Log mit Prüfsummen und Fehlerblöcken und zeigt einen Fortschrittsbalken an. Weitere Funktionen sind das Splitten großer Abbilder, das gezielte Überschreiben von Mustern zum sicheren Löschen\_und die Möglichkeit, Fehlersektoren separat auszugeben, was besonders bei defekten Medien hilfreich ist."
skillLevel: intermediate skillLevel: intermediate
url: https://sourceforge.net/projects/dc3dd/ url: https://sourceforge.net/projects/dc3dd/
icon: 💾 icon: 💾
@ -4848,15 +4848,15 @@ tools:
- name: ddrescue - name: ddrescue
type: software type: software
description: >- description: >-
GNUddrescue ist ein spezialisiertes DatenrettungsTool, das beschädigte GNU ddrescue ist ein spezialisiertes Datenrettungs-Tool, das beschädigte
oder fehlerhafte Blockgeräte sektorweise ausliest und zunächst alle gut oder fehlerhafte Blockgeräte sektorweise ausliest und zunächst alle gut
lesbaren Bereiche sichert, bevor es sich mehrfach an problematischen lesbaren Bereiche sichert, bevor es sich mehrfach an problematischen
Sektoren versucht. Sein MapFile protokolliert jeden Leseversuch, sodass Sektoren versucht. Sein Map-File protokolliert jeden Leseversuch, sodass
abgebrochene Wiederherstellungen jederzeit fortgesetzt oder optimiert abgebrochene Wiederherstellungen jederzeit fortgesetzt oder optimiert
werden können, ohne bereits gerettete Sektoren erneut zu belasten. Zudem werden können, ohne bereits gerettete Sektoren erneut zu belasten. Zudem
bietet ddrescue einen FillModus, um schwierige Bereiche gezielt mit bietet ddrescue einen Fill-Modus, um schwierige Bereiche gezielt mit
Platzhaltern zu überschreiben nützlich für die Vorbereitung Platzhaltern zu überschreiben nützlich für die Vorbereitung
nachträglicher DateisystemReparaturen. nachträglicher Dateisystem-Reparaturen.
skillLevel: intermediate skillLevel: intermediate
url: https://www.gnu.org/software/ddrescue/ url: https://www.gnu.org/software/ddrescue/
icon: 🛟 icon: 🛟
@ -4881,7 +4881,7 @@ tools:
knowledgebase: false knowledgebase: false
- name: REMnux - name: REMnux
type: software type: software
description: "REMnux ist eine auf Ubuntu basierende LinuxDistribution, die eine kuratierte Sammlung frei verfügbarer Tools für MalwareAnalyse, Reverse\_Engineering und Speicherforensik in einer sofort einsatzbereiten VM vereint. Sie erspart Analyst:innen das mühsame Zusammenstellen einzelner Werkzeuge, da Paketverwaltung, DesktopIntegration und LabSkripte bereits vorkonfiguriert sind. Zu den integrierten Highlights zählen unter anderem Ghidra, Radare2, Volatility, stegdetect sowie diverse Netzwerk und SandboxingUtilities, die regelmäßig in koordinierten Releases aktualisiert werden." description: "REMnux ist eine auf Ubuntu basierende Linux-Distribution, die eine kuratierte Sammlung frei verfügbarer Tools für Malware-Analyse, Reverse\_Engineering und Speicherforensik in einer sofort einsatzbereiten VM vereint. Sie erspart Analyst:innen das mühsame Zusammenstellen einzelner Werkzeuge, da Paketverwaltung, Desktop-Integration und Lab-Skripte bereits vorkonfiguriert sind. Zu den integrierten Highlights zählen unter anderem Ghidra, Radare2, Volatility, stegdetect sowie diverse Netzwerk- und Sandboxing-Utilities, die regelmäßig in koordinierten Releases aktualisiert werden."
skillLevel: intermediate skillLevel: intermediate
url: https://remnux.org/ url: https://remnux.org/
icon: 🐧 icon: 🐧
@ -4905,7 +4905,7 @@ tools:
knowledgebase: false knowledgebase: false
- name: Android Backup Extractor - name: Android Backup Extractor
type: software type: software
description: "Das bewährte KommandozeilenWerkzeug zum Entpacken und Packen von AndroidBackups (.ab) aus »adb backup«\_ inklusive Entschlüsselung passwort­geschützter Archive dank integrierter AESRoutinen. Ideal für die Extraktion forensisch relevanter AppDaten ohne RootZugriff und damit ein Musthave für MobileAnalysen. :contentReference[oaicite:0]{index=0}" description: "Das bewährte Kommandozeilen-Werkzeug zum Entpacken und Packen von Android-Backups (.ab) aus »adb backup«\_ inklusive Entschlüsselung passwort­geschützter Archive dank integrierter AES-Routinen. Ideal für die Extraktion forensisch relevanter App-Daten ohne Root-Zugriff und damit ein Must-have für Mobile-Analysen. :contentReference[oaicite:0]{index=0}"
skillLevel: intermediate skillLevel: intermediate
url: https://github.com/nelenkov/android-backup-extractor url: https://github.com/nelenkov/android-backup-extractor
icon: 📦 icon: 📦
@ -4932,7 +4932,7 @@ tools:
knowledgebase: false knowledgebase: false
- name: CAINE - name: CAINE
type: software type: software
description: "CAINE (Computer Aided INvestigative Environment) ist eine Ubuntubasierte LiveLinuxDistribution, die mehr als 150 ForensikWerkzeuge in einer schreibgeschützten Umgebung bündelt. Version 14.0 »Lightstream« (März\_2025) bringt Kernel\_6.8, UEFISupport und das UnBlockGUI zum gezielten Aufheben der WriteBlockFunktion für einzelne Devices. :contentReference[oaicite:2]{index=2}" description: "CAINE (Computer Aided INvestigative Environment) ist eine Ubuntu-basierte Live-Linux-Distribution, die mehr als 150 Forensik-Werkzeuge in einer schreibgeschützten Umgebung bündelt. Version 14.0 »Lightstream« (März\_2025) bringt Kernel\_6.8, UEFI-Support und das UnBlock-GUI zum gezielten Aufheben der Write-Block-Funktion für einzelne Devices. :contentReference[oaicite:2]{index=2}"
skillLevel: beginner skillLevel: beginner
url: https://www.caine-live.net/ url: https://www.caine-live.net/
icon: 💿 icon: 💿
@ -5002,7 +5002,7 @@ tools:
knowledgebase: false knowledgebase: false
- name: WiFi Pineapple - name: WiFi Pineapple
type: software type: software
description: "Die Hak5Hardware liefert mit der patentierten PineAPSuite einen vollwertigen RogueAccessPoint: automatisches Recon, Handshake und EnterpriseCredentialCapture, gezielte ClientFilterung sowie Cloud\_C²Fernsteuerung\_ alles per browser­basierter GUI auf dem Mark\_VII oder EnterpriseModell. :contentReference[oaicite:6]{index=6}" description: "Die Hak5-Hardware liefert mit der patentierten PineAP-Suite einen vollwertigen Rogue-Access-Point: automatisches Recon, Handshake- und Enterprise-Credential-Capture, gezielte Client-Filterung sowie Cloud\_C²-Fernsteuerung\_ alles per browser­basierter GUI auf dem Mark\_VII oder Enterprise-Modell. :contentReference[oaicite:6]{index=6}"
skillLevel: intermediate skillLevel: intermediate
url: https://shop.hak5.org/products/wifi-pineapple url: https://shop.hak5.org/products/wifi-pineapple
icon: 📡 icon: 📡

View File

@ -1,4 +1,4 @@
tools: meToCo:
- name: Autopsy - name: Autopsy
type: software type: software
description: >- description: >-
@ -113,7 +113,7 @@ phases:
domain-agnostic-software: domain-agnostic-software:
- id: collaboration-general - id: collaboration-general
name: Übergreifend & Kollaboration name: Übergreifend & Kollaboration
description: Cross-cutting tools and collaboration platforms description: Cross-cutting meToCo and collaboration platforms
- id: specific-os - id: specific-os
name: Betriebssysteme name: Betriebssysteme
description: Operating Systems which focus on forensics description: Operating Systems which focus on forensics

4
src/env.d.ts vendored
View File

@ -7,7 +7,7 @@ declare global {
toggleTheme: () => void; toggleTheme: () => void;
getStoredTheme: () => string; getStoredTheme: () => string;
}; };
toolsData: any[]; meToCoData: any[];
showToolDetails: (toolName: string, modalType?: string) => void; showToolDetails: (toolName: string, modalType?: string) => void;
hideToolDetails: (modalType?: string) => void; hideToolDetails: (modalType?: string) => void;
hideAllToolDetails: () => void; hideAllToolDetails: () => void;
@ -19,7 +19,7 @@ declare global {
clearAllFilters?: () => void; clearAllFilters?: () => void;
createToolSlug: (toolName: string) => string; createToolSlug: (toolName: string) => string;
findToolByIdentifier: (tools: any[], identifier: string) => any | undefined; findToolByIdentifier: (meToCo: any[], identifier: string) => any | undefined;
isToolHosted: (tool: any) => boolean; isToolHosted: (tool: any) => boolean;
checkClientAuth: (context?: string) => Promise<{authenticated: boolean; authRequired: boolean; expires?: string}>; checkClientAuth: (context?: string) => Promise<{authenticated: boolean; authRequired: boolean; expires?: string}>;

View File

@ -8,7 +8,7 @@ export interface Props {
description?: string; description?: string;
} }
const { title, description = 'ForensicPathways - A comprehensive directory of digital forensics and incident response tools' } = Astro.props; const { title, description = 'ForensicPathways - A comprehensive directory of digital forensics and incident response meToCo' } = Astro.props;
--- ---
<!DOCTYPE html> <!DOCTYPE html>
@ -34,10 +34,10 @@ const { title, description = 'ForensicPathways - A comprehensive directory of di
.replace(/^-|-$/g, ''); // Remove leading/trailing hyphens .replace(/^-|-$/g, ''); // Remove leading/trailing hyphens
} }
function findToolByIdentifier(tools, identifier) { function findToolByIdentifier(meToCo, identifier) {
if (!identifier || !Array.isArray(tools)) return undefined; if (!identifier || !Array.isArray(meToCo)) return undefined;
return tools.find(tool => return meToCo.find(tool =>
tool.name === identifier || tool.name === identifier ||
createToolSlug(tool.name) === identifier.toLowerCase() createToolSlug(tool.name) === identifier.toLowerCase()
); );
@ -76,14 +76,14 @@ const { title, description = 'ForensicPathways - A comprehensive directory of di
scrollToElement(element, options); scrollToElement(element, options);
} }
function prioritizeSearchResults(tools, searchTerm) { function prioritizeSearchResults(meToCo, searchTerm) {
if (!searchTerm || !searchTerm.trim()) { if (!searchTerm || !searchTerm.trim()) {
return tools; return meToCo;
} }
const lowerSearchTerm = searchTerm.toLowerCase().trim(); const lowerSearchTerm = searchTerm.toLowerCase().trim();
return tools.sort((a, b) => { return meToCo.sort((a, b) => {
const aTagsLower = (a.tags || []).map(tag => tag.toLowerCase()); const aTagsLower = (a.tags || []).map(tag => tag.toLowerCase());
const bTagsLower = (b.tags || []).map(tag => tag.toLowerCase()); const bTagsLower = (b.tags || []).map(tag => tag.toLowerCase());

View File

@ -84,10 +84,10 @@ async function validateToolData(tool: any, action: string): Promise<{ valid: boo
const errors: string[] = []; const errors: string[] = [];
try { try {
const existingData = { tools: [] }; const existingData = { meToCo: [] };
if (action === 'add') { if (action === 'add') {
const existingNames = new Set(existingData.tools.map((t: any) => t.name.toLowerCase())); const existingNames = new Set(existingData.meToCo.map((t: any) => t.name.toLowerCase()));
if (existingNames.has(tool.name.toLowerCase())) { if (existingNames.has(tool.name.toLowerCase())) {
errors.push('A tool with this name already exists'); errors.push('A tool with this name already exists');
} }
@ -102,10 +102,10 @@ async function validateToolData(tool: any, action: string): Promise<{ valid: boo
} }
} else if (tool.type === 'software') { } else if (tool.type === 'software') {
if (!tool.platforms || tool.platforms.length === 0) { if (!tool.platforms || tool.platforms.length === 0) {
errors.push('Software tools must specify at least one platform'); errors.push('Software meToCo must specify at least one platform');
} }
if (!tool.license) { if (!tool.license) {
errors.push('Software tools must specify a license'); errors.push('Software meToCo must specify a license');
} }
} }

View File

@ -14,7 +14,7 @@ if (authResult instanceof Response) {
const { authenticated, userEmail, userId } = authResult; const { authenticated, userEmail, userId } = authResult;
const data = await getToolsData(); const data = await getToolsData();
const sortedTools = data.tools.sort((a: any, b: any) => a.name.localeCompare(b.name)); const sortedTools = data.meToCo.sort((a: any, b: any) => a.name.localeCompare(b.name));
--- ---
<BaseLayout title="Contribute Knowledge Base Article"> <BaseLayout title="Contribute Knowledge Base Article">

View File

@ -17,7 +17,7 @@ const data = await getToolsData();
const domains = data.domains; const domains = data.domains;
const phases = data.phases; const phases = data.phases;
const domainAgnosticSoftware = data['domain-agnostic-software'] || []; const domainAgnosticSoftware = data['domain-agnostic-software'] || [];
const existingTools = data.tools; const existingTools = data.meToCo;
const editToolName = Astro.url.searchParams.get('edit'); const editToolName = Astro.url.searchParams.get('edit');
const editTool = editToolName ? existingTools.find(tool => tool.name === editToolName) : null; const editTool = editToolName ? existingTools.find(tool => tool.name === editToolName) : null;

View File

@ -8,7 +8,7 @@ import TargetedScenarios from '../components/TargetedScenarios.astro';
import { getToolsData } from '../utils/dataService.js'; import { getToolsData } from '../utils/dataService.js';
const data = await getToolsData(); const data = await getToolsData();
const tools = data.tools; const meToCo = data.meToCo;
const phases = data.phases; const phases = data.phases;
--- ---
@ -116,7 +116,7 @@ const phases = data.phases;
<div class="nist-workflow"> <div class="nist-workflow">
{phases.map((phase: any, index: number) => { {phases.map((phase: any, index: number) => {
const phaseTools = tools.filter((tool: any) => const phaseTools = meToCo.filter((tool: any) =>
tool.phases && tool.phases.includes(phase.id) tool.phases && tool.phases.includes(phase.id)
); );
@ -155,23 +155,23 @@ const phases = data.phases;
<AIQueryInterface /> <AIQueryInterface />
<section id="tools-grid" style="padding-bottom: 2rem;"> <section id="meToCo-grid" style="padding-bottom: 2rem;">
<div class="grid-auto-fit" id="tools-container"> <div class="grid-auto-fit" id="meToCo-container">
{tools.map((tool: any) => ( {meToCo.map((tool: any) => (
<ToolCard tool={tool} /> <ToolCard tool={tool} />
))} ))}
</div> </div>
<div id="no-results" style="display: none; text-align: center; padding: 4rem 0;"> <div id="no-results" style="display: none; text-align: center; padding: 4rem 0;">
<p class="text-muted" style="font-size: 1.125rem;">No tools found matching your criteria.</p> <p class="text-muted" style="font-size: 1.125rem;">No meToCo found matching your criteria.</p>
</div> </div>
</section> </section>
<ToolMatrix data={data} /> <ToolMatrix data={data} />
</BaseLayout> </BaseLayout>
<script define:vars={{ toolsData: data.tools, phases: data.phases }}> <script define:vars={{ meToCoData: data.meToCo, phases: data.phases }}>
window.toolsData = toolsData; window.meToCoData = meToCoData;
window.selectApproach = function(approach) { window.selectApproach = function(approach) {
console.log(`Selected approach: ${approach}`); console.log(`Selected approach: ${approach}`);
@ -221,19 +221,19 @@ const phases = data.phases;
gridToggle.click(); gridToggle.click();
} }
window.scrollToElementById('tools-grid'); window.scrollToElementById('meToCo-grid');
}; };
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const toolsContainer = document.getElementById('tools-container'); const meToCoContainer = document.getElementById('meToCo-container');
const toolsGrid = document.getElementById('tools-grid'); const meToCoGrid = document.getElementById('meToCo-grid');
const matrixContainer = document.getElementById('matrix-container'); const matrixContainer = document.getElementById('matrix-container');
const aiInterface = document.getElementById('ai-interface'); const aiInterface = document.getElementById('ai-interface');
const filtersSection = document.getElementById('filters-section'); const filtersSection = document.getElementById('filters-section');
const noResults = document.getElementById('no-results'); const noResults = document.getElementById('no-results');
const aiQueryBtn = document.getElementById('ai-query-btn'); const aiQueryBtn = document.getElementById('ai-query-btn');
if (!toolsContainer || !toolsGrid || !matrixContainer || !noResults || !aiInterface || !filtersSection) { if (!meToCoContainer || !meToCoGrid || !matrixContainer || !noResults || !aiInterface || !filtersSection) {
console.error('Required DOM elements not found'); console.error('Required DOM elements not found');
return; return;
} }
@ -250,7 +250,7 @@ const phases = data.phases;
} }
function switchToView(view) { function switchToView(view) {
toolsGrid.style.display = 'none'; meToCoGrid.style.display = 'none';
matrixContainer.style.display = 'none'; matrixContainer.style.display = 'none';
aiInterface.style.display = 'none'; aiInterface.style.display = 'none';
filtersSection.style.display = 'none'; filtersSection.style.display = 'none';
@ -279,7 +279,7 @@ const phases = data.phases;
showFilterControls(); showFilterControls();
break; break;
default: default:
toolsGrid.style.display = 'block'; meToCoGrid.style.display = 'block';
filtersSection.style.display = 'block'; filtersSection.style.display = 'block';
showFilterControls(); showFilterControls();
break; break;
@ -357,7 +357,7 @@ const phases = data.phases;
}, 2000); }, 2000);
} else { } else {
console.warn('Tool card not found in grid:', toolName); console.warn('Tool card not found in grid:', toolName);
window.scrollToElementById('tools-grid'); window.scrollToElementById('meToCo-grid');
} }
}, 300); }, 300);
}, 200); }, 200);
@ -412,7 +412,7 @@ const phases = data.phases;
return; return;
} }
const tool = window.findToolByIdentifier(window.toolsData, toolParam); const tool = window.findToolByIdentifier(window.meToCoData, toolParam);
if (!tool) { if (!tool) {
console.warn('Shared tool not found:', toolParam); console.warn('Shared tool not found:', toolParam);
return; return;
@ -442,7 +442,7 @@ const phases = data.phases;
}, 100); }, 100);
} }
window.addEventListener('toolsFiltered', (event) => { window.addEventListener('meToCoFiltered', (event) => {
const filtered = event.detail; const filtered = event.detail;
const currentView = document.querySelector('.view-toggle.active')?.getAttribute('data-view'); const currentView = document.querySelector('.view-toggle.active')?.getAttribute('data-view');

View File

@ -11,7 +11,7 @@ const allKnowledgebaseEntries = await getCollection('knowledgebase', (entry) =>
const knowledgebaseEntries = allKnowledgebaseEntries.map((entry) => { const knowledgebaseEntries = allKnowledgebaseEntries.map((entry) => {
const associatedTool = entry.data.tool_name const associatedTool = entry.data.tool_name
? data.tools.find((tool: any) => tool.name === entry.data.tool_name) ? data.meToCo.find((tool: any) => tool.name === entry.data.tool_name)
: null; : null;
return { return {
@ -25,7 +25,7 @@ const knowledgebaseEntries = allKnowledgebaseEntries.map((entry) => {
tags: entry.data.tags || [], tags: entry.data.tags || [],
tool_name: entry.data.tool_name, tool_name: entry.data.tool_name,
related_tools: entry.data.related_tools || [], related_meToCo: entry.data.related_meToCo || [],
associatedTool, associatedTool,
name: entry.data.title, name: entry.data.title,
@ -41,7 +41,7 @@ const knowledgebaseEntries = allKnowledgebaseEntries.map((entry) => {
knowledgebaseEntries.sort((a: any, b: any) => a.title.localeCompare(b.title)); knowledgebaseEntries.sort((a: any, b: any) => a.title.localeCompare(b.title));
--- ---
<BaseLayout title="Knowledgebase" description="Extended documentation and insights for DFIR tools"> <BaseLayout title="Knowledgebase" description="Extended documentation and insights for DFIR meToCo">
<section class="section-padding"> <section class="section-padding">
<div class="text-center mb-8 p-8 bg-secondary rounded-lg border"> <div class="text-center mb-8 p-8 bg-secondary rounded-lg border">
<h1 class="mb-4 text-2xl text-primary">Knowledgebase</h1> <h1 class="mb-4 text-2xl text-primary">Knowledgebase</h1>

View File

@ -25,12 +25,12 @@ const { Content } = await entry.render();
const data = await getToolsData(); const data = await getToolsData();
const primaryTool = entry.data.tool_name const primaryTool = entry.data.tool_name
? data.tools.find((t: any) => t.name === entry.data.tool_name) ? data.meToCo.find((t: any) => t.name === entry.data.tool_name)
: null; : null;
const relatedTools = entry.data.related_tools const relatedTools = entry.data.related_meToCo
? entry.data.related_tools.map((toolName: string) => ? entry.data.related_meToCo.map((toolName: string) =>
data.tools.find((t: any) => t.name === toolName) data.meToCo.find((t: any) => t.name === toolName)
).filter(Boolean) ).filter(Boolean)
: []; : [];

View File

@ -5,7 +5,7 @@ import { getToolsData } from '../utils/dataService.js';
const data = await getToolsData(); const data = await getToolsData();
const hostedServices = data.tools.filter((tool: any) => { const hostedServices = data.meToCo.filter((tool: any) => {
return tool.projectUrl !== undefined && return tool.projectUrl !== undefined &&
tool.projectUrl !== null && tool.projectUrl !== null &&
tool.projectUrl !== "" && tool.projectUrl !== "" &&

View File

@ -883,7 +883,7 @@ input[type="checkbox"] {
} }
/* Collaboration Tools - Consolidated */ /* Collaboration Tools - Consolidated */
.collaboration-tools-compact { .collaboration-meToCo-compact {
display: flex; display: flex;
gap: 1rem; gap: 1rem;
flex-wrap: wrap; flex-wrap: wrap;
@ -1107,7 +1107,7 @@ input[type="checkbox"] {
line-height: 1.4; line-height: 1.4;
} }
.phase-tools { .phase-meToCo {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1rem; gap: 1rem;
@ -2051,9 +2051,9 @@ footer {
.phase-button { width: 100%; } .phase-button { width: 100%; }
.phase-tools { grid-template-columns: 1fr; } .phase-meToCo { grid-template-columns: 1fr; }
.collaboration-tools-compact { .collaboration-meToCo-compact {
flex-direction: column; flex-direction: column;
} }
.collaboration-tool-compact { .collaboration-tool-compact {

View File

@ -2065,7 +2065,7 @@ input[type="checkbox"] {
line-height: 1.4; line-height: 1.4;
} }
.phase-tools { .phase-meToCo {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1rem; gap: 1rem;
@ -3123,7 +3123,7 @@ footer {
} }
/* Collaboration Tools */ /* Collaboration Tools */
.collaboration-tools-compact { .collaboration-meToCo-compact {
display: flex; display: flex;
gap: 1rem; gap: 1rem;
flex-wrap: wrap; flex-wrap: wrap;
@ -3538,11 +3538,11 @@ footer {
} }
@media (width <= 480px) { @media (width <= 480px) {
.phase-tools { .phase-meToCo {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
.collaboration-tools-compact { .collaboration-meToCo-compact {
flex-direction: column; flex-direction: column;
} }

View File

@ -127,8 +127,8 @@ class ImprovedMicroTaskAIPipeline {
console.log('[AI PIPELINE] Configuration loaded:', { console.log('[AI PIPELINE] Configuration loaded:', {
embeddingCandidates: this.embeddingCandidates, embeddingCandidates: this.embeddingCandidates,
embeddingSelection: `${this.embeddingSelectionLimit} tools, ${this.embeddingConceptsLimit} concepts`, embeddingSelection: `${this.embeddingSelectionLimit} meToCo, ${this.embeddingConceptsLimit} concepts`,
noEmbeddingsLimits: `${this.noEmbeddingsToolLimit || 'unlimited'} tools, ${this.noEmbeddingsConceptLimit || 'unlimited'} concepts`, noEmbeddingsLimits: `${this.noEmbeddingsToolLimit || 'unlimited'} meToCo, ${this.noEmbeddingsConceptLimit || 'unlimited'} concepts`,
auditEnabled: this.auditConfig.enabled auditEnabled: this.auditConfig.enabled
}); });
} }
@ -352,7 +352,7 @@ class ImprovedMicroTaskAIPipeline {
return true; return true;
} }
private async getIntelligentCandidates(userQuery: string, toolsData: any, mode: string) { private async getIntelligentCandidates(userQuery: string, meToCoData: any, mode: string) {
let candidateTools: any[] = []; let candidateTools: any[] = [];
let candidateConcepts: any[] = []; let candidateConcepts: any[] = [];
let selectionMethod = 'unknown'; let selectionMethod = 'unknown';
@ -378,12 +378,12 @@ class ImprovedMicroTaskAIPipeline {
console.log(`[AI PIPELINE] Embeddings found ${similarItems.length} similar items`); console.log(`[AI PIPELINE] Embeddings found ${similarItems.length} similar items`);
const toolsMap = new Map<string, any>(toolsData.tools.map((tool: any) => [tool.name, tool])); const meToCoMap = new Map<string, any>(meToCoData.meToCo.map((tool: any) => [tool.name, tool]));
const conceptsMap = new Map<string, any>(toolsData.concepts.map((concept: any) => [concept.name, concept])); const conceptsMap = new Map<string, any>(meToCoData.concepts.map((concept: any) => [concept.name, concept]));
const similarTools = similarItems const similarTools = similarItems
.filter((item): item is SimilarityResult => item.type === 'tool') .filter((item): item is SimilarityResult => item.type === 'tool')
.map(item => toolsMap.get(item.name)) .map(item => meToCoMap.get(item.name))
.filter((tool): tool is any => tool !== undefined); .filter((tool): tool is any => tool !== undefined);
const similarConcepts = similarItems const similarConcepts = similarItems
@ -391,9 +391,9 @@ class ImprovedMicroTaskAIPipeline {
.map(item => conceptsMap.get(item.name)) .map(item => conceptsMap.get(item.name))
.filter((concept): concept is any => concept !== undefined); .filter((concept): concept is any => concept !== undefined);
console.log(`[AI PIPELINE] Similarity-ordered results: ${similarTools.length} tools, ${similarConcepts.length} concepts`); console.log(`[AI PIPELINE] Similarity-ordered results: ${similarTools.length} meToCo, ${similarConcepts.length} concepts`);
const totalAvailableTools = toolsData.tools.length; const totalAvailableTools = meToCoData.meToCo.length;
const reductionRatio = similarTools.length / totalAvailableTools; const reductionRatio = similarTools.length / totalAvailableTools;
if (similarTools.length >= this.embeddingsMinTools && reductionRatio <= this.embeddingsMaxReductionRatio) { if (similarTools.length >= this.embeddingsMinTools && reductionRatio <= this.embeddingsMaxReductionRatio) {
@ -401,15 +401,15 @@ class ImprovedMicroTaskAIPipeline {
candidateConcepts = similarConcepts; candidateConcepts = similarConcepts;
selectionMethod = 'embeddings_candidates'; selectionMethod = 'embeddings_candidates';
console.log(`[AI PIPELINE] Using embeddings filtering: ${totalAvailableTools}${similarTools.length} tools (${(reductionRatio * 100).toFixed(1)}% reduction)`); console.log(`[AI PIPELINE] Using embeddings filtering: ${totalAvailableTools}${similarTools.length} meToCo (${(reductionRatio * 100).toFixed(1)}% reduction)`);
} else { } else {
if (similarTools.length < this.embeddingsMinTools) { if (similarTools.length < this.embeddingsMinTools) {
console.log(`[AI PIPELINE] Embeddings found too few tools (${similarTools.length} < ${this.embeddingsMinTools}), using full dataset`); console.log(`[AI PIPELINE] Embeddings found too few meToCo (${similarTools.length} < ${this.embeddingsMinTools}), using full dataset`);
} else { } else {
console.log(`[AI PIPELINE] Embeddings didn't filter enough (${(reductionRatio * 100).toFixed(1)}% > ${(this.embeddingsMaxReductionRatio * 100).toFixed(1)}%), using full dataset`); console.log(`[AI PIPELINE] Embeddings didn't filter enough (${(reductionRatio * 100).toFixed(1)}% > ${(this.embeddingsMaxReductionRatio * 100).toFixed(1)}%), using full dataset`);
} }
candidateTools = toolsData.tools; candidateTools = meToCoData.meToCo;
candidateConcepts = toolsData.concepts; candidateConcepts = meToCoData.concepts;
selectionMethod = 'full_dataset'; selectionMethod = 'full_dataset';
} }
@ -418,7 +418,7 @@ class ImprovedMicroTaskAIPipeline {
{ query: userQuery, threshold: this.similarityThreshold, candidates: this.embeddingCandidates }, { query: userQuery, threshold: this.similarityThreshold, candidates: this.embeddingCandidates },
{ {
candidatesFound: similarItems.length, candidatesFound: similarItems.length,
toolsInOrder: similarTools.slice(0, 3).map((t: any) => t.name), meToCoInOrder: similarTools.slice(0, 3).map((t: any) => t.name),
conceptsInOrder: similarConcepts.slice(0, 3).map((c: any) => c.name), conceptsInOrder: similarConcepts.slice(0, 3).map((c: any) => c.name),
reductionRatio: reductionRatio, reductionRatio: reductionRatio,
usingEmbeddings: selectionMethod === 'embeddings_candidates', usingEmbeddings: selectionMethod === 'embeddings_candidates',
@ -437,20 +437,20 @@ class ImprovedMicroTaskAIPipeline {
} }
} else { } else {
console.log(`[AI PIPELINE] Embeddings disabled or not ready, using full dataset`); console.log(`[AI PIPELINE] Embeddings disabled or not ready, using full dataset`);
candidateTools = toolsData.tools; candidateTools = meToCoData.meToCo;
candidateConcepts = toolsData.concepts; candidateConcepts = meToCoData.concepts;
selectionMethod = 'full_dataset'; selectionMethod = 'full_dataset';
} }
console.log(`[AI PIPELINE] AI will analyze ${candidateTools.length} candidate tools (method: ${selectionMethod})`); console.log(`[AI PIPELINE] AI will analyze ${candidateTools.length} candidate meToCo (method: ${selectionMethod})`);
const finalSelection = await this.aiSelectionWithFullData(userQuery, candidateTools, candidateConcepts, mode, selectionMethod); const finalSelection = await this.aiSelectionWithFullData(userQuery, candidateTools, candidateConcepts, mode, selectionMethod);
return { return {
tools: finalSelection.selectedTools, meToCo: finalSelection.selectedTools,
concepts: finalSelection.selectedConcepts, concepts: finalSelection.selectedConcepts,
domains: toolsData.domains, domains: meToCoData.domains,
phases: toolsData.phases, phases: meToCoData.phases,
'domain-agnostic-software': toolsData['domain-agnostic-software'] 'domain-agnostic-software': meToCoData['domain-agnostic-software']
}; };
} }
@ -463,7 +463,7 @@ class ImprovedMicroTaskAIPipeline {
) { ) {
const selectionStart = Date.now(); const selectionStart = Date.now();
const toolsWithFullData = candidateTools.map((tool: any) => ({ const meToCoWithFullData = candidateTools.map((tool: any) => ({
name: tool.name, name: tool.name,
type: tool.type, type: tool.type,
description: tool.description, description: tool.description,
@ -492,14 +492,14 @@ class ImprovedMicroTaskAIPipeline {
related_software: concept.related_software || [] related_software: concept.related_software || []
})); }));
let toolsToSend: any[]; let meToCoToSend: any[];
let conceptsToSend: any[]; let conceptsToSend: any[];
if (selectionMethod === 'embeddings_candidates') { if (selectionMethod === 'embeddings_candidates') {
toolsToSend = toolsWithFullData.slice(0, this.embeddingSelectionLimit); meToCoToSend = meToCoWithFullData.slice(0, this.embeddingSelectionLimit);
conceptsToSend = conceptsWithFullData.slice(0, this.embeddingConceptsLimit); conceptsToSend = conceptsWithFullData.slice(0, this.embeddingConceptsLimit);
console.log(`[AI PIPELINE] Embeddings enabled: sending top ${toolsToSend.length} similarity-ordered tools`); console.log(`[AI PIPELINE] Embeddings enabled: sending top ${meToCoToSend.length} similarity-ordered meToCo`);
} else { } else {
const maxTools = this.noEmbeddingsToolLimit > 0 ? const maxTools = this.noEmbeddingsToolLimit > 0 ?
Math.min(this.noEmbeddingsToolLimit, candidateTools.length) : Math.min(this.noEmbeddingsToolLimit, candidateTools.length) :
@ -509,23 +509,23 @@ class ImprovedMicroTaskAIPipeline {
Math.min(this.noEmbeddingsConceptLimit, candidateConcepts.length) : Math.min(this.noEmbeddingsConceptLimit, candidateConcepts.length) :
candidateConcepts.length; candidateConcepts.length;
toolsToSend = toolsWithFullData.slice(0, maxTools); meToCoToSend = meToCoWithFullData.slice(0, maxTools);
conceptsToSend = conceptsWithFullData.slice(0, maxConcepts); conceptsToSend = conceptsWithFullData.slice(0, maxConcepts);
console.log(`[AI PIPELINE] Embeddings disabled: sending ${toolsToSend.length}/${candidateTools.length} tools (limit: ${this.noEmbeddingsToolLimit || 'none'})`); console.log(`[AI PIPELINE] Embeddings disabled: sending ${meToCoToSend.length}/${candidateTools.length} meToCo (limit: ${this.noEmbeddingsToolLimit || 'none'})`);
} }
const basePrompt = getPrompt('toolSelection', mode, userQuery, selectionMethod, this.maxSelectedItems); const basePrompt = getPrompt('toolSelection', mode, userQuery, selectionMethod, this.maxSelectedItems);
const prompt = `${basePrompt} const prompt = `${basePrompt}
VERFÜGBARE TOOLS (mit vollständigen Daten): VERFÜGBARE TOOLS (mit vollständigen Daten):
${JSON.stringify(toolsToSend, null, 2)} ${JSON.stringify(meToCoToSend, null, 2)}
VERFÜGBARE KONZEPTE (mit vollständigen Daten): VERFÜGBARE KONZEPTE (mit vollständigen Daten):
${JSON.stringify(conceptsToSend, null, 2)}`; ${JSON.stringify(conceptsToSend, null, 2)}`;
const estimatedTokens = this.estimateTokens(prompt); const estimatedTokens = this.estimateTokens(prompt);
console.log(`[AI PIPELINE] Method: ${selectionMethod}, Tools: ${toolsToSend.length}, Estimated tokens: ~${estimatedTokens}`); console.log(`[AI PIPELINE] Method: ${selectionMethod}, Tools: ${meToCoToSend.length}, Estimated tokens: ~${estimatedTokens}`);
if (estimatedTokens > 35000) { if (estimatedTokens > 35000) {
console.warn(`[AI PIPELINE] WARNING: Prompt tokens (${estimatedTokens}) may exceed model limits`); console.warn(`[AI PIPELINE] WARNING: Prompt tokens (${estimatedTokens}) may exceed model limits`);
@ -545,7 +545,7 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
{ error: 'Invalid JSON structure', response: response.slice(0, 200) }, { error: 'Invalid JSON structure', response: response.slice(0, 200) },
10, 10,
selectionStart, selectionStart,
{ aiModel: this.config.model, selectionMethod, tokensSent: estimatedTokens, toolsSent: toolsToSend.length } { aiModel: this.config.model, selectionMethod, tokensSent: estimatedTokens, meToCoSent: meToCoToSend.length }
); );
} }
@ -554,11 +554,11 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
const totalSelected = result.selectedTools.length + result.selectedConcepts.length; const totalSelected = result.selectedTools.length + result.selectedConcepts.length;
if (totalSelected === 0) { if (totalSelected === 0) {
console.error('[AI PIPELINE] AI selection returned no tools'); console.error('[AI PIPELINE] AI selection returned no meToCo');
throw new Error('AI selection returned empty selection'); throw new Error('AI selection returned empty selection');
} }
console.log(`[AI PIPELINE] AI selected: ${result.selectedTools.length} tools, ${result.selectedConcepts.length} concepts from ${toolsToSend.length} candidates`); console.log(`[AI PIPELINE] AI selected: ${result.selectedTools.length} meToCo, ${result.selectedConcepts.length} concepts from ${meToCoToSend.length} candidates`);
const selectedTools = candidateTools.filter(tool => result.selectedTools.includes(tool.name)); const selectedTools = candidateTools.filter(tool => result.selectedTools.includes(tool.name));
const selectedConcepts = candidateConcepts.filter(concept => result.selectedConcepts.includes(concept.name)); const selectedConcepts = candidateConcepts.filter(concept => result.selectedConcepts.includes(concept.name));
@ -573,11 +573,11 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
selectedConceptCount: result.selectedConcepts.length, selectedConceptCount: result.selectedConcepts.length,
reasoning: result.reasoning?.slice(0, 200) + '...', reasoning: result.reasoning?.slice(0, 200) + '...',
finalToolNames: selectedTools.map(t => t.name), finalToolNames: selectedTools.map(t => t.name),
selectionEfficiency: `${toolsToSend.length}${result.selectedTools.length}` selectionEfficiency: `${meToCoToSend.length}${result.selectedTools.length}`
}, },
confidence, confidence,
selectionStart, selectionStart,
{ aiModel: this.config.model, selectionMethod, promptTokens: estimatedTokens, toolsSent: toolsToSend.length } { aiModel: this.config.model, selectionMethod, promptTokens: estimatedTokens, meToCoSent: meToCoToSend.length }
); );
} }
@ -710,7 +710,7 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
} }
private async selectToolsForPhase(context: AnalysisContext, phase: any): Promise<MicroTaskResult> { private async selectToolsForPhase(context: AnalysisContext, phase: any): Promise<MicroTaskResult> {
const phaseTools = context.filteredData.tools.filter((tool: any) => const phaseTools = context.filteredData.meToCo.filter((tool: any) =>
tool.phases && tool.phases.includes(phase.id) tool.phases && tool.phases.includes(phase.id)
); );
@ -901,8 +901,8 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
console.log(`[AI PIPELINE] Starting ${mode} query processing with context continuity and audit trail`); console.log(`[AI PIPELINE] Starting ${mode} query processing with context continuity and audit trail`);
try { try {
const toolsData = await getCompressedToolsDataForAI(); const meToCoData = await getCompressedToolsDataForAI();
const filteredData = await this.getIntelligentCandidates(userQuery, toolsData, mode); const filteredData = await this.getIntelligentCandidates(userQuery, meToCoData, mode);
const context: AnalysisContext = { const context: AnalysisContext = {
userQuery, userQuery,
@ -917,11 +917,11 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
this.mergeTemporaryAuditEntries(context); this.mergeTemporaryAuditEntries(context);
console.log(`[AI PIPELINE] Starting micro-tasks with ${filteredData.tools.length} tools visible`); console.log(`[AI PIPELINE] Starting micro-tasks with ${filteredData.meToCo.length} meToCo visible`);
this.addAuditEntry(context, 'initialization', 'pipeline-start', this.addAuditEntry(context, 'initialization', 'pipeline-start',
{ userQuery, mode, toolsDataLoaded: !!toolsData }, { userQuery, mode, meToCoDataLoaded: !!meToCoData },
{ candidateTools: filteredData.tools.length, candidateConcepts: filteredData.concepts.length }, { candidateTools: filteredData.meToCo.length, candidateConcepts: filteredData.concepts.length },
90, 90,
startTime, startTime,
{ auditEnabled: this.auditConfig.enabled } { auditEnabled: this.auditConfig.enabled }
@ -946,14 +946,14 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
// Task 4: Tool Selection/Evaluation (mode-dependent) // Task 4: Tool Selection/Evaluation (mode-dependent)
if (mode === 'workflow') { if (mode === 'workflow') {
const phases = toolsData.phases || []; const phases = meToCoData.phases || [];
for (const phase of phases) { for (const phase of phases) {
const toolSelectionResult = await this.selectToolsForPhase(context, phase); const toolSelectionResult = await this.selectToolsForPhase(context, phase);
if (toolSelectionResult.success) completedTasks++; else failedTasks++; if (toolSelectionResult.success) completedTasks++; else failedTasks++;
await this.delay(this.microTaskDelay); await this.delay(this.microTaskDelay);
} }
} else { } else {
const topTools = filteredData.tools.slice(0, 3); const topTools = filteredData.meToCo.slice(0, 3);
for (let i = 0; i < topTools.length; i++) { for (let i = 0; i < topTools.length; i++) {
const evaluationResult = await this.evaluateSpecificTool(context, topTools[i], i + 1); const evaluationResult = await this.evaluateSpecificTool(context, topTools[i], i + 1);
if (evaluationResult.success) completedTasks++; else failedTasks++; if (evaluationResult.success) completedTasks++; else failedTasks++;
@ -980,7 +980,7 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
const processingStats = { const processingStats = {
embeddingsUsed: embeddingsService.isEnabled(), embeddingsUsed: embeddingsService.isEnabled(),
candidatesFromEmbeddings: filteredData.tools.length, candidatesFromEmbeddings: filteredData.meToCo.length,
finalSelectedItems: (context.selectedTools?.length || 0) + finalSelectedItems: (context.selectedTools?.length || 0) +
(context.backgroundKnowledge?.length || 0), (context.backgroundKnowledge?.length || 0),
processingTimeMs: Date.now() - startTime, processingTimeMs: Date.now() - startTime,
@ -990,7 +990,7 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
}; };
console.log(`[AI PIPELINE] Completed: ${completedTasks} tasks, Failed: ${failedTasks} tasks`); console.log(`[AI PIPELINE] Completed: ${completedTasks} tasks, Failed: ${failedTasks} tasks`);
console.log(`[AI PIPELINE] Unique tools selected: ${context.seenToolNames.size}`); console.log(`[AI PIPELINE] Unique meToCo selected: ${context.seenToolNames.size}`);
console.log(`[AI PIPELINE] Audit trail entries: ${context.auditTrail.length}`); console.log(`[AI PIPELINE] Audit trail entries: ${context.auditTrail.length}`);
return { return {
@ -1027,7 +1027,7 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
if (isWorkflow) { if (isWorkflow) {
return { return {
...base, ...base,
recommended_tools: context.selectedTools?.map(st => ({ recommended_meToCo: context.selectedTools?.map(st => ({
name: st.tool.name, name: st.tool.name,
phase: st.phase, phase: st.phase,
priority: st.priority, priority: st.priority,
@ -1038,7 +1038,7 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
} else { } else {
return { return {
...base, ...base,
recommended_tools: context.selectedTools?.map(st => ({ recommended_meToCo: context.selectedTools?.map(st => ({
name: st.tool.name, name: st.tool.name,
rank: st.tool.evaluation?.rank || 1, rank: st.tool.evaluation?.rank || 1,
suitability_score: st.priority, suitability_score: st.priority,

View File

@ -26,7 +26,7 @@ const ToolSchema = z.object({
}); });
const ToolsDataSchema = z.object({ const ToolsDataSchema = z.object({
tools: z.array(ToolSchema), meToCo: z.array(ToolSchema),
domains: z.array(z.object({ domains: z.array(z.object({
id: z.string(), id: z.string(),
name: z.string(), name: z.string(),
@ -36,7 +36,7 @@ const ToolsDataSchema = z.object({
id: z.string(), id: z.string(),
name: z.string(), name: z.string(),
description: z.string().optional(), description: z.string().optional(),
typical_tools: z.array(z.string()).optional().default([]), typical_meToCo: z.array(z.string()).optional().default([]),
key_activities: z.array(z.string()).optional().default([]) key_activities: z.array(z.string()).optional().default([])
})), })),
'domain-agnostic-software': z.array(z.object({ 'domain-agnostic-software': z.array(z.object({
@ -63,7 +63,7 @@ const ToolsDataSchema = z.object({
}); });
interface ToolsData { interface ToolsData {
tools: any[]; meToCo: any[];
domains: any[]; domains: any[];
phases: any[]; phases: any[];
'domain-agnostic-software': any[]; 'domain-agnostic-software': any[];
@ -72,7 +72,7 @@ interface ToolsData {
} }
interface EnhancedCompressedToolsData { interface EnhancedCompressedToolsData {
tools: any[]; meToCo: any[];
concepts: any[]; concepts: any[];
domains: any[]; domains: any[];
phases: any[]; phases: any[];
@ -134,7 +134,7 @@ async function loadRawData(): Promise<ToolsData> {
cachedData.skill_levels = { cachedData.skill_levels = {
novice: "Minimal technical background required, guided interfaces", novice: "Minimal technical background required, guided interfaces",
beginner: "Basic IT knowledge, some command-line familiarity helpful", beginner: "Basic IT knowledge, some command-line familiarity helpful",
intermediate: "Solid technical foundation, comfortable with various tools", intermediate: "Solid technical foundation, comfortable with various meToCo",
advanced: "Extensive experience, deep technical understanding required", advanced: "Extensive experience, deep technical understanding required",
expert: "Specialist knowledge, cutting-edge techniques and complex scenarios" expert: "Specialist knowledge, cutting-edge techniques and complex scenarios"
}; };
@ -159,11 +159,11 @@ export async function getToolsData(): Promise<ToolsData> {
const seed = getDailySeed(); const seed = getDailySeed();
const randomFn = seededRandom(seed); const randomFn = seededRandom(seed);
const randomizedTools = shuffleArray(rawData.tools, randomFn); const randomizedTools = shuffleArray(rawData.meToCo, randomFn);
cachedRandomizedData = { cachedRandomizedData = {
...rawData, ...rawData,
tools: randomizedTools meToCo: randomizedTools
}; };
lastRandomizationDate = today; lastRandomizationDate = today;
@ -177,7 +177,7 @@ export async function getCompressedToolsDataForAI(): Promise<EnhancedCompressedT
if (!cachedCompressedData) { if (!cachedCompressedData) {
const data = await getToolsData(); const data = await getToolsData();
const compressedTools = data.tools const compressedTools = data.meToCo
.filter(tool => tool.type !== 'concept') .filter(tool => tool.type !== 'concept')
.map(tool => { .map(tool => {
const { projectUrl, statusUrl, ...compressedTool } = tool; const { projectUrl, statusUrl, ...compressedTool } = tool;
@ -196,7 +196,7 @@ export async function getCompressedToolsDataForAI(): Promise<EnhancedCompressedT
}; };
}); });
const concepts = data.tools const concepts = data.meToCo
.filter(tool => tool.type === 'concept') .filter(tool => tool.type === 'concept')
.map(concept => { .map(concept => {
const { projectUrl, statusUrl, platforms, accessType, license, ...compressedConcept } = concept; const { projectUrl, statusUrl, platforms, accessType, license, ...compressedConcept } = concept;
@ -210,7 +210,7 @@ export async function getCompressedToolsDataForAI(): Promise<EnhancedCompressedT
}); });
cachedCompressedData = { cachedCompressedData = {
tools: compressedTools, meToCo: compressedTools,
concepts: concepts, concepts: concepts,
domains: data.domains, domains: data.domains,
phases: data.phases, phases: data.phases,

View File

@ -73,8 +73,8 @@ class EmbeddingsService {
// Create data directory if it doesn't exist // Create data directory if it doesn't exist
await fs.mkdir(path.dirname(this.embeddingsPath), { recursive: true }); await fs.mkdir(path.dirname(this.embeddingsPath), { recursive: true });
const toolsData = await getCompressedToolsDataForAI(); const meToCoData = await getCompressedToolsDataForAI();
const currentDataHash = this.hashData(toolsData); const currentDataHash = this.hashData(meToCoData);
// Try to load existing embeddings // Try to load existing embeddings
const existingEmbeddings = await this.loadEmbeddings(); const existingEmbeddings = await this.loadEmbeddings();
@ -84,7 +84,7 @@ class EmbeddingsService {
this.embeddings = existingEmbeddings.embeddings; this.embeddings = existingEmbeddings.embeddings;
} else { } else {
console.log('[EMBEDDINGS] Generating new embeddings...'); console.log('[EMBEDDINGS] Generating new embeddings...');
await this.generateEmbeddings(toolsData, currentDataHash); await this.generateEmbeddings(meToCoData, currentDataHash);
} }
this.isInitialized = true; this.isInitialized = true;
@ -197,10 +197,10 @@ class EmbeddingsService {
throw new Error('Unknown embeddings API response format'); throw new Error('Unknown embeddings API response format');
} }
private async generateEmbeddings(toolsData: any, version: string): Promise<void> { private async generateEmbeddings(meToCoData: any, version: string): Promise<void> {
const allItems = [ const allItems = [
...toolsData.tools.map((tool: any) => ({ ...tool, type: 'tool' })), ...meToCoData.meToCo.map((tool: any) => ({ ...tool, type: 'tool' })),
...toolsData.concepts.map((concept: any) => ({ ...concept, type: 'concept' })) ...meToCoData.concepts.map((concept: any) => ({ ...concept, type: 'concept' }))
]; ];
const contents = allItems.map(item => this.createContentString(item)); const contents = allItems.map(item => this.createContentString(item));

View File

@ -288,7 +288,7 @@ ${data.metadata.contact}
### For Maintainers ### For Maintainers
1. Copy the YAML above 1. Copy the YAML above
2. Add to \`src/data/tools.yaml\` in the tools array 2. Add to \`src/data/tools.yaml\` in the meToCo array
3. Maintain alphabetical order 3. Maintain alphabetical order
4. Close this issue when done 4. Close this issue when done

View File

@ -26,10 +26,10 @@ export function createToolSlug(toolName: string): string {
.replace(/^-|-$/g, ''); // Remove leading/trailing hyphens .replace(/^-|-$/g, ''); // Remove leading/trailing hyphens
} }
export function findToolByIdentifier(tools: Tool[], identifier: string): Tool | undefined { export function findToolByIdentifier(meToCo: Tool[], identifier: string): Tool | undefined {
if (!identifier || !Array.isArray(tools)) return undefined; if (!identifier || !Array.isArray(meToCo)) return undefined;
return tools.find(tool => return meToCo.find(tool =>
tool.name === identifier || tool.name === identifier ||
createToolSlug(tool.name) === identifier.toLowerCase() createToolSlug(tool.name) === identifier.toLowerCase()
); );