From 61c9480b5b9542350132bbaf624ce793c8f194d4 Mon Sep 17 00:00:00 2001 From: Smartsheet-JB-Brown Date: Sat, 12 Apr 2025 17:34:00 -0700 Subject: [PATCH] refactor: rename prepare-for-commit to iterate - Renamed prepare_logs to iterations - Updated task manager to use new terminology - Simplified CLI interface - Added better TypeScript types - Improved error handling Task ID: 4d3f7a2e-8c1b-4f9d-b5e2-9c1d8f3a6b4d --- .roo/iterate-cli.ts | 137 ++++++++++++++++ .../PM-CLEANUP-20250412.json | 0 .../PM-STATE-FIX-20250412.json | 0 ..._4d3f7a2e-8c1b-4f9d-b5e2-9c1d8f3a6b4d.json | 10 +- .roo/package.json | 8 +- .roo/prepare-cli.ts | 148 ------------------ .roo/task-manager.ts | 146 +++++++---------- 7 files changed, 203 insertions(+), 246 deletions(-) create mode 100644 .roo/iterate-cli.ts rename .roo/{prepare_logs => iterations}/PM-CLEANUP-20250412.json (100%) rename .roo/{prepare_logs => iterations}/PM-STATE-FIX-20250412.json (100%) rename .roo/{prepare_logs => iterations}/task_4d3f7a2e-8c1b-4f9d-b5e2-9c1d8f3a6b4d.json (85%) delete mode 100644 .roo/prepare-cli.ts diff --git a/.roo/iterate-cli.ts b/.roo/iterate-cli.ts new file mode 100644 index 0000000000..4eb4102b3a --- /dev/null +++ b/.roo/iterate-cli.ts @@ -0,0 +1,137 @@ +#!/usr/bin/env node +import { program } from "commander" +import { taskManager } from "./task-manager" +import { execSync } from "child_process" + +program.name("iterate").description("CLI to manage task iterations") + +program + .command("create ") + .description("Create a new iteration") + .requiredOption("-d, --description ", "Task description") + .action(async (taskId: string, options: { description: string }) => { + try { + await taskManager.createIteration(taskId, options.description) + console.log(`Created iteration: ${taskId}`) + } catch (error) { + console.error("Failed to create iteration:", error) + process.exit(1) + } + }) + +program + .command("list") + .description("List all iterations") + .action(async () => { + try { + const iterations = await taskManager.listIterations() + console.log("Available iterations:") + for (const taskId of iterations) { + const task = await taskManager.getIteration(taskId) + if (task) { + console.log(`- ${taskId}: ${task.description} (${task.current_state.status})`) + } + } + } catch (error) { + console.error("Failed to list iterations:", error) + process.exit(1) + } + }) + +program + .command("status ") + .description("Show iteration status") + .action(async (taskId: string) => { + try { + const task = await taskManager.getIteration(taskId) + if (!task) { + console.log("No such iteration") + return + } + + console.log(`Iteration: ${task.task_id}`) + console.log(`Description: ${task.description}`) + console.log(`Status: ${task.current_state.status}`) + + if (task.checkpoints.length > 0) { + console.log("\nCheckpoints:") + task.checkpoints.forEach((checkpoint, i) => { + console.log(`${i + 1}. ${checkpoint.description}`) + console.log(` Changes: ${checkpoint.changes.join(", ")}`) + console.log(` Timestamp: ${checkpoint.timestamp}`) + }) + } + + if (task.test_results) { + console.log("\nTest results:") + console.log( + `- Unit tests: ${task.test_results.unit_tests.passing} passing, ${task.test_results.unit_tests.failing} failing`, + ) + console.log(`- Linting: ${task.test_results.linting}`) + console.log(`- Manual testing: ${task.test_results.manual_testing}`) + } + + if (task.current_state.final_commit) { + console.log("\nCommit info:") + console.log(`- Hash: ${task.current_state.final_commit.hash}`) + console.log(`- Message: ${task.current_state.final_commit.message}`) + console.log("- Changes:") + task.current_state.final_commit.changes.forEach((change) => { + console.log(` * ${change}`) + }) + } + } catch (error) { + console.error("Failed to get iteration status:", error) + process.exit(1) + } + }) + +program + .command("checkpoint ") + .description("Create a new checkpoint") + .requiredOption("-d, --description ", "Checkpoint description") + .requiredOption("-c, --component ", "Component being modified") + .requiredOption("--changes ", "List of changes") + .requiredOption("--risks ", "List of risks") + .requiredOption("--feedback ", "Expected user feedback") + .action(async (taskId: string, options) => { + try { + const checkpoint = { + id: `checkpoint_${Date.now()}`, + description: options.description, + component: options.component, + changes: options.changes, + risks: options.risks, + expected_feedback: options.feedback, + timestamp: new Date().toISOString(), + } + + await taskManager.addCheckpoint(taskId, checkpoint) + console.log(`Created checkpoint: ${checkpoint.id}`) + } catch (error) { + console.error("Failed to create checkpoint:", error) + process.exit(1) + } + }) + +program + .command("complete ") + .description("Complete an iteration with commit info") + .requiredOption("--message ", "Commit message") + .requiredOption("--changes ", "List of changes") + .action(async (taskId: string, options) => { + try { + const hash = execSync("git rev-parse HEAD").toString().trim() + await taskManager.completeIteration(taskId, { + hash, + message: options.message, + changes: options.changes, + }) + console.log(`Completed iteration: ${taskId}`) + } catch (error) { + console.error("Failed to complete iteration:", error) + process.exit(1) + } + }) + +program.parse() diff --git a/.roo/prepare_logs/PM-CLEANUP-20250412.json b/.roo/iterations/PM-CLEANUP-20250412.json similarity index 100% rename from .roo/prepare_logs/PM-CLEANUP-20250412.json rename to .roo/iterations/PM-CLEANUP-20250412.json diff --git a/.roo/prepare_logs/PM-STATE-FIX-20250412.json b/.roo/iterations/PM-STATE-FIX-20250412.json similarity index 100% rename from .roo/prepare_logs/PM-STATE-FIX-20250412.json rename to .roo/iterations/PM-STATE-FIX-20250412.json diff --git a/.roo/prepare_logs/task_4d3f7a2e-8c1b-4f9d-b5e2-9c1d8f3a6b4d.json b/.roo/iterations/task_4d3f7a2e-8c1b-4f9d-b5e2-9c1d8f3a6b4d.json similarity index 85% rename from .roo/prepare_logs/task_4d3f7a2e-8c1b-4f9d-b5e2-9c1d8f3a6b4d.json rename to .roo/iterations/task_4d3f7a2e-8c1b-4f9d-b5e2-9c1d8f3a6b4d.json index 9d3bd3a402..5d73087c2d 100644 --- a/.roo/prepare_logs/task_4d3f7a2e-8c1b-4f9d-b5e2-9c1d8f3a6b4d.json +++ b/.roo/iterations/task_4d3f7a2e-8c1b-4f9d-b5e2-9c1d8f3a6b4d.json @@ -51,6 +51,14 @@ ], "current_state": { "status": "completed", - "summary": "Successfully removed unused YamlParser.ts with no regressions" + "summary": "Successfully removed unused YamlParser.ts with no regressions", + "final_commit": { + "hash": "589b1596", + "message": "refactor: remove unused YamlParser implementation", + "changes": [ + "Removed src/services/package-manager/YamlParser.ts", + "All tests passing (1263 pass, 0 fail, 23 pending)" + ] + } } } diff --git a/.roo/package.json b/.roo/package.json index ca90aef68f..a7aac6ec3e 100644 --- a/.roo/package.json +++ b/.roo/package.json @@ -1,15 +1,15 @@ { - "name": "roo-prepare", + "name": "roo-iterate", "version": "1.0.0", - "description": "Prepare for commit task management system", + "description": "Iteration task management system", "private": true, "bin": { - "prepare": "./dist/prepare-cli.js" + "iterate": "./dist/iterate-cli.js" }, "scripts": { "build": "tsc", "prepare": "npm run build", - "start": "node ./dist/prepare-cli.js" + "start": "node ./dist/iterate-cli.js" }, "dependencies": { "commander": "^11.1.0" diff --git a/.roo/prepare-cli.ts b/.roo/prepare-cli.ts deleted file mode 100644 index 919f2ba458..0000000000 --- a/.roo/prepare-cli.ts +++ /dev/null @@ -1,148 +0,0 @@ -#!/usr/bin/env node -import { program } from "commander" -import { taskManager } from "./task-manager" -import * as fs from "fs/promises" -import * as path from "path" -import { execSync } from "child_process" - -program.name("prepare").description("CLI to manage prepare for commit tasks") - -program - .command("create ") - .description("Create a new task") - .requiredOption("-d, --description ", "Task description") - .action(async (taskId: string, options: { description: string }) => { - try { - const initialCommit = execSync("git rev-parse HEAD").toString().trim() - await taskManager.createTask(taskId, options.description, initialCommit) - console.log(`Created task: ${taskId}`) - } catch (error) { - console.error("Failed to create task:", error) - process.exit(1) - } - }) - -program - .command("switch ") - .description("Switch to a different task") - .action(async (taskId: string) => { - try { - await taskManager.switchTask(taskId) - const task = taskManager.getCurrentTask() - console.log(`Switched to task: ${taskId}`) - console.log("Current checkpoint:", task?.active_checkpoint) - if (task?.pending_decisions.length) { - console.log("\nPending decisions:") - task.pending_decisions.forEach((decision, i) => { - console.log(`${i + 1}. ${decision}`) - }) - } - } catch (error) { - console.error("Failed to switch task:", error) - process.exit(1) - } - }) - -program - .command("list") - .description("List all tasks") - .action(async () => { - try { - const tasks = await taskManager.listTasks() - console.log("Available tasks:") - for (const taskId of tasks) { - const content = await fs.readFile(path.join(".roo", "prepare_logs", `${taskId}.json`), "utf-8") - const task = JSON.parse(content) - console.log(`- ${taskId}: ${task.description} (${task.status})`) - } - } catch (error) { - console.error("Failed to list tasks:", error) - process.exit(1) - } - }) - -program - .command("status") - .description("Show current task status") - .action(() => { - const task = taskManager.getCurrentTask() - if (!task) { - console.log("No active task") - return - } - - console.log(`Current task: ${task.task_id}`) - console.log(`Description: ${task.description}`) - console.log(`Status: ${task.status}`) - console.log(`Active checkpoint: ${task.active_checkpoint}`) - - if (task.pending_decisions.length) { - console.log("\nPending decisions:") - task.pending_decisions.forEach((decision, i) => { - console.log(`${i + 1}. ${decision}`) - }) - } - - console.log("\nTest results:") - console.log( - `- Unit tests: ${task.test_results.unit_tests.passing} passing, ${task.test_results.unit_tests.failing} failing`, - ) - console.log(`- Linting: ${task.test_results.linting}`) - console.log(`- Manual testing: ${task.test_results.manual_testing}`) - - console.log("\nRollback info:") - console.log(`Full rollback: ${task.rollback_info.full_rollback}`) - console.log("Partial rollbacks:") - Object.entries(task.rollback_info.partial_rollbacks).forEach(([name, command]) => { - console.log(`- ${name}: ${command}`) - }) - }) - -program - .command("checkpoint") - .description("Create a new checkpoint") - .requiredOption("-d, --description ", "Checkpoint description") - .requiredOption("-c, --component ", "Component being modified") - .requiredOption("--changes ", "List of changes") - .requiredOption("--risks ", "List of risks") - .requiredOption("--feedback ", "Expected user feedback") - .action(async (options) => { - try { - const commitHash = execSync("git rev-parse HEAD").toString().trim() - const task = taskManager.getCurrentTask() - if (!task) throw new Error("No active task") - - const checkpoint = { - id: `${task.task_id}_${task.checkpoints.length + 1}`, - commit_hash: commitHash, - description: options.description, - component: options.component, - changes: options.changes, - risks: options.risks, - expected_feedback: options.feedback, - timestamp: new Date().toISOString(), - } - - await taskManager.addCheckpoint(checkpoint) - console.log(`Created checkpoint: ${checkpoint.id}`) - } catch (error) { - console.error("Failed to create checkpoint:", error) - process.exit(1) - } - }) - -program - .command("decide ") - .description("Resolve a pending decision") - .action(async (index: string) => { - try { - const idx = parseInt(index, 10) - 1 - await taskManager.resolvePendingDecision(idx) - console.log("Decision resolved") - } catch (error) { - console.error("Failed to resolve decision:", error) - process.exit(1) - } - }) - -program.parse() diff --git a/.roo/task-manager.ts b/.roo/task-manager.ts index 67ab2b656f..1e14fea34c 100644 --- a/.roo/task-manager.ts +++ b/.roo/task-manager.ts @@ -3,7 +3,6 @@ import * as path from "path" interface TaskCheckpoint { id: string - commit_hash: string description: string component: string changes: string[] @@ -14,14 +13,10 @@ interface TaskCheckpoint { interface TaskContext { task_id: string - active_checkpoint: string - status: "in_progress" | "completed" | "failed" - created_at: string - last_accessed: string description: string - initial_commit: string + created_at: string checkpoints: TaskCheckpoint[] - test_results: { + test_results?: { unit_tests: { passing: number failing: number @@ -30,130 +25,95 @@ interface TaskContext { linting: string manual_testing: string } - pending_decisions: string[] - rollback_info: { - full_rollback: string - partial_rollbacks: Record + current_state: { + status: "in_progress" | "completed" | "failed" + summary?: string + final_commit?: { + hash: string + message: string + changes: string[] + } } } class TaskManager { - private currentTaskId: string | null = null - private currentContext: TaskContext | null = null - private readonly logsDir = path.join(".roo", "prepare_logs") + private readonly iterationsDir = path.join(".roo", "iterations") constructor() { - this.ensureLogsDirectory() + this.ensureIterationsDirectory() } - private async ensureLogsDirectory() { + private async ensureIterationsDirectory() { try { - await fs.mkdir(this.logsDir, { recursive: true }) + await fs.mkdir(this.iterationsDir, { recursive: true }) } catch (error) { - console.error("Failed to create logs directory:", error) + console.error("Failed to create iterations directory:", error) } } - async switchTask(taskId: string): Promise { - if (this.currentTaskId) { - await this.saveCurrentTask() - } - await this.loadTask(taskId) - } - - private async saveCurrentTask(): Promise { - if (!this.currentTaskId || !this.currentContext) return - - this.currentContext.last_accessed = new Date().toISOString() - const logPath = this.getLogPath(this.currentTaskId) - - await fs.writeFile(logPath, JSON.stringify(this.currentContext, null, 2), "utf-8") - } - - private async loadTask(taskId: string): Promise { - const logPath = this.getLogPath(taskId) - - try { - const content = await fs.readFile(logPath, "utf-8") - this.currentContext = JSON.parse(content) - this.currentTaskId = taskId - } catch (error) { - console.error(`Failed to load task ${taskId}:`, error) - throw error - } - } - - async createTask(taskId: string, description: string, initialCommit: string): Promise { + async createIteration(taskId: string, description: string): Promise { const newTask: TaskContext = { task_id: taskId, - active_checkpoint: "", - status: "in_progress", - created_at: new Date().toISOString(), - last_accessed: new Date().toISOString(), description, - initial_commit: initialCommit, + created_at: new Date().toISOString(), checkpoints: [], - test_results: { - unit_tests: { passing: 0, failing: 0, pending: 0 }, - linting: "", - manual_testing: "", - }, - pending_decisions: [], - rollback_info: { - full_rollback: `git reset --hard ${initialCommit}`, - partial_rollbacks: {}, + current_state: { + status: "in_progress", }, } const logPath = this.getLogPath(taskId) await fs.writeFile(logPath, JSON.stringify(newTask, null, 2), "utf-8") - - this.currentTaskId = taskId - this.currentContext = newTask } - async addCheckpoint(checkpoint: TaskCheckpoint): Promise { - if (!this.currentContext) throw new Error("No active task") + async addCheckpoint(taskId: string, checkpoint: TaskCheckpoint): Promise { + const logPath = this.getLogPath(taskId) + const content = await fs.readFile(logPath, "utf-8") + const task = JSON.parse(content) as TaskContext - this.currentContext.checkpoints.push(checkpoint) - this.currentContext.active_checkpoint = checkpoint.id - this.currentContext.rollback_info.partial_rollbacks[checkpoint.description.toLowerCase().replace(/\s+/g, "_")] = - `git checkout ${checkpoint.commit_hash}` - - await this.saveCurrentTask() + task.checkpoints.push(checkpoint) + await fs.writeFile(logPath, JSON.stringify(task, null, 2), "utf-8") } - async updateTestResults(results: TaskContext["test_results"]): Promise { - if (!this.currentContext) throw new Error("No active task") + async updateTestResults(taskId: string, results: TaskContext["test_results"]): Promise { + const logPath = this.getLogPath(taskId) + const content = await fs.readFile(logPath, "utf-8") + const task = JSON.parse(content) as TaskContext - this.currentContext.test_results = results - await this.saveCurrentTask() + task.test_results = results + await fs.writeFile(logPath, JSON.stringify(task, null, 2), "utf-8") } - async addPendingDecision(decision: string): Promise { - if (!this.currentContext) throw new Error("No active task") + async completeIteration(taskId: string, commitInfo: TaskContext["current_state"]["final_commit"]): Promise { + const logPath = this.getLogPath(taskId) + const content = await fs.readFile(logPath, "utf-8") + const task = JSON.parse(content) as TaskContext - this.currentContext.pending_decisions.push(decision) - await this.saveCurrentTask() + task.current_state = { + status: "completed", + summary: `Successfully completed task with commit ${commitInfo.hash}`, + final_commit: commitInfo, + } + + await fs.writeFile(logPath, JSON.stringify(task, null, 2), "utf-8") } - async resolvePendingDecision(index: number): Promise { - if (!this.currentContext) throw new Error("No active task") - - this.currentContext.pending_decisions.splice(index, 1) - await this.saveCurrentTask() - } - - getCurrentTask(): TaskContext | null { - return this.currentContext + async getIteration(taskId: string): Promise { + try { + const logPath = this.getLogPath(taskId) + const content = await fs.readFile(logPath, "utf-8") + return JSON.parse(content) as TaskContext + } catch (error) { + return null + } } private getLogPath(taskId: string): string { - return path.join(this.logsDir, `${taskId}.json`) + return path.join(this.iterationsDir, `${taskId}.json`) } - async listTasks(): Promise { - const files = await fs.readdir(this.logsDir) + async listIterations(): Promise { + const files = await fs.readdir(this.iterationsDir) return files.filter((file) => file.endsWith(".json")).map((file) => file.replace(".json", "")) } }