precis-cli 0.1.3__py3-none-any.whl

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 (442) hide show
  1. app/__init__.py +16 -0
  2. app/api/__init__.py +32 -0
  3. app/api/dependencies.py +185 -0
  4. app/api/main.py +301 -0
  5. app/api/middleware/__init__.py +34 -0
  6. app/api/middleware/exception_handler.py +126 -0
  7. app/api/middleware/request_logging.py +97 -0
  8. app/api/middleware/token_auth.py +215 -0
  9. app/api/models/__init__.py +151 -0
  10. app/api/models/connection_rules.py +98 -0
  11. app/api/models/files.py +99 -0
  12. app/api/models/full_validation.py +554 -0
  13. app/api/models/project.py +117 -0
  14. app/api/models/projects.py +80 -0
  15. app/api/models/schema.py +121 -0
  16. app/api/models/v2_responses.py +46 -0
  17. app/api/models/validation.py +303 -0
  18. app/api/models/workspace.py +118 -0
  19. app/api/routers/__init__.py +56 -0
  20. app/api/routers/ai/__init__.py +36 -0
  21. app/api/routers/ai/chat.py +243 -0
  22. app/api/routers/ai/generate.py +156 -0
  23. app/api/routers/ai/hardware.py +199 -0
  24. app/api/routers/ai/jobs.py +544 -0
  25. app/api/routers/ai/migrate.py +471 -0
  26. app/api/routers/ai/models.py +352 -0
  27. app/api/routers/ai/ollama.py +108 -0
  28. app/api/routers/ai/providers.py +491 -0
  29. app/api/routers/ai/router.py +44 -0
  30. app/api/routers/ai/stream.py +281 -0
  31. app/api/routers/ai/utils.py +182 -0
  32. app/api/routers/core/__init__.py +34 -0
  33. app/api/routers/core/connection_rules.py +188 -0
  34. app/api/routers/core/data_sources.py +374 -0
  35. app/api/routers/core/regex.py +333 -0
  36. app/api/routers/core/reporting.py +263 -0
  37. app/api/routers/files/__init__.py +24 -0
  38. app/api/routers/files/ops.py +179 -0
  39. app/api/routers/files/transfer.py +101 -0
  40. app/api/routers/preview/__init__.py +35 -0
  41. app/api/routers/preview/content_mode.py +264 -0
  42. app/api/routers/preview/header_row.py +154 -0
  43. app/api/routers/preview/models.py +81 -0
  44. app/api/routers/preview/path_mode.py +440 -0
  45. app/api/routers/preview/router.py +30 -0
  46. app/api/routers/project/__init__.py +61 -0
  47. app/api/routers/project/base.py +111 -0
  48. app/api/routers/project/constraint.py +345 -0
  49. app/api/routers/project/full_config.py +411 -0
  50. app/api/routers/project/full_config_writer.py +327 -0
  51. app/api/routers/project/helpers.py +167 -0
  52. app/api/routers/project/inspection_fix.py +330 -0
  53. app/api/routers/project/manifest.py +605 -0
  54. app/api/routers/project/models.py +177 -0
  55. app/api/routers/project/pattern.py +268 -0
  56. app/api/routers/project/regex.py +358 -0
  57. app/api/routers/project/scanner.py +157 -0
  58. app/api/routers/project/schema.py +567 -0
  59. app/api/routers/project/schema_helpers.py +149 -0
  60. app/api/routers/project/settings.py +399 -0
  61. app/api/routers/project/template.py +325 -0
  62. app/api/routers/project/validation.py +227 -0
  63. app/api/routers/project/view.py +177 -0
  64. app/api/routers/project/workspaces.py +167 -0
  65. app/api/routers/projects/__init__.py +25 -0
  66. app/api/routers/projects/create.py +121 -0
  67. app/api/routers/projects/open.py +103 -0
  68. app/api/routers/projects/scan.py +100 -0
  69. app/api/routers/validation/__init__.py +39 -0
  70. app/api/routers/validation/common.py +263 -0
  71. app/api/routers/validation/content_mode.py +401 -0
  72. app/api/routers/validation/history.py +235 -0
  73. app/api/routers/validation/inline_mode.py +196 -0
  74. app/api/routers/validation/path_mode.py +314 -0
  75. app/api/routers/validation/router.py +51 -0
  76. app/api/services/full_validation_response_builder.py +412 -0
  77. app/api/services/io_error_messages.py +41 -0
  78. app/api/services/preview_service.py +248 -0
  79. app/cli/__init__.py +18 -0
  80. app/cli/__main__.py +30 -0
  81. app/cli/shared_services/__init__.py +42 -0
  82. app/cli/shared_services/config_ops.py +581 -0
  83. app/cli/shared_services/generation_ops.py +160 -0
  84. app/cli/shared_services/project_ops.py +288 -0
  85. app/cli/shell/__init__.py +48 -0
  86. app/cli/shell/commands/__init__.py +63 -0
  87. app/cli/shell/commands/ai/__init__.py +260 -0
  88. app/cli/shell/commands/ai/chat.py +331 -0
  89. app/cli/shell/commands/ai/delete.py +165 -0
  90. app/cli/shell/commands/ai/diff.py +70 -0
  91. app/cli/shell/commands/ai/display.py +428 -0
  92. app/cli/shell/commands/ai/executor.py +225 -0
  93. app/cli/shell/commands/ai/executor_utils.py +271 -0
  94. app/cli/shell/commands/ai/generate.py +285 -0
  95. app/cli/shell/commands/ai/interaction.py +262 -0
  96. app/cli/shell/commands/ai/migrate.py +281 -0
  97. app/cli/shell/commands/ai/resolver.py +224 -0
  98. app/cli/shell/commands/ai/status.py +101 -0
  99. app/cli/shell/commands/ai/switch.py +158 -0
  100. app/cli/shell/commands/ai/utils.py +52 -0
  101. app/cli/shell/commands/base.py +343 -0
  102. app/cli/shell/commands/config/__init__.py +131 -0
  103. app/cli/shell/commands/config/base.py +80 -0
  104. app/cli/shell/commands/config/check.py +246 -0
  105. app/cli/shell/commands/config/edit.py +148 -0
  106. app/cli/shell/commands/config/get.py +111 -0
  107. app/cli/shell/commands/config/init.py +123 -0
  108. app/cli/shell/commands/config/inspect.py +164 -0
  109. app/cli/shell/commands/config/list.py +104 -0
  110. app/cli/shell/commands/config/set.py +119 -0
  111. app/cli/shell/commands/config/show.py +150 -0
  112. app/cli/shell/commands/exit.py +67 -0
  113. app/cli/shell/commands/help.py +104 -0
  114. app/cli/shell/commands/infer_schema.py +156 -0
  115. app/cli/shell/commands/open.py +201 -0
  116. app/cli/shell/commands/project.py +215 -0
  117. app/cli/shell/commands/provider.py +619 -0
  118. app/cli/shell/commands/system.py +170 -0
  119. app/cli/shell/commands/validate.py +455 -0
  120. app/cli/shell/completer.py +231 -0
  121. app/cli/shell/config_storage.py +191 -0
  122. app/cli/shell/exceptions.py +90 -0
  123. app/cli/shell/formatter.py +371 -0
  124. app/cli/shell/interactive_menu.py +348 -0
  125. app/cli/shell/main.py +286 -0
  126. app/cli/shell/parser.py +266 -0
  127. app/cli/start.py +180 -0
  128. app/cli_main.py +52 -0
  129. app/mcp_server.py +311 -0
  130. app/shared/core/__init__.py +18 -0
  131. app/shared/core/app_version.py +59 -0
  132. app/shared/core/config/__init__.py +119 -0
  133. app/shared/core/config/server.py +193 -0
  134. app/shared/core/data_source/__init__.py +106 -0
  135. app/shared/core/data_source/loader.py +348 -0
  136. app/shared/core/data_source/loaders/__init__.py +213 -0
  137. app/shared/core/data_source/loaders/base.py +215 -0
  138. app/shared/core/data_source/loaders/converter.py +337 -0
  139. app/shared/core/data_source/loaders/csv_loader.py +252 -0
  140. app/shared/core/data_source/loaders/excel_loader.py +666 -0
  141. app/shared/core/data_source/loaders/extractor.py +268 -0
  142. app/shared/core/data_source/loaders/json_loader.py +354 -0
  143. app/shared/core/data_source/loaders/registry.py +88 -0
  144. app/shared/core/data_source/loaders/sql_loader.py +313 -0
  145. app/shared/core/data_source/loaders/strategies/__init__.py +100 -0
  146. app/shared/core/data_source/loaders/strategies/array_parser.py +277 -0
  147. app/shared/core/data_source/loaders/strategies/lines_parser.py +355 -0
  148. app/shared/core/data_source/loaders/strategies/object_parser.py +278 -0
  149. app/shared/core/data_source/schema_info.py +50 -0
  150. app/shared/core/data_source/specs/__init__.py +128 -0
  151. app/shared/core/data_source/specs/base.py +258 -0
  152. app/shared/core/data_source/specs/csv_source.py +137 -0
  153. app/shared/core/data_source/specs/excel_source.py +141 -0
  154. app/shared/core/data_source/specs/file_base.py +252 -0
  155. app/shared/core/data_source/specs/json_source.py +226 -0
  156. app/shared/core/data_source/specs/sql_source.py +161 -0
  157. app/shared/core/encoding.py +36 -0
  158. app/shared/core/io/__init__.py +24 -0
  159. app/shared/core/io/yaml.py +379 -0
  160. app/shared/core/manifest_schema/__init__.py +52 -0
  161. app/shared/core/manifest_schema/types.py +99 -0
  162. app/shared/core/manifest_schema/version.py +175 -0
  163. app/shared/core/patterns/__init__.py +24 -0
  164. app/shared/core/patterns/loader.py +134 -0
  165. app/shared/core/patterns/writer.py +244 -0
  166. app/shared/core/project/__init__.py +47 -0
  167. app/shared/core/project/constraint/builders/__init__.py +50 -0
  168. app/shared/core/project/constraint/builders/base.py +100 -0
  169. app/shared/core/project/constraint/builders/composite.py +77 -0
  170. app/shared/core/project/constraint/builders/conditional.py +67 -0
  171. app/shared/core/project/constraint/builders/foreign_key.py +53 -0
  172. app/shared/core/project/constraint/builders/registry.py +64 -0
  173. app/shared/core/project/constraint/builders/scripted.py +51 -0
  174. app/shared/core/project/constraint/builders/single_column.py +86 -0
  175. app/shared/core/project/constraint/builders/unique.py +53 -0
  176. app/shared/core/project/constraint/factory.py +170 -0
  177. app/shared/core/project/constraint/reader.py +214 -0
  178. app/shared/core/project/constraint/registry.py +233 -0
  179. app/shared/core/project/constraint/types/__init__.py +63 -0
  180. app/shared/core/project/constraint/types/constraint_file.py +261 -0
  181. app/shared/core/project/constraint/types/refs.py +460 -0
  182. app/shared/core/project/constraint/types.py +28 -0
  183. app/shared/core/project/constraint/writer.py +181 -0
  184. app/shared/core/project/loader/__init__.py +56 -0
  185. app/shared/core/project/loader/loader.py +30 -0
  186. app/shared/core/project/loader/loader_parts/config_inspector.py +137 -0
  187. app/shared/core/project/loader/loader_parts/embedded_constraints.py +224 -0
  188. app/shared/core/project/loader/loader_parts/file_loaders.py +58 -0
  189. app/shared/core/project/loader/loader_parts/inspection_ids.py +85 -0
  190. app/shared/core/project/loader/loader_parts/inspector_helpers.py +312 -0
  191. app/shared/core/project/loader/loader_parts/inspector_id_checks.py +274 -0
  192. app/shared/core/project/loader/loader_parts/inspector_reference_checks.py +690 -0
  193. app/shared/core/project/loader/loader_parts/inspector_uniqueness_checks.py +286 -0
  194. app/shared/core/project/loader/loader_parts/loading_error_messages.py +298 -0
  195. app/shared/core/project/loader/loader_parts/main.py +432 -0
  196. app/shared/core/project/loader/loader_parts/path_validation.py +117 -0
  197. app/shared/core/project/loader/loader_parts/runtime.py +125 -0
  198. app/shared/core/project/loader/types.py +246 -0
  199. app/shared/core/project/manifest/coverage.py +391 -0
  200. app/shared/core/project/manifest/reader.py +260 -0
  201. app/shared/core/project/manifest/types.py +91 -0
  202. app/shared/core/project/manifest/types_parts/__init__.py +60 -0
  203. app/shared/core/project/manifest/types_parts/constants.py +40 -0
  204. app/shared/core/project/manifest/types_parts/data_source.py +68 -0
  205. app/shared/core/project/manifest/types_parts/info.py +59 -0
  206. app/shared/core/project/manifest/types_parts/manifest.py +294 -0
  207. app/shared/core/project/manifest/types_parts/refs.py +153 -0
  208. app/shared/core/project/manifest/types_parts/settings.py +92 -0
  209. app/shared/core/project/manifest/types_parts/settings_file_processing.py +64 -0
  210. app/shared/core/project/manifest/types_parts/settings_script_security.py +78 -0
  211. app/shared/core/project/manifest/types_parts/settings_validation.py +83 -0
  212. app/shared/core/project/manifest/types_parts/template.py +66 -0
  213. app/shared/core/project/manifest/writer.py +262 -0
  214. app/shared/core/project/manual_data/__init__.py +27 -0
  215. app/shared/core/project/manual_data/types.py +75 -0
  216. app/shared/core/project/regex/reader.py +197 -0
  217. app/shared/core/project/regex/types.py +405 -0
  218. app/shared/core/project/regex/writer.py +123 -0
  219. app/shared/core/project/schema/reader.py +170 -0
  220. app/shared/core/project/schema/types.py +47 -0
  221. app/shared/core/project/schema/types_parts/__init__.py +36 -0
  222. app/shared/core/project/schema/types_parts/column.py +174 -0
  223. app/shared/core/project/schema/types_parts/column_utils.py +72 -0
  224. app/shared/core/project/schema/types_parts/constraint.py +165 -0
  225. app/shared/core/project/schema/types_parts/schema_id.py +66 -0
  226. app/shared/core/project/schema/types_parts/source.py +255 -0
  227. app/shared/core/project/schema/types_parts/source_options.py +347 -0
  228. app/shared/core/project/schema/types_parts/table.py +230 -0
  229. app/shared/core/project/schema/writer.py +139 -0
  230. app/shared/core/project/schema_ref_check.py +95 -0
  231. app/shared/core/project/template/__init__.py +27 -0
  232. app/shared/core/project/template/expander.py +263 -0
  233. app/shared/core/project/template/reader.py +120 -0
  234. app/shared/core/project/template/types.py +114 -0
  235. app/shared/core/project/transform/reader.py +76 -0
  236. app/shared/core/project/transform/types.py +116 -0
  237. app/shared/core/project/transform/writer.py +84 -0
  238. app/shared/core/pydantic_messages.py +59 -0
  239. app/shared/core/reporter/__init__.py +46 -0
  240. app/shared/core/reporter/reporter.py +220 -0
  241. app/shared/core/reporter/reporters/__init__.py +65 -0
  242. app/shared/core/reporter/reporters/base.py +188 -0
  243. app/shared/core/reporter/reporters/dingtalk_app_reporter.py +274 -0
  244. app/shared/core/reporter/reporters/email_reporter.py +271 -0
  245. app/shared/core/reporter/reporters/feishu_app_reporter.py +467 -0
  246. app/shared/core/reporter/reporters/local_file_reporter.py +208 -0
  247. app/shared/core/reporter/reporters/wecom_app_reporter.py +268 -0
  248. app/shared/core/utils/__init__.py +18 -0
  249. app/shared/core/utils/path_utils.py +60 -0
  250. app/shared/core/utils/regex_extract.py +113 -0
  251. app/shared/domain/__init__.py +114 -0
  252. app/shared/domain/constraints/__init__.py +76 -0
  253. app/shared/domain/constraints/allowed_values.py +211 -0
  254. app/shared/domain/constraints/base.py +141 -0
  255. app/shared/domain/constraints/charset.py +337 -0
  256. app/shared/domain/constraints/composite.py +174 -0
  257. app/shared/domain/constraints/condition_registry.py +130 -0
  258. app/shared/domain/constraints/conditional.py +629 -0
  259. app/shared/domain/constraints/date_logic.py +731 -0
  260. app/shared/domain/constraints/foreign_key.py +261 -0
  261. app/shared/domain/constraints/key_normalization.py +56 -0
  262. app/shared/domain/constraints/not_null.py +185 -0
  263. app/shared/domain/constraints/range.py +360 -0
  264. app/shared/domain/constraints/regex.py +218 -0
  265. app/shared/domain/constraints/scripted.py +276 -0
  266. app/shared/domain/constraints/unique.py +233 -0
  267. app/shared/domain/data_engine.py +384 -0
  268. app/shared/domain/data_types.py +113 -0
  269. app/shared/domain/data_types_parts/__init__.py +67 -0
  270. app/shared/domain/data_types_parts/base.py +204 -0
  271. app/shared/domain/data_types_parts/composite.py +250 -0
  272. app/shared/domain/data_types_parts/expression.py +202 -0
  273. app/shared/domain/data_types_parts/extracted.py +106 -0
  274. app/shared/domain/data_types_parts/json_types.py +234 -0
  275. app/shared/domain/data_types_parts/scalars.py +719 -0
  276. app/shared/domain/data_types_parts/sequence.py +129 -0
  277. app/shared/domain/dataset_schema.py +48 -0
  278. app/shared/domain/eval_sandbox.py +63 -0
  279. app/shared/domain/expression_system.py +366 -0
  280. app/shared/domain/regex_flags.py +53 -0
  281. app/shared/domain/schema/builder.py +223 -0
  282. app/shared/domain/schema/models.py +339 -0
  283. app/shared/domain/transforms/__init__.py +28 -0
  284. app/shared/domain/transforms/aggregate.py +141 -0
  285. app/shared/domain/transforms/base.py +171 -0
  286. app/shared/domain/transforms/cast_type.py +120 -0
  287. app/shared/domain/transforms/concat.py +103 -0
  288. app/shared/domain/transforms/conditional_assign.py +114 -0
  289. app/shared/domain/transforms/date_format.py +81 -0
  290. app/shared/domain/transforms/digits.py +77 -0
  291. app/shared/domain/transforms/drop_duplicates.py +94 -0
  292. app/shared/domain/transforms/fill_na.py +94 -0
  293. app/shared/domain/transforms/filter_rows.py +97 -0
  294. app/shared/domain/transforms/lookup.py +78 -0
  295. app/shared/domain/transforms/lower_case.py +70 -0
  296. app/shared/domain/transforms/map_value.py +90 -0
  297. app/shared/domain/transforms/math_expr.py +112 -0
  298. app/shared/domain/transforms/modulo.py +82 -0
  299. app/shared/domain/transforms/regex_extract.py +103 -0
  300. app/shared/domain/transforms/registry.py +95 -0
  301. app/shared/domain/transforms/replace.py +88 -0
  302. app/shared/domain/transforms/sort_rows.py +94 -0
  303. app/shared/domain/transforms/string_split.py +84 -0
  304. app/shared/domain/transforms/strip.py +73 -0
  305. app/shared/domain/transforms/substring.py +92 -0
  306. app/shared/domain/transforms/upper_case.py +70 -0
  307. app/shared/domain/transforms/weighted_sum.py +104 -0
  308. app/shared/domain/validation_constraints.py +69 -0
  309. app/shared/services/__init__.py +62 -0
  310. app/shared/services/ai/__init__.py +48 -0
  311. app/shared/services/ai/agent/__init__.py +40 -0
  312. app/shared/services/ai/agent/chat_tools/__init__.py +47 -0
  313. app/shared/services/ai/agent/chat_tools/apply_actions.py +592 -0
  314. app/shared/services/ai/agent/chat_tools/ask_user.py +237 -0
  315. app/shared/services/ai/agent/chat_tools/read_canvas.py +140 -0
  316. app/shared/services/ai/agent/chat_tools/read_project.py +160 -0
  317. app/shared/services/ai/agent/chat_tools/read_table.py +301 -0
  318. app/shared/services/ai/agent/chat_tools/schemas.py +105 -0
  319. app/shared/services/ai/agent/chat_tools/validate_table.py +131 -0
  320. app/shared/services/ai/agent/executor.py +554 -0
  321. app/shared/services/ai/agent/memory.py +256 -0
  322. app/shared/services/ai/agent/planner.py +282 -0
  323. app/shared/services/ai/agent/tool_registry.py +296 -0
  324. app/shared/services/ai/agent/tools/__init__.py +32 -0
  325. app/shared/services/ai/agent/tools/config_generate.py +133 -0
  326. app/shared/services/ai/agent/tools/config_refine.py +109 -0
  327. app/shared/services/ai/agent/tools/config_validate.py +403 -0
  328. app/shared/services/ai/agent/tools/merge_results.py +136 -0
  329. app/shared/services/ai/agent/tools/plan_chunks.py +79 -0
  330. app/shared/services/ai/agent/tools/script_parse.py +359 -0
  331. app/shared/services/ai/agent/types.py +138 -0
  332. app/shared/services/ai/chat_agent_runner.py +596 -0
  333. app/shared/services/ai/chat_orchestrator.py +725 -0
  334. app/shared/services/ai/failure_messages.py +65 -0
  335. app/shared/services/ai/job_storage.py +274 -0
  336. app/shared/services/ai/migrate_service.py +550 -0
  337. app/shared/services/ai/streaming/__init__.py +65 -0
  338. app/shared/services/ai/streaming/event_journal.py +197 -0
  339. app/shared/services/ai/streaming/orchestrator.py +262 -0
  340. app/shared/services/ai/streaming/pending_interaction_store.py +227 -0
  341. app/shared/services/ai/streaming/sse_response.py +148 -0
  342. app/shared/services/ai/streaming/types.py +73 -0
  343. app/shared/services/ai/types.py +213 -0
  344. app/shared/services/ai/utils.py +322 -0
  345. app/shared/services/diff/config_diff.py +320 -0
  346. app/shared/services/hardware.py +237 -0
  347. app/shared/services/llm/__init__.py +62 -0
  348. app/shared/services/llm/actions/__init__.py +42 -0
  349. app/shared/services/llm/actions/_canvas_validator.py +147 -0
  350. app/shared/services/llm/actions/_constraint_validator.py +401 -0
  351. app/shared/services/llm/actions/_regex_validator.py +85 -0
  352. app/shared/services/llm/actions/_schema_validator.py +82 -0
  353. app/shared/services/llm/actions/_settings_validator.py +76 -0
  354. app/shared/services/llm/actions/_transform_validator.py +78 -0
  355. app/shared/services/llm/actions/action_handlers.py +400 -0
  356. app/shared/services/llm/actions/action_parser.py +63 -0
  357. app/shared/services/llm/actions/action_processor.py +468 -0
  358. app/shared/services/llm/actions/action_validator.py +311 -0
  359. app/shared/services/llm/actions/diff_compute.py +195 -0
  360. app/shared/services/llm/actions/regex_handlers.py +284 -0
  361. app/shared/services/llm/actions/registry.py +336 -0
  362. app/shared/services/llm/actions/schema_handlers.py +335 -0
  363. app/shared/services/llm/actions/settings_handlers.py +180 -0
  364. app/shared/services/llm/actions/specs.py +259 -0
  365. app/shared/services/llm/actions/transform_handlers.py +279 -0
  366. app/shared/services/llm/actions/validation_types.py +147 -0
  367. app/shared/services/llm/cache/__init__.py +18 -0
  368. app/shared/services/llm/cache/response_cache.py +80 -0
  369. app/shared/services/llm/chat/__init__.py +35 -0
  370. app/shared/services/llm/chat/chat_system_prompt.py +561 -0
  371. app/shared/services/llm/chat/response_parser.py +296 -0
  372. app/shared/services/llm/config/__init__.py +45 -0
  373. app/shared/services/llm/config/crypto.py +135 -0
  374. app/shared/services/llm/config/loader.py +258 -0
  375. app/shared/services/llm/config/models.py +202 -0
  376. app/shared/services/llm/config/presets.py +128 -0
  377. app/shared/services/llm/config_generator.py +163 -0
  378. app/shared/services/llm/constraints/__init__.py +41 -0
  379. app/shared/services/llm/constraints/constraint_builder.py +177 -0
  380. app/shared/services/llm/constraints/constraint_deletion.py +84 -0
  381. app/shared/services/llm/constraints/constraint_id.py +174 -0
  382. app/shared/services/llm/constraints/frontend_instructions.py +333 -0
  383. app/shared/services/llm/constraints/inline_batch.py +279 -0
  384. app/shared/services/llm/discovery/__init__.py +35 -0
  385. app/shared/services/llm/discovery/scanner.py +181 -0
  386. app/shared/services/llm/generation/__init__.py +42 -0
  387. app/shared/services/llm/generation/agent_wiring.py +156 -0
  388. app/shared/services/llm/generation/config_builder.py +386 -0
  389. app/shared/services/llm/generation/errors.py +36 -0
  390. app/shared/services/llm/generation/existing_config.py +99 -0
  391. app/shared/services/llm/generation/profiler.py +279 -0
  392. app/shared/services/llm/generation/prompt_builder.py +199 -0
  393. app/shared/services/llm/generation/response_parser.py +144 -0
  394. app/shared/services/llm/generation/service.py +622 -0
  395. app/shared/services/llm/models.py +104 -0
  396. app/shared/services/llm/providers/__init__.py +48 -0
  397. app/shared/services/llm/providers/base.py +310 -0
  398. app/shared/services/llm/providers/cached_provider.py +90 -0
  399. app/shared/services/llm/providers/ollama.py +498 -0
  400. app/shared/services/llm/providers/openai.py +334 -0
  401. app/shared/services/llm/providers/registry.py +108 -0
  402. app/shared/services/llm/schema_resolver.py +141 -0
  403. app/shared/services/llm/suggestion_utils.py +219 -0
  404. app/shared/services/llm/validate_executor.py +163 -0
  405. app/shared/services/llm/yaml_io.py +406 -0
  406. app/shared/services/preview/__init__.py +18 -0
  407. app/shared/services/preview/loader.py +145 -0
  408. app/shared/services/preview/path_validation.py +138 -0
  409. app/shared/services/project_loader.py +57 -0
  410. app/shared/services/schema_inference.py +260 -0
  411. app/shared/services/schema_runtime_builder.py +120 -0
  412. app/shared/services/validation/__init__.py +52 -0
  413. app/shared/services/validation/chunked_loader.py +509 -0
  414. app/shared/services/validation/dag/__init__.py +35 -0
  415. app/shared/services/validation/dag/builder.py +141 -0
  416. app/shared/services/validation/dag/executor.py +225 -0
  417. app/shared/services/validation/dag/sorter.py +77 -0
  418. app/shared/services/validation/data_loader.py +231 -0
  419. app/shared/services/validation/engine.py +446 -0
  420. app/shared/services/validation/executor.py +1030 -0
  421. app/shared/services/validation/extractors.py +266 -0
  422. app/shared/services/validation/history.py +209 -0
  423. app/shared/services/validation/json_payload.py +136 -0
  424. app/shared/services/validation/loader.py +152 -0
  425. app/shared/services/validation/memory_monitor.py +179 -0
  426. app/shared/services/validation/postprocess.py +208 -0
  427. app/shared/services/validation/progress.py +64 -0
  428. app/shared/services/validation/report_export.py +222 -0
  429. app/shared/services/validation/resolver.py +180 -0
  430. app/shared/services/validation/service.py +418 -0
  431. app/shared/services/validation/types.py +238 -0
  432. app/shared/services/validation/validators/__init__.py +36 -0
  433. app/shared/services/validation/validators/adapter.py +182 -0
  434. app/shared/services/validation/validators/base.py +332 -0
  435. app/shared/services/validation/validators/composite.py +233 -0
  436. app/shared/services/validation/validators/date_logic.py +276 -0
  437. app/start_server.py +133 -0
  438. precis_cli-0.1.3.dist-info/METADATA +180 -0
  439. precis_cli-0.1.3.dist-info/RECORD +442 -0
  440. precis_cli-0.1.3.dist-info/WHEEL +5 -0
  441. precis_cli-0.1.3.dist-info/entry_points.txt +4 -0
  442. precis_cli-0.1.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,231 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ #
