#!/usr/bin/env nu # export-tracking.nu - Export tracking data in multiple formats # Follows NuShell 0.108+ guidelines with explicit types def main [ format: string = "json" # Required positional --output: string = "export" # Flag with value --project: string = "" # Optional filter --status: string = "all" # Filter by status --verbose = false ]: void { # Rule 3: Early validation if $format not-in ["json", "csv", "kanban", "markdown"] { error make { msg: $"Invalid format: [$format]. Must be: json, csv, kanban, or markdown" } } if $verbose { print "📊 Starting tracking export..." print $"📁 Format: [$format]" if ($project != "") { print $"🎯 Project filter: [$project]" } } # Rule 13: Predictable naming (get-tracking-data) let data = get-tracking-data $project $status # Rule 17: String interpolation let output-file = $"[$output].($format)" if $verbose { print $"📝 Exporting to [$output-file]" } # Rule 1: Single purpose - format and save match $format { "json" => { let json-content = ($data | to json) $json-content | save --force $output-file } "csv" => { let csv-content = format-csv $data $csv-content | save --force $output-file } "kanban" => { let kanban-content = format-kanban $data $kanban-content | save --force $output-file } "markdown" => { let md-content = format-markdown $data $md-content | save --force $output-file } } print $"✅ Exported to [$output-file]" # Rule 17: ($expr) for expressions let file-size = (stat $output-file | get size) print $"📦 File size: (($file-size / 1024) | math round --precision 2) KB" } # Rule 1: Single purpose - fetches data def get-tracking-data [project-filter: string, status-filter: string]: table { let url = if ($project-filter == "") { # Rule 17: Expression interpolation $"http://localhost:3000/api/v1/tracking/summary?status=($status-filter)" } else { $"http://localhost:3000/api/v1/tracking/projects/($project-filter)?status=($status-filter)" } try { http get $url | get items } catch { print "⚠️ Could not fetch data from tracking API" print " Make sure tracking server is running: cargo run -p vapora-backend" [] } } # Rule 1: Single purpose - formats as CSV def format-csv [data: table]: string { let header = "id,project,source,type,summary,timestamp\n" let rows = ( $data | each { |item| $"($item.id),($item.project_path),($item.source),($item.entry_type),\"($item.summary)\",($item.timestamp)" } | str join "\n" ) $header + $rows } # Rule 1: Single purpose - formats as Kanban def format-kanban [data: table]: string { let pending = ($data | where entry_type =~ "Todo" | where status == "Pending") let in-progress = ($data | where entry_type =~ "Todo" | where status == "InProgress") let completed = ($data | where entry_type =~ "Todo" | where status == "Completed") let output = $" # Kanban Board ## 📋 Pending ($($pending | length) items) ($pending | each { |item| $"- [$item.summary] *($item.priority)*" } | str join "\n") ## 🔄 In Progress ($($in-progress | length) items) ($in-progress | each { |item| $"- [$item.summary] *($item.priority)*" } | str join "\n") ## ✅ Completed ($($completed | length) items) ($completed | each { |item| $"- ✅ [$item.summary]" } | str join "\n") " $output } # Rule 1: Single purpose - formats as Markdown def format-markdown [data: table]: string { let changes = ($data | where source =~ "Change") let todos = ($data | where source =~ "Todo") let output = $" # Tracking Report Generated: (date now | format date '%Y-%m-%d %H:%M:%S UTC') ## Summary - **Total Entries**: ($($data | length)) - **Changes**: ($($changes | length)) - **TODOs**: ($($todos | length)) ## Changes ($changes | each { |item| $"### [$item.timestamp] - ($item.summary) **Impact**: ($item.impact) | **Breaking**: ($item.breaking) " } | str join) ## TODOs ($todos | each { |item| $"### [$item.summary] **Priority**: ($item.priority) | **Estimate**: ($item.estimate) | **Status**: ($item.status) " } | str join) " $output }