199 lines
5.6 KiB
TypeScript
199 lines
5.6 KiB
TypeScript
/**
|
|
* Batch Session State Management
|
|
*
|
|
* Stores answers from initial batch configuration and reuses them
|
|
* across all widgets in the batch session, eliminating repetitive questions.
|
|
*/
|
|
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
|
|
export interface BatchSessionAnswers {
|
|
detection_type?: 'generic' | 'monorepo-service' | 'nx-app' | 'turborepo-package' | 'lerna-package';
|
|
route?: 'greenfield' | 'brownfield';
|
|
brownfield_mode?: 'standard' | 'upgrade';
|
|
transmission?: 'manual' | 'cruise-control';
|
|
clarifications_strategy?: 'defer' | 'prompt' | 'skip';
|
|
implementation_scope?: 'none' | 'p0' | 'p0_p1' | 'all';
|
|
spec_output_location?: string;
|
|
target_stack?: string;
|
|
build_location?: string;
|
|
build_location_type?: 'subfolder' | 'separate' | 'replace';
|
|
}
|
|
|
|
export interface BatchSessionState {
|
|
sessionId: string;
|
|
startedAt: string;
|
|
batchRootDirectory: string;
|
|
totalRepos: number;
|
|
batchSize: number;
|
|
answers: BatchSessionAnswers;
|
|
processedRepos: string[];
|
|
}
|
|
|
|
const BATCH_SESSION_FILENAME = '.stackshift-batch-session.json';
|
|
|
|
/**
|
|
* Find batch session file by checking current directory and walking up
|
|
* Similar to how .git directories are found
|
|
*/
|
|
function findBatchSessionFile(startDir: string = process.cwd()): string | null {
|
|
let currentDir = path.resolve(startDir);
|
|
const root = path.parse(currentDir).root;
|
|
|
|
while (currentDir !== root) {
|
|
const batchSessionPath = path.join(currentDir, BATCH_SESSION_FILENAME);
|
|
if (fs.existsSync(batchSessionPath)) {
|
|
return batchSessionPath;
|
|
}
|
|
currentDir = path.dirname(currentDir);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Get batch session file path for a directory
|
|
*/
|
|
function getBatchSessionPath(directory: string = process.cwd()): string {
|
|
return path.join(directory, BATCH_SESSION_FILENAME);
|
|
}
|
|
|
|
/**
|
|
* Create a new batch session with initial answers
|
|
*/
|
|
export function createBatchSession(
|
|
batchRootDirectory: string,
|
|
totalRepos: number,
|
|
batchSize: number,
|
|
answers: BatchSessionAnswers
|
|
): BatchSessionState {
|
|
const session: BatchSessionState = {
|
|
sessionId: `batch-${Date.now()}`,
|
|
startedAt: new Date().toISOString(),
|
|
batchRootDirectory: path.resolve(batchRootDirectory),
|
|
totalRepos,
|
|
batchSize,
|
|
answers,
|
|
processedRepos: []
|
|
};
|
|
|
|
const sessionPath = getBatchSessionPath(batchRootDirectory);
|
|
fs.writeFileSync(sessionPath, JSON.stringify(session, null, 2));
|
|
|
|
return session;
|
|
}
|
|
|
|
/**
|
|
* Get current batch session if it exists
|
|
* Searches current directory and walks up to find batch session
|
|
*/
|
|
export function getBatchSession(startDir: string = process.cwd()): BatchSessionState | null {
|
|
try {
|
|
const sessionPath = findBatchSessionFile(startDir);
|
|
if (!sessionPath) {
|
|
return null;
|
|
}
|
|
|
|
const content = fs.readFileSync(sessionPath, 'utf-8');
|
|
return JSON.parse(content);
|
|
} catch (error) {
|
|
console.error('Error reading batch session:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if we're currently in a batch session
|
|
* Searches current directory and walks up
|
|
*/
|
|
export function hasBatchSession(startDir: string = process.cwd()): boolean {
|
|
return findBatchSessionFile(startDir) !== null;
|
|
}
|
|
|
|
/**
|
|
* Update batch session with processed repo
|
|
*/
|
|
export function markRepoProcessed(repoName: string, startDir: string = process.cwd()): void {
|
|
const sessionPath = findBatchSessionFile(startDir);
|
|
if (!sessionPath) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const content = fs.readFileSync(sessionPath, 'utf-8');
|
|
const session: BatchSessionState = JSON.parse(content);
|
|
|
|
if (!session.processedRepos.includes(repoName)) {
|
|
session.processedRepos.push(repoName);
|
|
}
|
|
|
|
fs.writeFileSync(sessionPath, JSON.stringify(session, null, 2));
|
|
} catch (error) {
|
|
console.error('Error updating batch session:', error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear batch session in specific directory
|
|
*/
|
|
export function clearBatchSession(directory: string = process.cwd()): boolean {
|
|
try {
|
|
const sessionPath = getBatchSessionPath(directory);
|
|
if (fs.existsSync(sessionPath)) {
|
|
fs.unlinkSync(sessionPath);
|
|
return true;
|
|
}
|
|
return false;
|
|
} catch (error) {
|
|
console.error('Error clearing batch session:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get batch session progress
|
|
*/
|
|
export function getBatchProgress(startDir: string = process.cwd()): string {
|
|
const session = getBatchSession(startDir);
|
|
if (!session) {
|
|
return 'No active batch session';
|
|
}
|
|
|
|
const processed = session.processedRepos.length;
|
|
const total = session.totalRepos;
|
|
const percentage = Math.round((processed / total) * 100);
|
|
|
|
return `Batch Progress: ${processed}/${total} repos (${percentage}%)`;
|
|
}
|
|
|
|
/**
|
|
* Format batch session for display
|
|
*/
|
|
export function formatBatchSession(session: BatchSessionState): string {
|
|
const duration = Date.now() - new Date(session.startedAt).getTime();
|
|
const hours = Math.floor(duration / 3600000);
|
|
const minutes = Math.floor((duration % 3600000) / 60000);
|
|
|
|
return `
|
|
📦 Active Batch Session
|
|
|
|
Session ID: ${session.sessionId}
|
|
Batch Root: ${session.batchRootDirectory}
|
|
Started: ${new Date(session.startedAt).toLocaleString()}
|
|
Duration: ${hours}h ${minutes}m
|
|
Total Repos: ${session.totalRepos}
|
|
Batch Size: ${session.batchSize}
|
|
Processed: ${session.processedRepos.length}/${session.totalRepos}
|
|
|
|
Configuration:
|
|
Route: ${session.answers.route || 'not set'}
|
|
Transmission: ${session.answers.transmission || 'not set'}
|
|
Spec Output: ${session.answers.spec_output_location || 'current directory'}
|
|
Build Location: ${session.answers.build_location || 'greenfield/'}
|
|
Target Stack: ${session.answers.target_stack || 'not set'}
|
|
|
|
Session File: ${session.batchRootDirectory}/${BATCH_SESSION_FILENAME}
|
|
`.trim();
|
|
}
|