const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args)); module.exports = async function() { const GITEA_API = 'https://git.firefrostgaming.com/api/v1'; const REPO_OWNER = 'firefrost-gaming'; const REPO_NAME = 'firefrost-operations-manual'; const TOKEN = process.env.GITEA_TOKEN || 'e0e330cba1749b01ab505093a160e4423ebbbe36'; const tasks = []; try { // Get list of task directories const response = await fetch( `${GITEA_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/docs/tasks?ref=master`, { headers: { 'Authorization': `token ${TOKEN}`, 'Accept': 'application/json' }, timeout: 30000 } ); if (!response.ok) { console.error('Failed to fetch task list:', response.status); return []; } const dirs = await response.json(); const taskDirs = dirs.filter(d => d.type === 'dir' && d.name !== '_archive'); // Fetch each task's README for (const dir of taskDirs) { try { // Try README.md first let readmePath = `docs/tasks/${dir.name}/README.md`; let readmeResponse = await fetch( `${GITEA_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/${encodeURIComponent(readmePath)}?ref=master`, { headers: { 'Authorization': `token ${TOKEN}`, 'Accept': 'application/json' } } ); if (!readmeResponse.ok) { // Try to find any .md file const filesResponse = await fetch( `${GITEA_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/docs/tasks/${encodeURIComponent(dir.name)}?ref=master`, { headers: { 'Authorization': `token ${TOKEN}`, 'Accept': 'application/json' } } ); if (filesResponse.ok) { const files = await filesResponse.json(); const mdFile = files.find(f => f.name.endsWith('.md')); if (mdFile) { readmePath = `docs/tasks/${dir.name}/${mdFile.name}`; readmeResponse = await fetch( `${GITEA_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/${encodeURIComponent(readmePath)}?ref=master`, { headers: { 'Authorization': `token ${TOKEN}`, 'Accept': 'application/json' } } ); } } } if (readmeResponse && readmeResponse.ok) { const fileData = await readmeResponse.json(); const content = Buffer.from(fileData.content, 'base64').toString('utf-8'); // Parse YAML frontmatter const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/); if (frontmatterMatch) { const frontmatter = {}; frontmatterMatch[1].split('\n').forEach(line => { const match = line.match(/^(\w+):\s*(.+)$/); if (match) { frontmatter[match[1]] = match[2].trim(); } }); // Extract title from first H1 const titleMatch = content.match(/^#\s+(.+)$/m); let title = titleMatch ? titleMatch[1] : dir.name; // Extract task number from title (e.g., "Task #87:" or "# Task #87") let taskNumber = null; const taskNumMatch = title.match(/#(\d+)/); if (taskNumMatch) { taskNumber = taskNumMatch[1]; } else { // Try to find task number in content const contentNumMatch = content.match(/\*\*Task ID:\*\*\s*#?(\d+)/i) || content.match(/Task #(\d+)/i) || content.match(/\*\*Task ID:\*\*\s*FFG-TASK-(\d+)/i); if (contentNumMatch) { taskNumber = contentNumMatch[1]; } } tasks.push({ slug: dir.name, title: title, taskNumber: taskNumber, status: frontmatter.status || 'open', priority: frontmatter.priority || 'P3', owner: frontmatter.owner || 'Michael', created: frontmatter.created || '2026-01-01', giteaUrl: `https://git.firefrostgaming.com/${REPO_OWNER}/${REPO_NAME}/src/branch/master/docs/tasks/${encodeURIComponent(dir.name)}` }); } } } catch (err) { console.error(`Error processing ${dir.name}:`, err.message); } } // Sort by priority (P1 first) then by task number (if available) then by title tasks.sort((a, b) => { if (a.priority !== b.priority) { return a.priority.localeCompare(b.priority); } // Sort by task number if both have one if (a.taskNumber && b.taskNumber) { return parseInt(a.taskNumber) - parseInt(b.taskNumber); } // Tasks with numbers come before those without if (a.taskNumber && !b.taskNumber) return -1; if (!a.taskNumber && b.taskNumber) return 1; return a.title.localeCompare(b.title); }); console.log(`[11ty] Loaded ${tasks.length} tasks from Gitea`); return tasks; } catch (err) { console.error('[11ty] Error fetching tasks:', err.message); return []; } };