feihong-code 7.2.0 → 7.5.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 (249) hide show
  1. package/.github/workflows/ci.yml +180 -140
  2. package/.github/workflows/release.yml +200 -173
  3. package/CHANGELOG.md +94 -115
  4. package/README.md +609 -586
  5. package/dist/agent/completion-engine.js +76 -45
  6. package/dist/agent/completion-engine.js.map +1 -1
  7. package/dist/agent/completion-postprocess.js +109 -0
  8. package/dist/agent/completion-postprocess.js.map +1 -0
  9. package/dist/agent/context-budget.js +121 -0
  10. package/dist/agent/context-budget.js.map +1 -0
  11. package/dist/agent/context-compactor.js +47 -0
  12. package/dist/agent/context-compactor.js.map +1 -1
  13. package/dist/agent/custom-agent.js +52 -52
  14. package/dist/agent/design-to-code.js +40 -40
  15. package/dist/agent/lint.js +121 -0
  16. package/dist/agent/lint.js.map +1 -0
  17. package/dist/agent/multi-agent.js +44 -44
  18. package/dist/agent/orchestrator.js +20 -20
  19. package/dist/agent/prompts.js +54 -54
  20. package/dist/agent/self-correction.js +24 -24
  21. package/dist/agent/self-heal.js +27 -27
  22. package/dist/cli/commands.js +9 -0
  23. package/dist/cli/commands.js.map +1 -1
  24. package/dist/cli/index.js +9 -0
  25. package/dist/cli/index.js.map +1 -1
  26. package/dist/cli/multi-pane-tui.js +217 -0
  27. package/dist/cli/multi-pane-tui.js.map +1 -0
  28. package/dist/cli/run.js +129 -40
  29. package/dist/cli/run.js.map +1 -1
  30. package/dist/cli/tui-run.js +79 -0
  31. package/dist/cli/tui-run.js.map +1 -0
  32. package/dist/cli/tui.js.map +1 -1
  33. package/dist/cli/version.js +1 -1
  34. package/dist/lsp/lsp-client.js +183 -0
  35. package/dist/lsp/lsp-client.js.map +1 -0
  36. package/dist/lsp/lsp-service.js +159 -0
  37. package/dist/lsp/lsp-service.js.map +1 -0
  38. package/dist/plugins/manager.js +50 -2
  39. package/dist/plugins/manager.js.map +1 -1
  40. package/dist/shared/i18n.js +108 -100
  41. package/dist/shared/i18n.js.map +1 -1
  42. package/dist/tools/generator/code-generator.js +40 -40
  43. package/dist/tools/generator/test-generator.js +9 -9
  44. package/dist/tools/shell/exec.js +23 -1
  45. package/dist/tools/shell/exec.js.map +1 -1
  46. package/dist/web/extra-apis.js +440 -0
  47. package/dist/web/extra-apis.js.map +1 -0
  48. package/dist/web/public/css/style.css +1715 -1715
  49. package/dist/web/public/index.html +1242 -1200
  50. package/dist/web/public/js/api.js +555 -496
  51. package/dist/web/public/js/app.js +2210 -2210
  52. package/dist/web/public/js/mock-api.js +234 -234
  53. package/dist/web/public/js/monaco-editor.js +363 -203
  54. package/dist/web/public/js/ui.js +2251 -1981
  55. package/dist/web/public/js/utils.js +214 -214
  56. package/dist/web/public/manifest.json +59 -59
  57. package/dist/web/public/service-worker.js +173 -173
  58. package/dist/web/server.js +97 -45
  59. package/dist/web/server.js.map +1 -1
  60. package/docs/BENCHMARK_REPORT_en.md +386 -329
  61. package/docs/BENCHMARK_REPORT_zh.md +386 -329
  62. package/docs/DPA.md +63 -0
  63. package/docs/DPA/346/225/260/346/215/256/345/244/204/347/220/206/345/215/217/350/256/256/346/250/241/346/235/277_v1.0.md +67 -0
  64. package/docs/SECURITY_WHITEPAPER.md +74 -0
  65. package/docs/SWE_BENCH_REPORT.md +55 -0
  66. package/docs/TECHNICAL_SPEC_en.md +292 -292
  67. package/docs/TECHNICAL_SPEC_zh.md +292 -292
  68. package/docs/UPDATE_NOTES_en.md +159 -159
  69. package/docs/UPDATE_NOTES_zh.md +159 -159
  70. package/docs/UPGRADE_7.2.0.md +309 -0
  71. package/docs/UPGRADE_GUIDE_7_5.md +86 -0
  72. package/docs/geo-feihong-code.html +391 -0
  73. package/docs//345/205/250/351/235/242/345/244/215/347/233/230_50/350/275/256/346/267/261/345/272/246/345/256/241/350/256/241_v7.2.0.md +208 -0
  74. package/docs//345/205/250/351/235/242/345/244/215/347/233/230_6/351/241/271/351/207/215/347/202/271/346/240/270/346/237/245_v7.2.0.md +152 -0
  75. package/docs//345/205/250/351/235/242/345/244/215/347/233/230_/350/277/220/350/241/214/346/227/266/345/256/236/346/265/213/347/211/210_v7.2.0.md +271 -0
  76. package/docs//345/220/210/350/247/204/350/256/244/350/257/201/345/207/206/345/244/207/346/270/205/345/215/225_v7.2.0.md +59 -0
  77. package/docs//345/256/211/345/205/250/347/231/275/347/232/256/344/271/246_v7.2.0.md +82 -0
  78. package/electron/main.js +404 -602
  79. package/package.json +175 -172
  80. package/templates/skills/api-design/SKILL.md +27 -0
  81. package/templates/skills/code-review/SKILL.md +35 -0
  82. package/templates/skills/dependency-upgrade/SKILL.md +29 -0
  83. package/templates/skills/doc-gen/SKILL.md +29 -0
  84. package/templates/skills/git-flow/SKILL.md +26 -0
  85. package/templates/skills/onboarding/SKILL.md +27 -0
  86. package/templates/skills/performance/SKILL.md +29 -0
  87. package/templates/skills/refactor/SKILL.md +28 -0
  88. package/templates/skills/security-audit/SKILL.md +28 -0
  89. package/templates/skills/test-gen/SKILL.md +30 -0
  90. package/tool-schema.json +197 -197
  91. package/dist/hello.js +0 -14
  92. package/dist/hello.js.map +0 -1
  93. package/dist/self-evolve/hook.ts +0 -80
  94. package/dist/self-evolve/manager.d.ts +0 -8
  95. package/dist/web/public/vendor/monaco/vs/abap-D-t0cyap.js +0 -1
  96. package/dist/web/public/vendor/monaco/vs/apex-CcIm7xu6.js +0 -1
  97. package/dist/web/public/vendor/monaco/vs/assets/css.worker-URu8fCFR.js +0 -97
  98. package/dist/web/public/vendor/monaco/vs/assets/editor.worker-lj3bdIIn.js +0 -30
  99. package/dist/web/public/vendor/monaco/vs/assets/editorWebWorkerMain-CA_vMoUU.js +0 -30
  100. package/dist/web/public/vendor/monaco/vs/assets/html.worker-D1SL3iM8.js +0 -474
  101. package/dist/web/public/vendor/monaco/vs/assets/json.worker-CoJx_OPf.js +0 -62
  102. package/dist/web/public/vendor/monaco/vs/assets/ts.worker-BWKtMYOk.js +0 -67722
  103. package/dist/web/public/vendor/monaco/vs/azcli-BA0tQDCg.js +0 -1
  104. package/dist/web/public/vendor/monaco/vs/basic-languages/monaco.contribution.js +0 -1
  105. package/dist/web/public/vendor/monaco/vs/bat-C397hTD6.js +0 -1
  106. package/dist/web/public/vendor/monaco/vs/bicep-DF5aW17k.js +0 -2
  107. package/dist/web/public/vendor/monaco/vs/cameligo-plsz8qhj.js +0 -1
  108. package/dist/web/public/vendor/monaco/vs/clojure-Y2auQMzK.js +0 -1
  109. package/dist/web/public/vendor/monaco/vs/coffee-Bu45yuWE.js +0 -1
  110. package/dist/web/public/vendor/monaco/vs/cpp-CkKPQIni.js +0 -1
  111. package/dist/web/public/vendor/monaco/vs/csharp-CX28MZyh.js +0 -1
  112. package/dist/web/public/vendor/monaco/vs/csp-D8uWnyxW.js +0 -1
  113. package/dist/web/public/vendor/monaco/vs/css-CaeNmE3S.js +0 -3
  114. package/dist/web/public/vendor/monaco/vs/css.worker-CyhWkhHo.js +0 -1
  115. package/dist/web/public/vendor/monaco/vs/cssMode-CV6Ay48H.js +0 -1
  116. package/dist/web/public/vendor/monaco/vs/cypher-DVThT8BS.js +0 -1
  117. package/dist/web/public/vendor/monaco/vs/dart-CmGfCvrO.js +0 -1
  118. package/dist/web/public/vendor/monaco/vs/dockerfile-CZqqYdch.js +0 -1
  119. package/dist/web/public/vendor/monaco/vs/ecl-30fUercY.js +0 -1
  120. package/dist/web/public/vendor/monaco/vs/editor/editor.main.css +0 -1
  121. package/dist/web/public/vendor/monaco/vs/editor/editor.main.js +0 -1
  122. package/dist/web/public/vendor/monaco/vs/editor/editor.worker.js +0 -1
  123. package/dist/web/public/vendor/monaco/vs/editor-KLE6jdfb.js +0 -831
  124. package/dist/web/public/vendor/monaco/vs/editor.js +0 -1
  125. package/dist/web/public/vendor/monaco/vs/editorWorkerHost-fVE1cjcC.js +0 -35
  126. package/dist/web/public/vendor/monaco/vs/elixir-xjPaIfzF.js +0 -1
  127. package/dist/web/public/vendor/monaco/vs/flow9-DqtmStfK.js +0 -1
  128. package/dist/web/public/vendor/monaco/vs/freemarker2-FWreY7v7.js +0 -3
  129. package/dist/web/public/vendor/monaco/vs/fsharp-BOMdg4U1.js +0 -1
  130. package/dist/web/public/vendor/monaco/vs/go-D_hbi-Jt.js +0 -1
  131. package/dist/web/public/vendor/monaco/vs/graphql-CKUU4kLG.js +0 -1
  132. package/dist/web/public/vendor/monaco/vs/handlebars-CZi4pHCH.js +0 -1
  133. package/dist/web/public/vendor/monaco/vs/hcl-DTaboeZW.js +0 -1
  134. package/dist/web/public/vendor/monaco/vs/html-j_7ZTNRU.js +0 -1
  135. package/dist/web/public/vendor/monaco/vs/html.worker-CA3iAimZ.js +0 -1
  136. package/dist/web/public/vendor/monaco/vs/htmlMode-27by_KM4.js +0 -1
  137. package/dist/web/public/vendor/monaco/vs/index-049xrXrp.js +0 -1
  138. package/dist/web/public/vendor/monaco/vs/index-CBVt3dzv.js +0 -5
  139. package/dist/web/public/vendor/monaco/vs/index.js +0 -1
  140. package/dist/web/public/vendor/monaco/vs/ini-CsNwO04R.js +0 -1
  141. package/dist/web/public/vendor/monaco/vs/initialize-DL0l1TGY.js +0 -1
  142. package/dist/web/public/vendor/monaco/vs/java-CI4ZMsH9.js +0 -1
  143. package/dist/web/public/vendor/monaco/vs/javascript-DTJl4Jn1.js +0 -1
  144. package/dist/web/public/vendor/monaco/vs/json.worker-BizpAl9O.js +0 -1
  145. package/dist/web/public/vendor/monaco/vs/jsonMode-DLUiMUrI.js +0 -1
  146. package/dist/web/public/vendor/monaco/vs/julia-BwzEvaQw.js +0 -1
  147. package/dist/web/public/vendor/monaco/vs/kotlin-IUYPiTV8.js +0 -1
  148. package/dist/web/public/vendor/monaco/vs/language/css/css.worker.js +0 -66
  149. package/dist/web/public/vendor/monaco/vs/language/css/monaco.contribution.js +0 -1
  150. package/dist/web/public/vendor/monaco/vs/language/html/html.worker.js +0 -443
  151. package/dist/web/public/vendor/monaco/vs/language/html/monaco.contribution.js +0 -1
  152. package/dist/web/public/vendor/monaco/vs/language/json/json.worker.js +0 -17
  153. package/dist/web/public/vendor/monaco/vs/language/json/monaco.contribution.js +0 -1
  154. package/dist/web/public/vendor/monaco/vs/language/typescript/monaco.contribution.js +0 -1
  155. package/dist/web/public/vendor/monaco/vs/language/typescript/ts.worker.js +0 -67693
  156. package/dist/web/public/vendor/monaco/vs/less-C0eDYdqa.js +0 -2
  157. package/dist/web/public/vendor/monaco/vs/lexon-iON-Kj97.js +0 -1
  158. package/dist/web/public/vendor/monaco/vs/liquid-CLJYelW6.js +0 -1
  159. package/dist/web/public/vendor/monaco/vs/loader.js +0 -1368
  160. package/dist/web/public/vendor/monaco/vs/lspLanguageFeatures-BIkJOWLw.js +0 -2
  161. package/dist/web/public/vendor/monaco/vs/lua-DtygF91M.js +0 -1
  162. package/dist/web/public/vendor/monaco/vs/m3-CsR4AuFi.js +0 -1
  163. package/dist/web/public/vendor/monaco/vs/main-BEx-Fmlo.js +0 -15
  164. package/dist/web/public/vendor/monaco/vs/main-DsK8pnKg.js +0 -3
  165. package/dist/web/public/vendor/monaco/vs/markdown-C_rD0bIw.js +0 -1
  166. package/dist/web/public/vendor/monaco/vs/mdx-CpzZIPHF.js +0 -1
  167. package/dist/web/public/vendor/monaco/vs/mips-CiYP61RB.js +0 -1
  168. package/dist/web/public/vendor/monaco/vs/monaco.contribution-9cKT3C7t.js +0 -1
  169. package/dist/web/public/vendor/monaco/vs/monaco.contribution-BE88ZNGY.js +0 -1
  170. package/dist/web/public/vendor/monaco/vs/monaco.contribution-BPhsneLd.js +0 -1
  171. package/dist/web/public/vendor/monaco/vs/monaco.contribution-BgRy6xDf.js +0 -1
  172. package/dist/web/public/vendor/monaco/vs/msdax-C38-sJlp.js +0 -1
  173. package/dist/web/public/vendor/monaco/vs/mysql-CdtbpvbG.js +0 -1
  174. package/dist/web/public/vendor/monaco/vs/nls/lang/cs.d.ts +0 -1
  175. package/dist/web/public/vendor/monaco/vs/nls/lang/cs.js +0 -9
  176. package/dist/web/public/vendor/monaco/vs/nls/lang/de.d.ts +0 -1
  177. package/dist/web/public/vendor/monaco/vs/nls/lang/de.js +0 -9
  178. package/dist/web/public/vendor/monaco/vs/nls/lang/es.d.ts +0 -1
  179. package/dist/web/public/vendor/monaco/vs/nls/lang/es.js +0 -9
  180. package/dist/web/public/vendor/monaco/vs/nls/lang/fr.d.ts +0 -1
  181. package/dist/web/public/vendor/monaco/vs/nls/lang/fr.js +0 -9
  182. package/dist/web/public/vendor/monaco/vs/nls/lang/it.d.ts +0 -1
  183. package/dist/web/public/vendor/monaco/vs/nls/lang/it.js +0 -9
  184. package/dist/web/public/vendor/monaco/vs/nls/lang/ja.d.ts +0 -1
  185. package/dist/web/public/vendor/monaco/vs/nls/lang/ja.js +0 -9
  186. package/dist/web/public/vendor/monaco/vs/nls/lang/ko.d.ts +0 -1
  187. package/dist/web/public/vendor/monaco/vs/nls/lang/ko.js +0 -9
  188. package/dist/web/public/vendor/monaco/vs/nls/lang/pl.d.ts +0 -1
  189. package/dist/web/public/vendor/monaco/vs/nls/lang/pl.js +0 -9
  190. package/dist/web/public/vendor/monaco/vs/nls/lang/pt-br.d.ts +0 -1
  191. package/dist/web/public/vendor/monaco/vs/nls/lang/pt-br.js +0 -9
  192. package/dist/web/public/vendor/monaco/vs/nls/lang/ru.d.ts +0 -1
  193. package/dist/web/public/vendor/monaco/vs/nls/lang/ru.js +0 -9
  194. package/dist/web/public/vendor/monaco/vs/nls/lang/tr.d.ts +0 -1
  195. package/dist/web/public/vendor/monaco/vs/nls/lang/tr.js +0 -9
  196. package/dist/web/public/vendor/monaco/vs/nls/lang/zh-cn.d.ts +0 -1
  197. package/dist/web/public/vendor/monaco/vs/nls/lang/zh-cn.js +0 -9
  198. package/dist/web/public/vendor/monaco/vs/nls/lang/zh-tw.d.ts +0 -1
  199. package/dist/web/public/vendor/monaco/vs/nls/lang/zh-tw.js +0 -9
  200. package/dist/web/public/vendor/monaco/vs/nls.messages-loader.js +0 -1
  201. package/dist/web/public/vendor/monaco/vs/objective-c-CntZFaHX.js +0 -1
  202. package/dist/web/public/vendor/monaco/vs/pascal-r6kuqfl_.js +0 -1
  203. package/dist/web/public/vendor/monaco/vs/pascaligo-BiXoTmXh.js +0 -1
  204. package/dist/web/public/vendor/monaco/vs/perl-DABw_TcH.js +0 -1
  205. package/dist/web/public/vendor/monaco/vs/pgsql-me_jFXeX.js +0 -1
  206. package/dist/web/public/vendor/monaco/vs/php-D_kh-9LK.js +0 -1
  207. package/dist/web/public/vendor/monaco/vs/pla-VfZjczW0.js +0 -1
  208. package/dist/web/public/vendor/monaco/vs/postiats-BBSzz8Pk.js +0 -1
  209. package/dist/web/public/vendor/monaco/vs/powerquery-Dt-g_2cc.js +0 -1
  210. package/dist/web/public/vendor/monaco/vs/powershell-B-7ap1zc.js +0 -1
  211. package/dist/web/public/vendor/monaco/vs/protobuf-BmtuEB1A.js +0 -2
  212. package/dist/web/public/vendor/monaco/vs/pug-BRpRNeEb.js +0 -1
  213. package/dist/web/public/vendor/monaco/vs/python-CqWUUgfu.js +0 -1
  214. package/dist/web/public/vendor/monaco/vs/qsharp-BzsFaUU9.js +0 -1
  215. package/dist/web/public/vendor/monaco/vs/r-f8dDdrp4.js +0 -1
  216. package/dist/web/public/vendor/monaco/vs/razor-hok5y9Km.js +0 -1
  217. package/dist/web/public/vendor/monaco/vs/redis-fvZQY4PI.js +0 -1
  218. package/dist/web/public/vendor/monaco/vs/redshift-45Et0LQi.js +0 -1
  219. package/dist/web/public/vendor/monaco/vs/restructuredtext-C7UUFKFD.js +0 -1
  220. package/dist/web/public/vendor/monaco/vs/ruby-CZO8zYTz.js +0 -1
  221. package/dist/web/public/vendor/monaco/vs/rust-Bfetafyc.js +0 -1
  222. package/dist/web/public/vendor/monaco/vs/sb-3GYllVck.js +0 -1
  223. package/dist/web/public/vendor/monaco/vs/scala-foMgrKo1.js +0 -1
  224. package/dist/web/public/vendor/monaco/vs/scheme-CHdMtr7p.js +0 -1
  225. package/dist/web/public/vendor/monaco/vs/scss-C1cmLt9V.js +0 -3
  226. package/dist/web/public/vendor/monaco/vs/shell-ClXCKCEW.js +0 -1
  227. package/dist/web/public/vendor/monaco/vs/solidity-MZ6ExpPy.js +0 -1
  228. package/dist/web/public/vendor/monaco/vs/sophia-DWkuSsPQ.js +0 -1
  229. package/dist/web/public/vendor/monaco/vs/sparql-AUGFYSyk.js +0 -1
  230. package/dist/web/public/vendor/monaco/vs/sql-32GpJSV2.js +0 -1
  231. package/dist/web/public/vendor/monaco/vs/st-CuDFIVZ_.js +0 -1
  232. package/dist/web/public/vendor/monaco/vs/swift-t-PfMj7W.js +0 -1
  233. package/dist/web/public/vendor/monaco/vs/systemverilog-Ch4vA8Yt.js +0 -1
  234. package/dist/web/public/vendor/monaco/vs/tcl-D74tq1nH.js +0 -1
  235. package/dist/web/public/vendor/monaco/vs/toggleHighContrast-qGX7E9o7.js +0 -61
  236. package/dist/web/public/vendor/monaco/vs/ts.worker-2QLmBukE.js +0 -1
  237. package/dist/web/public/vendor/monaco/vs/tsMode-B0S_kp2q.js +0 -11
  238. package/dist/web/public/vendor/monaco/vs/twig-C6taOxMV.js +0 -1
  239. package/dist/web/public/vendor/monaco/vs/typescript-_2t_511t.js +0 -1
  240. package/dist/web/public/vendor/monaco/vs/typespec-8OfoLt6R.js +0 -1
  241. package/dist/web/public/vendor/monaco/vs/vb-Dyb2648j.js +0 -1
  242. package/dist/web/public/vendor/monaco/vs/wgsl-BhLXMOR0.js +0 -298
  243. package/dist/web/public/vendor/monaco/vs/workers-BBttULjf.js +0 -1
  244. package/dist/web/public/vendor/monaco/vs/xml-cZjNDqDT.js +0 -1
  245. package/dist/web/public/vendor/monaco/vs/yaml-A1fOIdH6.js +0 -1
  246. package/dist/web/web-config.js +0 -143
  247. package/dist/web/web-config.js.map +0 -1
  248. package/docs/DEPLOYMENT.md +0 -382
  249. package/docs/MODEL_FINETUNING.md +0 -405
