imperal-sdk 6.0.2__tar.gz → 6.1.0__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.
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/CHANGELOG.md +8 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/PKG-INFO +10 -1
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/pyproject.toml +12 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/sdk-reference.json +1 -1
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/sdk_claims.json +1 -1
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/__init__.py +1 -1
- imperal_sdk-6.1.0/src/imperal_sdk/code_index.py +429 -0
- imperal_sdk-6.1.0/tests/test_code_index_contracts.py +82 -0
- imperal_sdk-6.1.0/tests/test_code_index_indexer.py +53 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/.cm.txt +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/.github/workflows/identity-contract.yml +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/.github/workflows/publish.yml +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/.github/workflows/test.yml +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/.gitignore +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/LICENSE +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/README.md +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/docs/sdl-facets.md +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/sdl_roles.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/.codebase-index-cache.pkl +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/_gateway.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/_http_retry.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/_shared_http.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/adversarial_oracle.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ai/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ai/client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/app.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/apps/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/apps/client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/auth/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/auth/client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/auth/middleware.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/auto_ui.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/billing/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/billing/client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/bom_extractor.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/cache/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/cache/client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/cache/protocol.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/catalog.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/chat/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/chat/action_result.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/chat/error_codes.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/chat/exceptions.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/chat/extension.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/chat/filters.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/chat/guards.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/chat/kernel_primitives.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/chat/narration.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/chat/narration_guard.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/chat/prompt.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/chat/refusal.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/cli/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/cli/linter.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/cli/main.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/config/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/config/client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/context.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/conversations/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/conversations/client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/core.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/cross_surface_bus.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/devtools/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/devtools/contract_checks.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/devtools/generate_api_surface.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/devtools/generate_reference.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/devtools/generate_sdk_claims.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/devtools/reference/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/devtools/reference/_flags.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/devtools/reference/_introspect.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/devtools/reference/client_methods.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/devtools/reference/dataclasses_kind.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/devtools/reference/decorators.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/devtools/reference/sdl_funcs.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/devtools/reference/sdl_roles.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/devtools/reference/ui_components.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/devtools/validate_identity_contract.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/errors.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/extension.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/extensions/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/extensions/client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/gnc_guard.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/http/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/http/client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ir/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ir/_impl.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ir/actions.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ir/custom_roles.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ir/migrate.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ir/produce.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ir/schema.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ir/skeleton.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ir/ui.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ir/ui_children.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ir/ui_template.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ir/validator.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/manifest.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/manifest_schema.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/manifest_schema_ui.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/notify/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/notify/client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/oauth_state.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/oauth_tokens.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/pipes.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/prompts/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/prompts/icnli_integrity_rules.txt +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/prompts/kernel_formatting_rule.txt +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/prompts/kernel_proactivity_rule.txt +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/protocols.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/rbac/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/rbac/client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/rpc/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/rpc/codec.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/rpc/contract.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/runtime/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/runtime/_platform.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/runtime/canon.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/runtime/engine.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/runtime/executor.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/runtime/hosted_client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/runtime/interpreter.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/runtime/llm_provider.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/runtime/local_engine.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/runtime/message_adapter.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/runtime/template.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/runtime/verbs.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schema/marathon_ram.sql +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/action_result.schema.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/actions/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/actions/ai_complete.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/actions/call.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/actions/conditional.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/actions/navigate.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/actions/open.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/actions/send.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/actions/store_create.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/actions/store_delete.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/actions/store_get.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/actions/store_list.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/actions/store_update.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/balance_info.schema.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/chat_result.schema.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/completion_result.schema.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/document.schema.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/event.schema.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/file_info.schema.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/function_call.schema.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/http_response.schema.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/imperal.schema.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/ir.schema.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/limits_result.schema.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/metered_event.schema.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/subscription_info.schema.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/ui_children/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/ui_children/accordion.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/ui_children/datatable_columns.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/ui_children/datatable_rows.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/ui_children/menu.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/ui_children/select.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/ui_children/tabs.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/ui_children/timeline.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/schemas/ui_children/tree.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/_generate_roles_json.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/entity.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/facet_resolve.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/facets/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/facets/catalog.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/facets/comm.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/facets/content.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/facets/device.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/facets/event.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/facets/geo.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/facets/identity.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/facets/media.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/facets/metric.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/facets/money.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/facets/net.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/facets/people.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/facets/quantity.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/facets/rating.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/facets/security.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/facets/task.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/facets/time.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/field.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/sdl/roles.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/search.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/secrets/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/secrets/client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/secrets/exceptions.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/secrets/panel_handler.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/secrets/spec.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/security/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/security/call_token.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/security/deactivation_guard.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/signals/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/signals/client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/skeleton/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/skeleton/client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/storage/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/storage/client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/store/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/store/client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/store/exceptions.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/testing/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/testing/autonomous_mock.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/testing/mock_context.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/testing/mock_secrets.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/transport.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/typed_context.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/types/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/types/action_result.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/types/chat_result.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/types/client_contracts.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/types/contracts.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/types/contributions.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/types/events.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/types/health.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/types/identity.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/types/metered_event.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/types/models.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/types/pagination.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/types/store_contracts.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ui/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ui/actions.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ui/base.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ui/canvas.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ui/data.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ui/display.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ui/feedback.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ui/graph.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ui/input_components.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ui/interactive.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ui/layout.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ui/liquid.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ui/signals.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ui/stage.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/ui/theme.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/users/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/users/client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/validator.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/validator_v1_6_0.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/src/imperal_sdk/vault_ram_client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/conftest.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/contract/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/contract/test_action_schemas.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/contract/test_artifacts_freshness.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/contract/test_contract_checks_selftest.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/contract/test_generate_sdk_claims.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/contract/test_identity_nonempty.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/contract/test_ir_schema_fresh.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/contract/test_meter_lua_contract.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/contract/test_metered_event_contract.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/contract/test_notify_wire_payload.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/contract/test_public_docstrings_engine_neutral.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/contract/test_reference_completeness.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/contract/test_reference_no_leak.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/contract/test_sample_contract_shape.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/contract/test_sdk_matches_kernel_contract.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/contracts/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/contracts/test_store_contracts.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/fixtures/contract/kernel-contract.sample.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/fixtures/ir/README.md +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/fixtures/ir/archive_ended.ir.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/fixtures/ir/link_saver.ir.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/fixtures/ir/test_fixtures_valid.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/fixtures/openapi/auth-gateway.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/fixtures/openapi/registry.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/fixtures/openapi/sharelock-cases.json +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/ir/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/ir/test_custom_roles.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/ir/test_ir_impl.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/ir/test_ir_mapping_real_ext.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/ir/test_ir_migrate.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/ir/test_ir_produce.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/ir/test_ir_schema.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/ir/test_ir_skeleton.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/ir/test_ir_ui.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/ir/test_ir_ui_produce.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/ir/test_ir_validator.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/ir/test_ir_versions.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/ir/test_ui_children.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/ir/test_ui_template.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/rpc/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/rpc/test_boundary_seal.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/rpc/test_codec.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/rpc/test_contract.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/runtime/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/runtime/test_canon.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/runtime/test_canon_template.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/runtime/test_engine_abc.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/runtime/test_engine_parity.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/runtime/test_executor_neutral.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/runtime/test_hosted_client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/runtime/test_interpreter.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/runtime/test_llm_provider_config_store.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/runtime/test_llm_provider_ctx_injection.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/runtime/test_local_engine.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/runtime/test_platform_shim.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/runtime/test_template.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/runtime/test_verb_ai.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/runtime/test_verb_call_directives.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/runtime/test_verb_conditional.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/runtime/test_verb_store.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/store/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/store/test_list_users_client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/store/test_query_all_client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_action_result_time_travel.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_action_result_typed.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_agent_presence.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_as_user.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_auth.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_autonomous_mock.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_billing.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_cache_client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_cache_model.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_call_token.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_callable_surface_single_source.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_chat_extension_deprecation.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_chat_extension_no_llm_router.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_chat_filters.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_chat_function_background_flag.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_chat_guards.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_chat_guards_bleed.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_chat_prompt.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_chat_result.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_cli.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_cli_sdk_commands.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_client_contracts.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_client_emit_neutral.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_config_client.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_context.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_context_background_task.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_context_deliver_chat_message.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_context_guards.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_contracts.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_contracts_live.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_contributions.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_core_primitives.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_data_model_kwarg.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_document_contract.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_emits_decorator.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_error_codes.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_errors.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_event_schema_v2.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_events_health.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_extension.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_extension_pipes.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_extension_v2.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_extensions_emit.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_gateway_namespaces.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_http_json_and_mock.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_http_retry.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_http_timeout_override.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_id_shape_guard.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_identity_contract.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_imperal_schema_v2.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_import_light.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_init_onboarding.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_kernel_primitives.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_liquid_ui.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_manifest.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_manifest_file_sinks.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_manifest_linter.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_manifest_no_orchestrator_tool.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_manifest_oauth.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_manifest_panels.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_manifest_roundtrip_gate.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_manifest_schema.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_manifest_v2_events.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_manifest_v2_other_sections.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_manifest_v2_webhooks.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_manifest_validator_v2.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_mock_context.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_models.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_narration_emission.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_narration_guard.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_oauth_authorize_url.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_oauth_tokens_shared.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_openai_max_completion_tokens.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_pagination.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_panel_rendering_contract.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_panel_swr_caching.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_panels.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_phase_a_dead_removal.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_phase_a_drift.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_phase_a_text.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_quantum_app.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdk_version_stamp.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_entity.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_entity_marker.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_exports.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facet_catalog.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facet_collisions.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facet_comm.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facet_content.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facet_device.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facet_event.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facet_exports.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facet_field.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facet_geo.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facet_identity.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facet_media.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facet_metric.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facet_money.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facet_net.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facet_people.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facet_quantity.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facet_rating.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facet_resolve.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facet_security.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facet_task.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facet_time.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facets_catalog.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facets_doc.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_facets_pkg.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_field.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_roles.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_roles_json.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_roles_of_facets.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sdl_vocab_version.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_search_provider.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_secret_scope_decorator.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_secret_spec_scope.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_skeleton_decorator.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_spec_validation.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_stage.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_surface_adaptation.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_sync_async_parity.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_transport_isolation.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_ui.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_ui_canvas.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_ui_fileupload_enhanced.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_ui_html.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_ui_image_enhanced.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_ui_modal.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_ui_open.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_ui_signals.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_ui_theme.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_user.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_v7_emit_refusal.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_validator.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_validator_drift.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_validator_pep563.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_validator_v1_6_0_rules.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_validator_v25.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/test_write_arg_bleed.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/tools/__init__.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/tools/test_generate_api_surface.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/tools/test_generate_reference.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/tools/test_reference_description.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/tools/test_reference_flags.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/tools/test_reference_typegraph.py +0 -0
- {imperal_sdk-6.0.2 → imperal_sdk-6.1.0}/tests/ui/test_input_type_enum.py +0 -0
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `imperal-sdk` are documented here.
|
|
4
4
|
|
|
5
|
+
## 6.1.0 — 2026-10-20
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **`imperal_sdk.code_index`** — the code index extractor (one code file -> its symbols,
|
|
9
|
+
imports, references, endpoints and schemas), moved here unchanged from the Webbee Code client
|
|
10
|
+
(`webbee/intel/models.py`, `contracts.py`, `indexer.py`) so the client and the Imperal kernel
|
|
11
|
+
share one extractor. Parsing needs the new optional extra `code-index` (tree-sitter).
|
|
12
|
+
|
|
5
13
|
## 6.0.1 — 2026-09-26
|
|
6
14
|
|
|
7
15
|
### Added & Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: imperal-sdk
|
|
3
|
-
Version: 6.0
|
|
3
|
+
Version: 6.1.0
|
|
4
4
|
Summary: SDK for building Imperal Cloud extensions
|
|
5
5
|
Author: Valentin Scerbacov, Imperal, Inc.
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -27,6 +27,11 @@ Requires-Dist: click>=8.1.0
|
|
|
27
27
|
Requires-Dist: httpx>=0.28.0
|
|
28
28
|
Requires-Dist: pydantic>=2.10.0
|
|
29
29
|
Requires-Dist: pyjwt[crypto]>=2.10.0
|
|
30
|
+
Provides-Extra: code-index
|
|
31
|
+
Requires-Dist: tree-sitter-javascript>=0.23; (sys_platform != 'darwin' or platform_machine != 'x86_64' or python_version < '3.13') and extra == 'code-index'
|
|
32
|
+
Requires-Dist: tree-sitter-python>=0.23; (sys_platform != 'darwin' or platform_machine != 'x86_64' or python_version < '3.13') and extra == 'code-index'
|
|
33
|
+
Requires-Dist: tree-sitter-typescript>=0.23; (sys_platform != 'darwin' or platform_machine != 'x86_64' or python_version < '3.13') and extra == 'code-index'
|
|
34
|
+
Requires-Dist: tree-sitter>=0.23; (sys_platform != 'darwin' or platform_machine != 'x86_64' or python_version < '3.13') and extra == 'code-index'
|
|
30
35
|
Provides-Extra: contract
|
|
31
36
|
Requires-Dist: schemathesis>=3.30.0; extra == 'contract'
|
|
32
37
|
Provides-Extra: db
|
|
@@ -38,6 +43,10 @@ Requires-Dist: openapi-spec-validator>=0.7.1; extra == 'dev'
|
|
|
38
43
|
Requires-Dist: pytest-asyncio>=0.25.0; extra == 'dev'
|
|
39
44
|
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
40
45
|
Requires-Dist: respx>=0.22.0; extra == 'dev'
|
|
46
|
+
Requires-Dist: tree-sitter-javascript>=0.23; (sys_platform != 'darwin' or platform_machine != 'x86_64' or python_version < '3.13') and extra == 'dev'
|
|
47
|
+
Requires-Dist: tree-sitter-python>=0.23; (sys_platform != 'darwin' or platform_machine != 'x86_64' or python_version < '3.13') and extra == 'dev'
|
|
48
|
+
Requires-Dist: tree-sitter-typescript>=0.23; (sys_platform != 'darwin' or platform_machine != 'x86_64' or python_version < '3.13') and extra == 'dev'
|
|
49
|
+
Requires-Dist: tree-sitter>=0.23; (sys_platform != 'darwin' or platform_machine != 'x86_64' or python_version < '3.13') and extra == 'dev'
|
|
41
50
|
Provides-Extra: fastapi
|
|
42
51
|
Requires-Dist: fastapi>=0.115.0; extra == 'fastapi'
|
|
43
52
|
Description-Content-Type: text/markdown
|
|
@@ -46,6 +46,10 @@ dev = [
|
|
|
46
46
|
"respx>=0.22.0",
|
|
47
47
|
"openapi-spec-validator>=0.7.1",
|
|
48
48
|
"jsonschema>=4.21.0",
|
|
49
|
+
'tree-sitter>=0.23; sys_platform != "darwin" or platform_machine != "x86_64" or python_version < "3.13"',
|
|
50
|
+
'tree-sitter-python>=0.23; sys_platform != "darwin" or platform_machine != "x86_64" or python_version < "3.13"',
|
|
51
|
+
'tree-sitter-typescript>=0.23; sys_platform != "darwin" or platform_machine != "x86_64" or python_version < "3.13"',
|
|
52
|
+
'tree-sitter-javascript>=0.23; sys_platform != "darwin" or platform_machine != "x86_64" or python_version < "3.13"',
|
|
49
53
|
]
|
|
50
54
|
fastapi = [
|
|
51
55
|
"fastapi>=0.115.0",
|
|
@@ -57,6 +61,14 @@ db = [
|
|
|
57
61
|
contract = [
|
|
58
62
|
"schemathesis>=3.30.0",
|
|
59
63
|
]
|
|
64
|
+
# imperal_sdk.code_index: tree-sitter parsing of Python / TypeScript / JavaScript
|
|
65
|
+
# (the same packages and markers the Webbee Code client ships).
|
|
66
|
+
code-index = [
|
|
67
|
+
'tree-sitter>=0.23; sys_platform != "darwin" or platform_machine != "x86_64" or python_version < "3.13"',
|
|
68
|
+
'tree-sitter-python>=0.23; sys_platform != "darwin" or platform_machine != "x86_64" or python_version < "3.13"',
|
|
69
|
+
'tree-sitter-typescript>=0.23; sys_platform != "darwin" or platform_machine != "x86_64" or python_version < "3.13"',
|
|
70
|
+
'tree-sitter-javascript>=0.23; sys_platform != "darwin" or platform_machine != "x86_64" or python_version < "3.13"',
|
|
71
|
+
]
|
|
60
72
|
|
|
61
73
|
[project.scripts]
|
|
62
74
|
imperal = "imperal_sdk.cli.main:cli"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Imperal Cloud SDK — build extensions for the Imperal platform."""
|
|
2
2
|
from typing import TYPE_CHECKING
|
|
3
3
|
|
|
4
|
-
__version__ = "6.0
|
|
4
|
+
__version__ = "6.1.0"
|
|
5
5
|
|
|
6
6
|
# 5.2.2 (2026-06-11): the package root resolves its public surface lazily
|
|
7
7
|
# (PEP 562). The eager imports pulled the HTTP transport (Context / client
|
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
"""Code index: one code file -> its symbols, imports, references and contracts.
|
|
2
|
+
|
|
3
|
+
Moved from the Webbee Code client (webbee/intel/models.py, contracts.py, indexer.py,
|
|
4
|
+
2026-10-20) so the client and the Imperal kernel share ONE extractor
|
|
5
|
+
(spec: docs/superpowers/specs/2026-10-19-code-graph-everywhere-design.md, ipw-repo).
|
|
6
|
+
tree-sitter is imported lazily: install the ``code-index`` extra to parse code.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import ast
|
|
11
|
+
import hashlib
|
|
12
|
+
import os
|
|
13
|
+
import re
|
|
14
|
+
from dataclasses import asdict, dataclass, field
|
|
15
|
+
from typing import Iterable
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# ---- models (from webbee/intel/models.py) ----
|
|
19
|
+
|
|
20
|
+
@dataclass(frozen=True)
|
|
21
|
+
class Symbol:
|
|
22
|
+
name: str
|
|
23
|
+
kind: str # "function" | "class" | "method" | "symbol"
|
|
24
|
+
path: str # workspace-relative
|
|
25
|
+
start_line: int
|
|
26
|
+
end_line: int
|
|
27
|
+
signature: str = ""
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class FileIndex:
|
|
32
|
+
path: str
|
|
33
|
+
lang: str # "python" | "typescript" | "javascript" | "other"
|
|
34
|
+
symbols: list[Symbol] = field(default_factory=list)
|
|
35
|
+
imports: list[str] = field(default_factory=list) # imported module/path strings
|
|
36
|
+
refs: list[str] = field(default_factory=list) # referenced identifier names (for the graph)
|
|
37
|
+
content_hash: str = ""
|
|
38
|
+
endpoints: list[dict] = field(default_factory=list)
|
|
39
|
+
schemas: list[dict] = field(default_factory=list)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass
|
|
43
|
+
class ProjectIndex:
|
|
44
|
+
files: dict[str, FileIndex] = field(default_factory=dict)
|
|
45
|
+
git_ref: str = ""
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# ---- contracts (from webbee/intel/contracts.py) ----
|
|
49
|
+
|
|
50
|
+
"""Deterministic endpoint/schema evidence extraction.
|
|
51
|
+
|
|
52
|
+
This is deliberately a projection over source snapshots, not a second source
|
|
53
|
+
of truth. Every record carries file+line provenance and is rebuilt from the
|
|
54
|
+
content-addressed repository index. Unsupported syntax is simply absent; no
|
|
55
|
+
LLM inference is stored as fact.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
_HTTP_METHODS = frozenset({"get", "post", "put", "patch", "delete", "options", "head"})
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@dataclass(frozen=True)
|
|
63
|
+
class EndpointEvidence:
|
|
64
|
+
method: str
|
|
65
|
+
route: str
|
|
66
|
+
handler: str
|
|
67
|
+
path: str
|
|
68
|
+
line: int
|
|
69
|
+
schema_refs: tuple[str, ...] = ()
|
|
70
|
+
|
|
71
|
+
def to_dict(self) -> dict:
|
|
72
|
+
return asdict(self)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@dataclass(frozen=True)
|
|
76
|
+
class SchemaEvidence:
|
|
77
|
+
name: str
|
|
78
|
+
schema_kind: str
|
|
79
|
+
path: str
|
|
80
|
+
line: int
|
|
81
|
+
fields: tuple[str, ...] = ()
|
|
82
|
+
storage_name: str = ""
|
|
83
|
+
|
|
84
|
+
def to_dict(self) -> dict:
|
|
85
|
+
return asdict(self)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _name(node) -> str:
|
|
89
|
+
if isinstance(node, ast.Name):
|
|
90
|
+
return node.id
|
|
91
|
+
if isinstance(node, ast.Attribute):
|
|
92
|
+
left = _name(node.value)
|
|
93
|
+
return f"{left}.{node.attr}" if left else node.attr
|
|
94
|
+
if isinstance(node, ast.Subscript):
|
|
95
|
+
return _name(node.value)
|
|
96
|
+
return ""
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _literal_string(node) -> str:
|
|
100
|
+
return node.value if isinstance(node, ast.Constant) and isinstance(node.value, str) else ""
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _annotation_names(node) -> set[str]:
|
|
104
|
+
if node is None:
|
|
105
|
+
return set()
|
|
106
|
+
names = set()
|
|
107
|
+
for part in ast.walk(node):
|
|
108
|
+
n = _name(part)
|
|
109
|
+
if n and n.split(".")[-1][:1].isupper():
|
|
110
|
+
names.add(n.split(".")[-1])
|
|
111
|
+
return names
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
_ROUTER_CTORS = frozenset({"APIRouter", "Blueprint", "FastAPI", "Flask"})
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _router_prefixes(tree) -> dict:
|
|
118
|
+
"""``name -> prefix`` of the routers this module builds (``router = APIRouter(prefix="/api")``,
|
|
119
|
+
``Blueprint("x", __name__, url_prefix="/x")``): a route is the router's prefix + its path."""
|
|
120
|
+
out = {}
|
|
121
|
+
for node in ast.walk(tree):
|
|
122
|
+
if isinstance(node, ast.Assign) and isinstance(node.value, ast.Call) \
|
|
123
|
+
and _name(node.value.func).split(".")[-1] in _ROUTER_CTORS:
|
|
124
|
+
prefix = next((_literal_string(k.value) for k in node.value.keywords
|
|
125
|
+
if k.arg in ("prefix", "url_prefix")), "")
|
|
126
|
+
for t in node.targets:
|
|
127
|
+
if isinstance(t, ast.Name):
|
|
128
|
+
out[t.id] = prefix
|
|
129
|
+
return out
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _route_of(prefixes: dict, owner: str, route: str) -> str:
|
|
133
|
+
"""The full route (the router's prefix + the path; a FastAPI router path may be "" under a
|
|
134
|
+
prefix), or "" when it is not a route."""
|
|
135
|
+
full = prefixes.get(owner, "") + route
|
|
136
|
+
return full if full.startswith("/") else ""
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _methods_kw(call) -> list:
|
|
140
|
+
for kw in call.keywords:
|
|
141
|
+
if kw.arg == "methods" and isinstance(kw.value, (ast.List, ast.Tuple, ast.Set)):
|
|
142
|
+
return [m.lower() for m in (_literal_string(e) for e in kw.value.elts) if m]
|
|
143
|
+
return []
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _endpoint_refs(fn, call) -> tuple:
|
|
147
|
+
refs = set()
|
|
148
|
+
if fn is not None:
|
|
149
|
+
for arg in (*fn.args.posonlyargs, *fn.args.args, *fn.args.kwonlyargs):
|
|
150
|
+
refs.update(_annotation_names(arg.annotation))
|
|
151
|
+
refs.update(_annotation_names(fn.returns))
|
|
152
|
+
for kw in call.keywords:
|
|
153
|
+
if kw.arg in {"response_model", "request_model", "model"}:
|
|
154
|
+
refs.update(_annotation_names(kw.value))
|
|
155
|
+
return tuple(sorted(refs))
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _python_contracts(path: str, text: str):
|
|
159
|
+
try:
|
|
160
|
+
tree = ast.parse(text)
|
|
161
|
+
except (SyntaxError, ValueError):
|
|
162
|
+
return [], []
|
|
163
|
+
prefixes = _router_prefixes(tree)
|
|
164
|
+
funcs = {n.name: n for n in ast.walk(tree) if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef))}
|
|
165
|
+
endpoints, schemas = [], []
|
|
166
|
+
for node in ast.walk(tree):
|
|
167
|
+
if isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute) \
|
|
168
|
+
and node.func.attr == "add_api_route" and len(node.args) >= 2:
|
|
169
|
+
# router.add_api_route("/x", handler, methods=["GET"])
|
|
170
|
+
owner, route = _name(node.func.value), _literal_string(node.args[0])
|
|
171
|
+
full, handler = _route_of(prefixes, owner, route), _name(node.args[1])
|
|
172
|
+
for method in (_methods_kw(node) or ["get"]):
|
|
173
|
+
if full and method in _HTTP_METHODS:
|
|
174
|
+
endpoints.append(EndpointEvidence(method.upper(), full, handler.split(".")[-1], path,
|
|
175
|
+
node.lineno, _endpoint_refs(funcs.get(handler), node)))
|
|
176
|
+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
177
|
+
for dec in node.decorator_list:
|
|
178
|
+
if not isinstance(dec, ast.Call) or not isinstance(dec.func, ast.Attribute):
|
|
179
|
+
continue
|
|
180
|
+
verb = dec.func.attr.lower()
|
|
181
|
+
route = _literal_string(dec.args[0]) if dec.args else ""
|
|
182
|
+
full = _route_of(prefixes, _name(dec.func.value), route)
|
|
183
|
+
# @router.get(...), and @app.route / @router.api_route(..., methods=[...])
|
|
184
|
+
methods = [verb] if verb in _HTTP_METHODS else (
|
|
185
|
+
_methods_kw(dec) or ["get"] if verb in ("route", "api_route") else [])
|
|
186
|
+
for method in methods:
|
|
187
|
+
if not full or method not in _HTTP_METHODS:
|
|
188
|
+
continue
|
|
189
|
+
endpoints.append(EndpointEvidence(
|
|
190
|
+
method.upper(), full, node.name, path,
|
|
191
|
+
getattr(dec, "lineno", node.lineno), _endpoint_refs(node, dec)))
|
|
192
|
+
elif isinstance(node, ast.ClassDef):
|
|
193
|
+
bases = {_name(b).split(".")[-1] for b in node.bases}
|
|
194
|
+
is_model = bool(bases & {"BaseModel", "TypedDict", "Schema", "Serializer"})
|
|
195
|
+
is_table = bool(bases & {"Base", "DeclarativeBase", "Model"})
|
|
196
|
+
if not (is_model or is_table):
|
|
197
|
+
continue
|
|
198
|
+
fields, storage = set(), ""
|
|
199
|
+
for stmt in node.body:
|
|
200
|
+
if isinstance(stmt, ast.AnnAssign) and isinstance(stmt.target, ast.Name):
|
|
201
|
+
fields.add(stmt.target.id)
|
|
202
|
+
elif isinstance(stmt, ast.Assign):
|
|
203
|
+
for target in stmt.targets:
|
|
204
|
+
if isinstance(target, ast.Name):
|
|
205
|
+
if target.id == "__tablename__":
|
|
206
|
+
storage = _literal_string(stmt.value)
|
|
207
|
+
elif isinstance(stmt.value, ast.Call):
|
|
208
|
+
call = _name(stmt.value.func).split(".")[-1]
|
|
209
|
+
if call in {"Column", "mapped_column", "Field"}:
|
|
210
|
+
fields.add(target.id)
|
|
211
|
+
schemas.append(SchemaEvidence(
|
|
212
|
+
node.name, "table" if is_table else "model", path, node.lineno,
|
|
213
|
+
tuple(sorted(fields)), storage))
|
|
214
|
+
return endpoints, schemas
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
_TS_ENDPOINT = re.compile(
|
|
218
|
+
r"(?m)\b(?:app|router|server)\s*\.\s*(get|post|put|patch|delete|options|head)"
|
|
219
|
+
r"\s*\(\s*([\"'])(/[^\"']*)\2\s*,\s*([A-Za-z_$][\w$]*)"
|
|
220
|
+
)
|
|
221
|
+
_TS_SCHEMA = re.compile(
|
|
222
|
+
r"(?ms)\b(?:export\s+)?(?:interface|type|class)\s+([A-Za-z_$][\w$]*)"
|
|
223
|
+
r"(?:\s+extends[^\{=]+)?\s*(?:\{|=\s*\{)(.*?)\}"
|
|
224
|
+
)
|
|
225
|
+
_TS_FIELD = re.compile(r"(?m)^\s*([A-Za-z_$][\w$]*)\s*\??\s*:")
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def _typescript_contracts(path: str, text: str):
|
|
229
|
+
endpoints = [EndpointEvidence(
|
|
230
|
+
m.group(1).upper(), m.group(3), m.group(4), path,
|
|
231
|
+
text.count("\n", 0, m.start()) + 1)
|
|
232
|
+
for m in _TS_ENDPOINT.finditer(text)]
|
|
233
|
+
schemas = []
|
|
234
|
+
for m in _TS_SCHEMA.finditer(text):
|
|
235
|
+
schemas.append(SchemaEvidence(
|
|
236
|
+
m.group(1), "model", path, text.count("\n", 0, m.start()) + 1,
|
|
237
|
+
tuple(sorted(set(_TS_FIELD.findall(m.group(2)))))))
|
|
238
|
+
return endpoints, schemas
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
_NEXT_HANDLER = re.compile(
|
|
242
|
+
r"(?m)^\s*export\s+(?:async\s+)?(?:function\s+|const\s+)(GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD)\b")
|
|
243
|
+
_NEXT_APP_ROUTE = re.compile(r"(?:^|/)app/(.*?)/?route\.(?:ts|tsx|js|jsx|mjs)$")
|
|
244
|
+
_NEXT_PAGES_API = re.compile(r"(?:^|/)pages/(api(?:/.*?)?)(?:/index)?\.(?:ts|tsx|js|jsx)$")
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def _next_route(segments: str) -> str:
|
|
248
|
+
"""A Next.js file route: route groups ``(x)`` and parallel slots ``@x`` vanish."""
|
|
249
|
+
parts = [p for p in segments.split("/") if p and not (p.startswith("(") and p.endswith(")"))
|
|
250
|
+
and not p.startswith("@")]
|
|
251
|
+
return "/" + "/".join(parts)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def _next_contracts(path: str, text: str):
|
|
255
|
+
"""Next.js route handlers: ``app/**/route.ts`` exporting GET/POST/..., and ``pages/api/**``."""
|
|
256
|
+
p = path.replace("\\", "/")
|
|
257
|
+
m = _NEXT_APP_ROUTE.search(p)
|
|
258
|
+
if m:
|
|
259
|
+
route = _next_route(m.group(1))
|
|
260
|
+
return [EndpointEvidence(h.group(1), route, h.group(1), path, text.count("\n", 0, h.start()) + 1)
|
|
261
|
+
for h in _NEXT_HANDLER.finditer(text)]
|
|
262
|
+
m = _NEXT_PAGES_API.search(p)
|
|
263
|
+
if m and re.search(r"(?m)^\s*export\s+default\b", text):
|
|
264
|
+
return [EndpointEvidence("ANY", _next_route(m.group(1)), "default", path, 1)]
|
|
265
|
+
return []
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def extract_contracts(path: str, text: str, lang: str):
|
|
269
|
+
if lang == "python":
|
|
270
|
+
return _python_contracts(path, text)
|
|
271
|
+
if lang in {"typescript", "javascript"}:
|
|
272
|
+
endpoints, schemas = _typescript_contracts(path, text)
|
|
273
|
+
return endpoints + _next_contracts(path, text), schemas
|
|
274
|
+
return [], []
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def match_contracts(repos: Iterable[dict]) -> list[dict]:
|
|
278
|
+
"""Build deterministic cross-repo links from exact contract identities.
|
|
279
|
+
|
|
280
|
+
Endpoint route+method and schema names are intentionally exact. Semantic
|
|
281
|
+
guesses belong in retrieval ranking, never in the evidence graph.
|
|
282
|
+
"""
|
|
283
|
+
repos = sorted(repos, key=lambda r: r.get("repo_key", ""))
|
|
284
|
+
out = []
|
|
285
|
+
for i, left in enumerate(repos):
|
|
286
|
+
for right in repos[i + 1:]:
|
|
287
|
+
lk, rk = left.get("repo_key", ""), right.get("repo_key", "")
|
|
288
|
+
le = {(x.method, x.route): x for x in left.get("endpoints", ())}
|
|
289
|
+
re_ = {(x.method, x.route): x for x in right.get("endpoints", ())}
|
|
290
|
+
for key in sorted(le.keys() & re_.keys()):
|
|
291
|
+
out.append({"relation": "endpoint_identity", "source_repo": lk,
|
|
292
|
+
"target_repo": rk, "identity": f"{key[0]} {key[1]}"})
|
|
293
|
+
# A schema contract can be declared as a concrete model/table OR
|
|
294
|
+
# referenced by an endpoint annotation/response_model. Both are
|
|
295
|
+
# deterministic source evidence; including references lets a
|
|
296
|
+
# producer endpoint link to a consumer's shared DTO even when the
|
|
297
|
+
# producer imports that DTO from another package.
|
|
298
|
+
def schema_names(repo):
|
|
299
|
+
names = {x.name for x in repo.get("schemas", ())}
|
|
300
|
+
for endpoint in repo.get("endpoints", ()):
|
|
301
|
+
names.update(endpoint.schema_refs)
|
|
302
|
+
return names
|
|
303
|
+
|
|
304
|
+
for name in sorted(schema_names(left) & schema_names(right)):
|
|
305
|
+
source, target = sorted((lk, rk))
|
|
306
|
+
out.append({"relation": "schema_name_match", "source_repo": source,
|
|
307
|
+
"target_repo": target, "identity": name})
|
|
308
|
+
return out
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
# ---- indexer (from webbee/intel/indexer.py) ----
|
|
312
|
+
|
|
313
|
+
LANG_BY_EXT = {".py": "python", ".ts": "typescript", ".tsx": "typescript",
|
|
314
|
+
".js": "javascript", ".jsx": "javascript"}
|
|
315
|
+
|
|
316
|
+
# tree-sitter Language handles are lazy-loaded + cached (import cost is real).
|
|
317
|
+
_LANG_CACHE: dict = {}
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def _get_language(lang: str):
|
|
321
|
+
if lang in _LANG_CACHE:
|
|
322
|
+
return _LANG_CACHE[lang]
|
|
323
|
+
try:
|
|
324
|
+
if lang == "python":
|
|
325
|
+
import tree_sitter_python as ts_py
|
|
326
|
+
from tree_sitter import Language
|
|
327
|
+
obj = Language(ts_py.language())
|
|
328
|
+
elif lang == "typescript":
|
|
329
|
+
import tree_sitter_typescript as ts_ts
|
|
330
|
+
from tree_sitter import Language
|
|
331
|
+
obj = Language(ts_ts.language_typescript())
|
|
332
|
+
elif lang == "javascript":
|
|
333
|
+
import tree_sitter_javascript as ts_js
|
|
334
|
+
from tree_sitter import Language
|
|
335
|
+
obj = Language(ts_js.language())
|
|
336
|
+
else:
|
|
337
|
+
obj = None
|
|
338
|
+
except Exception:
|
|
339
|
+
obj = None
|
|
340
|
+
_LANG_CACHE[lang] = obj
|
|
341
|
+
return obj
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
# Minimal per-language node-type -> symbol-kind maps (clean-room; NOT the AGPL
|
|
345
|
+
# package's queries). We walk the tree once and pick definition nodes; this is
|
|
346
|
+
# syntax-level extraction, exactly what tree-sitter guarantees.
|
|
347
|
+
_DEF_NODES = {
|
|
348
|
+
"python": {"function_definition": "function", "class_definition": "class"},
|
|
349
|
+
"typescript": {"function_declaration": "function", "class_declaration": "class",
|
|
350
|
+
"method_definition": "method", "interface_declaration": "class"},
|
|
351
|
+
"javascript": {"function_declaration": "function", "class_declaration": "class",
|
|
352
|
+
"method_definition": "method"},
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def _lang_for(path: str) -> str:
|
|
357
|
+
return LANG_BY_EXT.get(os.path.splitext(path)[1].lower(), "other")
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def _name_of(node, src_bytes: bytes) -> str:
|
|
361
|
+
n = node.child_by_field_name("name")
|
|
362
|
+
if n is not None:
|
|
363
|
+
return src_bytes[n.start_byte:n.end_byte].decode("utf-8", "replace")
|
|
364
|
+
return ""
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def parse_file(path: str, text: str) -> FileIndex | None:
|
|
368
|
+
lang = _lang_for(path)
|
|
369
|
+
fi = FileIndex(path=path, lang=lang, content_hash=hashlib.sha256(text.encode("utf-8", "replace")).hexdigest())
|
|
370
|
+
endpoints, schemas = extract_contracts(path, text, lang)
|
|
371
|
+
fi.endpoints = [x.to_dict() for x in endpoints]
|
|
372
|
+
fi.schemas = [x.to_dict() for x in schemas]
|
|
373
|
+
if lang == "other":
|
|
374
|
+
return fi # line-only fallback (no symbols) — never crash
|
|
375
|
+
L = _get_language(lang)
|
|
376
|
+
if L is None:
|
|
377
|
+
return fi
|
|
378
|
+
try:
|
|
379
|
+
from tree_sitter import Parser
|
|
380
|
+
parser = Parser(L)
|
|
381
|
+
src = text.encode("utf-8", "replace")
|
|
382
|
+
tree = parser.parse(src)
|
|
383
|
+
defmap = _DEF_NODES.get(lang, {})
|
|
384
|
+
stack = [tree.root_node]
|
|
385
|
+
while stack:
|
|
386
|
+
node = stack.pop()
|
|
387
|
+
kind = defmap.get(node.type)
|
|
388
|
+
if kind:
|
|
389
|
+
# A def/class node's own name-identifier must NOT be walked
|
|
390
|
+
# as a generic child -- otherwise it lands in `refs` too,
|
|
391
|
+
# making the defining file its own "caller"/"dependent".
|
|
392
|
+
# Nested defs (methods, inner functions) are still reached:
|
|
393
|
+
# every other child is still pushed onto the stack.
|
|
394
|
+
# NOTE: tree-sitter Node objects are re-wrapped on each
|
|
395
|
+
# access, so `is`/`is not` identity checks don't hold across
|
|
396
|
+
# two separate child_by_field_name/children calls -- compare
|
|
397
|
+
# by (start_byte, end_byte) span instead.
|
|
398
|
+
name_node = node.child_by_field_name("name")
|
|
399
|
+
name_span = (name_node.start_byte, name_node.end_byte) if name_node is not None else None
|
|
400
|
+
nm = _name_of(node, src)
|
|
401
|
+
if nm:
|
|
402
|
+
sig = src[node.start_byte:min(node.end_byte, node.start_byte + 200)].decode("utf-8", "replace").split("\n", 1)[0]
|
|
403
|
+
fi.symbols.append(Symbol(name=nm, kind=kind, path=path,
|
|
404
|
+
start_line=node.start_point[0] + 1,
|
|
405
|
+
end_line=node.end_point[0] + 1, signature=sig))
|
|
406
|
+
for ch in node.children:
|
|
407
|
+
if name_span is None or (ch.start_byte, ch.end_byte) != name_span:
|
|
408
|
+
stack.append(ch)
|
|
409
|
+
continue
|
|
410
|
+
if node.type in ("identifier", "call", "call_expression"):
|
|
411
|
+
fi.refs.append(src[node.start_byte:node.end_byte].decode("utf-8", "replace").split("(")[0].strip())
|
|
412
|
+
stack.extend(node.children)
|
|
413
|
+
except Exception:
|
|
414
|
+
return fi # parse error -> line-only, fail-soft
|
|
415
|
+
return fi
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def build_index(root: str, files: list[str]) -> ProjectIndex:
|
|
419
|
+
idx = ProjectIndex()
|
|
420
|
+
for rel in files:
|
|
421
|
+
try:
|
|
422
|
+
with open(os.path.join(root, rel), "r", encoding="utf-8") as f:
|
|
423
|
+
text = f.read()
|
|
424
|
+
except (OSError, UnicodeDecodeError):
|
|
425
|
+
continue
|
|
426
|
+
fi = parse_file(rel, text)
|
|
427
|
+
if fi is not None:
|
|
428
|
+
idx.files[rel] = fi
|
|
429
|
+
return idx
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from imperal_sdk.code_index import extract_contracts, match_contracts
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_extracts_python_http_endpoints_with_provenance():
|
|
5
|
+
text = '''
|
|
6
|
+
@router.post("/v1/orders/{order_id}", response_model=OrderOut)
|
|
7
|
+
async def create_order(order_id: int, body: OrderIn):
|
|
8
|
+
return service.create(body)
|
|
9
|
+
|
|
10
|
+
@app.get('/healthz')
|
|
11
|
+
def health():
|
|
12
|
+
return {"ok": True}
|
|
13
|
+
'''
|
|
14
|
+
endpoints, schemas = extract_contracts("api/orders.py", text, "python")
|
|
15
|
+
assert [(e.method, e.route, e.handler) for e in endpoints] == [
|
|
16
|
+
("POST", "/v1/orders/{order_id}", "create_order"),
|
|
17
|
+
("GET", "/healthz", "health"),
|
|
18
|
+
]
|
|
19
|
+
assert endpoints[0].path == "api/orders.py"
|
|
20
|
+
assert endpoints[0].line == 2
|
|
21
|
+
assert "OrderIn" in endpoints[0].schema_refs
|
|
22
|
+
assert "OrderOut" in endpoints[0].schema_refs
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_extracts_pydantic_and_sqlalchemy_schemas():
|
|
26
|
+
text = '''
|
|
27
|
+
class OrderIn(BaseModel):
|
|
28
|
+
sku: str
|
|
29
|
+
quantity: int = 1
|
|
30
|
+
|
|
31
|
+
class OrderRow(Base):
|
|
32
|
+
__tablename__ = "orders"
|
|
33
|
+
id = Column(Integer, primary_key=True)
|
|
34
|
+
payload = mapped_column(JSON)
|
|
35
|
+
'''
|
|
36
|
+
endpoints, schemas = extract_contracts("models.py", text, "python")
|
|
37
|
+
assert not endpoints
|
|
38
|
+
by_name = {s.name: s for s in schemas}
|
|
39
|
+
assert by_name["OrderIn"].schema_kind == "model"
|
|
40
|
+
assert by_name["OrderIn"].fields == ("quantity", "sku")
|
|
41
|
+
assert by_name["OrderRow"].schema_kind == "table"
|
|
42
|
+
assert by_name["OrderRow"].storage_name == "orders"
|
|
43
|
+
assert by_name["OrderRow"].fields == ("id", "payload")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_extracts_typescript_express_and_interfaces():
|
|
47
|
+
text = '''
|
|
48
|
+
router.put("/v1/users/:id", updateUser)
|
|
49
|
+
export interface UserPatch {
|
|
50
|
+
displayName?: string;
|
|
51
|
+
active: boolean;
|
|
52
|
+
}
|
|
53
|
+
'''
|
|
54
|
+
endpoints, schemas = extract_contracts("routes/users.ts", text, "typescript")
|
|
55
|
+
assert [(e.method, e.route, e.handler) for e in endpoints] == [
|
|
56
|
+
("PUT", "/v1/users/:id", "updateUser")
|
|
57
|
+
]
|
|
58
|
+
assert schemas[0].name == "UserPatch"
|
|
59
|
+
assert schemas[0].fields == ("active", "displayName")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_cross_repo_matching_is_deterministic_and_typed():
|
|
63
|
+
producer_eps, producer_schemas = extract_contracts(
|
|
64
|
+
"api.py",
|
|
65
|
+
'@app.post("/v1/orders", response_model=OrderOut)\ndef create(body: OrderIn): pass\n',
|
|
66
|
+
"python",
|
|
67
|
+
)
|
|
68
|
+
_, client_schemas = extract_contracts(
|
|
69
|
+
"client.py", "class OrderIn(BaseModel):\n sku: str\n", "python"
|
|
70
|
+
)
|
|
71
|
+
links = match_contracts(
|
|
72
|
+
[
|
|
73
|
+
{"repo_key": "producer", "endpoints": producer_eps, "schemas": producer_schemas},
|
|
74
|
+
{"repo_key": "client", "endpoints": [], "schemas": client_schemas},
|
|
75
|
+
]
|
|
76
|
+
)
|
|
77
|
+
schema_links = [x for x in links if x["relation"] == "schema_name_match"]
|
|
78
|
+
assert schema_links
|
|
79
|
+
assert schema_links[0]["source_repo"] == "client"
|
|
80
|
+
assert schema_links[0]["target_repo"] == "producer"
|
|
81
|
+
|
|
82
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
pytest.importorskip("tree_sitter") # skip when the intel extra isn't installed
|
|
3
|
+
from imperal_sdk import code_index as indexer
|
|
4
|
+
from imperal_sdk.code_index import ProjectIndex
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_parse_python_symbols(tmp_path):
|
|
8
|
+
src = "def alpha(x):\n return beta(x)\n\nclass Gamma:\n def method(self):\n pass\n"
|
|
9
|
+
fi = indexer.parse_file("m.py", src)
|
|
10
|
+
names = {s.name for s in fi.symbols}
|
|
11
|
+
assert {"alpha", "Gamma", "method"} <= names
|
|
12
|
+
a = next(s for s in fi.symbols if s.name == "alpha")
|
|
13
|
+
assert a.kind == "function" and a.start_line == 1
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_parse_ts_symbols():
|
|
17
|
+
fi = indexer.parse_file("m.ts", "export function widget(a: number){ return a }\nclass Box {}\n")
|
|
18
|
+
names = {s.name for s in fi.symbols}
|
|
19
|
+
assert "widget" in names and "Box" in names
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_unsupported_ext_is_line_only_not_crash():
|
|
23
|
+
fi = indexer.parse_file("data.bin", "\x00\x01binary")
|
|
24
|
+
assert fi is not None and fi.symbols == [] and fi.lang == "other"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_build_index(tmp_path):
|
|
28
|
+
(tmp_path / "a.py").write_text("def a():\n return b()\n")
|
|
29
|
+
(tmp_path / "b.py").write_text("def b():\n return 1\n")
|
|
30
|
+
idx = indexer.build_index(str(tmp_path), ["a.py", "b.py"])
|
|
31
|
+
assert isinstance(idx, ProjectIndex)
|
|
32
|
+
assert set(idx.files) == {"a.py", "b.py"}
|
|
33
|
+
assert any(s.name == "a" for s in idx.files["a.py"].symbols)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_def_own_name_is_not_recorded_as_a_ref():
|
|
37
|
+
# A def's own name-identifier must not land in fi.refs -- otherwise the
|
|
38
|
+
# defining file counts itself as a "caller"/"dependent" of its own
|
|
39
|
+
# symbol, inflating callers_of/impact_of_change with a false positive.
|
|
40
|
+
src = "def alpha():\n return 1\n"
|
|
41
|
+
fi = indexer.parse_file("m.py", src)
|
|
42
|
+
assert "alpha" not in fi.refs
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_nested_def_inside_class_still_discovered_after_name_exclusion():
|
|
46
|
+
# The name-node exclusion must not break traversal into a def's body --
|
|
47
|
+
# nested/inner defs (e.g. methods) still need to be found.
|
|
48
|
+
src = "class Gamma:\n def method(self):\n return other()\n"
|
|
49
|
+
fi = indexer.parse_file("m.py", src)
|
|
50
|
+
names = {s.name for s in fi.symbols}
|
|
51
|
+
assert {"Gamma", "method"} <= names
|
|
52
|
+
assert "other" in fi.refs # the call inside the method body is still a ref
|
|
53
|
+
assert "method" not in fi.refs # but the method's own name is not
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|