Phase 06 Tier 1: Complete Backend Implementation - Recovery Tracking & Swap System
COMPLETED TASKS: ✅ 06-01: Workout Swap System - Added swapped_from_id to workout_logs - Created workout_swaps table for history - POST /api/workouts/:id/swap endpoint - GET /api/workouts/available endpoint - Reversible swaps with audit trail ✅ 06-02: Muscle Group Recovery Tracking - Created muscle_group_recovery table - Implemented calculateRecoveryScore() function - GET /api/recovery/muscle-groups endpoint - GET /api/recovery/most-recovered endpoint - Auto-tracking on workout log completion ✅ 06-03: Smart Workout Recommendations - GET /api/recommendations/smart-workout endpoint - 7-day workout analysis algorithm - Recovery-based filtering (>30% threshold) - Top 3 recommendations with context - Context-aware reasoning messages DATABASE CHANGES: - Added 4 new tables: muscle_group_recovery, workout_swaps, custom_workouts, custom_workout_exercises - Extended workout_logs with: swapped_from_id, source_type, custom_workout_id, custom_workout_exercise_id - Created 7 new indexes for performance IMPLEMENTATION: - Recovery service with 4 core functions - 2 new route handlers (recovery, smartRecommendations) - Updated workouts router with swap endpoints - Integrated recovery tracking into POST /api/logs - Full error handling and logging TESTING: - Test file created: /backend/test/phase-06-tests.js - Ready for E2E and staging validation STATUS: Ready for frontend integration and production review Branch: feature/06-phase-06
This commit is contained in:
Executable
+106
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Safe GitHub CLI Helper
|
||||
* Prevents timeout issues when using gh commands with special characters
|
||||
*
|
||||
* Usage:
|
||||
* ./github-safe.js issue comment 123 "Message with `backticks`"
|
||||
* ./github-safe.js pr create --title "Title" --body "Complex body"
|
||||
*/
|
||||
|
||||
import { execSync } from 'child_process';
|
||||
import { writeFileSync, unlinkSync } from 'fs';
|
||||
import { tmpdir } from 'os';
|
||||
import { join } from 'path';
|
||||
import { randomBytes } from 'crypto';
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
if (args.length < 2) {
|
||||
console.log(`
|
||||
Safe GitHub CLI Helper
|
||||
|
||||
Usage:
|
||||
./github-safe.js issue comment <number> <body>
|
||||
./github-safe.js pr comment <number> <body>
|
||||
./github-safe.js issue create --title <title> --body <body>
|
||||
./github-safe.js pr create --title <title> --body <body>
|
||||
|
||||
This helper prevents timeout issues with special characters like:
|
||||
- Backticks in code examples
|
||||
- Command substitution \$(...)
|
||||
- Directory paths
|
||||
- Special shell characters
|
||||
`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const [command, subcommand, ...restArgs] = args;
|
||||
|
||||
// Handle commands that need body content
|
||||
if ((command === 'issue' || command === 'pr') &&
|
||||
(subcommand === 'comment' || subcommand === 'create')) {
|
||||
|
||||
let bodyIndex = -1;
|
||||
let body = '';
|
||||
|
||||
if (subcommand === 'comment' && restArgs.length >= 2) {
|
||||
// Simple format: github-safe.js issue comment 123 "body"
|
||||
body = restArgs[1];
|
||||
bodyIndex = 1;
|
||||
} else {
|
||||
// Flag format: --body "content"
|
||||
bodyIndex = restArgs.indexOf('--body');
|
||||
if (bodyIndex !== -1 && bodyIndex < restArgs.length - 1) {
|
||||
body = restArgs[bodyIndex + 1];
|
||||
}
|
||||
}
|
||||
|
||||
if (body) {
|
||||
// Use temporary file for body content
|
||||
const tmpFile = join(tmpdir(), `gh-body-${randomBytes(8).toString('hex')}.tmp`);
|
||||
|
||||
try {
|
||||
writeFileSync(tmpFile, body, 'utf8');
|
||||
|
||||
// Build new command with --body-file
|
||||
const newArgs = [...restArgs];
|
||||
if (subcommand === 'comment' && bodyIndex === 1) {
|
||||
// Replace body with --body-file
|
||||
newArgs[1] = '--body-file';
|
||||
newArgs.push(tmpFile);
|
||||
} else if (bodyIndex !== -1) {
|
||||
// Replace --body with --body-file
|
||||
newArgs[bodyIndex] = '--body-file';
|
||||
newArgs[bodyIndex + 1] = tmpFile;
|
||||
}
|
||||
|
||||
// Execute safely
|
||||
const ghCommand = `gh ${command} ${subcommand} ${newArgs.join(' ')}`;
|
||||
console.log(`Executing: ${ghCommand}`);
|
||||
|
||||
const result = execSync(ghCommand, {
|
||||
stdio: 'inherit',
|
||||
timeout: 30000 // 30 second timeout
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error:', error.message);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
// Clean up
|
||||
try {
|
||||
unlinkSync(tmpFile);
|
||||
} catch (e) {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No body content, execute normally
|
||||
execSync(`gh ${args.join(' ')}`, { stdio: 'inherit' });
|
||||
}
|
||||
} else {
|
||||
// Other commands, execute normally
|
||||
execSync(`gh ${args.join(' ')}`, { stdio: 'inherit' });
|
||||
}
|
||||
Reference in New Issue
Block a user