Skip to content

FileGenerator ​

ARFA Generator работает итеративно emit → write → cleanup, что позволяет нескольким плагинам последовательно изменять файлы, пока кодовая база не стабилизируется, а затем выполняются чекеры для проверки корректности и остальной жизненный цикл.

ts
ci?: boolean

Режим CI, по умолчанию false. При true вызовы startWatch() и параметр historyPath игнорируются, а при возникновении ошибок выбрасывается исключение

ts
rootDir: string

Корневая директория для glob-паттернов плагинов и watch-режима. Генератор не меняет файлы за её пределами

ts
plugins: Array<BasePlugin>

Плагины, которые предлагают файлы для записи. Выполняются в порядке объявления на каждой итерации

ts
checkers?: Array<BaseChecker>

Проверки, которые запускаются после завершения работы плагинов и каскадных изменений

ts
format?: (files: {
  plugin: string;
  content: string;
  filePath: string;
}) => {
  plugin: string;
  content: string;
  filePath: string;
} | Promise<{
  plugin: string;
  content: string;
  filePath: string;
}>

Функция форматирования содержимого файлов, предложенных плагинами. Вызывается перед сравнением с содержимым на диске и записью

ts
headerTemplate?: string

Общий текст, добавляемый в начало каждого сгенерированного файла, если плагин не указал skipHeader

ts
historyPath?: string

Абсолютный путь к файлу с результатами запусков в формате JSONL, при ci: true или если не указан — история не читается и не записывается

Размещайте файл за пределами rootDir, чтобы обновление не вызывало watch-события

API ​

runFullCycle ​

Запускает один полный проход генерации с проверками и жизненным циклом.

ts
runFullCycle(params?: {
  onStart?: () => void;
  afterCheckers?: (args: TypeAfterCheckersArgs) => void | Promise<void>;
  afterFinish?: (args: TypeAfterFinishArgs) => void | Promise<void>;
}): Promise<void>

type TypeAfterCheckersArgs = {
  changedFiles: Array<{ relativePath: string; absolutePath: string }>;
  deletedFiles: Array<{ relativePath: string; absolutePath: string }>;
  isFullGeneration: boolean;
};

type TypeAfterFinishArgs = TypeAfterCheckersArgs & { logs: TypeLogs };

onStart — синхронный колбэк перед запуском плагинов.

afterCheckers — синхронный или асинхронный колбэк после завершения работы плагинов и чекеров. Может использоваться для запуска бандлера и других не изменяющих код операций.

afterFinish — синхронный или асинхронный колбэк после afterCheckers. Получает те же данные и logs, включая ошибки из предыдущего колбэка. Подходит для вывода логов и произвольной логики, например отправки сигнала браузеру обновить страницу или запуска LLM-агента (то есть допускаются изменяющие код операции, они запустят новый цикл генерации, но только в watch-режиме). Ошибки из этого колбэка выводятся в консоль в обход logs и сохраняются в JSONL.

changedFiles содержит существующие файлы, изменённые плагинами или пользователем в рамках watch-процесса, а deletedFiles — удалённые файлы.

isFullGeneration для данного метода равен true.

startWatch ​

Начинает следить за изменениями в rootDir, не запуская первоначальную генерацию. При ci: true сразу возвращает завершённый Promise.

ts
startWatch(params?: {
  onStart?: () => void;
  afterCheckers?: (args: TypeAfterCheckersArgs) => void | Promise<void>;
  afterFinish?: (args: TypeAfterFinishArgs) => void | Promise<void>;
  aggregationTimeout?: number;
}): Promise<void>

onStart — синхронный колбэк, вызываемый после накопления изменений за aggregationTimeout, перед запуском плагинов.

isFullGeneration в данном методе равен false, а изменения файлов во время afterFinish вызовут новый полный цикл генерации.

aggregationTimeout (в миллисекундах, 0 по умолчанию) полезен в качестве debounce — для предотвращения лишних срабатываний при быстрых изменениях или настроенных File Watchers в IDE (например, переформатирование при сохранении файла).

startWatch следит за изменениями только в rootDir. Изменение внешних файлов вроде tsconfig, .env или зависимостей не перезапускает генерацию, как и изменение конфигурации самого генератора — в этом случае нужен ручной перезапуск процесса.

Дополнительно

Это долгоживущий процесс, который практически никогда не выбрасывает исключений, а сохраняет ошибки в логи для вывода в консоль и в JSONL. Таким образом, ошибки кода можно исправлять "на лету"

stopWatch ​

Останавливает наблюдение, но не отменяет уже выполняющийся цикл генерации.

ts
stopWatch(): Promise<void>

getControlledFiles ​

Возвращает список существующих файлов, контролируемых генератором, включая устаревшие файлы, которые плагины планируют удалить в cleanup фазе.

ts
getControlledFiles(): Promise<Array<{
  relativePath: string;
  absolutePath: string;
}>>
ts
const files = await generator.getControlledFiles();

console.log(files.map(({relativePath}) => relativePath));

removeGeneratedFiles ​

Вызывает настроенные плагины, но вместо создания файлов — удаляет их. Полезен при изменении конфигурации. Пустые папки, созданные плагинами, могут остаться: рекурсивное удаление папок не выполняется.

ts
removeGeneratedFiles(): Promise<void>

Пример: Codex в afterFinish

В watch-режиме при наличии // AGENT в изменённых файлах запускается Codex, который выполняет задачу и удаляет маркер для избежания бесконечного цикла

ts
async afterFinish({ changedFiles }) {
  const codex = new Codex();
  const thread = codex.startThread();

  for (const { absolutePath } of changedFiles || []) {
    const content = fs.readFileSync(absolutePath, 'utf8');
    const prompt = content.match(/\/\/ AGENT (.+)/)?.[1];

    if (!prompt) continue;

    await thread.run(`
      File: ${absolutePath}
      Task: ${prompt}
      Edit the file directly and remove the completed // AGENT command.
    `);
  }
},
Запустить Sandbox
USER: fibonacci.ts создан с содержимым:
ts
ARFA Generator выводит логи:
txt
[ARFA-GEN] finished in 0ms
afterFinish обновил файлы проекта:
ts

MIT License