3
+ # Copyright 2026 Precis Team
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ # backend/app/cli/shell/completer.py
17
+ """
18
+ @fileoverview CLI Shell Tab 补全模块
19
+
20
+ 功能概述:
21
+ - 为交互式 REPL 提供命令名 + 子命令名的 Tab 补全
22
+ - Windows 使用 pyreadline3,Unix 使用 stdlib readline,两者均不可用时静默降级
23
+ - 通过 readline 的 completer 协议接入原生 input()
24
+
25
+ 架构设计:
26
+ - install_readline_completer(): 导入 readline 后端并注册补全函数,返回是否成功
27
+ - _make_completer(): 工厂函数,返回符合 readline 协议的 complete(text, state) 闭包
28
+ - 补全分两层:顶层命令(含别名)/ 子命令(含别名)
29
+
30
+ 输入示例(REPL 内):
31
+ precis> val<Tab> → validate
32
+ precis> che<Tab> → check(validate 别名)
33
+ precis> project <Tab> → 列出 open/status/history
34
+
35
+ 输出示例:
36
+ install_readline_completer(registry) -> True # 成功注册
37
+ install_readline_completer(registry) -> False # 无可用 readline 后端,降级
38
+ """
39
+
40
+ from __future__ import annotations
41
+
42
+ import importlib
43
+ from collections.abc import Callable
44
+ from types import ModuleType
45
+ from typing import TYPE_CHECKING
46
+
47
+ if TYPE_CHECKING:
48
+ # 仅用于类型注解(from __future__ annotations 使注解为字符串),
49
+ # 运行时无需导入,避免与 parser→commands→parser 的循环导入。
50
+ from app.cli.shell.parser import CommandRegistry
51
+
52
+
53
+ def _import_readline() -> ModuleType | None:
54
+ """导入 readline 后端。
55
+
56
+ Unix 上 stdlib readline 可用;Windows 上 stdlib 无 readline,
57
+ 退回到 pyreadline3(需 pip install pyreadline3 或 precis[completion])。
58
+
59
+ Returns:
60
+ readline 模块对象;两者都不可用时返回 None
61
+ """
62
+ # Unix: stdlib readline(部分 Windows 构建如 Anaconda 也可能内置);
63
+ # Windows 退回 pyreadline3(与 stdlib readline 接口兼容)
64
+ for module_name in ("readline", "pyreadline3"):
65
+ try:
66
+ return importlib.import_module(module_name)
67
+ except ImportError:
68
+ continue
69
+ return None
70
+
71
+
72
+ def install_readline_completer(registry: CommandRegistry) -> bool:
73
+ """安装 Tab 补全到 readline 后端。
74
+
75
+ 配置 tab: complete、设置分词分隔符、注册补全函数。
76
+ 仅在交互 REPL 启动时调用一次。
77
+
78
+ Args:
79
+ registry: 命令注册表,补全函数据此提供候选
80
+
81
+ Returns:
82
+ True 表示成功注册(补全可用);
83
+ False 表示无可用 readline 后端,调用方应降级为无补全模式
84
+ """
85
+ readline = _import_readline()
86
+ if readline is None:
87
+ return False
88
+
89
+ # tab 键触发补全(标准 readline 配置)
90
+ readline.parse_and_bind("tab: complete")
91
+ # 命令/子命令补全按空格分词,不依赖标点等其他分隔符
92
+ readline.set_completer_delims(" \t\n")
93
+ # 注册补全函数
94
+ readline.set_completer(_make_completer(registry))
95
+ return True
96
+
97
+
98
+ def _make_completer(registry: CommandRegistry) -> Callable[[str, int], str | None]:
99
+ """构造 readline completer 闭包。
100
+
101
+ readline 协议:对同一 text 反复调用,state 从 0 递增,
102
+ 依次返回匹配候选,耗尽后返回 None。
103
+
104
+ Args:
105
+ registry: 命令注册表
106
+
107
+ Returns:
108
+ complete(text, state) -> Optional[str] 函数
109
+ """
110
+ # 每次补全会话缓存候选列表,避免每个 state 重复计算
111
+ # (readline 对同一 text 调用 complete(text,0..N),state=0 时重建列表)
112
+ cached: dict[str, list[str]] = {}
113
+
114
+ def complete(text: str, state: int) -> str | None:
115
+ # 延迟导入 readline:测试时可用 monkeypatch 替换 get_line_buffer
116
+ readline = _import_readline()
117
+ if readline is None:
118
+ return None
119
+
120
+ # state=0 表示新一轮补全,重建候选缓存
121
+ if state == 0:
122
+ cached[text] = _compute_candidates(registry, readline, text)
123
+
124
+ candidates = cached.get(text, [])
125
+ if state < len(candidates):
126
+ return candidates[state]
127
+ return None
128
+
129
+ return complete
130
+
131
+
132
+ def _compute_candidates(registry: CommandRegistry, readline: ModuleType, text: str) -> list[str]:
133
+ """计算当前补全候选列表。
134
+
135
+ 两层补全逻辑:
136
+ - 顶层:line_buffer 未出现已完成(带空格)的命令 → 候选为所有命令名+别名
137
+ - 子命令层:line_buffer 首词匹配到有子命令的命令 → 候选为该命令的子命令名+别名
138
+ - 其他(无子命令的命令,或已输入到第三词及以后)→ 空列表(不补全)
139
+
140
+ Args:
141
+ registry: 命令注册表
142
+ readline: readline 后端(用于 get_line_buffer)
143
+ text: 当前正在输入的 token(readline 传入)
144
+
145
+ Returns:
146
+ 匹配候选列表,已按字典序排序;每项在完整匹配时追加尾部空格
147
+ """
148
+ try:
149
+ line_buffer = readline.get_line_buffer()
150
+ except Exception:
151
+ # get_line_buffer 不可用时退化为仅用 text 做顶层补全
152
+ line_buffer = text
153
+
154
+ # 判断是否处于"正在输入第一个词"阶段:
155
+ # 若 line_buffer 去除尾部 text 后不含空格,说明还在第一个词
156
+ buffer_before_text = line_buffer[: len(line_buffer) - len(text)]
157
+ in_first_word = buffer_before_text.strip() == ""
158
+
159
+ if in_first_word:
160
+ # 顶层命令补全(含别名)
161
+ return _filter_and_decorate(_collect_top_level(registry), text)
162
+
163
+ # 已完成第一个词,尝试子命令补全。
164
+ # 关键:区分"已完成词"与"正在输入的词"。line_buffer 末尾若无空格,
165
+ # 说明最后那个 token 就是当前正在输入的词(即 text),不计入已完成词。
166
+ all_tokens = line_buffer.split()
167
+ trailing_space = line_buffer.endswith(" ")
168
+ # 已完成的词数:末尾有空格 → all_tokens 全是已完成;否则最后一个正在输入
169
+ completed_tokens = all_tokens if trailing_space else all_tokens[:-1]
170
+
171
+ first_word = completed_tokens[0] if completed_tokens else ""
172
+ command = registry.get(first_word)
173
+ if command is None:
174
+ return []
175
+
176
+ sub_names = command.list_subcommands()
177
+ if not sub_names:
178
+ # 该命令无子命令,不补全(参数/路径补全留给未来)
179
+ return []
180
+
181
+ # 仅当"正在输入第二个词"(completed_tokens 恰好 1 个)才补全子命令;
182
+ # 若已完成 2 个及以上词,说明在输第三词或更后,不再补全子命令。
183
+ if len(completed_tokens) >= 2:
184
+ return []
185
+
186
+ candidates: list[str] = []
187
+ for sub_name in sub_names:
188
+ candidates.append(sub_name)
189
+ sub_cmd = command.get_subcommand(sub_name)
190
+ if sub_cmd is not None:
191
+ candidates.extend(sub_cmd.aliases)
192
+
193
+ return _filter_and_decorate(candidates, text)
194
+
195
+
196
+ def _collect_top_level(registry: CommandRegistry) -> list[str]:
197
+ """收集所有顶层命令名 + 别名。"""
198
+ names: list[str] = []
199
+ for cmd in registry.get_all_commands():
200
+ names.append(cmd.name)
201
+ names.extend(cmd.aliases)
202
+ return names
203
+
204
+
205
+ def _filter_and_decorate(candidates: list[str], text: str) -> list[str]:
206
+ """过滤出以 text 开头的候选,去重排序,并对完整匹配项追加尾部空格。
207
+
208
+ readline 在单候选时会自动补全到完整词;追加空格让用户补全命令名后
209
+ 可直接继续输入子命令/参数,符合 shell 惯例。
210
+
211
+ Args:
212
+ candidates: 原始候选列表(可能含重复)
213
+ text: 前缀过滤条件
214
+
215
+ Returns:
216
+ 处理后的候选列表
217
+ """
218
+ seen: set[str] = set()
219
+ matched: list[str] = []
220
+ for c in candidates:
221
+ if c.startswith(text) and c not in seen:
222
+ seen.add(c)
223
+ # 完整匹配(text 非空且等于候选)时追加空格;
224
+ # 前缀补全(text 是候选的前缀)由 readline 自动补齐,也加空格提升体验
225
+ matched.append(c + " " if text else c)
226
+ matched.sort()
227
+ return matched
228
+
229
+
230
+ # Command 仅用于类型注解引用,避免 ruff 报未使用导入
231
+ __all__ = ["install_readline_completer", "_import_readline", "_make_completer", "_compute_candidates"]
@@ -0,0 +1,191 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ #
3
+ # Copyright 2026 Precis Team
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ """
17
+ @fileoverview CLI AI 配置存储模块
18
+
19
+ 功能概述:
20
+ - 适配 LLM 配置系统,管理 ~/.precis/ai_providers.yaml
21
+ - 提供 Provider 的增删改查与默认设置切换
22
+ - 支持配置热重载
23
+
24
+ 架构设计:
25
+ - CLIConfigStorage 封装 AIConfig 的加载与持久化
26
+ - 直接使用 AIProvider 模型,与 API 层保持一致
27
+ - 单例模式通过 get_cli_config() 提供全局访问
28
+ """
29
+
30
+ from __future__ import annotations
31
+
32
+ from app.shared.services.llm.config.loader import loader
33
+ from app.shared.services.llm.config.models import AIConfig, AIProvider
34
+
35
+
36
+ class CLIConfigStorage:
37
+ """CLI 配置存储管理类(直接使用 AIProvider 模型)"""
38
+
39
+ def __init__(self) -> None:
40
+ self._config: AIConfig
41
+ self._loaded_mtime: float | None = None
42
+ # §4.2: 启动即 strict——providers YAML 损坏时 fail-fast(明确报错+退出),
43
+ # 不再静默回退空配置(此前 add/save 会把空配置覆盖写盘,原配置彻底销毁)
44
+ self._load(strict=True)
45
+
46
+ def _load(self, strict: bool = False) -> None:
47
+ """从文件加载配置。
48
+
49
+ Args:
50
+ strict: 严格模式。为 True 时解析失败抛携带修复指引的 RuntimeError;
51
+ 为 False(默认)时静默回退到空 AIConfig(运行时 reload 容错语义)。
52
+ """
53
+ try:
54
+ self._config = loader.load()
55
+ try:
56
+ self._loaded_mtime = loader.config_path.stat().st_mtime
57
+ except OSError:
58
+ self._loaded_mtime = None
59
+ except Exception as e:
60
+ if strict:
61
+ # §4.2: 携带文件路径与修复指引的明确错误(调用方以非 0 退出呈现)
62
+ config_path = getattr(loader, "config_path", None)
63
+ raise RuntimeError(
64
+ f"AI Provider 配置文件损坏,已阻止启动以防空配置覆盖写盘:\n"
65
+ f" 文件: {config_path}\n"
66
+ f" 错误: {e}\n"
67
+ f" 修复: 手工修正 YAML 语法后重试;或备份后删除该文件重新 setup"
68
+ ) from e
69
+ self._config = AIConfig()
70
+
71
+ def _save(self) -> None:
72
+ """保存配置到文件。
73
+
74
+ §4.10: 写前 mtime 校验(读-改-写丢更新防护)——本实例加载后文件被其他进程
75
+ (TUI/Electron/另一 CLI 会话)修改过则拒绝写入并提示,避免后写覆盖先写。
76
+ """
77
+ try:
78
+ current_mtime = loader.config_path.stat().st_mtime
79
+ if self._loaded_mtime is not None and current_mtime != self._loaded_mtime:
80
+ raise RuntimeError(
81
+ "配置已被其他进程修改(CLI/TUI/Electron 并发编辑),请重新进入本会话加载最新配置后再修改"
82
+ )
83
+ except OSError:
84
+ pass # 文件尚不存在(首次写入)等场景直接尝试保存
85
+ loader.save(self._config)
86
+ try:
87
+ self._loaded_mtime = loader.config_path.stat().st_mtime
88
+ except OSError:
89
+ self._loaded_mtime = None
90
+
91
+ def get_provider(self, provider_id: str) -> AIProvider | None:
92
+ """获取指定 Provider"""
93
+ for p in self._config.providers:
94
+ if p.id == provider_id:
95
+ return p
96
+ return None
97
+
98
+ def get_active_provider(self) -> AIProvider | None:
99
+ """获取当前活动的 Provider"""
100
+ # 从 defaults 中获取默认 chat provider
101
+ default_id = self._config.defaults.get("chat")
102
+ if default_id:
103
+ return self.get_provider(default_id)
104
+ # 如果没有设置,返回第一个
105
+ if self._config.providers:
106
+ return self._config.providers[0]
107
+ return None
108
+
109
+ def set_active_provider(self, provider_id: str) -> bool:
110
+ """设置活动 Provider"""
111
+ if not any(p.id == provider_id for p in self._config.providers):
112
+ return False
113
+ self._config.defaults["chat"] = provider_id
114
+ self._save()
115
+ return True
116
+
117
+ def add_or_update_provider(self, provider: AIProvider) -> None:
118
+ """添加或更新 Provider"""
119
+ # 查找并替换或添加
120
+ for i, p in enumerate(self._config.providers):
121
+ if p.id == provider.id:
122
+ self._config.providers[i] = provider
123
+ break
124
+ else:
125
+ self._config.providers.append(provider)
126
+
127
+ # 如果是第一个 provider,设为默认
128
+ if len(self._config.providers) == 1:
129
+ self._config.defaults["chat"] = provider.id
130
+
131
+ self._save()
132
+
133
+ def mark_api_key_manual(self, provider_id: str) -> None:
134
+ """把 provider 的 api_key 标记为手工设置(§2.12:save 时不再按 env 来源剔除落盘)。
135
+
136
+ CLI 的 add/edit 路径在用户显式输入 API Key 后、落盘前调用——否则该 provider
137
+ 若存在同名环境变量(<ID>_API_KEY),save() 会把用户刚输入的 key 当 env 来源
138
+ 剔除,新 key 永不落盘(env 移除后 provider 无 key 可用)。
139
+ """
140
+ loader.mark_api_key_manual(provider_id)
141
+
142
+ def list_providers(self) -> list[AIProvider]:
143
+ """列出所有 Providers"""
144
+ return list(self._config.providers)
145
+
146
+ def has_configured_provider(self) -> bool:
147
+ """检查是否有已配置的 Provider(有 API Key)"""
148
+ for p in self._config.providers:
149
+ if p.api_key:
150
+ return True
151
+ return False
152
+
153
+ def delete_provider(self, provider_id: str) -> bool:
154
+ """删除 Provider"""
155
+ original_len = len(self._config.providers)
156
+ self._config.providers = [p for p in self._config.providers if p.id != provider_id]
157
+ if len(self._config.providers) < original_len:
158
+ if self._config.defaults.get("chat") == provider_id:
159
+ self._config.defaults["chat"] = ""
160
+ self._save()
161
+ return True
162
+ return False
163
+
164
+
165
+ # 全局配置存储实例
166
+ _cli_config = None
167
+
168
+
169
+ def get_cli_config() -> CLIConfigStorage:
170
+ """获取 CLI 配置存储实例(单例)"""
171
+ global _cli_config
172
+ if _cli_config is None:
173
+ _cli_config = CLIConfigStorage()
174
+ return _cli_config
175
+
176
+
177
+ def reload_providers_config() -> bool:
178
+ """重新加载 Provider 配置。
179
+
180
+ Returns:
181
+ 重载成功返回 True;配置文件损坏/格式非法导致解析失败时返回 False,
182
+ 调用方据此提示用户检查文件格式(如 provider reload 命令的错误分支)。
183
+ """
184
+ global _cli_config
185
+ if _cli_config:
186
+ loader.invalidate_cache()
187
+ try:
188
+ _cli_config._load(strict=True)
189
+ except Exception:
190
+ return False
191
+ return True
@@ -0,0 +1,90 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ #
3
+ # Copyright 2026 Precis Team
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ # backend/app/cli/shell/exceptions.py
17
+ """
18
+ @fileoverview CLI Shell 自定义异常模块
19
+
20
+ 功能概述:
21
+ - 定义 CLI 交互式界面中使用的自定义异常类型
22
+ - 为不同错误场景提供特定的退出码
23
+ - 所有异常继承自 CLIError 基类
24
+
25
+ 架构设计:
26
+ - CLIError 作为基础异常,包含消息和退出码
27
+ - 派生异常覆盖特定场景:项目未找到、命令未找到、验证失败等
28
+ """
29
+
30
+
31
+ class CLIError(Exception):
32
+ """CLI 基础异常类。"""
33
+
34
+ def __init__(self, message: str, exit_code: int = 1):
35
+ super().__init__(message)
36
+ self.message = message
37
+ self.exit_code = exit_code
38
+
39
+
40
+ class ProjectNotFoundError(CLIError):
41
+ """项目目录未找到异常。"""
42
+
43
+ def __init__(self, path: str):
44
+ super().__init__(f"项目目录未找到: {path}", exit_code=2)
45
+ self.path = path
46
+
47
+
48
+ class InvalidProjectError(CLIError):
49
+ """无效的项目目录异常。"""
50
+
51
+ def __init__(self, path: str, reason: str):
52
+ super().__init__(f"无效的项目目录: {path}, 原因: {reason}", exit_code=3)
53
+ self.path = path
54
+ self.reason = reason
55
+
56
+
57
+ class NoProjectOpenError(CLIError):
58
+ """未打开项目异常。"""
59
+
60
+ def __init__(self) -> None:
61
+ super().__init__("未打开项目,请使用 'open <path>' 命令打开项目", exit_code=4)
62
+
63
+
64
+ class CommandNotFoundError(CLIError):
65
+ """命令未找到异常。"""
66
+
67
+ def __init__(self, command: str):
68
+ super().__init__(f"命令未找到: {command}", exit_code=5)
69
+ self.command = command
70
+
71
+
72
+ class ValidationError(CLIError):
73
+ """验证执行异常。"""
74
+
75
+ def __init__(self, message: str):
76
+ super().__init__(f"验证执行失败: {message}", exit_code=6)
77
+
78
+
79
+ class ConfigError(CLIError):
80
+ """配置文件操作异常。"""
81
+
82
+ def __init__(self, message: str):
83
+ super().__init__(f"配置文件操作失败: {message}", exit_code=7)
84
+
85
+
86
+ class EditorError(CLIError):
87
+ """编辑器调用异常。"""
88
+
89
+ def __init__(self, message: str):
90
+ super().__init__(f"编辑器调用失败: {message}", exit_code=8)