UNPKG

relaycode

Version:

A developer assistant that automates applying code changes from LLMs.

1 lines 12.3 kB
{"version":3,"sources":["../../src/core/state.ts"],"names":["isRevertTransaction","state","r","getRevertedTransactionUuid","match","isUUID","str","sortByDateDesc","a","b","hasBeenProcessed","cwd","uuid","record","getDb","writePendingState","db","data","fromStateFile","updatePendingState","logger","commitState","markTransactionsAsGitCommitted","uuids","gitCommittedAt","deletePendingState","readStateFile","toStateFile","readAllStateFiles","options","stateDir","getStateDirectory","fs","records","validResults","revertedUuids","sf","revertedUuid","findLatestStateFile","findStateFileByIdentifier","identifier","index","transactions"],"mappings":"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","file":"state.cjs","sourcesContent":["import { type StateFile } from 'relaycode-core';\nimport { logger } from '../utils/logger';\nimport { getDb, toStateFile, fromStateFile } from './db';\nimport { promises as fs } from 'fs';\nimport { getStateDirectory } from './config';\n\nexport const isRevertTransaction = (state: StateFile): boolean => {\n return state.reasoning.some(r => r.startsWith('Reverting transaction'));\n}\n\nexport const getRevertedTransactionUuid = (state: StateFile): string | null => {\n for (const r of state.reasoning) {\n const match = r.match(/^Reverting transaction ([\\w-]+)\\./);\n if (match && match[1]) {\n return match[1];\n }\n }\n return null;\n}\n\nconst isUUID = (str: string): boolean => {\n return /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(str);\n};\n\nconst sortByDateDesc = (a: { createdAt: string | Date }, b: { createdAt: string | Date }) => {\n return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();\n};\n\nexport const hasBeenProcessed = async (cwd: string, uuid: string): Promise<boolean> => {\n const db = getDb(cwd);\n const record = await db.query().from('transactions').where({ uuid }).first();\n // 'committed' and 'undone' transactions are considered final.\n // 'pending' can be re-processed to handle orphaned transactions from crashes.\n return !!record && (record.status === 'committed' || record.status === 'undone');\n};\n\nexport const writePendingState = async (cwd: string, state: StateFile): Promise<void> => {\n const db = getDb(cwd);\n // First, remove any orphaned pending transaction with the same UUID to prevent unique constraint errors.\n // This allows reprocessing of transactions that were interrupted or crashed.\n await db.delete('transactions').where((r) => r.uuid === state.uuid && r.status === 'pending');\n\n // Now, insert the new pending transaction.\n const data = { ...fromStateFile(state), status: 'pending' };\n await db.insert('transactions', data as any);\n};\n\nexport const updatePendingState = async (cwd:string, state: StateFile): Promise<void> => {\n const db = getDb(cwd);\n const data = fromStateFile(state);\n const updated = await db.update('transactions').set(data as any).where({ uuid: state.uuid, status: 'pending' });\n if (updated.length === 0) {\n logger.warn(`Could not find pending transaction with uuid ${state.uuid} to update.`);\n }\n}\n\nexport const commitState = async (cwd: string, uuid: string): Promise<void> => {\n const db = getDb(cwd);\n // Also update status from 'pending' to 'committed'\n const updated = await db.update('transactions').set({ status: 'committed' }).where({ uuid, status: 'pending' });\n if (updated.length === 0) {\n logger.warn(`Could not find pending transaction with uuid ${uuid} to commit.`);\n }\n};\n\nexport const markTransactionsAsGitCommitted = async (cwd: string, uuids: string[]): Promise<void> => {\n const db = getDb(cwd);\n const gitCommittedAt = new Date().toISOString();\n \n for (const uuid of uuids) {\n const updated = await db.update('transactions').set({ gitCommittedAt }).where({ uuid, status: 'committed' });\n if (updated.length === 0) {\n logger.warn(`Could not find committed transaction with uuid ${uuid} to mark as git-committed.`);\n }\n }\n};\n\nexport const deletePendingState = async (cwd: string, uuid: string): Promise<void> => {\n // Validate UUID to prevent undefined.yaml errors\n if (!uuid || typeof uuid !== 'string' || !uuid.match(/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/)) {\n logger.error(`Fatal: Invalid UUID provided for deletePendingState: ${uuid}`);\n return;\n }\n \n const db = getDb(cwd);\n // In case of rollback, we mark it as 'undone' instead of deleting.\n const updated = await db.update('transactions').set({ status: 'undone' }).where({ uuid, status: 'pending' });\n if (updated.length === 0) {\n logger.debug(`Could not find pending transaction with uuid ${uuid} to mark as undone. It might have been committed or already undone.`);\n }\n};\n\nexport const readStateFile = async (cwd: string, uuid: string): Promise<StateFile | null> => {\n const db = getDb(cwd);\n const record = await db.query().from('transactions').where({ uuid, status: 'committed' }).first();\n return record ? toStateFile(record) : null;\n};\n\ninterface ReadStateFilesOptions {\n skipReverts?: boolean;\n}\n\nexport const readAllStateFiles = async (cwd: string = process.cwd(), options: ReadStateFilesOptions = {}): Promise<StateFile[] | null> => {\n const stateDir = getStateDirectory(cwd);\n try {\n await fs.access(stateDir);\n } catch {\n return null; // State directory does not exist, so not initialized\n }\n\n const db = getDb(cwd);\n let records = await db.query().from('transactions').where({ status: 'committed' }).all();\n \n if (!records) return [];\n \n let validResults = records.map(toStateFile);\n\n if (options.skipReverts) {\n const revertedUuids = new Set<string>();\n validResults.forEach(sf => {\n if (isRevertTransaction(sf)) {\n const revertedUuid = getRevertedTransactionUuid(sf);\n if (revertedUuid) {\n revertedUuids.add(revertedUuid);\n }\n }\n });\n\n validResults = validResults.filter(sf => \n !isRevertTransaction(sf) && !revertedUuids.has(sf.uuid)\n );\n }\n\n // Sort transactions by date, most recent first\n validResults.sort(sortByDateDesc);\n\n return validResults;\n}\n\nexport const findLatestStateFile = async (cwd: string = process.cwd(), options: ReadStateFilesOptions = {}): Promise<StateFile | null> => {\n const allFiles = await readAllStateFiles(cwd, options);\n return allFiles?.[0] ?? null;\n};\n\nexport const findStateFileByIdentifier = async (cwd: string, identifier: string, options: ReadStateFilesOptions = {}): Promise<StateFile | null> => {\n if (isUUID(identifier)) {\n // When fetching by UUID, we always return it if committed, regardless of whether it's a revert or not.\n const db = getDb(cwd);\n const record = await db.query().from('transactions').where({ uuid: identifier, status: 'committed' }).first();\n return record ? toStateFile(record) : null;\n }\n \n if (/^-?\\d+$/.test(identifier)) {\n const index = Math.abs(parseInt(identifier, 10));\n if (isNaN(index) || index <= 0) {\n return null;\n }\n\n const transactions = await readAllStateFiles(cwd, options);\n if (transactions && transactions.length >= index) {\n return transactions[index - 1] ?? null;\n }\n return null;\n }\n\n return null;\n};"]}