← back to jflournoy__garmin-analysis

Function bodies 261 total

All specs Real LLM only Function bodies
identifyLearnings function · javascript · L74-L97 (24 LOC)
scripts/retrospective.js
function identifyLearnings(commits) {
  const learnings = [];
  
  // Look for patterns indicating learnings
  if (commits.some(c => c.includes('fix:'))) {
    learnings.push('Bug fixes indicate areas needing more testing');
  }
  
  if (commits.some(c => c.includes('refactor:'))) {
    learnings.push('Refactoring suggests initial implementation could be improved');
  }
  
  if (commits.filter(c => c.includes('docs:')).length > 2) {
    learnings.push('Multiple documentation updates suggest initial docs were incomplete');
  }
  
  // Check for reverts or fixes to recent commits
  const revertPattern = /revert|undo|fix.*previous/i;
  if (commits.some(c => revertPattern.test(c))) {
    learnings.push('Reverts suggest need for better testing before commits');
  }
  
  return learnings;
}
generateReport function · javascript · L99-L168 (70 LOC)
scripts/retrospective.js
function generateReport() {
  console.log('\n📊 Session Retrospective\n');
  console.log('='.repeat(50));
  
  const { commits, patterns } = analyzeGitHistory();
  
  console.log(`\n📅 Period: ${options.since}`);
  console.log(`📝 Total Commits: ${commits.length}`);
  
  if (options.metrics) {
    const metrics = getMetrics();
    console.log('\n📈 Metrics:');
    console.log(`  Files Changed: ${metrics.filesChanged}`);
    console.log(`  Lines Added: ${metrics.insertions}`);
    console.log(`  Lines Removed: ${metrics.deletions}`);
    console.log(`  Net Change: ${metrics.insertions - metrics.deletions}`);
  }
  
  console.log('\n🔍 Commit Patterns:');
  Object.entries(patterns)
    .filter(([, count]) => count > 0)
    .sort(([, a], [, b]) => b - a)
    .forEach(([type, count]) => {
      const percentage = Math.round((count / commits.length) * 100);
      console.log(`  ${type}: ${count} (${percentage}%)`);
    });
  
  console.log('\n💡 Recent Changes:');
  commits.slice(0, 5).forEach(co
updateLearnings function · javascript · L170-L211 (42 LOC)
scripts/retrospective.js
function updateLearnings(commits, patterns, learnings) {
  const learningsFile = path.join(process.cwd(), 'LEARNINGS.md');
  
  if (!fs.existsSync(learningsFile)) {
    console.log('\n⚠️  LEARNINGS.md not found, skipping update');
    return;
  }
  
  const date = new Date().toISOString().split('T')[0];
  const entry = `
### Session Retrospective - ${date}
**Commits**: ${commits.length}
**Primary Focus**: ${Object.entries(patterns).sort(([,a], [,b]) => b - a)[0]?.[0] || 'mixed'}

#### Patterns Observed
${Object.entries(patterns)
  .filter(([, count]) => count > 0)
  .map(([type, count]) => `- ${type}: ${count}`)
  .join('\n')}

#### Key Insights
${learnings.map(l => `- ${l}`).join('\n') || '- Session focused on implementation'}

---
`;
  
  // Read current content
  let content = fs.readFileSync(learningsFile, 'utf8');
  
  // Find the Recent Session Learnings section and add entry
  const marker = '## Recent Session Learnings';
  const index = content.indexOf(marker);
  
  if (index !
getNextSessionNumber function · javascript · L36-L56 (21 LOC)
scripts/session-history.js
function getNextSessionNumber(dateDir) {
  if (!fs.existsSync(dateDir)) {
    return '001';
  }
  
  const files = fs.readdirSync(dateDir);
  const sessionFiles = files.filter(f => f.startsWith('session-'));
  
  if (sessionFiles.length === 0) {
    return '001';
  }
  
  // Extract numbers and find max
  const numbers = sessionFiles
    .map(f => f.match(/session-(\d{3})/))
    .filter(m => m)
    .map(m => parseInt(m[1]));
  
  const maxNum = Math.max(...numbers, 0);
  return String(maxNum + 1).padStart(3, '0');
}
getLastSaveInfo function · javascript · L58-L67 (10 LOC)
scripts/session-history.js
function getLastSaveInfo() {
  if (fs.existsSync(LAST_SAVE_FILE)) {
    try {
      return JSON.parse(fs.readFileSync(LAST_SAVE_FILE, 'utf8'));
    } catch {
      return null;
    }
  }
  return null;
}
captureGitActivity function · javascript · L94-L142 (49 LOC)
scripts/session-history.js
function captureGitActivity(sinceCommit = null) {
  const activity = {
    commits: [],
    filesChanged: [],
    branch: 'unknown',
    newCommitsOnly: false
  };
  
  try {
    // Get current branch
    activity.branch = execSync('git branch --show-current', {encoding: 'utf8'}).trim();
    
    // Get commits since last save or recent commits
    let commitCommand = 'git log --oneline -20';
    if (sinceCommit) {
      // Only get commits since the specified commit
      commitCommand = `git log --oneline ${sinceCommit}..HEAD`;
      activity.newCommitsOnly = true;
    }
    
    const commits = execSync(commitCommand, {encoding: 'utf8'}).trim();
    if (commits) {
      activity.commits = commits.split('\n').map(c => {
        const [hash, ...messageParts] = c.split(' ');
        return {
          hash: hash.substring(0, 7),
          message: messageParts.join(' ')
        };
      });
    }
    
    // Get files changed in working directory
    const changes = execSync('git statu
getTestResultsFromCache function · javascript · L146-L155 (10 LOC)
scripts/session-history.js
function getTestResultsFromCache() {
  // This could read from a .test-results.json file if needed
  // For now, just return empty results to avoid running tests
  return {
    lastRun: null,
    passing: 0,
    failing: 0,
    skipped: true
  };
}
Repobility · severity-and-effort ranking · https://repobility.com
getLastCommitFromSave function · javascript · L158-L170 (13 LOC)
scripts/session-history.js
function getLastCommitFromSave() {
  const lastSave = getLastSaveInfo();
  if (!lastSave || !lastSave.file) return null;
  
  try {
    const content = fs.readFileSync(lastSave.file, 'utf8');
    // Extract the first commit hash from the previous save
    const match = content.match(/- `([a-f0-9]{7})` /); 
    return match ? match[1] : null;
  } catch {
    return null;
  }
}
detectSessionType function · javascript · L173-L186 (14 LOC)
scripts/session-history.js
function detectSessionType() {
  // Check if running in test environment (but not just "testing" in description)
  if (process.env.NODE_ENV === 'test' || process.argv[1]?.includes('test.js')) {
    return 'test';
  }
  
  // Check if running automated (CI, cron, etc)
  if (process.env.CI || process.env.GITHUB_ACTIONS) {
    return 'automated';
  }
  
  // Default to manual
  return 'manual';
}
saveSession function · javascript · L189-L343 (155 LOC)
scripts/session-history.js
function saveSession(description = '', options = {}) {
  // Check environment variable to skip saves
  if (process.env.SKIP_SESSION_SAVE === '1' || process.env.SKIP_SESSION_SAVE === 'true') {
    return null;
  }
  
  // Detect session type and check if we should skip
  const sessionType = options.sessionType || detectSessionType();
  if (sessionType === 'test' && !options.forceSave && !options.testing) {
    console.log('⏭️  Skipping test session save');
    return null;
  }
  
  const sessionDir = getSessionDirectory();
  const sessionNum = getNextSessionNumber(sessionDir);
  const timestamp = getTimeString();
  
  // Check for delta mode
  const isDelta = options.delta || false;
  const lastCommit = isDelta ? getLastCommitFromSave() : null;
  
  // Determine filename
  const baseFilename = `session-${sessionNum}-${timestamp}`;
  const suffix = isDelta ? '-delta' : '';
  const filename = description 
    ? `${baseFilename}${suffix}-${description.replace(/[^a-z0-9]/gi, '-')}.txt`
    
saveDelta function · javascript · L345-L358 (14 LOC)
scripts/session-history.js
function saveDelta() {
  const lastSave = getLastSaveInfo();
  
  if (!lastSave) {
    console.log('⚠️  No previous save found, performing full save');
    return saveSession('initial', { delta: false });
  }
  
  console.log('\n📝 Saving delta since last save...');
  console.log(`Last save: ${lastSave.date} at ${lastSave.time}`);
  
  // Use the new saveSession with delta option
  return saveSession('', { delta: true });
}
listSessions function · javascript · L360-L440 (81 LOC)
scripts/session-history.js
function listSessions() {
  console.log('\n📚 Session History\n');
  console.log('='.repeat(50));
  
  if (!fs.existsSync(SESSION_HISTORY_DIR)) {
    console.log('No session history found');
    return;
  }
  
  const dates = fs.readdirSync(SESSION_HISTORY_DIR)
    .filter(d => /^\d{4}-\d{2}-\d{2}$/.test(d))
    .sort()
    .reverse();
  
  if (dates.length === 0) {
    console.log('No sessions saved yet');
    return;
  }
  
  // Show recent sessions
  dates.slice(0, 7).forEach(date => {
    const dateDir = path.join(SESSION_HISTORY_DIR, date);
    const files = fs.readdirSync(dateDir)
      .filter(f => f.startsWith('session-'))
      .sort();
    
    if (files.length > 0) {
      console.log(`\n📅 ${date}`);
      files.forEach(file => {
        // Skip metadata files if they still exist (backwards compatibility)
        if (file.endsWith('.meta.json')) return;
        
        const stats = fs.statSync(path.join(dateDir, file));
        const size = (stats.size / 1024).toFixed(1);
 
archiveSessions function · javascript · L442-L477 (36 LOC)
scripts/session-history.js
function archiveSessions(daysOld = 30) {
  const archiveDir = path.join(SESSION_HISTORY_DIR, 'archive');
  ensureDirectoryExists(archiveDir);
  
  const cutoffDate = new Date();
  cutoffDate.setDate(cutoffDate.getDate() - daysOld);
  
  console.log(`\n📦 Archiving sessions older than ${daysOld} days...`);
  console.log(`Cutoff date: ${cutoffDate.toISOString().split('T')[0]}`);
  
  if (!fs.existsSync(SESSION_HISTORY_DIR)) {
    console.log('No sessions to archive');
    return;
  }
  
  const dates = fs.readdirSync(SESSION_HISTORY_DIR)
    .filter(d => /^\d{4}-\d{2}-\d{2}$/.test(d));
  
  let archivedCount = 0;
  dates.forEach(date => {
    const dateObj = new Date(date);
    if (dateObj < cutoffDate) {
      const sourcePath = path.join(SESSION_HISTORY_DIR, date);
      const destPath = path.join(archiveDir, date);
      
      // Move directory to archive
      if (!fs.existsSync(destPath)) {
        fs.renameSync(sourcePath, destPath);
        console.log(`  Archived: ${date}`);
    
showHelp function · javascript · L479-L505 (27 LOC)
scripts/session-history.js
function showHelp() {
  console.log(`
📚 Session History Manager

Usage: node scripts/session-history.js [command] [options]

Commands:
  save [description]  Save current session with optional description
  delta              Save only changes since last save
  list               List recent session history
  archive [days]     Archive sessions older than N days (default: 30)
  help               Show this help message

Examples:
  npm run session:save
  npm run session:save "feature-implementation"
  npm run session:delta
  npm run session:list
  npm run session:archive 60

Notes:
  - Sessions are organized by date in session-history/
  - Delta saves only capture changes since last save
  - Use 'save' for full session captures
  - Archive old sessions to keep history organized
`);
}
checkGitStatus function · javascript · L42-L69 (28 LOC)
scripts/setup.js
function checkGitStatus(filepath) {
  try {
    // Check if file exists
    if (!fs.existsSync(filepath)) {
      return 'NEW_FILE';
    }
    
    // Check if file is tracked by git
    try {
      execSync(`git ls-files --error-unmatch "${filepath}"`, { stdio: 'ignore' });
    } catch {
      return 'UNTRACKED';
    }
    
    // Check for uncommitted changes
    const diffOutput = execSync(`git diff --name-only "${filepath}"`, { encoding: 'utf8' });
    const stagedOutput = execSync(`git diff --staged --name-only "${filepath}"`, { encoding: 'utf8' });
    
    if (diffOutput.trim() || stagedOutput.trim()) {
      return 'UNCOMMITTED';
    }
    
    return 'CLEAN';
  } catch {
    // If git commands fail, assume file is safe to modify
    return 'UNKNOWN';
  }
}
Repobility (the analyzer behind this table) · https://repobility.com
isGitRepo function · javascript · L91-L98 (8 LOC)
scripts/setup.js
function isGitRepo() {
  try {
    execSync('git status', { stdio: 'ignore' });
    return true;
  } catch {
    return false;
  }
}
getAllFiles function · javascript · L106-L119 (14 LOC)
scripts/setup.js
function getAllFiles(dir, files = []) {
  if (!fs.existsSync(dir)) return files;
  
  const items = fs.readdirSync(dir);
  for (const item of items) {
    const fullPath = path.join(dir, item);
    if (fs.statSync(fullPath).isDirectory()) {
      getAllFiles(fullPath, files);
    } else {
      files.push(fullPath);
    }
  }
  return files;
}
detectConflicts function · javascript · L122-L135 (14 LOC)
scripts/setup.js
function detectConflicts(sourceDir, targetDir) {
  const conflicts = [];
  if (!fs.existsSync(targetDir)) return conflicts;
  
  const sourceFiles = getAllFiles(sourceDir);
  for (const file of sourceFiles) {
    const relativePath = path.relative(sourceDir, file);
    const targetPath = path.join(targetDir, relativePath);
    if (fs.existsSync(targetPath)) {
      conflicts.push(relativePath);
    }
  }
  return conflicts;
}
promptUser function · javascript · L138-L176 (39 LOC)
scripts/setup.js
async function promptUser(conflicts) {
  console.log('');
  console.log(`⚠️  Found ${conflicts.length} existing file(s):`);
  // Show first 5 conflicts
  conflicts.slice(0, 5).forEach(file => {
    console.log(`   • ${file}`);
  });
  if (conflicts.length > 5) {
    console.log(`   ... and ${conflicts.length - 5} more`);
  }
  
  console.log('');
  console.log('How would you like to proceed?');
  console.log('  1. Skip - Keep your existing files (recommended)');
  console.log('  2. Backup - Backup existing and install fresh');
  console.log('  3. Merge - Add only non-conflicting files');
  console.log('  4. Cancel - Exit without changes');
  console.log('');
  
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
  });
  
  return new Promise((resolve) => {
    rl.question('Choice [1-4]: ', (answer) => {
      rl.close();
      switch (answer.trim()) {
        case '1': resolve('skip'); break;
        case '2': resolve('backup'); break;
        c
determineStrategy function · javascript · L179-L188 (10 LOC)
scripts/setup.js
async function determineStrategy(conflicts, options) {
  if (conflicts.length === 0) return 'proceed';
  
  if (options.skip) return 'skip';
  if (options.backup) return 'backup';
  if (options.force) return 'backup'; // Force is like backup but less interactive
  if (options.interactive) return await promptUser(conflicts);
  
  return 'skip'; // Default safe behavior
}
copyRecursive function · javascript · L191-L242 (52 LOC)
scripts/setup.js
function copyRecursive(source, target, skipExisting = false) {
  // Create target directory if it doesn't exist
  if (!options['dry-run'] && !fs.existsSync(target)) {
    fs.mkdirSync(target, { recursive: true });
  }
  
  const items = fs.readdirSync(source);
  let copied = 0;
  let skipped = 0;
  
  for (const item of items) {
    const sourcePath = path.join(source, item);
    const targetPath = path.join(target, item);
    
    if (fs.statSync(sourcePath).isDirectory()) {
      const result = copyRecursive(sourcePath, targetPath, skipExisting);
      copied += result.copied;
      skipped += result.skipped;
    } else {
      const gitStatus = checkGitStatus(targetPath);
      const fileSize = fs.statSync(sourcePath).size;
      
      if (skipExisting && fs.existsSync(targetPath)) {
        skipped++;
        if (options['dry-run']) {
          dryRunData.skippedFiles.push({ path: targetPath, reason: 'exists', gitStatus });
        }
      } else {
        if (options['dry-run']) 
backupDirectory function · javascript · L245-L252 (8 LOC)
scripts/setup.js
function backupDirectory(dir) {
  if (!fs.existsSync(dir)) return null;
  
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5);
  const backupPath = `${dir}.backup-${timestamp}`;
  fs.renameSync(dir, backupPath);
  return backupPath;
}
safeCopy function · javascript · L255-L291 (37 LOC)
scripts/setup.js
function safeCopy(source, target, strategy, name) {
  let result = { copied: 0, skipped: 0, backedUp: null };
  
  switch (strategy) {
    case 'proceed':
      // No conflicts, just copy
      result = copyRecursive(source, target);
      break;
      
    case 'skip':
      // Skip all conflicts
      console.log(`   ⏭️  Preserving existing ${name}`);
      result.skipped = getAllFiles(source).length;
      break;
      
    case 'backup':
      // Backup existing and copy fresh
      if (fs.existsSync(target)) {
        result.backedUp = backupDirectory(target);
        console.log(`   📦 Backed up to ${path.basename(result.backedUp)}`);
      }
      result = copyRecursive(source, target);
      break;
      
    case 'merge':
      // Only copy non-conflicting files
      result = copyRecursive(source, target, true);
      break;
      
    case 'cancel':
      console.log('❌ Setup cancelled');
      process.exit(0);
      break;
  }
  
  return result;
}
All rows above produced by Repobility · https://repobility.com
mergePackageJson function · javascript · L311-L480 (170 LOC)
scripts/setup.js
async function mergePackageJson(sourcePackagePath, targetPackagePath, options) {
  // Check if source package.json exists
  if (!fs.existsSync(sourcePackagePath)) {
    return { added: 0, skipped: 0, conflicts: [] };
  }
  
  // Check if target package.json exists
  if (!fs.existsSync(targetPackagePath)) {
    // Create new package.json with essential scripts
    const newPackage = {
      name: path.basename(process.cwd()),
      version: '1.0.0',
      description: '',
      scripts: ESSENTIAL_SCRIPTS,
      devDependencies: {}
    };
    
    fs.writeFileSync(targetPackagePath, JSON.stringify(newPackage, null, 2));
    console.log('   ✅ Created package.json with Claude scripts');
    return { added: Object.keys(ESSENTIAL_SCRIPTS).length, skipped: 0, conflicts: [] };
  }
  
  // Read target package.json
  const targetPackage = JSON.parse(fs.readFileSync(targetPackagePath, 'utf8'));
  const backupPath = targetPackagePath + '.backup-' + new Date().toISOString().replace(/[:.]/g, '-').sl
copyScriptsDirectory function · javascript · L483-L536 (54 LOC)
scripts/setup.js
function copyScriptsDirectory(sourceDir, targetDir) {
  const scriptsNeeded = new Set();
  
  // Extract script file references from ESSENTIAL_SCRIPTS
  for (const scriptContent of Object.values(ESSENTIAL_SCRIPTS)) {
    const matches = scriptContent.match(/node scripts\/([^.\s]+\.js)/g);
    if (matches) {
      matches.forEach(match => {
        const filename = match.replace('node scripts/', '');
        scriptsNeeded.add(filename);
      });
    }
  }
  
  // Create scripts directory if it doesn't exist
  if (!options['dry-run'] && !fs.existsSync(targetDir)) {
    fs.mkdirSync(targetDir, { recursive: true });
  }
  
  let copied = 0;
  let skipped = 0;
  
  // Copy needed script files
  for (const scriptFile of scriptsNeeded) {
    const sourcePath = path.join(sourceDir, scriptFile);
    const targetPath = path.join(targetDir, scriptFile);
    
    if (fs.existsSync(sourcePath)) {
      const gitStatus = checkGitStatus(targetPath);
      const fileSize = fs.statSync(sourcePath).siz
displayDryRunResults function · javascript · L539-L616 (78 LOC)
scripts/setup.js
function displayDryRunResults() {
  console.log('\n⚠️  SAFETY WARNINGS:');
  console.log('────────────────────');
  if (dryRunData.safetyWarnings.length > 0) {
    dryRunData.safetyWarnings.forEach(warning => {
      console.log(`• ${warning}`);
    });
  } else {
    console.log('• None - repository is clean ✅');
  }
  
  console.log('\n✅ SAFE TO ADD:');
  console.log('───────────────');
  console.log(`• ${dryRunData.newFiles.length} new files in .claude/commands/`);
  console.log(`• ${dryRunData.newFiles.filter(f => f.path.includes('.claude/agents')).length} new files in .claude/agents/`);
  console.log('• Configuration files: CLAUDE.md, AGENTS.md');
  
  if (dryRunData.packageJsonChanges) {
    console.log('\n📦 PACKAGE.JSON CHANGES:');
    console.log('───────────────────────');
    const changes = dryRunData.packageJsonChanges;
    console.log(`• Would add ${changes.added} new scripts`);
    if (changes.conflicts && changes.conflicts.length > 0) {
      console.log(`• Would conflic
main function · javascript · L619-L780 (162 LOC)
scripts/setup.js
async function main() {
  // Define source and target paths
  const sourceCommands = path.join(__dirname, '../.claude/commands');
  const targetCommands = '.claude/commands';
  const sourceAgents = path.join(__dirname, '../.claude/agents');
  const targetAgents = '.claude/agents';
  
  // Check if source files exist
  if (!fs.existsSync(sourceCommands)) {
    console.log('❌ Source commands not found. Make sure you\'re running from the correct package.');
    process.exit(1);
  }
  
  // Create .claude directory if it doesn't exist
  if (!fs.existsSync('.claude')) {
    if (!options['dry-run']) {
      fs.mkdirSync('.claude', { recursive: true });
      console.log('✅ Created .claude directory');
    }
  }
  
  // Detect conflicts
  const commandConflicts = detectConflicts(sourceCommands, targetCommands);
  const agentConflicts = detectConflicts(sourceAgents, targetAgents);
  const allConflicts = [...new Set([...commandConflicts, ...agentConflicts])];
  
  // Determine strategy
  const 
detectTestFramework function · javascript · L24-L60 (37 LOC)
scripts/tdd.js
function detectTestFramework(packageJson) {
  try {
    // If packageJson provided (for testing), use it
    if (packageJson) {
      const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
      
      if (deps.jest) return 'jest';
      if (deps.vitest) return 'vitest';
      if (deps.mocha) return 'mocha';
      if (deps.jasmine) return 'jasmine';
      if (deps['@playwright/test']) return 'playwright';
      if (deps.cypress) return 'cypress';
      
      return 'unknown';
    }
    
    // Otherwise read from filesystem
    if (fs.existsSync('package.json')) {
      const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
      return detectTestFramework(pkg);
    }
    
    // Python frameworks
    if (fs.existsSync('pytest.ini') || fs.existsSync('setup.cfg')) return 'pytest';
    if (fs.existsSync('manage.py')) return 'django';
    
    // Ruby
    if (fs.existsSync('Gemfile')) {
      const gemfile = fs.readFileSync('Gemfile', 'utf8');
      if (g
getTestCommand function · javascript · L62-L82 (21 LOC)
scripts/tdd.js
function getTestCommand(framework) {
  // If no framework provided, detect it
  if (!framework) {
    framework = detectTestFramework();
  }
  
  switch (framework) {
    case 'jest':
      return 'npx jest --watch';
    case 'vitest':
      return 'npx vitest';
    case 'mocha':
      return 'npx mocha --watch';
    case 'pytest':
      return 'pytest --tb=short -v';
    case 'rspec':
      return 'rspec --format documentation';
    default:
      return 'npm test';
  }
}
startTDD function · javascript · L84-L130 (47 LOC)
scripts/tdd.js
function startTDD(featureName) {
  if (!featureName) {
    console.log('❌ Please specify a feature name');
    console.log('Usage: /tdd start <feature-name>');
    process.exit(1);
  }
  
  console.log('🚀 Starting TDD Workflow');
  console.log('========================');
  console.log('');
  console.log(`Feature: ${featureName}`);
  console.log(`Test Framework: ${detectTestFramework()}`);
  console.log('');
  
  // Create TDD tracking file
  const tddFile = `.tdd-session-${Date.now()}.md`;
  const content = `# TDD Session: ${featureName}
Date: ${new Date().toISOString()}
Framework: ${detectTestFramework()}

## Red Phase
- [ ] Write failing test
- [ ] Verify test fails for the right reason

## Green Phase
- [ ] Write minimal code to pass
- [ ] Verify test passes

## Refactor Phase
- [ ] Improve code structure
- [ ] Ensure tests still pass

## Progress Log
`;
  
  fs.writeFileSync(tddFile, content);
  
  console.log('📝 TDD Cycle:');
  console.log('');
  console.log(`  ${colors.red}1. RE
redPhase function · javascript · L132-L183 (52 LOC)
scripts/tdd.js
function redPhase() {
  console.log(`${colors.red}🔴 RED Phase - Write Failing Test${colors.reset}`);
  console.log('===================================');
  console.log('');
  console.log('Guidelines:');
  console.log('  1. Write the smallest possible failing test');
  console.log('  2. Test one behavior at a time');
  console.log('  3. Name test clearly: test_should_[expected_behavior]');
  console.log('  4. Run test to verify it fails');
  console.log('');
  console.log('Example test structure:');
  
  const framework = detectTestFramework();
  
  switch (framework) {
    case 'jest':
    case 'vitest':
      console.log(`
  describe('Feature', () => {
    it('should do expected behavior', () => {
      // Arrange
      const input = ...;
      
      // Act
      const result = functionToTest(input);
      
      // Assert
      expect(result).toBe(expected);
    });
  });`);
      break;
    case 'pytest':
      console.log(`
  def test_should_do_expected_behavior():
      # Arrang
Citation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
greenPhase function · javascript · L185-L201 (17 LOC)
scripts/tdd.js
function greenPhase() {
  console.log(`${colors.green}🟢 GREEN Phase - Make Test Pass${colors.reset}`);
  console.log('==================================');
  console.log('');
  console.log('Guidelines:');
  console.log('  1. Write MINIMAL code to pass the test');
  console.log('  2. Don\'t worry about elegance yet');
  console.log('  3. Hard-code values if needed');
  console.log('  4. Focus only on making test green');
  console.log('');
  console.log('Anti-patterns to avoid:');
  console.log('  ❌ Adding untested functionality');
  console.log('  ❌ Over-engineering the solution');
  console.log('  ❌ Refactoring before test passes');
  console.log('');
  console.log(`Run: ${colors.yellow}${getTestCommand()}${colors.reset}`);
}
refactorPhase function · javascript · L203-L221 (19 LOC)
scripts/tdd.js
function refactorPhase() {
  console.log(`${colors.blue}🔵 REFACTOR Phase - Improve Code${colors.reset}`);
  console.log('===================================');
  console.log('');
  console.log('Refactoring checklist:');
  console.log('  □ Remove duplication');
  console.log('  □ Improve naming');
  console.log('  □ Extract methods/functions');
  console.log('  □ Simplify conditionals');
  console.log('  □ Apply design patterns');
  console.log('');
  console.log('Rules:');
  console.log('  ✅ Tests must stay green');
  console.log('  ✅ Refactor production code OR tests (not both)');
  console.log('  ✅ Make small, incremental changes');
  console.log('  ✅ Run tests after each change');
  console.log('');
  console.log(`Run: ${colors.yellow}${getTestCommand()}${colors.reset}`);
}
runTests function · javascript · L223-L252 (30 LOC)
scripts/tdd.js
function runTests(watch = false) {
  console.log('🧪 Running Tests');
  console.log('================');
  console.log('');
  
  const testCmd = getTestCommand();
  console.log(`Command: ${testCmd}`);
  console.log('');
  
  try {
    if (watch) {
      // Start test watcher
      console.log('Starting test watcher... (Press Ctrl+C to stop)');
      const child = spawn(testCmd, { shell: true, stdio: 'inherit' });
      
      child.on('error', (error) => {
        console.error(`Error: ${error.message}`);
      });
    } else {
      // Run tests once
      const result = execSync(testCmd.replace('--watch', ''), { encoding: 'utf8' });
      console.log(result);
    }
  } catch {
    console.log(`${colors.red}Tests failed!${colors.reset}`);
    console.log('');
    console.log('This is expected in the RED phase.');
    console.log('Make sure tests fail for the right reason.');
  }
}
showCycle function · javascript · L254-L280 (27 LOC)
scripts/tdd.js
function showCycle() {
  console.log('🔄 TDD Cycle Overview');
  console.log('====================');
  console.log('');
  
  console.log(`${colors.red}┌─────────────┐${colors.reset}`);
  console.log(`${colors.red}│   1. RED    │${colors.reset} Write a failing test`);
  console.log(`${colors.red}└──────┬──────┘${colors.reset}`);
  console.log('       │');
  console.log(`${colors.green}┌──────▼──────┐${colors.reset}`);
  console.log(`${colors.green}│  2. GREEN   │${colors.reset} Make test pass (minimal code)`);
  console.log(`${colors.green}└──────┬──────┘${colors.reset}`);
  console.log('       │');
  console.log(`${colors.blue}┌──────▼──────┐${colors.reset}`);
  console.log(`${colors.blue}│ 3. REFACTOR │${colors.reset} Improve code (tests stay green)`);
  console.log(`${colors.blue}└──────┬──────┘${colors.reset}`);
  console.log('       │');
  console.log('       └────────┐');
  console.log('                ↓');
  console.log('         Repeat cycle');
  console.log('');
  console.log('
showStats function · javascript · L282-L317 (36 LOC)
scripts/tdd.js
function showStats() {
  console.log('📊 TDD Statistics');
  console.log('=================');
  console.log('');
  
  // Count test files
  try {
    const testFiles = execSync('find . -name "*.test.*" -o -name "*.spec.*" | grep -v node_modules | wc -l', { encoding: 'utf8' }).trim();
    console.log(`Test files: ${testFiles}`);
    
    // Check coverage if available
    if (fs.existsSync('coverage/coverage-summary.json')) {
      const coverage = JSON.parse(fs.readFileSync('coverage/coverage-summary.json', 'utf8'));
      const total = coverage.total;
      
      console.log('');
      console.log('Coverage:');
      console.log(`  • Lines: ${total.lines.pct}%`);
      console.log(`  • Branches: ${total.branches.pct}%`);
      console.log(`  • Functions: ${total.functions.pct}%`);
      console.log(`  • Statements: ${total.statements.pct}%`);
    }
    
    // Recent test commits
    const testCommits = execSync('git log --oneline --grep="test" -5 2>/dev/null', { encoding: 'utf8' });
showHelp function · javascript · L319-L339 (21 LOC)
scripts/tdd.js
function showHelp() {
  console.log('🧪 TDD (Test-Driven Development) Commands');
  console.log('=========================================');
  console.log('');
  console.log('Available commands:');
  console.log('  /tdd start <feature>  - Start TDD session for feature');
  console.log('  /tdd red              - Guidelines for RED phase');
  console.log('  /tdd green            - Guidelines for GREEN phase');
  console.log('  /tdd refactor         - Guidelines for REFACTOR phase');
  console.log('  /tdd test [--watch]   - Run tests (with optional watch)');
  console.log('  /tdd cycle            - Show TDD cycle overview');
  console.log('  /tdd stats            - Show testing statistics');
  console.log('  /tdd help             - Show this help message');
  console.log('');
  console.log('Example workflow:');
  console.log('  1. /tdd start user-auth');
  console.log('  2. /tdd red     (write failing test)');
  console.log('  3. /tdd green   (make test pass)');
  console.log('  4. /tdd r
exec function · javascript · L17-L24 (8 LOC)
scripts/todo-github.js
function exec(command) {
  try {
    return execSync(command, { encoding: 'utf8', stdio: 'pipe' }).trim();
  } catch (error) {
    console.error(`Error: ${error.message}`);
    process.exit(1);
  }
}
formatIssue function · javascript · L26-L37 (12 LOC)
scripts/todo-github.js
function formatIssue(issue) {
  const parts = issue.split('\t');
  const number = parts[0];
  const state = parts[1];
  const title = parts[2];
  const labels = parts[3] || '';
  
  const stateIcon = state === 'OPEN' ? '🔵' : '✅';
  const labelStr = labels ? ` [${labels}]` : '';
  
  return `${stateIcon} #${number}: ${title}${labelStr}`;
}
Repobility · severity-and-effort ranking · https://repobility.com
listIssues function · javascript · L39-L60 (22 LOC)
scripts/todo-github.js
function listIssues(filter = 'open') {
  console.log(`\n📋 GitHub Issues (${filter}):`);
  console.log('─'.repeat(50));
  
  const stateFlag = filter === 'all' ? '' : `--state ${filter}`;
  const command = `gh issue list ${stateFlag} --limit 30 --json number,state,title,labels,updatedAt --template '{{range .}}{{.number}}\t{{.state}}\t{{.title}}\t{{range .labels}}{{.name}} {{end}}\t{{.updatedAt}}{{println}}{{end}}'`;
  
  const output = exec(command);
  
  if (!output) {
    console.log('No issues found');
    return;
  }
  
  const issues = output.split('\n').filter(Boolean);
  issues.forEach(issue => {
    console.log(formatIssue(issue));
  });
  
  console.log('─'.repeat(50));
  console.log(`Total: ${issues.length} issues`);
}
createIssue function · javascript · L62-L73 (12 LOC)
scripts/todo-github.js
function createIssue(title, body = '', labels = []) {
  console.log(`\n➕ Creating issue: "${title}"`);
  
  const labelFlag = labels.length > 0 ? `--label "${labels.join(',')}"` : '';
  const bodyFlag = body ? `--body "${body}"` : '';
  
  const command = `gh issue create --title "${title}" ${bodyFlag} ${labelFlag}`;
  const result = exec(command);
  
  console.log(`✅ Issue created: ${result}`);
  return result;
}
closeIssue function · javascript · L75-L84 (10 LOC)
scripts/todo-github.js
function closeIssue(number, comment = '') {
  console.log(`\n✅ Closing issue #${number}`);
  
  if (comment) {
    exec(`gh issue comment ${number} --body "${comment}"`);
  }
  
  exec(`gh issue close ${number}`);
  console.log(`Issue #${number} closed`);
}
reopenIssue function · javascript · L86-L95 (10 LOC)
scripts/todo-github.js
function reopenIssue(number, comment = '') {
  console.log(`\n🔄 Reopening issue #${number}`);
  
  if (comment) {
    exec(`gh issue comment ${number} --body "${comment}"`);
  }
  
  exec(`gh issue reopen ${number}`);
  console.log(`Issue #${number} reopened`);
}
showIssue function · javascript · L103-L109 (7 LOC)
scripts/todo-github.js
function showIssue(number) {
  console.log(`\n📄 Issue #${number} Details:`);
  console.log('─'.repeat(50));
  
  const issue = exec(`gh issue view ${number}`);
  console.log(issue);
}
showStats function · javascript · L111-L132 (22 LOC)
scripts/todo-github.js
function showStats() {
  console.log('\n📊 Issue Statistics:');
  console.log('─'.repeat(50));
  
  const openCount = exec('gh issue list --state open --limit 999 --json number --jq "length"');
  const closedCount = exec('gh issue list --state closed --limit 999 --json number --jq "length"');
  
  console.log(`🔵 Open: ${openCount}`);
  console.log(`✅ Closed: ${closedCount}`);
  console.log(`📈 Total: ${parseInt(openCount) + parseInt(closedCount)}`);
  
  // Get label distribution
  console.log('\n🏷️  Label Distribution:');
  const labels = exec('gh issue list --state open --limit 999 --json labels --jq "[.[].labels[].name] | group_by(.) | map({label: .[0], count: length})"');
  
  if (labels && labels !== '[]') {
    const labelData = JSON.parse(labels);
    labelData.forEach(item => {
      console.log(`  ${item.label}: ${item.count}`);
    });
  }
}
showHelp function · javascript · L134-L162 (29 LOC)
scripts/todo-github.js
function showHelp() {
  console.log(`
📋 GitHub Issue Todo Management

Usage: node scripts/todo-github.js <command> [options]

Commands:
  list [filter]        List issues (open/closed/all, default: open)
  add <title> [body]   Create new issue
  done <number>        Close an issue
  reopen <number>      Reopen an issue
  comment <number>     Add comment to issue
  show <number>        Show issue details
  stats               Show issue statistics
  help                Show this help

Examples:
  node scripts/todo-github.js list
  node scripts/todo-github.js add "Fix login bug"
  node scripts/todo-github.js done 42
  node scripts/todo-github.js comment 42 "Working on this"

Labels:
  Priority: ${LABELS.priority.join(', ')}
  Type: ${LABELS.type.join(', ')}
  Status: ${LABELS.status.join(', ')}
  Area: ${LABELS.area.join(', ')}
`);
}
CrossLaggedResultsAnalyzer.__init__ method · python · L29-L48 (20 LOC)
src/analysis/analyze_crosslagged_results.py
    def __init__(self, results_dir: str = "output/full_comparison"):
        """Initialize analyzer with results directory.

        Args:
            results_dir: Path to directory containing cross-lagged model results.
        """
        self.results_dir = Path(results_dir)

        # Check if directory exists
        if not self.results_dir.exists():
            raise ValueError(f"Results directory not found: {self.results_dir}")

        # Load comparison tables if they exist
        self.comparison_df = None
        self.summary_df = None

        # Store loaded results
        self.fixed_results = {}
        self.estimated_results = {}
        self.cumulative_results = {}
Repobility (the analyzer behind this table) · https://repobility.com
CrossLaggedResultsAnalyzer.load_comparison_tables method · python · L50-L65 (16 LOC)
src/analysis/analyze_crosslagged_results.py
    def load_comparison_tables(self) -> None:
        """Load comparison tables from results directory."""
        raw_path = self.results_dir / "model_comparison_raw.csv"
        summary_path = self.results_dir / "analysis_summary.csv"

        if raw_path.exists():
            self.comparison_df = pd.read_csv(raw_path)
            print(f"Loaded comparison table: {len(self.comparison_df)} rows")
        else:
            print(f"Warning: Comparison table not found: {raw_path}")

        if summary_path.exists():
            self.summary_df = pd.read_csv(summary_path)
            print(f"Loaded summary table: {len(self.summary_df)} rows")
        else:
            print(f"Warning: Summary table not found: {summary_path}")
CrossLaggedResultsAnalyzer.load_individual_results method · python · L67-L89 (23 LOC)
src/analysis/analyze_crosslagged_results.py
    def load_individual_results(self) -> None:
        """Load individual model results from subdirectories."""
        print("\n" + "=" * 70)
        print("LOADING INDIVIDUAL MODEL RESULTS")
        print("=" * 70)

        # Load fixed lag results
        fixed_dir = self.results_dir / "fixed_lag"
        if fixed_dir.exists():
            print(f"\nLoading fixed lag results from: {fixed_dir}")
            self._load_fixed_results(fixed_dir)

        # Load estimated lag results
        estimated_dir = self.results_dir / "estimated_lag"
        if estimated_dir.exists():
            print(f"\nLoading estimated lag results from: {estimated_dir}")
            self._load_estimated_results(estimated_dir)

        # Load cumulative lag results
        cumulative_dir = self.results_dir / "cumulative_lag"
        if cumulative_dir.exists():
            print(f"\nLoading cumulative lag results from: {cumulative_dir}")
            self._load_cumulative_results(cumulative_dir)
CrossLaggedResultsAnalyzer._load_fixed_results method · python · L91-L114 (24 LOC)
src/analysis/analyze_crosslagged_results.py
    def _load_fixed_results(self, fixed_dir: Path) -> None:
        """Load fixed lag model results."""
        for var_dir in fixed_dir.iterdir():
            if var_dir.is_dir():
                var_name = var_dir.name
                self.fixed_results[var_name] = {}

                for lag_dir in var_dir.iterdir():
                    if lag_dir.is_dir() and "lag_" in lag_dir.name:
                        # Extract lag value from directory name
                        lag_str = lag_dir.name.replace("lag_", "").replace("days", "")
                        try:
                            lag_value = float(lag_str)
                        except ValueError:
                            continue

                        # Load posterior summary
                        summary_path = lag_dir / "posterior_summary.csv"
                        if summary_path.exists():
                            try:
                                summary_df = pd.read_csv(summary_path)
                  
‹ prevpage 2 / 6next ›