From 35f48d38bba76cb0d9bac4985b3c94af97f2cf2f Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 8 Apr 2026 14:33:09 +0000 Subject: [PATCH] feat: Read task_number from YAML frontmatter Updated data fetcher to: 1. Prioritize task_number from frontmatter (new) 2. Fall back to folder/file name pattern (task-XXX-*) 3. Fall back to title pattern (#XX) Also handles standalone .md files (task-098, task-099) Chronicler #69 --- _data/tasks.js | 72 ++++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/_data/tasks.js b/_data/tasks.js index 27dc984..d6a7b68 100644 --- a/_data/tasks.js +++ b/_data/tasks.js @@ -26,14 +26,25 @@ module.exports = async function() { return []; } - const dirs = await response.json(); - const taskDirs = dirs.filter(d => d.type === 'dir' && d.name !== '_archive'); + const items = await response.json(); + // Include both directories AND standalone .md files (like task-098, task-099) + const taskItems = items.filter(d => + (d.type === 'dir' && d.name !== '_archive') || + (d.type === 'file' && d.name.startsWith('task-') && d.name.endsWith('.md')) + ); - // Fetch each task's README - for (const dir of taskDirs) { + for (const item of taskItems) { try { - // Try README.md first - let readmePath = `docs/tasks/${dir.name}/README.md`; + let readmePath; + + if (item.type === 'file') { + // Standalone task file + readmePath = `docs/tasks/${item.name}`; + } else { + // Directory - try README.md first + readmePath = `docs/tasks/${item.name}/README.md`; + } + let readmeResponse = await fetch( `${GITEA_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/${encodeURIComponent(readmePath)}?ref=master`, { @@ -44,10 +55,10 @@ module.exports = async function() { } ); - if (!readmeResponse.ok) { - // Try to find any .md file + // If README.md not found in directory, try to find any .md file + if (!readmeResponse.ok && item.type === 'dir') { const filesResponse = await fetch( - `${GITEA_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/docs/tasks/${encodeURIComponent(dir.name)}?ref=master`, + `${GITEA_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/docs/tasks/${encodeURIComponent(item.name)}?ref=master`, { headers: { 'Authorization': `token ${TOKEN}`, @@ -60,7 +71,7 @@ module.exports = async function() { const files = await filesResponse.json(); const mdFile = files.find(f => f.name.endsWith('.md')); if (mdFile) { - readmePath = `docs/tasks/${dir.name}/${mdFile.name}`; + readmePath = `docs/tasks/${item.name}/${mdFile.name}`; readmeResponse = await fetch( `${GITEA_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/${encodeURIComponent(readmePath)}?ref=master`, { @@ -91,25 +102,25 @@ module.exports = async function() { // Extract title from first H1 const titleMatch = content.match(/^#\s+(.+)$/m); - let title = titleMatch ? titleMatch[1] : dir.name; + let title = titleMatch ? titleMatch[1] : item.name; - // Extract task number - check multiple sources + // Get task number - priority: frontmatter > folder name > title > content let taskNumber = null; - // 1. Check frontmatter for task_number field + // 1. YAML frontmatter task_number (preferred source) if (frontmatter.task_number) { - taskNumber = frontmatter.task_number; + taskNumber = String(frontmatter.task_number); } - // 2. Check folder name (e.g., task-048-n8n-rebuild) + // 2. Folder/file name pattern (task-048-*) if (!taskNumber) { - const folderNumMatch = dir.name.match(/^task-0*(\d+)/); - if (folderNumMatch) { - taskNumber = folderNumMatch[1]; + const nameNumMatch = item.name.match(/^task-0*(\d+)/); + if (nameNumMatch) { + taskNumber = nameNumMatch[1]; } } - // 3. Check title for #XX pattern + // 3. Title pattern (#XX) if (!taskNumber) { const titleNumMatch = title.match(/#(\d+)/); if (titleNumMatch) { @@ -117,43 +128,36 @@ module.exports = async function() { } } - // 4. Check content for Task ID or Task #XX patterns - if (!taskNumber) { - const contentNumMatch = content.match(/\*\*Task ID:\*\*\s*#?(\d+)/i) || - content.match(/\*\*Task ID:\*\*\s*FFG-TASK-0*(\d+)/i) || - content.match(/^#\s+Task\s+#(\d+)/im); - if (contentNumMatch) { - taskNumber = contentNumMatch[1]; - } - } + // Build Gitea URL + const giteaPath = item.type === 'file' + ? `docs/tasks/${item.name}` + : `docs/tasks/${item.name}`; tasks.push({ - slug: dir.name, + slug: item.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)}` + giteaUrl: `https://git.firefrostgaming.com/${REPO_OWNER}/${REPO_NAME}/src/branch/master/${giteaPath}` }); } } } catch (err) { - console.error(`Error processing ${dir.name}:`, err.message); + console.error(`Error processing ${item.name}:`, err.message); } } - // Sort by priority (P1 first) then by task number (if available) then by title + // Sort by priority (P1 first) then by task number 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);