import { CLICommand } from "../cli/CLICommand.js"; import { parseTodoFile, writeTodoFile } from "../file.js"; import { getCurrentBranch, commitFileWithBody } from "../git.js"; import { validateStatusTransition } from "../issue.js"; export class CancelCommand extends CLICommand { name = "cancel "; help = "Cancel an issue"; description = "Set issue to cancelled (must be on issue branch or develop)"; addArguments(yargs) { return yargs .positional("id", { type: "number", demandOption: true }) .option("reason", { type: "string", demandOption: true, description: "Reason for cancellation", }); } async execute(args) { const todo = await parseTodoFile(); const issue = todo.issues.find(i => i.id === args.id); if (!issue) { console.error(`Issue #${args.id} not found`); return 1; } // Cancel allowed from develop (if open) or issue branch (if in-progress/hold) const issueBranch = `${issue.type}/${issue.id}`; const branch = getCurrentBranch(); if (branch !== "develop" && branch !== issueBranch) { console.error(`Must be on develop or ${issueBranch} to cancel (currently on ${branch})`); return 1; } const err = validateStatusTransition(issue.status, "cancelled"); if (err) { console.error(err); return 1; } issue.status = "cancelled"; writeTodoFile(todo); commitFileWithBody("TODO", `todo(${issue.id}): cancelled`, args.reason); console.log(`Issue #${issue.id} is now cancelled`); return 0; } }