locadex 0.1.0 → 0.1.1

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.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#360](https://github.com/generaltranslation/gt/pull/360) [`c3dff6b`](https://github.com/generaltranslation/gt/commit/c3dff6bb527d9831a91c3a5072f8f6af62f8f5a5) Thanks [@brian-lou](https://github.com/brian-lou)! - Update setup process to fix package.json edits
8
+
9
+ - [#362](https://github.com/generaltranslation/gt/pull/362) [`134a0fc`](https://github.com/generaltranslation/gt/commit/134a0fc4203e3659c3d0c38684e1e4cc705a7485) Thanks [@brian-lou](https://github.com/brian-lou)! - Fix mcp startup script location
10
+
3
11
  ## 0.1.0
4
12
 
5
13
  ### Minor Changes
package/dist/mcp.js CHANGED
@@ -19,10 +19,10 @@ export async function start() {
19
19
  logger.initialize({ verbose, debug }, logFile);
20
20
  if (stateFile && existsSync(stateFile)) {
21
21
  const state = JSON.parse(readFileSync(stateFile, 'utf8'));
22
- logger.debugMessage(`[locadex-mcp-sse] state: ${JSON.stringify(state, null, 2)}`);
22
+ logger.debugMessage(`[locadex-mcp] state: ${JSON.stringify(state, null, 2)}`);
23
23
  }
24
24
  else {
25
- throw new Error(`[locadex-mcp-sse] state file not found: ${stateFile}`);
25
+ throw new Error(`[locadex-mcp] state file not found: ${stateFile}`);
26
26
  }
27
27
  const mcpServer = new McpServer({
28
28
  name: 'Locadex: AI Agent for Internationalization',
@@ -68,7 +68,7 @@ export async function start() {
68
68
  }
69
69
  // Start the SSE server
70
70
  start().catch(async (error) => {
71
- logger.error(`[locadex-mcp-sse] Failed to start: ${error instanceof Error ? error.message : String(error)}`);
71
+ logger.error(`[locadex-mcp] Failed to start: ${error instanceof Error ? error.message : String(error)}`);
72
72
  await exit(1);
73
73
  });
74
74
  //# sourceMappingURL=mcp.js.map
package/dist/mcp.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.js","sourceRoot":"/","sources":["mcp.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,KAAK;IACzB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC;IAC5D,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;IAClD,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3E,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,aAAa,CAAC,CAAC;IAEpD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,MAAM,CAAC;IACvD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,MAAM,CAAC;IAEnD,MAAM,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,OAAO,CAAC,CAAC;IAE/C,IAAI,SAAS,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;QAC1D,MAAM,CAAC,YAAY,CACjB,4BAA4B,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAC7D,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,KAAK,CAAC,2CAA2C,SAAS,EAAE,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC;QAC9B,IAAI,EAAE,4CAA4C;QAClD,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,eAAe,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC;aACvE,OAAO;KACX,CAAC,CAAC;IAEH,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IACtB,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAExB,yCAAyC;IACzC,MAAM,UAAU,GAAG;QACjB,UAAU,EAAE,EAAmD;QAC/D,GAAG,EAAE,EAAwC;KAC9C,CAAC;IAEF,YAAY,CAAC,SAAS,CAAC,CAAC;IACxB,cAAc,CAAC,SAAS,CAAC,CAAC;IAE1B,kCAAkC;IAClC,iDAAiD;IACjD,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QACjC,MAAM,SAAS,GAAG,IAAI,kBAAkB,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;QAC3D,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC;QAEhD,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACnB,OAAO,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,MAAM,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,0CAA0C;IAC1C,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QACvC,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,SAAmB,CAAC;QAChD,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC5C,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,SAAS,CAAC,iBAAiB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QACxD,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;QACpB,MAAM,WAAW,GACf,IAAI,KAAK,aAAa;YACpB,CAAC,CAAC,GAAG,IAAI,eAAe,aAAa,cAAc;YACnD,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC;QAChB,MAAM,CAAC,YAAY,CACjB,iCAAiC,WAAW,oBAAoB,SAAS,EAAE,CAC5E,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,uBAAuB;AACvB,KAAK,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;IAC5B,MAAM,CAAC,KAAK,CACV,sCAAsC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAC/F,CAAC;IACF,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC;AAChB,CAAC,CAAC,CAAC","sourcesContent":["#!/usr/bin/env node\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { addDocsTools } from './mcp/tools/docs.js';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { fromPackageRoot } from './utils/getPaths.js';\nimport { addGuidesTools } from './mcp/tools/guides.js';\nimport express from 'express';\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';\nimport { logger } from './logging/logger.js';\nimport { findAvailablePort } from './mcp/getPort.js';\nimport { exit } from './utils/shutdown.js';\n\nexport async function start() {\n const stateFile = process.env.LOCADEX_FILES_STATE_FILE_PATH;\n const logFile = process.env.LOCADEX_LOG_FILE_PATH;\n const requestedPort = process.env.PORT ? parseInt(process.env.PORT) : 8888;\n const port = await findAvailablePort(requestedPort);\n\n const verbose = process.env.LOCADEX_VERBOSE === 'true';\n const debug = process.env.LOCADEX_DEBUG === 'true';\n\n logger.initialize({ verbose, debug }, logFile);\n\n if (stateFile && existsSync(stateFile)) {\n const state = JSON.parse(readFileSync(stateFile, 'utf8'));\n logger.debugMessage(\n `[locadex-mcp-sse] state: ${JSON.stringify(state, null, 2)}`\n );\n } else {\n throw new Error(`[locadex-mcp-sse] state file not found: ${stateFile}`);\n }\n\n const mcpServer = new McpServer({\n name: 'Locadex: AI Agent for Internationalization',\n version: JSON.parse(readFileSync(fromPackageRoot('package.json'), 'utf8'))\n .version,\n });\n\n const app = express();\n app.use(express.json());\n\n // Store transports for each session type\n const transports = {\n streamable: {} as Record<string, StreamableHTTPServerTransport>,\n sse: {} as Record<string, SSEServerTransport>,\n };\n\n addDocsTools(mcpServer);\n addGuidesTools(mcpServer);\n\n // SSE endpoint for legacy clients\n // Claude Code only supports SSE as of 2025-06-04\n app.get('/sse', async (req, res) => {\n const transport = new SSEServerTransport('/messages', res);\n transports.sse[transport.sessionId] = transport;\n\n res.on('close', () => {\n delete transports.sse[transport.sessionId];\n });\n\n await mcpServer.connect(transport);\n });\n\n // Companion endpoint for sending messages\n app.post('/messages', async (req, res) => {\n const sessionId = req.query.sessionId as string;\n const transport = transports.sse[sessionId];\n if (transport) {\n await transport.handlePostMessage(req, res, req.body);\n } else {\n res.status(400).send('No transport found for sessionId');\n }\n });\n\n app.listen(port, () => {\n const portMessage =\n port !== requestedPort\n ? `${port} (requested ${requestedPort} was in use)`\n : `${port}`;\n logger.debugMessage(\n `[locadex-mcp] started on port ${portMessage} with state file ${stateFile}`\n );\n });\n}\n\n// Start the SSE server\nstart().catch(async (error) => {\n logger.error(\n `[locadex-mcp-sse] Failed to start: ${error instanceof Error ? error.message : String(error)}`\n );\n await exit(1);\n});\n"]}
1
+ {"version":3,"file":"mcp.js","sourceRoot":"/","sources":["mcp.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { addDocsTools } from './mcp/tools/docs.js';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { fromPackageRoot } from './utils/getPaths.js';\nimport { addGuidesTools } from './mcp/tools/guides.js';\nimport express from 'express';\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';\nimport { logger } from './logging/logger.js';\nimport { findAvailablePort } from './mcp/getPort.js';\nimport { exit } from './utils/shutdown.js';\n\nexport async function start() {\n const stateFile = process.env.LOCADEX_FILES_STATE_FILE_PATH;\n const logFile = process.env.LOCADEX_LOG_FILE_PATH;\n const requestedPort = process.env.PORT ? parseInt(process.env.PORT) : 8888;\n const port = await findAvailablePort(requestedPort);\n\n const verbose = process.env.LOCADEX_VERBOSE === 'true';\n const debug = process.env.LOCADEX_DEBUG === 'true';\n\n logger.initialize({ verbose, debug }, logFile);\n\n if (stateFile && existsSync(stateFile)) {\n const state = JSON.parse(readFileSync(stateFile, 'utf8'));\n logger.debugMessage(\n `[locadex-mcp] state: ${JSON.stringify(state, null, 2)}`\n );\n } else {\n throw new Error(`[locadex-mcp] state file not found: ${stateFile}`);\n }\n\n const mcpServer = new McpServer({\n name: 'Locadex: AI Agent for Internationalization',\n version: JSON.parse(readFileSync(fromPackageRoot('package.json'), 'utf8'))\n .version,\n });\n\n const app = express();\n app.use(express.json());\n\n // Store transports for each session type\n const transports = {\n streamable: {} as Record<string, StreamableHTTPServerTransport>,\n sse: {} as Record<string, SSEServerTransport>,\n };\n\n addDocsTools(mcpServer);\n addGuidesTools(mcpServer);\n\n // SSE endpoint for legacy clients\n // Claude Code only supports SSE as of 2025-06-04\n app.get('/sse', async (req, res) => {\n const transport = new SSEServerTransport('/messages', res);\n transports.sse[transport.sessionId] = transport;\n\n res.on('close', () => {\n delete transports.sse[transport.sessionId];\n });\n\n await mcpServer.connect(transport);\n });\n\n // Companion endpoint for sending messages\n app.post('/messages', async (req, res) => {\n const sessionId = req.query.sessionId as string;\n const transport = transports.sse[sessionId];\n if (transport) {\n await transport.handlePostMessage(req, res, req.body);\n } else {\n res.status(400).send('No transport found for sessionId');\n }\n });\n\n app.listen(port, () => {\n const portMessage =\n port !== requestedPort\n ? `${port} (requested ${requestedPort} was in use)`\n : `${port}`;\n logger.debugMessage(\n `[locadex-mcp] started on port ${portMessage} with state file ${stateFile}`\n );\n });\n}\n\n// Start the SSE server\nstart().catch(async (error) => {\n logger.error(\n `[locadex-mcp] Failed to start: ${error instanceof Error ? error.message : String(error)}`\n );\n await exit(1);\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.ts","sourceRoot":"/","sources":["tasks/setup.ts"],"names":[],"mappings":"AA4BA,wBAAsB,SAAS,CAC7B,aAAa,EAAE,OAAO,EACtB,uBAAuB,CAAC,EAAE,MAAM,iBA0HjC"}
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"/","sources":["tasks/setup.ts"],"names":[],"mappings":"AA4BA,wBAAsB,SAAS,CAC7B,aAAa,EAAE,OAAO,EACtB,uBAAuB,CAAC,EAAE,MAAM,iBA4HjC"}
@@ -27,7 +27,7 @@ export async function setupTask(bypassPrompts, specifiedPackageManager) {
27
27
  }
28
28
  const manager = LocadexManager.getInstance();
29
29
  const packageManager = await getPackageManager(manager.rootDirectory, specifiedPackageManager);
30
- const appPackageJson = await getPackageJson(manager.appDirectory);
30
+ let appPackageJson = await getPackageJson(manager.appDirectory);
31
31
  if (appPackageJson) {
32
32
  if (!isPackageInstalled('gt-next', appPackageJson)) {
33
33
  const spinner = createSpinner('timer');
@@ -73,6 +73,8 @@ export async function setupTask(bypassPrompts, specifiedPackageManager) {
73
73
  });
74
74
  logger.success(`Feel free to edit ${chalk.cyan('gt.config.json')} to customize your translation setup. Docs: https://generaltranslation.com/docs/cli/reference/config`);
75
75
  // Add translate to scripts
76
+ // Re-get the package.json to make sure it's updated
77
+ appPackageJson = await getPackageJson(manager.appDirectory);
76
78
  if (appPackageJson) {
77
79
  await addTranslateScript(manager, appPackageJson, packageManager);
78
80
  }
@@ -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 const 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 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(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"]}
@@ -115,7 +115,7 @@ export class LocadexManager {
115
115
  mcpSseConfig.mcpServers.locadex.url = `http://localhost:${port}/sse`;
116
116
  fs.writeFileSync(this.mcpConfigPath, JSON.stringify(mcpSseConfig, null, 2));
117
117
  logger.debugMessage(`Starting MCP server on port ${port} with config: ${JSON.stringify(mcpSseConfig, null, 2)}`);
118
- this.mcpProcess = spawn('node', [fromPackageRoot('dist/mcp-sse.js')], {
118
+ this.mcpProcess = spawn('node', [fromPackageRoot('dist/mcp.js')], {
119
119
  env: {
120
120
  ...process.env,
121
121
  LOCADEX_FILES_STATE_FILE_PATH: this.filesStateFilePath,
@@ -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-sse.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 } 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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "locadex",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "An AI agent for internationalization",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",