715 Zeilen
22 KiB
JavaScript
715 Zeilen
22 KiB
JavaScript
/**
|
|
* TASKMATE - Coding Routes
|
|
* ========================
|
|
* Verwaltung von Server-Anwendungen mit Claude/Codex Integration
|
|
*/
|
|
|
|
const express = require('express');
|
|
const router = express.Router();
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const { getDb } = require('../database');
|
|
const logger = require('../utils/logger');
|
|
const gitService = require('../services/gitService');
|
|
|
|
/**
|
|
* Prüft ob ein Pfad ein Server-Pfad (Linux) ist
|
|
*/
|
|
function isServerPath(localPath) {
|
|
return localPath && localPath.startsWith('/');
|
|
}
|
|
|
|
/**
|
|
* Schreibt CLAUDE.md in ein Verzeichnis
|
|
*/
|
|
function writeCLAUDEmd(directoryPath, content) {
|
|
if (!content || !directoryPath) return false;
|
|
|
|
try {
|
|
const claudePath = path.join(directoryPath, 'CLAUDE.md');
|
|
fs.writeFileSync(claudePath, content, 'utf8');
|
|
logger.info(`CLAUDE.md geschrieben: ${claudePath}`);
|
|
return true;
|
|
} catch (e) {
|
|
logger.error('CLAUDE.md schreiben fehlgeschlagen:', e);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Liest CLAUDE.md aus einem Verzeichnis
|
|
*/
|
|
function readCLAUDEmd(directoryPath) {
|
|
if (!directoryPath) {
|
|
logger.info('readCLAUDEmd: No directoryPath provided');
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
const claudePath = path.join(directoryPath, 'CLAUDE.md');
|
|
logger.info(`readCLAUDEmd: Checking path ${claudePath}`);
|
|
|
|
if (fs.existsSync(claudePath)) {
|
|
const content = fs.readFileSync(claudePath, 'utf8');
|
|
logger.info(`readCLAUDEmd: Successfully read ${content.length} characters from ${claudePath}`);
|
|
return content;
|
|
} else {
|
|
logger.info(`readCLAUDEmd: File does not exist: ${claudePath}`);
|
|
}
|
|
} catch (e) {
|
|
logger.error('CLAUDE.md lesen fehlgeschlagen:', e);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* GET /api/coding/directories
|
|
* Alle Coding-Verzeichnisse abrufen
|
|
*/
|
|
router.get('/directories', (req, res) => {
|
|
try {
|
|
const db = getDb();
|
|
const directories = db.prepare(`
|
|
SELECT cd.*, u.display_name as creator_name
|
|
FROM coding_directories cd
|
|
LEFT JOIN users u ON cd.created_by = u.id
|
|
ORDER BY cd.position ASC, cd.name ASC
|
|
`).all();
|
|
|
|
res.json(directories.map(dir => {
|
|
// CLAUDE.md aus dem Dateisystem lesen falls vorhanden
|
|
let claudeMdFromDisk = null;
|
|
if (isServerPath(dir.local_path)) {
|
|
claudeMdFromDisk = readCLAUDEmd(dir.local_path);
|
|
// Fallback: Wenn Pfad /home/claude-dev/TaskMate ist, versuche /app/taskmate-source
|
|
if (!claudeMdFromDisk && dir.local_path === '/home/claude-dev/TaskMate') {
|
|
logger.info('Trying fallback path for TaskMate: /app/taskmate-source');
|
|
claudeMdFromDisk = readCLAUDEmd('/app/taskmate-source');
|
|
}
|
|
}
|
|
|
|
return {
|
|
id: dir.id,
|
|
name: dir.name,
|
|
localPath: dir.local_path,
|
|
description: dir.description,
|
|
color: dir.color,
|
|
claudeInstructions: dir.claude_instructions,
|
|
claudeMdFromDisk: claudeMdFromDisk,
|
|
hasCLAUDEmd: !!claudeMdFromDisk,
|
|
giteaRepoUrl: dir.gitea_repo_url,
|
|
giteaRepoOwner: dir.gitea_repo_owner,
|
|
giteaRepoName: dir.gitea_repo_name,
|
|
defaultBranch: dir.default_branch,
|
|
lastSync: dir.last_sync,
|
|
position: dir.position,
|
|
createdAt: dir.created_at,
|
|
createdBy: dir.created_by,
|
|
creatorName: dir.creator_name
|
|
};
|
|
}));
|
|
} catch (error) {
|
|
logger.error('Fehler beim Abrufen der Coding-Verzeichnisse:', error);
|
|
res.status(500).json({ error: 'Interner Serverfehler' });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* POST /api/coding/directories
|
|
* Neues Coding-Verzeichnis erstellen
|
|
*/
|
|
router.post('/directories', (req, res) => {
|
|
try {
|
|
const { name, localPath, description, color, claudeInstructions, giteaRepoUrl, giteaRepoOwner, giteaRepoName, defaultBranch } = req.body;
|
|
|
|
if (!name || !localPath) {
|
|
return res.status(400).json({ error: 'Name und Server-Pfad sind erforderlich' });
|
|
}
|
|
|
|
const db = getDb();
|
|
|
|
// Prüfe ob Pfad bereits existiert
|
|
const existing = db.prepare('SELECT id FROM coding_directories WHERE local_path = ?').get(localPath);
|
|
if (existing) {
|
|
return res.status(400).json({ error: 'Diese Anwendung ist bereits registriert' });
|
|
}
|
|
|
|
// Höchste Position ermitteln
|
|
const maxPos = db.prepare('SELECT COALESCE(MAX(position), -1) as max FROM coding_directories').get().max;
|
|
|
|
const result = db.prepare(`
|
|
INSERT INTO coding_directories (name, local_path, description, color, claude_instructions, gitea_repo_url, gitea_repo_owner, gitea_repo_name, default_branch, position, created_by)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
`).run(
|
|
name,
|
|
localPath,
|
|
description || null,
|
|
color || '#4F46E5',
|
|
null, // claudeInstructions wird nicht mehr gespeichert
|
|
giteaRepoUrl || null,
|
|
giteaRepoOwner || null,
|
|
giteaRepoName || null,
|
|
defaultBranch || 'main',
|
|
maxPos + 1,
|
|
req.user.id
|
|
);
|
|
|
|
const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(result.lastInsertRowid);
|
|
|
|
// Ordner erstellen falls nicht vorhanden
|
|
let directoryCreated = false;
|
|
if (isServerPath(localPath) && !fs.existsSync(localPath)) {
|
|
try {
|
|
fs.mkdirSync(localPath, { recursive: true });
|
|
directoryCreated = true;
|
|
logger.info(`Anwendungsordner erstellt: ${localPath}`);
|
|
} catch (e) {
|
|
logger.error('Ordner erstellen fehlgeschlagen:', e);
|
|
}
|
|
}
|
|
|
|
// CLAUDE.md wird nicht mehr geschrieben - nur readonly
|
|
let claudeMdWritten = false;
|
|
|
|
logger.info(`Coding-Anwendung erstellt: ${name} (${localPath})`);
|
|
|
|
// CLAUDE.md aus dem Dateisystem lesen für aktuelle Anzeige
|
|
const claudeMdFromDisk = isServerPath(directory.local_path) ? readCLAUDEmd(directory.local_path) : null;
|
|
|
|
res.status(201).json({
|
|
id: directory.id,
|
|
name: directory.name,
|
|
localPath: directory.local_path,
|
|
description: directory.description,
|
|
color: directory.color,
|
|
claudeInstructions: directory.claude_instructions,
|
|
claudeMdFromDisk: claudeMdFromDisk,
|
|
hasCLAUDEmd: !!claudeMdFromDisk,
|
|
giteaRepoUrl: directory.gitea_repo_url,
|
|
giteaRepoOwner: directory.gitea_repo_owner,
|
|
giteaRepoName: directory.gitea_repo_name,
|
|
defaultBranch: directory.default_branch,
|
|
position: directory.position,
|
|
createdAt: directory.created_at,
|
|
directoryCreated,
|
|
claudeMdWritten
|
|
});
|
|
} catch (error) {
|
|
logger.error('Fehler beim Erstellen der Coding-Anwendung:', error);
|
|
res.status(500).json({ error: 'Interner Serverfehler' });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* PUT /api/coding/directories/:id
|
|
* Coding-Anwendung aktualisieren
|
|
*/
|
|
router.put('/directories/:id', (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const { name, localPath, description, color, claudeInstructions, giteaRepoUrl, giteaRepoOwner, giteaRepoName, defaultBranch, position } = req.body;
|
|
|
|
const db = getDb();
|
|
|
|
const existing = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
|
if (!existing) {
|
|
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
|
}
|
|
|
|
// Prüfe ob neuer Pfad bereits von anderem Eintrag verwendet wird
|
|
if (localPath && localPath !== existing.local_path) {
|
|
const pathExists = db.prepare('SELECT id FROM coding_directories WHERE local_path = ? AND id != ?').get(localPath, id);
|
|
if (pathExists) {
|
|
return res.status(400).json({ error: 'Dieser Server-Pfad ist bereits registriert' });
|
|
}
|
|
}
|
|
|
|
db.prepare(`
|
|
UPDATE coding_directories SET
|
|
name = COALESCE(?, name),
|
|
local_path = COALESCE(?, local_path),
|
|
description = ?,
|
|
color = COALESCE(?, color),
|
|
claude_instructions = ?,
|
|
gitea_repo_url = ?,
|
|
gitea_repo_owner = ?,
|
|
gitea_repo_name = ?,
|
|
default_branch = COALESCE(?, default_branch),
|
|
position = COALESCE(?, position)
|
|
WHERE id = ?
|
|
`).run(
|
|
name || null,
|
|
localPath || null,
|
|
description !== undefined ? description : existing.description,
|
|
color || null,
|
|
null, // claudeInstructions wird nicht mehr aktualisiert
|
|
giteaRepoUrl !== undefined ? giteaRepoUrl : existing.gitea_repo_url,
|
|
giteaRepoOwner !== undefined ? giteaRepoOwner : existing.gitea_repo_owner,
|
|
giteaRepoName !== undefined ? giteaRepoName : existing.gitea_repo_name,
|
|
defaultBranch || null,
|
|
position !== undefined ? position : null,
|
|
id
|
|
);
|
|
|
|
const updated = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
|
const finalPath = updated.local_path;
|
|
|
|
// Ordner erstellen falls nicht vorhanden
|
|
let directoryCreated = false;
|
|
if (isServerPath(finalPath) && !fs.existsSync(finalPath)) {
|
|
try {
|
|
fs.mkdirSync(finalPath, { recursive: true });
|
|
directoryCreated = true;
|
|
logger.info(`Anwendungsordner erstellt: ${finalPath}`);
|
|
} catch (e) {
|
|
logger.error('Ordner erstellen fehlgeschlagen:', e);
|
|
}
|
|
}
|
|
|
|
// CLAUDE.md wird nicht mehr geschrieben - nur readonly
|
|
let claudeMdWritten = false;
|
|
|
|
logger.info(`Coding-Anwendung aktualisiert: ${updated.name}`);
|
|
|
|
// CLAUDE.md aus dem Dateisystem lesen für aktuelle Anzeige
|
|
const claudeMdFromDisk = isServerPath(updated.local_path) ? readCLAUDEmd(updated.local_path) : null;
|
|
|
|
res.json({
|
|
id: updated.id,
|
|
name: updated.name,
|
|
localPath: updated.local_path,
|
|
description: updated.description,
|
|
color: updated.color,
|
|
claudeInstructions: updated.claude_instructions,
|
|
claudeMdFromDisk: claudeMdFromDisk,
|
|
hasCLAUDEmd: !!claudeMdFromDisk,
|
|
giteaRepoUrl: updated.gitea_repo_url,
|
|
giteaRepoOwner: updated.gitea_repo_owner,
|
|
giteaRepoName: updated.gitea_repo_name,
|
|
defaultBranch: updated.default_branch,
|
|
position: updated.position,
|
|
createdAt: updated.created_at,
|
|
directoryCreated,
|
|
claudeMdWritten
|
|
});
|
|
} catch (error) {
|
|
logger.error('Fehler beim Aktualisieren der Coding-Anwendung:', error);
|
|
res.status(500).json({ error: 'Interner Serverfehler' });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* DELETE /api/coding/directories/:id
|
|
* Coding-Anwendung löschen
|
|
*/
|
|
router.delete('/directories/:id', (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const db = getDb();
|
|
|
|
const existing = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
|
if (!existing) {
|
|
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
|
}
|
|
|
|
db.prepare('DELETE FROM coding_directories WHERE id = ?').run(id);
|
|
|
|
logger.info(`Coding-Anwendung gelöscht: ${existing.name}`);
|
|
|
|
res.json({ message: 'Anwendung gelöscht' });
|
|
} catch (error) {
|
|
logger.error('Fehler beim Löschen der Coding-Anwendung:', error);
|
|
res.status(500).json({ error: 'Interner Serverfehler' });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* GET /api/coding/directories/:id/status
|
|
* Git-Status eines Verzeichnisses abrufen
|
|
*/
|
|
router.get('/directories/:id/status', (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const db = getDb();
|
|
|
|
const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
|
if (!directory) {
|
|
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
|
}
|
|
|
|
const localPath = directory.local_path;
|
|
|
|
// Prüfe ob es ein Git-Repository ist
|
|
if (!gitService.isGitRepository(localPath)) {
|
|
return res.json({
|
|
isGitRepo: false,
|
|
message: 'Kein Git-Repository'
|
|
});
|
|
}
|
|
|
|
const status = gitService.getStatus(localPath);
|
|
|
|
if (!status.success) {
|
|
return res.status(500).json({ error: status.error });
|
|
}
|
|
|
|
res.json({
|
|
isGitRepo: true,
|
|
branch: status.branch,
|
|
hasChanges: status.hasChanges,
|
|
changes: status.changes,
|
|
ahead: status.ahead,
|
|
behind: status.behind,
|
|
isClean: status.isClean
|
|
});
|
|
} catch (error) {
|
|
logger.error('Fehler beim Abrufen des Git-Status:', error);
|
|
res.status(500).json({ error: 'Interner Serverfehler' });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* POST /api/coding/directories/:id/fetch
|
|
* Git Fetch ausführen
|
|
*/
|
|
router.post('/directories/:id/fetch', (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const db = getDb();
|
|
|
|
const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
|
if (!directory) {
|
|
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
|
}
|
|
|
|
const result = gitService.fetchRemote(directory.local_path);
|
|
|
|
if (!result.success) {
|
|
return res.status(500).json({ error: result.error });
|
|
}
|
|
|
|
// Last sync aktualisieren
|
|
db.prepare('UPDATE coding_directories SET last_sync = CURRENT_TIMESTAMP WHERE id = ?').run(id);
|
|
|
|
logger.info(`Git fetch ausgeführt für: ${directory.name}`);
|
|
|
|
res.json({ success: true, message: 'Fetch erfolgreich' });
|
|
} catch (error) {
|
|
logger.error('Fehler beim Git Fetch:', error);
|
|
res.status(500).json({ error: 'Interner Serverfehler' });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* POST /api/coding/directories/:id/pull
|
|
* Git Pull ausführen
|
|
*/
|
|
router.post('/directories/:id/pull', (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const db = getDb();
|
|
|
|
const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
|
if (!directory) {
|
|
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
|
}
|
|
|
|
const result = gitService.pullChanges(directory.local_path, { branch: directory.default_branch });
|
|
|
|
if (!result.success) {
|
|
return res.status(500).json({ error: result.error });
|
|
}
|
|
|
|
// Last sync aktualisieren
|
|
db.prepare('UPDATE coding_directories SET last_sync = CURRENT_TIMESTAMP WHERE id = ?').run(id);
|
|
|
|
logger.info(`Git pull ausgeführt für: ${directory.name}`);
|
|
|
|
res.json({ success: true, message: 'Pull erfolgreich', output: result.output });
|
|
} catch (error) {
|
|
logger.error('Fehler beim Git Pull:', error);
|
|
res.status(500).json({ error: 'Interner Serverfehler' });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* POST /api/coding/directories/:id/push
|
|
* Git Push ausführen
|
|
*/
|
|
router.post('/directories/:id/push', (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const { force } = req.body;
|
|
const db = getDb();
|
|
|
|
const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
|
if (!directory) {
|
|
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
|
}
|
|
|
|
const result = gitService.pushWithUpstream(directory.local_path, directory.default_branch, 'origin', force);
|
|
|
|
if (!result.success) {
|
|
return res.status(500).json({ error: result.error });
|
|
}
|
|
|
|
// Last sync aktualisieren
|
|
db.prepare('UPDATE coding_directories SET last_sync = CURRENT_TIMESTAMP WHERE id = ?').run(id);
|
|
|
|
logger.info(`Git push ausgeführt für: ${directory.name}`);
|
|
|
|
res.json({ success: true, message: 'Push erfolgreich', output: result.output });
|
|
} catch (error) {
|
|
logger.error('Fehler beim Git Push:', error);
|
|
res.status(500).json({ error: 'Interner Serverfehler' });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* POST /api/coding/directories/:id/commit
|
|
* Git Commit ausführen
|
|
*/
|
|
router.post('/directories/:id/commit', (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const { message } = req.body;
|
|
const db = getDb();
|
|
|
|
if (!message || message.trim() === '') {
|
|
return res.status(400).json({ error: 'Commit-Nachricht erforderlich' });
|
|
}
|
|
|
|
const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
|
if (!directory) {
|
|
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
|
}
|
|
|
|
// Stage all changes
|
|
const stageResult = gitService.stageAll(directory.local_path);
|
|
if (!stageResult.success) {
|
|
return res.status(500).json({ error: stageResult.error });
|
|
}
|
|
|
|
// Commit with author info
|
|
const author = {
|
|
name: req.user.display_name || req.user.username,
|
|
email: req.user.email || `${req.user.username}@taskmate.local`
|
|
};
|
|
|
|
const result = gitService.commit(directory.local_path, message, author);
|
|
|
|
if (!result.success) {
|
|
return res.status(500).json({ error: result.error });
|
|
}
|
|
|
|
logger.info(`Git commit ausgeführt für: ${directory.name} - "${message}"`);
|
|
|
|
res.json({ success: true, message: 'Commit erfolgreich', output: result.output });
|
|
} catch (error) {
|
|
logger.error('Fehler beim Git Commit:', error);
|
|
res.status(500).json({ error: 'Interner Serverfehler' });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* GET /api/coding/directories/:id/branches
|
|
* Branches abrufen
|
|
*/
|
|
router.get('/directories/:id/branches', (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const db = getDb();
|
|
|
|
const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
|
if (!directory) {
|
|
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
|
}
|
|
|
|
const result = gitService.getBranches(directory.local_path);
|
|
|
|
if (!result.success) {
|
|
return res.status(500).json({ error: result.error });
|
|
}
|
|
|
|
res.json({ branches: result.branches });
|
|
} catch (error) {
|
|
logger.error('Fehler beim Abrufen der Branches:', error);
|
|
res.status(500).json({ error: 'Interner Serverfehler' });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* POST /api/coding/directories/:id/checkout
|
|
* Branch wechseln
|
|
*/
|
|
router.post('/directories/:id/checkout', (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const { branch } = req.body;
|
|
const db = getDb();
|
|
|
|
if (!branch) {
|
|
return res.status(400).json({ error: 'Branch erforderlich' });
|
|
}
|
|
|
|
const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
|
if (!directory) {
|
|
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
|
}
|
|
|
|
const result = gitService.checkoutBranch(directory.local_path, branch);
|
|
|
|
if (!result.success) {
|
|
return res.status(500).json({ error: result.error });
|
|
}
|
|
|
|
logger.info(`Branch gewechselt für ${directory.name}: ${branch}`);
|
|
|
|
res.json({ success: true, message: `Gewechselt zu Branch: ${branch}` });
|
|
} catch (error) {
|
|
logger.error('Fehler beim Branch-Wechsel:', error);
|
|
res.status(500).json({ error: 'Interner Serverfehler' });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* POST /api/coding/validate-path
|
|
* Pfad validieren
|
|
*/
|
|
router.post('/validate-path', (req, res) => {
|
|
try {
|
|
const { path: localPath } = req.body;
|
|
|
|
if (!localPath) {
|
|
return res.status(400).json({ error: 'Pfad erforderlich' });
|
|
}
|
|
|
|
// Nur Server-Pfade können validiert werden
|
|
if (isServerPath(localPath)) {
|
|
const containerPath = gitService.windowsToContainerPath(localPath);
|
|
const exists = fs.existsSync(containerPath);
|
|
const isGitRepo = exists && gitService.isGitRepository(localPath);
|
|
|
|
res.json({
|
|
valid: true,
|
|
exists,
|
|
isGitRepo,
|
|
isServerPath: true
|
|
});
|
|
} else {
|
|
// Windows-Pfad kann nicht serverseitig validiert werden
|
|
res.json({
|
|
valid: true,
|
|
exists: null,
|
|
isGitRepo: null,
|
|
isServerPath: false,
|
|
message: 'Windows-Pfade können nicht serverseitig validiert werden'
|
|
});
|
|
}
|
|
} catch (error) {
|
|
logger.error('Fehler bei der Pfad-Validierung:', error);
|
|
res.status(500).json({ error: 'Interner Serverfehler' });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* GET /api/coding/directories/:id/commits
|
|
* Commit-Historie abrufen
|
|
*/
|
|
router.get('/directories/:id/commits', (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const limit = parseInt(req.query.limit) || 20;
|
|
const db = getDb();
|
|
|
|
const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
|
if (!directory) {
|
|
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
|
}
|
|
|
|
const result = gitService.getCommitHistory(directory.local_path, limit);
|
|
|
|
if (!result.success) {
|
|
return res.status(500).json({ error: result.error });
|
|
}
|
|
|
|
res.json({ commits: result.commits });
|
|
} catch (error) {
|
|
logger.error('Fehler beim Abrufen der Commit-Historie:', error);
|
|
res.status(500).json({ error: 'Interner Serverfehler' });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* GET /api/coding/directories/:id/usage
|
|
* Aktuelle Verbrauchsdaten abrufen (simuliert)
|
|
*/
|
|
router.get('/directories/:id/usage', (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const db = getDb();
|
|
|
|
const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
|
if (!directory) {
|
|
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
|
}
|
|
|
|
// Simulierte Verbrauchsdaten generieren
|
|
const usage = {
|
|
cpu_percent: Math.random() * 100,
|
|
memory_mb: Math.floor(Math.random() * 4096),
|
|
disk_read_mb: Math.random() * 100,
|
|
disk_write_mb: Math.random() * 50,
|
|
network_recv_mb: Math.random() * 10,
|
|
network_sent_mb: Math.random() * 10,
|
|
process_count: Math.floor(Math.random() * 20) + 1,
|
|
timestamp: new Date()
|
|
};
|
|
|
|
// Speichere in Datenbank für Historie
|
|
db.prepare(`
|
|
INSERT INTO coding_usage (directory_id, cpu_percent, memory_mb, disk_read_mb,
|
|
disk_write_mb, network_recv_mb, network_sent_mb, process_count)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
`).run(id, usage.cpu_percent, usage.memory_mb, usage.disk_read_mb,
|
|
usage.disk_write_mb, usage.network_recv_mb, usage.network_sent_mb, usage.process_count);
|
|
|
|
res.json({ usage });
|
|
} catch (error) {
|
|
logger.error('Fehler beim Abrufen der Verbrauchsdaten:', error);
|
|
res.status(500).json({ error: 'Interner Serverfehler' });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* GET /api/coding/directories/:id/usage/history
|
|
* Historische Verbrauchsdaten abrufen
|
|
*/
|
|
router.get('/directories/:id/usage/history', (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const hours = parseInt(req.query.hours) || 24;
|
|
const db = getDb();
|
|
|
|
const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
|
if (!directory) {
|
|
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
|
}
|
|
|
|
const history = db.prepare(`
|
|
SELECT * FROM coding_usage
|
|
WHERE directory_id = ?
|
|
AND timestamp > datetime('now', '-${hours} hours')
|
|
ORDER BY timestamp DESC
|
|
LIMIT 100
|
|
`).all(id);
|
|
|
|
res.json({ history });
|
|
} catch (error) {
|
|
logger.error('Fehler beim Abrufen der Verbrauchshistorie:', error);
|
|
res.status(500).json({ error: 'Interner Serverfehler' });
|
|
}
|
|
});
|
|
|
|
module.exports = router;
|