@yuaone/core 0.1.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 (235) hide show
  1. package/LICENSE +663 -0
  2. package/README.md +15 -0
  3. package/dist/__tests__/context-manager.test.d.ts +6 -0
  4. package/dist/__tests__/context-manager.test.d.ts.map +1 -0
  5. package/dist/__tests__/context-manager.test.js +220 -0
  6. package/dist/__tests__/context-manager.test.js.map +1 -0
  7. package/dist/__tests__/governor.test.d.ts +6 -0
  8. package/dist/__tests__/governor.test.d.ts.map +1 -0
  9. package/dist/__tests__/governor.test.js +210 -0
  10. package/dist/__tests__/governor.test.js.map +1 -0
  11. package/dist/__tests__/model-router.test.d.ts +6 -0
  12. package/dist/__tests__/model-router.test.d.ts.map +1 -0
  13. package/dist/__tests__/model-router.test.js +329 -0
  14. package/dist/__tests__/model-router.test.js.map +1 -0
  15. package/dist/agent-logger.d.ts +384 -0
  16. package/dist/agent-logger.d.ts.map +1 -0
  17. package/dist/agent-logger.js +820 -0
  18. package/dist/agent-logger.js.map +1 -0
  19. package/dist/agent-loop.d.ts +163 -0
  20. package/dist/agent-loop.d.ts.map +1 -0
  21. package/dist/agent-loop.js +609 -0
  22. package/dist/agent-loop.js.map +1 -0
  23. package/dist/agent-modes.d.ts +85 -0
  24. package/dist/agent-modes.d.ts.map +1 -0
  25. package/dist/agent-modes.js +418 -0
  26. package/dist/agent-modes.js.map +1 -0
  27. package/dist/approval.d.ts +137 -0
  28. package/dist/approval.d.ts.map +1 -0
  29. package/dist/approval.js +299 -0
  30. package/dist/approval.js.map +1 -0
  31. package/dist/async-completion-queue.d.ts +56 -0
  32. package/dist/async-completion-queue.d.ts.map +1 -0
  33. package/dist/async-completion-queue.js +77 -0
  34. package/dist/async-completion-queue.js.map +1 -0
  35. package/dist/auto-fix.d.ts +174 -0
  36. package/dist/auto-fix.d.ts.map +1 -0
  37. package/dist/auto-fix.js +319 -0
  38. package/dist/auto-fix.js.map +1 -0
  39. package/dist/codebase-context.d.ts +396 -0
  40. package/dist/codebase-context.d.ts.map +1 -0
  41. package/dist/codebase-context.js +1260 -0
  42. package/dist/codebase-context.js.map +1 -0
  43. package/dist/conflict-resolver.d.ts +191 -0
  44. package/dist/conflict-resolver.d.ts.map +1 -0
  45. package/dist/conflict-resolver.js +524 -0
  46. package/dist/conflict-resolver.js.map +1 -0
  47. package/dist/constants.d.ts +52 -0
  48. package/dist/constants.d.ts.map +1 -0
  49. package/dist/constants.js +141 -0
  50. package/dist/constants.js.map +1 -0
  51. package/dist/context-budget.d.ts +435 -0
  52. package/dist/context-budget.d.ts.map +1 -0
  53. package/dist/context-budget.js +903 -0
  54. package/dist/context-budget.js.map +1 -0
  55. package/dist/context-compressor.d.ts +143 -0
  56. package/dist/context-compressor.d.ts.map +1 -0
  57. package/dist/context-compressor.js +511 -0
  58. package/dist/context-compressor.js.map +1 -0
  59. package/dist/context-manager.d.ts +112 -0
  60. package/dist/context-manager.d.ts.map +1 -0
  61. package/dist/context-manager.js +247 -0
  62. package/dist/context-manager.js.map +1 -0
  63. package/dist/continuous-reflection.d.ts +267 -0
  64. package/dist/continuous-reflection.d.ts.map +1 -0
  65. package/dist/continuous-reflection.js +338 -0
  66. package/dist/continuous-reflection.js.map +1 -0
  67. package/dist/cross-file-refactor.d.ts +352 -0
  68. package/dist/cross-file-refactor.d.ts.map +1 -0
  69. package/dist/cross-file-refactor.js +1544 -0
  70. package/dist/cross-file-refactor.js.map +1 -0
  71. package/dist/dag-orchestrator.d.ts +138 -0
  72. package/dist/dag-orchestrator.d.ts.map +1 -0
  73. package/dist/dag-orchestrator.js +379 -0
  74. package/dist/dag-orchestrator.js.map +1 -0
  75. package/dist/debate-orchestrator.d.ts +301 -0
  76. package/dist/debate-orchestrator.d.ts.map +1 -0
  77. package/dist/debate-orchestrator.js +719 -0
  78. package/dist/debate-orchestrator.js.map +1 -0
  79. package/dist/dependency-analyzer.d.ts +113 -0
  80. package/dist/dependency-analyzer.d.ts.map +1 -0
  81. package/dist/dependency-analyzer.js +444 -0
  82. package/dist/dependency-analyzer.js.map +1 -0
  83. package/dist/design-loop.d.ts +59 -0
  84. package/dist/design-loop.d.ts.map +1 -0
  85. package/dist/design-loop.js +344 -0
  86. package/dist/design-loop.js.map +1 -0
  87. package/dist/doc-intelligence.d.ts +383 -0
  88. package/dist/doc-intelligence.d.ts.map +1 -0
  89. package/dist/doc-intelligence.js +1307 -0
  90. package/dist/doc-intelligence.js.map +1 -0
  91. package/dist/dynamic-role-generator.d.ts +76 -0
  92. package/dist/dynamic-role-generator.d.ts.map +1 -0
  93. package/dist/dynamic-role-generator.js +194 -0
  94. package/dist/dynamic-role-generator.js.map +1 -0
  95. package/dist/errors.d.ts +69 -0
  96. package/dist/errors.d.ts.map +1 -0
  97. package/dist/errors.js +102 -0
  98. package/dist/errors.js.map +1 -0
  99. package/dist/event-bus.d.ts +159 -0
  100. package/dist/event-bus.d.ts.map +1 -0
  101. package/dist/event-bus.js +305 -0
  102. package/dist/event-bus.js.map +1 -0
  103. package/dist/execution-engine.d.ts +425 -0
  104. package/dist/execution-engine.d.ts.map +1 -0
  105. package/dist/execution-engine.js +1555 -0
  106. package/dist/execution-engine.js.map +1 -0
  107. package/dist/git-intelligence.d.ts +306 -0
  108. package/dist/git-intelligence.d.ts.map +1 -0
  109. package/dist/git-intelligence.js +1099 -0
  110. package/dist/git-intelligence.js.map +1 -0
  111. package/dist/governor.d.ts +77 -0
  112. package/dist/governor.d.ts.map +1 -0
  113. package/dist/governor.js +161 -0
  114. package/dist/governor.js.map +1 -0
  115. package/dist/hierarchical-planner.d.ts +313 -0
  116. package/dist/hierarchical-planner.d.ts.map +1 -0
  117. package/dist/hierarchical-planner.js +981 -0
  118. package/dist/hierarchical-planner.js.map +1 -0
  119. package/dist/index.d.ts +121 -0
  120. package/dist/index.d.ts.map +1 -0
  121. package/dist/index.js +123 -0
  122. package/dist/index.js.map +1 -0
  123. package/dist/intent-inference.d.ts +103 -0
  124. package/dist/intent-inference.d.ts.map +1 -0
  125. package/dist/intent-inference.js +605 -0
  126. package/dist/intent-inference.js.map +1 -0
  127. package/dist/interrupt-manager.d.ts +143 -0
  128. package/dist/interrupt-manager.d.ts.map +1 -0
  129. package/dist/interrupt-manager.js +196 -0
  130. package/dist/interrupt-manager.js.map +1 -0
  131. package/dist/kernel.d.ts +564 -0
  132. package/dist/kernel.d.ts.map +1 -0
  133. package/dist/kernel.js +1419 -0
  134. package/dist/kernel.js.map +1 -0
  135. package/dist/language-support.d.ts +232 -0
  136. package/dist/language-support.d.ts.map +1 -0
  137. package/dist/language-support.js +1134 -0
  138. package/dist/language-support.js.map +1 -0
  139. package/dist/llm-client.d.ts +82 -0
  140. package/dist/llm-client.d.ts.map +1 -0
  141. package/dist/llm-client.js +475 -0
  142. package/dist/llm-client.js.map +1 -0
  143. package/dist/mcp-client.d.ts +232 -0
  144. package/dist/mcp-client.d.ts.map +1 -0
  145. package/dist/mcp-client.js +718 -0
  146. package/dist/mcp-client.js.map +1 -0
  147. package/dist/memory-manager.d.ts +200 -0
  148. package/dist/memory-manager.d.ts.map +1 -0
  149. package/dist/memory-manager.js +568 -0
  150. package/dist/memory-manager.js.map +1 -0
  151. package/dist/memory.d.ts +87 -0
  152. package/dist/memory.d.ts.map +1 -0
  153. package/dist/memory.js +341 -0
  154. package/dist/memory.js.map +1 -0
  155. package/dist/model-router.d.ts +245 -0
  156. package/dist/model-router.d.ts.map +1 -0
  157. package/dist/model-router.js +632 -0
  158. package/dist/model-router.js.map +1 -0
  159. package/dist/parallel-executor.d.ts +125 -0
  160. package/dist/parallel-executor.d.ts.map +1 -0
  161. package/dist/parallel-executor.js +201 -0
  162. package/dist/parallel-executor.js.map +1 -0
  163. package/dist/perf-optimizer.d.ts +212 -0
  164. package/dist/perf-optimizer.d.ts.map +1 -0
  165. package/dist/perf-optimizer.js +721 -0
  166. package/dist/perf-optimizer.js.map +1 -0
  167. package/dist/persona.d.ts +305 -0
  168. package/dist/persona.d.ts.map +1 -0
  169. package/dist/persona.js +887 -0
  170. package/dist/persona.js.map +1 -0
  171. package/dist/planner.d.ts +70 -0
  172. package/dist/planner.d.ts.map +1 -0
  173. package/dist/planner.js +264 -0
  174. package/dist/planner.js.map +1 -0
  175. package/dist/qa-pipeline.d.ts +365 -0
  176. package/dist/qa-pipeline.d.ts.map +1 -0
  177. package/dist/qa-pipeline.js +1352 -0
  178. package/dist/qa-pipeline.js.map +1 -0
  179. package/dist/reasoning-adapter.d.ts +116 -0
  180. package/dist/reasoning-adapter.d.ts.map +1 -0
  181. package/dist/reasoning-adapter.js +187 -0
  182. package/dist/reasoning-adapter.js.map +1 -0
  183. package/dist/role-registry.d.ts +55 -0
  184. package/dist/role-registry.d.ts.map +1 -0
  185. package/dist/role-registry.js +192 -0
  186. package/dist/role-registry.js.map +1 -0
  187. package/dist/sandbox-tiers.d.ts +327 -0
  188. package/dist/sandbox-tiers.d.ts.map +1 -0
  189. package/dist/sandbox-tiers.js +928 -0
  190. package/dist/sandbox-tiers.js.map +1 -0
  191. package/dist/security-scanner.d.ts +222 -0
  192. package/dist/security-scanner.d.ts.map +1 -0
  193. package/dist/security-scanner.js +1129 -0
  194. package/dist/security-scanner.js.map +1 -0
  195. package/dist/security.d.ts +93 -0
  196. package/dist/security.d.ts.map +1 -0
  197. package/dist/security.js +393 -0
  198. package/dist/security.js.map +1 -0
  199. package/dist/self-reflection.d.ts +397 -0
  200. package/dist/self-reflection.d.ts.map +1 -0
  201. package/dist/self-reflection.js +908 -0
  202. package/dist/self-reflection.js.map +1 -0
  203. package/dist/session-persistence.d.ts +191 -0
  204. package/dist/session-persistence.d.ts.map +1 -0
  205. package/dist/session-persistence.js +395 -0
  206. package/dist/session-persistence.js.map +1 -0
  207. package/dist/speculative-executor.d.ts +210 -0
  208. package/dist/speculative-executor.d.ts.map +1 -0
  209. package/dist/speculative-executor.js +618 -0
  210. package/dist/speculative-executor.js.map +1 -0
  211. package/dist/state-machine.d.ts +289 -0
  212. package/dist/state-machine.d.ts.map +1 -0
  213. package/dist/state-machine.js +695 -0
  214. package/dist/state-machine.js.map +1 -0
  215. package/dist/sub-agent.d.ts +177 -0
  216. package/dist/sub-agent.d.ts.map +1 -0
  217. package/dist/sub-agent.js +303 -0
  218. package/dist/sub-agent.js.map +1 -0
  219. package/dist/system-prompt.d.ts +26 -0
  220. package/dist/system-prompt.d.ts.map +1 -0
  221. package/dist/system-prompt.js +84 -0
  222. package/dist/system-prompt.js.map +1 -0
  223. package/dist/test-intelligence.d.ts +439 -0
  224. package/dist/test-intelligence.d.ts.map +1 -0
  225. package/dist/test-intelligence.js +1165 -0
  226. package/dist/test-intelligence.js.map +1 -0
  227. package/dist/types.d.ts +632 -0
  228. package/dist/types.d.ts.map +1 -0
  229. package/dist/types.js +6 -0
  230. package/dist/types.js.map +1 -0
  231. package/dist/vector-index.d.ts +314 -0
  232. package/dist/vector-index.d.ts.map +1 -0
  233. package/dist/vector-index.js +618 -0
  234. package/dist/vector-index.js.map +1 -0
  235. package/package.json +41 -0
