@intlayer/engine 9.5.12 → 9.6.0

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.
Files changed (44) hide show
  1. package/dist/assets/installSkills/skills/cli.md +28 -1
  2. package/dist/assets/installSkills/skills/compat.md +1 -1
  3. package/dist/assets/installSkills/skills/dev-tools.md +8 -6
  4. package/dist/cjs/cli.cjs +2 -0
  5. package/dist/cjs/init/index.cjs +12 -2
  6. package/dist/cjs/init/index.cjs.map +1 -1
  7. package/dist/cjs/init/utils/packageManager.cjs +1 -1
  8. package/dist/cjs/init/utils/packageManager.cjs.map +1 -1
  9. package/dist/cjs/installMCP/installMCP.cjs +35 -25
  10. package/dist/cjs/installMCP/installMCP.cjs.map +1 -1
  11. package/dist/cjs/installSkills/index.cjs +26 -1
  12. package/dist/cjs/installSkills/index.cjs.map +1 -1
  13. package/dist/cjs/listGitFiles.cjs +3 -5
  14. package/dist/cjs/listGitFiles.cjs.map +1 -1
  15. package/dist/cjs/listProjects.cjs +1 -2
  16. package/dist/cjs/listProjects.cjs.map +1 -1
  17. package/dist/esm/cli.mjs +3 -3
  18. package/dist/esm/init/index.mjs +12 -2
  19. package/dist/esm/init/index.mjs.map +1 -1
  20. package/dist/esm/init/utils/packageManager.mjs +1 -1
  21. package/dist/esm/init/utils/packageManager.mjs.map +1 -1
  22. package/dist/esm/installMCP/installMCP.mjs +35 -25
  23. package/dist/esm/installMCP/installMCP.mjs.map +1 -1
  24. package/dist/esm/installSkills/index.mjs +27 -3
  25. package/dist/esm/installSkills/index.mjs.map +1 -1
  26. package/dist/esm/listGitFiles.mjs +1 -1
  27. package/dist/esm/listGitFiles.mjs.map +1 -1
  28. package/dist/esm/listProjects.mjs +1 -1
  29. package/dist/esm/listProjects.mjs.map +1 -1
  30. package/dist/esm/utils/runParallel/pidTree.mjs +3 -3
  31. package/dist/esm/utils/runParallel/pidTree.mjs.map +1 -1
  32. package/dist/esm/utils/runParallel/ps.mjs +2 -2
  33. package/dist/esm/utils/runParallel/ps.mjs.map +1 -1
  34. package/dist/esm/utils/runParallel/wmic.mjs +2 -2
  35. package/dist/esm/utils/runParallel/wmic.mjs.map +1 -1
  36. package/dist/types/cli.d.ts +3 -3
  37. package/dist/types/init/index.d.ts.map +1 -1
  38. package/dist/types/init/utils/packageManager.d.ts +5 -0
  39. package/dist/types/init/utils/packageManager.d.ts.map +1 -1
  40. package/dist/types/installMCP/installMCP.d.ts +4 -0
  41. package/dist/types/installMCP/installMCP.d.ts.map +1 -1
  42. package/dist/types/installSkills/index.d.ts +6 -0
  43. package/dist/types/installSkills/index.d.ts.map +1 -1
  44. package/package.json +9 -9
@@ -1,47 +1,57 @@
1
1
  import { PLATFORMS_METADATA } from "../installSkills/index.mjs";
2
2
  import path from "node:path";
3
3
  import { promises } from "node:fs";
4
- import os from "node:os";
5
4
 
6
5
  //#region src/installMCP/installMCP.ts
6
+ /** Transports accepted by `intlayer init mcp --transport`. */
7
+ const MCP_TRANSPORTS = ["stdio", "sse"];
7
8
  const MCP_CONFIG_FILENAME = "mcp.json";
8
- const CLAUDE_DESKTOP_CONFIG_PATH = process.platform === "win32" ? path.join(process.env.APPDATA || "", "Claude", "claude_desktop_config.json") : path.join(os.homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
9
+ /** Project-scoped MCP configuration file read by Claude Code. */
10
+ const CLAUDE_CODE_MCP_CONFIG_FILENAME = ".mcp.json";
11
+ /** Platforms whose MCP entries declare their transport as `type`. */
12
+ const TYPED_TRANSPORT_PLATFORMS = ["VSCode", "Claude"];
13
+ /** Resolves the MCP configuration file written for a platform. */
14
+ const getMCPConfigPath = (projectRoot, platform) => {
15
+ if (platform === "Claude") return path.join(projectRoot, CLAUDE_CODE_MCP_CONFIG_FILENAME);
16
+ const relativeDir = path.dirname(PLATFORMS_METADATA[platform]?.dir ?? ".");
17
+ return path.join(projectRoot, relativeDir, MCP_CONFIG_FILENAME);
18
+ };
19
+ /** Builds the Intlayer MCP server entry for a platform and transport. */
20
+ const getMCPServerConfig = (platform, transport) => {
21
+ const isTypedTransport = TYPED_TRANSPORT_PLATFORMS.includes(platform);
22
+ if (transport === "stdio") return {
23
+ command: "npx",
24
+ args: ["-y", "@intlayer/mcp"],
25
+ ...isTypedTransport ? { type: "stdio" } : {}
26
+ };
27
+ return {
28
+ url: "https://mcp.intlayer.org",
29
+ ...isTypedTransport ? { type: "sse" } : { transport: "sse" }
30
+ };
31
+ };
9
32
  /**
10
33
  * Installs the Intlayer MCP server configuration for a specific platform.
34
+ * Every platform is configured at the project level (Claude Code included,
35
+ * through `.mcp.json`), so nothing outside the project is modified.
11
36
  */
12
37
  const installMCP = async (projectRoot, platform, transport) => {
13
- let configPath;
14
- let configKey = "mcpServers";
15
- if (platform === "Claude") configPath = CLAUDE_DESKTOP_CONFIG_PATH;
16
- else {
17
- const relativeDir = path.dirname(PLATFORMS_METADATA[platform]?.dir ?? ".");
18
- configPath = path.join(projectRoot, relativeDir, MCP_CONFIG_FILENAME);
19
- if (platform === "VSCode") configKey = "servers";
20
- }
38
+ const configPath = getMCPConfigPath(projectRoot, platform);
39
+ const serversKey = platform === "VSCode" ? "servers" : "mcpServers";
21
40
  await promises.mkdir(path.dirname(configPath), { recursive: true });
22
41
  let config = {};
23
42
  try {
24
43
  const content = await promises.readFile(configPath, "utf-8");
25
44
  config = JSON.parse(content);
26
45
  } catch {}
27
- if (!config[configKey]) config[configKey] = {};
28
- if (transport === "stdio") {
29
- const mcpConfig = {
30
- command: "npx",
31
- args: ["-y", "@intlayer/mcp"]
32
- };
33
- if (platform === "VSCode") mcpConfig.type = "stdio";
34
- config[configKey].intlayer = mcpConfig;
35
- } else {
36
- const mcpConfig = { url: "https://mcp.intlayer.org" };
37
- if (platform === "VSCode") mcpConfig.type = "sse";
38
- else mcpConfig.transport = "sse";
39
- config[configKey].intlayer = mcpConfig;
40
- }
46
+ const servers = config[serversKey] ?? {};
47
+ config[serversKey] = {
48
+ ...servers,
49
+ intlayer: getMCPServerConfig(platform, transport)
50
+ };
41
51
  await promises.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
42
52
  return `MCP server configuration updated in ${configPath}`;
43
53
  };
44
54
 
45
55
  //#endregion
46
- export { installMCP };
56
+ export { MCP_TRANSPORTS, installMCP };
47
57
  //# sourceMappingURL=installMCP.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"installMCP.mjs","names":["fs"],"sources":["../../../src/installMCP/installMCP.ts"],"sourcesContent":["import { promises as fs } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { PLATFORMS_METADATA, type Platform } from '../installSkills';\n\nexport type MCPTransport = 'stdio' | 'sse';\n\nconst MCP_CONFIG_FILENAME = 'mcp.json';\n\nconst CLAUDE_DESKTOP_CONFIG_PATH =\n process.platform === 'win32'\n ? path.join(\n process.env.APPDATA || '',\n 'Claude',\n 'claude_desktop_config.json'\n )\n : path.join(\n os.homedir(),\n 'Library',\n 'Application Support',\n 'Claude',\n 'claude_desktop_config.json'\n );\n\n/**\n * Installs the Intlayer MCP server configuration for a specific platform.\n */\nexport const installMCP = async (\n projectRoot: string,\n platform: Platform,\n transport: MCPTransport\n): Promise<string> => {\n let configPath: string;\n let configKey = 'mcpServers';\n\n if (platform === 'Claude') {\n configPath = CLAUDE_DESKTOP_CONFIG_PATH;\n } else {\n const relativeDir = path.dirname(PLATFORMS_METADATA[platform]?.dir ?? '.'); // e.g. .cursor or .vscode\n configPath = path.join(projectRoot, relativeDir, MCP_CONFIG_FILENAME);\n\n if (platform === 'VSCode') {\n configKey = 'servers';\n }\n }\n\n // Ensure the configuration directory exists\n await fs.mkdir(path.dirname(configPath), { recursive: true });\n\n let config: any = {};\n try {\n const content = await fs.readFile(configPath, 'utf-8');\n config = JSON.parse(content);\n } catch {\n // File doesn't exist or is invalid JSON, start fresh\n }\n\n if (!config[configKey]) {\n config[configKey] = {};\n }\n\n if (transport === 'stdio') {\n const mcpConfig: any = {\n command: 'npx',\n args: ['-y', '@intlayer/mcp'],\n };\n\n if (platform === 'VSCode') {\n mcpConfig.type = 'stdio';\n }\n\n config[configKey].intlayer = mcpConfig;\n } else {\n const mcpConfig: any = {\n url: 'https://mcp.intlayer.org',\n };\n\n if (platform === 'VSCode') {\n mcpConfig.type = 'sse';\n } else {\n mcpConfig.transport = 'sse';\n }\n\n config[configKey].intlayer = mcpConfig;\n }\n\n await fs.writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8');\n\n return `MCP server configuration updated in ${configPath}`;\n};\n"],"mappings":";;;;;;AAOA,MAAM,sBAAsB;AAE5B,MAAM,6BACJ,QAAQ,aAAa,UACjB,KAAK,KACH,QAAQ,IAAI,WAAW,IACvB,UACA,4BACF,IACA,KAAK,KACH,GAAG,QAAQ,GACX,WACA,uBACA,UACA,4BACF;;;;AAKN,MAAa,aAAa,OACxB,aACA,UACA,cACoB;CACpB,IAAI;CACJ,IAAI,YAAY;CAEhB,IAAI,aAAa,UACf,aAAa;MACR;EACL,MAAM,cAAc,KAAK,QAAQ,mBAAmB,SAAS,EAAE,OAAO,GAAG;EACzE,aAAa,KAAK,KAAK,aAAa,aAAa,mBAAmB;EAEpE,IAAI,aAAa,UACf,YAAY;CAEhB;CAGA,MAAMA,SAAG,MAAM,KAAK,QAAQ,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;CAE5D,IAAI,SAAc,CAAC;CACnB,IAAI;EACF,MAAM,UAAU,MAAMA,SAAG,SAAS,YAAY,OAAO;EACrD,SAAS,KAAK,MAAM,OAAO;CAC7B,QAAQ,CAER;CAEA,IAAI,CAAC,OAAO,YACV,OAAO,aAAa,CAAC;CAGvB,IAAI,cAAc,SAAS;EACzB,MAAM,YAAiB;GACrB,SAAS;GACT,MAAM,CAAC,MAAM,eAAe;EAC9B;EAEA,IAAI,aAAa,UACf,UAAU,OAAO;EAGnB,OAAO,UAAU,CAAC,WAAW;CAC/B,OAAO;EACL,MAAM,YAAiB,EACrB,KAAK,2BACP;EAEA,IAAI,aAAa,UACf,UAAU,OAAO;OAEjB,UAAU,YAAY;EAGxB,OAAO,UAAU,CAAC,WAAW;CAC/B;CAEA,MAAMA,SAAG,UAAU,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG,OAAO;CAEvE,OAAO,uCAAuC;AAChD"}
1
+ {"version":3,"file":"installMCP.mjs","names":["fs"],"sources":["../../../src/installMCP/installMCP.ts"],"sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { PLATFORMS_METADATA, type Platform } from '../installSkills';\n\nexport type MCPTransport = 'stdio' | 'sse';\n\n/** Transports accepted by `intlayer init mcp --transport`. */\nexport const MCP_TRANSPORTS: MCPTransport[] = ['stdio', 'sse'];\n\nconst MCP_CONFIG_FILENAME = 'mcp.json';\n\n/** Project-scoped MCP configuration file read by Claude Code. */\nconst CLAUDE_CODE_MCP_CONFIG_FILENAME = '.mcp.json';\n\n/** One MCP server entry, as written under the platform's servers key. */\ntype MCPServerConfig = {\n command?: string;\n args?: string[];\n url?: string;\n type?: MCPTransport;\n transport?: MCPTransport;\n};\n\n/** Parsed MCP configuration file, keeping any unrelated keys untouched. */\ntype MCPConfigFile = Record<string, unknown>;\n\n/** Platforms whose MCP entries declare their transport as `type`. */\nconst TYPED_TRANSPORT_PLATFORMS: Platform[] = ['VSCode', 'Claude'];\n\n/** Resolves the MCP configuration file written for a platform. */\nconst getMCPConfigPath = (projectRoot: string, platform: Platform): string => {\n if (platform === 'Claude') {\n return path.join(projectRoot, CLAUDE_CODE_MCP_CONFIG_FILENAME);\n }\n\n // e.g. `.cursor/skills` → `.cursor/mcp.json`\n const relativeDir = path.dirname(PLATFORMS_METADATA[platform]?.dir ?? '.');\n\n return path.join(projectRoot, relativeDir, MCP_CONFIG_FILENAME);\n};\n\n/** Builds the Intlayer MCP server entry for a platform and transport. */\nconst getMCPServerConfig = (\n platform: Platform,\n transport: MCPTransport\n): MCPServerConfig => {\n const isTypedTransport = TYPED_TRANSPORT_PLATFORMS.includes(platform);\n\n if (transport === 'stdio') {\n return {\n command: 'npx',\n args: ['-y', '@intlayer/mcp'],\n ...(isTypedTransport ? { type: 'stdio' } : {}),\n };\n }\n\n return {\n url: 'https://mcp.intlayer.org',\n ...(isTypedTransport ? { type: 'sse' } : { transport: 'sse' }),\n };\n};\n\n/**\n * Installs the Intlayer MCP server configuration for a specific platform.\n * Every platform is configured at the project level (Claude Code included,\n * through `.mcp.json`), so nothing outside the project is modified.\n */\nexport const installMCP = async (\n projectRoot: string,\n platform: Platform,\n transport: MCPTransport\n): Promise<string> => {\n const configPath = getMCPConfigPath(projectRoot, platform);\n const serversKey = platform === 'VSCode' ? 'servers' : 'mcpServers';\n\n // Ensure the configuration directory exists\n await fs.mkdir(path.dirname(configPath), { recursive: true });\n\n let config: MCPConfigFile = {};\n try {\n const content = await fs.readFile(configPath, 'utf-8');\n config = JSON.parse(content) as MCPConfigFile;\n } catch {\n // File doesn't exist or is invalid JSON, start fresh\n }\n\n const servers = (config[serversKey] ?? {}) as Record<string, MCPServerConfig>;\n\n config[serversKey] = {\n ...servers,\n intlayer: getMCPServerConfig(platform, transport),\n };\n\n await fs.writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8');\n\n return `MCP server configuration updated in ${configPath}`;\n};\n"],"mappings":";;;;;;AAOA,MAAa,iBAAiC,CAAC,SAAS,KAAK;AAE7D,MAAM,sBAAsB;;AAG5B,MAAM,kCAAkC;;AAexC,MAAM,4BAAwC,CAAC,UAAU,QAAQ;;AAGjE,MAAM,oBAAoB,aAAqB,aAA+B;CAC5E,IAAI,aAAa,UACf,OAAO,KAAK,KAAK,aAAa,+BAA+B;CAI/D,MAAM,cAAc,KAAK,QAAQ,mBAAmB,SAAS,EAAE,OAAO,GAAG;CAEzE,OAAO,KAAK,KAAK,aAAa,aAAa,mBAAmB;AAChE;;AAGA,MAAM,sBACJ,UACA,cACoB;CACpB,MAAM,mBAAmB,0BAA0B,SAAS,QAAQ;CAEpE,IAAI,cAAc,SAChB,OAAO;EACL,SAAS;EACT,MAAM,CAAC,MAAM,eAAe;EAC5B,GAAI,mBAAmB,EAAE,MAAM,QAAQ,IAAI,CAAC;CAC9C;CAGF,OAAO;EACL,KAAK;EACL,GAAI,mBAAmB,EAAE,MAAM,MAAM,IAAI,EAAE,WAAW,MAAM;CAC9D;AACF;;;;;;AAOA,MAAa,aAAa,OACxB,aACA,UACA,cACoB;CACpB,MAAM,aAAa,iBAAiB,aAAa,QAAQ;CACzD,MAAM,aAAa,aAAa,WAAW,YAAY;CAGvD,MAAMA,SAAG,MAAM,KAAK,QAAQ,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;CAE5D,IAAI,SAAwB,CAAC;CAC7B,IAAI;EACF,MAAM,UAAU,MAAMA,SAAG,SAAS,YAAY,OAAO;EACrD,SAAS,KAAK,MAAM,OAAO;CAC7B,QAAQ,CAER;CAEA,MAAM,UAAW,OAAO,eAAe,CAAC;CAExC,OAAO,cAAc;EACnB,GAAG;EACH,UAAU,mBAAmB,UAAU,SAAS;CAClD;CAEA,MAAMA,SAAG,UAAU,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG,OAAO;CAEvE,OAAO,uCAAuC;AAChD"}
@@ -2,7 +2,7 @@ import { readAsset } from "../_virtual/_utils_asset.mjs";
2
2
  import path from "node:path";