@@ -1,203 +1,363 @@
1
- /**
2
- * 飞虹 Code - Monaco Editor 封装模块
3
- * VSCode 同款编辑器内核,提供语法高亮、智能补全、内联 ghost text 等能力
4
- *
5
- * 依赖:index.html 中已加载 vendor/monaco/vs/loader.js(AMD loader)
6
- */
7
- (function (global) {
8
- 'use strict';
9
-
10
- let monacoInstance = null;
11
- let initPromise = null;
12
- const editors = new Map(); // containerId -> editor instance
13
- let inlineCompletionProvider = null;
14
- let completionItemProvider = null;
15
-
16
- /** 根据文件扩展名推断 Monaco language id */
17
- function detectLanguage(filePath) {
18
- const ext = filePath.split('.').pop().toLowerCase();
19
- const map = {
20
- ts: 'typescript', tsx: 'typescript', js: 'javascript', jsx: 'javascript',
21
- json: 'json', md: 'markdown', html: 'html', css: 'css', scss: 'scss',
22
- less: 'less', py: 'python', java: 'java', c: 'c', cpp: 'cpp', h: 'cpp',
23
- cs: 'csharp', go: 'go', rs: 'rust', php: 'php', rb: 'ruby', swift: 'swift',
24
- kt: 'kotlin', scala: 'scala', sh: 'shell', bash: 'shell', zsh: 'shell',
25
- sql: 'sql', yaml: 'yaml', yml: 'yaml', xml: 'xml', vue: 'html', svelte: 'html',
26
- proto: 'protobuf', dockerfile: 'dockerfile', toml: 'ini', ini: 'ini',
27
- };
28
- if (filePath.toLowerCase().endsWith('dockerfile')) return 'dockerfile';
29
- return map[ext] || 'plaintext';
30
- }
31
-
32
- /** 初始化 Monaco(只执行一次,返回 Promise) */
33
- function initMonaco() {
34
- if (monacoInstance) return Promise.resolve(monacoInstance);
35
- if (initPromise) return initPromise;
36
-
37
- initPromise = new Promise((resolve, reject) => {
38
- if (typeof global.require === 'undefined') {
39
- reject(new Error('Monaco loader.js 未加载,请检查 vendor/monaco/vs/loader.js'));
40
- return;
41
- }
42
- global.require.config({ paths: { vs: 'vendor/monaco/vs' } });
43
- global.require(['vs/editor/editor.main'], function () {
44
- monacoInstance = global.monaco;
45
- // 配置默认主题(跟随系统深色/浅色)
46
- const isDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
47
- monacoInstance.editor.setTheme(isDark ? 'vs-dark' : 'vs');
48
- resolve(monacoInstance);
49
- }, reject);
50
- });
51
- return initPromise;
52
- }
53
-
54
- /**
55
- * 在指定容器中创建 Monaco 编辑器
56
- * @param {HTMLElement|string} container - 容器元素或 ID
57
- * @param {string} value - 初始内容
58
- * @param {string} filePath - 文件路径(用于推断语言)
59
- * @param {object} options - 额外选项
60
- * @returns {Promise<monaco.editor.IStandaloneCodeEditor>}
61
- */
62
- async function createEditor(container, value, filePath, options = {}) {
63
- const monaco = await initMonaco();
64
- const el = typeof container === 'string' ? document.getElementById(container) : container;
65
- if (!el) throw new Error('编辑器容器不存在: ' + container);
66
-
67
- // 如果该容器已有编辑器,先销毁
68
- const existing = editors.get(el.id || container);
69
- if (existing) {
70
- existing.dispose();
71
- editors.delete(el.id || container);
72
- }
73
-
74
- const language = detectLanguage(filePath);
75
- const editor = monaco.editor.create(el, {
76
- value: value || '',
77
- language: language,
78
- theme: undefined, // 使用全局主题
79
- automaticLayout: true,
80
- fontSize: 13,
81
- lineNumbers: 'on',
82
- minimap: { enabled: true },
83
- scrollBeyondLastLine: false,
84
- wordWrap: 'on',
85
- bracketPairColorization: { enabled: true },
86
- guides: { bracketPairs: true, indentation: true },
87
- tabSize: 2,
88
- renderWhitespace: 'selection',
89
- smoothScrolling: true,
90
- cursorBlinking: 'smooth',
91
- // P0-1: 启用内联补全(ghost text,Tab 接受)
92
- inlineSuggest: { enabled: true, showToolbar: 'always' },
93
- // 启用快速建议(输入时自动触发补全弹窗)
94
- quickSuggestions: { other: true, comments: false, strings: true },
95
- quickSuggestionsDelay: 200,
96
- ...options,
97
- });
98
-
99
- const key = el.id || container;
100
- editors.set(key, editor);
101
- return editor;
102
- }
103
-
104
- /** 获取编辑器实例 */
105
- function getEditor(container) {
106
- const key = typeof container === 'string' ? container : container.id;
107
- return editors.get(key);
108
- }
109
-
110
- /** 销毁编辑器 */
111
- function disposeEditor(container) {
112
- const key = typeof container === 'string' ? container : container.id;
113
- const editor = editors.get(key);
114
- if (editor) {
115
- editor.dispose();
116
- editors.delete(key);
117
- }
118
- }
119
-
120
- /**
121
- * 注册内联补全 Provider(ghost text,Tab 接受)
122
- * @param {function} fetchFn - 异步补全函数,参数 {filePath, content, offset},返回 {text: string}
123
- */
124
- function registerInlineCompletions(fetchFn) {
125
- initMonaco().then((monaco) => {
126
- if (inlineCompletionProvider) {
127
- inlineCompletionProvider.dispose();
128
- }
129
- inlineCompletionProvider = monaco.languages.registerInlineCompletionsProvider('*', {
130
- provideInlineCompletions: async function (model, position, context, token) {
131
- try {
132
- const filePath = model.uri.path || 'untitled';
133
- const content = model.getValue();
134
- const offset = model.getOffsetAt(position);
135
- const result = await fetchFn({ filePath, content, offset, token });
136
- if (!result || !result.text) return { items: [] };
137
- const item = {
138
- range: new monaco.Range(position.lineNumber, position.column, position.lineNumber, position.column),
139
- insertText: result.text,
140
- filterText: result.text.slice(0, 20),
141
- };
142
- return { items: [item] };
143
- } catch (e) {
144
- return { items: [] };
145
- }
146
- },
147
- freeInlineCompletions: function () {},
148
- });
149
- });
150
- }
151
-
152
- /**
153
- * 注册补全项 Provider(Ctrl+Space 触发弹窗,↑↓选择,Enter接受)
154
- * @param {function} fetchFn - 异步补全函数,参数 {filePath, content, offset, prefix},返回数组 [{label, kind, insertText, detail}]
155
- */
156
- function registerCompletionItems(fetchFn) {
157
- initMonaco().then((monaco) => {
158
- if (completionItemProvider) {
159
- completionItemProvider.dispose();
160
- }
161
- completionItemProvider = monaco.languages.registerCompletionItemProvider('*', {
162
- triggerCharacters: ['.', '(', ',', ' '],
163
- provideCompletionItems: async function (model, position, context, token) {
164
- try {
165
- const filePath = model.uri.path || 'untitled';
166
- const content = model.getValue();
167
- const offset = model.getOffsetAt(position);
168
- const word = model.getWordUntilPosition(position);
169
- const prefix = word.word || '';
170
- const suggestions = await fetchFn({ filePath, content, offset, prefix, token });
171
- if (!Array.isArray(suggestions) || !suggestions.length) return { suggestions: [] };
172
- const range = new monaco.Range(
173
- position.lineNumber, word.startColumn,
174
- position.lineNumber, position.column
175
- );
176
- return {
177
- suggestions: suggestions.map((s) => ({
178
- label: s.label || s.insertText || '',
179
- kind: monaco.languages.CompletionItemKind[s.kind] || monaco.languages.CompletionItemKind.Text,
180
- insertText: s.insertText || '',
181
- detail: s.detail || '',
182
- range: range,
183
- })),
184
- };
185
- } catch (e) {
186
- return { suggestions: [] };
187
- }
188
- },
189
- });
190
- });
191
- }
192
-
193
- /** 暴露全局 API */
194
- global.FHMonaco = {
195
- init: initMonaco,
196
- createEditor: createEditor,
197
- getEditor: getEditor,
198
- disposeEditor: disposeEditor,
199
- detectLanguage: detectLanguage,
200
- registerInlineCompletions: registerInlineCompletions,
201
- registerCompletionItems: registerCompletionItems,
202
- };
203
- })(window);
1
+ /**
2
+ * 飞虹 Code - Monaco Editor 封装模块
3
+ * VSCode 同款编辑器内核,提供语法高亮、智能补全、内联 ghost text 等能力
4
+ *
5
+ * 依赖:index.html 中已加载 vendor/monaco/vs/loader.js(AMD loader)
6
+ */
7
+ (function (global) {
8
+ 'use strict';
9
+
10
+ let monacoInstance = null;
11
+ let initPromise = null;
12
+ const editors = new Map(); // containerId -> editor instance
13
+ let activeEditor = null; // 最近创建的编辑器(供 lint/诊断反馈定位)
14
+ let inlineCompletionProvider = null;
15
+ let completionItemProvider = null;
16
+
17
+ /** 获取当前活跃编辑器(P6-1 lint 反馈定位) */
18
+ function getActiveEditor() {
19
+ return activeEditor;
20
+ }
21
+
22
+ /** 根据文件扩展名推断 Monaco language id */
23
+ function detectLanguage(filePath) {
24
+ const ext = filePath.split('.').pop().toLowerCase();
25
+ const map = {
26
+ ts: 'typescript', tsx: 'typescript', js: 'javascript', jsx: 'javascript',
27
+ json: 'json', md: 'markdown', html: 'html', css: 'css', scss: 'scss',
28
+ less: 'less', py: 'python', java: 'java', c: 'c', cpp: 'cpp', h: 'cpp',
29
+ cs: 'csharp', go: 'go', rs: 'rust', php: 'php', rb: 'ruby', swift: 'swift',
30
+ kt: 'kotlin', scala: 'scala', sh: 'shell', bash: 'shell', zsh: 'shell',
31
+ sql: 'sql', yaml: 'yaml', yml: 'yaml', xml: 'xml', vue: 'html', svelte: 'html',
32
+ proto: 'protobuf', dockerfile: 'dockerfile', toml: 'ini', ini: 'ini',
33
+ };
34
+ if (filePath.toLowerCase().endsWith('dockerfile')) return 'dockerfile';
35
+ return map[ext] || 'plaintext';
36
+ }
37
+
38
+ /** 初始化 Monaco(只执行一次,返回 Promise) */
39
+ function initMonaco() {
40
+ if (monacoInstance) return Promise.resolve(monacoInstance);
41
+ if (initPromise) return initPromise;
42
+
43
+ initPromise = new Promise((resolve, reject) => {
44
+ if (typeof global.require === 'undefined') {
45
+ reject(new Error('Monaco loader.js 未加载,请检查 vendor/monaco/vs/loader.js'));
46
+ return;
47
+ }
48
+ global.require.config({ paths: { vs: 'vendor/monaco/vs' } });
49
+ global.require(['vs/editor/editor.main'], function () {
50
+ monacoInstance = global.monaco;
51
+ // 配置默认主题(跟随系统深色/浅色)
52
+ const isDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
53
+ monacoInstance.editor.setTheme(isDark ? 'vs-dark' : 'vs');
54
+ resolve(monacoInstance);
55
+ }, reject);
56
+ });
57
+ return initPromise;
58
+ }
59
+
60
+ /**
61
+ * 在指定容器中创建 Monaco 编辑器
62
+ * @param {HTMLElement|string} container - 容器元素或 ID
63
+ * @param {string} value - 初始内容
64
+ * @param {string} filePath - 文件路径(用于推断语言)
65
+ * @param {object} options - 额外选项
66
+ * @returns {Promise<monaco.editor.IStandaloneCodeEditor>}
67
+ */
68
+ async function createEditor(container, value, filePath, options = {}) {
69
+ const monaco = await initMonaco();
70
+ const el = typeof container === 'string' ? document.getElementById(container) : container;
71
+ if (!el) throw new Error('编辑器容器不存在: ' + container);
72
+
73
+ // 如果该容器已有编辑器,先销毁
74
+ const existing = editors.get(el.id || container);
75
+ if (existing) {
76
+ existing.dispose();
77
+ editors.delete(el.id || container);
78
+ }
79
+
80
+ const language = detectLanguage(filePath);
81
+ const editor = monaco.editor.create(el, {
82
+ value: value || '',
83
+ language: language,
84
+ theme: undefined, // 使用全局主题
85
+ automaticLayout: true,
86
+ fontSize: 13,
87
+ lineNumbers: 'on',
88
+ minimap: { enabled: true },
89
+ scrollBeyondLastLine: false,
90
+ wordWrap: 'on',
91
+ bracketPairColorization: { enabled: true },
92
+ guides: { bracketPairs: true, indentation: true },
93
+ tabSize: 2,
94
+ renderWhitespace: 'selection',
95
+ smoothScrolling: true,
96
+ cursorBlinking: 'smooth',
97
+ // P0-1: 启用内联补全(ghost text,Tab 接受)
98
+ inlineSuggest: { enabled: true, showToolbar: 'always' },
99
+ // 启用快速建议(输入时自动触发补全弹窗)
100
+ quickSuggestions: { other: true, comments: false, strings: true },
101
+ quickSuggestionsDelay: 200,
102
+ ...options,
103
+ });
104
+
105
+ const key = el.id || container;
106
+ editors.set(key, editor);
107
+ activeEditor = editor; // P6-1: 记录最近活跃编辑器供 lint 反馈定位
108
+ return editor;
109
+ }
110
+
111
+ /** 获取编辑器实例 */
112
+ function getEditor(container) {
113
+ const key = typeof container === 'string' ? container : container.id;
114
+ return editors.get(key);
115
+ }
116
+
117
+ /** 销毁编辑器 */
118
+ function disposeEditor(container) {
119
+ const key = typeof container === 'string' ? container : container.id;
120
+ const editor = editors.get(key);
121
+ if (editor) {
122
+ editor.dispose();
123
+ editors.delete(key);
124
+ }
125
+ }
126
+
127
+ /**
128
+ * 注册内联补全 Provider(ghost text,Tab 接受)
129
+ * @param {function} fetchFn - 异步补全函数,参数 {filePath, content, offset},返回 {text: string}
130
+ */
131
+ /**
132
+ * 注册行内补全 Provider(ghost text)
133
+ * @param {function} fetchFn - 异步补全函数,参数 {filePath, content, offset, token},返回 {text} 或 null
134
+ * @param {{getActiveEditor?:function, onAccept?:function}} [opts] - P6-1: getActiveEditor 取当前编辑器;onAccept 在补全被接受(插入)时回调插入文本
135
+ */
136
+ function registerInlineCompletions(fetchFn, opts) {
137
+ const o = opts || {};
138
+ initMonaco().then((monaco) => {
139
+ if (inlineCompletionProvider) {
140
+ inlineCompletionProvider.dispose();
141
+ }
142
+ let lastText = '';
143
+ inlineCompletionProvider = monaco.languages.registerInlineCompletionsProvider('*', {
144
+ provideInlineCompletions: async function (model, position, context, token) {
145
+ try {
146
+ const filePath = model.uri.path || 'untitled';
147
+ const content = model.getValue();
148
+ const offset = model.getOffsetAt(position);
149
+ const result = await fetchFn({ filePath, content, offset, token });
150
+ if (!result || !result.text) return { items: [] };
151
+ const item = {
152
+ range: new monaco.Range(position.lineNumber, position.column, position.lineNumber, position.column),
153
+ insertText: result.text,
154
+ filterText: result.text.slice(0, 20),
155
+ };
156
+ lastText = result.text;
157
+ return { items: [item] };
158
+ } catch (e) {
159
+ return { items: [] };
160
+ }
161
+ },
162
+ freeInlineCompletions: function () {},
163
+ });
164
+
165
+ // P6-1: accept 检测——编辑器内容变化且插入文本匹配最近补全 onAccept(插入文本)
166
+ const bindAccept = function () {
167
+ const editor = typeof o.getActiveEditor === 'function' ? o.getActiveEditor() : null;
168
+ if (!editor || editor.__fhInlineAcceptBound) return;
169
+ editor.__fhInlineAcceptBound = true;
170
+ editor.onDidChangeModelContent((e) => {
171
+ if (!lastText) return;
172
+ for (const ch of e.changes || []) {
173
+ const ins = ch.text || '';
174
+ if (ins && (ins.startsWith(lastText) || lastText.startsWith(ins))) {
175
+ const accepted = ins.length >= lastText.length ? ins : lastText;
176
+ if (typeof o.onAccept === 'function') {
177
+ try { o.onAccept(accepted); } catch { /* lint 回调失败不阻塞编辑 */ }
178
+ }
179
+ lastText = '';
180
+ break;
181
+ }
182
+ }
183
+ });
184
+ };
185
+ bindAccept();
186
+ });
187
+ }
188
+
189
+ /**
190
+ * 注册补全项 Provider(Ctrl+Space 触发弹窗,↑↓选择,Enter接受)
191
+ * @param {function} fetchFn - 异步补全函数,参数 {filePath, content, offset, prefix},返回数组 [{label, kind, insertText, detail}]
192
+ */
193
+ function registerCompletionItems(fetchFn) {
194
+ initMonaco().then((monaco) => {
195
+ if (completionItemProvider) {
196
+ completionItemProvider.dispose();
197
+ }
198
+ completionItemProvider = monaco.languages.registerCompletionItemProvider('*', {
199
+ triggerCharacters: ['.', '(', ',', ' '],
200
+ provideCompletionItems: async function (model, position, context, token) {
201
+ try {
202
+ const filePath = model.uri.path || 'untitled';
203
+ const content = model.getValue();
204
+ const offset = model.getOffsetAt(position);
205
+ const word = model.getWordUntilPosition(position);
206
+ const prefix = word.word || '';
207
+ const suggestions = await fetchFn({ filePath, content, offset, prefix, token });
208
+ if (!Array.isArray(suggestions) || !suggestions.length) return { suggestions: [] };
209
+ const range = new monaco.Range(
210
+ position.lineNumber, word.startColumn,
211
+ position.lineNumber, position.column
212
+ );
213
+ return {
214
+ suggestions: suggestions.map((s) => ({
215
+ label: s.label || s.insertText || '',
216
+ kind: monaco.languages.CompletionItemKind[s.kind] || monaco.languages.CompletionItemKind.Text,
217
+ insertText: s.insertText || '',
218
+ detail: s.detail || '',
219
+ range: range,
220
+ })),
221
+ };
222
+ } catch (e) {
223
+ return { suggestions: [] };
224
+ }
225
+ },
226
+ });
227
+ });
228
+ }
229
+
230
+ /**
231
+ * 注册语义诊断 Provider(P4-2:编辑时错误波浪线)
232
+ * @param {function} fetchFn - 异步诊断函数,参数 {filePath, content},返回 [{line, column, endLine, endColumn, message, severity}]
233
+ * @param {function} [getEditor] - 获取当前编辑器实例(默认遍历已注册编辑器)
234
+ */
235
+ function registerDiagnostics(fetchFn, getActiveEditor) {
236
+ initMonaco().then((monaco) => {
237
+ // P5-2: 诊断 hover 提示——hover 到有 marker 的行时展示错误/警告详情
238
+ const langSet = [
239
+ 'typescript', 'javascript', 'json', 'markdown', 'html', 'css', 'scss', 'less',
240
+ 'python', 'java', 'c', 'cpp', 'csharp', 'go', 'rust', 'php', 'ruby', 'swift',
241
+ 'kotlin', 'scala', 'shell', 'sql', 'yaml', 'xml', 'protobuf', 'dockerfile',
242
+ 'ini', 'plaintext',
243
+ ];
244
+ const hoverDisp = monaco.languages.registerHoverProvider(langSet, {
245
+ provideHover(model, position) {
246
+ let editor;
247
+ try { editor = typeof getActiveEditor === 'function' ? getActiveEditor() : null; } catch { editor = null; }
248
+ if (!editor || editor.isDisposed?.()) return null;
249
+ const cur = editor.getModel();
250
+ if (!cur || model.uri.toString() !== cur.uri.toString()) return null;
251
+ const markers = monaco.editor.getModelMarkers({ resource: model.uri })
252
+ .filter((x) => x.startLineNumber <= position.lineNumber && position.lineNumber <= x.endLineNumber);
253
+ if (markers.length === 0) return null;
254
+ const md = markers.map((x) => {
255
+ const sevName = x.severity === monaco.MarkerSeverity.Error ? '错误' : x.severity === monaco.MarkerSeverity.Warning ? '警告' : '提示';
256
+ const icon = x.severity === monaco.MarkerSeverity.Error ? '⛔' : x.severity === monaco.MarkerSeverity.Warning ? '⚠️' : 'ℹ️';
257
+ return '**' + icon + ' ' + sevName + '** (L' + x.startLineNumber + ':' + x.startColumn + ') \n' + x.message;
258
+ }).join('\n\n---\n\n');
259
+ return {
260
+ contents: [{ value: '#### 飞虹 Code 诊断\n\n' + md, isTrusted: true }],
261
+ range: new monaco.Range(position.lineNumber, 1, position.lineNumber, 1),
262
+ };
263
+ },
264
+ });
265
+ hoverDisp; // 引用保持存活(Monaco 内部维护)
266
+
267
+ // 防抖 + 单飞,避免编辑时高频请求
268
+ let timer = null;
269
+ let inflight = false;
270
+ let queued = false;
271
+ const run = async function () {
272
+ if (inflight) { queued = true; return; }
273
+ const editor = typeof getActiveEditor === 'function' ? getActiveEditor() : null;
274
+ if (!editor || editor.isDisposed?.()) return;
275
+ const model = editor.getModel();
276
+ if (!model) return;
277
+ inflight = true;
278
+ try {
279
+ const filePath = model.uri.path || 'untitled';
280
+ const content = model.getValue();
281
+ const result = await fetchFn({ filePath, content });
282
+ if (!result || !Array.isArray(result.diagnostics)) {
283
+ monaco.editor.setModelMarkers(model, 'fhcode', []);
284
+ return;
285
+ }
286
+ const markers = result.diagnostics.map((d) => {
287
+ const sev = d.severity === 1 || d.severity === 'error'
288
+ ? monaco.MarkerSeverity.Error
289
+ : d.severity === 2 || d.severity === 'warning'
290
+ ? monaco.MarkerSeverity.Warning
291
+ : monaco.MarkerSeverity.Info;
292
+ return {
293
+ severity: sev,
294
+ message: d.message || '',
295
+ startLineNumber: d.line ?? 1,
296
+ startColumn: d.column ?? 1,
297
+ endLineNumber: d.endLine ?? (d.line ?? 1),
298
+ endColumn: d.endColumn ?? (d.column ?? 1) + (d.message?.length || 8),
299
+ };
300
+ });
301
+ monaco.editor.setModelMarkers(model, 'fhcode', markers);
302
+ } catch {
303
+ /* 诊断失败静默(不阻塞编辑) */
304
+ } finally {
305
+ inflight = false;
306
+ if (queued) { queued = false; timer = setTimeout(run, 200); }
307
+ }
308
+ };
309
+ const schedule = function () {
310
+ clearTimeout(timer);
311
+ timer = setTimeout(run, 350);
312
+ };
313
+ // 绑定现有编辑器(createEditor 后由 ui 层调用 attachDiagnostics 触发监听)
314
+ const editor = typeof getActiveEditor === 'function' ? getActiveEditor() : null;
315
+ if (editor && !editor.__fhDiagnosticsBound) {
316
+ editor.__fhDiagnosticsBound = true;
317
+ editor.onDidChangeModelContent(schedule);
318
+ editor.onDidChangeModel(() => schedule());
319
+ }
320
+ return { run, schedule };
321
+ });
322
+ }
323
+
324
+ /**
325
+ * P6-1: 补全接受后的 lint 反馈——把 /api/lint 结果追加为编辑器波浪线(owner: fhcode-lint)
326
+ * @param {Array} issues - [{severity, line, column, message}]
327
+ */
328
+ function showLintFeedback(issues) {
329
+ initMonaco().then((monaco) => {
330
+ const editor = activeEditor;
331
+ if (!editor || editor.isDisposed?.()) return;
332
+ const model = editor.getModel();
333
+ if (!model) return;
334
+ if (!Array.isArray(issues) || issues.length === 0) {
335
+ monaco.editor.setModelMarkers(model, 'fhcode-lint', []);
336
+ return;
337
+ }
338
+ const markers = issues.map((d) => ({
339
+ severity: d.severity === 1 ? monaco.MarkerSeverity.Error : d.severity === 2 ? monaco.MarkerSeverity.Warning : monaco.MarkerSeverity.Info,
340
+ message: '补全校验:' + (d.message || ''),
341
+ startLineNumber: d.line ?? 1,
342
+ startColumn: d.column ?? 1,
343
+ endLineNumber: d.line ?? 1,
344
+ endColumn: (d.column ?? 1) + (d.message?.length || 20),
345
+ }));
346
+ monaco.editor.setModelMarkers(model, 'fhcode-lint', markers);
347
+ });
348
+ }
349
+
350
+ /** 暴露全局 API */
351
+ global.FHMonaco = {
352
+ init: initMonaco,
353
+ createEditor: createEditor,
354
+ getEditor: getEditor,
355
+ disposeEditor: disposeEditor,
356
+ detectLanguage: detectLanguage,
357
+ getActiveEditor: getActiveEditor,
358
+ registerInlineCompletions: registerInlineCompletions,
359
+ registerCompletionItems: registerCompletionItems,
360
+ registerDiagnostics: registerDiagnostics,
361
+ showLintFeedback: showLintFeedback,
362
+ };
363
+ })(window);