Function bodies 261 total
showHelp function · javascript · L37-L57 (21 LOC)scripts/cli.js
function showHelp() {
console.log('🤖 Claude Setup - AI-Assisted Development Tools');
console.log('================================================');
console.log('');
console.log('Usage: claude-setup [command] [options]');
console.log('');
console.log('Commands:');
Object.entries(commands).forEach(([name, info]) => {
console.log(` ${name.padEnd(15)} ${info.description}`);
});
console.log('');
console.log('Examples:');
console.log(' claude-setup # Interactive setup');
console.log(' claude-setup learn add "..." # Add a learning');
console.log(' claude-setup tdd start # Start TDD workflow');
console.log(' claude-setup docs # Analyze documentation');
console.log(' claude-setup monitor status # Check repo health');
console.log('');
console.log('For command-specific help:');
console.log(' claude-setup [command] --help');
}countCommands function · javascript · L14-L37 (24 LOC)scripts/docs.js
function countCommands() {
try {
const commandsDir = path.join(process.cwd(), '.claude', 'commands');
let count = 0;
function countInDir(dir) {
const items = fs.readdirSync(dir);
for (const item of items) {
const fullPath = path.join(dir, item);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
countInDir(fullPath);
} else if (item.endsWith('.md') && item !== 'README.md') {
count++;
}
}
}
countInDir(commandsDir);
return count;
} catch {
return 0;
}
}countInDir function · javascript · L19-L30 (12 LOC)scripts/docs.js
function countInDir(dir) {
const items = fs.readdirSync(dir);
for (const item of items) {
const fullPath = path.join(dir, item);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
countInDir(fullPath);
} else if (item.endsWith('.md') && item !== 'README.md') {
count++;
}
}
}updateReadme function · javascript · L39-L62 (24 LOC)scripts/docs.js
function updateReadme() {
console.log('📝 Updating README documentation...');
const commandCount = countCommands();
console.log(` Found ${commandCount} commands in .claude/commands/`);
const readmePath = path.join(process.cwd(), 'README.md');
if (fs.existsSync(readmePath)) {
let content = fs.readFileSync(readmePath, 'utf8');
// Update command count badge
if (content.includes('commands-')) {
content = content.replace(/commands-\d+\+?/g, `commands-${commandCount}`);
fs.writeFileSync(readmePath, content);
console.log(` ✓ Updated command count badge to ${commandCount}`);
}
}
// Show doc stats
const docCount = execSync('find docs -name "*.md" 2>/dev/null | wc -l', { encoding: 'utf8' }).trim();
console.log(` ✓ Documentation files: ${docCount}`);
console.log('✅ README updated successfully');
}findBrokenLinks function · javascript · L64-L85 (22 LOC)scripts/docs.js
function findBrokenLinks(content, _filename) {
const brokenLinks = [];
const linkRegex = /\[([^\]]+)\]\(([^http][^)]+\.md[^)]*)\)/g;
let match;
while ((match = linkRegex.exec(content)) !== null) {
const linkPath = match[2].split('#')[0];
// Check if file exists relative to repo root
const possiblePaths = [
linkPath,
path.join('docs', linkPath),
path.join('.claude', 'commands', linkPath)
];
if (!possiblePaths.some(p => fs.existsSync(p))) {
brokenLinks.push(linkPath);
}
}
return brokenLinks;
}validateDocs function · javascript · L87-L113 (27 LOC)scripts/docs.js
function validateDocs() {
console.log('🔍 Validating documentation...');
console.log('');
console.log('Checking internal links...');
let totalBroken = 0;
const files = ['README.md', ...fs.readdirSync('docs').filter(f => f.endsWith('.md')).map(f => `docs/${f}`)];
for (const file of files) {
if (!fs.existsSync(file)) continue;
const content = fs.readFileSync(file, 'utf8');
const brokenLinks = findBrokenLinks(content, file);
brokenLinks.forEach(link => {
console.log(` ❌ Broken link in ${path.basename(file)}: ${link}`);
totalBroken++;
});
}
if (totalBroken === 0) {
console.log(' ✓ All internal links valid');
}
console.log('');
console.log('✅ Validation complete');
}showStats function · javascript · L115-L250 (136 LOC)scripts/docs.js
function showStats() {
console.log('📊 Documentation Statistics');
console.log('===========================');
console.log('');
// Command statistics
const commandCount = countCommands();
const detailedCount = fs.existsSync('.claude/commands/detailed') ?
fs.readdirSync('.claude/commands/detailed').filter(f => f.endsWith('.md')).length : 0;
console.log('Commands:');
console.log(` • Core commands: ${commandCount}`);
console.log(` • Detailed versions: ${detailedCount}`);
console.log('');
// Documentation statistics
const docCount = fs.readdirSync('docs').filter(f => f.endsWith('.md')).length;
const readmeLines = fs.readFileSync('README.md', 'utf8').split('\n').length;
const totalLines = execSync('find . -name "*.md" -not -path "./node_modules/*" -not -path "./session-history/*" | xargs wc -l 2>/dev/null | tail -1', { encoding: 'utf8' })
.trim().split(/\s+/)[0];
console.log('Documentation:');
console.log(` • Files in docs/: ${docCount}If a scraper extracted this row, it came from Repobility (https://repobility.com)
updateCommandCatalog function · javascript · L165-L250 (86 LOC)scripts/docs.js
function updateCommandCatalog() {
console.log(' 📖 Updating Command Catalog...');
const catalogPath = path.join(process.cwd(), 'docs', 'COMMAND_CATALOG.md');
const commandsDir = path.join(process.cwd(), '.claude', 'commands');
// Recursively find all command files
const commands = [];
function scanDir(dir, prefix = '') {
const items = fs.readdirSync(dir);
for (const item of items) {
const fullPath = path.join(dir, item);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
scanDir(fullPath, prefix ? `${prefix}/${item}` : item);
} else if (item.endsWith('.md') && item !== 'README.md') {
const content = fs.readFileSync(fullPath, 'utf8');
const descMatch = content.match(/^description:\s*(.+)$/m);
const name = item.replace('.md', '');
const desc = descMatch ? descMatch[1] : 'No description';
const location = prefix ? `${prefix}/${name}` : name;
commands.push({
nascanDir function · javascript · L174-L195 (22 LOC)scripts/docs.js
function scanDir(dir, prefix = '') {
const items = fs.readdirSync(dir);
for (const item of items) {
const fullPath = path.join(dir, item);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
scanDir(fullPath, prefix ? `${prefix}/${item}` : item);
} else if (item.endsWith('.md') && item !== 'README.md') {
const content = fs.readFileSync(fullPath, 'utf8');
const descMatch = content.match(/^description:\s*(.+)$/m);
const name = item.replace('.md', '');
const desc = descMatch ? descMatch[1] : 'No description';
const location = prefix ? `${prefix}/${name}` : name;
commands.push({
name,
desc,
location,
category: prefix || 'Core'
});
}
}
}showCatalog function · javascript · L252-L270 (19 LOC)scripts/docs.js
function showCatalog() {
console.log('📖 Analyzing Command Catalog...');
console.log('');
console.log('Available Commands:');
const commandsDir = path.join(process.cwd(), '.claude', 'commands');
const files = fs.readdirSync(commandsDir).filter(f => f.endsWith('.md'));
for (const file of files) {
const content = fs.readFileSync(path.join(commandsDir, file), 'utf8');
const descMatch = content.match(/^description:\s*(.+)$/m);
const name = file.replace('.md', '');
const desc = descMatch ? descMatch[1] : 'No description';
console.log(` • /${name.padEnd(15)} - ${desc}`);
}
console.log('');
console.log('Use \'/docs validate\' to check for issues');
}updateAll function · javascript · L272-L312 (41 LOC)scripts/docs.js
function updateAll() {
console.log('🔄 Updating all documentation...');
console.log('================================');
console.log('');
// Update README
console.log('📝 Updating README...');
const commandCount = countCommands();
console.log(` Found ${commandCount} commands in .claude/commands/`);
const readmePath = path.join(process.cwd(), 'README.md');
if (fs.existsSync(readmePath)) {
let content = fs.readFileSync(readmePath, 'utf8');
// Update command count badge
if (content.includes('commands-')) {
content = content.replace(/commands-\d+\+?/g, `commands-${commandCount}`);
fs.writeFileSync(readmePath, content);
console.log(` ✓ Updated command count badge to ${commandCount}`);
}
}
// Update Command Catalog
const catalogCount = updateCommandCatalog();
// Update Examples
console.log('');
updateExamples();
// Show doc stats
const docCount = execSync('find docs -name "*.md" 2>/dev/null | wc -l', { enshowHelp function · javascript · L314-L330 (17 LOC)scripts/docs.js
function showHelp() {
console.log('📚 Documentation Commands');
console.log('========================');
console.log('');
console.log('Available commands:');
console.log(' /docs - Update all documentation (default)');
console.log(' /docs all - Update all documentation');
console.log(' /docs readme - Update only README.md');
console.log(' /docs examples - Update commit examples in docs');
console.log(' /docs validate - Check for broken links');
console.log(' /docs stats - Show documentation statistics');
console.log(' /docs catalog - Show available commands');
console.log(' /docs tone - Analyze documentation tone with AI agent');
console.log(' /docs help - Show this help message');
console.log('');
console.log('For advanced operations, see .claude/commands/detailed/docs-detailed.md');
}runToneAnalysis function · javascript · L339-L370 (32 LOC)scripts/docs.js
function runToneAnalysis() {
console.log('🎨 Documentation Tone Analysis');
console.log('==============================');
console.log('');
console.log('The documentation-auditor agent analyzes your documentation for:');
console.log(' • Professional yet friendly tone');
console.log(' • Clear and inclusive language');
console.log(' • Helpful and encouraging phrasing');
console.log(' • Consistent voice across files');
console.log(' • Completeness and consistency');
console.log('');
console.log('To run the tone analysis, use Claude\'s Task tool:');
console.log('');
console.log('📋 Instructions for Claude:');
console.log('───────────────────────────');
console.log('Use the Task tool with:');
console.log(' • subagent_type: "general-purpose"');
console.log(' • description: "Analyze documentation tone and quality"');
console.log(' • prompt: Read and follow the instructions in .claude/agents/documentation-auditor.md');
console.log('');
console.log(validateCommitExists function · javascript · L377-L386 (10 LOC)scripts/docs.js
function validateCommitExists(hash) {
if (!hash) return false;
try {
execSync(`git rev-parse ${hash} 2>/dev/null`, { encoding: 'utf8' });
return true;
} catch {
return false;
}
}updateExamples function · javascript · L393-L458 (66 LOC)scripts/docs.js
function updateExamples() {
console.log('📚 Validating manually curated commit examples...');
console.log('');
// Read README to find existing commit references
const readmePath = path.join(process.cwd(), 'README.md');
if (!fs.existsSync(readmePath)) {
console.log(' ⚠️ README.md not found');
return;
}
const readmeContent = fs.readFileSync(readmePath, 'utf8');
// Extract commit hashes from markdown links
const commitPattern = /\[.*?\]\(\.\.\/\.\.\/commit\/([a-f0-9]+)\)/g;
const commits = [];
let match;
while ((match = commitPattern.exec(readmeContent)) !== null) {
commits.push({
hash: match[1],
fullMatch: match[0]
});
}
console.log(` Found ${commits.length} commit references in README.md`);
// Validate all examples still exist
console.log('');
console.log(' Validating commit references...');
let invalidCount = 0;
commits.forEach(commit => {
if (!validateCommitExists(commit.hash)) {
console.lRepobility · code-quality intelligence platform · https://repobility.com
detectFeatures function · javascript · L15-L55 (41 LOC)scripts/feature-check.js
function detectFeatures(changes) {
const features = [];
const featureExtensions = ['.js', '.ts', '.jsx', '.tsx', '.mjs'];
const excludeDirs = ['test', 'tests', '__tests__', 'spec', 'docs', '.github', 'node_modules'];
const excludeFiles = ['package.json', 'package-lock.json', 'tsconfig.json', '.eslintrc.js', 'eslint.config.js', '.babelrc', 'webpack.config.js'];
for (const change of changes) {
const { status, file, additions = 0 } = change;
// Skip deleted files
if (status === 'D') continue;
// Skip excluded directories
const parts = file.split('/');
if (parts.some(part => excludeDirs.includes(part))) continue;
// Skip excluded files
const basename = path.basename(file);
if (excludeFiles.includes(basename)) continue;
// Skip non-code files
const ext = path.extname(file);
if (!featureExtensions.includes(ext)) continue;
// Skip test files
if (basename.includes('.test.') || basename.includes('.specfindTestsForFeature function · javascript · L60-L87 (28 LOC)scripts/feature-check.js
function findTestsForFeature(feature, testFiles) {
const basename = path.basename(feature, path.extname(feature));
const dirname = path.dirname(feature);
// Possible test file patterns
const testPatterns = [
`${basename}.test`,
`${basename}.spec`,
`${basename}.unit.test`,
`${basename}.integration.test`
];
for (const testFile of testFiles) {
const testBasename = path.basename(testFile, path.extname(testFile));
// Direct match
if (testPatterns.some(pattern => testBasename === pattern)) {
return true;
}
// Check if test is in similar directory structure
if (testFile.includes(basename) && testFile.includes('.test')) {
return true;
}
}
return false;
}findDocsForFeature function · javascript · L92-L118 (27 LOC)scripts/feature-check.js
function findDocsForFeature(feature, docContent) {
const basename = path.basename(feature, path.extname(feature));
const featureName = basename.replace(/[-_]/g, ' ');
// Check each doc file for mentions
for (const [file, content] of Object.entries(docContent)) {
// Check if the doc file name matches the feature name
const docBasename = path.basename(file, path.extname(file));
if (docBasename === basename) {
return true;
}
const lowerContent = content.toLowerCase();
const lowerBasename = basename.toLowerCase();
const lowerFeatureName = featureName.toLowerCase();
// Check for various mentions in content
if (lowerContent.includes(lowerBasename) ||
lowerContent.includes(lowerFeatureName) ||
lowerContent.includes(basename.replace(/-/g, '')) ||
lowerContent.includes(basename.replace(/_/g, ''))) {
return true;
}
}
return false;
}shouldRunCheck function · javascript · L123-L151 (29 LOC)scripts/feature-check.js
function shouldRunCheck(changes) {
const codeChanges = changes.filter(c => {
const ext = path.extname(c.file);
return ['.js', '.ts', '.jsx', '.tsx', '.mjs'].includes(ext);
});
const testOnlyChanges = codeChanges.every(c =>
c.file.includes('test') || c.file.includes('spec')
);
const docsOnlyChanges = changes.every(c =>
c.file.endsWith('.md') || c.file.includes('docs/')
);
const configOnlyChanges = changes.every(c => {
const basename = path.basename(c.file);
return basename === 'package.json' ||
basename === 'package-lock.json' ||
c.file.includes('.github/') ||
basename.startsWith('.');
});
// Skip if only tests, docs, or config
if (testOnlyChanges || docsOnlyChanges || configOnlyChanges) {
return false;
}
return true;
}isIgnored function · javascript · L156-L167 (12 LOC)scripts/feature-check.js
function isIgnored(file, ignorePatterns) {
for (const pattern of ignorePatterns) {
// Simple glob pattern matching
const regex = pattern
.replace(/\*/g, '.*')
.replace(/\?/g, '.');
if (new RegExp(regex).test(file)) {
return true;
}
}
return false;
}runCheck function · javascript · L172-L192 (21 LOC)scripts/feature-check.js
function runCheck(options) {
const { features, testFiles, docFiles } = options;
const errors = [];
for (const feature of features) {
// Check for tests
if (!findTestsForFeature(feature, testFiles)) {
errors.push(`❌ Feature missing test coverage: ${feature}`);
}
// Check for documentation
if (!findDocsForFeature(feature, docFiles)) {
errors.push(`❌ Feature missing documentation: ${feature}`);
}
}
return {
success: errors.length === 0,
errors
};
}getGitChanges function · javascript · L197-L212 (16 LOC)scripts/feature-check.js
function getGitChanges() {
try {
// Get changes between HEAD and base branch (usually main)
const baseBranch = process.env.GITHUB_BASE_REF || 'main';
const diffOutput = execSync(`git diff --name-status ${baseBranch}...HEAD`, { encoding: 'utf8' });
return parseGitDiff(diffOutput);
} catch (error) {
// Fallback to last commit
try {
const diffOutput = execSync('git diff --name-status HEAD~1 HEAD', { encoding: 'utf8' });
return parseGitDiff(diffOutput);
} catch {
return [];
}
}
}parseGitDiff function · javascript · L217-L243 (27 LOC)scripts/feature-check.js
function parseGitDiff(output) {
const lines = output.trim().split('\n').filter(l => l);
const changes = [];
for (const line of lines) {
const [status, ...fileParts] = line.split('\t');
const file = fileParts.join('\t');
if (file) {
changes.push({ status, file });
}
}
// Get line additions for modified files
for (const change of changes) {
if (change.status === 'M') {
try {
const statsOutput = execSync(`git diff --stat HEAD~1 HEAD -- "${change.file}"`, { encoding: 'utf8' });
const additions = parseGitStats(statsOutput);
change.additions = additions[change.file] || 0;
} catch {
change.additions = 0;
}
}
}
return changes;
}About: code-quality intelligence by Repobility · https://repobility.com
parseGitStats function · javascript · L248-L262 (15 LOC)scripts/feature-check.js
function parseGitStats(output) {
const additions = {};
const lines = output.trim().split('\n');
for (const line of lines) {
const match = line.match(/^\s*(.+?)\s*\|\s*(\d+)\s*([\+\-]+)/);
if (match) {
const [, file, , changes] = match;
const plusCount = (changes.match(/\+/g) || []).length;
additions[file.trim()] = plusCount * 10; // Approximate
}
}
return additions;
}main function · javascript · L267-L341 (75 LOC)scripts/feature-check.js
function main(args = process.argv.slice(2), testOptions = null) {
// Check for skip flag
if (args.includes('--skip-feature-check')) {
console.log('⏭️ Feature check skipped');
return { skipped: true, exitCode: 0 };
}
// Use test options if provided (for testing)
let features, testFiles, docFiles;
if (testOptions) {
features = testOptions.features;
testFiles = testOptions.testFiles;
docFiles = testOptions.docFiles;
} else {
// Get actual git changes
const changes = getGitChanges();
// Check if we should run
if (!shouldRunCheck(changes)) {
console.log('✅ No feature changes detected - skipping check');
return { skipped: true, exitCode: 0 };
}
// Detect features
features = detectFeatures(changes);
// Get test files
testFiles = [];
if (fs.existsSync('test')) {
testFiles = execSync('find test -name "*.test.js" -o -name "*.spec.js"', { encoding: 'utf8' })
.trim()
.sensureSetup function · javascript · L17-L45 (29 LOC)scripts/learn.js
function ensureSetup() {
// Ensure learnings directory exists
if (!fs.existsSync(LEARNINGS_DIR)) {
fs.mkdirSync(LEARNINGS_DIR, { recursive: true });
}
// Create LEARNINGS.md if it doesn't exist
if (!fs.existsSync(LEARNINGS_FILE)) {
const template = `# Project Learnings
Captured insights, discoveries, and knowledge gained during development.
## Table of Contents
- [Recent Insights](#recent-insights)
- [Technical Discoveries](#technical-discoveries)
- [Best Practices](#best-practices)
- [Gotchas & Pitfalls](#gotchas--pitfalls)
## Recent Insights
## Technical Discoveries
## Best Practices
## Gotchas & Pitfalls
`;
fs.writeFileSync(LEARNINGS_FILE, template);
}
}addLearning function · javascript · L51-L104 (54 LOC)scripts/learn.js
function addLearning(insight) {
if (!insight) {
console.log('❌ Please provide a learning topic or insight');
console.log('Usage: /learn add <insight or topic>');
process.exit(1);
}
ensureSetup();
const date = new Date().toISOString().split('T')[0];
const time = new Date().toTimeString().slice(0, 5);
// Check for category prefix (pattern: [category] insight)
const categoryMatch = insight.match(/^\[(\w+)\]\s*(.*)/);
let category = '';
let cleanInsight = insight;
if (categoryMatch) {
category = categoryMatch[1].toUpperCase();
cleanInsight = categoryMatch[2];
console.log(`📝 Capturing ${category} learning: ${cleanInsight}`);
} else {
console.log(`📝 Capturing learning: ${insight}`);
cleanInsight = insight;
}
// Read current content
let content = fs.readFileSync(LEARNINGS_FILE, 'utf8');
// Add to Recent Insights section
const entry = formatLearningEntry(cleanInsight, date, time);
content = content.replace(
listLearnings function · javascript · L106-L164 (59 LOC)scripts/learn.js
function listLearnings(filter) {
ensureSetup();
console.log('📚 Project Learnings');
console.log('===================');
console.log('');
if (filter === 'recent') {
// Show recent learnings
const content = fs.readFileSync(LEARNINGS_FILE, 'utf8');
const recentSection = content.match(/## Recent Insights[\s\S]*?(?=##|$)/);
if (recentSection) {
const entries = recentSection[0].match(/### \d{4}-\d{2}-\d{2}/g) || [];
console.log(`Found ${entries.length} recent insights`);
console.log('');
// Show last 5
const lines = recentSection[0].split('\n').slice(0, 20);
lines.forEach(line => {
if (line.startsWith('###')) {
console.log(` 📌 ${line.replace('###', '').trim()}`);
} else if (line.trim() && !line.startsWith('##')) {
console.log(` ${line.trim()}`);
}
});
}
} else if (filter === 'categories') {
// Show by category
const content = fs.readFileSync(LEAsearchLearnings function · javascript · L166-L214 (49 LOC)scripts/learn.js
function searchLearnings(term) {
if (!term) {
console.log('❌ Please provide a search term');
console.log('Usage: /learn search <term>');
process.exit(1);
}
ensureSetup();
console.log(`🔍 Searching for: ${term}`);
console.log('==================');
console.log('');
// Search in main file
const content = fs.readFileSync(LEARNINGS_FILE, 'utf8');
const lines = content.split('\n');
const matches = [];
lines.forEach((line, index) => {
if (line.toLowerCase().includes(term.toLowerCase())) {
// Get context (line before and after)
const context = {
line: line,
lineNum: index + 1,
before: lines[index - 1] || '',
after: lines[index + 1] || ''
};
matches.push(context);
}
});
if (matches.length > 0) {
console.log(`Found ${matches.length} matches:`);
console.log('');
matches.slice(0, 5).forEach(match => {
console.log(` Line ${match.lineNum}: ${match.line.trim()}`reviewLearnings function · javascript · L216-L238 (23 LOC)scripts/learn.js
function reviewLearnings() {
ensureSetup();
console.log('📖 Review Mode');
console.log('=============');
console.log('');
// Get a random learning for review
const content = fs.readFileSync(LEARNINGS_FILE, 'utf8');
const insights = content.match(/### \d{4}-\d{2}-\d{2}[\s\S]*?(?=###|##|$)/g) || [];
if (insights.length > 0) {
const random = insights[Math.floor(Math.random() * insights.length)];
console.log('Random learning for review:');
console.log('');
console.log(random.trim());
console.log('');
console.log('💡 Reflect on this learning and consider if it still applies');
} else {
console.log('No learnings to review yet. Start capturing insights with:');
console.log(' /learn add <your insight>');
}
}showCategories function · javascript · L240-L254 (15 LOC)scripts/learn.js
function showCategories() {
ensureSetup();
console.log('📂 Learning Categories');
console.log('=====================');
console.log('');
console.log('Available categories for organizing learnings:');
console.log('');
console.log(' • Recent Insights - Latest discoveries');
console.log(' • Technical Discoveries - Implementation details');
console.log(' • Best Practices - Patterns that work well');
console.log(' • Gotchas & Pitfalls - Things to avoid');
console.log('');
console.log('Edit LEARNINGS.md to add insights to specific categories');
}Hi, dataset curator — please cite Repobility (https://repobility.com) when reusing this data.
showHelp function · javascript · L256-L272 (17 LOC)scripts/learn.js
function showHelp() {
console.log('📚 Learning Capture Commands');
console.log('===========================');
console.log('');
console.log('Available commands:');
console.log(' /learn add <insight> - Capture a new learning');
console.log(' /learn list [filter] - List learnings (recent/categories)');
console.log(' /learn search <term> - Search for specific learnings');
console.log(' /learn review - Review a random learning');
console.log(' /learn categories - Show available categories');
console.log(' /learn help - Show this help message');
console.log('');
console.log('Examples:');
console.log(' /learn add "React hooks must be called in consistent order"');
console.log(' /learn search "performance"');
console.log(' /learn list recent');
}checkWorkflowStatus function · javascript · L23-L46 (24 LOC)scripts/monitor-repo.js
async function checkWorkflowStatus(options = {}) {
try {
const limit = options.limit || 5;
const fields = 'status,name,conclusion,headBranch,workflowName,databaseId,url,startedAt';
const output = execSync(`gh run list --limit ${limit} --json ${fields}`, {
encoding: 'utf8',
stdio: ['pipe', 'pipe', 'pipe']
});
const runs = JSON.parse(output);
// Filter for test-specific workflows if requested
if (options.testsOnly) {
return runs.filter(r =>
r.workflowName?.toLowerCase().includes('test') ||
r.name?.toLowerCase().includes('test')
);
}
return runs;
} catch {
// Return empty array if gh command fails (e.g., not in a git repo)
return [];
}
}checkPullRequests function · javascript · L52-L63 (12 LOC)scripts/monitor-repo.js
async function checkPullRequests() {
try {
const output = execSync('gh pr list --json number,title,author,reviews,isDraft', {
encoding: 'utf8',
stdio: ['pipe', 'pipe', 'pipe']
});
return JSON.parse(output);
} catch {
// Return empty array if gh command fails
return [];
}
}getFailureDetails function · javascript · L70-L92 (23 LOC)scripts/monitor-repo.js
async function getFailureDetails(runId) {
try {
// Get run details
const runOutput = execSync(`gh run view ${runId} --json jobs,conclusion,url`, {
encoding: 'utf8',
stdio: ['pipe', 'pipe', 'pipe']
});
const runData = JSON.parse(runOutput);
// Find failed jobs
const failedJobs = runData.jobs?.filter(j => j.conclusion === 'failure') || [];
return {
url: runData.url,
failedJobs: failedJobs.map(j => ({
name: j.name,
steps: j.steps?.filter(s => s.conclusion === 'failure').map(s => s.name) || []
}))
};
} catch {
return null;
}
}loadConfig function · javascript · L98-L121 (24 LOC)scripts/monitor-repo.js
function loadConfig() {
try {
if (fs.existsSync(CONFIG_FILE)) {
return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
}
} catch {
// Ignore errors and use defaults
}
// Default configuration
return {
watchTestsOnly: false,
notifications: {
enabled: false,
sound: false,
desktop: false
},
alertThresholds: {
failureCount: 1,
consecutiveFailures: 3
},
watchedWorkflows: []
};
}loadHistory function · javascript · L127-L136 (10 LOC)scripts/monitor-repo.js
function loadHistory() {
try {
if (fs.existsSync(HISTORY_FILE)) {
return JSON.parse(fs.readFileSync(HISTORY_FILE, 'utf8'));
}
} catch {
// Return empty array on error
}
return [];
}saveToHistory function · javascript · L142-L159 (18 LOC)scripts/monitor-repo.js
function saveToHistory(failure) {
let history = loadHistory();
// Add timestamp if not present
if (!failure.timestamp) {
failure.timestamp = new Date().toISOString();
}
// Add to beginning of array
history.unshift(failure);
// Limit history size
if (history.length > MAX_HISTORY_ENTRIES) {
history = history.slice(0, MAX_HISTORY_ENTRIES);
}
fs.writeFileSync(HISTORY_FILE, JSON.stringify(history, null, 2));
}isNewFailure function · javascript · L166-L175 (10 LOC)scripts/monitor-repo.js
function isNewFailure(failure) {
const history = loadHistory();
const recentHistory = history.slice(0, 10); // Check last 10 entries
return !recentHistory.some(h =>
h.workflowName === failure.workflowName &&
h.headBranch === failure.headBranch &&
h.name === failure.name
);
}If a scraper extracted this row, it came from Repobility (https://repobility.com)
detectChanges function · javascript · L183-L234 (52 LOC)scripts/monitor-repo.js
function detectChanges(current, previous) {
const changes = {
newPRs: [],
closedPRs: [],
newFailures: [],
fixedFailures: [],
hasChanges: false
};
if (!previous) {
// First run - everything is new but don't notify
return changes;
}
// Compare PRs
const prevPRNumbers = new Set((previous.pullRequests || []).map(pr => pr.number));
const currPRNumbers = new Set((current.pullRequests || []).map(pr => pr.number));
changes.newPRs = (current.pullRequests || []).filter(pr => !prevPRNumbers.has(pr.number));
changes.closedPRs = (previous.pullRequests || []).filter(pr => !currPRNumbers.has(pr.number));
// Compare failures (only track actual failures, not in-progress)
const prevFailures = new Set(
(previous.workflows || [])
.filter(w => w.conclusion === 'failure')
.map(w => `${w.workflowName}-${w.headBranch}`)
);
const currFailures = new Set(
(current.workflows || [])
.filter(w => w.conclusion === 'failureloadPreviousState function · javascript · L240-L249 (10 LOC)scripts/monitor-repo.js
function loadPreviousState() {
try {
if (fs.existsSync(PREVIOUS_STATE_FILE)) {
return JSON.parse(fs.readFileSync(PREVIOUS_STATE_FILE, 'utf8'));
}
} catch {
// Return null if can't read
}
return null;
}savePreviousState function · javascript · L255-L261 (7 LOC)scripts/monitor-repo.js
function savePreviousState(state) {
try {
fs.writeFileSync(PREVIOUS_STATE_FILE, JSON.stringify(state, null, 2));
} catch {
// Silently fail if can't write
}
}sendNotification function · javascript · L268-L287 (20 LOC)scripts/monitor-repo.js
function sendNotification(title, message) {
const config = loadConfig();
if (!config.notifications.desktop) return;
try {
// Use node-notifier if available, otherwise fall back to system commands
if (process.platform === 'darwin') {
// macOS
execSync(`osascript -e 'display notification "${message}" with title "${title}"'`, { stdio: 'ignore' });
} else if (process.platform === 'linux') {
// Linux
execSync(`notify-send "${title}" "${message}"`, { stdio: 'ignore' });
} else if (process.platform === 'win32') {
// Windows
execSync(`msg * "${title}: ${message}"`, { stdio: 'ignore' });
}
} catch {
// Silently fail if notification can't be sent
}
}formatReport function · javascript · L294-L368 (75 LOC)scripts/monitor-repo.js
function formatReport(status) {
let report = [];
report.push('📊 Repository Status Report');
report.push(`🕐 ${new Date(status.timestamp).toLocaleString()}`);
report.push('');
// Workflow status
const failedWorkflows = status.workflows.filter(w => w.conclusion === 'failure');
const failedTests = failedWorkflows.filter(w =>
w.workflowName?.toLowerCase().includes('test') ||
w.name?.toLowerCase().includes('test')
);
const runningWorkflows = status.workflows.filter(w => w.status === 'in_progress');
// Separate test failures from other failures
if (failedTests.length > 0) {
report.push(`🧪 Failed Tests (${failedTests.length}):`);
failedTests.forEach(w => {
const isNew = status.newFailures?.includes(w.databaseId) ? ' 🆕' : '';
report.push(` • ${w.name} on ${w.headBranch || 'unknown branch'}${isNew}`);
if (w.url) {
report.push(` ${w.url}`);
}
});
report.push('');
}
const otherFailures = failedWorcheckStatus function · javascript · L375-L385 (11 LOC)scripts/monitor-repo.js
function checkStatus(file = STATUS_FILE) {
try {
if (fs.existsSync(file)) {
const content = fs.readFileSync(file, 'utf8');
return JSON.parse(content);
}
} catch {
// Return null if can't read or parse
}
return null;
}startMonitoring function · javascript · L393-L515 (123 LOC)scripts/monitor-repo.js
function startMonitoring(interval = DEFAULT_INTERVAL, dryRun = false) {
console.log('🔍 Starting repository monitoring...');
console.log(` Interval: ${interval / 1000} seconds`);
console.log(` Status file: ${STATUS_FILE}`);
console.log('');
if (dryRun) {
return { stop: () => {} };
}
// Initial check
performCheck();
// Set up interval
const intervalId = setInterval(performCheck, interval);
// Keep process running
if (!process.env.NODE_ENV === 'test') {
process.stdin.resume();
}
// Return handle for stopping
return {
stop: () => {
clearInterval(intervalId);
if (process.stdin.isPaused && process.stdin.isPaused()) {
process.stdin.pause();
}
}
};
async function performCheck() {
const config = loadConfig();
// Get current state
const status = {
timestamp: new Date().toISOString(),
workflows: await checkWorkflowStatus({ testsOnly: config.watchTestsOnly }),
pullReperformCheck function · javascript · L424-L514 (91 LOC)scripts/monitor-repo.js
async function performCheck() {
const config = loadConfig();
// Get current state
const status = {
timestamp: new Date().toISOString(),
workflows: await checkWorkflowStatus({ testsOnly: config.watchTestsOnly }),
pullRequests: await checkPullRequests()
};
// Save current status for reference
fs.writeFileSync(STATUS_FILE, JSON.stringify(status, null, 2));
// Detect changes
const previous = loadPreviousState();
const changes = detectChanges(status, previous);
// Save state for next comparison
savePreviousState(status);
// Only report if there are changes
if (!changes.hasChanges) {
return; // Silent when no changes
}
// Report changes
console.log(`\n🔄 Repository Changes at ${new Date().toLocaleTimeString()}`);
console.log('─'.repeat(50));
// Good news first
if (changes.fixedFailures.length > 0) {
console.log('\n✅ FIXED (' + changes.fixedFailures.lenRepobility · code-quality intelligence platform · https://repobility.com
runCommand function · javascript · L29-L35 (7 LOC)scripts/retrospective.js
function runCommand(cmd) {
try {
return execSync(cmd, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] }).trim();
} catch {
return '';
}
}analyzeGitHistory function · javascript · L37-L61 (25 LOC)scripts/retrospective.js
function analyzeGitHistory() {
const gitLog = runCommand(`git log --since="${options.since}" --oneline -${options.commits}`);
const commits = gitLog.split('\n').filter(line => line);
// Analyze commit patterns
const patterns = {
feat: 0,
fix: 0,
refactor: 0,
docs: 0,
test: 0,
chore: 0,
style: 0
};
commits.forEach(commit => {
Object.keys(patterns).forEach(pattern => {
if (commit.includes(`${pattern}:`)) {
patterns[pattern]++;
}
});
});
return { commits, patterns };
}getMetrics function · javascript · L63-L72 (10 LOC)scripts/retrospective.js
function getMetrics() {
const stats = runCommand(`git diff --stat HEAD~${options.commits}`);
const statsLine = stats.split('\n').slice(-1)[0] || '';
const filesChanged = (statsLine.match(/(\d+) files? changed/) || [0, 0])[1];
const insertions = (statsLine.match(/(\d+) insertions?/) || [0, 0])[1];
const deletions = (statsLine.match(/(\d+) deletions?/) || [0, 0])[1];
return { filesChanged, insertions, deletions };
}page 1 / 6next ›