3
3
  import { v } from "@intlayer/config/logger";
4
4
  import { getMarkdownMetadata } from "@intlayer/core/markdown";
5
- import { promises } from "node:fs";
5
+ import { existsSync, promises } from "node:fs";
6
6
 
7
7
  //#region src/installSkills/index.ts
8
8
  /**
@@ -172,7 +172,7 @@ const PLATFORMS_METADATA = {
172
172
  Claude: {
173
173
  label: "Claude Code",
174
174
  dir: ".claude/skills",
175
- check: () => process.env.CLAUDE === "true"
175
+ check: () => process.env.CLAUDE === "true" || process.env.CLAUDECODE === "1"
176
176
  },
177
177
  GitHub: {
178
178
  label: "GitHub Copilot Workspace",
@@ -290,6 +290,30 @@ const PLATFORMS_METADATA = {
290
290
  };
291
291
  const PLATFORMS = Object.keys(PLATFORMS_METADATA);
292
292
  /**
293
+ * Root folders too common to identify a platform on their own (e.g. `.github`
294
+ * exists in most repositories regardless of the AI tool in use).
295
+ */
296
+ const AMBIGUOUS_PLATFORM_DIRECTORIES = /* @__PURE__ */ new Set([
297
+ ".github",
298
+ ".vscode",
299
+ "skills"
300
+ ]);
301
+ /** Root config folder of a platform (e.g. `.cursor`), if it identifies it. */
302
+ const getPlatformDirectory = (platform) => {
303
+ const [rootDirectory] = (PLATFORMS_METADATA[platform]?.dir ?? "").split("/");
304
+ if (!rootDirectory || AMBIGUOUS_PLATFORM_DIRECTORIES.has(rootDirectory)) return;
305
+ return rootDirectory;
306
+ };
307
+ /**
308
+ * Detects the AI platform in use. The environment of the running tool wins;
309
+ * otherwise the first platform whose config folder (`.claude`, `.cursor`…)
310
+ * exists in the project root is returned.
311
+ */
312
+ const detectPlatform = (projectRoot) => PLATFORMS.find((platform) => PLATFORMS_METADATA[platform]?.check?.()) ?? PLATFORMS.find((platform) => {
313
+ const platformDirectory = getPlatformDirectory(platform);
314
+ return platformDirectory !== void 0 && existsSync(path.join(projectRoot, platformDirectory));
315
+ });
316
+ /**
293
317
  * Maps specific skill keys to special filenames if they differ from standard snake_case.
294
318
  */
295
319
  const SKILL_FILENAME_MAP = {};
@@ -419,5 +443,5 @@ const installSkills = async (projectRoot, platform, skills) => {
419
443
  };
420
444
 
421
445
  //#endregion
