UNPKG

relaycode

Version:

A developer assistant that automates applying code changes from LLMs.

1 lines 9.52 kB
{"version":3,"sources":["../../src/commands/revert.ts"],"names":["revertCommand","identifier","options","cwd","prompter","getConfirmation","createConfirmationHandler","config","loadConfigOrExit","targetDescription","effectiveIdentifier","isIndexSearch","index","logger","chalk","stateToRevert","findStateFileByIdentifier","allTransactions","readAllStateFiles","nonRevertTransactions","revertCount","formatTransactionDetails","line","inverse_operations","finalPaths","op","finalPath","snapshotPath","content","newUuid","uuidv4","reasoning","parsedResponse","processPatch"],"mappings":"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","file":"revert.cjs","sourcesContent":["import { loadConfigOrExit } from '../core/config';\nimport { findStateFileByIdentifier, readAllStateFiles } from '../core/state';\nimport { processPatch } from '../core/transaction';\nimport { logger } from '../utils/logger';\nimport { type FileOperation, type ParsedLLMResponse } from 'relaycode-core';\nimport { v4 as uuidv4 } from 'uuid';\nimport { createConfirmationHandler, type Prompter } from '../utils/prompt';\nimport { formatTransactionDetails } from '../utils/formatters';\nimport chalk from 'chalk';\n\ninterface RevertOptions {\n yes?: boolean;\n includeReverts?: boolean;\n}\n\nexport const revertCommand = async (identifier?: string, options: RevertOptions = {}, cwd: string = process.cwd(), prompter?: Prompter): Promise<void> => {\n const getConfirmation = createConfirmationHandler(options, prompter);\n const config = await loadConfigOrExit(cwd);\n\n let targetDescription: string;\n\n // Default to '1' to revert the latest transaction if no identifier is provided.\n const effectiveIdentifier = identifier ?? '1';\n\n const isIndexSearch = /^-?\\d+$/.test(effectiveIdentifier);\n\n if (isIndexSearch) {\n const index = Math.abs(parseInt(effectiveIdentifier, 10));\n if (isNaN(index) || index <= 0) {\n logger.error(`Invalid index. Please provide a positive number (e.g., ${chalk.cyan('\"1\"')} for the latest).`);\n return;\n }\n targetDescription = index === 1 ? 'the latest transaction' : `the ${chalk.cyan(index)}-th latest transaction`;\n } else {\n // We assume it's a UUID, findStateFileByIdentifier will validate\n targetDescription = `transaction with UUID '${chalk.cyan(effectiveIdentifier)}'`;\n }\n\n logger.info(`Looking for ${targetDescription}...`);\n const stateToRevert = await findStateFileByIdentifier(cwd, effectiveIdentifier, {\n skipReverts: !options.includeReverts,\n });\n\n if (!stateToRevert) {\n logger.error(`Could not find ${targetDescription}.`);\n if (isIndexSearch) {\n const allTransactions = await readAllStateFiles(cwd, { skipReverts: false }); // Show total count including reverts\n const nonRevertTransactions = await readAllStateFiles(cwd, { skipReverts: true });\n const revertCount = (allTransactions?.length ?? 0) - (nonRevertTransactions?.length ?? 0);\n \n logger.info(`Found ${chalk.cyan(allTransactions?.length ?? 0)} total transactions.`);\n if (revertCount > 0) {\n logger.info(`${chalk.cyan(revertCount)} of them are revert transactions, which are skipped by default.`);\n logger.info(`Use the ${chalk.cyan('--include-reverts')} flag to include them in the search.`);\n }\n }\n return;\n }\n logger.log(chalk.bold(`Transaction to be reverted:`));\n formatTransactionDetails(stateToRevert).forEach(line => logger.log(line));\n\n const confirmed = await getConfirmation('\\nAre you sure you want to revert this transaction? (y/N)');\n if (!confirmed) {\n logger.info('Revert operation cancelled.');\n return;\n }\n\n // 3. Generate inverse operations.\n // This logic is simpler and more robust than trying to reverse each operation individually.\n // It determines the final state of files after the transaction and generates operations\n // to transform that final state back to the initial snapshot state.\n const inverse_operations: FileOperation[] = [];\n\n // Get a set of all file paths that existed *after* the transaction.\n const finalPaths = new Set<string>(Object.keys(stateToRevert.snapshot));\n for (const op of stateToRevert.operations) {\n if (op.type === 'rename') {\n finalPaths.delete(op.from);\n finalPaths.add(op.to);\n } else if (op.type === 'write' && !finalPaths.has(op.path)) {\n finalPaths.add(op.path); // A new file was created\n } else if (op.type === 'delete') {\n finalPaths.delete(op.path);\n }\n }\n\n // Any path that exists now but didn't in the snapshot (or was null) must be deleted.\n for (const finalPath of finalPaths) {\n if (!stateToRevert.snapshot.hasOwnProperty(finalPath) || stateToRevert.snapshot[finalPath] === null) {\n inverse_operations.push({ type: 'delete', path: finalPath });\n }\n }\n\n // Any path that was in the snapshot must be restored to its original content.\n for (const [snapshotPath, content] of Object.entries(stateToRevert.snapshot)) {\n if (content !== null) {\n inverse_operations.push({ type: 'write', path: snapshotPath, content, patchStrategy: 'replace' });\n }\n }\n\n if (inverse_operations.length === 0) {\n logger.warn('No operations to revert for this transaction.');\n return;\n }\n\n // 4. Create and process a new \"revert\" transaction\n const newUuid = uuidv4();\n const reasoning = [\n `Reverting transaction ${stateToRevert.uuid}.`,\n `Reasoning from original transaction: ${stateToRevert.reasoning.join(' ')}`\n ];\n\n const parsedResponse: ParsedLLMResponse = {\n control: {\n projectId: config.projectId,\n uuid: newUuid,\n },\n operations: inverse_operations,\n reasoning,\n };\n\n logger.info(`Creating new transaction ${chalk.gray(newUuid)} to perform the revert.`);\n await processPatch(config, parsedResponse, { cwd, prompter, yes: options.yes });\n};"]}