locadex 0.1.0-alpha.9 → 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 +20 -0
- package/README.md +3 -5
- package/dist/cli.js +11 -10
- package/dist/cli.js.map +1 -1
- package/dist/commands/i18n.d.ts.map +1 -1
- package/dist/commands/i18n.js +15 -14
- package/dist/commands/i18n.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +15 -14
- package/dist/commands/setup.js.map +1 -1
- package/dist/index.js +1 -4
- package/dist/index.js.map +1 -1
- package/dist/logging/console.js +2 -5
- package/dist/logging/console.js.map +1 -1
- package/dist/logging/logger.d.ts +4 -2
- package/dist/logging/logger.d.ts.map +1 -1
- package/dist/logging/logger.js +1 -4
- package/dist/logging/logger.js.map +1 -1
- package/dist/mcp/getDocs.js +1 -4
- package/dist/mcp/getDocs.js.map +1 -1
- package/dist/mcp/getGuide.js +1 -4
- package/dist/mcp/getGuide.js.map +1 -1
- package/dist/mcp/getPort.js +1 -4
- package/dist/mcp/getPort.js.map +1 -1
- package/dist/mcp/tools/docs.js +1 -4
- package/dist/mcp/tools/docs.js.map +1 -1
- package/dist/mcp/tools/guides.js +1 -4
- package/dist/mcp/tools/guides.js.map +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +56 -16
- package/dist/mcp.js.map +1 -1
- package/dist/prompts/system.js +1 -4
- package/dist/prompts/system.js.map +1 -1
- package/dist/tasks/concurrency.d.ts +72 -0
- package/dist/tasks/concurrency.d.ts.map +1 -0
- package/dist/tasks/concurrency.js +132 -0
- package/dist/tasks/concurrency.js.map +1 -0
- package/dist/tasks/i18n.d.ts.map +1 -1
- package/dist/tasks/i18n.js +60 -127
- package/dist/tasks/i18n.js.map +1 -1
- package/dist/tasks/setup.d.ts.map +1 -1
- package/dist/tasks/setup.js +40 -44
- package/dist/tasks/setup.js.map +1 -1
- package/dist/telemetry.js +1 -4
- package/dist/telemetry.js.map +1 -1
- package/dist/types/claude-sdk.d.ts +1 -1
- package/dist/types/claude-sdk.d.ts.map +1 -1
- package/dist/types/claude-sdk.js +1 -4
- package/dist/types/claude-sdk.js.map +1 -1
- package/dist/types/cli.d.ts +3 -0
- package/dist/types/cli.d.ts.map +1 -1
- package/dist/types/cli.js +1 -4
- package/dist/types/cli.js.map +1 -1
- package/dist/utils/claudeCode.d.ts +6 -5
- package/dist/utils/claudeCode.d.ts.map +1 -1
- package/dist/utils/claudeCode.js +50 -17
- package/dist/utils/claudeCode.js.map +1 -1
- package/dist/utils/config.d.ts +4 -3
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +33 -20
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/dag/createDag.d.ts.map +1 -1
- package/dist/utils/dag/createDag.js +10 -11
- package/dist/utils/dag/createDag.js.map +1 -1
- package/dist/utils/dag/extractFiles.d.ts.map +1 -1
- package/dist/utils/dag/extractFiles.js +6 -9
- package/dist/utils/dag/extractFiles.js.map +1 -1
- package/dist/utils/dag/getFiles.d.ts +1 -12
- package/dist/utils/dag/getFiles.d.ts.map +1 -1
- package/dist/utils/dag/getFiles.js +5 -53
- package/dist/utils/dag/getFiles.js.map +1 -1
- package/dist/utils/dag/matchFiles.d.ts +2 -2
- package/dist/utils/dag/matchFiles.d.ts.map +1 -1
- package/dist/utils/dag/matchFiles.js +3 -6
- package/dist/utils/dag/matchFiles.js.map +1 -1
- package/dist/utils/fs/findConfigs.d.ts +4 -4
- package/dist/utils/fs/findConfigs.d.ts.map +1 -1
- package/dist/utils/fs/findConfigs.js +7 -13
- package/dist/utils/fs/findConfigs.js.map +1 -1
- package/dist/utils/fs/getFiles.d.ts +1 -1
- package/dist/utils/fs/getFiles.d.ts.map +1 -1
- package/dist/utils/fs/getFiles.js +3 -6
- package/dist/utils/fs/getFiles.js.map +1 -1
- package/dist/utils/fs/git.d.ts +6 -0
- package/dist/utils/fs/git.d.ts.map +1 -0
- package/dist/utils/fs/git.js +32 -0
- package/dist/utils/fs/git.js.map +1 -0
- package/dist/utils/fs/writeFiles.js +1 -4
- package/dist/utils/fs/writeFiles.js.map +1 -1
- package/dist/utils/getPaths.js +1 -4
- package/dist/utils/getPaths.js.map +1 -1
- package/dist/utils/locadexManager.d.ts +15 -5
- package/dist/utils/locadexManager.d.ts.map +1 -1
- package/dist/utils/locadexManager.js +80 -73
- package/dist/utils/locadexManager.js.map +1 -1
- package/dist/utils/lockfile.d.ts +2 -2
- package/dist/utils/lockfile.d.ts.map +1 -1
- package/dist/utils/lockfile.js +8 -17
- package/dist/utils/lockfile.js.map +1 -1
- package/dist/utils/packages/installPackage.d.ts +4 -0
- package/dist/utils/packages/installPackage.d.ts.map +1 -1
- package/dist/utils/packages/installPackage.js +41 -5
- package/dist/utils/packages/installPackage.js.map +1 -1
- package/dist/utils/session.js +1 -4
- package/dist/utils/session.js.map +1 -1
- package/dist/utils/shared.js +1 -4
- package/dist/utils/shared.js.map +1 -1
- package/dist/utils/shutdown.d.ts.map +1 -1
- package/dist/utils/shutdown.js +1 -9
- package/dist/utils/shutdown.js.map +1 -1
- package/dist/utils/stats.js +1 -4
- package/dist/utils/stats.js.map +1 -1
- package/guides/next/advanced/var-outside-client-server-component.md +1 -1
- package/package.json +4 -6
- package/dist/mcp/debugger.d.ts +0 -3
- package/dist/mcp/debugger.d.ts.map +0 -1
- package/dist/mcp/debugger.js +0 -37
- package/dist/mcp/debugger.js.map +0 -1
- package/dist/mcp-sse.d.ts +0 -3
- package/dist/mcp-sse.d.ts.map +0 -1
- package/dist/mcp-sse.js +0 -77
- package/dist/mcp-sse.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guides.js","sources":["mcp/tools/guides.ts"],"
|
|
1
|
+
{"version":3,"file":"guides.js","sourceRoot":"/","sources":["mcp/tools/guides.ts"],"names":[],"mappings":"AACA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AASjD,MAAM,CAAC,MAAM,MAAM,GAAY;IAC7B;QACE,EAAE,EAAE,0BAA0B;QAC9B,WAAW,EACT,uEAAuE;QACzE,IAAI,EAAE,oCAAoC;QAC1C,IAAI,EAAE,WAAW;KAClB;IACD;QACE,EAAE,EAAE,gBAAgB;QACpB,WAAW,EACT,wEAAwE;QAC1E,IAAI,EAAE,0BAA0B;QAChC,IAAI,EAAE,OAAO;KACd;IACD;QACE,EAAE,EAAE,qBAAqB;QACzB,WAAW,EACT,6HAA6H;QAC/H,IAAI,EAAE,+BAA+B;QACrC,IAAI,EAAE,OAAO;KACd;IACD;QACE,EAAE,EAAE,oBAAoB;QACxB,WAAW,EACT,sGAAsG;QACxG,IAAI,EAAE,8BAA8B;QACpC,IAAI,EAAE,OAAO;KACd;IACD;QACE,EAAE,EAAE,sBAAsB;QAC1B,WAAW,EACT,0IAA0I;QAC5I,IAAI,EAAE,gCAAgC;QACtC,IAAI,EAAE,OAAO;KACd;IACD;QACE,EAAE,EAAE,mCAAmC;QACvC,WAAW,EACT,gEAAgE;QAClE,IAAI,EAAE,6CAA6C;QACnD,IAAI,EAAE,OAAO;KACd;IACD;QACE,EAAE,EAAE,mCAAmC;QACvC,WAAW,EACT,gEAAgE;QAClE,IAAI,EAAE,6CAA6C;QACnD,IAAI,EAAE,OAAO;KACd;IACD;QACE,EAAE,EAAE,wCAAwC;QAC5C,WAAW,EACT,+OAA+O;QACjP,IAAI,EAAE,sDAAsD;QAC5D,IAAI,EAAE,UAAU;KACjB;IACD;QACE,EAAE,EAAE,wCAAwC;QAC5C,WAAW,EACT,+OAA+O;QACjP,IAAI,EAAE,sDAAsD;QAC5D,IAAI,EAAE,UAAU;KACjB;IACD;QACE,EAAE,EAAE,+CAA+C;QACnD,WAAW,EACT,+PAA+P;QACjQ,IAAI,EAAE,6DAA6D;QACnE,IAAI,EAAE,UAAU;KACjB;IACD;QACE,EAAE,EAAE,iCAAiC;QACrC,WAAW,EACT,2HAA2H;QAC7H,IAAI,EAAE,2CAA2C;QACjD,IAAI,EAAE,UAAU;KACjB;IACD;QACE,EAAE,EAAE,+CAA+C;QACnD,WAAW,EACT,gJAAgJ;QAClJ,IAAI,EAAE,yDAAyD;QAC/D,IAAI,EAAE,UAAU;KACjB;IACD;QACE,EAAE,EAAE,oCAAoC;QACxC,WAAW,EACT,+KAA+K;QACjL,IAAI,EAAE,8CAA8C;QACpD,IAAI,EAAE,UAAU;KACjB;IACD;QACE,EAAE,EAAE,yBAAyB;QAC7B,WAAW,EACT,8GAA8G;QAChH,IAAI,EAAE,mCAAmC;QACzC,IAAI,EAAE,UAAU;KACjB;CACF,CAAC;AAEF,MAAM,UAAU,cAAc,CAAC,MAAiB;IAC9C,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QACvB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,WAAW,EAAE,EAAE,EAAE,KAAK,IAAI,EAAE;YACtD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;YACxB,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;YAChD,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,CAAC,GAAG,CAAC,iBAAiB,KAAK,CAAC,EAAE,2BAA2B,IAAI,EAAE,CAAC,CAAC;gBACvE,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,yBAAyB,KAAK,EAAE;yBACvC;qBACF;oBACD,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YACD,MAAM,CAAC,GAAG,CACR,iBAAiB,KAAK,CAAC,EAAE,iCAAiC,IAAI,EAAE,CACjE,CAAC;YACF,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,OAAO,IAAI,EAAE;qBACpB;iBACF;aACF,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport getGuide from '../getGuide.js';\nimport { logger } from '../../logging/logger.js';\n\ntype Guide = {\n id: string;\n description: string;\n path: string;\n type: 'important' | 'basic' | 'advanced';\n};\n\nexport const guides: Guide[] = [\n {\n id: 'important_next-functions',\n description:\n 'Important documentation outlining the imports available in `gt-next`.',\n path: 'guides/next/important/functions.md',\n type: 'important',\n },\n {\n id: 'basic_next-jsx',\n description:\n 'Basic guide for translating JSX and HTML content in a Next.js project.',\n path: 'guides/next/basic/jsx.md',\n type: 'basic',\n },\n {\n id: 'basic_next-branches',\n description:\n 'Basic guide for using branch components and dealing with conditional logic in or pluralization in JSX in a Next.js project.',\n path: 'guides/next/basic/branches.md',\n type: 'basic',\n },\n {\n id: 'basic_next-strings',\n description:\n 'Basic guide for how to use `useGT()` and `getGT()` to internationalize strings in a Next.js project.',\n path: 'guides/next/basic/strings.md',\n type: 'basic',\n },\n {\n id: 'basic_next-variables',\n description:\n 'Basic guide for using internationalizing variable content (Currency, DateTime, Numbers, and other dynamic content) in a Next.js project.',\n path: 'guides/next/basic/variables.md',\n type: 'basic',\n },\n {\n id: 'basic_next-client-side-components',\n description:\n 'Basic guide on how to internationalize client-side components.',\n path: 'guides/next/basic/client-side-components.md',\n type: 'basic',\n },\n {\n id: 'basic_next-server-side-components',\n description:\n 'Basic guide on how to internationalize server-side components.',\n path: 'guides/next/basic/server-side-components.md',\n type: 'basic',\n },\n {\n id: 'advanced_next-outside-client-component',\n description:\n 'Advanced guide for wherever you see a `const` or `let` or a function outside of a function scope that needs to be internationalized. This guide is specifically for when these variables are ONLY used or imported by client side components.',\n path: 'guides/next/advanced/var-outside-client-component.md',\n type: 'advanced',\n },\n {\n id: 'advanced_next-outside-server-component',\n description:\n 'Advanced guide for wherever you see a `const` or `let` or a function outside of a function scope that needs to be internationalized. This guide is specifically for when these variables are ONLY used or imported by server side components.',\n path: 'guides/next/advanced/var-outside-server-component.md',\n type: 'advanced',\n },\n {\n id: 'advanced_next-outside-client-server-component',\n description:\n 'Advanced guide for wherever you see a `const` or `let` or a function outside of a function scope that needs to be internationalized. This guide is specifically for when these variables are used or imported by both client side and server side components.',\n path: 'guides/next/advanced/var-outside-client-server-component.md',\n type: 'advanced',\n },\n {\n id: 'advanced_next-ternary-operators',\n description:\n 'Advanced guide for complex scenarios with ternary operators or conditional statements that needs to be internationalized.',\n path: 'guides/next/advanced/ternary-operators.md',\n type: 'advanced',\n },\n {\n id: 'advanced_next-complicated-mapping-expressions',\n description:\n 'Advanced guide for wherever you see a mapping expression or mapping expression for a nested data structure that needs to be internationalized.',\n path: 'guides/next/advanced/complicated-mapping-expressions.md',\n type: 'advanced',\n },\n {\n id: 'advanced_next-interpolated-strings',\n description:\n 'Advanced guide for wherever you see a string with variables within/around it or interpolated string (template string literal with quasis) that needs to be internationalized.',\n path: 'guides/next/advanced/interpolated-strings.md',\n type: 'advanced',\n },\n {\n id: 'advanced_next-migrating',\n description:\n 'Advanced guide for migrating from an existing i18n library such as react-i18next or next-i18next to gt-next.',\n path: 'guides/next/advanced/migrating.md',\n type: 'advanced',\n },\n];\n\nexport function addGuidesTools(server: McpServer) {\n guides.forEach((guide) => {\n server.tool(guide.id, guide.description, {}, async () => {\n const path = guide.path;\n const { content, error } = await getGuide(path);\n if (error) {\n logger.log(`[locadex-mcp: ${guide.id}] Error fetching guide: ${path}`);\n return {\n content: [\n {\n type: 'text',\n text: `Error fetching guide: ${error}`,\n },\n ],\n isError: true,\n };\n }\n logger.log(\n `[locadex-mcp: ${guide.id}] Guide fetched successfully: ${path}`\n );\n return {\n content: [\n {\n type: 'text',\n text: content ?? '',\n },\n ],\n };\n });\n });\n}\n"]}
|
package/dist/mcp.d.ts
CHANGED
package/dist/mcp.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.d.ts","sourceRoot":"/","sources":["mcp.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"/","sources":["mcp.ts"],"names":[],"mappings":";AAcA,wBAAsB,KAAK,kBAuE1B"}
|
package/dist/mcp.js
CHANGED
|
@@ -1,34 +1,74 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="d5982bc6-3621-56f8-ac4a-8f0368dd1b1e")}catch(e){}}();
|
|
4
|
-
import './telemetry.js';
|
|
5
2
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
6
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
7
3
|
import { addDocsTools } from './mcp/tools/docs.js';
|
|
8
4
|
import { existsSync, readFileSync } from 'node:fs';
|
|
9
5
|
import { fromPackageRoot } from './utils/getPaths.js';
|
|
10
6
|
import { addGuidesTools } from './mcp/tools/guides.js';
|
|
11
|
-
|
|
7
|
+
import express from 'express';
|
|
8
|
+
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
|
|
9
|
+
import { logger } from './logging/logger.js';
|
|
10
|
+
import { findAvailablePort } from './mcp/getPort.js';
|
|
11
|
+
import { exit } from './utils/shutdown.js';
|
|
12
|
+
export async function start() {
|
|
12
13
|
const stateFile = process.env.LOCADEX_FILES_STATE_FILE_PATH;
|
|
14
|
+
const logFile = process.env.LOCADEX_LOG_FILE_PATH;
|
|
15
|
+
const requestedPort = process.env.PORT ? parseInt(process.env.PORT) : 8888;
|
|
16
|
+
const port = await findAvailablePort(requestedPort);
|
|
17
|
+
const verbose = process.env.LOCADEX_VERBOSE === 'true';
|
|
18
|
+
const debug = process.env.LOCADEX_DEBUG === 'true';
|
|
19
|
+
logger.initialize({ verbose, debug }, logFile);
|
|
13
20
|
if (stateFile && existsSync(stateFile)) {
|
|
14
21
|
const state = JSON.parse(readFileSync(stateFile, 'utf8'));
|
|
15
|
-
|
|
22
|
+
logger.debugMessage(`[locadex-mcp] state: ${JSON.stringify(state, null, 2)}`);
|
|
16
23
|
}
|
|
17
24
|
else {
|
|
18
25
|
throw new Error(`[locadex-mcp] state file not found: ${stateFile}`);
|
|
19
26
|
}
|
|
20
|
-
const
|
|
27
|
+
const mcpServer = new McpServer({
|
|
21
28
|
name: 'Locadex: AI Agent for Internationalization',
|
|
22
29
|
version: JSON.parse(readFileSync(fromPackageRoot('package.json'), 'utf8'))
|
|
23
30
|
.version,
|
|
24
31
|
});
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
const app = express();
|
|
33
|
+
app.use(express.json());
|
|
34
|
+
// Store transports for each session type
|
|
35
|
+
const transports = {
|
|
36
|
+
streamable: {},
|
|
37
|
+
sse: {},
|
|
38
|
+
};
|
|
39
|
+
addDocsTools(mcpServer);
|
|
40
|
+
addGuidesTools(mcpServer);
|
|
41
|
+
// SSE endpoint for legacy clients
|
|
42
|
+
// Claude Code only supports SSE as of 2025-06-04
|
|
43
|
+
app.get('/sse', async (req, res) => {
|
|
44
|
+
const transport = new SSEServerTransport('/messages', res);
|
|
45
|
+
transports.sse[transport.sessionId] = transport;
|
|
46
|
+
res.on('close', () => {
|
|
47
|
+
delete transports.sse[transport.sessionId];
|
|
48
|
+
});
|
|
49
|
+
await mcpServer.connect(transport);
|
|
50
|
+
});
|
|
51
|
+
// Companion endpoint for sending messages
|
|
52
|
+
app.post('/messages', async (req, res) => {
|
|
53
|
+
const sessionId = req.query.sessionId;
|
|
54
|
+
const transport = transports.sse[sessionId];
|
|
55
|
+
if (transport) {
|
|
56
|
+
await transport.handlePostMessage(req, res, req.body);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
res.status(400).send('No transport found for sessionId');
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
app.listen(port, () => {
|
|
63
|
+
const portMessage = port !== requestedPort
|
|
64
|
+
? `${port} (requested ${requestedPort} was in use)`
|
|
65
|
+
: `${port}`;
|
|
66
|
+
logger.debugMessage(`[locadex-mcp] started on port ${portMessage} with state file ${stateFile}`);
|
|
67
|
+
});
|
|
31
68
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
69
|
+
// Start the SSE server
|
|
70
|
+
start().catch(async (error) => {
|
|
71
|
+
logger.error(`[locadex-mcp] Failed to start: ${error instanceof Error ? error.message : String(error)}`);
|
|
72
|
+
await exit(1);
|
|
73
|
+
});
|
|
74
|
+
//# sourceMappingURL=mcp.js.map
|
package/dist/mcp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.js","sources":["mcp.ts"],"
|
|
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"]}
|
package/dist/prompts/system.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="1e9e969a-185e-5a86-a7a7-a61c5b750119")}catch(e){}}();
|
|
3
1
|
import { guides } from '../mcp/tools/guides.js';
|
|
4
2
|
import { docsTools } from '../mcp/tools/docs.js';
|
|
5
3
|
export const mcpDocsTools = Object.keys(docsTools).map((tool) => `mcp__locadex__${tool}`);
|
|
@@ -13,5 +11,4 @@ ${mcpDocsTools.join('\n')}
|
|
|
13
11
|
${mcpGuidesTools.join('\n')}
|
|
14
12
|
|
|
15
13
|
Generally, you should use the guides tools to help you with your tasks. You should only call the docs tools when you need specific information not covered by the guides.`;
|
|
16
|
-
//# sourceMappingURL=system.js.map
|
|
17
|
-
//# debugId=1e9e969a-185e-5a86-a7a7-a61c5b750119
|
|
14
|
+
//# sourceMappingURL=system.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system.js","sources":["prompts/system.ts"],"
|
|
1
|
+
{"version":3,"file":"system.js","sourceRoot":"/","sources":["prompts/system.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,CACpD,CAAC,IAAI,EAAE,EAAE,CAAC,iBAAiB,IAAI,EAAE,CAClC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,GAAG,CACtC,CAAC,KAAK,EAAE,EAAE,CAAC,iBAAiB,KAAK,CAAC,EAAE,EAAE,CACvC,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG;;;EAG1B,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;;;EAGvB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;;0KAE+I,CAAC","sourcesContent":["import { guides } from '../mcp/tools/guides.js';\nimport { docsTools } from '../mcp/tools/docs.js';\n\nexport const mcpDocsTools = Object.keys(docsTools).map(\n (tool) => `mcp__locadex__${tool}`\n);\n\nexport const mcpGuidesTools = guides.map(\n (guide) => `mcp__locadex__${guide.id}`\n);\n\nexport const allMcpPrompt = `You have access to mcp tools made available via the 'locadex' mcp server:\n\n## Documentation Tools:\n${mcpDocsTools.join('\\n')}\n\n## Guide Tools:\n${mcpGuidesTools.join('\\n')}\n\nGenerally, you should use the guides tools to help you with your tasks. You should only call the docs tools when you need specific information not covered by the guides.`;\n"]}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface for defining how to process tasks in parallel.
|
|
3
|
+
* Separates task preparation (preProcess) from result handling (postProcess).
|
|
4
|
+
*
|
|
5
|
+
* @template TTask - The type of individual tasks being processed
|
|
6
|
+
* @template TContext - The type of shared context/configuration
|
|
7
|
+
*/
|
|
8
|
+
export interface TaskProcessor<TTask, TContext> {
|
|
9
|
+
/**
|
|
10
|
+
* Prepares tasks for processing and generates the prompt for the AI agent.
|
|
11
|
+
* Called before each batch is sent to an agent.
|
|
12
|
+
*
|
|
13
|
+
* @param tasks - Batch of tasks to process
|
|
14
|
+
* @param context - Shared context containing configuration and state
|
|
15
|
+
* @returns Promise that resolves to the prompt string for the AI agent
|
|
16
|
+
*/
|
|
17
|
+
preProcess: (tasks: TTask[], context: TContext) => Promise<string>;
|
|
18
|
+
/**
|
|
19
|
+
* Handles the results after the AI agent completes processing.
|
|
20
|
+
* Called after each batch is successfully processed.
|
|
21
|
+
*
|
|
22
|
+
* @param tasks - The batch of tasks that were processed
|
|
23
|
+
* @param context - Shared context containing configuration and state
|
|
24
|
+
* @param agentReport - The report/output generated by the AI agent
|
|
25
|
+
*/
|
|
26
|
+
postProcess: (tasks: TTask[], context: TContext, agentReport: string) => Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Configuration options for parallel processing behavior.
|
|
30
|
+
*/
|
|
31
|
+
export interface ParallelProcessingOptions {
|
|
32
|
+
/** Number of concurrent agents to run in parallel */
|
|
33
|
+
concurrency: number;
|
|
34
|
+
/** Number of tasks to process in each batch */
|
|
35
|
+
batchSize: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Executes tasks in parallel using a pool of agents with proper concurrency control.
|
|
39
|
+
*
|
|
40
|
+
* This is a generic parallel processing framework that handles:
|
|
41
|
+
* - Task queue management with thread-safe access
|
|
42
|
+
* - Agent pool creation and lifecycle management
|
|
43
|
+
* - Error handling and abort signal propagation
|
|
44
|
+
* - Proper cleanup and resource management
|
|
45
|
+
*
|
|
46
|
+
* @template TTask - The type of tasks to process (e.g., string, object, etc.)
|
|
47
|
+
* @template TContext - The type of context passed to the processor functions
|
|
48
|
+
*
|
|
49
|
+
* @param taskQueue - Array of tasks to process. Will be consumed (mutated) during processing.
|
|
50
|
+
* @param processor - Object implementing preProcess and postProcess methods for task handling
|
|
51
|
+
* @param context - Context object passed to processor methods, containing shared state/config
|
|
52
|
+
* @param options - Configuration for parallel processing (concurrency level, batch size)
|
|
53
|
+
*
|
|
54
|
+
* @throws {Error} If processing fails or is aborted
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* const processor: TaskProcessor<string, { config: Config }> = {
|
|
59
|
+
* preProcess: async (files, context) => generatePrompt(files, context.config),
|
|
60
|
+
* postProcess: async (files, context, report) => handleResults(files, report)
|
|
61
|
+
* };
|
|
62
|
+
*
|
|
63
|
+
* await runParallelProcessing(
|
|
64
|
+
* ['file1.ts', 'file2.ts'],
|
|
65
|
+
* processor,
|
|
66
|
+
* { config: myConfig },
|
|
67
|
+
* { concurrency: 3, batchSize: 2 }
|
|
68
|
+
* );
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export declare function runParallelProcessing<TTask, TContext>(taskQueue: TTask[], processor: TaskProcessor<TTask, TContext>, context: TContext, options: ParallelProcessingOptions, maxRetries?: number): Promise<void>;
|
|
72
|
+
//# sourceMappingURL=concurrency.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { LocadexManager } from '../utils/locadexManager.js';
|
|
2
|
+
import { logger } from '../logging/logger.js';
|
|
3
|
+
import { exit } from '../utils/shutdown.js';
|
|
4
|
+
/**
|
|
5
|
+
* Executes tasks in parallel using a pool of agents with proper concurrency control.
|
|
6
|
+
*
|
|
7
|
+
* This is a generic parallel processing framework that handles:
|
|
8
|
+
* - Task queue management with thread-safe access
|
|
9
|
+
* - Agent pool creation and lifecycle management
|
|
10
|
+
* - Error handling and abort signal propagation
|
|
11
|
+
* - Proper cleanup and resource management
|
|
12
|
+
*
|
|
13
|
+
* @template TTask - The type of tasks to process (e.g., string, object, etc.)
|
|
14
|
+
* @template TContext - The type of context passed to the processor functions
|
|
15
|
+
*
|
|
16
|
+
* @param taskQueue - Array of tasks to process. Will be consumed (mutated) during processing.
|
|
17
|
+
* @param processor - Object implementing preProcess and postProcess methods for task handling
|
|
18
|
+
* @param context - Context object passed to processor methods, containing shared state/config
|
|
19
|
+
* @param options - Configuration for parallel processing (concurrency level, batch size)
|
|
20
|
+
*
|
|
21
|
+
* @throws {Error} If processing fails or is aborted
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* const processor: TaskProcessor<string, { config: Config }> = {
|
|
26
|
+
* preProcess: async (files, context) => generatePrompt(files, context.config),
|
|
27
|
+
* postProcess: async (files, context, report) => handleResults(files, report)
|
|
28
|
+
* };
|
|
29
|
+
*
|
|
30
|
+
* await runParallelProcessing(
|
|
31
|
+
* ['file1.ts', 'file2.ts'],
|
|
32
|
+
* processor,
|
|
33
|
+
* { config: myConfig },
|
|
34
|
+
* { concurrency: 3, batchSize: 2 }
|
|
35
|
+
* );
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export async function runParallelProcessing(taskQueue, processor, context, options, maxRetries = 1) {
|
|
39
|
+
const { concurrency, batchSize } = options;
|
|
40
|
+
const manager = LocadexManager.getInstance();
|
|
41
|
+
const agentAbortController = manager.getAgentAbortController();
|
|
42
|
+
let firstError = null;
|
|
43
|
+
// Mutex for task queue access
|
|
44
|
+
let taskQueueMutex = Promise.resolve();
|
|
45
|
+
// Helper function to safely get tasks from queue
|
|
46
|
+
const getNextTasks = async (batchSize) => {
|
|
47
|
+
return new Promise((resolve) => {
|
|
48
|
+
taskQueueMutex = taskQueueMutex.then(() => {
|
|
49
|
+
const tasks = taskQueue.splice(0, batchSize);
|
|
50
|
+
resolve(tasks);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
const processTask = async () => {
|
|
55
|
+
while (taskQueue.length > 0 && !agentAbortController.signal.aborted) {
|
|
56
|
+
// Check if we should abort early
|
|
57
|
+
if (agentAbortController.signal.aborted) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
// Get an available agent atomically
|
|
61
|
+
const agentInfo = await manager.getAvailableAgent();
|
|
62
|
+
if (!agentInfo) {
|
|
63
|
+
// No available agents, wait a bit (but check for abort)
|
|
64
|
+
await new Promise((resolve) => {
|
|
65
|
+
const timeout = global.setTimeout(resolve, 100);
|
|
66
|
+
agentAbortController.signal.addEventListener('abort', () => {
|
|
67
|
+
global.clearTimeout(timeout);
|
|
68
|
+
resolve(undefined);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const { id: agentId, agent } = agentInfo;
|
|
74
|
+
// Get the next batch of tasks (thread-safe)
|
|
75
|
+
const tasks = await getNextTasks(batchSize);
|
|
76
|
+
if (tasks.length === 0) {
|
|
77
|
+
manager.markAgentFree(agentId);
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
logger.debugMessage(`Using agent ${agentId} for ${tasks.length} tasks.`);
|
|
81
|
+
// Process tasks using the provided processor
|
|
82
|
+
try {
|
|
83
|
+
// Pre-process: generate prompt
|
|
84
|
+
const prompt = await processor.preProcess(tasks, context);
|
|
85
|
+
// dynamic timeout based on the number of tasks
|
|
86
|
+
const dynamicTimeoutSec = manager.getTimeoutFactor() * tasks.length;
|
|
87
|
+
// Claude call with timeout and retry (handled inside agent.run)
|
|
88
|
+
await agent.run(prompt, {}, dynamicTimeoutSec, maxRetries);
|
|
89
|
+
const agentReport = agent.generateReport();
|
|
90
|
+
manager.markAgentFree(agentId);
|
|
91
|
+
// Post-process: handle reports, progress, etc.
|
|
92
|
+
await processor.postProcess(tasks, context, agentReport);
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
// Check if this is an abort
|
|
96
|
+
if (agentAbortController.signal.aborted) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
// Capture the first error and signal all other agents to abort
|
|
100
|
+
if (!firstError) {
|
|
101
|
+
firstError = new Error(`Error in claude parallel process (${agentId}): ${error}`);
|
|
102
|
+
logger.debugMessage(firstError.message);
|
|
103
|
+
}
|
|
104
|
+
await exit(1); // Exit this agent's processing immediately
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
// Create agent pool
|
|
110
|
+
manager.createAgentPool();
|
|
111
|
+
// Start parallel processing
|
|
112
|
+
const processingPromises = Array.from({ length: concurrency }, () => processTask());
|
|
113
|
+
try {
|
|
114
|
+
await Promise.all(processingPromises);
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
// Check if this is an abort
|
|
118
|
+
if (agentAbortController.signal.aborted) {
|
|
119
|
+
throw new Error('Processing aborted');
|
|
120
|
+
}
|
|
121
|
+
// This shouldn't happen since we handle errors within processTask
|
|
122
|
+
logger.debugMessage(`Unexpected error in parallel processing: ${error}`);
|
|
123
|
+
if (!firstError) {
|
|
124
|
+
firstError = new Error(`Unexpected error in parallel processing: ${error}`);
|
|
125
|
+
}
|
|
126
|
+
throw firstError;
|
|
127
|
+
}
|
|
128
|
+
if (firstError) {
|
|
129
|
+
throw firstError;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=concurrency.js.map
|
|
@@ -0,0 +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"]}
|
package/dist/tasks/i18n.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i18n.d.ts","sourceRoot":"/","sources":["tasks/i18n.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"i18n.d.ts","sourceRoot":"/","sources":["tasks/i18n.ts"],"names":[],"mappings":"AAuBA,wBAAsB,QAAQ,kBAyN7B"}
|