422
- export { PLATFORMS, PLATFORMS_METADATA, SKILLS, SKILLS_METADATA, getInitialSkills, installSkills };
446
+ export { PLATFORMS, PLATFORMS_METADATA, SKILLS, SKILLS_METADATA, detectPlatform, getInitialSkills, installSkills };
423
447
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["fs"],"sources":["../../../src/installSkills/index.ts"],"sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { readAsset } from 'utils:asset';\nimport { v } from '@intlayer/config/logger';\nimport { getMarkdownMetadata } from '@intlayer/core/markdown';\n\n/**\n * Metadata for each available documentation skill.\n */\nexport const SKILLS_METADATA = {\n Config: 'Intlayer configuration documentation',\n Content: 'Reference for all Intlayer content node types (t, enu, etc.)',\n Markdown:\n 'Markdown / rich text content: md(), MDX components, MarkdownProvider, SSR',\n Usage: 'How to use Intlayer in your project',\n CLI: 'Intlayer CLI commands and usage',\n Compiler:\n 'Intlayer Compiler setup and usage for automatic content extraction without .content files',\n BundleOptimization:\n 'Purge, minify and import modes; writing code the bundle optimizer can follow',\n RemoteContent: 'How to use Intlayer with Remote/CMS/Server-side content',\n DevTools: 'ESLint, LSP, VS Code & Chrome extensions, MCP server and CI/CD',\n Compat:\n 'Migrate from i18next, next-intl, react-intl, vue-i18n, Lingui… keeping their API',\n NextJS: 'Next.js-specific usage (Server & Client components)',\n React: 'React-specific syntax and hooks usage',\n Vue: 'Vue-specific composables and syntax',\n Svelte: 'Svelte-specific stores and syntax',\n Angular: 'Angular-specific syntax and Injectable Function usage',\n Preact: 'Preact-specific syntax and hooks usage',\n Solid: 'Solid-specific syntax and hooks usage',\n Astro: 'Astro-specific usage, middleware and islands',\n Lit: 'Lit-specific ReactiveController usage (useIntlayer, useLocale)',\n Vanilla: 'Framework-less JavaScript usage (vanilla-intlayer)',\n Remix: 'Remix 3 router middleware and request-scoped hooks',\n Backend:\n 'Server-side usage for Express, Fastify, Hono, NestJS, AdonisJS and Elysia',\n} as const;\n\nexport type Skill = keyof typeof SKILLS_METADATA;\n\nexport const SKILLS = Object.keys(SKILLS_METADATA) as Skill[];\n\n/** Skills preselected for every project, whatever its stack. */\nconst BASE_SKILLS: Skill[] = [\n 'Usage',\n 'Content',\n 'Config',\n 'CLI',\n 'Compiler',\n 'BundleOptimization',\n 'DevTools',\n];\n\n/**\n * Packages whose presence in `package.json` preselects a framework skill.\n * Both the framework itself and its Intlayer adapter are listed, so a skill is\n * suggested before and after the adapter is installed.\n */\nconst SKILL_TRIGGER_PACKAGES: Partial<Record<Skill, string[]>> = {\n NextJS: ['next', 'next-intlayer'],\n React: [\n 'react',\n 'react-intlayer',\n 'react-native-intlayer',\n 'react-scripts-intlayer',\n 'lynx-intlayer',\n ],\n Preact: ['preact', 'preact-intlayer'],\n Solid: ['solid-js', '@solidjs/start', 'solid-intlayer'],\n Vue: ['vue', 'nuxt', 'vue-intlayer', 'nuxt-intlayer'],\n Svelte: ['svelte', '@sveltejs/kit', 'svelte-intlayer'],\n Angular: ['@angular/core', '@analogjs/platform', 'angular-intlayer'],\n Astro: ['astro', 'astro-intlayer'],\n Lit: ['lit', 'lit-intlayer'],\n Vanilla: ['vanilla-intlayer'],\n Remix: ['remix', 'remix-intlayer'],\n Compat: [\n 'i18next',\n 'react-i18next',\n 'next-i18next',\n 'next-intl',\n 'use-intl',\n 'react-intl',\n 'vue-i18n',\n '@lingui/core',\n '@lingui/react',\n '@nuxtjs/i18n',\n '@ngx-translate/core',\n '@jsverse/transloco',\n 'svelte-i18n',\n 'next-translate',\n 'node-polyglot',\n 'i18n-js',\n '@intlayer/i18next',\n '@intlayer/react-i18next',\n '@intlayer/next-i18next',\n '@intlayer/next-intl',\n '@intlayer/use-intl',\n '@intlayer/react-intl',\n '@intlayer/vue-i18n',\n '@intlayer/lingui',\n '@intlayer/sync-json-plugin',\n '@intlayer/sync-po-plugin',\n ],\n Backend: [\n 'express',\n 'fastify',\n 'hono',\n 'elysia',\n '@nestjs/core',\n '@adonisjs/core',\n 'express-intlayer',\n 'fastify-intlayer',\n 'hono-intlayer',\n 'elysia-intlayer',\n 'adonis-intlayer',\n ],\n};\n\n/**\n * Resolves the skills to preselect from the project's installed packages.\n *\n * @param dependencies - Merged `dependencies` and `devDependencies` of `package.json`.\n * @returns The base skills plus every framework skill whose packages are installed.\n */\nexport const getInitialSkills = (\n dependencies: Record<string, string>\n): Skill[] => {\n const detectedSkills = SKILLS.filter((skill) =>\n SKILL_TRIGGER_PACKAGES[skill]?.some(\n (packageName) => packageName in dependencies\n )\n );\n\n return [...BASE_SKILLS, ...detectedSkills];\n};\n\nexport interface PlatformMetadata {\n label: string;\n dir: string;\n check?: () => boolean;\n}\n\n/**\n * Metadata and configuration for each supported platform.\n */\nexport const PLATFORMS_METADATA: Record<string, PlatformMetadata> = {\n Cursor: {\n label: 'Cursor',\n dir: '.cursor/skills',\n check: () =>\n process.env.CURSOR === 'true' || process.env.TERM_PROGRAM === 'cursor',\n },\n Windsurf: {\n label: 'Windsurf',\n dir: '.windsurf/skills',\n check: () =>\n process.env.WINDSURF === 'true' ||\n process.env.TERM_PROGRAM === 'windsurf',\n },\n Trae: {\n label: 'Trae',\n dir: '.trae/skills',\n check: () =>\n process.env.TRAE === 'true' || process.env.TERM_PROGRAM === 'trae',\n },\n TraeCN: {\n label: 'Trae CN',\n dir: '.trae/skills',\n check: () => process.env.TRAE_CN === 'true',\n },\n VSCode: {\n label: 'VS Code',\n dir: '.vscode/skills',\n check: () =>\n process.env.VSCODE === 'true' || process.env.TERM_PROGRAM === 'vscode',\n },\n OpenCode: {\n label: 'OpenCode',\n dir: '.opencode/skills',\n check: () => process.env.OPENCODE === 'true',\n },\n Claude: {\n label: 'Claude Code',\n dir: '.claude/skills',\n check: () => process.env.CLAUDE === 'true',\n },\n GitHub: {\n label: 'GitHub Copilot Workspace',\n dir: '.github/skills',\n check: () =>\n process.env.GITHUB_ACTIONS === 'true' || !!process.env.GITHUB_WORKSPACE,\n },\n Antigravity: {\n label: 'Antigravity',\n dir: '.agent/skills',\n },\n Augment: {\n label: 'Augment',\n dir: '.augment/skills',\n },\n OpenClaw: {\n label: 'OpenClaw',\n dir: 'skills',\n },\n Cline: {\n label: 'Cline',\n dir: '.cline/skills',\n },\n CodeBuddy: {\n label: 'CodeBuddy',\n dir: '.codebuddy/skills',\n },\n CommandCode: {\n label: 'Command Code',\n dir: '.commandcode/skills',\n },\n Continue: {\n label: 'Continue',\n dir: '.continue/skills',\n },\n Crush: {\n label: 'Crush',\n dir: '.crush/skills',\n },\n Droid: {\n label: 'Droid',\n dir: '.factory/skills',\n },\n Goose: {\n label: 'Goose',\n dir: '.goose/skills',\n },\n IFlow: {\n label: 'iFlow CLI',\n dir: '.iflow/skills',\n },\n Junie: {\n label: 'Junie',\n dir: '.junie/skills',\n },\n KiloCode: {\n label: 'Kilo Code',\n dir: '.kilocode/skills',\n },\n Kiro: {\n label: 'Kiro CLI',\n dir: '.kiro/skills',\n },\n Kode: {\n label: 'Kode',\n dir: '.kode/skills',\n },\n MCPJam: {\n label: 'MCPJam',\n dir: '.mcpjam/skills',\n },\n MistralVibe: {\n label: 'Mistral Vibe',\n dir: '.vibe/skills',\n },\n Mux: {\n label: 'Mux',\n dir: '.mux/skills',\n },\n OpenHands: {\n label: 'OpenHands',\n dir: '.openhands/skills',\n },\n Pi: {\n label: 'Pi',\n dir: '.pi/skills',\n },\n Qoder: {\n label: 'Qoder',\n dir: '.qoder/skills',\n },\n Qwen: {\n label: 'Qwen Code',\n dir: '.qwen/skills',\n },\n RooCode: {\n label: 'Roo Code',\n dir: '.roo/skills',\n },\n Zencoder: {\n label: 'Zencoder',\n dir: '.zencoder/skills',\n },\n Neovate: {\n label: 'Neovate',\n dir: '.neovate/skills',\n },\n Pochi: {\n label: 'Pochi',\n dir: '.pochi/skills',\n },\n Other: {\n label: 'Other',\n dir: 'skills',\n },\n} as const;\n\nexport type Platform = keyof typeof PLATFORMS_METADATA;\n\nexport const PLATFORMS = Object.keys(PLATFORMS_METADATA) as Platform[];\n\n/**\n * Maps specific skill keys to special filenames if they differ from standard snake_case.\n */\nconst SKILL_FILENAME_MAP: Partial<Record<Skill, string>> = {};\n\n/**\n * Helper to convert CamelCase to kebab-case for directory naming\n */\nconst camelToKebabCase = (str: string) =>\n str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();\n\n/**\n * Reads the raw markdown content for a specific skill from the assets folder.\n */\nconst getSkillContent = (skill: Skill): string => {\n const baseName = SKILL_FILENAME_MAP[skill] ?? camelToKebabCase(skill);\n const fileName = `./skills/${baseName}.md`;\n\n try {\n return readAsset(fileName);\n } catch {\n console.warn(\n `Warning: Could not read asset for skill: ${skill} at ${fileName}`\n );\n return '';\n }\n};\n\n/**\n * Reads the licence content from the assets folder.\n */\nconst getLicenceContent = (): string => {\n try {\n return readAsset('./LICENCE.md');\n } catch {\n console.warn('Warning: Could not read LICENCE.md asset');\n return '';\n }\n};\n\nconst ALLOWED_FETCH_HOSTS = new Set(['intlayer.org']);\n\n/** Upper bound on the redirect chain a reference URL may take. */\nconst MAX_FETCH_REDIRECTS = 5;\n\n/**\n * Parses a URL and rejects it unless it is an HTTPS address on an allowed host.\n *\n * @param url - Absolute URL to validate.\n * @returns The parsed URL.\n * @throws When the protocol or host is not allowed.\n */\nconst parseAllowedUrl = (url: string | URL): URL => {\n const parsed = new URL(url);\n\n if (\n parsed.protocol !== 'https:' ||\n !ALLOWED_FETCH_HOSTS.has(parsed.hostname)\n ) {\n throw new Error(`Blocked fetch to disallowed host: ${parsed.hostname}`);\n }\n\n return parsed;\n};\n\n/**\n * Fetches the content of a URL using native fetch.\n *\n * Redirects are followed manually so every hop is re-checked against the host\n * allowlist — a redirect off `intlayer.org` is refused rather than silently\n * followed. Letting `fetch` refuse them outright (`redirect: 'error'`) instead\n * reported an unhelpful `TypeError: fetch failed` for a documentation URL that\n * merely moved.\n *\n * @param url - Absolute URL to read.\n * @returns The response body as text.\n */\nconst fetchUrlContent = async (url: string): Promise<string> => {\n let target = parseAllowedUrl(url);\n\n for (let hop = 0; hop <= MAX_FETCH_REDIRECTS; hop++) {\n const response = await fetch(target, { redirect: 'manual' });\n\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get('location');\n\n if (!location) {\n throw new Error(`Failed to fetch ${url}: redirect without a location`);\n }\n\n target = parseAllowedUrl(new URL(location, target));\n continue;\n }\n\n if (!response.ok) {\n throw new Error(`Failed to fetch ${url}: ${response.statusText}`);\n }\n\n return response.text();\n }\n\n throw new Error(`Failed to fetch ${url}: too many redirects`);\n};\n\n/**\n * Installs skills using the \"Agent Skills\" directory standard.\n * Standard: <PROJECT_ROOT>/<CONFIG_DIR>/skills/<SKILL_NAME>/SKILL.md\n */\nexport const installSkills = async (\n projectRoot: string,\n platform: Platform,\n skills: Skill[]\n): Promise<string> => {\n // Determine destination directory\n const relativeDir = PLATFORMS_METADATA[platform]?.dir ?? 'skills';\n const skillsBaseDir = path.join(projectRoot, relativeDir);\n\n // Ensure the base directory exists\n await fs.mkdir(skillsBaseDir, { recursive: true });\n\n const createdSkills: string[] = [];\n const licenceContent = getLicenceContent();\n\n for (const skill of skills) {\n const baseName = SKILL_FILENAME_MAP[skill] ?? camelToKebabCase(skill);\n const skillName = `intlayer-${baseName}`;\n const skillContent = getSkillContent(skill);\n\n if (!skillContent) continue;\n\n // Extract unique URLs\n const urls = Array.from(\n new Set(skillContent.match(/https:\\/\\/intlayer\\.org\\/[^\\s)]+\\.md/g) || [])\n );\n\n // Agent Standard: .../skills/<skill-name>/SKILL.md\n const skillDir = path.join(skillsBaseDir, skillName);\n const referenceDir = path.join(skillDir, 'references');\n\n // Ensure directories exist\n await fs.mkdir(referenceDir, { recursive: true });\n\n // Write License\n if (licenceContent) {\n await fs.writeFile(\n path.join(skillDir, 'LICENCE.md'),\n licenceContent,\n 'utf-8'\n );\n }\n\n let updatedSkillContent = skillContent;\n\n // Parallel download of references\n const downloadPromises = urls.map(async (url) => {\n try {\n const content = await fetchUrlContent(url);\n const metadata = getMarkdownMetadata<{ slugs?: string[] }>(content);\n\n let fileName = '';\n\n // Determine filename from slugs or URL path\n if (Array.isArray(metadata.slugs)) {\n fileName = metadata.slugs\n .filter((slug) => slug !== 'doc')\n .join('_')\n // Scoped package slugs (`@intlayer/babel`) must not create subfolders\n .replaceAll('/', '_');\n } else {\n const urlPath = new URL(url).pathname;\n fileName = urlPath\n .split('/')\n .filter((part) => part && part !== 'doc')\n .map((part) => part.replace('.md', '')) // Clean extension for joining\n .join('_');\n }\n\n // Ensure it ends with .md\n fileName = fileName ? `${fileName}.md` : 'index.md';\n const localRefPath = `references/${fileName}`;\n\n return {\n url,\n localRefPath,\n fileName,\n content,\n success: true,\n };\n } catch (error) {\n console.warn(\n `Warning: Failed to download ref ${url} for skill ${skill}`,\n error\n );\n return { url, success: false };\n }\n });\n\n const results = await Promise.all(downloadPromises);\n\n // Process results: Write files and update content string\n for (const res of results) {\n if (res.success && res.fileName && res.content && res.localRefPath) {\n // Write the reference file\n await fs.writeFile(\n path.join(referenceDir, res.fileName),\n res.content,\n 'utf-8'\n );\n\n // Update the main content to point to local file\n updatedSkillContent = updatedSkillContent.replaceAll(\n res.url,\n res.localRefPath\n );\n }\n }\n\n // Write the main SKILL.md\n const filePath = path.join(skillDir, 'SKILL.md');\n await fs.writeFile(filePath, updatedSkillContent, 'utf-8');\n createdSkills.push(`${skillName}/SKILL.md`);\n }\n\n if (createdSkills.length === 0) {\n return `No skill files were created. Check your asset paths.`;\n }\n\n return `${v} Created ${createdSkills.length} skills in ${skillsBaseDir}`;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["fs"],"sources":["../../../src/installSkills/index.ts"],"sourcesContent":["import { existsSync, promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { readAsset } from 'utils:asset';\nimport { v } from '@intlayer/config/logger';\nimport { getMarkdownMetadata } from '@intlayer/core/markdown';\n\n/**\n * Metadata for each available documentation skill.\n */\nexport const SKILLS_METADATA = {\n Config: 'Intlayer configuration documentation',\n Content: 'Reference for all Intlayer content node types (t, enu, etc.)',\n Markdown:\n 'Markdown / rich text content: md(), MDX components, MarkdownProvider, SSR',\n Usage: 'How to use Intlayer in your project',\n CLI: 'Intlayer CLI commands and usage',\n Compiler:\n 'Intlayer Compiler setup and usage for automatic content extraction without .content files',\n BundleOptimization:\n 'Purge, minify and import modes; writing code the bundle optimizer can follow',\n RemoteContent: 'How to use Intlayer with Remote/CMS/Server-side content',\n DevTools: 'ESLint, LSP, VS Code & Chrome extensions, MCP server and CI/CD',\n Compat:\n 'Migrate from i18next, next-intl, react-intl, vue-i18n, Lingui… keeping their API',\n NextJS: 'Next.js-specific usage (Server & Client components)',\n React: 'React-specific syntax and hooks usage',\n Vue: 'Vue-specific composables and syntax',\n Svelte: 'Svelte-specific stores and syntax',\n Angular: 'Angular-specific syntax and Injectable Function usage',\n Preact: 'Preact-specific syntax and hooks usage',\n Solid: 'Solid-specific syntax and hooks usage',\n Astro: 'Astro-specific usage, middleware and islands',\n Lit: 'Lit-specific ReactiveController usage (useIntlayer, useLocale)',\n Vanilla: 'Framework-less JavaScript usage (vanilla-intlayer)',\n Remix: 'Remix 3 router middleware and request-scoped hooks',\n Backend:\n 'Server-side usage for Express, Fastify, Hono, NestJS, AdonisJS and Elysia',\n} as const;\n\nexport type Skill = keyof typeof SKILLS_METADATA;\n\nexport const SKILLS = Object.keys(SKILLS_METADATA) as Skill[];\n\n/** Skills preselected for every project, whatever its stack. */\nconst BASE_SKILLS: Skill[] = [\n 'Usage',\n 'Content',\n 'Config',\n 'CLI',\n 'Compiler',\n 'BundleOptimization',\n 'DevTools',\n];\n\n/**\n * Packages whose presence in `package.json` preselects a framework skill.\n * Both the framework itself and its Intlayer adapter are listed, so a skill is\n * suggested before and after the adapter is installed.\n */\nconst SKILL_TRIGGER_PACKAGES: Partial<Record<Skill, string[]>> = {\n NextJS: ['next', 'next-intlayer'],\n React: [\n 'react',\n 'react-intlayer',\n 'react-native-intlayer',\n 'react-scripts-intlayer',\n 'lynx-intlayer',\n ],\n Preact: ['preact', 'preact-intlayer'],\n Solid: ['solid-js', '@solidjs/start', 'solid-intlayer'],\n Vue: ['vue', 'nuxt', 'vue-intlayer', 'nuxt-intlayer'],\n Svelte: ['svelte', '@sveltejs/kit', 'svelte-intlayer'],\n Angular: ['@angular/core', '@analogjs/platform', 'angular-intlayer'],\n Astro: ['astro', 'astro-intlayer'],\n Lit: ['lit', 'lit-intlayer'],\n Vanilla: ['vanilla-intlayer'],\n Remix: ['remix', 'remix-intlayer'],\n Compat: [\n 'i18next',\n 'react-i18next',\n 'next-i18next',\n 'next-intl',\n 'use-intl',\n 'react-intl',\n 'vue-i18n',\n '@lingui/core',\n '@lingui/react',\n '@nuxtjs/i18n',\n '@ngx-translate/core',\n '@jsverse/transloco',\n 'svelte-i18n',\n 'next-translate',\n 'node-polyglot',\n 'i18n-js',\n '@intlayer/i18next',\n '@intlayer/react-i18next',\n '@intlayer/next-i18next',\n '@intlayer/next-intl',\n '@intlayer/use-intl',\n '@intlayer/react-intl',\n '@intlayer/vue-i18n',\n '@intlayer/lingui',\n '@intlayer/sync-json-plugin',\n '@intlayer/sync-po-plugin',\n ],\n Backend: [\n 'express',\n 'fastify',\n 'hono',\n 'elysia',\n '@nestjs/core',\n '@adonisjs/core',\n 'express-intlayer',\n 'fastify-intlayer',\n 'hono-intlayer',\n 'elysia-intlayer',\n 'adonis-intlayer',\n ],\n};\n\n/**\n * Resolves the skills to preselect from the project's installed packages.\n *\n * @param dependencies - Merged `dependencies` and `devDependencies` of `package.json`.\n * @returns The base skills plus every framework skill whose packages are installed.\n */\nexport const getInitialSkills = (\n dependencies: Record<string, string>\n): Skill[] => {\n const detectedSkills = SKILLS.filter((skill) =>\n SKILL_TRIGGER_PACKAGES[skill]?.some(\n (packageName) => packageName in dependencies\n )\n );\n\n return [...BASE_SKILLS, ...detectedSkills];\n};\n\nexport interface PlatformMetadata {\n label: string;\n dir: string;\n check?: () => boolean;\n}\n\n/**\n * Metadata and configuration for each supported platform.\n */\nexport const PLATFORMS_METADATA: Record<string, PlatformMetadata> = {\n Cursor: {\n label: 'Cursor',\n dir: '.cursor/skills',\n check: () =>\n process.env.CURSOR === 'true' || process.env.TERM_PROGRAM === 'cursor',\n },\n Windsurf: {\n label: 'Windsurf',\n dir: '.windsurf/skills',\n check: () =>\n process.env.WINDSURF === 'true' ||\n process.env.TERM_PROGRAM === 'windsurf',\n },\n Trae: {\n label: 'Trae',\n dir: '.trae/skills',\n check: () =>\n process.env.TRAE === 'true' || process.env.TERM_PROGRAM === 'trae',\n },\n TraeCN: {\n label: 'Trae CN',\n dir: '.trae/skills',\n check: () => process.env.TRAE_CN === 'true',\n },\n VSCode: {\n label: 'VS Code',\n dir: '.vscode/skills',\n check: () =>\n process.env.VSCODE === 'true' || process.env.TERM_PROGRAM === 'vscode',\n },\n OpenCode: {\n label: 'OpenCode',\n dir: '.opencode/skills',\n check: () => process.env.OPENCODE === 'true',\n },\n Claude: {\n label: 'Claude Code',\n dir: '.claude/skills',\n check: () =>\n process.env.CLAUDE === 'true' || process.env.CLAUDECODE === '1',\n },\n GitHub: {\n label: 'GitHub Copilot Workspace',\n dir: '.github/skills',\n check: () =>\n process.env.GITHUB_ACTIONS === 'true' || !!process.env.GITHUB_WORKSPACE,\n },\n Antigravity: {\n label: 'Antigravity',\n dir: '.agent/skills',\n },\n Augment: {\n label: 'Augment',\n dir: '.augment/skills',\n },\n OpenClaw: {\n label: 'OpenClaw',\n dir: 'skills',\n },\n Cline: {\n label: 'Cline',\n dir: '.cline/skills',\n },\n CodeBuddy: {\n label: 'CodeBuddy',\n dir: '.codebuddy/skills',\n },\n CommandCode: {\n label: 'Command Code',\n dir: '.commandcode/skills',\n },\n Continue: {\n label: 'Continue',\n dir: '.continue/skills',\n },\n Crush: {\n label: 'Crush',\n dir: '.crush/skills',\n },\n Droid: {\n label: 'Droid',\n dir: '.factory/skills',\n },\n Goose: {\n label: 'Goose',\n dir: '.goose/skills',\n },\n IFlow: {\n label: 'iFlow CLI',\n dir: '.iflow/skills',\n },\n Junie: {\n label: 'Junie',\n dir: '.junie/skills',\n },\n KiloCode: {\n label: 'Kilo Code',\n dir: '.kilocode/skills',\n },\n Kiro: {\n label: 'Kiro CLI',\n dir: '.kiro/skills',\n },\n Kode: {\n label: 'Kode',\n dir: '.kode/skills',\n },\n MCPJam: {\n label: 'MCPJam',\n dir: '.mcpjam/skills',\n },\n MistralVibe: {\n label: 'Mistral Vibe',\n dir: '.vibe/skills',\n },\n Mux: {\n label: 'Mux',\n dir: '.mux/skills',\n },\n OpenHands: {\n label: 'OpenHands',\n dir: '.openhands/skills',\n },\n Pi: {\n label: 'Pi',\n dir: '.pi/skills',\n },\n Qoder: {\n label: 'Qoder',\n dir: '.qoder/skills',\n },\n Qwen: {\n label: 'Qwen Code',\n dir: '.qwen/skills',\n },\n RooCode: {\n label: 'Roo Code',\n dir: '.roo/skills',\n },\n Zencoder: {\n label: 'Zencoder',\n dir: '.zencoder/skills',\n },\n Neovate: {\n label: 'Neovate',\n dir: '.neovate/skills',\n },\n Pochi: {\n label: 'Pochi',\n dir: '.pochi/skills',\n },\n Other: {\n label: 'Other',\n dir: 'skills',\n },\n} as const;\n\nexport type Platform = keyof typeof PLATFORMS_METADATA;\n\nexport const PLATFORMS = Object.keys(PLATFORMS_METADATA) as Platform[];\n\n/**\n * Root folders too common to identify a platform on their own (e.g. `.github`\n * exists in most repositories regardless of the AI tool in use).\n */\nconst AMBIGUOUS_PLATFORM_DIRECTORIES = new Set([\n '.github',\n '.vscode',\n 'skills',\n]);\n\n/** Root config folder of a platform (e.g. `.cursor`), if it identifies it. */\nconst getPlatformDirectory = (platform: Platform): string | undefined => {\n const [rootDirectory] = (PLATFORMS_METADATA[platform]?.dir ?? '').split('/');\n\n if (!rootDirectory || AMBIGUOUS_PLATFORM_DIRECTORIES.has(rootDirectory)) {\n return undefined;\n }\n\n return rootDirectory;\n};\n\n/**\n * Detects the AI platform in use. The environment of the running tool wins;\n * otherwise the first platform whose config folder (`.claude`, `.cursor`…)\n * exists in the project root is returned.\n */\nexport const detectPlatform = (projectRoot: string): Platform | undefined =>\n PLATFORMS.find((platform) => PLATFORMS_METADATA[platform]?.check?.()) ??\n PLATFORMS.find((platform) => {\n const platformDirectory = getPlatformDirectory(platform);\n\n return (\n platformDirectory !== undefined &&\n existsSync(path.join(projectRoot, platformDirectory))\n );\n });\n\n/**\n * Maps specific skill keys to special filenames if they differ from standard snake_case.\n */\nconst SKILL_FILENAME_MAP: Partial<Record<Skill, string>> = {};\n\n/**\n * Helper to convert CamelCase to kebab-case for directory naming\n */\nconst camelToKebabCase = (str: string) =>\n str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();\n\n/**\n * Reads the raw markdown content for a specific skill from the assets folder.\n */\nconst getSkillContent = (skill: Skill): string => {\n const baseName = SKILL_FILENAME_MAP[skill] ?? camelToKebabCase(skill);\n const fileName = `./skills/${baseName}.md`;\n\n try {\n return readAsset(fileName);\n } catch {\n console.warn(\n `Warning: Could not read asset for skill: ${skill} at ${fileName}`\n );\n return '';\n }\n};\n\n/**\n * Reads the licence content from the assets folder.\n */\nconst getLicenceContent = (): string => {\n try {\n return readAsset('./LICENCE.md');\n } catch {\n console.warn('Warning: Could not read LICENCE.md asset');\n return '';\n }\n};\n\nconst ALLOWED_FETCH_HOSTS = new Set(['intlayer.org']);\n\n/** Upper bound on the redirect chain a reference URL may take. */\nconst MAX_FETCH_REDIRECTS = 5;\n\n/**\n * Parses a URL and rejects it unless it is an HTTPS address on an allowed host.\n *\n * @param url - Absolute URL to validate.\n * @returns The parsed URL.\n * @throws When the protocol or host is not allowed.\n */\nconst parseAllowedUrl = (url: string | URL): URL => {\n const parsed = new URL(url);\n\n if (\n parsed.protocol !== 'https:' ||\n !ALLOWED_FETCH_HOSTS.has(parsed.hostname)\n ) {\n throw new Error(`Blocked fetch to disallowed host: ${parsed.hostname}`);\n }\n\n return parsed;\n};\n\n/**\n * Fetches the content of a URL using native fetch.\n *\n * Redirects are followed manually so every hop is re-checked against the host\n * allowlist — a redirect off `intlayer.org` is refused rather than silently\n * followed. Letting `fetch` refuse them outright (`redirect: 'error'`) instead\n * reported an unhelpful `TypeError: fetch failed` for a documentation URL that\n * merely moved.\n *\n * @param url - Absolute URL to read.\n * @returns The response body as text.\n */\nconst fetchUrlContent = async (url: string): Promise<string> => {\n let target = parseAllowedUrl(url);\n\n for (let hop = 0; hop <= MAX_FETCH_REDIRECTS; hop++) {\n const response = await fetch(target, { redirect: 'manual' });\n\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get('location');\n\n if (!location) {\n throw new Error(`Failed to fetch ${url}: redirect without a location`);\n }\n\n target = parseAllowedUrl(new URL(location, target));\n continue;\n }\n\n if (!response.ok) {\n throw new Error(`Failed to fetch ${url}: ${response.statusText}`);\n }\n\n return response.text();\n }\n\n throw new Error(`Failed to fetch ${url}: too many redirects`);\n};\n\n/**\n * Installs skills using the \"Agent Skills\" directory standard.\n * Standard: <PROJECT_ROOT>/<CONFIG_DIR>/skills/<SKILL_NAME>/SKILL.md\n */\nexport const installSkills = async (\n projectRoot: string,\n platform: Platform,\n skills: Skill[]\n): Promise<string> => {\n // Determine destination directory\n const relativeDir = PLATFORMS_METADATA[platform]?.dir ?? 'skills';\n const skillsBaseDir = path.join(projectRoot, relativeDir);\n\n // Ensure the base directory exists\n await fs.mkdir(skillsBaseDir, { recursive: true });\n\n const createdSkills: string[] = [];\n const licenceContent = getLicenceContent();\n\n for (const skill of skills) {\n const baseName = SKILL_FILENAME_MAP[skill] ?? camelToKebabCase(skill);\n const skillName = `intlayer-${baseName}`;\n const skillContent = getSkillContent(skill);\n\n if (!skillContent) continue;\n\n // Extract unique URLs\n const urls = Array.from(\n new Set(skillContent.match(/https:\\/\\/intlayer\\.org\\/[^\\s)]+\\.md/g) || [])\n );\n\n // Agent Standard: .../skills/<skill-name>/SKILL.md\n const skillDir = path.join(skillsBaseDir, skillName);\n const referenceDir = path.join(skillDir, 'references');\n\n // Ensure directories exist\n await fs.mkdir(referenceDir, { recursive: true });\n\n // Write License\n if (licenceContent) {\n await fs.writeFile(\n path.join(skillDir, 'LICENCE.md'),\n licenceContent,\n 'utf-8'\n );\n }\n\n let updatedSkillContent = skillContent;\n\n // Parallel download of references\n const downloadPromises = urls.map(async (url) => {\n try {\n const content = await fetchUrlContent(url);\n const metadata = getMarkdownMetadata<{ slugs?: string[] }>(content);\n\n let fileName = '';\n\n // Determine filename from slugs or URL path\n if (Array.isArray(metadata.slugs)) {\n fileName = metadata.slugs\n .filter((slug) => slug !== 'doc')\n .join('_')\n // Scoped package slugs (`@intlayer/babel`) must not create subfolders\n .replaceAll('/', '_');\n } else {\n const urlPath = new URL(url).pathname;\n fileName = urlPath\n .split('/')\n .filter((part) => part && part !== 'doc')\n .map((part) => part.replace('.md', '')) // Clean extension for joining\n .join('_');\n }\n\n // Ensure it ends with .md\n fileName = fileName ? `${fileName}.md` : 'index.md';\n const localRefPath = `references/${fileName}`;\n\n return {\n url,\n localRefPath,\n fileName,\n content,\n success: true,\n };\n } catch (error) {\n console.warn(\n `Warning: Failed to download ref ${url} for skill ${skill}`,\n error\n );\n return { url, success: false };\n }\n });\n\n const results = await Promise.all(downloadPromises);\n\n // Process results: Write files and update content string\n for (const res of results) {\n if (res.success && res.fileName && res.content && res.localRefPath) {\n // Write the reference file\n await fs.writeFile(\n path.join(referenceDir, res.fileName),\n res.content,\n 'utf-8'\n );\n\n // Update the main content to point to local file\n updatedSkillContent = updatedSkillContent.replaceAll(\n res.url,\n res.localRefPath\n );\n }\n }\n\n // Write the main SKILL.md\n const filePath = path.join(skillDir, 'SKILL.md');\n await fs.writeFile(filePath, updatedSkillContent, 'utf-8');\n createdSkills.push(`${skillName}/SKILL.md`);\n }\n\n if (createdSkills.length === 0) {\n return `No skill files were created. Check your asset paths.`;\n }\n\n return `${v} Created ${createdSkills.length} skills in ${skillsBaseDir}`;\n};\n"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { join } from "node:path";
2
2
  import { getAppLogger } from "@intlayer/config/logger";
3
3
  import { readFileSync } from "node:fs";
4
4
  import { log } from "@intlayer/config/built";
5
- import simpleGit from "simple-git";
5
+ import { simpleGit } from "simple-git";
6
6
 
7
7
  //#region src/listGitFiles.ts
8
8
  const getGitRootDir = async () => {
@@ -1 +1 @@
1
- {"version":3,"file":"listGitFiles.mjs","names":[],"sources":["../../src/listGitFiles.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { log } from '@intlayer/config/built';\nimport { getAppLogger } from '@intlayer/config/logger';\nimport simpleGit from 'simple-git';\n\nexport type DiffMode = 'gitDiff' | 'uncommitted' | 'unpushed' | 'untracked';\n\nconst getGitRootDir = async (): Promise<string | null> => {\n try {\n const git = simpleGit();\n const rootDir = await git.revparse(['--show-toplevel']);\n return rootDir.trim();\n } catch (error) {\n const appLogger = getAppLogger({ log });\n appLogger(`Error getting git root directory: ${error}`, {\n level: 'error',\n });\n return null;\n }\n};\n\nexport type ListGitFilesOptions = {\n mode: DiffMode[];\n baseRef?: string;\n currentRef?: string;\n absolute?: boolean;\n};\n\nexport const listGitFiles = async ({\n mode,\n baseRef = 'origin/main',\n currentRef = 'HEAD', // HEAD points to the current branch's latest commit\n absolute = true,\n}: ListGitFilesOptions) => {\n try {\n const git = simpleGit();\n const diff: Set<string> = new Set();\n\n if (mode.includes('untracked')) {\n const status = await git.status();\n status.not_added.forEach((file) => {\n diff.add(file);\n });\n }\n\n if (mode.includes('uncommitted')) {\n // Get uncommitted changes\n const uncommittedDiff = await git.diff(['--name-only', 'HEAD']);\n\n const uncommittedFiles = uncommittedDiff.split('\\n').filter(Boolean);\n\n uncommittedFiles.forEach((file) => {\n diff.add(file);\n });\n }\n\n if (mode.includes('unpushed')) {\n // Get unpushed commits\n const unpushedDiff = await git.diff(['--name-only', '@{push}...HEAD']);\n\n const unpushedFiles = unpushedDiff.split('\\n').filter(Boolean);\n\n unpushedFiles.forEach((file) => {\n diff.add(file);\n });\n }\n\n if (mode.includes('gitDiff')) {\n // Get the base branch (usually main/master) from CI environment\n\n await git.fetch(baseRef);\n\n const diffBranch = await git.diff([\n '--name-only',\n `${baseRef}...${currentRef}`,\n ]);\n\n const gitDiffFiles = diffBranch.split('\\n').filter(Boolean);\n\n gitDiffFiles.forEach((file) => {\n diff.add(file);\n });\n }\n\n if (absolute) {\n const gitRootDir = await getGitRootDir();\n if (!gitRootDir) {\n return [];\n }\n return Array.from(diff).map((file) => join(gitRootDir, file));\n }\n\n return Array.from(diff);\n } catch (error) {\n console.warn('Failed to get changes list:', error);\n }\n};\n\nexport type ListGitLinesOptions = {\n mode: DiffMode[];\n baseRef?: string;\n currentRef?: string;\n};\n\nexport const listGitLines = async (\n filePath: string,\n {\n mode,\n baseRef = 'origin/main',\n currentRef = 'HEAD', // HEAD points to the current branch's latest commit\n }: ListGitLinesOptions\n): Promise<number[]> => {\n const git = simpleGit();\n // We collect **line numbers** (1-based) that were modified/added by the diff.\n // Using a Set ensures uniqueness when the same line is reported by several modes.\n const changedLines: Set<number> = new Set();\n\n /**\n * Extracts line numbers from a diff generated with `--unified=0`.\n * Each hunk header looks like: @@ -<oldStart>,<oldCount> +<newStart>,<newCount> @@\n * We consider both the \"+\" (new) side for additions and the \"-\" (old) side for deletions.\n * For deletions, we add the line before and after the deletion point in the current file.\n */\n const collectLinesFromDiff = (diffOutput: string) => {\n const hunkRegex = /@@ -(\\d+)(?:,(\\d+))? \\+(\\d+)(?:,(\\d+))? @@/g;\n let match: RegExpExecArray | null;\n\n // biome-ignore lint/suspicious/noAssignInExpressions: Used in while loop condition\n while ((match = hunkRegex.exec(diffOutput)) !== null) {\n const oldCount = match[2] ? Number(match[2]) : 1;\n const newStart = Number(match[3]);\n const newCount = match[4] ? Number(match[4]) : 1;\n\n // Handle additions/modifications (+ side)\n if (newCount > 0) {\n for (let i = 0; i < newCount; i++) {\n changedLines.add(newStart + i);\n }\n }\n\n // Handle deletions (- side)\n if (oldCount > 0 && newCount === 0) {\n // For deletions, add the line before and after the deletion point\n // The deletion point in the new file is at newStart\n if (newStart > 1) {\n changedLines.add(newStart - 1); // Line before deletion\n }\n changedLines.add(newStart); // Line after deletion (if it exists)\n }\n }\n };\n\n // 1. Handle untracked files – when a file is untracked its entire content is new.\n if (mode.includes('untracked')) {\n const status = await git.status();\n const isUntracked = status.not_added.includes(filePath);\n if (isUntracked) {\n try {\n const content = readFileSync(filePath, 'utf-8');\n content.split('\\n').forEach((_, idx) => {\n changedLines.add(idx + 1);\n });\n } catch {\n // ignore read errors – file may have been deleted, etc.\n }\n }\n }\n\n // 2. Uncommitted changes (working tree vs HEAD)\n if (mode.includes('uncommitted')) {\n const diffOutput = await git.diff(['--unified=0', 'HEAD', '--', filePath]);\n collectLinesFromDiff(diffOutput);\n }\n\n // 3. Unpushed commits – compare local branch to its upstream\n if (mode.includes('unpushed')) {\n const diffOutput = await git.diff([\n '--unified=0',\n '@{push}...HEAD',\n '--',\n filePath,\n ]);\n collectLinesFromDiff(diffOutput);\n }\n\n // 4. Regular git diff between baseRef and currentRef (e.g., CI pull-request diff)\n if (mode.includes('gitDiff')) {\n await git.fetch(baseRef);\n const diffOutput = await git.diff([\n '--unified=0',\n `${baseRef}...${currentRef}`,\n '--',\n filePath,\n ]);\n collectLinesFromDiff(diffOutput);\n }\n\n // Return the list sorted for convenience\n return Array.from(changedLines).sort((a, b) => a - b);\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"listGitFiles.mjs","names":[],"sources":["../../src/listGitFiles.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { log } from '@intlayer/config/built';\nimport { getAppLogger } from '@intlayer/config/logger';\nimport { simpleGit } from 'simple-git';\n\nexport type DiffMode = 'gitDiff' | 'uncommitted' | 'unpushed' | 'untracked';\n\nconst getGitRootDir = async (): Promise<string | null> => {\n try {\n const git = simpleGit();\n const rootDir = await git.revparse(['--show-toplevel']);\n return rootDir.trim();\n } catch (error) {\n const appLogger = getAppLogger({ log });\n appLogger(`Error getting git root directory: ${error}`, {\n level: 'error',\n });\n return null;\n }\n};\n\nexport type ListGitFilesOptions = {\n mode: DiffMode[];\n baseRef?: string;\n currentRef?: string;\n absolute?: boolean;\n};\n\nexport const listGitFiles = async ({\n mode,\n baseRef = 'origin/main',\n currentRef = 'HEAD', // HEAD points to the current branch's latest commit\n absolute = true,\n}: ListGitFilesOptions) => {\n try {\n const git = simpleGit();\n const diff: Set<string> = new Set();\n\n if (mode.includes('untracked')) {\n const status = await git.status();\n status.not_added.forEach((file) => {\n diff.add(file);\n });\n }\n\n if (mode.includes('uncommitted')) {\n // Get uncommitted changes\n const uncommittedDiff = await git.diff(['--name-only', 'HEAD']);\n\n const uncommittedFiles = uncommittedDiff.split('\\n').filter(Boolean);\n\n uncommittedFiles.forEach((file) => {\n diff.add(file);\n });\n }\n\n if (mode.includes('unpushed')) {\n // Get unpushed commits\n const unpushedDiff = await git.diff(['--name-only', '@{push}...HEAD']);\n\n const unpushedFiles = unpushedDiff.split('\\n').filter(Boolean);\n\n unpushedFiles.forEach((file) => {\n diff.add(file);\n });\n }\n\n if (mode.includes('gitDiff')) {\n // Get the base branch (usually main/master) from CI environment\n\n await git.fetch(baseRef);\n\n const diffBranch = await git.diff([\n '--name-only',\n `${baseRef}...${currentRef}`,\n ]);\n\n const gitDiffFiles = diffBranch.split('\\n').filter(Boolean);\n\n gitDiffFiles.forEach((file) => {\n diff.add(file);\n });\n }\n\n if (absolute) {\n const gitRootDir = await getGitRootDir();\n if (!gitRootDir) {\n return [];\n }\n return Array.from(diff).map((file) => join(gitRootDir, file));\n }\n\n return Array.from(diff);\n } catch (error) {\n console.warn('Failed to get changes list:', error);\n }\n};\n\nexport type ListGitLinesOptions = {\n mode: DiffMode[];\n baseRef?: string;\n currentRef?: string;\n};\n\nexport const listGitLines = async (\n filePath: string,\n {\n mode,\n baseRef = 'origin/main',\n currentRef = 'HEAD', // HEAD points to the current branch's latest commit\n }: ListGitLinesOptions\n): Promise<number[]> => {\n const git = simpleGit();\n // We collect **line numbers** (1-based) that were modified/added by the diff.\n // Using a Set ensures uniqueness when the same line is reported by several modes.\n const changedLines: Set<number> = new Set();\n\n /**\n * Extracts line numbers from a diff generated with `--unified=0`.\n * Each hunk header looks like: @@ -<oldStart>,<oldCount> +<newStart>,<newCount> @@\n * We consider both the \"+\" (new) side for additions and the \"-\" (old) side for deletions.\n * For deletions, we add the line before and after the deletion point in the current file.\n */\n const collectLinesFromDiff = (diffOutput: string) => {\n const hunkRegex = /@@ -(\\d+)(?:,(\\d+))? \\+(\\d+)(?:,(\\d+))? @@/g;\n let match: RegExpExecArray | null;\n\n // biome-ignore lint/suspicious/noAssignInExpressions: Used in while loop condition\n while ((match = hunkRegex.exec(diffOutput)) !== null) {\n const oldCount = match[2] ? Number(match[2]) : 1;\n const newStart = Number(match[3]);\n const newCount = match[4] ? Number(match[4]) : 1;\n\n // Handle additions/modifications (+ side)\n if (newCount > 0) {\n for (let i = 0; i < newCount; i++) {\n changedLines.add(newStart + i);\n }\n }\n\n // Handle deletions (- side)\n if (oldCount > 0 && newCount === 0) {\n // For deletions, add the line before and after the deletion point\n // The deletion point in the new file is at newStart\n if (newStart > 1) {\n changedLines.add(newStart - 1); // Line before deletion\n }\n changedLines.add(newStart); // Line after deletion (if it exists)\n }\n }\n };\n\n // 1. Handle untracked files – when a file is untracked its entire content is new.\n if (mode.includes('untracked')) {\n const status = await git.status();\n const isUntracked = status.not_added.includes(filePath);\n if (isUntracked) {\n try {\n const content = readFileSync(filePath, 'utf-8');\n content.split('\\n').forEach((_, idx) => {\n changedLines.add(idx + 1);\n });\n } catch {\n // ignore read errors – file may have been deleted, etc.\n }\n }\n }\n\n // 2. Uncommitted changes (working tree vs HEAD)\n if (mode.includes('uncommitted')) {\n const diffOutput = await git.diff(['--unified=0', 'HEAD', '--', filePath]);\n collectLinesFromDiff(diffOutput);\n }\n\n // 3. Unpushed commits – compare local branch to its upstream\n if (mode.includes('unpushed')) {\n const diffOutput = await git.diff([\n '--unified=0',\n '@{push}...HEAD',\n '--',\n filePath,\n ]);\n collectLinesFromDiff(diffOutput);\n }\n\n // 4. Regular git diff between baseRef and currentRef (e.g., CI pull-request diff)\n if (mode.includes('gitDiff')) {\n await git.fetch(baseRef);\n const diffOutput = await git.diff([\n '--unified=0',\n `${baseRef}...${currentRef}`,\n '--',\n filePath,\n ]);\n collectLinesFromDiff(diffOutput);\n }\n\n // Return the list sorted for convenience\n return Array.from(changedLines).sort((a, b) => a - b);\n};\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { dirname } from "node:path";
2
2
  import { configurationFilesCandidates } from "@intlayer/config/node";
3
3
  import fg from "fast-glob";
4
- import simpleGit from "simple-git";
4
+ import { simpleGit } from "simple-git";
5
5
 
6
6
  //#region src/listProjects.ts
7
7
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"listProjects.mjs","names":[],"sources":["../../src/listProjects.ts"],"sourcesContent":["import { dirname } from 'node:path';\nimport { configurationFilesCandidates } from '@intlayer/config/node';\nimport fg from 'fast-glob';\nimport simpleGit from 'simple-git';\n\nexport type ListProjectsOptions = {\n /**\n * Base directory to search from\n * @default process.cwd()\n */\n baseDir?: string;\n /**\n * If true, search from the git root directory instead of baseDir\n * @default false\n */\n gitRoot?: boolean;\n};\n\n/**\n * Returns the git repository root directory, or `null` when the given\n * directory is not inside a git repository.\n */\nexport const getGitRootDir = async (cwd?: string): Promise<string | null> => {\n try {\n const git = cwd ? simpleGit(cwd) : simpleGit();\n const rootDir = await git.revparse(['--show-toplevel']);\n return rootDir.trim();\n } catch (_error) {\n return null;\n }\n};\n\n/**\n * List all Intlayer projects by searching for configuration files\n *\n * @param options - Options for listing projects\n * @returns Array of absolute paths to project directories containing Intlayer config\n */\nexport const listProjects = async (\n options?: ListProjectsOptions\n): Promise<{ searchDir: string; projectsPath: string[] }> => {\n let searchDir = options?.baseDir ?? process.cwd();\n\n // If gitRoot option is enabled, try to get the git root directory\n if (options?.gitRoot) {\n const gitRootDir = await getGitRootDir(searchDir);\n if (gitRootDir) {\n searchDir = gitRootDir;\n }\n }\n\n // Build glob patterns for all config file candidates\n const configPatterns = configurationFilesCandidates.map(\n (fileName) => `**/${fileName}`\n );\n\n // Search for all config files\n const configFiles = await fg(configPatterns, {\n cwd: searchDir,\n absolute: true,\n ignore: ['**/node_modules/**', '**/.git/**'],\n dot: true, // Include dot files like .intlayerrc\n });\n\n // Extract unique directory paths from config files\n const projectDirs = [...new Set(configFiles.map((file) => dirname(file)))];\n\n // Sort alphabetically for consistent output\n return { searchDir, projectsPath: projectDirs.sort() };\n};\n"],"mappings":";;;;;;;;;;AAsBA,MAAa,gBAAgB,OAAO,QAAyC;CAC3E,IAAI;EAGF,QAAO,OAFK,MAAM,UAAU,GAAG,IAAI,UAAU,EACpB,CAAC,SAAS,CAAC,iBAAiB,CAAC,EACxC,CAAC,KAAK;CACtB,SAAS,QAAQ;EACf,OAAO;CACT;AACF;;;;;;;AAQA,MAAa,eAAe,OAC1B,YAC2D;CAC3D,IAAI,YAAY,SAAS,WAAW,QAAQ,IAAI;CAGhD,IAAI,SAAS,SAAS;EACpB,MAAM,aAAa,MAAM,cAAc,SAAS;EAChD,IAAI,YACF,YAAY;CAEhB;CAGA,MAAM,iBAAiB,6BAA6B,KACjD,aAAa,MAAM,UACtB;CAGA,MAAM,cAAc,MAAM,GAAG,gBAAgB;EAC3C,KAAK;EACL,UAAU;EACV,QAAQ,CAAC,sBAAsB,YAAY;EAC3C,KAAK;CACP,CAAC;CAGD,MAAM,cAAc,CAAC,GAAG,IAAI,IAAI,YAAY,KAAK,SAAS,QAAQ,IAAI,CAAC,CAAC,CAAC;CAGzE,OAAO;EAAE;EAAW,cAAc,YAAY,KAAK;CAAE;AACvD"}
1
+ {"version":3,"file":"listProjects.mjs","names":[],"sources":["../../src/listProjects.ts"],"sourcesContent":["import { dirname } from 'node:path';\nimport { configurationFilesCandidates } from '@intlayer/config/node';\nimport fg from 'fast-glob';\nimport { simpleGit } from 'simple-git';\n\nexport type ListProjectsOptions = {\n /**\n * Base directory to search from\n * @default process.cwd()\n */\n baseDir?: string;\n /**\n * If true, search from the git root directory instead of baseDir\n * @default false\n */\n gitRoot?: boolean;\n};\n\n/**\n * Returns the git repository root directory, or `null` when the given\n * directory is not inside a git repository.\n */\nexport const getGitRootDir = async (cwd?: string): Promise<string | null> => {\n try {\n const git = cwd ? simpleGit(cwd) : simpleGit();\n const rootDir = await git.revparse(['--show-toplevel']);\n return rootDir.trim();\n } catch (_error) {\n return null;\n }\n};\n\n/**\n * List all Intlayer projects by searching for configuration files\n *\n * @param options - Options for listing projects\n * @returns Array of absolute paths to project directories containing Intlayer config\n */\nexport const listProjects = async (\n options?: ListProjectsOptions\n): Promise<{ searchDir: string; projectsPath: string[] }> => {\n let searchDir = options?.baseDir ?? process.cwd();\n\n // If gitRoot option is enabled, try to get the git root directory\n if (options?.gitRoot) {\n const gitRootDir = await getGitRootDir(searchDir);\n if (gitRootDir) {\n searchDir = gitRootDir;\n }\n }\n\n // Build glob patterns for all config file candidates\n const configPatterns = configurationFilesCandidates.map(\n (fileName) => `**/${fileName}`\n );\n\n // Search for all config files\n const configFiles = await fg(configPatterns, {\n cwd: searchDir,\n absolute: true,\n ignore: ['**/node_modules/**', '**/.git/**'],\n dot: true, // Include dot files like .intlayerrc\n });\n\n // Extract unique directory paths from config files\n const projectDirs = [...new Set(configFiles.map((file) => dirname(file)))];\n\n // Sort alphabetically for consistent output\n return { searchDir, projectsPath: projectDirs.sort() };\n};\n"],"mappings":";;;;;;;;;;AAsBA,MAAa,gBAAgB,OAAO,QAAyC;CAC3E,IAAI;EAGF,QAAO,OAFK,MAAM,UAAU,GAAG,IAAI,UAAU,EACpB,CAAC,SAAS,CAAC,iBAAiB,CAAC,EACxC,CAAC,KAAK;CACtB,SAAS,QAAQ;EACf,OAAO;CACT;AACF;;;;;;;AAQA,MAAa,eAAe,OAC1B,YAC2D;CAC3D,IAAI,YAAY,SAAS,WAAW,QAAQ,IAAI;CAGhD,IAAI,SAAS,SAAS;EACpB,MAAM,aAAa,MAAM,cAAc,SAAS;EAChD,IAAI,YACF,YAAY;CAEhB;CAGA,MAAM,iBAAiB,6BAA6B,KACjD,aAAa,MAAM,UACtB;CAGA,MAAM,cAAc,MAAM,GAAG,gBAAgB;EAC3C,KAAK;EACL,UAAU;EACV,QAAQ,CAAC,sBAAsB,YAAY;EAC3C,KAAK;CACP,CAAC;CAGD,MAAM,cAAc,CAAC,GAAG,IAAI,IAAI,YAAY,KAAK,SAAS,QAAQ,IAAI,CAAC,CAAC,CAAC;CAGzE,OAAO;EAAE;EAAW,cAAc,YAAY,KAAK;CAAE;AACvD"}
@@ -1,6 +1,6 @@
1
1
  import { ps } from "./ps.mjs";
2
2
  import { wmic } from "./wmic.mjs";
3
- import * as os$1 from "node:os";
3
+ import * as os from "node:os";
4
4
 
5
5
  //#region src/utils/runParallel/pidTree.ts
6
6
  const platformToMethod = {
@@ -16,7 +16,7 @@ const methodToFn = {
16
16
  ps,
17
17
  wmic
18
18
  };
19
- let platform = os$1.platform();
19
+ let platform = os.platform();
20
20
  if (platform.startsWith("win")) platform = "win";
21
21
  const method = platformToMethod[platform];
22
22
  /**
@@ -24,7 +24,7 @@ const method = platformToMethod[platform];
24
24
  */
25
25
  const getAll = (callback) => {
26
26
  if (method === void 0) {
27
- callback(/* @__PURE__ */ new Error(os$1.platform() + " is not supported yet, please open an issue (https://github.com/simonepri/pidtree)"), void 0);
27
+ callback(/* @__PURE__ */ new Error(os.platform() + " is not supported yet, please open an issue (https://github.com/simonepri/pidtree)"), void 0);
28
28
  return;
29
29
  }
30
30
  const listFn = methodToFn[method];
@@ -1 +1 @@
1
- {"version":3,"file":"pidTree.mjs","names":["os"],"sources":["../../../../src/utils/runParallel/pidTree.ts"],"sourcesContent":["import * as os from 'node:os';\nimport { ps } from './ps';\nimport { wmic } from './wmic';\n\ntype Platform =\n | 'darwin'\n | 'sunos'\n | 'freebsd'\n | 'netbsd'\n | 'win'\n | 'linux'\n | 'aix';\ntype Method = 'ps' | 'wmic';\n\ntype ProcessList = [number, number][]; // [PPID, PID][]\n\ninterface ListOptions {\n root?: boolean;\n advanced?: boolean;\n}\n\ntype ProcessInfo = { pid: number; ppid?: number };\ntype ResultType<T extends ListOptions | undefined> = T extends {\n advanced: true;\n}\n ? ProcessInfo[]\n : number[];\n\ntype ProcessListCallback = (err: Error | null, list?: ProcessList) => void;\ntype ListCallback<T extends ListOptions | undefined> = (\n err: Error | null,\n list?: ResultType<T>\n) => void;\n\ntype ProcessListFn = (callback: ProcessListCallback) => void;\n\nconst platformToMethod: Record<Platform, Method> = {\n darwin: 'ps',\n sunos: 'ps',\n freebsd: 'ps',\n netbsd: 'ps',\n win: 'wmic',\n linux: 'ps',\n aix: 'ps',\n};\n\nconst methodToFn: Record<Method, ProcessListFn> = {\n ps,\n wmic,\n};\n\nlet platform: string = os.platform();\nif (platform.startsWith('win')) {\n platform = 'win';\n}\n\nconst method: Method | undefined = platformToMethod[platform as Platform];\n\n/**\n * Gets the list of all the pids of the system.\n */\nconst getAll = (callback: ProcessListCallback): void => {\n if (method === undefined) {\n callback(\n new Error(\n os.platform() +\n ' is not supported yet, please open an issue (https://github.com/simonepri/pidtree)'\n ),\n undefined\n );\n return;\n }\n\n const listFn = methodToFn[method];\n listFn(callback);\n};\n\n/**\n * Get the list of children and grandchildren pids of the given PID.\n * @param PID A PID. If -1 will return all the pids.\n * @param options Optional options object.\n * @param callback Called when the list is ready.\n */\nconst pidtree = <T extends ListOptions | undefined>(\n PID: number | string,\n options: T | ListCallback<T> | undefined,\n callback?: ListCallback<T>\n): void => {\n let normalizedOptions: ListOptions;\n let normalizedCallback: ListCallback<T>;\n\n if (typeof options === 'function') {\n normalizedCallback = options;\n normalizedOptions = {};\n } else {\n normalizedCallback = callback!;\n normalizedOptions = typeof options === 'object' ? options : {};\n }\n\n const parsedPID = parseInt(String(PID), 10);\n if (Number.isNaN(parsedPID) || parsedPID < -1) {\n normalizedCallback(\n new TypeError('The pid provided is invalid') as Error,\n undefined\n );\n return;\n }\n\n getAll((err, processList) => {\n if (err) {\n normalizedCallback(err, undefined);\n return;\n }\n\n if (!processList) {\n normalizedCallback(new Error('Failed to get process list'), undefined);\n return;\n }\n\n // If the user wants the whole list just return it\n if (parsedPID === -1) {\n const result = processList.map(([ppid, pid]) =>\n normalizedOptions.advanced ? { ppid, pid } : pid\n ) as ResultType<T>;\n\n normalizedCallback(null, result);\n return;\n }\n\n let root: ProcessInfo | number | undefined;\n for (let l = 0; l < processList.length; l++) {\n const proc = processList[l];\n\n if (!proc) continue;\n const [ppid, pid] = proc;\n\n if (pid === parsedPID) {\n root = normalizedOptions.advanced\n ? { ppid, pid: parsedPID }\n : parsedPID;\n break;\n }\n\n if (ppid === parsedPID) {\n root = normalizedOptions.advanced ? { pid: parsedPID } : parsedPID; // Special pids like 0 on *nix\n }\n }\n\n if (root === undefined) {\n normalizedCallback(new Error('No matching pid found'), undefined);\n return;\n }\n\n // Build the adjacency Hash Map (pid -> [children of pid])\n const tree: Record<number, number[]> = {};\n const listCopy = [...processList];\n while (listCopy.length > 0) {\n const element = listCopy.pop();\n\n if (!element) continue;\n const ppid = element[0];\n const pid = element[1];\n const children = tree[ppid];\n\n if (children) {\n children.push(pid);\n } else {\n tree[ppid] = [pid];\n }\n }\n\n // Starting by the PID provided by the user, traverse the tree using the\n // adjacency Hash Map until the whole subtree is visited.\n // Each pid encountered while visiting is added to the pids array.\n let idx = 0;\n const pids: (ProcessInfo | number)[] = [root];\n while (idx < pids.length) {\n const curpid = normalizedOptions.advanced\n ? (pids[idx++] as ProcessInfo).pid\n : (pids[idx++] as number);\n const children = tree[curpid];\n\n if (!children) continue;\n const length = children.length;\n for (let j = 0; j < length; j++) {\n const childPid = children[j];\n\n if (childPid === undefined) continue;\n\n pids.push(\n normalizedOptions.advanced\n ? { ppid: curpid, pid: childPid }\n : childPid\n );\n }\n\n delete tree[curpid];\n }\n\n if (!normalizedOptions.root) {\n pids.shift(); // Remove root\n }\n\n normalizedCallback(null, pids as ResultType<T>);\n });\n};\n\nconst pify = <T extends ListOptions | undefined>(\n fn: typeof pidtree,\n arg1: number | string,\n arg2: T | undefined\n): Promise<ResultType<T>> => {\n return new Promise((resolve, reject) => {\n fn(arg1, arg2, (err, data) => {\n if (err) return reject(err);\n if (data === undefined) {\n return reject(new Error('No data returned'));\n }\n resolve(data);\n });\n });\n};\n\n// Node versions prior to 4.0.0 do not define have `startsWith`.\n/* istanbul ignore if */\nif (!String.prototype.startsWith) {\n String.prototype.startsWith = function (suffix: string): boolean {\n return this.substring(0, suffix.length) === suffix;\n };\n}\n\n/**\n * Get the list of children pids of the given pid.\n * @param pid A PID. If -1 will return all the pids.\n * @param options Optional options object.\n * @param callback Called when the list is ready. If not provided a promise is returned instead.\n * @returns Only when the callback is not provided.\n */\nexport const list = <T extends ListOptions | undefined>(\n pid: number | string,\n options?: T | ListCallback<T>,\n callback?: ListCallback<T>\n): Promise<ResultType<T>> | undefined => {\n if (typeof options === 'function') {\n pidtree(pid, undefined, options);\n return;\n }\n\n if (typeof callback === 'function') {\n pidtree(pid, options, callback);\n return;\n }\n\n return pify(pidtree, pid, options);\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"pidTree.mjs","names":[],"sources":["../../../../src/utils/runParallel/pidTree.ts"],"sourcesContent":["import * as os from 'node:os';\nimport { ps } from './ps';\nimport { wmic } from './wmic';\n\ntype Platform =\n | 'darwin'\n | 'sunos'\n | 'freebsd'\n | 'netbsd'\n | 'win'\n | 'linux'\n | 'aix';\ntype Method = 'ps' | 'wmic';\n\ntype ProcessList = [number, number][]; // [PPID, PID][]\n\ninterface ListOptions {\n root?: boolean;\n advanced?: boolean;\n}\n\ntype ProcessInfo = { pid: number; ppid?: number };\ntype ResultType<T extends ListOptions | undefined> = T extends {\n advanced: true;\n}\n ? ProcessInfo[]\n : number[];\n\ntype ProcessListCallback = (err: Error | null, list?: ProcessList) => void;\ntype ListCallback<T extends ListOptions | undefined> = (\n err: Error | null,\n list?: ResultType<T>\n) => void;\n\ntype ProcessListFn = (callback: ProcessListCallback) => void;\n\nconst platformToMethod: Record<Platform, Method> = {\n darwin: 'ps',\n sunos: 'ps',\n freebsd: 'ps',\n netbsd: 'ps',\n win: 'wmic',\n linux: 'ps',\n aix: 'ps',\n};\n\nconst methodToFn: Record<Method, ProcessListFn> = {\n ps,\n wmic,\n};\n\nlet platform: string = os.platform();\nif (platform.startsWith('win')) {\n platform = 'win';\n}\n\nconst method: Method | undefined = platformToMethod[platform as Platform];\n\n/**\n * Gets the list of all the pids of the system.\n */\nconst getAll = (callback: ProcessListCallback): void => {\n if (method === undefined) {\n callback(\n new Error(\n os.platform() +\n ' is not supported yet, please open an issue (https://github.com/simonepri/pidtree)'\n ),\n undefined\n );\n return;\n }\n\n const listFn = methodToFn[method];\n listFn(callback);\n};\n\n/**\n * Get the list of children and grandchildren pids of the given PID.\n * @param PID A PID. If -1 will return all the pids.\n * @param options Optional options object.\n * @param callback Called when the list is ready.\n */\nconst pidtree = <T extends ListOptions | undefined>(\n PID: number | string,\n options: T | ListCallback<T> | undefined,\n callback?: ListCallback<T>\n): void => {\n let normalizedOptions: ListOptions;\n let normalizedCallback: ListCallback<T>;\n\n if (typeof options === 'function') {\n normalizedCallback = options;\n normalizedOptions = {};\n } else {\n normalizedCallback = callback!;\n normalizedOptions = typeof options === 'object' ? options : {};\n }\n\n const parsedPID = parseInt(String(PID), 10);\n if (Number.isNaN(parsedPID) || parsedPID < -1) {\n normalizedCallback(\n new TypeError('The pid provided is invalid') as Error,\n undefined\n );\n return;\n }\n\n getAll((err, processList) => {\n if (err) {\n normalizedCallback(err, undefined);\n return;\n }\n\n if (!processList) {\n normalizedCallback(new Error('Failed to get process list'), undefined);\n return;\n }\n\n // If the user wants the whole list just return it\n if (parsedPID === -1) {\n const result = processList.map(([ppid, pid]) =>\n normalizedOptions.advanced ? { ppid, pid } : pid\n ) as ResultType<T>;\n\n normalizedCallback(null, result);\n return;\n }\n\n let root: ProcessInfo | number | undefined;\n for (let l = 0; l < processList.length; l++) {\n const proc = processList[l];\n\n if (!proc) continue;\n const [ppid, pid] = proc;\n\n if (pid === parsedPID) {\n root = normalizedOptions.advanced\n ? { ppid, pid: parsedPID }\n : parsedPID;\n break;\n }\n\n if (ppid === parsedPID) {\n root = normalizedOptions.advanced ? { pid: parsedPID } : parsedPID; // Special pids like 0 on *nix\n }\n }\n\n if (root === undefined) {\n normalizedCallback(new Error('No matching pid found'), undefined);\n return;\n }\n\n // Build the adjacency Hash Map (pid -> [children of pid])\n const tree: Record<number, number[]> = {};\n const listCopy = [...processList];\n while (listCopy.length > 0) {\n const element = listCopy.pop();\n\n if (!element) continue;\n const ppid = element[0];\n const pid = element[1];\n const children = tree[ppid];\n\n if (children) {\n children.push(pid);\n } else {\n tree[ppid] = [pid];\n }\n }\n\n // Starting by the PID provided by the user, traverse the tree using the\n // adjacency Hash Map until the whole subtree is visited.\n // Each pid encountered while visiting is added to the pids array.\n let idx = 0;\n const pids: (ProcessInfo | number)[] = [root];\n while (idx < pids.length) {\n const curpid = normalizedOptions.advanced\n ? (pids[idx++] as ProcessInfo).pid\n : (pids[idx++] as number);\n const children = tree[curpid];\n\n if (!children) continue;\n const length = children.length;\n for (let j = 0; j < length; j++) {\n const childPid = children[j];\n\n if (childPid === undefined) continue;\n\n pids.push(\n normalizedOptions.advanced\n ? { ppid: curpid, pid: childPid }\n : childPid\n );\n }\n\n delete tree[curpid];\n }\n\n if (!normalizedOptions.root) {\n pids.shift(); // Remove root\n }\n\n normalizedCallback(null, pids as ResultType<T>);\n });\n};\n\nconst pify = <T extends ListOptions | undefined>(\n fn: typeof pidtree,\n arg1: number | string,\n arg2: T | undefined\n): Promise<ResultType<T>> => {\n return new Promise((resolve, reject) => {\n fn(arg1, arg2, (err, data) => {\n if (err) return reject(err);\n if (data === undefined) {\n return reject(new Error('No data returned'));\n }\n resolve(data);\n });\n });\n};\n\n// Node versions prior to 4.0.0 do not define have `startsWith`.\n/* istanbul ignore if */\nif (!String.prototype.startsWith) {\n String.prototype.startsWith = function (suffix: string): boolean {\n return this.substring(0, suffix.length) === suffix;\n };\n}\n\n/**\n * Get the list of children pids of the given pid.\n * @param pid A PID. If -1 will return all the pids.\n * @param options Optional options object.\n * @param callback Called when the list is ready. If not provided a promise is returned instead.\n * @returns Only when the callback is not provided.\n */\nexport const list = <T extends ListOptions | undefined>(\n pid: number | string,\n options?: T | ListCallback<T>,\n callback?: ListCallback<T>\n): Promise<ResultType<T>> | undefined => {\n if (typeof options === 'function') {\n pidtree(pid, undefined, options);\n return;\n }\n\n if (typeof callback === 'function') {\n pidtree(pid, options, callback);\n return;\n }\n\n return pify(pidtree, pid, options);\n};\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { run } from "./bin.mjs";
2
- import * as os$1 from "node:os";
2
+ import * as os from "node:os";
3
3
 
4
4
  //#region src/utils/runParallel/ps.ts
5
5
  /**
@@ -25,7 +25,7 @@ const ps = (callback) => {
25
25
  return;
26
26
  }
27
27
  try {
28
- const lines = stdout.split(os$1.EOL);
28
+ const lines = stdout.split(os.EOL);
29
29
  const list = [];
30
30
  for (let i = 1; i < lines.length; i++) {
31
31
  const line = lines[i];
@@ -1 +1 @@
1
- {"version":3,"file":"ps.mjs","names":["os"],"sources":["../../../../src/utils/runParallel/ps.ts"],"sourcesContent":["import * as os from 'node:os';\nimport { run } from './bin';\n\ntype ProcessList = [number, number][]; // [PPID, PID][]\ntype ProcessListCallback = (err: Error | null, list?: ProcessList) => void;\n\n/**\n * Gets the list of all the pids of the system through the ps command.\n * @param callback Callback function with error and process list.\n */\nexport const ps = (callback: ProcessListCallback): void => {\n const args = ['-A', '-o', 'ppid,pid'];\n\n run('ps', args, (err, stdout, code) => {\n if (err) {\n callback(err);\n return;\n }\n if (code !== 0) {\n callback(new Error(`pidtree ps command exited with code ${code}`));\n return;\n }\n\n // Example of stdout\n //\n // PPID PID\n // 1 430\n // 430 432\n // 1 727\n // 1 7166\n\n if (!stdout) {\n callback(new Error('No stdout received from ps command'));\n return;\n }\n\n try {\n const lines = stdout.split(os.EOL);\n\n const list: ProcessList = [];\n for (let i = 1; i < lines.length; i++) {\n const line = lines[i];\n\n if (!line) continue;\n\n const trimmed = line.trim();\n\n if (!trimmed) continue;\n\n const parts = trimmed.split(/\\s+/);\n const p0 = parts[0];\n const p1 = parts[1];\n\n if (!p0 || !p1) continue;\n\n const ppid = parseInt(p0, 10); // PPID\n const pid = parseInt(p1, 10); // PID\n\n if (!Number.isNaN(ppid) && !Number.isNaN(pid)) {\n list.push([ppid, pid]);\n }\n }\n\n callback(null, list);\n } catch (error) {\n callback(error instanceof Error ? error : new Error(String(error)));\n }\n });\n};\n"],"mappings":";;;;;;;;AAUA,MAAa,MAAM,aAAwC;CAGzD,IAAI,MAAM;EAFI;EAAM;EAAM;CAEb,IAAI,KAAK,QAAQ,SAAS;EACrC,IAAI,KAAK;GACP,SAAS,GAAG;GACZ;EACF;EACA,IAAI,SAAS,GAAG;GACd,yBAAS,IAAI,MAAM,uCAAuC,MAAM,CAAC;GACjE;EACF;EAUA,IAAI,CAAC,QAAQ;GACX,yBAAS,IAAI,MAAM,oCAAoC,CAAC;GACxD;EACF;EAEA,IAAI;GACF,MAAM,QAAQ,OAAO,MAAMA,KAAG,GAAG;GAEjC,MAAM,OAAoB,CAAC;GAC3B,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;IACrC,MAAM,OAAO,MAAM;IAEnB,IAAI,CAAC,MAAM;IAEX,MAAM,UAAU,KAAK,KAAK;IAE1B,IAAI,CAAC,SAAS;IAEd,MAAM,QAAQ,QAAQ,MAAM,KAAK;IACjC,MAAM,KAAK,MAAM;IACjB,MAAM,KAAK,MAAM;IAEjB,IAAI,CAAC,MAAM,CAAC,IAAI;IAEhB,MAAM,OAAO,SAAS,IAAI,EAAE;IAC5B,MAAM,MAAM,SAAS,IAAI,EAAE;IAE3B,IAAI,CAAC,OAAO,MAAM,IAAI,KAAK,CAAC,OAAO,MAAM,GAAG,GAC1C,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC;GAEzB;GAEA,SAAS,MAAM,IAAI;EACrB,SAAS,OAAO;GACd,SAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;EACpE;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"ps.mjs","names":[],"sources":["../../../../src/utils/runParallel/ps.ts"],"sourcesContent":["import * as os from 'node:os';\nimport { run } from './bin';\n\ntype ProcessList = [number, number][]; // [PPID, PID][]\ntype ProcessListCallback = (err: Error | null, list?: ProcessList) => void;\n\n/**\n * Gets the list of all the pids of the system through the ps command.\n * @param callback Callback function with error and process list.\n */\nexport const ps = (callback: ProcessListCallback): void => {\n const args = ['-A', '-o', 'ppid,pid'];\n\n run('ps', args, (err, stdout, code) => {\n if (err) {\n callback(err);\n return;\n }\n if (code !== 0) {\n callback(new Error(`pidtree ps command exited with code ${code}`));\n return;\n }\n\n // Example of stdout\n //\n // PPID PID\n // 1 430\n // 430 432\n // 1 727\n // 1 7166\n\n if (!stdout) {\n callback(new Error('No stdout received from ps command'));\n return;\n }\n\n try {\n const lines = stdout.split(os.EOL);\n\n const list: ProcessList = [];\n for (let i = 1; i < lines.length; i++) {\n const line = lines[i];\n\n if (!line) continue;\n\n const trimmed = line.trim();\n\n if (!trimmed) continue;\n\n const parts = trimmed.split(/\\s+/);\n const p0 = parts[0];\n const p1 = parts[1];\n\n if (!p0 || !p1) continue;\n\n const ppid = parseInt(p0, 10); // PPID\n const pid = parseInt(p1, 10); // PID\n\n if (!Number.isNaN(ppid) && !Number.isNaN(pid)) {\n list.push([ppid, pid]);\n }\n }\n\n callback(null, list);\n } catch (error) {\n callback(error instanceof Error ? error : new Error(String(error)));\n }\n });\n};\n"],"mappings":";;;;;;;;AAUA,MAAa,MAAM,aAAwC;CAGzD,IAAI,MAAM;EAFI;EAAM;EAAM;CAEb,IAAI,KAAK,QAAQ,SAAS;EACrC,IAAI,KAAK;GACP,SAAS,GAAG;GACZ;EACF;EACA,IAAI,SAAS,GAAG;GACd,yBAAS,IAAI,MAAM,uCAAuC,MAAM,CAAC;GACjE;EACF;EAUA,IAAI,CAAC,QAAQ;GACX,yBAAS,IAAI,MAAM,oCAAoC,CAAC;GACxD;EACF;EAEA,IAAI;GACF,MAAM,QAAQ,OAAO,MAAM,GAAG,GAAG;GAEjC,MAAM,OAAoB,CAAC;GAC3B,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;IACrC,MAAM,OAAO,MAAM;IAEnB,IAAI,CAAC,MAAM;IAEX,MAAM,UAAU,KAAK,KAAK;IAE1B,IAAI,CAAC,SAAS;IAEd,MAAM,QAAQ,QAAQ,MAAM,KAAK;IACjC,MAAM,KAAK,MAAM;IACjB,MAAM,KAAK,MAAM;IAEjB,IAAI,CAAC,MAAM,CAAC,IAAI;IAEhB,MAAM,OAAO,SAAS,IAAI,EAAE;IAC5B,MAAM,MAAM,SAAS,IAAI,EAAE;IAE3B,IAAI,CAAC,OAAO,MAAM,IAAI,KAAK,CAAC,OAAO,MAAM,GAAG,GAC1C,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC;GAEzB;GAEA,SAAS,MAAM,IAAI;EACrB,SAAS,OAAO;GACd,SAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;EACpE;CACF,CAAC;AACH"}
@@ -1,5 +1,5 @@
1
1
  import { run } from "./bin.mjs";
2
- import * as os$1 from "node:os";
2
+ import * as os from "node:os";
3
3
 
4
4
  //#region src/utils/runParallel/wmic.ts
5
5
  /**
@@ -28,7 +28,7 @@ const wmic = (callback) => {
28
28
  return;
29
29
  }
30
30
  try {
31
- const lines = stdout.split(os$1.EOL);
31
+ const lines = stdout.split(os.EOL);
32
32
  const list = [];
33
33
  for (let i = 1; i < lines.length; i++) {
34
34
  const line = lines[i];
@@ -1 +1 @@
1
- {"version":3,"file":"wmic.mjs","names":["os"],"sources":["../../../../src/utils/runParallel/wmic.ts"],"sourcesContent":["import type { SpawnOptions } from 'node:child_process';\nimport * as os from 'node:os';\nimport { run } from './bin';\n\ntype ProcessList = [number, number][]; // [PPID, PID][]\ntype ProcessListCallback = (err: Error | null, list?: ProcessList) => void;\n\n/**\n * Gets the list of all the pids of the system through the wmic command.\n * @param callback Callback function with error and process list.\n */\nexport const wmic = (callback: ProcessListCallback): void => {\n const args = ['PROCESS', 'get', 'ParentProcessId,ProcessId'];\n const options: SpawnOptions = {\n windowsHide: true,\n windowsVerbatimArguments: true,\n };\n run('wmic', args, options, (err, stdout, code) => {\n if (err) {\n callback(err);\n return;\n }\n\n if (code !== 0) {\n callback(new Error(`pidtree wmic command exited with code ${code}`));\n return;\n }\n\n // Example of stdout\n //\n // ParentProcessId ProcessId\n // 0 777\n\n if (!stdout) {\n callback(new Error('No stdout received from wmic command'));\n return;\n }\n\n try {\n const lines = stdout.split(os.EOL);\n\n const list: ProcessList = [];\n for (let i = 1; i < lines.length; i++) {\n const line = lines[i];\n\n if (!line) continue;\n const trimmed = line.trim();\n\n if (!trimmed) continue;\n\n const parts = trimmed.split(/\\s+/);\n const p0 = parts[0];\n const p1 = parts[1];\n\n if (!p0 || !p1) continue;\n\n const ppid = parseInt(p0, 10); // PPID\n const pid = parseInt(p1, 10); // PID\n\n if (!Number.isNaN(ppid) && !Number.isNaN(pid)) {\n list.push([ppid, pid]);\n }\n }\n\n callback(null, list);\n } catch (error) {\n callback(error instanceof Error ? error : new Error(String(error)));\n }\n });\n};\n"],"mappings":";;;;;;;;AAWA,MAAa,QAAQ,aAAwC;CAM3D,IAAI,QAAQ;EALE;EAAW;EAAO;CAKjB,GAAG;EAHhB,aAAa;EACb,0BAA0B;CAEJ,IAAI,KAAK,QAAQ,SAAS;EAChD,IAAI,KAAK;GACP,SAAS,GAAG;GACZ;EACF;EAEA,IAAI,SAAS,GAAG;GACd,yBAAS,IAAI,MAAM,yCAAyC,MAAM,CAAC;GACnE;EACF;EAOA,IAAI,CAAC,QAAQ;GACX,yBAAS,IAAI,MAAM,sCAAsC,CAAC;GAC1D;EACF;EAEA,IAAI;GACF,MAAM,QAAQ,OAAO,MAAMA,KAAG,GAAG;GAEjC,MAAM,OAAoB,CAAC;GAC3B,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;IACrC,MAAM,OAAO,MAAM;IAEnB,IAAI,CAAC,MAAM;IACX,MAAM,UAAU,KAAK,KAAK;IAE1B,IAAI,CAAC,SAAS;IAEd,MAAM,QAAQ,QAAQ,MAAM,KAAK;IACjC,MAAM,KAAK,MAAM;IACjB,MAAM,KAAK,MAAM;IAEjB,IAAI,CAAC,MAAM,CAAC,IAAI;IAEhB,MAAM,OAAO,SAAS,IAAI,EAAE;IAC5B,MAAM,MAAM,SAAS,IAAI,EAAE;IAE3B,IAAI,CAAC,OAAO,MAAM,IAAI,KAAK,CAAC,OAAO,MAAM,GAAG,GAC1C,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC;GAEzB;GAEA,SAAS,MAAM,IAAI;EACrB,SAAS,OAAO;GACd,SAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;EACpE;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"wmic.mjs","names":[],"sources":["../../../../src/utils/runParallel/wmic.ts"],"sourcesContent":["import type { SpawnOptions } from 'node:child_process';\nimport * as os from 'node:os';\nimport { run } from './bin';\n\ntype ProcessList = [number, number][]; // [PPID, PID][]\ntype ProcessListCallback = (err: Error | null, list?: ProcessList) => void;\n\n/**\n * Gets the list of all the pids of the system through the wmic command.\n * @param callback Callback function with error and process list.\n */\nexport const wmic = (callback: ProcessListCallback): void => {\n const args = ['PROCESS', 'get', 'ParentProcessId,ProcessId'];\n const options: SpawnOptions = {\n windowsHide: true,\n windowsVerbatimArguments: true,\n };\n run('wmic', args, options, (err, stdout, code) => {\n if (err) {\n callback(err);\n return;\n }\n\n if (code !== 0) {\n callback(new Error(`pidtree wmic command exited with code ${code}`));\n return;\n }\n\n // Example of stdout\n //\n // ParentProcessId ProcessId\n // 0 777\n\n if (!stdout) {\n callback(new Error('No stdout received from wmic command'));\n return;\n }\n\n try {\n const lines = stdout.split(os.EOL);\n\n const list: ProcessList = [];\n for (let i = 1; i < lines.length; i++) {\n const line = lines[i];\n\n if (!line) continue;\n const trimmed = line.trim();\n\n if (!trimmed) continue;\n\n const parts = trimmed.split(/\\s+/);\n const p0 = parts[0];\n const p1 = parts[1];\n\n if (!p0 || !p1) continue;\n\n const ppid = parseInt(p0, 10); // PPID\n const pid = parseInt(p1, 10); // PID\n\n if (!Number.isNaN(ppid) && !Number.isNaN(pid)) {\n list.push([ppid, pid]);\n }\n }\n\n callback(null, list);\n } catch (error) {\n callback(error instanceof Error ? error : new Error(String(error)));\n }\n });\n};\n"],"mappings":";;;;;;;;AAWA,MAAa,QAAQ,aAAwC;CAM3D,IAAI,QAAQ;EALE;EAAW;EAAO;CAKjB,GAAG;EAHhB,aAAa;EACb,0BAA0B;CAEJ,IAAI,KAAK,QAAQ,SAAS;EAChD,IAAI,KAAK;GACP,SAAS,GAAG;GACZ;EACF;EAEA,IAAI,SAAS,GAAG;GACd,yBAAS,IAAI,MAAM,yCAAyC,MAAM,CAAC;GACnE;EACF;EAOA,IAAI,CAAC,QAAQ;GACX,yBAAS,IAAI,MAAM,sCAAsC,CAAC;GAC1D;EACF;EAEA,IAAI;GACF,MAAM,QAAQ,OAAO,MAAM,GAAG,GAAG;GAEjC,MAAM,OAAoB,CAAC;GAC3B,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;IACrC,MAAM,OAAO,MAAM;IAEnB,IAAI,CAAC,MAAM;IACX,MAAM,UAAU,KAAK,KAAK;IAE1B,IAAI,CAAC,SAAS;IAEd,MAAM,QAAQ,QAAQ,MAAM,KAAK;IACjC,MAAM,KAAK,MAAM;IACjB,MAAM,KAAK,MAAM;IAEjB,IAAI,CAAC,MAAM,CAAC,IAAI;IAEhB,MAAM,OAAO,SAAS,IAAI,EAAE;IAC5B,MAAM,MAAM,SAAS,IAAI,EAAE;IAE3B,IAAI,CAAC,OAAO,MAAM,IAAI,KAAK,CAAC,OAAO,MAAM,GAAG,GAC1C,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC;GAEzB;GAEA,SAAS,MAAM,IAAI;EACrB,SAAS,OAAO;GACd,SAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;EACpE;CACF,CAAC;AACH"}
@@ -17,10 +17,10 @@ import "./init/utils/index.js";
17
17
  import { ContentStrategy, InitOptions, getDefaultApplicationURL, initIntlayer, logInitSuccessMessage } from "./init/index.js";
18
18
  import { UpgradeIntlayerPackagesOptions, UpgradeIntlayerPackagesResult, upgradeIntlayerPackages } from "./init/upgradeIntlayerPackages.js";
19
19
  import { installLSP } from "./installLSP.js";
20
- import { PLATFORMS, PLATFORMS_METADATA, Platform, PlatformMetadata, SKILLS, SKILLS_METADATA, Skill, getInitialSkills, installSkills } from "./installSkills/index.js";
21
- import { MCPTransport, installMCP } from "./installMCP/installMCP.js";
20
+ import { PLATFORMS, PLATFORMS_METADATA, Platform, PlatformMetadata, SKILLS, SKILLS_METADATA, Skill, detectPlatform, getInitialSkills, installSkills } from "./installSkills/index.js";
21
+ import { MCPTransport, MCP_TRANSPORTS, installMCP } from "./installMCP/installMCP.js";
22
22
  import { listDictionaries, listDictionariesWithStats } from "./listDictionariesPath.js";
23
23
  import { DiffMode, ListGitFilesOptions, ListGitLinesOptions, listGitFiles, listGitLines } from "./listGitFiles.js";
24
24
  import { ListProjectsOptions, getGitRootDir, listProjects } from "./listProjects.js";
25
25
  import { logConfigDetails } from "./logConfigDetails.js";
26
- export { COMPAT_I18N_LIBRARIES, type CmsCredentials, type CompatI18nLibrary, ContentStrategy, DictionaryStatus, DiffMode, DocumentationRouter, type DocumentationRouterType, InitOptions, ListGitFilesOptions, ListGitLinesOptions, ListProjectsOptions, MCPTransport, NEXT_INTLAYER_BABEL_CONFIG_CONTENT, PLATFORMS, PLATFORMS_METADATA, type PackageManager, Platform, PlatformMetadata, type RoutingMode, SKILLS, SKILLS_METADATA, Skill, UpgradeIntlayerPackagesOptions, UpgradeIntlayerPackagesResult, detectCompatI18nLibraries, detectExportedComponentName, detectFormatCommand, detectPackageManager, enableEditorInConfig, findLockFileDir, getContentDeclarationFileTemplate, getDefaultApplicationURL, getDocumentationUrl, getGitRootDir, getInitialSkills, hasLintTooling, hasUrlRoutingFramework, initIntlayer, installLSP, installMCP, installPackages, installSkills, listDictionaries, listDictionariesWithStats, listGitFiles, listGitLines, listProjects, logConfigDetails, logInitSuccessMessage, prepareIntlayer, setupCmsCredentials, transformJSFile, upgradeIntlayerPackages, writeCmsCredentialsToEnv, writeContentDeclaration, writeJSFile };
26
+ export { COMPAT_I18N_LIBRARIES, type CmsCredentials, type CompatI18nLibrary, ContentStrategy, DictionaryStatus, DiffMode, DocumentationRouter, type DocumentationRouterType, InitOptions, ListGitFilesOptions, ListGitLinesOptions, ListProjectsOptions, MCPTransport, MCP_TRANSPORTS, NEXT_INTLAYER_BABEL_CONFIG_CONTENT, PLATFORMS, PLATFORMS_METADATA, type PackageManager, Platform, PlatformMetadata, type RoutingMode, SKILLS, SKILLS_METADATA, Skill, UpgradeIntlayerPackagesOptions, UpgradeIntlayerPackagesResult, detectCompatI18nLibraries, detectExportedComponentName, detectFormatCommand, detectPackageManager, detectPlatform, enableEditorInConfig, findLockFileDir, getContentDeclarationFileTemplate, getDefaultApplicationURL, getDocumentationUrl, getGitRootDir, getInitialSkills, hasLintTooling, hasUrlRoutingFramework, initIntlayer, installLSP, installMCP, installPackages, installSkills, listDictionaries, listDictionariesWithStats, listGitFiles, listGitLines, listProjects, logConfigDetails, logInitSuccessMessage, prepareIntlayer, setupCmsCredentials, transformJSFile, upgradeIntlayerPackages, writeCmsCredentialsToEnv, writeContentDeclaration, writeJSFile };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/init/index.ts"],"mappings":";;;;;;;;;;qBA4Ea,2BAAwB,cACrB;;;;;;;;;;YAsBJ;;;;YAQA;EACV;;EAEA;;;;;EAKA;;EAEA;;EAEA;;EAEA;;;;;;;EAOA;;EAEA;;;;;;EAMA;;;;;;EAMA,cAAc;;;;;;;EAOd;;;;;;;EAOA,kBAAkB;;;;;qBAMP,eAAY,iBAAyB,UAAY,gBAAW;;;qBAqjC5D,wBAAqB"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/init/index.ts"],"mappings":";;;;;;;;;;qBA4Ea,2BAAwB,cACrB;;;;;;;;;;YAsBJ;;;;YAQA;EACV;;EAEA;;;;;EAKA;;EAEA;;EAEA;;EAEA;;;;;;;EAOA;;EAEA;;;;;;EAMA;;;;;;EAMA,cAAc;;;;;;;EAOd;;;;;;;EAOA,kBAAkB;;;;;qBAMP,eAAY,iBAAyB,UAAY,gBAAW;;;qBA6kC5D,wBAAqB"}
@@ -132,6 +132,11 @@ export type DetectMissingPackagesOptions = {
132
132
  * The project's development dependencies (from `package.json` `devDependencies`).
133
133
  */
134
134
  devDependencies?: Record<string, string>;
135
+ /**
136
+ * Skip `eslint-plugin-intlayer`, even when the project lints. Set when the
137
+ * lint step is not part of the setup.
138
+ */
139
+ skipLintPlugin?: boolean;
135
140
  };
136
141
  /** An existing i18n library Intlayer ships a compat adapter for. */
137
142
  export type CompatI18nLibrary = {
@@ -1 +1 @@
1
- {"version":3,"file":"packageManager.d.ts","names":[],"sources":["../../../../src/init/utils/packageManager.ts"],"mappings":";;YAMY;;;;;YAMA;;;;;;;EAOV;;;;;EAKA;;;;;EAKA;;;;;;;;;;;;;;;EAeA;;;;;;;YAQU;;EAEV;;EAEA;;;;;;;;EAQA;;IAEE;;IAEA;;;;YAKQ;;EAEV;;EAEA;;EAEA;;;;;;EAMA,kBAAkB;;;;;;EAMlB,wBAAwB;;;;;;EAMxB;;;;;;;;qBASW,yBAAyB;;;;;;qBAiDzB,uBAAoB,oBAAsB;;;;;;qBAY1C,kBAAe;;;;;;;YA2ChB;;;;;;EAMV;;;;;;EAMA,eAAe;;;;EAIf,kBAAkB;;;YAIR;;EAEV;;;;;;EAMA;;;;;EAKA,cAAc;;;;;;;;qBASH,gCAAgC;;;;;qBA+GhC,6BAA6B;;;;;;;;qBAc7B,sCAAmC,aACjC;;;;;;;;;;qBA8BF,4BAAyB,cACtB;;qBAOH;;;;;;;;;qBAUA,kBAAe,cACZ;;;;;;;;;;;qBAiBH,iBAAc,cAAkB;qBAIhC,gCAA6B,iBACvB,wBAAsB,UAC9B,iCACR;;;;;qBAyZU,kBAAe,iBACX,oBACG,gBACF,gBAAc;;;;;;;;;;qBAgBnB,wBAAqB;;;;;;;;qBAarB,mBAAgB;;;;;;qBAahB,oBAAiB,iBACb,gBACC"}
1
+ {"version":3,"file":"packageManager.d.ts","names":[],"sources":["../../../../src/init/utils/packageManager.ts"],"mappings":";;YAMY;;;;;YAMA;;;;;;;EAOV;;;;;EAKA;;;;;EAKA;;;;;;;;;;;;;;;EAeA;;;;;;;YAQU;;EAEV;;EAEA;;;;;;;;EAQA;;IAEE;;IAEA;;;;YAKQ;;EAEV;;EAEA;;EAEA;;;;;;EAMA,kBAAkB;;;;;;EAMlB,wBAAwB;;;;;;EAMxB;;;;;;;;qBASW,yBAAyB;;;;;;qBAiDzB,uBAAoB,oBAAsB;;;;;;qBAY1C,kBAAe;;;;;;;YA2ChB;;;;;;EAMV;;;;;;EAMA,eAAe;;;;EAIf,kBAAkB;;;;;EAKlB;;;YAIU;;EAEV;;;;;;EAMA;;;;;EAKA,cAAc;;;;;;;;qBASH,gCAAgC;;;;;qBA+GhC,6BAA6B;;;;;;;;qBAc7B,sCAAmC,aACjC;;;;;;;;;;qBA8BF,4BAAyB,cACtB;;qBAOH;;;;;;;;;qBAUA,kBAAe,cACZ;;;;;;;;;;;qBAiBH,iBAAc,cAAkB;qBAIhC,gCAA6B,iBACvB,wBAAsB,UAC9B,iCACR;;;;;qBAyZU,kBAAe,iBACX,oBACG,gBACF,gBAAc;;;;;;;;;;qBAgBnB,wBAAqB;;;;;;;;qBAarB,mBAAgB;;;;;;qBAahB,oBAAiB,iBACb,gBACC"}
@@ -1,8 +1,12 @@
1
1
  import { Platform } from "../installSkills/index.js";
2
2
  //#region src/installMCP/installMCP.d.ts
3
3
  export type MCPTransport = 'stdio' | 'sse';
4
+ /** Transports accepted by `intlayer init mcp --transport`. */
5
+ export declare const MCP_TRANSPORTS: MCPTransport[];
4
6
  /**
5
7
  * Installs the Intlayer MCP server configuration for a specific platform.
8
+ * Every platform is configured at the project level (Claude Code included,
9
+ * through `.mcp.json`), so nothing outside the project is modified.
6
10
  */
7
11
  export declare const installMCP: (projectRoot: string, platform: Platform, transport: MCPTransport) => Promise<string>;
8
12
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"installMCP.d.ts","names":[],"sources":["../../../src/installMCP/installMCP.ts"],"mappings":";;YAKY;;;;qBAsBC,aAAU,qBACF,UACT,UAAQ,WACP,iBACV"}
1
+ {"version":3,"file":"installMCP.d.ts","names":[],"sources":["../../../src/installMCP/installMCP.ts"],"mappings":";;YAIY;;qBAGC,gBAAgB;;;;;;qBA4DhB,aAAU,qBACF,UACT,UAAQ,WACP,iBACV"}
@@ -46,6 +46,12 @@ export interface PlatformMetadata {
46
46
  export declare const PLATFORMS_METADATA: Record<string, PlatformMetadata>;
47
47
  export type Platform = keyof typeof PLATFORMS_METADATA;
48
48
  export declare const PLATFORMS: Platform[];
49
+ /**
50
+ * Detects the AI platform in use. The environment of the running tool wins;
51
+ * otherwise the first platform whose config folder (`.claude`, `.cursor`…)
52
+ * exists in the project root is returned.
53
+ */
54
+ export declare const detectPlatform: (projectRoot: string) => Platform | undefined;
49
55
  /**
50
56
  * Installs skills using the "Agent Skills" directory standard.
51
57
  * Standard: <PROJECT_ROOT>/<CONFIG_DIR>/skills/<SKILL_NAME>/SKILL.md
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/installSkills/index.ts"],"mappings":";;;;qBASa;WACX;WACA;WACA;WAEA;WACA;WACA;WAEA;WAEA;WACA;WACA;WAEA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;;YAIU,qBAAqB;qBAEpB,QAAyC;;;;;;;qBAqFzC,mBAAgB,cACb,2BACb;iBAUc;EACf;EACA;EACA;;;;;qBAMW,oBAAoB,eAAe;YA6JpC,wBAAwB;qBAEvB,WAA+C;;;;;qBA8G/C,gBAAa,qBACL,UACT,UAAQ,QACV,YACP"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/installSkills/index.ts"],"mappings":";;;;qBASa;WACX;WACA;WACA;WAEA;WACA;WACA;WAEA;WAEA;WACA;WACA;WAEA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;;YAIU,qBAAqB;qBAEpB,QAAyC;;;;;;;qBAqFzC,mBAAgB,cACb,2BACb;iBAUc;EACf;EACA;EACA;;;;;qBAMW,oBAAoB,eAAe;YA8JpC,wBAAwB;qBAEvB,WAA+C;;;;;;qBA4B/C,iBAAc,wBAA0B;;;;;qBAuHxC,gBAAa,qBACL,UACT,UAAQ,QACV,YACP"}