{"version":3,"sources":["../../src/core/state.ts"],"names":["isRevertTransaction","state","r","getRevertedTransactionUuid","match","isUUID","str","sortByDateDesc","a","b","hasBeenProcessed","cwd","uuid","record","getDb","writePendingState","logger","db","data","fromStateFile","updatePendingState","commitState","updated","stateDir","getStateDirectory","path","markTransactionsAsGitCommitted","uuids","gitCommittedAt","deletePendingState","readStateFile","toStateFile","readAllStateFiles","options","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 path from 'path';\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  // Validate UUID to prevent undefined.yaml errors\n  if (!state.uuid || typeof state.uuid !== 'string' || !state.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 writePendingState: ${state.uuid}`);\n    throw new Error(`Invalid UUID: ${state.uuid}`);\n  }\n  \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<string | null> => {\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  \n  if (updated.length > 0) {\n    const record = updated[0] as { id: number };\n    const stateDir = getStateDirectory(cwd);\n    // Path construction based on konro's per-record strategy. The double 'transactions' is intentional.\n    // <stateDir>/<dbName>/<tableName>/<recordId>.json\n    const filePath = path.join(stateDir, 'transactions', 'transactions', `${record.id}.json`);\n    return filePath;\n  }\n  return null;\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    const 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};"]}