@@ -0,0 +1,1134 @@
1
+ /**
2
+ * @module language-support
3
+ * @description Multi-language intelligence for the YUAN coding agent.
4
+ * Provides language detection, parsing patterns, tool configuration,
5
+ * code generation hints, and project type detection for 14+ languages.
6
+ */
7
+ import { extname, basename } from "node:path";
8
+ // ─── Built-in Language Configs ───
9
+ const TYPESCRIPT_CONFIG = {
10
+ name: "typescript",
11
+ displayName: "TypeScript",
12
+ extensions: ["ts", "tsx", "mts", "cts"],
13
+ patterns: {
14
+ function: /(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*(?:<[^>]*>)?\s*\(([^)]*)\)(?:\s*:\s*([^{]+))?\s*\{/g,
15
+ class: /(?:export\s+)?(?:abstract\s+)?class\s+(\w+)(?:\s+extends\s+\w+)?(?:\s+implements\s+[\w,\s]+)?\s*\{/g,
16
+ interface: /(?:export\s+)?interface\s+(\w+)(?:\s+extends\s+[\w,\s]+)?\s*\{/g,
17
+ import: /import\s+(?:(?:type\s+)?(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)(?:\s*,\s*(?:\{[^}]*\}|\*\s+as\s+\w+|\w+))*\s+from\s+)?['"]([^'"]+)['"]/g,
18
+ export: /export\s+(?:default\s+)?(?:type\s+)?(?:(?:async\s+)?function|class|interface|type|enum|const|let|var)\s+(\w+)/g,
19
+ singleLineComment: /\/\/.*/g,
20
+ multiLineComment: { start: /\/\*/g, end: /\*\//g },
21
+ docComment: /\/\*\*[\s\S]*?\*\//g,
22
+ stringLiteral: /(?:`(?:[^`\\]|\\.)*`|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/g,
23
+ },
24
+ buildCommands: ["tsc", "npm run build", "pnpm run build"],
25
+ testCommands: ["jest", "vitest", "npm test", "pnpm test"],
26
+ lintCommands: ["eslint .", "biome check .", "tsc --noEmit"],
27
+ packageFiles: ["package.json", "tsconfig.json"],
28
+ lockFiles: [
29
+ "package-lock.json",
30
+ "pnpm-lock.yaml",
31
+ "yarn.lock",
32
+ "bun.lockb",
33
+ ],
34
+ namingConvention: "camelCase",
35
+ fileNaming: "kebab-case",
36
+ importStyle: "mixed",
37
+ docCommentPrefix: "/**",
38
+ docCommentStyle: "jsdoc",
39
+ };
40
+ const JAVASCRIPT_CONFIG = {
41
+ name: "javascript",
42
+ displayName: "JavaScript",
43
+ extensions: ["js", "jsx", "mjs", "cjs"],
44
+ shebangs: ["node", "nodejs"],
45
+ patterns: {
46
+ function: /(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)\s*\{/g,
47
+ class: /(?:export\s+)?class\s+(\w+)(?:\s+extends\s+\w+)?\s*\{/g,
48
+ import: /import\s+(?:(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)(?:\s*,\s*(?:\{[^}]*\}|\*\s+as\s+\w+|\w+))*\s+from\s+)?['"]([^'"]+)['"]/g,
49
+ export: /export\s+(?:default\s+)?(?:(?:async\s+)?function|class|const|let|var)\s+(\w+)/g,
50
+ singleLineComment: /\/\/.*/g,
51
+ multiLineComment: { start: /\/\*/g, end: /\*\//g },
52
+ docComment: /\/\*\*[\s\S]*?\*\//g,
53
+ stringLiteral: /(?:`(?:[^`\\]|\\.)*`|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/g,
54
+ },
55
+ buildCommands: ["npm run build", "pnpm run build"],
56
+ testCommands: ["jest", "vitest", "mocha", "npm test"],
57
+ lintCommands: ["eslint .", "biome check ."],
58
+ packageFiles: ["package.json"],
59
+ lockFiles: [
60
+ "package-lock.json",
61
+ "pnpm-lock.yaml",
62
+ "yarn.lock",
63
+ "bun.lockb",
64
+ ],
65
+ namingConvention: "camelCase",
66
+ fileNaming: "kebab-case",
67
+ importStyle: "mixed",
68
+ docCommentPrefix: "/**",
69
+ docCommentStyle: "jsdoc",
70
+ };
71
+ const PYTHON_CONFIG = {
72
+ name: "python",
73
+ displayName: "Python",
74
+ extensions: ["py", "pyi", "pyw"],
75
+ shebangs: ["python", "python3"],
76
+ patterns: {
77
+ function: /(?:async\s+)?def\s+(\w+)\s*\(([^)]*)\)(?:\s*->\s*([^\s:]+))?\s*:/g,
78
+ class: /class\s+(\w+)(?:\(([^)]*)\))?\s*:/g,
79
+ interface: /class\s+(\w+)\((?:Protocol|ABC)\):/g,
80
+ import: /(?:from\s+([\w.]+)\s+import\s+(?:\([\s\S]*?\)|[^;\n]+)|import\s+([\w.,\s]+))/g,
81
+ singleLineComment: /#.*/g,
82
+ multiLineComment: { start: /"""/g, end: /"""/g },
83
+ docComment: /"""[\s\S]*?"""/g,
84
+ stringLiteral: /(?:f?r?"""[\s\S]*?"""|f?r?'''[\s\S]*?'''|f?r?"(?:[^"\\]|\\.)*"|f?r?'(?:[^'\\]|\\.)*')/g,
85
+ },
86
+ buildCommands: ["python -m build", "pip install -e ."],
87
+ testCommands: ["pytest", "python -m pytest", "python -m unittest"],
88
+ lintCommands: ["ruff check .", "flake8", "mypy .", "pylint"],
89
+ packageFiles: [
90
+ "pyproject.toml",
91
+ "setup.py",
92
+ "setup.cfg",
93
+ "requirements.txt",
94
+ ],
95
+ lockFiles: ["poetry.lock", "Pipfile.lock", "requirements.lock"],
96
+ namingConvention: "snake_case",
97
+ fileNaming: "snake_case",
98
+ importStyle: "absolute",
99
+ docCommentPrefix: '"""',
100
+ docCommentStyle: "pydoc",
101
+ };
102
+ const GO_CONFIG = {
103
+ name: "go",
104
+ displayName: "Go",
105
+ extensions: ["go"],
106
+ patterns: {
107
+ function: /func\s+(?:\(\s*\w+\s+\*?\w+\s*\)\s+)?(\w+)\s*\(([^)]*)\)(?:\s*(?:\(([^)]+)\)|(\w+)))?\s*\{/g,
108
+ class: /type\s+(\w+)\s+struct\s*\{/g,
109
+ interface: /type\s+(\w+)\s+interface\s*\{/g,
110
+ import: /import\s+(?:\(\s*([\s\S]*?)\s*\)|"([^"]+)")/g,
111
+ singleLineComment: /\/\/.*/g,
112
+ multiLineComment: { start: /\/\*/g, end: /\*\//g },
113
+ docComment: /\/\/\s*\w[\s\S]*?(?=\nfunc|\ntype|\nvar|\nconst)/g,
114
+ stringLiteral: /(?:`[^`]*`|"(?:[^"\\]|\\.)*")/g,
115
+ },
116
+ buildCommands: ["go build ./..."],
117
+ testCommands: ["go test ./..."],
118
+ lintCommands: ["golangci-lint run", "go vet ./..."],
119
+ packageFiles: ["go.mod"],
120
+ lockFiles: ["go.sum"],
121
+ namingConvention: "camelCase",
122
+ fileNaming: "snake_case",
123
+ importStyle: "package",
124
+ docCommentPrefix: "//",
125
+ docCommentStyle: "godoc",
126
+ };
127
+ const RUST_CONFIG = {
128
+ name: "rust",
129
+ displayName: "Rust",
130
+ extensions: ["rs"],
131
+ patterns: {
132
+ function: /(?:pub(?:\(crate\))?\s+)?(?:async\s+)?fn\s+(\w+)\s*(?:<[^>]*>)?\s*\(([^)]*)\)(?:\s*->\s*([^\s{]+))?\s*(?:where\s+[^{]*)?\{/g,
133
+ class: /(?:pub(?:\(crate\))?\s+)?struct\s+(\w+)(?:<[^>]*>)?/g,
134
+ interface: /(?:pub(?:\(crate\))?\s+)?trait\s+(\w+)(?:<[^>]*>)?/g,
135
+ import: /use\s+([\w:]+(?:::\{[^}]+\}|::\*)?)\s*;/g,
136
+ export: /pub\s+(?:(?:async\s+)?fn|struct|trait|enum|type|const|mod)\s+(\w+)/g,
137
+ singleLineComment: /\/\/.*/g,
138
+ multiLineComment: { start: /\/\*/g, end: /\*\//g },
139
+ docComment: /\/\/\/.*(?:\n\/\/\/.*)*/g,
140
+ stringLiteral: /(?:r#*"[\s\S]*?"#*|"(?:[^"\\]|\\.)*")/g,
141
+ },
142
+ buildCommands: ["cargo build"],
143
+ testCommands: ["cargo test"],
144
+ lintCommands: ["cargo clippy", "cargo check"],
145
+ packageFiles: ["Cargo.toml"],
146
+ lockFiles: ["Cargo.lock"],
147
+ namingConvention: "snake_case",
148
+ fileNaming: "snake_case",
149
+ importStyle: "absolute",
150
+ docCommentPrefix: "///",
151
+ docCommentStyle: "rustdoc",
152
+ };
153
+ const JAVA_CONFIG = {
154
+ name: "java",
155
+ displayName: "Java",
156
+ extensions: ["java"],
157
+ patterns: {
158
+ function: /(?:(?:public|private|protected)\s+)?(?:static\s+)?(?:synchronized\s+)?(?:[\w<>\[\],\s]+)\s+(\w+)\s*\(([^)]*)\)(?:\s+throws\s+[\w,\s]+)?\s*\{/g,
159
+ class: /(?:(?:public|private|protected)\s+)?(?:abstract\s+)?(?:final\s+)?class\s+(\w+)(?:<[^>]*>)?(?:\s+extends\s+\w+)?(?:\s+implements\s+[\w,\s]+)?\s*\{/g,
160
+ interface: /(?:public\s+)?interface\s+(\w+)(?:<[^>]*>)?(?:\s+extends\s+[\w,\s]+)?\s*\{/g,
161
+ import: /import\s+(?:static\s+)?([\w.*]+)\s*;/g,
162
+ singleLineComment: /\/\/.*/g,
163
+ multiLineComment: { start: /\/\*/g, end: /\*\//g },
164
+ docComment: /\/\*\*[\s\S]*?\*\//g,
165
+ stringLiteral: /(?:"""[\s\S]*?"""|"(?:[^"\\]|\\.)*")/g,
166
+ },
167
+ buildCommands: ["mvn compile", "gradle build", "javac"],
168
+ testCommands: ["mvn test", "gradle test"],
169
+ lintCommands: ["checkstyle", "spotbugs"],
170
+ packageFiles: ["pom.xml", "build.gradle", "build.gradle.kts"],
171
+ lockFiles: ["gradle.lockfile"],
172
+ namingConvention: "camelCase",
173
+ fileNaming: "PascalCase",
174
+ importStyle: "absolute",
175
+ docCommentPrefix: "/**",
176
+ docCommentStyle: "javadoc",
177
+ };
178
+ const C_CONFIG = {
179
+ name: "c",
180
+ displayName: "C",
181
+ extensions: ["c", "h"],
182
+ patterns: {
183
+ function: /(?:(?:static|extern|inline)\s+)?(?:[\w*]+\s+)+(\w+)\s*\(([^)]*)\)\s*\{/g,
184
+ class: /(?:typedef\s+)?struct\s+(\w+)\s*\{/g,
185
+ import: /#include\s+[<"]([^>"]+)[>"]/g,
186
+ singleLineComment: /\/\/.*/g,
187
+ multiLineComment: { start: /\/\*/g, end: /\*\//g },
188
+ docComment: /\/\*\*[\s\S]*?\*\//g,
189
+ stringLiteral: /"(?:[^"\\]|\\.)*"/g,
190
+ },
191
+ buildCommands: ["make", "cmake --build .", "gcc"],
192
+ testCommands: ["make test", "ctest"],
193
+ lintCommands: ["cppcheck", "clang-tidy"],
194
+ packageFiles: ["CMakeLists.txt", "Makefile", "meson.build"],
195
+ lockFiles: [],
196
+ namingConvention: "snake_case",
197
+ fileNaming: "snake_case",
198
+ importStyle: "relative",
199
+ docCommentPrefix: "/**",
200
+ docCommentStyle: "javadoc",
201
+ };
202
+ const CPP_CONFIG = {
203
+ name: "cpp",
204
+ displayName: "C++",
205
+ extensions: ["cpp", "cc", "cxx", "hpp", "hh", "hxx"],
206
+ patterns: {
207
+ function: /(?:(?:virtual|static|inline|explicit|constexpr)\s+)*(?:[\w:*&<>,\s]+)\s+(\w+)\s*\(([^)]*)\)(?:\s*(?:const|noexcept|override|final|\s)+)*\s*\{/g,
208
+ class: /(?:template\s*<[^>]*>\s*)?class\s+(\w+)(?:\s*:\s*(?:public|private|protected)\s+[\w:]+(?:\s*,\s*(?:public|private|protected)\s+[\w:]+)*)?\s*\{/g,
209
+ import: /#include\s+[<"]([^>"]+)[>"]/g,
210
+ singleLineComment: /\/\/.*/g,
211
+ multiLineComment: { start: /\/\*/g, end: /\*\//g },
212
+ docComment: /\/\*\*[\s\S]*?\*\//g,
213
+ stringLiteral: /(?:R"([^(]*)\([\s\S]*?\)\1"|"(?:[^"\\]|\\.)*")/g,
214
+ },
215
+ buildCommands: ["make", "cmake --build .", "g++", "clang++"],
216
+ testCommands: ["make test", "ctest"],
217
+ lintCommands: ["cppcheck", "clang-tidy", "cpplint"],
218
+ packageFiles: [
219
+ "CMakeLists.txt",
220
+ "Makefile",
221
+ "meson.build",
222
+ "conanfile.txt",
223
+ "vcpkg.json",
224
+ ],
225
+ lockFiles: ["conan.lock"],
226
+ namingConvention: "camelCase",
227
+ fileNaming: "snake_case",
228
+ importStyle: "mixed",
229
+ docCommentPrefix: "/**",
230
+ docCommentStyle: "javadoc",
231
+ };
232
+ const RUBY_CONFIG = {
233
+ name: "ruby",
234
+ displayName: "Ruby",
235
+ extensions: ["rb", "rake", "gemspec"],
236
+ shebangs: ["ruby"],
237
+ patterns: {
238
+ function: /def\s+(self\.)?(\w+[?!=]?)\s*(?:\(([^)]*)\))?/g,
239
+ class: /class\s+([\w:]+)(?:\s*<\s*([\w:]+))?/g,
240
+ interface: /module\s+([\w:]+)/g,
241
+ import: /require(?:_relative)?\s+['"]([^'"]+)['"]/g,
242
+ singleLineComment: /#.*/g,
243
+ multiLineComment: { start: /=begin/g, end: /=end/g },
244
+ docComment: /##.*(?:\n#.*)*/g,
245
+ stringLiteral: /(?:%[qQwWiI]?(?:\{[^}]*\}|\([^)]*\)|\[[^\]]*\]|<[^>]*>|([^\w\s])[\s\S]*?\1)|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/g,
246
+ },
247
+ buildCommands: ["bundle exec rake build", "gem build"],
248
+ testCommands: ["bundle exec rspec", "bundle exec rake test", "ruby -Itest"],
249
+ lintCommands: ["rubocop", "bundle exec rubocop"],
250
+ packageFiles: ["Gemfile", "*.gemspec"],
251
+ lockFiles: ["Gemfile.lock"],
252
+ namingConvention: "snake_case",
253
+ fileNaming: "snake_case",
254
+ importStyle: "absolute",
255
+ docCommentPrefix: "#",
256
+ docCommentStyle: "none",
257
+ };
258
+ const PHP_CONFIG = {
259
+ name: "php",
260
+ displayName: "PHP",
261
+ extensions: ["php", "phtml"],
262
+ shebangs: ["php"],
263
+ patterns: {
264
+ function: /(?:(?:public|private|protected|static)\s+)*function\s+(\w+)\s*\(([^)]*)\)(?:\s*:\s*\??([\w|]+))?\s*\{/g,
265
+ class: /(?:(?:abstract|final)\s+)?class\s+(\w+)(?:\s+extends\s+\w+)?(?:\s+implements\s+[\w,\s]+)?\s*\{/g,
266
+ interface: /interface\s+(\w+)(?:\s+extends\s+[\w,\s]+)?\s*\{/g,
267
+ import: /(?:use\s+([\w\\]+)(?:\s+as\s+\w+)?;|require(?:_once)?\s+['"]([^'"]+)['"])/g,
268
+ singleLineComment: /(?:\/\/|#).*/g,
269
+ multiLineComment: { start: /\/\*/g, end: /\*\//g },
270
+ docComment: /\/\*\*[\s\S]*?\*\//g,
271
+ stringLiteral: /(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/g,
272
+ },
273
+ buildCommands: ["composer install"],
274
+ testCommands: ["phpunit", "./vendor/bin/phpunit"],
275
+ lintCommands: ["phpstan", "phpcs", "php-cs-fixer fix --dry-run"],
276
+ packageFiles: ["composer.json"],
277
+ lockFiles: ["composer.lock"],
278
+ namingConvention: "camelCase",
279
+ fileNaming: "PascalCase",
280
+ importStyle: "absolute",
281
+ docCommentPrefix: "/**",
282
+ docCommentStyle: "javadoc",
283
+ };
284
+ const SWIFT_CONFIG = {
285
+ name: "swift",
286
+ displayName: "Swift",
287
+ extensions: ["swift"],
288
+ patterns: {
289
+ function: /(?:(?:public|private|internal|fileprivate|open)\s+)?(?:(?:static|class|mutating|override)\s+)?func\s+(\w+)\s*(?:<[^>]*>)?\s*\(([^)]*)\)(?:\s*(?:throws|rethrows)\s*)?(?:\s*->\s*([^\s{]+))?\s*\{/g,
290
+ class: /(?:(?:public|private|internal|fileprivate|open)\s+)?(?:final\s+)?class\s+(\w+)(?:<[^>]*>)?(?:\s*:\s*[\w,\s]+)?\s*\{/g,
291
+ interface: /(?:(?:public|private|internal)\s+)?protocol\s+(\w+)(?:\s*:\s*[\w,\s]+)?\s*\{/g,
292
+ import: /import\s+(?:(?:typealias|struct|class|enum|protocol|let|var|func)\s+)?(\w+)/g,
293
+ singleLineComment: /\/\/.*/g,
294
+ multiLineComment: { start: /\/\*/g, end: /\*\//g },
295
+ docComment: /\/\/\/.*(?:\n\/\/\/.*)*/g,
296
+ stringLiteral: /(?:"""[\s\S]*?"""|"(?:[^"\\]|\\.)*")/g,
297
+ },
298
+ buildCommands: ["swift build", "xcodebuild"],
299
+ testCommands: ["swift test", "xcodebuild test"],
300
+ lintCommands: ["swiftlint"],
301
+ packageFiles: ["Package.swift", "*.xcodeproj", "*.xcworkspace"],
302
+ lockFiles: ["Package.resolved"],
303
+ namingConvention: "camelCase",
304
+ fileNaming: "PascalCase",
305
+ importStyle: "package",
306
+ docCommentPrefix: "///",
307
+ docCommentStyle: "none",
308
+ };
309
+ const KOTLIN_CONFIG = {
310
+ name: "kotlin",
311
+ displayName: "Kotlin",
312
+ extensions: ["kt", "kts"],
313
+ patterns: {
314
+ function: /(?:(?:public|private|protected|internal)\s+)?(?:(?:suspend|inline|infix|operator|override)\s+)*fun\s+(?:<[^>]*>\s+)?(\w+)\s*\(([^)]*)\)(?:\s*:\s*([^\s{=]+))?\s*[{=]/g,
315
+ class: /(?:(?:public|private|protected|internal)\s+)?(?:(?:abstract|open|data|sealed|inner|enum)\s+)*class\s+(\w+)(?:<[^>]*>)?(?:\s*\([^)]*\))?(?:\s*:\s*[\w(),\s]+)?\s*\{?/g,
316
+ interface: /(?:(?:public|private|protected|internal)\s+)?interface\s+(\w+)(?:<[^>]*>)?(?:\s*:\s*[\w,\s]+)?\s*\{/g,
317
+ import: /import\s+([\w.*]+)/g,
318
+ singleLineComment: /\/\/.*/g,
319
+ multiLineComment: { start: /\/\*/g, end: /\*\//g },
320
+ docComment: /\/\*\*[\s\S]*?\*\//g,
321
+ stringLiteral: /(?:"""[\s\S]*?"""|"(?:[^"\\]|\\.)*")/g,
322
+ },
323
+ buildCommands: ["gradle build", "./gradlew build", "mvn compile"],
324
+ testCommands: ["gradle test", "./gradlew test", "mvn test"],
325
+ lintCommands: ["ktlint", "detekt"],
326
+ packageFiles: ["build.gradle.kts", "build.gradle", "pom.xml"],
327
+ lockFiles: ["gradle.lockfile"],
328
+ namingConvention: "camelCase",
329
+ fileNaming: "PascalCase",
330
+ importStyle: "absolute",
331
+ docCommentPrefix: "/**",
332
+ docCommentStyle: "javadoc",
333
+ };
334
+ const DART_CONFIG = {
335
+ name: "dart",
336
+ displayName: "Dart",
337
+ extensions: ["dart"],
338
+ patterns: {
339
+ function: /(?:(?:static|external)\s+)?(?:Future<[\w<>?]+>|[\w<>?]+)\s+(\w+)\s*(?:<[^>]*>)?\s*\(([^)]*)\)(?:\s*(?:async\*?|sync\*))?\s*\{/g,
340
+ class: /(?:abstract\s+)?class\s+(\w+)(?:<[^>]*>)?(?:\s+extends\s+\w+)?(?:\s+with\s+[\w,\s]+)?(?:\s+implements\s+[\w,\s]+)?\s*\{/g,
341
+ interface: /(?:abstract\s+)?class\s+(\w+)(?:<[^>]*>)?\s*\{/g,
342
+ import: /import\s+'([^']+)'/g,
343
+ export: /export\s+'([^']+)'/g,
344
+ singleLineComment: /\/\/.*/g,
345
+ multiLineComment: { start: /\/\*/g, end: /\*\//g },
346
+ docComment: /\/\/\/.*(?:\n\/\/\/.*)*/g,
347
+ stringLiteral: /(?:r?"""[\s\S]*?"""|r?'''[\s\S]*?'''|r?"(?:[^"\\]|\\.)*"|r?'(?:[^'\\]|\\.)*')/g,
348
+ },
349
+ buildCommands: ["dart compile", "flutter build"],
350
+ testCommands: ["dart test", "flutter test"],
351
+ lintCommands: ["dart analyze", "flutter analyze"],
352
+ packageFiles: ["pubspec.yaml"],
353
+ lockFiles: ["pubspec.lock"],
354
+ namingConvention: "camelCase",
355
+ fileNaming: "snake_case",
356
+ importStyle: "package",
357
+ docCommentPrefix: "///",
358
+ docCommentStyle: "none",
359
+ };
360
+ const SHELL_CONFIG = {
361
+ name: "shell",
362
+ displayName: "Shell",
363
+ extensions: ["sh", "bash", "zsh", "fish"],
364
+ shebangs: ["bash", "sh", "zsh", "fish"],
365
+ patterns: {
366
+ function: /(?:function\s+)?(\w+)\s*\(\s*\)\s*\{/g,
367
+ class: /(?!)/g, // no classes in shell
368
+ import: /(?:source|\.)[ \t]+['"]?([^'";\s]+)['"]?/g,
369
+ singleLineComment: /#.*/g,
370
+ multiLineComment: { start: /<<'?COMMENT'?/g, end: /^COMMENT$/gm },
371
+ stringLiteral: /(?:"(?:[^"\\]|\\.)*"|'[^']*'|\$'(?:[^'\\]|\\.)*')/g,
372
+ },
373
+ buildCommands: [],
374
+ testCommands: ["bats", "shunit2"],
375
+ lintCommands: ["shellcheck"],
376
+ packageFiles: [],
377
+ lockFiles: [],
378
+ namingConvention: "snake_case",
379
+ fileNaming: "kebab-case",
380
+ importStyle: "relative",
381
+ docCommentPrefix: "#",
382
+ docCommentStyle: "none",
383
+ };
384
+ /** Map of all built-in language configurations. */
385
+ const BUILTIN_LANGUAGES = {
386
+ typescript: TYPESCRIPT_CONFIG,
387
+ javascript: JAVASCRIPT_CONFIG,
388
+ python: PYTHON_CONFIG,
389
+ go: GO_CONFIG,
390
+ rust: RUST_CONFIG,
391
+ java: JAVA_CONFIG,
392
+ c: C_CONFIG,
393
+ cpp: CPP_CONFIG,
394
+ ruby: RUBY_CONFIG,
395
+ php: PHP_CONFIG,
396
+ swift: SWIFT_CONFIG,
397
+ kotlin: KOTLIN_CONFIG,
398
+ dart: DART_CONFIG,
399
+ shell: SHELL_CONFIG,
400
+ unknown: {
401
+ name: "unknown",
402
+ displayName: "Unknown",
403
+ extensions: [],
404
+ patterns: {
405
+ function: /(?!)/g,
406
+ class: /(?!)/g,
407
+ import: /(?!)/g,
408
+ singleLineComment: /(?!)/g,
409
+ multiLineComment: { start: /(?!)/g, end: /(?!)/g },
410
+ stringLiteral: /(?!)/g,
411
+ },
412
+ buildCommands: [],
413
+ testCommands: [],
414
+ lintCommands: [],
415
+ packageFiles: [],
416
+ lockFiles: [],
417
+ namingConvention: "camelCase",
418
+ fileNaming: "kebab-case",
419
+ importStyle: "relative",
420
+ docCommentPrefix: "//",
421
+ docCommentStyle: "none",
422
+ },
423
+ };
424
+ /** Extension to language lookup table. */
425
+ const EXTENSION_MAP = {};
426
+ for (const [lang, config] of Object.entries(BUILTIN_LANGUAGES)) {
427
+ for (const ext of config.extensions) {
428
+ EXTENSION_MAP[ext] = lang;
429
+ }
430
+ }
431
+ const PROJECT_DETECTION_RULES = [
432
+ // JavaScript / TypeScript frameworks
433
+ {
434
+ name: "Next.js",
435
+ language: "typescript",
436
+ framework: "nextjs",
437
+ triggerFiles: ["next.config.js", "next.config.mjs", "next.config.ts"],
438
+ suggestedTools: [
439
+ "eslint",
440
+ "prettier",
441
+ "jest",
442
+ "playwright",
443
+ "next lint",
444
+ ],
445
+ },
446
+ {
447
+ name: "Express",
448
+ language: "typescript",
449
+ framework: "express",
450
+ triggerFiles: [],
451
+ contentPatterns: [
452
+ { file: "package.json", pattern: /"express"\s*:/ },
453
+ ],
454
+ suggestedTools: ["eslint", "jest", "supertest"],
455
+ },
456
+ {
457
+ name: "React (Vite)",
458
+ language: "typescript",
459
+ framework: "react-vite",
460
+ triggerFiles: ["vite.config.ts", "vite.config.js"],
461
+ contentPatterns: [
462
+ { file: "package.json", pattern: /"react"\s*:/ },
463
+ ],
464
+ suggestedTools: ["eslint", "vitest", "playwright"],
465
+ },
466
+ {
467
+ name: "Vue.js",
468
+ language: "typescript",
469
+ framework: "vue",
470
+ triggerFiles: [],
471
+ contentPatterns: [
472
+ { file: "package.json", pattern: /"vue"\s*:/ },
473
+ ],
474
+ suggestedTools: ["eslint", "vitest", "vue-tsc"],
475
+ },
476
+ {
477
+ name: "Svelte",
478
+ language: "typescript",
479
+ framework: "svelte",
480
+ triggerFiles: ["svelte.config.js", "svelte.config.ts"],
481
+ suggestedTools: ["eslint", "svelte-check", "vitest"],
482
+ },
483
+ // Python frameworks
484
+ {
485
+ name: "Django",
486
+ language: "python",
487
+ framework: "django",
488
+ triggerFiles: ["manage.py"],
489
+ contentPatterns: [
490
+ { file: "requirements.txt", pattern: /django/i },
491
+ ],
492
+ suggestedTools: ["pytest-django", "ruff", "mypy", "black"],
493
+ },
494
+ {
495
+ name: "Flask",
496
+ language: "python",
497
+ framework: "flask",
498
+ triggerFiles: [],
499
+ contentPatterns: [
500
+ { file: "requirements.txt", pattern: /flask/i },
501
+ { file: "pyproject.toml", pattern: /flask/i },
502
+ ],
503
+ suggestedTools: ["pytest", "ruff", "mypy"],
504
+ },
505
+ {
506
+ name: "FastAPI",
507
+ language: "python",
508
+ framework: "fastapi",
509
+ triggerFiles: [],
510
+ contentPatterns: [
511
+ { file: "requirements.txt", pattern: /fastapi/i },
512
+ { file: "pyproject.toml", pattern: /fastapi/i },
513
+ ],
514
+ suggestedTools: ["pytest", "ruff", "mypy", "uvicorn"],
515
+ },
516
+ // Go
517
+ {
518
+ name: "Go Project",
519
+ language: "go",
520
+ triggerFiles: ["go.mod"],
521
+ suggestedTools: ["golangci-lint", "go vet", "go test"],
522
+ },
523
+ // Rust
524
+ {
525
+ name: "Rust Project",
526
+ language: "rust",
527
+ triggerFiles: ["Cargo.toml"],
528
+ suggestedTools: ["cargo clippy", "cargo test", "cargo fmt"],
529
+ },
530
+ // Java / Kotlin
531
+ {
532
+ name: "Spring Boot",
533
+ language: "java",
534
+ framework: "spring",
535
+ triggerFiles: [],
536
+ contentPatterns: [
537
+ { file: "pom.xml", pattern: /spring-boot/ },
538
+ { file: "build.gradle", pattern: /spring-boot/ },
539
+ { file: "build.gradle.kts", pattern: /spring-boot/ },
540
+ ],
541
+ suggestedTools: ["maven", "gradle", "junit", "checkstyle"],
542
+ },
543
+ {
544
+ name: "Android (Kotlin)",
545
+ language: "kotlin",
546
+ framework: "android",
547
+ triggerFiles: [],
548
+ contentPatterns: [
549
+ {
550
+ file: "build.gradle.kts",
551
+ pattern: /com\.android\.application/,
552
+ },
553
+ {
554
+ file: "build.gradle",
555
+ pattern: /com\.android\.application/,
556
+ },
557
+ ],
558
+ suggestedTools: ["gradle", "ktlint", "detekt"],
559
+ },
560
+ // Swift
561
+ {
562
+ name: "Swift Package",
563
+ language: "swift",
564
+ triggerFiles: ["Package.swift"],
565
+ suggestedTools: ["swift build", "swift test", "swiftlint"],
566
+ },
567
+ {
568
+ name: "iOS App",
569
+ language: "swift",
570
+ framework: "uikit",
571
+ triggerFiles: [],
572
+ contentPatterns: [
573
+ {
574
+ file: "*.xcodeproj/project.pbxproj",
575
+ pattern: /iphoneos/i,
576
+ },
577
+ ],
578
+ suggestedTools: ["xcodebuild", "swiftlint", "xctest"],
579
+ },
580
+ // Dart / Flutter
581
+ {
582
+ name: "Flutter",
583
+ language: "dart",
584
+ framework: "flutter",
585
+ triggerFiles: [],
586
+ contentPatterns: [
587
+ { file: "pubspec.yaml", pattern: /flutter:/ },
588
+ ],
589
+ suggestedTools: ["flutter analyze", "flutter test", "dart fix"],
590
+ },
591
+ {
592
+ name: "Dart Project",
593
+ language: "dart",
594
+ triggerFiles: ["pubspec.yaml"],
595
+ suggestedTools: ["dart analyze", "dart test"],
596
+ },
597
+ // Ruby
598
+ {
599
+ name: "Ruby on Rails",
600
+ language: "ruby",
601
+ framework: "rails",
602
+ triggerFiles: ["Rakefile", "config/routes.rb"],
603
+ contentPatterns: [
604
+ { file: "Gemfile", pattern: /rails/ },
605
+ ],
606
+ suggestedTools: ["rubocop", "rspec", "bundler"],
607
+ },
608
+ // PHP
609
+ {
610
+ name: "Laravel",
611
+ language: "php",
612
+ framework: "laravel",
613
+ triggerFiles: ["artisan"],
614
+ contentPatterns: [
615
+ { file: "composer.json", pattern: /laravel\/framework/ },
616
+ ],
617
+ suggestedTools: ["phpstan", "phpunit", "pint"],
618
+ },
619
+ ];
620
+ const MONOREPO_INDICATORS = [
621
+ "pnpm-workspace.yaml",
622
+ "lerna.json",
623
+ "nx.json",
624
+ "turbo.json",
625
+ "rush.json",
626
+ "packages",
627
+ "apps",
628
+ ];
629
+ // ─── LanguageSupport Class ───
630
+ /**
631
+ * Provides multi-language intelligence for the YUAN coding agent.
632
+ *
633
+ * Supports language detection (by extension and content), parsing pattern access,
634
+ * tool configuration, code generation hints, and project type detection.
635
+ */
636
+ export class LanguageSupport {
637
+ configs;
638
+ extMap;
639
+ /**
640
+ * Creates a new LanguageSupport instance.
641
+ * @param config Optional configuration for additional languages or overrides.
642
+ */
643
+ constructor(config) {
644
+ this.configs = new Map();
645
+ this.extMap = new Map(Object.entries(EXTENSION_MAP));
646
+ // Load built-in configs
647
+ for (const [lang, cfg] of Object.entries(BUILTIN_LANGUAGES)) {
648
+ this.configs.set(lang, { ...cfg });
649
+ }
650
+ // Apply overrides
651
+ if (config?.overrides) {
652
+ for (const [lang, overrides] of Object.entries(config.overrides)) {
653
+ const existing = this.configs.get(lang);
654
+ if (existing && overrides) {
655
+ this.configs.set(lang, {
656
+ ...existing,
657
+ ...overrides,
658
+ });
659
+ }
660
+ }
661
+ }
662
+ // Register additional languages
663
+ if (config?.additionalLanguages) {
664
+ for (const langConfig of config.additionalLanguages) {
665
+ this.configs.set(langConfig.name, langConfig);
666
+ for (const ext of langConfig.extensions) {
667
+ this.extMap.set(ext, langConfig.name);
668
+ }
669
+ }
670
+ }
671
+ }
672
+ // ─── Detection ───
673
+ /**
674
+ * Detects the programming language of a file.
675
+ * First checks file extension, then falls back to content-based detection.
676
+ * @param filePath File path to detect language from.
677
+ * @param content Optional file content for shebang/syntax detection.
678
+ * @returns Detected language identifier.
679
+ */
680
+ detectLanguage(filePath, content) {
681
+ // 1. Try extension
682
+ const ext = extname(filePath).replace(/^\./, "").toLowerCase();
683
+ const byExt = this.extMap.get(ext);
684
+ if (byExt)
685
+ return byExt;
686
+ // Special filename handling
687
+ const name = basename(filePath).toLowerCase();
688
+ if (name === "makefile" || name === "gnumakefile")
689
+ return "c";
690
+ if (name === "rakefile")
691
+ return "ruby";
692
+ if (name === "gemfile")
693
+ return "ruby";
694
+ if (name === "dockerfile")
695
+ return "shell";
696
+ // 2. Try content-based detection
697
+ if (content) {
698
+ return this.detectFromContent(content);
699
+ }
700
+ return "unknown";
701
+ }
702
+ /**
703
+ * Detects project types from a list of files present in the project.
704
+ * @param files List of file paths (relative or absolute).
705
+ * @param readFile Optional function to read file content for pattern matching.
706
+ * @returns Array of detected project types, sorted by specificity.
707
+ */
708
+ detectProjectType(files, readFile) {
709
+ const fileSet = new Set(files.map((f) => basename(f)));
710
+ const results = [];
711
+ const isMonorepo = MONOREPO_INDICATORS.some((indicator) => files.some((f) => basename(f) === indicator || f.includes(`/${indicator}/`)));
712
+ for (const rule of PROJECT_DETECTION_RULES) {
713
+ let detected = false;
714
+ let detectedBy = "";
715
+ // Check trigger files
716
+ for (const trigger of rule.triggerFiles) {
717
+ if (fileSet.has(trigger) || files.some((f) => f.endsWith(trigger))) {
718
+ detected = true;
719
+ detectedBy = trigger;
720
+ break;
721
+ }
722
+ }
723
+ // Check content patterns (if readFile provided and not yet detected)
724
+ if (!detected && rule.contentPatterns && readFile) {
725
+ for (const { file, pattern } of rule.contentPatterns) {
726
+ const matchingFiles = files.filter((f) => {
727
+ const b = basename(f);
728
+ if (file.includes("*")) {
729
+ const re = new RegExp("^" + file.replace(/\*/g, ".*") + "$");
730
+ return re.test(b) || re.test(f);
731
+ }
732
+ return b === file || f.endsWith(file);
733
+ });
734
+ for (const mf of matchingFiles) {
735
+ const content = readFile(mf);
736
+ if (content && pattern.test(content)) {
737
+ detected = true;
738
+ detectedBy = `${file} (content match)`;
739
+ break;
740
+ }
741
+ }
742
+ if (detected)
743
+ break;
744
+ }
745
+ }
746
+ if (detected) {
747
+ results.push({
748
+ name: rule.name,
749
+ language: rule.language,
750
+ framework: rule.framework,
751
+ isMonorepo,
752
+ detectedBy,
753
+ suggestedTools: rule.suggestedTools,
754
+ });
755
+ }
756
+ }
757
+ return results;
758
+ }
759
+ // ─── Config Access ───
760
+ /**
761
+ * Returns the full configuration for a language.
762
+ * @param language Language to get config for.
763
+ * @returns Language configuration.
764
+ */
765
+ getConfig(language) {
766
+ return this.configs.get(language) ?? BUILTIN_LANGUAGES.unknown;
767
+ }
768
+ /**
769
+ * Returns parsing patterns for a language.
770
+ * @param language Language to get patterns for.
771
+ * @returns Language patterns.
772
+ */
773
+ getPatterns(language) {
774
+ return this.getConfig(language).patterns;
775
+ }
776
+ /**
777
+ * Returns all registered language identifiers.
778
+ * @returns Array of supported language names.
779
+ */
780
+ getAllLanguages() {
781
+ return [...this.configs.keys()];
782
+ }
783
+ // ─── Language-Specific Helpers ───
784
+ /**
785
+ * Returns the primary build command for a language, optionally specialized by project type.
786
+ * @param language Target language.
787
+ * @param projectType Optional project type/framework name.
788
+ * @returns Build command string.
789
+ */
790
+ getBuildCommand(language, projectType) {
791
+ const config = this.getConfig(language);
792
+ // Project-type specific overrides
793
+ if (projectType) {
794
+ const pt = projectType.toLowerCase();
795
+ if (pt === "nextjs" || pt === "next.js")
796
+ return "next build";
797
+ if (pt === "vite" || pt === "react-vite")
798
+ return "vite build";
799
+ if (pt === "flutter")
800
+ return "flutter build";
801
+ if (pt === "android")
802
+ return "./gradlew assembleDebug";
803
+ if (pt === "spring")
804
+ return "mvn package";
805
+ if (pt === "rails")
806
+ return "bundle exec rake assets:precompile";
807
+ if (pt === "laravel")
808
+ return "composer install --optimize-autoloader";
809
+ }
810
+ return config.buildCommands[0] ?? "";
811
+ }
812
+ /**
813
+ * Returns the primary test command for a language, optionally specialized by project type.
814
+ * @param language Target language.
815
+ * @param projectType Optional project type/framework name.
816
+ * @returns Test command string.
817
+ */
818
+ getTestCommand(language, projectType) {
819
+ const config = this.getConfig(language);
820
+ if (projectType) {
821
+ const pt = projectType.toLowerCase();
822
+ if (pt === "nextjs" || pt === "next.js")
823
+ return "jest --config jest.config.ts";
824
+ if (pt === "django")
825
+ return "python manage.py test";
826
+ if (pt === "flutter")
827
+ return "flutter test";
828
+ if (pt === "rails")
829
+ return "bundle exec rspec";
830
+ if (pt === "laravel")
831
+ return "php artisan test";
832
+ }
833
+ return config.testCommands[0] ?? "";
834
+ }
835
+ /**
836
+ * Returns the primary lint command for a language, optionally specialized by project type.
837
+ * @param language Target language.
838
+ * @param projectType Optional project type/framework name.
839
+ * @returns Lint command string.
840
+ */
841
+ getLintCommand(language, projectType) {
842
+ const config = this.getConfig(language);
843
+ if (projectType) {
844
+ const pt = projectType.toLowerCase();
845
+ if (pt === "nextjs" || pt === "next.js")
846
+ return "next lint";
847
+ if (pt === "flutter")
848
+ return "flutter analyze";
849
+ }
850
+ return config.lintCommands[0] ?? "";
851
+ }
852
+ /**
853
+ * Returns the primary package manifest file name for a language.
854
+ * @param language Target language.
855
+ * @returns Package file name, or null if not applicable.
856
+ */
857
+ getPackageFile(language) {
858
+ const config = this.getConfig(language);
859
+ return config.packageFiles[0] ?? null;
860
+ }
861
+ // ─── Parsing Helpers ───
862
+ /**
863
+ * Extracts function/method declarations from source code.
864
+ * @param content Source code content.
865
+ * @param language Language of the source code.
866
+ * @returns Array of parsed function symbols.
867
+ */
868
+ extractFunctions(content, language) {
869
+ const patterns = this.getPatterns(language);
870
+ const regex = new RegExp(patterns.function.source, patterns.function.flags);
871
+ const results = [];
872
+ const lines = content.split("\n");
873
+ let match;
874
+ while ((match = regex.exec(content)) !== null) {
875
+ const line = this.getLineNumber(content, match.index);
876
+ const name = this.extractName(match, language);
877
+ if (!name)
878
+ continue;
879
+ const visibility = this.extractVisibility(lines[line - 1] ?? "", language);
880
+ results.push({
881
+ name,
882
+ line,
883
+ params: match[2]?.trim() || undefined,
884
+ returnType: match[3]?.trim() || undefined,
885
+ visibility,
886
+ });
887
+ }
888
+ return results;
889
+ }
890
+ /**
891
+ * Extracts class/struct declarations from source code.
892
+ * @param content Source code content.
893
+ * @param language Language of the source code.
894
+ * @returns Array of parsed class symbols.
895
+ */
896
+ extractClasses(content, language) {
897
+ const patterns = this.getPatterns(language);
898
+ const regex = new RegExp(patterns.class.source, patterns.class.flags);
899
+ const results = [];
900
+ let match;
901
+ while ((match = regex.exec(content)) !== null) {
902
+ const line = this.getLineNumber(content, match.index);
903
+ const name = match[1];
904
+ if (!name)
905
+ continue;
906
+ const lineText = content.split("\n")[line - 1] ?? "";
907
+ const visibility = this.extractVisibility(lineText, language);
908
+ results.push({ name, line, visibility });
909
+ }
910
+ return results;
911
+ }
912
+ /**
913
+ * Extracts import statements from source code.
914
+ * @param content Source code content.
915
+ * @param language Language of the source code.
916
+ * @returns Array of parsed imports.
917
+ */
918
+ extractImports(content, language) {
919
+ const patterns = this.getPatterns(language);
920
+ const regex = new RegExp(patterns.import.source, patterns.import.flags);
921
+ const results = [];
922
+ let match;
923
+ while ((match = regex.exec(content)) !== null) {
924
+ const line = this.getLineNumber(content, match.index);
925
+ const fullMatch = match[0];
926
+ // Extract source — use first non-empty capture group
927
+ let source = "";
928
+ for (let i = 1; i < match.length; i++) {
929
+ if (match[i]) {
930
+ source = match[i];
931
+ break;
932
+ }
933
+ }
934
+ if (!source)
935
+ continue;
936
+ // Extract named imports
937
+ const names = [];
938
+ const namedMatch = fullMatch.match(/\{([^}]+)\}/);
939
+ if (namedMatch) {
940
+ names.push(...namedMatch[1]
941
+ .split(",")
942
+ .map((n) => n.trim().replace(/\s+as\s+\w+/, ""))
943
+ .filter(Boolean));
944
+ }
945
+ // Detect default import
946
+ const isDefault = !namedMatch &&
947
+ !fullMatch.includes("*") &&
948
+ (language === "typescript" ||
949
+ language === "javascript" ||
950
+ language === "python");
951
+ results.push({ source, names, line, isDefault });
952
+ }
953
+ return results;
954
+ }
955
+ // ─── Naming ───
956
+ /**
957
+ * Converts a name to the naming convention of the target language.
958
+ * @param name Name to convert (supports camelCase, snake_case, PascalCase, kebab-case input).
959
+ * @param language Target language.
960
+ * @returns Converted name.
961
+ */
962
+ toLanguageConvention(name, language) {
963
+ const config = this.getConfig(language);
964
+ const words = this.splitWords(name);
965
+ if (words.length === 0)
966
+ return name;
967
+ switch (config.namingConvention) {
968
+ case "camelCase":
969
+ return (words[0].toLowerCase() +
970
+ words
971
+ .slice(1)
972
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
973
+ .join(""));
974
+ case "snake_case":
975
+ return words.map((w) => w.toLowerCase()).join("_");
976
+ case "PascalCase":
977
+ return words
978
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
979
+ .join("");
980
+ case "kebab-case":
981
+ return words.map((w) => w.toLowerCase()).join("-");
982
+ default:
983
+ return name;
984
+ }
985
+ }
986
+ /**
987
+ * Returns the file naming convention description for a language.
988
+ * @param language Target language.
989
+ * @returns File naming convention string.
990
+ */
991
+ getFileNameConvention(language) {
992
+ const config = this.getConfig(language);
993
+ const examples = {
994
+ camelCase: "myComponent.ts",
995
+ snake_case: "my_component.py",
996
+ PascalCase: "MyComponent.java",
997
+ "kebab-case": "my-component.ts",
998
+ };
999
+ return `${config.fileNaming} (e.g., ${examples[config.fileNaming] ?? "file.ext"})`;
1000
+ }
1001
+ // ─── Private Helpers ───
1002
+ /**
1003
+ * Detects language from file content (shebangs and syntax patterns).
1004
+ */
1005
+ detectFromContent(content) {
1006
+ // Check shebang
1007
+ const shebangMatch = content.match(/^#!\s*(?:\/usr\/bin\/env\s+)?(\w+)/);
1008
+ if (shebangMatch) {
1009
+ const interpreter = shebangMatch[1].toLowerCase();
1010
+ for (const [, config] of this.configs) {
1011
+ if (config.shebangs?.some((s) => interpreter.includes(s))) {
1012
+ return config.name;
1013
+ }
1014
+ }
1015
+ }
1016
+ // Heuristic: check for language-specific syntax patterns
1017
+ if (content.includes("<?php") ||
1018
+ content.match(/^\s*<\?(?:php)?/m)) {
1019
+ return "php";
1020
+ }
1021
+ if (content.match(/^package\s+\w+/m) && content.includes("func ")) {
1022
+ return "go";
1023
+ }
1024
+ if (content.match(/^use\s+\w+::/m) ||
1025
+ content.match(/^fn\s+\w+/m)) {
1026
+ return "rust";
1027
+ }
1028
+ if (content.match(/^import\s+\w+/m) &&
1029
+ content.match(/^(?:public\s+)?class\s+\w+/m)) {
1030
+ // Could be Java or Kotlin — check for Kotlin-specific syntax
1031
+ if (content.includes("fun ") ||
1032
+ content.includes("val ") ||
1033
+ content.includes("var ")) {
1034
+ return "kotlin";
1035
+ }
1036
+ return "java";
1037
+ }
1038
+ if (content.match(/^import\s+(?:Foundation|UIKit|SwiftUI)/m) ||
1039
+ content.match(/^(?:struct|class)\s+\w+\s*:\s*(?:View|ObservableObject)/m)) {
1040
+ return "swift";
1041
+ }
1042
+ if (content.match(/^import\s+'/m) ||
1043
+ content.match(/^class\s+\w+\s+extends\s+State(?:less|ful)Widget/m)) {
1044
+ return "dart";
1045
+ }
1046
+ if (content.match(/^(?:def|class)\s+/m) &&
1047
+ content.match(/:\s*$/m) &&
1048
+ !content.includes("{")) {
1049
+ return "python";
1050
+ }
1051
+ if (content.match(/^(?:require|module\.exports)/m) ||
1052
+ content.match(/^(?:const|let|var)\s+\w+\s*=\s*require\(/m)) {
1053
+ return "javascript";
1054
+ }
1055
+ if (content.match(/^import\s+.*from\s+['"]/m) ||
1056
+ content.match(/^(?:interface|type)\s+\w+/m)) {
1057
+ return "typescript";
1058
+ }
1059
+ if (content.match(/^(?:require|gem|class)\s+/m) &&
1060
+ content.match(/\bdo\b.*\|/)) {
1061
+ return "ruby";
1062
+ }
1063
+ return "unknown";
1064
+ }
1065
+ /** Returns the 1-based line number for a character index. */
1066
+ getLineNumber(content, index) {
1067
+ let line = 1;
1068
+ for (let i = 0; i < index && i < content.length; i++) {
1069
+ if (content[i] === "\n")
1070
+ line++;
1071
+ }
1072
+ return line;
1073
+ }
1074
+ /** Extracts function name from a regex match, handling language-specific patterns. */
1075
+ extractName(match, language) {
1076
+ // Ruby: function pattern captures `self.` in group 1, name in group 2
1077
+ if (language === "ruby") {
1078
+ return match[2] ?? match[1] ?? null;
1079
+ }
1080
+ return match[1] ?? null;
1081
+ }
1082
+ /** Detects visibility modifier from a line of code. */
1083
+ extractVisibility(line, language) {
1084
+ const trimmed = line.trimStart();
1085
+ switch (language) {
1086
+ case "typescript":
1087
+ case "java":
1088
+ case "kotlin":
1089
+ case "swift":
1090
+ case "php":
1091
+ case "dart":
1092
+ case "cpp":
1093
+ if (trimmed.startsWith("private"))
1094
+ return "private";
1095
+ if (trimmed.startsWith("protected"))
1096
+ return "protected";
1097
+ if (trimmed.startsWith("public"))
1098
+ return "public";
1099
+ // In TS/Java, no modifier defaults to public (TS) or package-private (Java)
1100
+ if (language === "typescript")
1101
+ return "public";
1102
+ return undefined;
1103
+ case "python":
1104
+ if (trimmed.match(/def\s+__\w+/))
1105
+ return "private";
1106
+ if (trimmed.match(/def\s+_\w+/))
1107
+ return "protected";
1108
+ return "public";
1109
+ case "rust":
1110
+ if (trimmed.startsWith("pub"))
1111
+ return "public";
1112
+ return "private";
1113
+ case "go":
1114
+ // Go uses capitalization for visibility
1115
+ // Handled at call site via name
1116
+ return undefined;
1117
+ case "ruby":
1118
+ // Ruby visibility is context-dependent — simplified here
1119
+ return undefined;
1120
+ default:
1121
+ return undefined;
1122
+ }
1123
+ }
1124
+ /** Splits a name into words (handles camelCase, snake_case, PascalCase, kebab-case). */
1125
+ splitWords(name) {
1126
+ return name
1127
+ .replace(/[-_]/g, " ")
1128
+ .replace(/([a-z])([A-Z])/g, "$1 $2")
1129
+ .replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2")
1130
+ .split(/\s+/)
1131
+ .filter(Boolean);
1132
+ }
1133
+ }
1134
+ //# sourceMappingURL=language-support.js.map