locadex 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # locadex
2
2
 
3
+ ## 0.1.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#363](https://github.com/generaltranslation/gt/pull/363) [`ed05e88`](https://github.com/generaltranslation/gt/commit/ed05e889a5c126dec0967854e9d51c0eb4b58ed7) Thanks [@brian-lou](https://github.com/brian-lou)! - Fix max timeout for locadex
8
+
9
+ - [#365](https://github.com/generaltranslation/gt/pull/365) [`8c72867`](https://github.com/generaltranslation/gt/commit/8c72867a1a1157769738a0f52bb6dd45dc1d7822) Thanks [@brian-lou](https://github.com/brian-lou)! - Separate hard and soft timeouts
10
+
3
11
  ## 0.1.1
4
12
 
5
13
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"concurrency.d.ts","sourceRoot":"/","sources":["tasks/concurrency.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,EAAE,QAAQ;IAC5C;;;;;;;OAOG;IACH,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,QAAQ,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnE;;;;;;;OAOG;IACH,WAAW,EAAE,CACX,KAAK,EAAE,KAAK,EAAE,EACd,OAAO,EAAE,QAAQ,EACjB,WAAW,EAAE,MAAM,KAChB,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,QAAQ,EACzD,SAAS,EAAE,KAAK,EAAE,EAClB,SAAS,EAAE,aAAa,CAAC,KAAK,EAAE,QAAQ,CAAC,EACzC,OAAO,EAAE,QAAQ,EACjB,OAAO,EAAE,yBAAyB,EAClC,UAAU,GAAE,MAAU,GACrB,OAAO,CAAC,IAAI,CAAC,CAoHf"}
1
+ {"version":3,"file":"concurrency.d.ts","sourceRoot":"/","sources":["tasks/concurrency.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,EAAE,QAAQ;IAC5C;;;;;;;OAOG;IACH,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,QAAQ,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnE;;;;;;;OAOG;IACH,WAAW,EAAE,CACX,KAAK,EAAE,KAAK,EAAE,EACd,OAAO,EAAE,QAAQ,EACjB,WAAW,EAAE,MAAM,KAChB,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,QAAQ,EACzD,SAAS,EAAE,KAAK,EAAE,EAClB,SAAS,EAAE,aAAa,CAAC,KAAK,EAAE,QAAQ,CAAC,EACzC,OAAO,EAAE,QAAQ,EACjB,OAAO,EAAE,yBAAyB,EAClC,UAAU,GAAE,MAAU,GACrB,OAAO,CAAC,IAAI,CAAC,CA2Hf"}
@@ -85,7 +85,10 @@ export async function runParallelProcessing(taskQueue, processor, context, optio
85
85
  // dynamic timeout based on the number of tasks
86
86
  const dynamicTimeoutSec = manager.getTimeoutFactor() * tasks.length;
87
87
  // Claude call with timeout and retry (handled inside agent.run)
88
- await agent.run(prompt, {}, dynamicTimeoutSec, maxRetries);
88
+ await agent.run(prompt, {
89
+ timeoutSec: dynamicTimeoutSec,
90
+ maxRetries: 1,
91
+ }, {});
89
92
  const agentReport = agent.generateReport();
90
93
  manager.markAgentFree(agentId);
91
94
  // Post-process: handle reports, progress, etc.
@@ -106,8 +109,8 @@ export async function runParallelProcessing(taskQueue, processor, context, optio
106
109
  }
107
110
  }
108
111
  };
109
- // Create agent pool
110
- manager.createAgentPool();
112
+ // Create agent pool with 100 (soft) turns cutoff
113
+ manager.createAgentPool({ softTurnLimit: 100 });
111
114
  // Start parallel processing
112
115
  const processingPromises = Array.from({ length: concurrency }, () => processTask());
113
116
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"concurrency.js","sourceRoot":"/","sources":["tasks/concurrency.ts"],"names":[],"mappings":"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","sourcesContent":["import { LocadexManager } from '../utils/locadexManager.js';\nimport { logger } from '../logging/logger.js';\nimport { exit } from '../utils/shutdown.js';\n\n/**\n * Interface for defining how to process tasks in parallel.\n * Separates task preparation (preProcess) from result handling (postProcess).\n *\n * @template TTask - The type of individual tasks being processed\n * @template TContext - The type of shared context/configuration\n */\nexport interface TaskProcessor<TTask, TContext> {\n /**\n * Prepares tasks for processing and generates the prompt for the AI agent.\n * Called before each batch is sent to an agent.\n *\n * @param tasks - Batch of tasks to process\n * @param context - Shared context containing configuration and state\n * @returns Promise that resolves to the prompt string for the AI agent\n */\n preProcess: (tasks: TTask[], context: TContext) => Promise<string>;\n\n /**\n * Handles the results after the AI agent completes processing.\n * Called after each batch is successfully processed.\n *\n * @param tasks - The batch of tasks that were processed\n * @param context - Shared context containing configuration and state\n * @param agentReport - The report/output generated by the AI agent\n */\n postProcess: (\n tasks: TTask[],\n context: TContext,\n agentReport: string\n ) => Promise<void>;\n}\n\n/**\n * Configuration options for parallel processing behavior.\n */\nexport interface ParallelProcessingOptions {\n /** Number of concurrent agents to run in parallel */\n concurrency: number;\n /** Number of tasks to process in each batch */\n batchSize: number;\n}\n\n/**\n * Executes tasks in parallel using a pool of agents with proper concurrency control.\n *\n * This is a generic parallel processing framework that handles:\n * - Task queue management with thread-safe access\n * - Agent pool creation and lifecycle management\n * - Error handling and abort signal propagation\n * - Proper cleanup and resource management\n *\n * @template TTask - The type of tasks to process (e.g., string, object, etc.)\n * @template TContext - The type of context passed to the processor functions\n *\n * @param taskQueue - Array of tasks to process. Will be consumed (mutated) during processing.\n * @param processor - Object implementing preProcess and postProcess methods for task handling\n * @param context - Context object passed to processor methods, containing shared state/config\n * @param options - Configuration for parallel processing (concurrency level, batch size)\n *\n * @throws {Error} If processing fails or is aborted\n *\n * @example\n * ```typescript\n * const processor: TaskProcessor<string, { config: Config }> = {\n * preProcess: async (files, context) => generatePrompt(files, context.config),\n * postProcess: async (files, context, report) => handleResults(files, report)\n * };\n *\n * await runParallelProcessing(\n * ['file1.ts', 'file2.ts'],\n * processor,\n * { config: myConfig },\n * { concurrency: 3, batchSize: 2 }\n * );\n * ```\n */\nexport async function runParallelProcessing<TTask, TContext>(\n taskQueue: TTask[],\n processor: TaskProcessor<TTask, TContext>,\n context: TContext,\n options: ParallelProcessingOptions,\n maxRetries: number = 1\n): Promise<void> {\n const { concurrency, batchSize } = options;\n const manager = LocadexManager.getInstance();\n\n const agentAbortController = manager.getAgentAbortController();\n let firstError: Error | null = null;\n\n // Mutex for task queue access\n let taskQueueMutex = Promise.resolve();\n\n // Helper function to safely get tasks from queue\n const getNextTasks = async (batchSize: number): Promise<TTask[]> => {\n return new Promise((resolve) => {\n taskQueueMutex = taskQueueMutex.then(() => {\n const tasks = taskQueue.splice(0, batchSize);\n resolve(tasks);\n });\n });\n };\n\n const processTask = async (): Promise<void> => {\n while (taskQueue.length > 0 && !agentAbortController.signal.aborted) {\n // Check if we should abort early\n if (agentAbortController.signal.aborted) {\n return;\n }\n\n // Get an available agent atomically\n const agentInfo = await manager.getAvailableAgent();\n if (!agentInfo) {\n // No available agents, wait a bit (but check for abort)\n await new Promise((resolve) => {\n const timeout = global.setTimeout(resolve, 100);\n agentAbortController.signal.addEventListener('abort', () => {\n global.clearTimeout(timeout);\n resolve(undefined);\n });\n });\n continue;\n }\n\n const { id: agentId, agent } = agentInfo;\n\n // Get the next batch of tasks (thread-safe)\n const tasks = await getNextTasks(batchSize);\n if (tasks.length === 0) {\n manager.markAgentFree(agentId);\n break;\n }\n\n logger.debugMessage(`Using agent ${agentId} for ${tasks.length} tasks.`);\n\n // Process tasks using the provided processor\n try {\n // Pre-process: generate prompt\n const prompt = await processor.preProcess(tasks, context);\n\n // dynamic timeout based on the number of tasks\n const dynamicTimeoutSec = manager.getTimeoutFactor() * tasks.length;\n\n // Claude call with timeout and retry (handled inside agent.run)\n await agent.run(prompt, {}, dynamicTimeoutSec, maxRetries);\n\n const agentReport = agent.generateReport();\n manager.markAgentFree(agentId);\n\n // Post-process: handle reports, progress, etc.\n await processor.postProcess(tasks, context, agentReport);\n } catch (error) {\n // Check if this is an abort\n if (agentAbortController.signal.aborted) {\n return;\n }\n\n // Capture the first error and signal all other agents to abort\n if (!firstError) {\n firstError = new Error(\n `Error in claude parallel process (${agentId}): ${error}`\n );\n logger.debugMessage(firstError.message);\n }\n await exit(1); // Exit this agent's processing immediately\n return;\n }\n }\n };\n\n // Create agent pool\n manager.createAgentPool();\n\n // Start parallel processing\n const processingPromises = Array.from({ length: concurrency }, () =>\n processTask()\n );\n\n try {\n await Promise.all(processingPromises);\n } catch (error) {\n // Check if this is an abort\n if (agentAbortController.signal.aborted) {\n throw new Error('Processing aborted');\n }\n\n // This shouldn't happen since we handle errors within processTask\n logger.debugMessage(`Unexpected error in parallel processing: ${error}`);\n if (!firstError) {\n firstError = new Error(\n `Unexpected error in parallel processing: ${error}`\n );\n }\n throw firstError;\n }\n\n if (firstError) {\n throw firstError;\n }\n}\n"]}
1
+ {"version":3,"file":"concurrency.js","sourceRoot":"/","sources":["tasks/concurrency.ts"],"names":[],"mappings":"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","sourcesContent":["import { LocadexManager } from '../utils/locadexManager.js';\nimport { logger } from '../logging/logger.js';\nimport { exit } from '../utils/shutdown.js';\n\n/**\n * Interface for defining how to process tasks in parallel.\n * Separates task preparation (preProcess) from result handling (postProcess).\n *\n * @template TTask - The type of individual tasks being processed\n * @template TContext - The type of shared context/configuration\n */\nexport interface TaskProcessor<TTask, TContext> {\n /**\n * Prepares tasks for processing and generates the prompt for the AI agent.\n * Called before each batch is sent to an agent.\n *\n * @param tasks - Batch of tasks to process\n * @param context - Shared context containing configuration and state\n * @returns Promise that resolves to the prompt string for the AI agent\n */\n preProcess: (tasks: TTask[], context: TContext) => Promise<string>;\n\n /**\n * Handles the results after the AI agent completes processing.\n * Called after each batch is successfully processed.\n *\n * @param tasks - The batch of tasks that were processed\n * @param context - Shared context containing configuration and state\n * @param agentReport - The report/output generated by the AI agent\n */\n postProcess: (\n tasks: TTask[],\n context: TContext,\n agentReport: string\n ) => Promise<void>;\n}\n\n/**\n * Configuration options for parallel processing behavior.\n */\nexport interface ParallelProcessingOptions {\n /** Number of concurrent agents to run in parallel */\n concurrency: number;\n /** Number of tasks to process in each batch */\n batchSize: number;\n}\n\n/**\n * Executes tasks in parallel using a pool of agents with proper concurrency control.\n *\n * This is a generic parallel processing framework that handles:\n * - Task queue management with thread-safe access\n * - Agent pool creation and lifecycle management\n * - Error handling and abort signal propagation\n * - Proper cleanup and resource management\n *\n * @template TTask - The type of tasks to process (e.g., string, object, etc.)\n * @template TContext - The type of context passed to the processor functions\n *\n * @param taskQueue - Array of tasks to process. Will be consumed (mutated) during processing.\n * @param processor - Object implementing preProcess and postProcess methods for task handling\n * @param context - Context object passed to processor methods, containing shared state/config\n * @param options - Configuration for parallel processing (concurrency level, batch size)\n *\n * @throws {Error} If processing fails or is aborted\n *\n * @example\n * ```typescript\n * const processor: TaskProcessor<string, { config: Config }> = {\n * preProcess: async (files, context) => generatePrompt(files, context.config),\n * postProcess: async (files, context, report) => handleResults(files, report)\n * };\n *\n * await runParallelProcessing(\n * ['file1.ts', 'file2.ts'],\n * processor,\n * { config: myConfig },\n * { concurrency: 3, batchSize: 2 }\n * );\n * ```\n */\nexport async function runParallelProcessing<TTask, TContext>(\n taskQueue: TTask[],\n processor: TaskProcessor<TTask, TContext>,\n context: TContext,\n options: ParallelProcessingOptions,\n maxRetries: number = 1\n): Promise<void> {\n const { concurrency, batchSize } = options;\n const manager = LocadexManager.getInstance();\n\n const agentAbortController = manager.getAgentAbortController();\n let firstError: Error | null = null;\n\n // Mutex for task queue access\n let taskQueueMutex = Promise.resolve();\n\n // Helper function to safely get tasks from queue\n const getNextTasks = async (batchSize: number): Promise<TTask[]> => {\n return new Promise((resolve) => {\n taskQueueMutex = taskQueueMutex.then(() => {\n const tasks = taskQueue.splice(0, batchSize);\n resolve(tasks);\n });\n });\n };\n\n const processTask = async (): Promise<void> => {\n while (taskQueue.length > 0 && !agentAbortController.signal.aborted) {\n // Check if we should abort early\n if (agentAbortController.signal.aborted) {\n return;\n }\n\n // Get an available agent atomically\n const agentInfo = await manager.getAvailableAgent();\n if (!agentInfo) {\n // No available agents, wait a bit (but check for abort)\n await new Promise((resolve) => {\n const timeout = global.setTimeout(resolve, 100);\n agentAbortController.signal.addEventListener('abort', () => {\n global.clearTimeout(timeout);\n resolve(undefined);\n });\n });\n continue;\n }\n\n const { id: agentId, agent } = agentInfo;\n\n // Get the next batch of tasks (thread-safe)\n const tasks = await getNextTasks(batchSize);\n if (tasks.length === 0) {\n manager.markAgentFree(agentId);\n break;\n }\n\n logger.debugMessage(`Using agent ${agentId} for ${tasks.length} tasks.`);\n\n // Process tasks using the provided processor\n try {\n // Pre-process: generate prompt\n const prompt = await processor.preProcess(tasks, context);\n\n // dynamic timeout based on the number of tasks\n const dynamicTimeoutSec = manager.getTimeoutFactor() * tasks.length;\n\n // Claude call with timeout and retry (handled inside agent.run)\n await agent.run(\n prompt,\n {\n timeoutSec: dynamicTimeoutSec,\n maxRetries: 1,\n },\n {}\n );\n\n const agentReport = agent.generateReport();\n manager.markAgentFree(agentId);\n\n // Post-process: handle reports, progress, etc.\n await processor.postProcess(tasks, context, agentReport);\n } catch (error) {\n // Check if this is an abort\n if (agentAbortController.signal.aborted) {\n return;\n }\n\n // Capture the first error and signal all other agents to abort\n if (!firstError) {\n firstError = new Error(\n `Error in claude parallel process (${agentId}): ${error}`\n );\n logger.debugMessage(firstError.message);\n }\n await exit(1); // Exit this agent's processing immediately\n return;\n }\n }\n };\n\n // Create agent pool with 100 (soft) turns cutoff\n manager.createAgentPool({ softTurnLimit: 100 });\n\n // Start parallel processing\n const processingPromises = Array.from({ length: concurrency }, () =>\n processTask()\n );\n\n try {\n await Promise.all(processingPromises);\n } catch (error) {\n // Check if this is an abort\n if (agentAbortController.signal.aborted) {\n throw new Error('Processing aborted');\n }\n\n // This shouldn't happen since we handle errors within processTask\n logger.debugMessage(`Unexpected error in parallel processing: ${error}`);\n if (!firstError) {\n firstError = new Error(\n `Unexpected error in parallel processing: ${error}`\n );\n }\n throw firstError;\n }\n\n if (firstError) {\n throw firstError;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.d.ts","sourceRoot":"/","sources":["tasks/i18n.ts"],"names":[],"mappings":"AAuBA,wBAAsB,QAAQ,kBAyN7B"}
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"/","sources":["tasks/i18n.ts"],"names":[],"mappings":"AAuBA,wBAAsB,QAAQ,kBAiO7B"}
@@ -105,12 +105,16 @@ export async function i18nTask() {
105
105
  // // Always clean up the file list when done, regardless of success or failure
106
106
  // cleanUp(stateFilePath);
107
107
  // Create a clean agent for cleanup
108
- const cleanupAgent = manager.createSingleAgent('claude_cleanup_agent');
108
+ const cleanupAgent = manager.createSingleAgent('claude_cleanup_agent', {});
109
109
  logger.initializeSpinner();
110
110
  logger.spinner.start('Fixing errors...');
111
111
  const fixPrompt = getFixPrompt(manager.appDirectory);
112
112
  try {
113
- await cleanupAgent.run(fixPrompt, { maxTurns: 200 }, 1000, 3);
113
+ await cleanupAgent.run(fixPrompt, {
114
+ maxTurns: 200,
115
+ timeoutSec: 300,
116
+ maxRetries: 1,
117
+ }, {});
114
118
  reports.push(`## Fixed errors\n${cleanupAgent.generateReport()}`);
115
119
  }
116
120
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.js","sourceRoot":"/","sources":["tasks/i18n.ts"],"names":[],"mappings":"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","sourcesContent":["import { createSpinner } from '../logging/console.js';\nimport { allMcpPrompt } from '../prompts/system.js';\nimport { exit } from '../utils/shutdown.js';\nimport { logger } from '../logging/logger.js';\nimport { LocadexManager } from '../utils/locadexManager.js';\nimport {\n addFilesToManager,\n markFileAsEdited,\n markFileAsInProgress,\n} from '../utils/dag/getFiles.js';\nimport { runParallelProcessing, TaskProcessor } from './concurrency.js';\nimport { outro } from '@clack/prompts';\nimport chalk from 'chalk';\nimport { appendFileSync } from 'node:fs';\nimport { detectFormatter, formatFiles } from 'gtx-cli/hooks/postProcess';\nimport path from 'node:path';\nimport { updateLockfile, cleanupLockfile } from '../utils/lockfile.js';\nimport { installClaudeCode } from '../utils/packages/installPackage.js';\nimport { extractFiles } from '../utils/dag/extractFiles.js';\nimport { Dag } from '../utils/dag/createDag.js';\nimport { getPackageJson, isPackageInstalled } from 'gtx-cli/utils/packageJson';\nimport { deleteAddedFiles } from '../utils/fs/git.js';\n\nexport async function i18nTask() {\n const manager = LocadexManager.getInstance();\n // have to use the package.json from the appDir\n const packageJson = await getPackageJson(manager.appDirectory);\n const isUsingGTNext = packageJson\n ? isPackageInstalled('gt-next', packageJson)\n : false;\n if (!isUsingGTNext) {\n logger.error(\n `gt-next not detected in ${manager.appDirectory}. Please specify the correct app directory with the --app-dir flag, or ensure that gt-next is correctly installed in the project.`\n );\n await exit(1);\n }\n\n // Install claude-code if not installed\n await installClaudeCode();\n\n logger.debugMessage('App directory: ' + manager.appDirectory);\n logger.debugMessage('Root directory: ' + manager.rootDirectory);\n\n // Init message\n const spinner = createSpinner();\n spinner.start('Initializing Locadex...');\n\n const { files, dag } = extractFiles(manager);\n\n if (files.length === 0) {\n spinner.stop('No files have changed since last run');\n outro(chalk.green('✅ Locadex i18n complete - no changes detected!'));\n await exit(0);\n }\n\n const filesStateFilePath = manager.getFilesStateFilePath();\n const concurrency = manager.getMaxConcurrency();\n const batchSize = manager.getBatchSize();\n\n // Create the list of files (aka tasks) to process\n const taskQueue = Array.from(files);\n\n // Add files to manager\n const stateFilePath = addFilesToManager(filesStateFilePath, taskQueue);\n spinner.stop('Locadex initialized');\n\n logger.verboseMessage(`Processing ${files.length} modified files`);\n logger.debugMessage(`Track progress here: ${stateFilePath}`);\n logger.debugMessage(`Order:\\n${taskQueue.join('\\n')}`);\n\n logger.message(`Using ${concurrency} concurrent agents`);\n logger.initializeProgressBar(taskQueue.length);\n\n const fileProcessingStartTime = Date.now();\n logger.progressBar.start(`Processing ${taskQueue.length} files...`);\n\n // Shared reports array for collecting results\n const reports: string[] = [];\n\n // Create i18n task processor\n const i18nProcessor: TaskProcessor<\n string,\n {\n dag: Dag;\n files: string[];\n filesStateFilePath: string;\n }\n > = {\n preProcess: async (files, context) => {\n const { dag, filesStateFilePath } = context;\n logger.debugMessage(`Files: ${files.join(', ')}`);\n // Mark tasks as in progress\n await Promise.all(\n files.map((file) => markFileAsInProgress(file, filesStateFilePath))\n );\n\n // Construct prompt\n const dependencies = Object.fromEntries(\n files.map((file) => [\n file,\n Array.from(new Set(dag.getDependencies(file))).map(String),\n ])\n );\n const dependents = Object.fromEntries(\n files.map((file) => [\n file,\n Array.from(new Set(dag.getDependents(file))).map(String),\n ])\n );\n\n return getPrompt({\n targetFile: files,\n dependencyFiles: dependencies,\n dependentFiles: dependents,\n });\n },\n postProcess: async (files, context, agentReport) => {\n const { filesStateFilePath } = context;\n\n // Mark tasks as complete\n await Promise.all(\n files.map((task) => markFileAsEdited(task, filesStateFilePath))\n );\n\n // Add agent report\n reports.push(agentReport);\n\n // Update progress bar\n logger.progressBar.advance(\n files.length,\n `Processed ${Number(((reports.length * files.length) / files.length) * 100).toFixed(2)}% of files`\n );\n\n // Update stats\n manager.stats.updateStats({\n newProcessedFiles: files.length,\n });\n },\n };\n\n // Run parallel processing\n await runParallelProcessing(\n Array.from(taskQueue),\n i18nProcessor,\n { dag, files, filesStateFilePath },\n {\n concurrency,\n batchSize,\n },\n 1\n );\n\n if (manager.isAborted()) {\n return;\n }\n\n logger.progressBar.stop(\n `Processed ${files.length} files [${Math.round(\n (Date.now() - fileProcessingStartTime) / 1000\n )}s]`\n );\n\n // TODO: uncomment\n // // Always clean up the file list when done, regardless of success or failure\n // cleanUp(stateFilePath);\n\n // Create a clean agent for cleanup\n const cleanupAgent = manager.createSingleAgent('claude_cleanup_agent');\n\n logger.initializeSpinner();\n logger.spinner.start('Fixing errors...');\n const fixPrompt = getFixPrompt(manager.appDirectory);\n try {\n await cleanupAgent.run(fixPrompt, { maxTurns: 200 }, 1000, 3);\n reports.push(`## Fixed errors\\n${cleanupAgent.generateReport()}`);\n } catch (error) {\n logger.debugMessage(\n `[claude_cleanup_agent] Fixing errors failed: ${error}`\n );\n manager.stats.recordTelemetry(false);\n outro(chalk.red('❌ Locadex i18n failed!'));\n await exit(1);\n return;\n }\n logger.spinner.stop('Fixed errors');\n\n // Generate report\n const reportSummary = `# Summary of locadex i18n changes\n${reports.join('\\n')}`;\n const summaryFilePath = path.join(\n manager.getLogDirectory(),\n 'locadex-report.md'\n );\n appendFileSync(summaryFilePath, reportSummary);\n logger.step(`Saved summary of changes to: ${summaryFilePath}`);\n\n // cleanup\n const formatter = await detectFormatter();\n if (formatter) {\n await formatFiles(files, formatter);\n }\n\n const lockfilePath = manager.getLockFilePath();\n\n // Update lockfile with processed files\n updateLockfile(files, lockfilePath, manager.rootDirectory);\n\n // Clean up stale entries from lockfile\n cleanupLockfile(lockfilePath, manager.rootDirectory);\n\n logger.message(chalk.dim(`Updated lockfile with ${files.length} files`));\n\n deleteAddedFiles([\n path.relative(manager.rootDirectory, manager.locadexDirectory),\n ]);\n\n logger.info(\n chalk.dim(\n `Total Cost: $${manager.stats.getStats().totalCost.toFixed(2)}\nTotal wall time: ${Math.round(\n (Date.now() - manager.stats.getStats().startTime) / 1000\n )}s\nTotal files processed: ${manager.stats.getStats().processedFiles}`\n )\n );\n\n const finalStats = manager.stats.getStats();\n\n // Record telemetry for final stats\n manager.stats.recordTelemetry(true);\n\n logger.verboseMessage(\n `Total input tokens: ${finalStats.inputTokens}\nTotal cached input tokens: ${finalStats.cachedInputTokens}\nTotal output tokens: ${finalStats.outputTokens}\nTotal turns: ${finalStats.turns}`\n );\n\n outro(chalk.green('✅ Locadex i18n complete!'));\n await exit(0);\n}\n\nfunction getPrompt({\n targetFile,\n dependencyFiles,\n dependentFiles,\n}: {\n targetFile: string[];\n dependencyFiles: Record<string, string[]>;\n dependentFiles: Record<string, string[]>;\n}) {\n const prompt = `# Task: Internationalize the target file(s) using gt-next.\n\n## INSTRUCTIONS\n\n- You are given a list of target files and their corresponding dependency/dependent files.\n- The project is already setup for internationalization. Do not try to setup the project again for i18n.\n\n## Workflow:\n1. **Gather context** Read the target files closely (you should not have to read the dependency/dependent files).\n2. **Evaluate if i18n is necessary** Evaluate if the target files need to be internationalized using gt-next \n - If the target files have no relevant content, are already internationalized, or contain build-time code (e.g. nextjs plugins) they should never be internationalized.\n**IMPORTANT**: IF NONE OF THE TARGET FILES NEED TO BE INTERNATIONALIZED, YOUR TASK IS COMPLETE AND YOU MAY RETURN.\n3. **Identify the tools to use** Given the contents of the files, ask yourself which tools and guides you need to use to get the necessary knowledge to internationalize the target files. Here are some helpful questions to evaluate for tool selection:\n - 3.a. Does this file contain a component? If so, is it a server-side component or a client-side component?\n - 3.b. Is the content that needs to be i18ned being used in this same file, or is it being used in another file?\n - 3.c. Is there any string interpolation that needs to be i18ned?\n - 3.d. Is there any conditional logic or rendering that needs to be i18ned?\n - 3.e. Is the content that needs to be i18ned HTML/JSX or a string?\n4. **Internationalize** You now have the necessary knowledge. Internationalize the files using the information from the tools provided to you.\n - 4.a. Do not worry about running tsc. We will do that later.\n\n## RULES:\n- ALWAYS use the <T> component to internationalize HTML/JSX content.\n- ALWAYS use getGT() or useGT() and getDict() or useDict() to internationalize string content (strings created with '', \"\", or \\`\\`).\n - When possible, avoid using getDict() or useDict(); getGT() and useGT() are preferred.\n- DO NOT internationalize non-user facing content or content that is functional, such as ids, class names, error strings, logical strings, etc.\n- Do not add i18n middleware to the app.\n- When adding 'useGT()' or 'useDict()' to a client component, you must add 'use client' to the top of the file.\n- Always adhere to the guides provided via the 'mcp__locadex__' tools.\n - These guides provide additional knowledge about how to internationalize the content.\n- Minimize the footprint of your changes.\n- Focus on internationalizing the content of the target files.\n- NEVER move internationalized content to a different file. All content MUST remain in the same file where it came from.\n- NEVER CREATE OR DELETE ANY FILES (especially .bak files)\n- Internationalize all user facing content in the target files. \n- NEVER EDIT FILES THAT ARE NOT GIVEN TO YOU.\n\n## TARGET FILE INFORMATION\n${targetFile.map(\n (file, index) => `\nTARGET FILE ${index + 1}:\n${file}\n\nDEPENDENCY FILES (files imported by target file ${index + 1}):\n${dependencyFiles[file].length > 0 ? ` ${dependencyFiles[file].join(', ')}` : 'none'}\n\nDEPENDENT FILES (files that import target file ${index + 1}):\n${dependentFiles[file].length > 0 ? ` ${dependentFiles[file].join(', ')}` : 'none'}\n`\n)}\n\n---\n\n## MCP TOOLS\n\n${allMcpPrompt}\n\n## Final output\n- When you are done, please return a brief summary of the files you modified, following this format.\n- **DO NOT** include any other text in your response. \n- If there were issues with some files, please include the issues in the list of changes for that file.\n\n[file 1 path]\n- List of changes to file 1\n`;\n\n return prompt;\n}\n\n// check (dry run and ts check) should be at the end\n\nfunction getFixPrompt(appDirectory: string) {\n const prompt = `# Task: Fix internationalization errors in the project.\n\n## INSTRUCTIONS\n\nPreviously, you helped me internationalize a set of files in this project.\nYour new task is as follows:\n\n1. Run the gt-next validator.\n2. Fix all errors output by the gt-next validator.\n3. Whenever you are finished with your changes, run the gt-next validator.\n4. Repeat steps 1-3 until there are no more errors, or until you believe that you have fixed all errors.\n\n## RULES:\n- ONLY modify files that are relevant to the internationalization of the project.\n- ONLY fix errors that result from your current or previous implementation.\n- Resolve unused imports from 'gt-next'. \n - In particular, if a file contains user-facing content that should be internationalized and is not, you should internationalize it.\n- Resolve missing imports from 'gt-next'. If a file is missing an import from 'gt-next', add it.\n\nTo run the gt-next validator, run the following command from the app root:\n'npx locadex translate --dry-run'\nThe app root is: \"${appDirectory}\"\n\n## MCP TOOLS\n\n${allMcpPrompt}\n\n## Final output\n- When you are done, please return a brief summary of the files you modified, following this format.\n- **DO NOT** include any other text in your response. \n- If there were issues with some files, please include the issues in the list of changes for that file.\n\n[file 1 path]\n- List of changes to file 1\n`;\n\n return prompt;\n}\n"]}
1
+ {"version":3,"file":"i18n.js","sourceRoot":"/","sources":["tasks/i18n.ts"],"names":[],"mappings":"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","sourcesContent":["import { createSpinner } from '../logging/console.js';\nimport { allMcpPrompt } from '../prompts/system.js';\nimport { exit } from '../utils/shutdown.js';\nimport { logger } from '../logging/logger.js';\nimport { LocadexManager } from '../utils/locadexManager.js';\nimport {\n addFilesToManager,\n markFileAsEdited,\n markFileAsInProgress,\n} from '../utils/dag/getFiles.js';\nimport { runParallelProcessing, TaskProcessor } from './concurrency.js';\nimport { outro } from '@clack/prompts';\nimport chalk from 'chalk';\nimport { appendFileSync } from 'node:fs';\nimport { detectFormatter, formatFiles } from 'gtx-cli/hooks/postProcess';\nimport path from 'node:path';\nimport { updateLockfile, cleanupLockfile } from '../utils/lockfile.js';\nimport { installClaudeCode } from '../utils/packages/installPackage.js';\nimport { extractFiles } from '../utils/dag/extractFiles.js';\nimport { Dag } from '../utils/dag/createDag.js';\nimport { getPackageJson, isPackageInstalled } from 'gtx-cli/utils/packageJson';\nimport { deleteAddedFiles } from '../utils/fs/git.js';\n\nexport async function i18nTask() {\n const manager = LocadexManager.getInstance();\n // have to use the package.json from the appDir\n const packageJson = await getPackageJson(manager.appDirectory);\n const isUsingGTNext = packageJson\n ? isPackageInstalled('gt-next', packageJson)\n : false;\n if (!isUsingGTNext) {\n logger.error(\n `gt-next not detected in ${manager.appDirectory}. Please specify the correct app directory with the --app-dir flag, or ensure that gt-next is correctly installed in the project.`\n );\n await exit(1);\n }\n\n // Install claude-code if not installed\n await installClaudeCode();\n\n logger.debugMessage('App directory: ' + manager.appDirectory);\n logger.debugMessage('Root directory: ' + manager.rootDirectory);\n\n // Init message\n const spinner = createSpinner();\n spinner.start('Initializing Locadex...');\n\n const { files, dag } = extractFiles(manager);\n\n if (files.length === 0) {\n spinner.stop('No files have changed since last run');\n outro(chalk.green('✅ Locadex i18n complete - no changes detected!'));\n await exit(0);\n }\n\n const filesStateFilePath = manager.getFilesStateFilePath();\n const concurrency = manager.getMaxConcurrency();\n const batchSize = manager.getBatchSize();\n\n // Create the list of files (aka tasks) to process\n const taskQueue = Array.from(files);\n\n // Add files to manager\n const stateFilePath = addFilesToManager(filesStateFilePath, taskQueue);\n spinner.stop('Locadex initialized');\n\n logger.verboseMessage(`Processing ${files.length} modified files`);\n logger.debugMessage(`Track progress here: ${stateFilePath}`);\n logger.debugMessage(`Order:\\n${taskQueue.join('\\n')}`);\n\n logger.message(`Using ${concurrency} concurrent agents`);\n logger.initializeProgressBar(taskQueue.length);\n\n const fileProcessingStartTime = Date.now();\n logger.progressBar.start(`Processing ${taskQueue.length} files...`);\n\n // Shared reports array for collecting results\n const reports: string[] = [];\n\n // Create i18n task processor\n const i18nProcessor: TaskProcessor<\n string,\n {\n dag: Dag;\n files: string[];\n filesStateFilePath: string;\n }\n > = {\n preProcess: async (files, context) => {\n const { dag, filesStateFilePath } = context;\n logger.debugMessage(`Files: ${files.join(', ')}`);\n // Mark tasks as in progress\n await Promise.all(\n files.map((file) => markFileAsInProgress(file, filesStateFilePath))\n );\n\n // Construct prompt\n const dependencies = Object.fromEntries(\n files.map((file) => [\n file,\n Array.from(new Set(dag.getDependencies(file))).map(String),\n ])\n );\n const dependents = Object.fromEntries(\n files.map((file) => [\n file,\n Array.from(new Set(dag.getDependents(file))).map(String),\n ])\n );\n\n return getPrompt({\n targetFile: files,\n dependencyFiles: dependencies,\n dependentFiles: dependents,\n });\n },\n postProcess: async (files, context, agentReport) => {\n const { filesStateFilePath } = context;\n\n // Mark tasks as complete\n await Promise.all(\n files.map((task) => markFileAsEdited(task, filesStateFilePath))\n );\n\n // Add agent report\n reports.push(agentReport);\n\n // Update progress bar\n logger.progressBar.advance(\n files.length,\n `Processed ${Number(((reports.length * files.length) / files.length) * 100).toFixed(2)}% of files`\n );\n\n // Update stats\n manager.stats.updateStats({\n newProcessedFiles: files.length,\n });\n },\n };\n\n // Run parallel processing\n await runParallelProcessing(\n Array.from(taskQueue),\n i18nProcessor,\n { dag, files, filesStateFilePath },\n {\n concurrency,\n batchSize,\n },\n 1\n );\n\n if (manager.isAborted()) {\n return;\n }\n\n logger.progressBar.stop(\n `Processed ${files.length} files [${Math.round(\n (Date.now() - fileProcessingStartTime) / 1000\n )}s]`\n );\n\n // TODO: uncomment\n // // Always clean up the file list when done, regardless of success or failure\n // cleanUp(stateFilePath);\n\n // Create a clean agent for cleanup\n const cleanupAgent = manager.createSingleAgent('claude_cleanup_agent', {});\n\n logger.initializeSpinner();\n logger.spinner.start('Fixing errors...');\n const fixPrompt = getFixPrompt(manager.appDirectory);\n try {\n await cleanupAgent.run(\n fixPrompt,\n {\n maxTurns: 200,\n timeoutSec: 300,\n maxRetries: 1,\n },\n {}\n );\n reports.push(`## Fixed errors\\n${cleanupAgent.generateReport()}`);\n } catch (error) {\n logger.debugMessage(\n `[claude_cleanup_agent] Fixing errors failed: ${error}`\n );\n manager.stats.recordTelemetry(false);\n outro(chalk.red('❌ Locadex i18n failed!'));\n await exit(1);\n return;\n }\n logger.spinner.stop('Fixed errors');\n\n // Generate report\n const reportSummary = `# Summary of locadex i18n changes\n${reports.join('\\n')}`;\n const summaryFilePath = path.join(\n manager.getLogDirectory(),\n 'locadex-report.md'\n );\n appendFileSync(summaryFilePath, reportSummary);\n logger.step(`Saved summary of changes to: ${summaryFilePath}`);\n\n // cleanup\n const formatter = await detectFormatter();\n if (formatter) {\n await formatFiles(files, formatter);\n }\n\n const lockfilePath = manager.getLockFilePath();\n\n // Update lockfile with processed files\n updateLockfile(files, lockfilePath, manager.rootDirectory);\n\n // Clean up stale entries from lockfile\n cleanupLockfile(lockfilePath, manager.rootDirectory);\n\n logger.message(chalk.dim(`Updated lockfile with ${files.length} files`));\n\n deleteAddedFiles([\n path.relative(manager.rootDirectory, manager.locadexDirectory),\n ]);\n\n logger.info(\n chalk.dim(\n `Total Cost: $${manager.stats.getStats().totalCost.toFixed(2)}\nTotal wall time: ${Math.round(\n (Date.now() - manager.stats.getStats().startTime) / 1000\n )}s\nTotal files processed: ${manager.stats.getStats().processedFiles}`\n )\n );\n\n const finalStats = manager.stats.getStats();\n\n // Record telemetry for final stats\n manager.stats.recordTelemetry(true);\n\n logger.verboseMessage(\n `Total input tokens: ${finalStats.inputTokens}\nTotal cached input tokens: ${finalStats.cachedInputTokens}\nTotal output tokens: ${finalStats.outputTokens}\nTotal turns: ${finalStats.turns}`\n );\n\n outro(chalk.green('✅ Locadex i18n complete!'));\n await exit(0);\n}\n\nfunction getPrompt({\n targetFile,\n dependencyFiles,\n dependentFiles,\n}: {\n targetFile: string[];\n dependencyFiles: Record<string, string[]>;\n dependentFiles: Record<string, string[]>;\n}) {\n const prompt = `# Task: Internationalize the target file(s) using gt-next.\n\n## INSTRUCTIONS\n\n- You are given a list of target files and their corresponding dependency/dependent files.\n- The project is already setup for internationalization. Do not try to setup the project again for i18n.\n\n## Workflow:\n1. **Gather context** Read the target files closely (you should not have to read the dependency/dependent files).\n2. **Evaluate if i18n is necessary** Evaluate if the target files need to be internationalized using gt-next \n - If the target files have no relevant content, are already internationalized, or contain build-time code (e.g. nextjs plugins) they should never be internationalized.\n**IMPORTANT**: IF NONE OF THE TARGET FILES NEED TO BE INTERNATIONALIZED, YOUR TASK IS COMPLETE AND YOU MAY RETURN.\n3. **Identify the tools to use** Given the contents of the files, ask yourself which tools and guides you need to use to get the necessary knowledge to internationalize the target files. Here are some helpful questions to evaluate for tool selection:\n - 3.a. Does this file contain a component? If so, is it a server-side component or a client-side component?\n - 3.b. Is the content that needs to be i18ned being used in this same file, or is it being used in another file?\n - 3.c. Is there any string interpolation that needs to be i18ned?\n - 3.d. Is there any conditional logic or rendering that needs to be i18ned?\n - 3.e. Is the content that needs to be i18ned HTML/JSX or a string?\n4. **Internationalize** You now have the necessary knowledge. Internationalize the files using the information from the tools provided to you.\n - 4.a. Do not worry about running tsc. We will do that later.\n\n## RULES:\n- ALWAYS use the <T> component to internationalize HTML/JSX content.\n- ALWAYS use getGT() or useGT() and getDict() or useDict() to internationalize string content (strings created with '', \"\", or \\`\\`).\n - When possible, avoid using getDict() or useDict(); getGT() and useGT() are preferred.\n- DO NOT internationalize non-user facing content or content that is functional, such as ids, class names, error strings, logical strings, etc.\n- Do not add i18n middleware to the app.\n- When adding 'useGT()' or 'useDict()' to a client component, you must add 'use client' to the top of the file.\n- Always adhere to the guides provided via the 'mcp__locadex__' tools.\n - These guides provide additional knowledge about how to internationalize the content.\n- Minimize the footprint of your changes.\n- Focus on internationalizing the content of the target files.\n- NEVER move internationalized content to a different file. All content MUST remain in the same file where it came from.\n- NEVER CREATE OR DELETE ANY FILES (especially .bak files)\n- Internationalize all user facing content in the target files. \n- NEVER EDIT FILES THAT ARE NOT GIVEN TO YOU.\n\n## TARGET FILE INFORMATION\n${targetFile.map(\n (file, index) => `\nTARGET FILE ${index + 1}:\n${file}\n\nDEPENDENCY FILES (files imported by target file ${index + 1}):\n${dependencyFiles[file].length > 0 ? ` ${dependencyFiles[file].join(', ')}` : 'none'}\n\nDEPENDENT FILES (files that import target file ${index + 1}):\n${dependentFiles[file].length > 0 ? ` ${dependentFiles[file].join(', ')}` : 'none'}\n`\n)}\n\n---\n\n## MCP TOOLS\n\n${allMcpPrompt}\n\n## Final output\n- When you are done, please return a brief summary of the files you modified, following this format.\n- **DO NOT** include any other text in your response. \n- If there were issues with some files, please include the issues in the list of changes for that file.\n\n[file 1 path]\n- List of changes to file 1\n`;\n\n return prompt;\n}\n\n// check (dry run and ts check) should be at the end\n\nfunction getFixPrompt(appDirectory: string) {\n const prompt = `# Task: Fix internationalization errors in the project.\n\n## INSTRUCTIONS\n\nPreviously, you helped me internationalize a set of files in this project.\nYour new task is as follows:\n\n1. Run the gt-next validator.\n2. Fix all errors output by the gt-next validator.\n3. Whenever you are finished with your changes, run the gt-next validator.\n4. Repeat steps 1-3 until there are no more errors, or until you believe that you have fixed all errors.\n\n## RULES:\n- ONLY modify files that are relevant to the internationalization of the project.\n- ONLY fix errors that result from your current or previous implementation.\n- Resolve unused imports from 'gt-next'. \n - In particular, if a file contains user-facing content that should be internationalized and is not, you should internationalize it.\n- Resolve missing imports from 'gt-next'. If a file is missing an import from 'gt-next', add it.\n\nTo run the gt-next validator, run the following command from the app root:\n'npx locadex translate --dry-run'\nThe app root is: \"${appDirectory}\"\n\n## MCP TOOLS\n\n${allMcpPrompt}\n\n## Final output\n- When you are done, please return a brief summary of the files you modified, following this format.\n- **DO NOT** include any other text in your response. \n- If there were issues with some files, please include the issues in the list of changes for that file.\n\n[file 1 path]\n- List of changes to file 1\n`;\n\n return prompt;\n}\n"]}
@@ -100,11 +100,15 @@ async function setupLocaleSelector() {
100
100
  logger.spinner.start('Creating locale selector...');
101
101
  // Create agent
102
102
  const manager = LocadexManager.getInstance();
103
- const agent = manager.createSingleAgent('claude_setup_agent');
103
+ const agent = manager.createSingleAgent('claude_setup_agent', {});
104
104
  // Fix prompt
105
105
  const localeSelectorPrompt = getLocaleSelectorPrompt(manager.appDirectory);
106
106
  try {
107
- await agent.run(localeSelectorPrompt, { maxTurns: 50 }, 1000, 3);
107
+ await agent.run(localeSelectorPrompt, {
108
+ maxTurns: 50,
109
+ timeoutSec: 120,
110
+ maxRetries: 1,
111
+ }, {});
108
112
  // Generate report
109
113
  const report = agent.generateReport();
110
114
  const reportSummary = `# Summary of locadex setup changes
@@ -1 +1 @@
1
- {"version":3,"file":"setup.js","sourceRoot":"/","sources":["tasks/setup.ts"],"names":[],"mappings":"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","sourcesContent":["import { createSpinner, promptConfirm } from '../logging/console.js';\nimport {\n getPackageJson,\n isPackageInstalled,\n updatePackageJson,\n} from 'gtx-cli/utils/packageJson';\nimport { getPackageManager } from 'gtx-cli/utils/packageManager';\nimport { installPackage } from 'gtx-cli/utils/installPackage';\nimport chalk from 'chalk';\nimport { logger } from '../logging/logger.js';\nimport { findFilepaths } from '../utils/fs/findConfigs.js';\nimport { wrapContentNext } from 'gtx-cli/next/parse/wrapContent';\nimport { handleInitGT } from 'gtx-cli/next/parse/handleInitGT';\nimport { detectFormatter, formatFiles } from 'gtx-cli/hooks/postProcess';\nimport { createOrUpdateConfig } from 'gtx-cli/fs/config/setupConfig';\nimport { i18nTask } from '../tasks/i18n.js';\nimport { getNextDirectories } from '../utils/fs/getFiles.js';\nimport { LocadexManager } from '../utils/locadexManager.js';\nimport { outro } from '@clack/prompts';\nimport { appendFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { exit } from '../utils/shutdown.js';\nimport {\n addTranslateScript,\n installClaudeCode,\n installLocadex,\n} from '../utils/packages/installPackage.js';\n\nexport async function setupTask(\n bypassPrompts: boolean,\n specifiedPackageManager?: string\n) {\n if (!bypassPrompts) {\n await promptConfirm({\n message: chalk.yellow(\n `Locadex will modify files! Make sure you have committed or stashed any changes. Do you want to continue?`\n ),\n defaultValue: true,\n cancelMessage: 'Operation cancelled.',\n });\n }\n\n const manager = LocadexManager.getInstance();\n\n const packageManager = await getPackageManager(\n manager.rootDirectory,\n specifiedPackageManager\n );\n let appPackageJson = await getPackageJson(manager.appDirectory);\n\n if (appPackageJson) {\n if (!isPackageInstalled('gt-next', appPackageJson)) {\n const spinner = createSpinner('timer');\n spinner.start(`Installing gt-next with ${packageManager.name}...`);\n await installPackage(\n 'gt-next',\n packageManager,\n false,\n manager.appDirectory\n );\n spinner.stop('Automatically installed gt-next.');\n }\n }\n\n const nextConfigPath = findFilepaths(\n [\n './next.config.js',\n './next.config.ts',\n './next.config.mjs',\n './next.config.mts',\n ],\n manager.appDirectory\n )[0];\n\n if (!nextConfigPath) {\n logger.error('No next.config.[js|ts|mjs|mts] file found.');\n await exit(1);\n }\n\n const errors: string[] = [];\n const warnings: string[] = [];\n let filesUpdated: string[] = [];\n\n const babel = createSpinner();\n\n babel.start('Wrapping <GTProvider> tags...');\n\n // Wrap all JSX elements in the src directory with a <T> tag, with unique ids\n const { filesUpdated: filesUpdatedNext } = await wrapContentNext(\n {\n src: getNextDirectories(manager.appDirectory),\n config: nextConfigPath,\n disableIds: true,\n disableFormatting: true,\n skipTs: true,\n addGTProvider: true,\n },\n 'gt-next',\n errors,\n warnings\n );\n filesUpdated = [...filesUpdated, ...filesUpdatedNext];\n\n babel.stop(`Modified ${filesUpdated.length} files.`);\n\n // Add the withGTConfig() function to the next.config.js file\n await handleInitGT(nextConfigPath, errors, warnings, filesUpdated);\n logger.step(`Added withGTConfig() to your ${nextConfigPath} file.`);\n\n // Create gt.config.json\n await createOrUpdateConfig(\n path.resolve(manager.appDirectory, 'gt.config.json'),\n {\n defaultLocale: 'en',\n locales: ['es', 'fr', 'de', 'ja', 'zh'],\n framework: 'next-app',\n }\n );\n\n logger.success(\n `Feel free to edit ${chalk.cyan(\n 'gt.config.json'\n )} to customize your translation setup. Docs: https://generaltranslation.com/docs/cli/reference/config`\n );\n\n // Add translate to scripts\n // Re-get the package.json to make sure it's updated\n appPackageJson = await getPackageJson(manager.appDirectory);\n if (appPackageJson) {\n await addTranslateScript(manager, appPackageJson, packageManager);\n }\n\n // Install claude-code if not installed\n await installClaudeCode();\n\n // Install locadex if not installed\n const rootPackageJson = await getPackageJson(manager.rootDirectory);\n if (\n rootPackageJson &&\n !isPackageInstalled('locadex', rootPackageJson, true, true)\n ) {\n await installLocadex(manager);\n }\n\n // Set up locale selector\n await setupLocaleSelector();\n\n const formatter = await detectFormatter();\n if (formatter && filesUpdated.length > 0) {\n await formatFiles(filesUpdated, formatter);\n }\n\n // Run i18n command\n await i18nTask();\n}\n\nasync function setupLocaleSelector() {\n logger.initializeSpinner();\n logger.spinner.start('Creating locale selector...');\n\n // Create agent\n const manager = LocadexManager.getInstance();\n\n const agent = manager.createSingleAgent('claude_setup_agent');\n\n // Fix prompt\n const localeSelectorPrompt = getLocaleSelectorPrompt(manager.appDirectory);\n try {\n await agent.run(localeSelectorPrompt, { maxTurns: 50 }, 1000, 3);\n\n // Generate report\n const report = agent.generateReport();\n const reportSummary = `# Summary of locadex setup changes\n${report}`;\n const summaryFilePath = path.join(\n manager.getLogDirectory(),\n 'locadex-report.md'\n );\n appendFileSync(summaryFilePath, reportSummary);\n } catch (error) {\n // Check if this is an abort\n if (manager.getAgentAbortController().signal.aborted) {\n return;\n }\n logger.debugMessage(`[setup] Adding locale selector failed: ${error}`);\n outro(chalk.red('❌ Locadex setup failed!'));\n await exit(1);\n }\n\n logger.spinner.stop('Locale selector setup complete');\n}\n\nfunction getLocaleSelectorPrompt(appDirectory: string) {\n const prompt = `# Task: Add a locale selector to the app\n\n## Instructions\n- The locale selector should be a dropdown that allows the user to select the locale.\n- The app root is: \"${appDirectory}\"\n\n## LOCALE SELECTOR USAGE\n(1) Import the locale selector component from 'gt-next/client'\n(2) Add the locale selector to the app\n\nFor example:\nimport { LocaleSelector } from 'gt-next/client';\n\nfunction MyComponent() {\n return (\n <div>\n <LocaleSelector />\n <p>Hello, world!</p>\n </div>\n );\n}\n\n## RULES\n- The locale selector should be added to a header or footer or some other very obvious place in the app.\n- Scan across files to find the best place to add the locale selector.\n- **DO NOT** create new files. You may only modify existing files.\n- You do not need to mark the component containing the LocaleSelector with 'use client'. The LocaleSelector component is already internally marked with 'use client'.\n\n## Final output\n- When you are done, please return a **brief summary** of the files you modified.\n- **DO NOT** include any other text in your response.\n`;\n return prompt;\n}\n"]}
1
+ {"version":3,"file":"setup.js","sourceRoot":"/","sources":["tasks/setup.ts"],"names":[],"mappings":"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","sourcesContent":["import { createSpinner, promptConfirm } from '../logging/console.js';\nimport {\n getPackageJson,\n isPackageInstalled,\n updatePackageJson,\n} from 'gtx-cli/utils/packageJson';\nimport { getPackageManager } from 'gtx-cli/utils/packageManager';\nimport { installPackage } from 'gtx-cli/utils/installPackage';\nimport chalk from 'chalk';\nimport { logger } from '../logging/logger.js';\nimport { findFilepaths } from '../utils/fs/findConfigs.js';\nimport { wrapContentNext } from 'gtx-cli/next/parse/wrapContent';\nimport { handleInitGT } from 'gtx-cli/next/parse/handleInitGT';\nimport { detectFormatter, formatFiles } from 'gtx-cli/hooks/postProcess';\nimport { createOrUpdateConfig } from 'gtx-cli/fs/config/setupConfig';\nimport { i18nTask } from '../tasks/i18n.js';\nimport { getNextDirectories } from '../utils/fs/getFiles.js';\nimport { LocadexManager } from '../utils/locadexManager.js';\nimport { outro } from '@clack/prompts';\nimport { appendFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { exit } from '../utils/shutdown.js';\nimport {\n addTranslateScript,\n installClaudeCode,\n installLocadex,\n} from '../utils/packages/installPackage.js';\n\nexport async function setupTask(\n bypassPrompts: boolean,\n specifiedPackageManager?: string\n) {\n if (!bypassPrompts) {\n await promptConfirm({\n message: chalk.yellow(\n `Locadex will modify files! Make sure you have committed or stashed any changes. Do you want to continue?`\n ),\n defaultValue: true,\n cancelMessage: 'Operation cancelled.',\n });\n }\n\n const manager = LocadexManager.getInstance();\n\n const packageManager = await getPackageManager(\n manager.rootDirectory,\n specifiedPackageManager\n );\n let appPackageJson = await getPackageJson(manager.appDirectory);\n\n if (appPackageJson) {\n if (!isPackageInstalled('gt-next', appPackageJson)) {\n const spinner = createSpinner('timer');\n spinner.start(`Installing gt-next with ${packageManager.name}...`);\n await installPackage(\n 'gt-next',\n packageManager,\n false,\n manager.appDirectory\n );\n spinner.stop('Automatically installed gt-next.');\n }\n }\n\n const nextConfigPath = findFilepaths(\n [\n './next.config.js',\n './next.config.ts',\n './next.config.mjs',\n './next.config.mts',\n ],\n manager.appDirectory\n )[0];\n\n if (!nextConfigPath) {\n logger.error('No next.config.[js|ts|mjs|mts] file found.');\n await exit(1);\n }\n\n const errors: string[] = [];\n const warnings: string[] = [];\n let filesUpdated: string[] = [];\n\n const babel = createSpinner();\n\n babel.start('Wrapping <GTProvider> tags...');\n\n // Wrap all JSX elements in the src directory with a <T> tag, with unique ids\n const { filesUpdated: filesUpdatedNext } = await wrapContentNext(\n {\n src: getNextDirectories(manager.appDirectory),\n config: nextConfigPath,\n disableIds: true,\n disableFormatting: true,\n skipTs: true,\n addGTProvider: true,\n },\n 'gt-next',\n errors,\n warnings\n );\n filesUpdated = [...filesUpdated, ...filesUpdatedNext];\n\n babel.stop(`Modified ${filesUpdated.length} files.`);\n\n // Add the withGTConfig() function to the next.config.js file\n await handleInitGT(nextConfigPath, errors, warnings, filesUpdated);\n logger.step(`Added withGTConfig() to your ${nextConfigPath} file.`);\n\n // Create gt.config.json\n await createOrUpdateConfig(\n path.resolve(manager.appDirectory, 'gt.config.json'),\n {\n defaultLocale: 'en',\n locales: ['es', 'fr', 'de', 'ja', 'zh'],\n framework: 'next-app',\n }\n );\n\n logger.success(\n `Feel free to edit ${chalk.cyan(\n 'gt.config.json'\n )} to customize your translation setup. Docs: https://generaltranslation.com/docs/cli/reference/config`\n );\n\n // Add translate to scripts\n // Re-get the package.json to make sure it's updated\n appPackageJson = await getPackageJson(manager.appDirectory);\n if (appPackageJson) {\n await addTranslateScript(manager, appPackageJson, packageManager);\n }\n\n // Install claude-code if not installed\n await installClaudeCode();\n\n // Install locadex if not installed\n const rootPackageJson = await getPackageJson(manager.rootDirectory);\n if (\n rootPackageJson &&\n !isPackageInstalled('locadex', rootPackageJson, true, true)\n ) {\n await installLocadex(manager);\n }\n\n // Set up locale selector\n await setupLocaleSelector();\n\n const formatter = await detectFormatter();\n if (formatter && filesUpdated.length > 0) {\n await formatFiles(filesUpdated, formatter);\n }\n\n // Run i18n command\n await i18nTask();\n}\n\nasync function setupLocaleSelector() {\n logger.initializeSpinner();\n logger.spinner.start('Creating locale selector...');\n\n // Create agent\n const manager = LocadexManager.getInstance();\n\n const agent = manager.createSingleAgent('claude_setup_agent', {});\n\n // Fix prompt\n const localeSelectorPrompt = getLocaleSelectorPrompt(manager.appDirectory);\n try {\n await agent.run(\n localeSelectorPrompt,\n {\n maxTurns: 50,\n timeoutSec: 120,\n maxRetries: 1,\n },\n {}\n );\n\n // Generate report\n const report = agent.generateReport();\n const reportSummary = `# Summary of locadex setup changes\n${report}`;\n const summaryFilePath = path.join(\n manager.getLogDirectory(),\n 'locadex-report.md'\n );\n appendFileSync(summaryFilePath, reportSummary);\n } catch (error) {\n // Check if this is an abort\n if (manager.getAgentAbortController().signal.aborted) {\n return;\n }\n logger.debugMessage(`[setup] Adding locale selector failed: ${error}`);\n outro(chalk.red('❌ Locadex setup failed!'));\n await exit(1);\n }\n\n logger.spinner.stop('Locale selector setup complete');\n}\n\nfunction getLocaleSelectorPrompt(appDirectory: string) {\n const prompt = `# Task: Add a locale selector to the app\n\n## Instructions\n- The locale selector should be a dropdown that allows the user to select the locale.\n- The app root is: \"${appDirectory}\"\n\n## LOCALE SELECTOR USAGE\n(1) Import the locale selector component from 'gt-next/client'\n(2) Add the locale selector to the app\n\nFor example:\nimport { LocaleSelector } from 'gt-next/client';\n\nfunction MyComponent() {\n return (\n <div>\n <LocaleSelector />\n <p>Hello, world!</p>\n </div>\n );\n}\n\n## RULES\n- The locale selector should be added to a header or footer or some other very obvious place in the app.\n- Scan across files to find the best place to add the locale selector.\n- **DO NOT** create new files. You may only modify existing files.\n- You do not need to mark the component containing the LocaleSelector with 'use client'. The LocaleSelector component is already internally marked with 'use client'.\n\n## Final output\n- When you are done, please return a **brief summary** of the files you modified.\n- **DO NOT** include any other text in your response.\n`;\n return prompt;\n}\n"]}
@@ -1,9 +1,14 @@
1
1
  import { LocadexManager } from './locadexManager.js';
2
- export interface ClaudeCodeOptions {
2
+ export type ClaudeRunOptions = {
3
3
  additionalSystemPrompt?: string;
4
4
  additionalAllowedTools?: string[];
5
5
  maxTurns?: number;
6
- }
6
+ timeoutSec: number;
7
+ maxRetries: number;
8
+ };
9
+ export type ClaudeRunnerOptions = {
10
+ softTurnLimit?: number;
11
+ };
7
12
  export interface ClaudeCodeObservation {
8
13
  }
9
14
  export declare class ClaudeCodeRunner {
@@ -14,17 +19,17 @@ export declare class ClaudeCodeRunner {
14
19
  private manager;
15
20
  private changes;
16
21
  private controller;
17
- private maxTurns;
22
+ private softTurnLimit;
18
23
  private turns;
19
24
  constructor(manager: LocadexManager, controller: AbortController, options: {
20
25
  id: string;
21
26
  apiKey: string;
22
27
  mcpConfig: string;
23
- maxTurns: number;
28
+ softTurnLimit: number;
24
29
  });
25
30
  getSessionId(): string | undefined;
26
31
  reset(): void;
27
- run(prompt: string, options: ClaudeCodeOptions, obs: ClaudeCodeObservation, timeoutSec?: number, maxRetries?: number): Promise<string>;
32
+ run(prompt: string, options: ClaudeRunOptions, obs: ClaudeCodeObservation): Promise<string>;
28
33
  private handleSDKOutput;
29
34
  generateReport(): string;
30
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"claudeCode.d.ts","sourceRoot":"/","sources":["utils/claudeCode.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAIrD,MAAM,WAAW,iBAAiB;IAChC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;CAAG;AA+DzC,qBAAa,gBAAgB;IAazB,OAAO,CAAC,OAAO;IAZjB,OAAO,CAAC,EAAE,CAAS;IACnB,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAa;gBAGxB,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,eAAe,EACnB,OAAO,EAAE;QACf,EAAE,EAAE,MAAM,CAAC;QACX,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;KAClB;IAgBH,YAAY,IAAI,MAAM,GAAG,SAAS;IAGlC,KAAK;IAKC,GAAG,CACP,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,iBAAiB,EAC1B,GAAG,EAAE,qBAAqB,EAC1B,UAAU,GAAE,MAAY,EACxB,UAAU,GAAE,MAAU,GACrB,OAAO,CAAC,MAAM,CAAC;IAkJlB,OAAO,CAAC,eAAe;IAoEvB,cAAc,IAAI,MAAM;CAGzB"}
1
+ {"version":3,"file":"claudeCode.d.ts","sourceRoot":"/","sources":["utils/claudeCode.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAIrD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,WAAW,qBAAqB;CAAG;AA+DzC,qBAAa,gBAAgB;IAazB,OAAO,CAAC,OAAO;IAZjB,OAAO,CAAC,EAAE,CAAS;IACnB,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,KAAK,CAAa;gBAGxB,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,eAAe,EACnB,OAAO,EAAE;QACf,EAAE,EAAE,MAAM,CAAC;QACX,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;KACvB;IAgBH,YAAY,IAAI,MAAM,GAAG,SAAS;IAGlC,KAAK;IAKC,GAAG,CACP,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,qBAAqB,GACzB,OAAO,CAAC,MAAM,CAAC;IAqJlB,OAAO,CAAC,eAAe;IAoEvB,cAAc,IAAI,MAAM;CAGzB"}
@@ -53,7 +53,7 @@ export class ClaudeCodeRunner {
53
53
  manager;
54
54
  changes = [];
55
55
  controller;
56
- maxTurns;
56
+ softTurnLimit;
57
57
  turns = 0;
58
58
  constructor(manager, controller, options) {
59
59
  this.options = options;
@@ -61,7 +61,7 @@ export class ClaudeCodeRunner {
61
61
  this.id = options.id;
62
62
  this.mcpConfig = options.mcpConfig;
63
63
  this.controller = controller;
64
- this.maxTurns = options.maxTurns;
64
+ this.softTurnLimit = options.softTurnLimit;
65
65
  // Ensure API key is set
66
66
  if (!process.env.ANTHROPIC_API_KEY && !this.options.apiKey) {
67
67
  throw new Error('ANTHROPIC_API_KEY environment variable or apiKey option is required');
@@ -74,7 +74,7 @@ export class ClaudeCodeRunner {
74
74
  this.sessionId = undefined;
75
75
  this.turns = 0;
76
76
  }
77
- async run(prompt, options, obs, timeoutSec = 300, maxRetries = 1) {
77
+ async run(prompt, options, obs) {
78
78
  this.changes = [];
79
79
  return withRetry(() => Sentry.startSpan({
80
80
  name: 'claude-code-exec',
@@ -89,7 +89,7 @@ export class ClaudeCodeRunner {
89
89
  }
90
90
  args.push('--output-format', 'stream-json');
91
91
  args.push('--verbose');
92
- if (this.sessionId && this.turns < this.maxTurns) {
92
+ if (this.sessionId && this.turns < this.softTurnLimit) {
93
93
  args.push('--resume', this.sessionId);
94
94
  }
95
95
  if (this.mcpConfig) {
@@ -107,6 +107,9 @@ export class ClaudeCodeRunner {
107
107
  env.ANTHROPIC_API_KEY = this.options.apiKey;
108
108
  logger.debugMessage(`[${this.id}] Spawning Claude Code with additional args: ${JSON.stringify({
109
109
  maxTurns: options.maxTurns,
110
+ softTurnLimit: this.softTurnLimit,
111
+ timeoutSec: options.timeoutSec,
112
+ maxRetries: options.maxRetries,
110
113
  sessionId: this.sessionId,
111
114
  mcpConfig: this.mcpConfig,
112
115
  additionalAllowedTools: options.additionalAllowedTools,
@@ -161,7 +164,7 @@ export class ClaudeCodeRunner {
161
164
  reject(new Error(`[${this.id}] failed to run Claude Code: ${error.message}`));
162
165
  }
163
166
  });
164
- }), timeoutSec, `Claude Code operation timed out after ${timeoutSec}s`)), maxRetries);
167
+ }), options.timeoutSec, `Claude Code operation timed out after ${options.timeoutSec}s`)), options.maxRetries);
165
168
  }
166
169
  handleSDKOutput(outputData, obs) {
167
170
  if (outputData.type === 'assistant') {
@@ -1 +1 @@
1
- {"version":3,"file":"claudeCode.js","sourceRoot":"/","sources":["utils/claudeCode.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from 'node:child_process';\nimport { ClaudeSDKMessage } from '../types/claude-sdk.js';\nimport { guides } from '../mcp/tools/guides.js';\nimport { logger } from '../logging/logger.js';\nimport { posthog } from '../telemetry.js';\nimport { LocadexManager } from './locadexManager.js';\nimport { getSessionId } from './session.js';\nimport * as Sentry from '@sentry/node';\n\nexport interface ClaudeCodeOptions {\n additionalSystemPrompt?: string;\n additionalAllowedTools?: string[];\n maxTurns?: number;\n}\n\nexport interface ClaudeCodeObservation {}\n\nconst DEFAULT_ALLOWED_TOOLS = [\n 'mcp__locadex__fetch-docs',\n 'mcp__locadex__list-docs',\n 'Bash',\n 'Edit',\n 'MultiEdit',\n 'Write',\n].concat(guides.map((guide) => `mcp__locadex__${guide.id}`));\n\nconst DISALLOWED_TOOLS = ['NotebookEdit', 'WebFetch', 'WebSearch'];\n\n/**\n * Wraps a promise with a timeout mechanism\n */\nasync function withTimeout<T>(\n promise: Promise<T>,\n timeoutSec: number,\n timeoutMessage?: string\n): Promise<T> {\n const timeoutPromise = new Promise<never>((_, reject) => {\n global.setTimeout(() => {\n reject(\n new Error(timeoutMessage || `Operation timed out after ${timeoutSec}s`)\n );\n }, timeoutSec * 1000);\n });\n\n return Promise.race([promise, timeoutPromise]);\n}\n\n/**\n * Retries an async operation with exponential backoff\n */\nasync function withRetry<T>(\n operation: () => Promise<T>,\n maxRetries: number = 1,\n baseDelayMs: number = 1000\n): Promise<T> {\n let lastError: Error;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await operation();\n } catch (error) {\n lastError = error as Error;\n\n if (attempt === maxRetries) {\n throw lastError;\n }\n\n const delay = baseDelayMs * Math.pow(2, attempt);\n logger.debugMessage(\n `Agent operation failed (attempt ${attempt + 1}/${maxRetries + 1}), retrying in ${delay}ms: ${error}`\n );\n await new Promise((resolve) => global.setTimeout(resolve, delay));\n }\n }\n\n throw lastError!;\n}\n\nexport class ClaudeCodeRunner {\n private id: string;\n private sessionId: string | undefined;\n private mcpConfig: string | undefined;\n private manager: LocadexManager;\n private changes: string[] = [];\n private controller: AbortController;\n private maxTurns: number;\n private turns: number = 0;\n\n constructor(\n manager: LocadexManager,\n controller: AbortController,\n private options: {\n id: string;\n apiKey: string;\n mcpConfig: string;\n maxTurns: number;\n }\n ) {\n this.manager = manager;\n this.id = options.id;\n this.mcpConfig = options.mcpConfig;\n this.controller = controller;\n this.maxTurns = options.maxTurns;\n\n // Ensure API key is set\n if (!process.env.ANTHROPIC_API_KEY && !this.options.apiKey) {\n throw new Error(\n 'ANTHROPIC_API_KEY environment variable or apiKey option is required'\n );\n }\n }\n\n getSessionId(): string | undefined {\n return this.sessionId;\n }\n reset() {\n this.sessionId = undefined;\n this.turns = 0;\n }\n\n async run(\n prompt: string,\n options: ClaudeCodeOptions,\n obs: ClaudeCodeObservation,\n timeoutSec: number = 300,\n maxRetries: number = 1\n ): Promise<string> {\n this.changes = [];\n return withRetry(\n () =>\n Sentry.startSpan(\n {\n name: 'claude-code-exec',\n op: 'claude-code.exec',\n attributes: {\n 'process.command': 'claude',\n },\n },\n () =>\n withTimeout(\n new Promise((resolve, reject) => {\n const args = ['-p', prompt];\n\n if (options.additionalSystemPrompt) {\n args.push(\n '--append-system-prompt',\n options.additionalSystemPrompt\n );\n }\n\n args.push('--output-format', 'stream-json');\n args.push('--verbose');\n\n if (this.sessionId && this.turns < this.maxTurns) {\n args.push('--resume', this.sessionId);\n }\n\n if (this.mcpConfig) {\n args.push('--mcp-config', this.mcpConfig);\n }\n\n args.push(\n '--allowedTools',\n [\n ...DEFAULT_ALLOWED_TOOLS,\n ...(options?.additionalAllowedTools || []),\n ].join(',')\n );\n\n args.push('--disallowedTools', DISALLOWED_TOOLS.join(','));\n\n if (options.maxTurns) {\n args.push('--max-turns', options.maxTurns.toString());\n }\n\n const env = { ...process.env };\n env.ANTHROPIC_API_KEY = this.options.apiKey;\n logger.debugMessage(\n `[${this.id}] Spawning Claude Code with additional args: ${JSON.stringify(\n {\n maxTurns: options.maxTurns,\n sessionId: this.sessionId,\n mcpConfig: this.mcpConfig,\n additionalAllowedTools: options.additionalAllowedTools,\n },\n null,\n 2\n )}. API key is ${this.options.apiKey ? 'set' : 'not set'}`\n );\n\n const claude = spawn('claude', args, {\n stdio: ['ignore', 'pipe', 'pipe'],\n env,\n signal: this.controller.signal,\n });\n\n logger.debugMessage(`[${this.id}] Spawned claude code process`);\n\n const output = '';\n const errorOutput = '';\n\n let buffer = '';\n claude.stdout?.on('data', (data) => {\n buffer += data.toString();\n const lines = buffer.split('\\n');\n\n // Keep the last incomplete line in buffer\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.trim()) {\n try {\n logger.debugMessage(`[${this.id}] ${line}`);\n const outputData: ClaudeSDKMessage = JSON.parse(line);\n this.handleSDKOutput(outputData, obs);\n } catch (error) {\n logger.debugMessage(\n `[${this.id}] Failed to parse JSON: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n }\n });\n\n claude.stderr?.on('data', (data) => {\n logger.debugMessage(`[${this.id}] ${data.toString().trim()}`);\n });\n\n claude.on('close', (code) => {\n if (code === 0) {\n resolve(output.trim());\n } else {\n logger.debugMessage(\n `[${this.id}] Claude Code exited with code ${code}: ${errorOutput}`\n );\n reject(\n new Error(\n `[${this.id}] Claude Code exited with code ${code}: ${errorOutput}`\n )\n );\n }\n });\n\n claude.on('error', (error) => {\n // Check if this is an AbortError\n if (error.name === 'AbortError') {\n logger.debugMessage(\n `[${this.id}] Claude Code process was aborted`\n );\n reject(\n new Error(`[${this.id}] Claude Code process was aborted`)\n );\n } else {\n logger.debugMessage(\n `[${this.id}] failed to run Claude Code: ${error.message}`\n );\n reject(\n new Error(\n `[${this.id}] failed to run Claude Code: ${error.message}`\n )\n );\n }\n });\n }),\n timeoutSec,\n `Claude Code operation timed out after ${timeoutSec}s`\n )\n ),\n maxRetries\n );\n }\n\n private handleSDKOutput(\n outputData: ClaudeSDKMessage,\n obs: ClaudeCodeObservation\n ) {\n if (outputData.type === 'assistant') {\n const text: string[] = [];\n const toolUses: string[] = [];\n outputData.message.content.forEach((c) => {\n if (c.type === 'text') {\n text.push(c.text);\n }\n if (c.type === 'tool_use') {\n toolUses.push(c.name);\n if (c.name.startsWith('mcp__locadex__')) {\n posthog.capture({\n distinctId: getSessionId(),\n event: 'tool_used',\n properties: {\n tool: c.name,\n },\n });\n }\n }\n });\n if (text.length > 0) {\n logger.verboseMessage(`[${this.id}] ${text.join('').trim()}`);\n }\n if (toolUses.length > 0) {\n logger.debugMessage(`[${this.id}] used tools: ${toolUses.join(', ')}`);\n }\n this.manager.stats.updateStats({\n newToolCalls: toolUses.length,\n newInputTokens: outputData.message.usage.input_tokens,\n newOutputTokens: outputData.message.usage.output_tokens,\n newCachedInputTokens:\n outputData.message.usage.cache_read_input_tokens ?? 0,\n });\n } else if (outputData.type === 'result') {\n if (!outputData.is_error) {\n logger.verboseMessage(\n `[${this.id}] finished task.\\nCost: $${Number(outputData.cost_usd).toFixed(2)}\\nDuration: ${\n Number(outputData.duration_ms) / 1000\n }s`\n );\n } else {\n logger.verboseMessage(\n `[${this.id}] finished task with error: ${outputData.subtype}\\nCost: $${outputData.cost_usd}\\nDuration: ${\n Number(outputData.duration_ms) / 1000\n }s`\n );\n }\n if (outputData.subtype === 'success') {\n this.changes.push(outputData.result);\n }\n this.manager.stats.updateStats({\n newCost: Number(outputData.cost_usd),\n newWallDuration: Number(outputData.duration_ms),\n newApiDuration: Number(outputData.duration_api_ms),\n newTurns: Number(outputData.num_turns),\n });\n this.turns = Number(outputData.num_turns);\n } else if (outputData.type === 'system') {\n if (outputData.subtype === 'init') {\n this.sessionId = outputData.session_id;\n }\n }\n }\n\n generateReport(): string {\n return this.changes.join('\\n');\n }\n}\n"]}
1
+ {"version":3,"file":"claudeCode.js","sourceRoot":"/","sources":["utils/claudeCode.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from 'node:child_process';\nimport { ClaudeSDKMessage } from '../types/claude-sdk.js';\nimport { guides } from '../mcp/tools/guides.js';\nimport { logger } from '../logging/logger.js';\nimport { posthog } from '../telemetry.js';\nimport { LocadexManager } from './locadexManager.js';\nimport { getSessionId } from './session.js';\nimport * as Sentry from '@sentry/node';\n\nexport type ClaudeRunOptions = {\n additionalSystemPrompt?: string;\n additionalAllowedTools?: string[];\n maxTurns?: number; // Hard limit on the number of turns per Claude Code call\n\n // required\n timeoutSec: number; // Timeout per .run() call\n maxRetries: number; // Max number of retries per .run() call\n};\n\nexport type ClaudeRunnerOptions = {\n softTurnLimit?: number; // Soft limit on the number of turns per Claude runner\n};\n\nexport interface ClaudeCodeObservation {}\n\nconst DEFAULT_ALLOWED_TOOLS = [\n 'mcp__locadex__fetch-docs',\n 'mcp__locadex__list-docs',\n 'Bash',\n 'Edit',\n 'MultiEdit',\n 'Write',\n].concat(guides.map((guide) => `mcp__locadex__${guide.id}`));\n\nconst DISALLOWED_TOOLS = ['NotebookEdit', 'WebFetch', 'WebSearch'];\n\n/**\n * Wraps a promise with a timeout mechanism\n */\nasync function withTimeout<T>(\n promise: Promise<T>,\n timeoutSec: number,\n timeoutMessage?: string\n): Promise<T> {\n const timeoutPromise = new Promise<never>((_, reject) => {\n global.setTimeout(() => {\n reject(\n new Error(timeoutMessage || `Operation timed out after ${timeoutSec}s`)\n );\n }, timeoutSec * 1000);\n });\n\n return Promise.race([promise, timeoutPromise]);\n}\n\n/**\n * Retries an async operation with exponential backoff\n */\nasync function withRetry<T>(\n operation: () => Promise<T>,\n maxRetries: number = 1,\n baseDelayMs: number = 1000\n): Promise<T> {\n let lastError: Error;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await operation();\n } catch (error) {\n lastError = error as Error;\n\n if (attempt === maxRetries) {\n throw lastError;\n }\n\n const delay = baseDelayMs * Math.pow(2, attempt);\n logger.debugMessage(\n `Agent operation failed (attempt ${attempt + 1}/${maxRetries + 1}), retrying in ${delay}ms: ${error}`\n );\n await new Promise((resolve) => global.setTimeout(resolve, delay));\n }\n }\n\n throw lastError!;\n}\n\nexport class ClaudeCodeRunner {\n private id: string;\n private sessionId: string | undefined;\n private mcpConfig: string | undefined;\n private manager: LocadexManager;\n private changes: string[] = [];\n private controller: AbortController;\n private softTurnLimit: number;\n private turns: number = 0;\n\n constructor(\n manager: LocadexManager,\n controller: AbortController,\n private options: {\n id: string;\n apiKey: string;\n mcpConfig: string;\n softTurnLimit: number;\n }\n ) {\n this.manager = manager;\n this.id = options.id;\n this.mcpConfig = options.mcpConfig;\n this.controller = controller;\n this.softTurnLimit = options.softTurnLimit;\n\n // Ensure API key is set\n if (!process.env.ANTHROPIC_API_KEY && !this.options.apiKey) {\n throw new Error(\n 'ANTHROPIC_API_KEY environment variable or apiKey option is required'\n );\n }\n }\n\n getSessionId(): string | undefined {\n return this.sessionId;\n }\n reset() {\n this.sessionId = undefined;\n this.turns = 0;\n }\n\n async run(\n prompt: string,\n options: ClaudeRunOptions,\n obs: ClaudeCodeObservation\n ): Promise<string> {\n this.changes = [];\n return withRetry(\n () =>\n Sentry.startSpan(\n {\n name: 'claude-code-exec',\n op: 'claude-code.exec',\n attributes: {\n 'process.command': 'claude',\n },\n },\n () =>\n withTimeout(\n new Promise((resolve, reject) => {\n const args = ['-p', prompt];\n\n if (options.additionalSystemPrompt) {\n args.push(\n '--append-system-prompt',\n options.additionalSystemPrompt\n );\n }\n\n args.push('--output-format', 'stream-json');\n args.push('--verbose');\n\n if (this.sessionId && this.turns < this.softTurnLimit) {\n args.push('--resume', this.sessionId);\n }\n\n if (this.mcpConfig) {\n args.push('--mcp-config', this.mcpConfig);\n }\n\n args.push(\n '--allowedTools',\n [\n ...DEFAULT_ALLOWED_TOOLS,\n ...(options?.additionalAllowedTools || []),\n ].join(',')\n );\n\n args.push('--disallowedTools', DISALLOWED_TOOLS.join(','));\n\n if (options.maxTurns) {\n args.push('--max-turns', options.maxTurns.toString());\n }\n\n const env = { ...process.env };\n env.ANTHROPIC_API_KEY = this.options.apiKey;\n logger.debugMessage(\n `[${this.id}] Spawning Claude Code with additional args: ${JSON.stringify(\n {\n maxTurns: options.maxTurns,\n softTurnLimit: this.softTurnLimit,\n timeoutSec: options.timeoutSec,\n maxRetries: options.maxRetries,\n sessionId: this.sessionId,\n mcpConfig: this.mcpConfig,\n additionalAllowedTools: options.additionalAllowedTools,\n },\n null,\n 2\n )}. API key is ${this.options.apiKey ? 'set' : 'not set'}`\n );\n\n const claude = spawn('claude', args, {\n stdio: ['ignore', 'pipe', 'pipe'],\n env,\n signal: this.controller.signal,\n });\n\n logger.debugMessage(`[${this.id}] Spawned claude code process`);\n\n const output = '';\n const errorOutput = '';\n\n let buffer = '';\n claude.stdout?.on('data', (data) => {\n buffer += data.toString();\n const lines = buffer.split('\\n');\n\n // Keep the last incomplete line in buffer\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.trim()) {\n try {\n logger.debugMessage(`[${this.id}] ${line}`);\n const outputData: ClaudeSDKMessage = JSON.parse(line);\n this.handleSDKOutput(outputData, obs);\n } catch (error) {\n logger.debugMessage(\n `[${this.id}] Failed to parse JSON: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n }\n });\n\n claude.stderr?.on('data', (data) => {\n logger.debugMessage(`[${this.id}] ${data.toString().trim()}`);\n });\n\n claude.on('close', (code) => {\n if (code === 0) {\n resolve(output.trim());\n } else {\n logger.debugMessage(\n `[${this.id}] Claude Code exited with code ${code}: ${errorOutput}`\n );\n reject(\n new Error(\n `[${this.id}] Claude Code exited with code ${code}: ${errorOutput}`\n )\n );\n }\n });\n\n claude.on('error', (error) => {\n // Check if this is an AbortError\n if (error.name === 'AbortError') {\n logger.debugMessage(\n `[${this.id}] Claude Code process was aborted`\n );\n reject(\n new Error(`[${this.id}] Claude Code process was aborted`)\n );\n } else {\n logger.debugMessage(\n `[${this.id}] failed to run Claude Code: ${error.message}`\n );\n reject(\n new Error(\n `[${this.id}] failed to run Claude Code: ${error.message}`\n )\n );\n }\n });\n }),\n options.timeoutSec,\n `Claude Code operation timed out after ${options.timeoutSec}s`\n )\n ),\n options.maxRetries\n );\n }\n\n private handleSDKOutput(\n outputData: ClaudeSDKMessage,\n obs: ClaudeCodeObservation\n ) {\n if (outputData.type === 'assistant') {\n const text: string[] = [];\n const toolUses: string[] = [];\n outputData.message.content.forEach((c) => {\n if (c.type === 'text') {\n text.push(c.text);\n }\n if (c.type === 'tool_use') {\n toolUses.push(c.name);\n if (c.name.startsWith('mcp__locadex__')) {\n posthog.capture({\n distinctId: getSessionId(),\n event: 'tool_used',\n properties: {\n tool: c.name,\n },\n });\n }\n }\n });\n if (text.length > 0) {\n logger.verboseMessage(`[${this.id}] ${text.join('').trim()}`);\n }\n if (toolUses.length > 0) {\n logger.debugMessage(`[${this.id}] used tools: ${toolUses.join(', ')}`);\n }\n this.manager.stats.updateStats({\n newToolCalls: toolUses.length,\n newInputTokens: outputData.message.usage.input_tokens,\n newOutputTokens: outputData.message.usage.output_tokens,\n newCachedInputTokens:\n outputData.message.usage.cache_read_input_tokens ?? 0,\n });\n } else if (outputData.type === 'result') {\n if (!outputData.is_error) {\n logger.verboseMessage(\n `[${this.id}] finished task.\\nCost: $${Number(outputData.cost_usd).toFixed(2)}\\nDuration: ${\n Number(outputData.duration_ms) / 1000\n }s`\n );\n } else {\n logger.verboseMessage(\n `[${this.id}] finished task with error: ${outputData.subtype}\\nCost: $${outputData.cost_usd}\\nDuration: ${\n Number(outputData.duration_ms) / 1000\n }s`\n );\n }\n if (outputData.subtype === 'success') {\n this.changes.push(outputData.result);\n }\n this.manager.stats.updateStats({\n newCost: Number(outputData.cost_usd),\n newWallDuration: Number(outputData.duration_ms),\n newApiDuration: Number(outputData.duration_api_ms),\n newTurns: Number(outputData.num_turns),\n });\n this.turns = Number(outputData.num_turns);\n } else if (outputData.type === 'system') {\n if (outputData.subtype === 'init') {\n this.sessionId = outputData.session_id;\n }\n }\n }\n\n generateReport(): string {\n return this.changes.join('\\n');\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { ClaudeCodeRunner } from './claudeCode.js';
1
+ import { ClaudeCodeRunner, ClaudeRunnerOptions } from './claudeCode.js';
2
2
  import { AgentStats } from './stats.js';
3
3
  import { CliOptions, LocadexConfig } from '../types/cli.js';
4
4
  export interface LocadexRunMetadata {
@@ -32,7 +32,7 @@ export declare class LocadexManager {
32
32
  private maxConcurrency;
33
33
  private batchSize;
34
34
  private timeout;
35
- private maxTurns;
35
+ private defaultSoftTurnLimit;
36
36
  private agentPool;
37
37
  private agentAbortController;
38
38
  private mcpAbortController;
@@ -54,10 +54,8 @@ export declare class LocadexManager {
54
54
  options: Partial<LocadexConfig>;
55
55
  }): void;
56
56
  static reset(): void;
57
- createSingleAgent(id: string, options?: {
58
- maxTurns?: number;
59
- }): ClaudeCodeRunner;
60
- createAgentPool(): void;
57
+ createSingleAgent(id: string, options: ClaudeRunnerOptions): ClaudeCodeRunner;
58
+ createAgentPool(options: ClaudeRunnerOptions): void;
61
59
  getAvailableAgent(): Promise<{
62
60
  id: string;
63
61
  agent: ClaudeCodeRunner;
@@ -1 +1 @@
1
- {"version":3,"file":"locadexManager.d.ts","sourceRoot":"/","sources":["utils/locadexManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"locadexManager.d.ts","sourceRoot":"/","sources":["utils/locadexManager.ts"],"names":[],"mappings":"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"}
@@ -37,7 +37,7 @@ export class LocadexManager {
37
37
  maxConcurrency;
38
38
  batchSize;
39
39
  timeout;
40
- maxTurns = 100;
40
+ defaultSoftTurnLimit = 100;
41
41
  // Agent pool
42
42
  agentPool;
43
43
  // Abort controllers
@@ -167,20 +167,20 @@ export class LocadexManager {
167
167
  LocadexManager.instance = undefined;
168
168
  }
169
169
  }
170
- createSingleAgent(id, options = {}) {
170
+ createSingleAgent(id, options) {
171
171
  return new ClaudeCodeRunner(this, this.agentAbortController, {
172
172
  apiKey: this.apiKey,
173
173
  mcpConfig: this.mcpConfigPath,
174
- maxTurns: this.maxTurns,
174
+ softTurnLimit: options.softTurnLimit ?? this.defaultSoftTurnLimit,
175
175
  id,
176
176
  });
177
177
  }
178
- createAgentPool() {
178
+ createAgentPool(options) {
179
179
  if (this.agentPool.size === 0) {
180
180
  for (let i = 0; i < this.maxConcurrency; i++) {
181
181
  const agentId = `claude_task_agent_${i + 1}`;
182
182
  this.agentPool.set(agentId, {
183
- agent: this.createSingleAgent(agentId),
183
+ agent: this.createSingleAgent(agentId, options),
184
184
  busy: false,
185
185
  });
186
186
  }
@@ -1 +1 @@
1
- {"version":3,"file":"locadexManager.js","sourceRoot":"/","sources":["utils/locadexManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { ClaudeCodeRunner } from './claudeCode.js';\nimport { fromPackageRoot } from './getPaths.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { FileEntry } from './dag/getFiles.js';\nimport { logger } from '../logging/logger.js';\nimport { addToGitIgnore } from './fs/writeFiles.js';\nimport { spawn } from 'node:child_process';\nimport type { ChildProcess } from 'node:child_process';\nimport { setTimeout } from 'node:timers';\nimport { AgentStats } from './stats.js';\nimport { CliOptions, LocadexConfig } from '../types/cli.js';\nimport { findAvailablePort } from '../mcp/getPort.js';\nimport { createConfig, getConfig } from './config.js';\nimport { gracefulShutdown, exit } from './shutdown.js';\nimport { LOCKFILE_NAME } from './lockfile.js';\n\nexport interface LocadexRunMetadata {\n createdAt: string;\n locadexVersion: string;\n workingDirectory: string;\n projectName: string;\n transport: 'sse' | 'stdio';\n tempDirectory: string;\n nodeVersion: string;\n platform: string;\n arch: string;\n logFile: string;\n batchSize: number;\n maxConcurrency: number;\n [key: string]: any;\n}\n\nconst mcpSseConfig = {\n mcpServers: {\n locadex: {\n type: 'sse',\n url: 'http://localhost:8888/sse',\n },\n },\n};\n\nexport class LocadexManager {\n private static instance: LocadexManager | undefined;\n private mcpProcess: ChildProcess | undefined;\n private mcpTransport: 'sse' | 'stdio';\n\n // Paths\n private mcpConfigPath: string;\n private filesStateFilePath: string;\n private metadataFilePath: string;\n private lockFilePath: string;\n private currentRunDir: string;\n public locadexDirectory: string;\n public appDirectory: string;\n public rootDirectory: string;\n\n // Config\n private apiKey: string;\n private maxConcurrency: number;\n private batchSize: number;\n private timeout: number;\n private maxTurns: number = 100;\n\n // Agent pool\n private agentPool: Map<string, { agent: ClaudeCodeRunner; busy: boolean }>;\n\n // Abort controllers\n private agentAbortController: AbortController;\n private mcpAbortController: AbortController;\n private aborted: boolean = false;\n\n // State\n private agentMutex = Promise.resolve();\n private config: LocadexConfig;\n public stats: AgentStats;\n public logFile: string;\n\n private constructor(params: {\n rootDirectory: string;\n appDirectory: string;\n mcpTransport: 'sse' | 'stdio';\n apiKey: string;\n metadata: Partial<LocadexRunMetadata>;\n options: Partial<LocadexConfig>;\n }) {\n this.apiKey = params.apiKey;\n this.agentPool = new Map();\n this.stats = new AgentStats();\n this.mcpTransport = params.mcpTransport;\n this.agentAbortController = new AbortController();\n this.mcpAbortController = new AbortController();\n\n // appDirectory is the absolute path to the app directory\n this.appDirectory = params.appDirectory;\n this.rootDirectory = params.rootDirectory;\n\n this.locadexDirectory = path.resolve(this.rootDirectory, '.locadex');\n this.currentRunDir = path.resolve(\n this.locadexDirectory,\n 'runs',\n Date.now().toString()\n );\n fs.mkdirSync(this.currentRunDir, { recursive: true });\n\n this.config = getConfig(\n this.locadexDirectory,\n this.rootDirectory,\n this.appDirectory,\n params.options\n );\n logger.debugMessage(\n `Locadex loaded with config: ${JSON.stringify(this.config, null, 2)}`\n );\n\n createConfig(this.locadexDirectory, {\n batchSize: this.config.batchSize,\n maxConcurrency: this.config.maxConcurrency,\n matchingFiles: this.config.matchingFiles,\n timeout: this.config.timeout,\n });\n\n addToGitIgnore(this.rootDirectory, '.locadex/runs');\n\n this.maxConcurrency = this.config.maxConcurrency;\n this.batchSize = this.config.batchSize;\n this.timeout = this.config.timeout;\n this.mcpConfigPath = path.resolve(this.currentRunDir, 'mcp.json');\n this.filesStateFilePath = path.resolve(\n this.currentRunDir,\n 'files-state.json'\n );\n this.metadataFilePath = path.resolve(this.currentRunDir, 'metadata.json');\n this.logFile = path.resolve(this.currentRunDir, 'log.txt');\n this.lockFilePath = path.resolve(this.locadexDirectory, LOCKFILE_NAME);\n\n // Create files-state.json\n const filesState: FileEntry[] = [];\n fs.writeFileSync(\n this.filesStateFilePath,\n JSON.stringify(filesState, null, 2)\n );\n\n // Create metadata.json\n const metadata: LocadexRunMetadata = {\n createdAt: new Date().toISOString(),\n locadexVersion: JSON.parse(\n fs.readFileSync(fromPackageRoot('package.json'), 'utf8')\n ).version,\n workingDirectory: this.appDirectory,\n projectName: path.basename(this.appDirectory),\n transport: params.mcpTransport,\n tempDirectory: this.currentRunDir,\n nodeVersion: process.version,\n platform: process.platform,\n arch: process.arch,\n logFile: this.logFile,\n batchSize: this.config.batchSize,\n maxConcurrency: this.config.maxConcurrency,\n ...params.metadata,\n };\n fs.writeFileSync(this.metadataFilePath, JSON.stringify(metadata, null, 2));\n\n // Register cleanup with graceful shutdown\n gracefulShutdown.addHandler({\n name: 'locadex-manager-cleanup',\n handler: () => this.cleanup(),\n timeout: 3000,\n });\n }\n\n async startMcpServer() {\n if (this.mcpTransport === 'stdio') {\n return;\n }\n\n // First, search for an available port\n const port = await findAvailablePort(8888);\n mcpSseConfig.mcpServers.locadex.url = `http://localhost:${port}/sse`;\n fs.writeFileSync(this.mcpConfigPath, JSON.stringify(mcpSseConfig, null, 2));\n\n logger.debugMessage(\n `Starting MCP server on port ${port} with config: ${JSON.stringify(\n mcpSseConfig,\n null,\n 2\n )}`\n );\n\n this.mcpProcess = spawn('node', [fromPackageRoot('dist/mcp.js')], {\n env: {\n ...process.env,\n LOCADEX_FILES_STATE_FILE_PATH: this.filesStateFilePath,\n LOCADEX_VERBOSE: logger.verbose ? 'true' : 'false',\n LOCADEX_DEBUG: logger.debug ? 'true' : 'false',\n LOCADEX_LOG_FILE_PATH: this.logFile,\n PORT: port.toString(),\n },\n stdio: ['ignore', 'inherit', 'inherit'],\n signal: this.mcpAbortController.signal,\n });\n\n this.mcpProcess.on('error', async (error) => {\n if (error.name === 'AbortError') {\n logger.debugMessage('MCP server was closed');\n } else {\n logger.error(`MCP server failed to start: ${error.message}`);\n await exit(1);\n }\n });\n\n this.mcpProcess.on('exit', async (code, signal) => {\n if (code !== 0 && code !== null) {\n logger.error(`MCP server exited with code ${code}`);\n await exit(code as 0 | 1);\n }\n if (signal) {\n logger.error(`MCP server was killed with signal ${signal}`);\n await exit(0);\n }\n });\n }\n\n static getInstance(): LocadexManager {\n if (!LocadexManager.instance) {\n throw new Error('LocadexManager not initialized');\n }\n return LocadexManager.instance;\n }\n\n static initialize(params: {\n rootDirectory: string;\n appDirectory: string;\n mcpTransport: 'sse' | 'stdio';\n apiKey: string;\n metadata: Partial<LocadexRunMetadata>;\n cliOptions: CliOptions;\n options: Partial<LocadexConfig>;\n }): void {\n if (!LocadexManager.instance) {\n LocadexManager.instance = new LocadexManager(params);\n logger.initialize(params.cliOptions, LocadexManager.instance.logFile);\n\n logger.debugMessage(\n `Locadex loaded with config: ${JSON.stringify(\n LocadexManager.instance.config,\n null,\n 2\n )}`\n );\n LocadexManager.instance.startMcpServer();\n }\n }\n\n static reset(): void {\n if (LocadexManager.instance) {\n LocadexManager.instance.cleanup();\n LocadexManager.instance = undefined;\n }\n }\n\n createSingleAgent(\n id: string,\n options: { maxTurns?: number } = {}\n ): ClaudeCodeRunner {\n return new ClaudeCodeRunner(this, this.agentAbortController, {\n apiKey: this.apiKey,\n mcpConfig: this.mcpConfigPath,\n maxTurns: this.maxTurns,\n id,\n });\n }\n\n createAgentPool(): void {\n if (this.agentPool.size === 0) {\n for (let i = 0; i < this.maxConcurrency; i++) {\n const agentId = `claude_task_agent_${i + 1}`;\n this.agentPool.set(agentId, {\n agent: this.createSingleAgent(agentId),\n busy: false,\n });\n }\n }\n }\n\n async getAvailableAgent(): Promise<{\n id: string;\n agent: ClaudeCodeRunner;\n } | null> {\n return new Promise((resolve) => {\n this.agentMutex = this.agentMutex.then(() => {\n for (const [id, agentData] of this.agentPool) {\n if (!agentData.busy) {\n agentData.busy = true;\n resolve({\n id,\n agent: agentData.agent,\n });\n return;\n }\n }\n resolve(null);\n });\n });\n }\n\n markAgentFree(agentId: string): void {\n const agentData = this.agentPool.get(agentId);\n if (agentData) {\n agentData.busy = false;\n }\n }\n\n getAgentPool(): Map<\n string,\n { agent: ClaudeCodeRunner; sessionId?: string; busy: boolean }\n > {\n return this.agentPool;\n }\n\n cleanupAgents(): void {\n logger.debugMessage('Cleaning up all Claude Code agents and processes');\n\n // Abort all active processes\n this.agentAbortController.abort();\n\n // Mark agents as free\n for (const agentData of this.agentPool.values()) {\n agentData.busy = false;\n }\n\n // Clear the agent pool\n this.agentPool.clear();\n }\n\n getFilesStateFilePath(): string {\n return this.filesStateFilePath;\n }\n getMetadataFilePath(): string {\n return this.metadataFilePath;\n }\n getMaxConcurrency(): number {\n return this.maxConcurrency;\n }\n getBatchSize(): number {\n return this.batchSize;\n }\n getTimeoutFactor(): number {\n return this.timeout;\n }\n getConfig(): LocadexConfig {\n return this.config;\n }\n\n getLockFilePath(): string {\n return this.lockFilePath;\n }\n\n cleanup(): void {\n if (this.aborted) {\n return;\n }\n this.aborted = true;\n // Clean up agents first (if not already done)\n this.cleanupAgents();\n\n // Clean up MCP process using abort controller\n if (this.mcpProcess && !this.mcpProcess.killed) {\n logger.debugMessage('Terminating MCP process via abort controller');\n this.mcpAbortController.abort();\n\n // Give the process a moment to handle the abort signal gracefully\n setTimeout(() => {\n if (this.mcpProcess && !this.mcpProcess.killed) {\n logger.debugMessage('Force killing MCP process as fallback');\n this.mcpProcess.kill('SIGTERM');\n }\n }, 1000);\n }\n }\n\n getLogDirectory(): string {\n return this.currentRunDir;\n }\n\n getAgentAbortController(): AbortController {\n return this.agentAbortController;\n }\n\n isAborted(): boolean {\n return this.aborted;\n }\n}\n"]}
1
+ {"version":3,"file":"locadexManager.js","sourceRoot":"/","sources":["utils/locadexManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { ClaudeCodeRunner, ClaudeRunnerOptions } from './claudeCode.js';\nimport { fromPackageRoot } from './getPaths.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { FileEntry } from './dag/getFiles.js';\nimport { logger } from '../logging/logger.js';\nimport { addToGitIgnore } from './fs/writeFiles.js';\nimport { spawn } from 'node:child_process';\nimport type { ChildProcess } from 'node:child_process';\nimport { setTimeout } from 'node:timers';\nimport { AgentStats } from './stats.js';\nimport { CliOptions, LocadexConfig } from '../types/cli.js';\nimport { findAvailablePort } from '../mcp/getPort.js';\nimport { createConfig, getConfig } from './config.js';\nimport { gracefulShutdown, exit } from './shutdown.js';\nimport { LOCKFILE_NAME } from './lockfile.js';\n\nexport interface LocadexRunMetadata {\n createdAt: string;\n locadexVersion: string;\n workingDirectory: string;\n projectName: string;\n transport: 'sse' | 'stdio';\n tempDirectory: string;\n nodeVersion: string;\n platform: string;\n arch: string;\n logFile: string;\n batchSize: number;\n maxConcurrency: number;\n [key: string]: any;\n}\n\nconst mcpSseConfig = {\n mcpServers: {\n locadex: {\n type: 'sse',\n url: 'http://localhost:8888/sse',\n },\n },\n};\n\nexport class LocadexManager {\n private static instance: LocadexManager | undefined;\n private mcpProcess: ChildProcess | undefined;\n private mcpTransport: 'sse' | 'stdio';\n\n // Paths\n private mcpConfigPath: string;\n private filesStateFilePath: string;\n private metadataFilePath: string;\n private lockFilePath: string;\n private currentRunDir: string;\n public locadexDirectory: string;\n public appDirectory: string;\n public rootDirectory: string;\n\n // Config\n private apiKey: string;\n private maxConcurrency: number;\n private batchSize: number;\n private timeout: number;\n private defaultSoftTurnLimit: number = 100;\n\n // Agent pool\n private agentPool: Map<string, { agent: ClaudeCodeRunner; busy: boolean }>;\n\n // Abort controllers\n private agentAbortController: AbortController;\n private mcpAbortController: AbortController;\n private aborted: boolean = false;\n\n // State\n private agentMutex = Promise.resolve();\n private config: LocadexConfig;\n public stats: AgentStats;\n public logFile: string;\n\n private constructor(params: {\n rootDirectory: string;\n appDirectory: string;\n mcpTransport: 'sse' | 'stdio';\n apiKey: string;\n metadata: Partial<LocadexRunMetadata>;\n options: Partial<LocadexConfig>;\n }) {\n this.apiKey = params.apiKey;\n this.agentPool = new Map();\n this.stats = new AgentStats();\n this.mcpTransport = params.mcpTransport;\n this.agentAbortController = new AbortController();\n this.mcpAbortController = new AbortController();\n\n // appDirectory is the absolute path to the app directory\n this.appDirectory = params.appDirectory;\n this.rootDirectory = params.rootDirectory;\n\n this.locadexDirectory = path.resolve(this.rootDirectory, '.locadex');\n this.currentRunDir = path.resolve(\n this.locadexDirectory,\n 'runs',\n Date.now().toString()\n );\n fs.mkdirSync(this.currentRunDir, { recursive: true });\n\n this.config = getConfig(\n this.locadexDirectory,\n this.rootDirectory,\n this.appDirectory,\n params.options\n );\n logger.debugMessage(\n `Locadex loaded with config: ${JSON.stringify(this.config, null, 2)}`\n );\n\n createConfig(this.locadexDirectory, {\n batchSize: this.config.batchSize,\n maxConcurrency: this.config.maxConcurrency,\n matchingFiles: this.config.matchingFiles,\n timeout: this.config.timeout,\n });\n\n addToGitIgnore(this.rootDirectory, '.locadex/runs');\n\n this.maxConcurrency = this.config.maxConcurrency;\n this.batchSize = this.config.batchSize;\n this.timeout = this.config.timeout;\n this.mcpConfigPath = path.resolve(this.currentRunDir, 'mcp.json');\n this.filesStateFilePath = path.resolve(\n this.currentRunDir,\n 'files-state.json'\n );\n this.metadataFilePath = path.resolve(this.currentRunDir, 'metadata.json');\n this.logFile = path.resolve(this.currentRunDir, 'log.txt');\n this.lockFilePath = path.resolve(this.locadexDirectory, LOCKFILE_NAME);\n\n // Create files-state.json\n const filesState: FileEntry[] = [];\n fs.writeFileSync(\n this.filesStateFilePath,\n JSON.stringify(filesState, null, 2)\n );\n\n // Create metadata.json\n const metadata: LocadexRunMetadata = {\n createdAt: new Date().toISOString(),\n locadexVersion: JSON.parse(\n fs.readFileSync(fromPackageRoot('package.json'), 'utf8')\n ).version,\n workingDirectory: this.appDirectory,\n projectName: path.basename(this.appDirectory),\n transport: params.mcpTransport,\n tempDirectory: this.currentRunDir,\n nodeVersion: process.version,\n platform: process.platform,\n arch: process.arch,\n logFile: this.logFile,\n batchSize: this.config.batchSize,\n maxConcurrency: this.config.maxConcurrency,\n ...params.metadata,\n };\n fs.writeFileSync(this.metadataFilePath, JSON.stringify(metadata, null, 2));\n\n // Register cleanup with graceful shutdown\n gracefulShutdown.addHandler({\n name: 'locadex-manager-cleanup',\n handler: () => this.cleanup(),\n timeout: 3000,\n });\n }\n\n async startMcpServer() {\n if (this.mcpTransport === 'stdio') {\n return;\n }\n\n // First, search for an available port\n const port = await findAvailablePort(8888);\n mcpSseConfig.mcpServers.locadex.url = `http://localhost:${port}/sse`;\n fs.writeFileSync(this.mcpConfigPath, JSON.stringify(mcpSseConfig, null, 2));\n\n logger.debugMessage(\n `Starting MCP server on port ${port} with config: ${JSON.stringify(\n mcpSseConfig,\n null,\n 2\n )}`\n );\n\n this.mcpProcess = spawn('node', [fromPackageRoot('dist/mcp.js')], {\n env: {\n ...process.env,\n LOCADEX_FILES_STATE_FILE_PATH: this.filesStateFilePath,\n LOCADEX_VERBOSE: logger.verbose ? 'true' : 'false',\n LOCADEX_DEBUG: logger.debug ? 'true' : 'false',\n LOCADEX_LOG_FILE_PATH: this.logFile,\n PORT: port.toString(),\n },\n stdio: ['ignore', 'inherit', 'inherit'],\n signal: this.mcpAbortController.signal,\n });\n\n this.mcpProcess.on('error', async (error) => {\n if (error.name === 'AbortError') {\n logger.debugMessage('MCP server was closed');\n } else {\n logger.error(`MCP server failed to start: ${error.message}`);\n await exit(1);\n }\n });\n\n this.mcpProcess.on('exit', async (code, signal) => {\n if (code !== 0 && code !== null) {\n logger.error(`MCP server exited with code ${code}`);\n await exit(code as 0 | 1);\n }\n if (signal) {\n logger.error(`MCP server was killed with signal ${signal}`);\n await exit(0);\n }\n });\n }\n\n static getInstance(): LocadexManager {\n if (!LocadexManager.instance) {\n throw new Error('LocadexManager not initialized');\n }\n return LocadexManager.instance;\n }\n\n static initialize(params: {\n rootDirectory: string;\n appDirectory: string;\n mcpTransport: 'sse' | 'stdio';\n apiKey: string;\n metadata: Partial<LocadexRunMetadata>;\n cliOptions: CliOptions;\n options: Partial<LocadexConfig>;\n }): void {\n if (!LocadexManager.instance) {\n LocadexManager.instance = new LocadexManager(params);\n logger.initialize(params.cliOptions, LocadexManager.instance.logFile);\n\n logger.debugMessage(\n `Locadex loaded with config: ${JSON.stringify(\n LocadexManager.instance.config,\n null,\n 2\n )}`\n );\n LocadexManager.instance.startMcpServer();\n }\n }\n\n static reset(): void {\n if (LocadexManager.instance) {\n LocadexManager.instance.cleanup();\n LocadexManager.instance = undefined;\n }\n }\n\n createSingleAgent(\n id: string,\n options: ClaudeRunnerOptions\n ): ClaudeCodeRunner {\n return new ClaudeCodeRunner(this, this.agentAbortController, {\n apiKey: this.apiKey,\n mcpConfig: this.mcpConfigPath,\n softTurnLimit: options.softTurnLimit ?? this.defaultSoftTurnLimit,\n id,\n });\n }\n\n createAgentPool(options: ClaudeRunnerOptions): void {\n if (this.agentPool.size === 0) {\n for (let i = 0; i < this.maxConcurrency; i++) {\n const agentId = `claude_task_agent_${i + 1}`;\n this.agentPool.set(agentId, {\n agent: this.createSingleAgent(agentId, options),\n busy: false,\n });\n }\n }\n }\n\n async getAvailableAgent(): Promise<{\n id: string;\n agent: ClaudeCodeRunner;\n } | null> {\n return new Promise((resolve) => {\n this.agentMutex = this.agentMutex.then(() => {\n for (const [id, agentData] of this.agentPool) {\n if (!agentData.busy) {\n agentData.busy = true;\n resolve({\n id,\n agent: agentData.agent,\n });\n return;\n }\n }\n resolve(null);\n });\n });\n }\n\n markAgentFree(agentId: string): void {\n const agentData = this.agentPool.get(agentId);\n if (agentData) {\n agentData.busy = false;\n }\n }\n\n getAgentPool(): Map<\n string,\n { agent: ClaudeCodeRunner; sessionId?: string; busy: boolean }\n > {\n return this.agentPool;\n }\n\n cleanupAgents(): void {\n logger.debugMessage('Cleaning up all Claude Code agents and processes');\n\n // Abort all active processes\n this.agentAbortController.abort();\n\n // Mark agents as free\n for (const agentData of this.agentPool.values()) {\n agentData.busy = false;\n }\n\n // Clear the agent pool\n this.agentPool.clear();\n }\n\n getFilesStateFilePath(): string {\n return this.filesStateFilePath;\n }\n getMetadataFilePath(): string {\n return this.metadataFilePath;\n }\n getMaxConcurrency(): number {\n return this.maxConcurrency;\n }\n getBatchSize(): number {\n return this.batchSize;\n }\n getTimeoutFactor(): number {\n return this.timeout;\n }\n getConfig(): LocadexConfig {\n return this.config;\n }\n\n getLockFilePath(): string {\n return this.lockFilePath;\n }\n\n cleanup(): void {\n if (this.aborted) {\n return;\n }\n this.aborted = true;\n // Clean up agents first (if not already done)\n this.cleanupAgents();\n\n // Clean up MCP process using abort controller\n if (this.mcpProcess && !this.mcpProcess.killed) {\n logger.debugMessage('Terminating MCP process via abort controller');\n this.mcpAbortController.abort();\n\n // Give the process a moment to handle the abort signal gracefully\n setTimeout(() => {\n if (this.mcpProcess && !this.mcpProcess.killed) {\n logger.debugMessage('Force killing MCP process as fallback');\n this.mcpProcess.kill('SIGTERM');\n }\n }, 1000);\n }\n }\n\n getLogDirectory(): string {\n return this.currentRunDir;\n }\n\n getAgentAbortController(): AbortController {\n return this.agentAbortController;\n }\n\n isAborted(): boolean {\n return this.aborted;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "locadex",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "An AI agent for internationalization",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",