precis-cli 0.1.5__tar.gz → 0.1.6__tar.gz
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.
- {precis_cli-0.1.5 → precis_cli-0.1.6}/MANIFEST.in +0 -1
- {precis_cli-0.1.5/precis_cli.egg-info → precis_cli-0.1.6}/PKG-INFO +1 -1
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shared_services/config_ops.py +52 -19
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shared_services/generation_ops.py +41 -12
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shared_services/project_ops.py +22 -3
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/ai/chat.py +0 -2
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/ai/generate.py +2 -1
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/ai/migrate.py +10 -2
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/ai/switch.py +6 -5
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/config/check.py +8 -3
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/config/edit.py +9 -3
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/config/get.py +5 -5
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/config/set.py +9 -2
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/config/show.py +7 -3
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/validate.py +22 -1
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/formatter.py +16 -8
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/interactive_menu.py +41 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/main.py +13 -6
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/start.py +20 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/mcp_server.py +31 -13
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/loaders/excel_loader.py +99 -15
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/loader/loader_parts/main.py +27 -11
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/utils/path_utils.py +12 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/config/loader.py +10 -23
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/schema_inference.py +37 -17
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/chunked_loader.py +25 -9
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/executor.py +3 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/report_export.py +17 -2
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/resolver.py +26 -1
- {precis_cli-0.1.5 → precis_cli-0.1.6/precis_cli.egg-info}/PKG-INFO +1 -1
- {precis_cli-0.1.5 → precis_cli-0.1.6}/pyproject.toml +1 -4
- {precis_cli-0.1.5 → precis_cli-0.1.6}/PYPI_README.md +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/README.md +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/dependencies.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/main.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/middleware/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/middleware/exception_handler.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/middleware/request_logging.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/middleware/token_auth.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/models/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/models/connection_rules.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/models/files.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/models/full_validation.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/models/project.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/models/projects.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/models/schema.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/models/v2_responses.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/models/validation.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/models/workspace.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/ai/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/ai/chat.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/ai/generate.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/ai/hardware.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/ai/jobs.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/ai/migrate.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/ai/models.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/ai/ollama.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/ai/providers.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/ai/router.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/ai/stream.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/ai/utils.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/core/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/core/connection_rules.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/core/data_sources.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/core/regex.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/core/reporting.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/files/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/files/ops.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/files/transfer.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/preview/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/preview/content_mode.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/preview/header_row.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/preview/models.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/preview/path_mode.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/preview/router.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/project/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/project/base.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/project/constraint.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/project/full_config.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/project/full_config_writer.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/project/helpers.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/project/inspection_fix.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/project/manifest.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/project/models.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/project/pattern.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/project/regex.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/project/scanner.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/project/schema.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/project/schema_helpers.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/project/settings.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/project/template.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/project/validation.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/project/view.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/project/workspaces.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/projects/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/projects/create.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/projects/open.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/projects/scan.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/validation/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/validation/common.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/validation/content_mode.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/validation/history.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/validation/inline_mode.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/validation/path_mode.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/routers/validation/router.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/services/full_validation_response_builder.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/services/io_error_messages.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/api/services/preview_service.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/__main__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shared_services/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/ai/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/ai/delete.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/ai/diff.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/ai/display.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/ai/executor.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/ai/executor_utils.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/ai/interaction.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/ai/resolver.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/ai/status.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/ai/utils.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/base.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/config/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/config/base.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/config/init.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/config/inspect.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/config/list.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/exit.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/help.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/infer_schema.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/open.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/project.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/provider.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/commands/system.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/completer.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/config_storage.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/exceptions.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli/shell/parser.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/cli_main.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/app_version.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/config/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/config/server.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/loader.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/loaders/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/loaders/base.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/loaders/converter.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/loaders/csv_loader.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/loaders/extractor.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/loaders/json_loader.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/loaders/registry.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/loaders/sql_loader.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/loaders/strategies/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/loaders/strategies/array_parser.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/loaders/strategies/lines_parser.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/loaders/strategies/object_parser.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/schema_info.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/specs/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/specs/base.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/specs/csv_source.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/specs/excel_source.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/specs/file_base.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/specs/json_source.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/data_source/specs/sql_source.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/encoding.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/io/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/io/yaml.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/manifest_schema/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/manifest_schema/types.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/manifest_schema/version.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/patterns/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/patterns/loader.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/patterns/writer.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/constraint/builders/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/constraint/builders/base.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/constraint/builders/composite.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/constraint/builders/conditional.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/constraint/builders/foreign_key.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/constraint/builders/registry.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/constraint/builders/scripted.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/constraint/builders/single_column.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/constraint/builders/unique.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/constraint/factory.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/constraint/reader.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/constraint/registry.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/constraint/types/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/constraint/types/constraint_file.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/constraint/types/refs.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/constraint/types.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/constraint/writer.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/loader/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/loader/loader.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/loader/loader_parts/config_inspector.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/loader/loader_parts/embedded_constraints.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/loader/loader_parts/file_loaders.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/loader/loader_parts/inspection_ids.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/loader/loader_parts/inspector_helpers.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/loader/loader_parts/inspector_id_checks.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/loader/loader_parts/inspector_reference_checks.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/loader/loader_parts/inspector_uniqueness_checks.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/loader/loader_parts/loading_error_messages.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/loader/loader_parts/path_validation.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/loader/loader_parts/runtime.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/loader/types.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/manifest/coverage.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/manifest/reader.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/manifest/types.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/manifest/types_parts/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/manifest/types_parts/constants.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/manifest/types_parts/data_source.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/manifest/types_parts/info.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/manifest/types_parts/manifest.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/manifest/types_parts/refs.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/manifest/types_parts/settings.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/manifest/types_parts/settings_file_processing.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/manifest/types_parts/settings_script_security.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/manifest/types_parts/settings_validation.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/manifest/types_parts/template.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/manifest/writer.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/manual_data/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/manual_data/types.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/regex/reader.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/regex/types.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/regex/writer.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/schema/reader.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/schema/types.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/schema/types_parts/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/schema/types_parts/column.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/schema/types_parts/column_utils.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/schema/types_parts/constraint.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/schema/types_parts/schema_id.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/schema/types_parts/source.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/schema/types_parts/source_options.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/schema/types_parts/table.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/schema/writer.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/schema_ref_check.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/template/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/template/expander.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/template/reader.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/template/types.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/transform/reader.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/transform/types.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/project/transform/writer.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/pydantic_messages.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/reporter/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/reporter/reporter.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/reporter/reporters/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/reporter/reporters/base.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/reporter/reporters/dingtalk_app_reporter.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/reporter/reporters/email_reporter.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/reporter/reporters/feishu_app_reporter.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/reporter/reporters/local_file_reporter.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/reporter/reporters/wecom_app_reporter.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/utils/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/core/utils/regex_extract.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/constraints/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/constraints/allowed_values.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/constraints/base.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/constraints/charset.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/constraints/composite.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/constraints/condition_registry.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/constraints/conditional.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/constraints/date_logic.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/constraints/foreign_key.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/constraints/key_normalization.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/constraints/not_null.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/constraints/range.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/constraints/regex.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/constraints/scripted.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/constraints/unique.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/data_engine.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/data_types.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/data_types_parts/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/data_types_parts/base.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/data_types_parts/composite.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/data_types_parts/expression.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/data_types_parts/extracted.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/data_types_parts/json_types.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/data_types_parts/scalars.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/data_types_parts/sequence.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/dataset_schema.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/eval_sandbox.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/expression_system.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/regex_flags.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/schema/builder.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/schema/models.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/aggregate.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/base.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/cast_type.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/concat.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/conditional_assign.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/date_format.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/digits.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/drop_duplicates.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/fill_na.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/filter_rows.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/lookup.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/lower_case.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/map_value.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/math_expr.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/modulo.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/regex_extract.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/registry.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/replace.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/sort_rows.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/string_split.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/strip.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/substring.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/upper_case.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/transforms/weighted_sum.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/domain/validation_constraints.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/agent/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/agent/chat_tools/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/agent/chat_tools/apply_actions.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/agent/chat_tools/ask_user.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/agent/chat_tools/read_canvas.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/agent/chat_tools/read_project.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/agent/chat_tools/read_table.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/agent/chat_tools/schemas.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/agent/chat_tools/validate_table.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/agent/executor.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/agent/memory.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/agent/planner.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/agent/tool_registry.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/agent/tools/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/agent/tools/config_generate.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/agent/tools/config_refine.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/agent/tools/config_validate.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/agent/tools/merge_results.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/agent/tools/plan_chunks.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/agent/tools/script_parse.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/agent/types.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/chat_agent_runner.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/chat_orchestrator.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/failure_messages.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/job_storage.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/migrate_service.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/streaming/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/streaming/event_journal.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/streaming/orchestrator.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/streaming/pending_interaction_store.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/streaming/sse_response.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/streaming/types.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/types.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/ai/utils.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/diff/config_diff.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/hardware.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/actions/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/actions/_canvas_validator.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/actions/_constraint_validator.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/actions/_regex_validator.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/actions/_schema_validator.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/actions/_settings_validator.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/actions/_transform_validator.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/actions/action_handlers.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/actions/action_parser.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/actions/action_processor.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/actions/action_validator.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/actions/diff_compute.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/actions/regex_handlers.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/actions/registry.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/actions/schema_handlers.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/actions/settings_handlers.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/actions/specs.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/actions/transform_handlers.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/actions/validation_types.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/cache/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/cache/response_cache.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/chat/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/chat/chat_system_prompt.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/chat/response_parser.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/config/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/config/crypto.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/config/models.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/config/presets.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/config_generator.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/constraints/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/constraints/constraint_builder.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/constraints/constraint_deletion.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/constraints/constraint_id.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/constraints/frontend_instructions.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/constraints/inline_batch.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/discovery/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/discovery/scanner.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/generation/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/generation/agent_wiring.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/generation/config_builder.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/generation/errors.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/generation/existing_config.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/generation/profiler.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/generation/prompt_builder.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/generation/response_parser.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/generation/service.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/models.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/providers/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/providers/base.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/providers/cached_provider.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/providers/ollama.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/providers/openai.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/providers/registry.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/schema_resolver.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/suggestion_utils.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/validate_executor.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/llm/yaml_io.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/preview/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/preview/loader.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/preview/path_validation.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/project_loader.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/schema_runtime_builder.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/dag/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/dag/builder.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/dag/executor.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/dag/sorter.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/data_loader.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/engine.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/extractors.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/history.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/json_payload.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/loader.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/memory_monitor.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/postprocess.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/progress.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/service.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/types.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/validators/__init__.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/validators/adapter.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/validators/base.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/validators/composite.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/shared/services/validation/validators/date_logic.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/app/start_server.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/precis_cli.egg-info/SOURCES.txt +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/precis_cli.egg-info/dependency_links.txt +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/precis_cli.egg-info/entry_points.txt +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/precis_cli.egg-info/requires.txt +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/precis_cli.egg-info/top_level.txt +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/setup.cfg +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/tests/test_local_file_reporter.py +0 -0
- {precis_cli-0.1.5 → precis_cli-0.1.6}/tests/test_schema_builder.py +0 -0
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
from __future__ import annotations
|
|
42
42
|
|
|
43
43
|
import logging
|
|
44
|
+
import math
|
|
44
45
|
import os
|
|
45
46
|
import tempfile
|
|
46
47
|
from collections.abc import Iterator
|
|
@@ -207,6 +208,10 @@ def resolve_config_file(project_path: str, filename: str | None) -> tuple[str |
|
|
|
207
208
|
def get_by_dotpath(data: dict, key_path: str) -> tuple[bool, Any]:
|
|
208
209
|
"""按点号路径从字典中查找值。
|
|
209
210
|
|
|
211
|
+
YAML 键可为非字符串(如 ``2024:`` 解析为 int、``true:`` 解析为 bool)——
|
|
212
|
+
路径段除精确匹配外也按字符串形态匹配非字符串键,防止"键存在却查不到"
|
|
213
|
+
进而被 set 侧写出同形态影子键。
|
|
214
|
+
|
|
210
215
|
Args:
|
|
211
216
|
data: 配置字典
|
|
212
217
|
key_path: 点号路径,如 "project.name"
|
|
@@ -217,8 +222,16 @@ def get_by_dotpath(data: dict, key_path: str) -> tuple[bool, Any]:
|
|
|
217
222
|
keys = key_path.split(".")
|
|
218
223
|
value: Any = data
|
|
219
224
|
for key in keys:
|
|
220
|
-
if isinstance(value, dict)
|
|
221
|
-
|
|
225
|
+
if isinstance(value, dict):
|
|
226
|
+
if key in value:
|
|
227
|
+
value = value[key]
|
|
228
|
+
continue
|
|
229
|
+
for k, v in value.items():
|
|
230
|
+
if not isinstance(k, str) and str(k) == key:
|
|
231
|
+
value = v
|
|
232
|
+
break
|
|
233
|
+
else:
|
|
234
|
+
return False, None
|
|
222
235
|
else:
|
|
223
236
|
return False, None
|
|
224
237
|
return True, value
|
|
@@ -227,7 +240,8 @@ def get_by_dotpath(data: dict, key_path: str) -> tuple[bool, Any]:
|
|
|
227
240
|
def set_by_dotpath(data: dict, key_path: str, value: Any) -> dict:
|
|
228
241
|
"""按点号路径写入值,返回新 data(不改原 dict)。
|
|
229
242
|
|
|
230
|
-
|
|
243
|
+
中间层级不存在时自动创建空字典;路径段与既有非字符串键(如 int ``2024``)
|
|
244
|
+
字符串形态相同时复用原键,防止写出同形态影子键并存。
|
|
231
245
|
|
|
232
246
|
Args:
|
|
233
247
|
data: 原配置字典(不会被修改)
|
|
@@ -244,10 +258,21 @@ def set_by_dotpath(data: dict, key_path: str, value: Any) -> dict:
|
|
|
244
258
|
keys = key_path.split(".")
|
|
245
259
|
current = new_data
|
|
246
260
|
for key in keys[:-1]:
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
261
|
+
existing = current.get(key)
|
|
262
|
+
if isinstance(existing, dict):
|
|
263
|
+
current = existing
|
|
264
|
+
continue
|
|
265
|
+
# 同形态非字符串键复用(写原键而非另建字符串影子键)
|
|
266
|
+
non_str_key = next((k for k in current if not isinstance(k, str) and str(k) == key), None)
|
|
267
|
+
if non_str_key is not None and isinstance(current[non_str_key], dict):
|
|
268
|
+
current = current[non_str_key]
|
|
269
|
+
continue
|
|
270
|
+
target = non_str_key if non_str_key is not None else key
|
|
271
|
+
current[target] = {}
|
|
272
|
+
current = current[target]
|
|
273
|
+
leaf = keys[-1]
|
|
274
|
+
leaf_key = next((k for k in current if not isinstance(k, str) and str(k) == leaf), leaf)
|
|
275
|
+
current[leaf_key] = value
|
|
251
276
|
return new_data
|
|
252
277
|
|
|
253
278
|
|
|
@@ -267,8 +292,9 @@ def parse_config_value(value_str: str) -> tuple[bool, Any, str]:
|
|
|
267
292
|
value_str: 原始字符串值
|
|
268
293
|
|
|
269
294
|
Returns:
|
|
270
|
-
(成功, 转换后的值, 错误信息)
|
|
271
|
-
|
|
295
|
+
(成功, 转换后的值, 错误信息);毒化字面量(inf/nan/下划线整数等
|
|
296
|
+
无法被下游安全消费的数值形态)返回 (False, None, 错误信息),
|
|
297
|
+
调用方应拒绝落盘。
|
|
272
298
|
"""
|
|
273
299
|
# 尝试布尔值
|
|
274
300
|
if value_str.lower() == "true":
|
|
@@ -278,17 +304,24 @@ def parse_config_value(value_str: str) -> tuple[bool, Any, str]:
|
|
|
278
304
|
if value_str.lower() == "null" or value_str.lower() == "none":
|
|
279
305
|
return True, None, ""
|
|
280
306
|
|
|
281
|
-
#
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
307
|
+
# 尝试整数:拒绝 Python 下划线字面量('1_0' 静默变 10 会毒化下游数值读取)
|
|
308
|
+
if "_" not in value_str:
|
|
309
|
+
try:
|
|
310
|
+
return True, int(value_str), ""
|
|
311
|
+
except ValueError:
|
|
312
|
+
pass
|
|
286
313
|
|
|
287
|
-
#
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
314
|
+
# 尝试浮点数:拒绝非有限值(inf/nan/溢出 1e999)与下划线字面量——
|
|
315
|
+
# timeout_seconds: .inf 落盘后 validate 侧 int(inf) 抛 OverflowError,项目从此无法校验
|
|
316
|
+
if "_" not in value_str:
|
|
317
|
+
try:
|
|
318
|
+
parsed_float = float(value_str)
|
|
319
|
+
except ValueError:
|
|
320
|
+
parsed_float = None
|
|
321
|
+
if parsed_float is not None:
|
|
322
|
+
if not math.isfinite(parsed_float):
|
|
323
|
+
return False, None, f"不接受非有限数值: {value_str}(inf/nan 落盘会使项目无法校验)"
|
|
324
|
+
return True, parsed_float, ""
|
|
292
325
|
|
|
293
326
|
# 去除引号
|
|
294
327
|
if (value_str.startswith('"') and value_str.endswith('"')) or (
|
|
@@ -36,6 +36,7 @@ from __future__ import annotations
|
|
|
36
36
|
import glob
|
|
37
37
|
import logging
|
|
38
38
|
import os
|
|
39
|
+
import re
|
|
39
40
|
from pathlib import Path
|
|
40
41
|
from typing import Any
|
|
41
42
|
|
|
@@ -46,6 +47,25 @@ logger = logging.getLogger(__name__)
|
|
|
46
47
|
# 支持的文件扩展名(generate/migrate 共用)
|
|
47
48
|
SUPPORTED_EXTENSIONS = (".xlsx", ".xls", ".csv", ".json", ".jsonl")
|
|
48
49
|
|
|
50
|
+
# 实体 id 安全白名单:字母/数字/下划线/连字符(H10——LLM 生成的 id 未消毒即拼盘
|
|
51
|
+
# 路径时,`../../evil` 类路径成分可越项目写文件/建目录,写盘前须拒绝)
|
|
52
|
+
_SAFE_ENTITY_ID_RE = re.compile(r"[A-Za-z0-9_-]+")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _filter_safe_entity_ids(entities: dict[str, Any], kind: str) -> dict[str, Any]:
|
|
56
|
+
"""过滤掉含路径成分或非法字符的实体 id,记录错误日志(H10)。
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
仅保留安全 id 的实体字典;非法 id 整体跳过(不写盘、不进 manifest 引用)
|
|
60
|
+
"""
|
|
61
|
+
safe: dict[str, Any] = {}
|
|
62
|
+
for eid, body in entities.items():
|
|
63
|
+
if isinstance(eid, str) and _SAFE_ENTITY_ID_RE.fullmatch(eid):
|
|
64
|
+
safe[eid] = body
|
|
65
|
+
else:
|
|
66
|
+
logger.error("跳过非法实体 id(含路径成分或非法字符,kind=%s): %r", kind, eid)
|
|
67
|
+
return safe
|
|
68
|
+
|
|
49
69
|
|
|
50
70
|
def scan_data_files(patterns: list[str], project_path: str) -> list[str]:
|
|
51
71
|
"""展开数据文件路径(支持通配符、相对路径、data/ 目录扫描)。
|
|
@@ -91,8 +111,9 @@ def scan_data_files(patterns: list[str], project_path: str) -> list[str]:
|
|
|
91
111
|
def apply_generated_config(result: dict[str, Any], project_path: str) -> list[str]:
|
|
92
112
|
"""将生成的配置写入项目目录。
|
|
93
113
|
|
|
94
|
-
|
|
95
|
-
|
|
114
|
+
保留策略为并集(R6):生成 manifest 未携带的既有顶层键(project/settings/
|
|
115
|
+
templates/data_sources 等)一律保留,防止空/局部 manifest 清空既有配置;
|
|
116
|
+
schemas、constraints、regex_nodes 引用则始终按生成结果覆盖写入。
|
|
96
117
|
|
|
97
118
|
Args:
|
|
98
119
|
result: ConfigGenerationService / ConfigMigrationService 返回的配置字典
|
|
@@ -111,16 +132,24 @@ def apply_generated_config(result: dict[str, Any], project_path: str) -> list[st
|
|
|
111
132
|
except Exception:
|
|
112
133
|
logger.warning("读取现有 manifest 失败,将覆盖写入", exc_info=True)
|
|
113
134
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
135
|
+
generated_manifest = result.get("manifest")
|
|
136
|
+
if generated_manifest:
|
|
137
|
+
manifest = dict(generated_manifest)
|
|
138
|
+
else:
|
|
139
|
+
# LLM 未返回 manifest:以现有 manifest 为底仅补最小骨架,
|
|
140
|
+
# 不再制造空 project 兜底清空既有 project.id/settings(R6)
|
|
141
|
+
manifest = dict(existing_manifest)
|
|
142
|
+
manifest.setdefault("version", 2)
|
|
143
|
+
manifest.setdefault("project", {"id": "", "name": ""})
|
|
144
|
+
|
|
145
|
+
# 保留策略并集(R6):生成 manifest 未携带的既有键一律保留
|
|
146
|
+
for key, value in existing_manifest.items():
|
|
147
|
+
if key not in manifest:
|
|
148
|
+
manifest[key] = value
|
|
149
|
+
|
|
150
|
+
schemas = _filter_safe_entity_ids(result.get("schemas", {}) or {}, "schema")
|
|
151
|
+
constraints = _filter_safe_entity_ids(result.get("constraints", {}) or {}, "constraint")
|
|
152
|
+
regex_nodes = _filter_safe_entity_ids(result.get("regex_nodes", {}) or {}, "regex")
|
|
124
153
|
|
|
125
154
|
# 确保目录存在
|
|
126
155
|
(Path(project_path) / "schemas").mkdir(exist_ok=True)
|
|
@@ -51,10 +51,25 @@ HISTORY_FILE = os.path.expanduser("~/.precis_project_history")
|
|
|
51
51
|
MAX_HISTORY = 10
|
|
52
52
|
|
|
53
53
|
|
|
54
|
+
def _backup_corrupt_history() -> None:
|
|
55
|
+
"""把损坏的历史文件改名备份(.corrupt.bak),失败仅记日志。
|
|
56
|
+
|
|
57
|
+
原实现在 JSON 损坏后静默按空历史继续——下次保存直接覆盖,
|
|
58
|
+
用户历史不可恢复;备份保留现场供手工抢救。
|
|
59
|
+
"""
|
|
60
|
+
try:
|
|
61
|
+
backup = f"{HISTORY_FILE}.corrupt.bak"
|
|
62
|
+
os.replace(HISTORY_FILE, backup)
|
|
63
|
+
logger.warning("项目历史文件损坏,已备份到 %s 并从空历史继续", backup)
|
|
64
|
+
except OSError:
|
|
65
|
+
logger.error("备份损坏的项目历史文件失败: %s", HISTORY_FILE, exc_info=True)
|
|
66
|
+
|
|
67
|
+
|
|
54
68
|
def load_history() -> list[dict]:
|
|
55
69
|
"""加载项目打开历史。
|
|
56
70
|
|
|
57
71
|
从 HISTORY_FILE 读取历史记录。文件不存在、格式损坏或权限不足时返回空列表。
|
|
72
|
+
JSON 损坏时先把原文件备份为 ``*.corrupt.bak`` 再按空历史继续(不静默清零)。
|
|
58
73
|
|
|
59
74
|
Returns:
|
|
60
75
|
历史记录列表,每个元素为包含 path 和 last_opened 的字典
|
|
@@ -78,7 +93,8 @@ def load_history() -> list[dict]:
|
|
|
78
93
|
return valid
|
|
79
94
|
return []
|
|
80
95
|
except json.JSONDecodeError:
|
|
81
|
-
# JSON
|
|
96
|
+
# JSON 格式损坏:备份后按空历史继续
|
|
97
|
+
_backup_corrupt_history()
|
|
82
98
|
return []
|
|
83
99
|
except PermissionError:
|
|
84
100
|
# 无权限读取,返回空列表
|
|
@@ -91,7 +107,8 @@ def load_history() -> list[dict]:
|
|
|
91
107
|
def _save_history(history: list[dict]) -> None:
|
|
92
108
|
"""保存项目打开历史。
|
|
93
109
|
|
|
94
|
-
|
|
110
|
+
原子写(临时文件 + os.replace):进程中断不会留下半截 JSON——
|
|
111
|
+
半截文件在下次 load 即被判损坏。保存失败仅记录日志,不阻断主流程。
|
|
95
112
|
|
|
96
113
|
Args:
|
|
97
114
|
history: 历史记录列表
|
|
@@ -99,8 +116,10 @@ def _save_history(history: list[dict]) -> None:
|
|
|
99
116
|
try:
|
|
100
117
|
# 确保目录存在(用户主目录)
|
|
101
118
|
os.makedirs(os.path.dirname(HISTORY_FILE), exist_ok=True)
|
|
102
|
-
|
|
119
|
+
tmp_file = f"{HISTORY_FILE}.tmp"
|
|
120
|
+
with open(tmp_file, "w", encoding="utf-8") as f:
|
|
103
121
|
json.dump(history, f, ensure_ascii=False, indent=2)
|
|
122
|
+
os.replace(tmp_file, HISTORY_FILE)
|
|
104
123
|
except (PermissionError, OSError):
|
|
105
124
|
# 保存失败时记录错误日志,但不阻断主流程
|
|
106
125
|
logger.error("保存项目历史记录失败", exc_info=True)
|
|
@@ -53,6 +53,7 @@ from app.cli.shared_services.generation_ops import (
|
|
|
53
53
|
)
|
|
54
54
|
from app.cli.shell.commands.base import Command, CommandResult, ProjectContext
|
|
55
55
|
from app.cli.shell.formatter import Formatter
|
|
56
|
+
from app.shared.core.utils.path_utils import display_relpath
|
|
56
57
|
from app.shared.services.llm.generation import (
|
|
57
58
|
ConfigGenerationService,
|
|
58
59
|
GenerationOptions,
|
|
@@ -200,7 +201,7 @@ class AIGenerateCommand(Command):
|
|
|
200
201
|
print(Formatter.info(f"迭代次数: {max_iterations}"))
|
|
201
202
|
print(Formatter.info("数据文件:"))
|
|
202
203
|
for p in file_paths:
|
|
203
|
-
print(f" - {
|
|
204
|
+
print(f" - {display_relpath(p, project_path)}")
|
|
204
205
|
|
|
205
206
|
def progress_callback(stage: str, progress: float, extra: dict[str, Any] | None = None) -> None:
|
|
206
207
|
"""终端进度回调。"""
|
|
@@ -51,6 +51,7 @@ from app.cli.shared_services.generation_ops import (
|
|
|
51
51
|
)
|
|
52
52
|
from app.cli.shell.commands.base import Command, CommandResult, ProjectContext
|
|
53
53
|
from app.cli.shell.formatter import Formatter
|
|
54
|
+
from app.shared.core.utils.path_utils import display_relpath
|
|
54
55
|
from app.shared.services.ai.migrate_service import ConfigMigrationService
|
|
55
56
|
from app.shared.services.llm.generation import (
|
|
56
57
|
GenerationOptions,
|
|
@@ -72,6 +73,10 @@ def _infer_language(file_path: str) -> str:
|
|
|
72
73
|
return "natural_language"
|
|
73
74
|
|
|
74
75
|
|
|
76
|
+
# --language 可选值(与 usage 声明一致)
|
|
77
|
+
_SUPPORTED_LANGUAGES = ("python", "sql", "excel_formula", "natural_language")
|
|
78
|
+
|
|
79
|
+
|
|
75
80
|
class AIMigrateCommand(Command):
|
|
76
81
|
"""AI 配置迁移命令。
|
|
77
82
|
|
|
@@ -171,6 +176,9 @@ class AIMigrateCommand(Command):
|
|
|
171
176
|
|
|
172
177
|
if language is None:
|
|
173
178
|
language = _infer_language(script_path)
|
|
179
|
+
elif language not in _SUPPORTED_LANGUAGES:
|
|
180
|
+
# 枚举校验:非法值前置拒绝(usage 已声明可选值),不透传下游晦涩报错
|
|
181
|
+
return CommandResult.error(f"--language 仅支持 {'|'.join(_SUPPORTED_LANGUAGES)},收到: {language}")
|
|
174
182
|
|
|
175
183
|
try:
|
|
176
184
|
with open(script_path, encoding="utf-8") as f:
|
|
@@ -202,10 +210,10 @@ class AIMigrateCommand(Command):
|
|
|
202
210
|
|
|
203
211
|
print(Formatter.header("\nAI 配置迁移"))
|
|
204
212
|
print(Formatter.info(f"项目: {project_name}"))
|
|
205
|
-
print(Formatter.info(f"脚本: {
|
|
213
|
+
print(Formatter.info(f"脚本: {display_relpath(script_path, project_path)} ({language})"))
|
|
206
214
|
print(Formatter.info("数据文件:"))
|
|
207
215
|
for p in file_paths:
|
|
208
|
-
print(f" - {
|
|
216
|
+
print(f" - {display_relpath(p, project_path)}")
|
|
209
217
|
|
|
210
218
|
def progress_callback(stage: str, progress: float, extra: dict[str, Any] | None = None) -> None:
|
|
211
219
|
"""终端进度回调。"""
|
|
@@ -58,19 +58,20 @@ class AISwitchCommand(Command):
|
|
|
58
58
|
|
|
59
59
|
@property
|
|
60
60
|
def usage(self) -> str:
|
|
61
|
-
return "ai switch
|
|
61
|
+
return "ai switch [provider_id]"
|
|
62
62
|
|
|
63
63
|
@property
|
|
64
64
|
def help_text(self) -> str:
|
|
65
65
|
return """
|
|
66
|
-
用法: ai switch
|
|
66
|
+
用法: ai switch [provider_id]
|
|
67
67
|
|
|
68
68
|
示例:
|
|
69
|
-
ai switch
|
|
70
|
-
ai switch
|
|
69
|
+
ai switch # 交互式选择 Provider(方向键导航)
|
|
70
|
+
ai switch openai # 切换到 OpenAI
|
|
71
|
+
ai switch kimi # 切换到 Kimi
|
|
71
72
|
|
|
72
73
|
说明:
|
|
73
|
-
|
|
74
|
+
缺省参数时进入交互式选择;传入 provider_id 时直接切换(大小写不敏感)。
|
|
74
75
|
使用 'ai status' 查看可用的 Provider。
|
|
75
76
|
""".strip()
|
|
76
77
|
|
|
@@ -104,8 +104,11 @@ class ConfigCheckCommand(Command):
|
|
|
104
104
|
# 否则验证所有 YAML 文件
|
|
105
105
|
all_files = []
|
|
106
106
|
for root, _, files in os.walk(project_path):
|
|
107
|
-
#
|
|
108
|
-
|
|
107
|
+
# 跳过项目内的隐藏子目录(.git 等)——以项目根为基准算相对路径,
|
|
108
|
+
# 项目自身位于隐藏目录时不受影响(原实现按绝对路径分段判断,
|
|
109
|
+
# 根目录含点前缀时整个 walk 被跳过,0 文件假绿)
|
|
110
|
+
rel_root = os.path.relpath(root, project_path)
|
|
111
|
+
if rel_root != "." and any(part.startswith(".") for part in rel_root.split(os.sep)):
|
|
109
112
|
continue
|
|
110
113
|
for f in files:
|
|
111
114
|
if f.endswith((".yaml", ".yml")):
|
|
@@ -145,7 +148,9 @@ class ConfigCheckCommand(Command):
|
|
|
145
148
|
return CommandResult.ok(f"✓ 所有 {valid_count} 个配置文件格式正确")
|
|
146
149
|
|
|
147
150
|
# 有错误时只显示错误文件(除非指定 --all)
|
|
148
|
-
|
|
151
|
+
# 注意:文案不再内嵌 [bold] 等 rich 标记——CommandResult.error 经
|
|
152
|
+
# Formatter.print_error 统一转义渲染,内嵌标记会以字面量呈现
|
|
153
|
+
output_lines = [f"\n发现 {invalid_count} 个配置文件格式错误:"]
|
|
149
154
|
output_lines.extend(results)
|
|
150
155
|
if show_all:
|
|
151
156
|
output_lines.append(f"\n总计: {valid_count} 个有效, {invalid_count} 个无效")
|
|
@@ -86,8 +86,9 @@ class ConfigEditCommand(Command):
|
|
|
86
86
|
# 列出可用的配置文件
|
|
87
87
|
available = []
|
|
88
88
|
for root, _, files in os.walk(project_path):
|
|
89
|
-
#
|
|
90
|
-
|
|
89
|
+
# 跳过项目内的隐藏子目录(以项目根为基准,同 config check 修法)
|
|
90
|
+
rel_root = os.path.relpath(root, project_path)
|
|
91
|
+
if rel_root != "." and any(part.startswith(".") for part in rel_root.split(os.sep)):
|
|
91
92
|
continue
|
|
92
93
|
for f in files:
|
|
93
94
|
if f.endswith((".yaml", ".yml")):
|
|
@@ -103,8 +104,13 @@ class ConfigEditCommand(Command):
|
|
|
103
104
|
editor = self._get_editor()
|
|
104
105
|
|
|
105
106
|
try:
|
|
107
|
+
# EDITOR/VISUAL 可含参数(如 "code -w"、"vim -f")——shlex 拆分后拼接,
|
|
108
|
+
# 原样整体当可执行名会在含空格/参数时 FileNotFoundError
|
|
109
|
+
import shlex
|
|
110
|
+
|
|
111
|
+
editor_cmd = shlex.split(editor, posix=(sys.platform != "win32"))
|
|
106
112
|
result = subprocess.run(
|
|
107
|
-
[
|
|
113
|
+
[*editor_cmd, config_path],
|
|
108
114
|
cwd=project_path,
|
|
109
115
|
)
|
|
110
116
|
|
|
@@ -34,11 +34,9 @@
|
|
|
34
34
|
CommandResult.error("配置项不存在: project.unknown")
|
|
35
35
|
"""
|
|
36
36
|
|
|
37
|
-
import os
|
|
38
|
-
|
|
39
37
|
import yaml
|
|
40
38
|
|
|
41
|
-
from app.cli.shared_services.config_ops import get_by_dotpath
|
|
39
|
+
from app.cli.shared_services.config_ops import find_config_file, get_by_dotpath
|
|
42
40
|
from app.cli.shell.commands.base import Command, CommandResult, ProjectContext
|
|
43
41
|
|
|
44
42
|
|
|
@@ -80,9 +78,11 @@ class ConfigGetCommand(Command):
|
|
|
80
78
|
|
|
81
79
|
config_file = args[0]
|
|
82
80
|
key_path = args[1]
|
|
83
|
-
|
|
81
|
+
# 穿越防护与族内其他命令(show/set/check)同源:find_config_file
|
|
82
|
+
# 统一拒绝绝对路径/.. 引用并做文件名递归回退(原裸 join 是族内唯一残留)
|
|
83
|
+
config_path = find_config_file(project_path, config_file)
|
|
84
84
|
|
|
85
|
-
if not
|
|
85
|
+
if not config_path:
|
|
86
86
|
return CommandResult.error(f"配置文件不存在: {config_file}")
|
|
87
87
|
|
|
88
88
|
try:
|
|
@@ -39,6 +39,8 @@
|
|
|
39
39
|
CommandResult.error("配置文件不存在: project.precis.yaml")
|
|
40
40
|
"""
|
|
41
41
|
|
|
42
|
+
from typing import Any
|
|
43
|
+
|
|
42
44
|
from app.cli.shared_services.config_ops import (
|
|
43
45
|
MATCH_BASENAME,
|
|
44
46
|
parse_config_value,
|
|
@@ -98,8 +100,13 @@ class ConfigSetCommand(Command):
|
|
|
98
100
|
value_str = raw_args[2]
|
|
99
101
|
|
|
100
102
|
# 解析值(委托 shared_services 纯逻辑,CLI/TUI 同源)
|
|
101
|
-
#
|
|
102
|
-
|
|
103
|
+
# 毒化字面量(inf/nan/下划线整数)被拒绝时按参数错误处理,不落盘
|
|
104
|
+
if as_string:
|
|
105
|
+
value: Any = value_str
|
|
106
|
+
else:
|
|
107
|
+
parse_ok, value, parse_error = parse_config_value(value_str)
|
|
108
|
+
if not parse_ok:
|
|
109
|
+
return CommandResult.error(parse_error)
|
|
103
110
|
|
|
104
111
|
# 定位结果(用于文件名模糊回退命中时披露实际写入路径)
|
|
105
112
|
resolved_path, match_kind = resolve_config_file(project_path, config_file)
|
|
@@ -126,7 +126,7 @@ class ConfigShowCommand(Command):
|
|
|
126
126
|
return CommandResult.ok("\n".join(output_lines))
|
|
127
127
|
|
|
128
128
|
def _show_single_file(self, config_path: str, config_file: str) -> CommandResult:
|
|
129
|
-
"""
|
|
129
|
+
"""显示单个配置文件(原文输出,H11)。
|
|
130
130
|
|
|
131
131
|
Args:
|
|
132
132
|
config_path: 文件的完整路径
|
|
@@ -134,14 +134,18 @@ class ConfigShowCommand(Command):
|
|
|
134
134
|
|
|
135
135
|
Returns:
|
|
136
136
|
文件内容或错误提示
|
|
137
|
+
|
|
138
|
+
H11:过去用 PyYAML safe_load+dump 有损重序列化(注释全丢、`007`→`7`),
|
|
139
|
+
与无参模式/`--string` 的"原样呈现"承诺三方不一致。改为直接读原文输出,
|
|
140
|
+
与无参模式的 _show_file 同口径。
|
|
137
141
|
"""
|
|
138
142
|
try:
|
|
139
143
|
with open(config_path, encoding="utf-8") as f:
|
|
140
|
-
|
|
144
|
+
raw_text = f.read()
|
|
141
145
|
|
|
142
146
|
output_lines = [
|
|
143
147
|
Formatter.header(f"\n{config_file}"),
|
|
144
|
-
|
|
148
|
+
raw_text,
|
|
145
149
|
]
|
|
146
150
|
return CommandResult.ok("\n".join(output_lines))
|
|
147
151
|
except yaml.YAMLError as e:
|
|
@@ -111,6 +111,21 @@ def _parse_standalone_args(args: list[str]) -> dict:
|
|
|
111
111
|
return result
|
|
112
112
|
|
|
113
113
|
|
|
114
|
+
def _find_dangling_option(args: list[str]) -> str | None:
|
|
115
|
+
"""检测缺值的 standalone 选项(尾部悬挂或值位置是下一个选项)。
|
|
116
|
+
|
|
117
|
+
`validate --table`(尾部悬挂)过去被静默忽略 → 变全表校验;
|
|
118
|
+
`validate --table --format json` 的值位被下一个选项占据时同理。
|
|
119
|
+
返回首个悬挂选项名(无则 None),供调用方报参数错误。
|
|
120
|
+
"""
|
|
121
|
+
for i, arg in enumerate(args):
|
|
122
|
+
if arg not in _STANDALONE_OPTIONS:
|
|
123
|
+
continue
|
|
124
|
+
if i + 1 >= len(args) or args[i + 1] in _STANDALONE_OPTIONS:
|
|
125
|
+
return arg
|
|
126
|
+
return None
|
|
127
|
+
|
|
128
|
+
|
|
114
129
|
def _split_positional_args(args: list[str]) -> list[str]:
|
|
115
130
|
"""剥离 args 中的选项及选项值,返回剩余位置参数。
|
|
116
131
|
|
|
@@ -183,6 +198,10 @@ class ValidateCommand(Command):
|
|
|
183
198
|
"""
|
|
184
199
|
# 检测是否为 standalone 模式
|
|
185
200
|
parsed = _parse_standalone_args(args)
|
|
201
|
+
# 尾部悬挂选项(缺值)前置拒绝:防 `validate --table` 静默降级为全表校验
|
|
202
|
+
dangling = _find_dangling_option(args)
|
|
203
|
+
if dangling:
|
|
204
|
+
return CommandResult.error(f"{dangling} 需要参数值\n用法: {self.usage}", exit_code=2)
|
|
186
205
|
if parsed["manifest"] is not None:
|
|
187
206
|
return self._execute_standalone(parsed)
|
|
188
207
|
|
|
@@ -203,7 +222,9 @@ class ValidateCommand(Command):
|
|
|
203
222
|
"""
|
|
204
223
|
project_path = context.project_path
|
|
205
224
|
if project_path is None:
|
|
206
|
-
|
|
225
|
+
# 使用错误(未打开项目)对齐 standalone 各错误路径的 exit_code=2 契约,
|
|
226
|
+
# 避免 CI 按 0/1/2 分流把工具错误误判为"发现数据违规"
|
|
227
|
+
return CommandResult.error("未打开项目,请先使用 'open <path>' 命令打开项目", exit_code=2)
|
|
207
228
|
|
|
208
229
|
# 表名过滤来源优先级:--table/-t 选项 > 首个位置参数 > None(校验全部)
|
|
209
230
|
# 位置参数须先剥离选项及选项值,否则 `validate --table users` 会把 "--table" 当表名
|
|
@@ -251,11 +251,19 @@ class Formatter:
|
|
|
251
251
|
|
|
252
252
|
for i, error in enumerate(errors, 1):
|
|
253
253
|
error_type = error.get("error_type", "UnknownError")
|
|
254
|
-
|
|
254
|
+
# 双字段兼容:格式检查/约束错误经 service 层归一为 cell_value/error_message,
|
|
255
|
+
# 部分内部路径仍产 value/message(对齐 json_payload.py 的兼容读取)
|
|
256
|
+
message = error.get("message")
|
|
257
|
+
if message is None:
|
|
258
|
+
message = error.get("error_message")
|
|
259
|
+
if message is None:
|
|
260
|
+
message = "无错误信息"
|
|
255
261
|
table_name = error.get("table", "")
|
|
256
262
|
column = error.get("column", "")
|
|
257
263
|
row_index = error.get("row_index")
|
|
258
264
|
value = error.get("value")
|
|
265
|
+
if value is None:
|
|
266
|
+
value = error.get("cell_value")
|
|
259
267
|
|
|
260
268
|
type_display = error_type.replace("Violation", "").replace("Error", "")
|
|
261
269
|
type_color = "red" if "Violation" in error_type else "yellow"
|
|
@@ -263,15 +271,15 @@ class Formatter:
|
|
|
263
271
|
lines.append(f" [bold][{i}][/bold] [{type_color}]【{type_display}】[/{type_color}]")
|
|
264
272
|
|
|
265
273
|
if table_name:
|
|
266
|
-
lines.append(f" 表: [cyan]{table_name}[/cyan]")
|
|
274
|
+
lines.append(f" 表: [cyan]{markup_escape(str(table_name))}[/cyan]")
|
|
267
275
|
if column:
|
|
268
|
-
lines.append(f" 列: [cyan]{column}[/cyan]")
|
|
276
|
+
lines.append(f" 列: [cyan]{markup_escape(str(column))}[/cyan]")
|
|
269
277
|
if row_index is not None:
|
|
270
278
|
lines.append(f" 行号: [cyan]{row_index}[/cyan]")
|
|
271
279
|
if value is not None:
|
|
272
|
-
lines.append(f" 值: [yellow]{value}[/yellow]")
|
|
280
|
+
lines.append(f" 值: [yellow]{markup_escape(str(value))}[/yellow]")
|
|
273
281
|
|
|
274
|
-
lines.append(f" [dim]消息:[/dim] {message}")
|
|
282
|
+
lines.append(f" [dim]消息:[/dim] {markup_escape(str(message))}")
|
|
275
283
|
lines.append("")
|
|
276
284
|
|
|
277
285
|
lines.append("[cyan]" + "═" * 60 + "[/cyan]")
|
|
@@ -315,8 +323,8 @@ class Formatter:
|
|
|
315
323
|
ds = (raw_datasets or {}).get(table)
|
|
316
324
|
row_count = len(ds) if ds is not None and hasattr(ds, "__len__") else "-"
|
|
317
325
|
source = fc.get("source_file") or ""
|
|
318
|
-
src_hint = f" [dim]({source})[/dim]" if source else ""
|
|
319
|
-
table_lines.append(f" {bullet} {table}: {row_count} 行{src_hint}")
|
|
326
|
+
src_hint = f" [dim]({markup_escape(str(source))})[/dim]" if source else ""
|
|
327
|
+
table_lines.append(f" {bullet} {markup_escape(str(table))}: {row_count} 行{src_hint}")
|
|
320
328
|
tables_block = "\n".join(table_lines) if table_lines else " (无)"
|
|
321
329
|
|
|
322
330
|
# ---- 约束检查统计 ----
|
|
@@ -353,7 +361,7 @@ class Formatter:
|
|
|
353
361
|
tag = f"[green]{mark_ok}[/green]" if passed else f"[red]{mark_fail}[/red]"
|
|
354
362
|
err_cnt = c.get("error_count", 0)
|
|
355
363
|
err_hint = f" [red]({err_cnt} 错误)[/red]" if err_cnt else ""
|
|
356
|
-
lines.append(f" {bullet} {desc} {tag}{err_hint}")
|
|
364
|
+
lines.append(f" {bullet} {markup_escape(str(desc))} {tag}{err_hint}")
|
|
357
365
|
|
|
358
366
|
return "\n".join(lines)
|
|
359
367
|
|