elva-cli 1.1.0rc2__tar.gz → 1.2.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.
- elva_cli-1.2.0/.github/ISSUE_TEMPLATE/bug_report.yml +27 -0
- elva_cli-1.2.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- elva_cli-1.2.0/.github/ISSUE_TEMPLATE/feature_request.yml +19 -0
- elva_cli-1.2.0/.github/pull_request_template.md +14 -0
- elva_cli-1.2.0/.github/workflows/ci.yml +57 -0
- elva_cli-1.2.0/.github/workflows/installer.yml +76 -0
- elva_cli-1.2.0/.github/workflows/release.yml +160 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/.gitignore +6 -0
- elva_cli-1.2.0/AGENTS.md +23 -0
- elva_cli-1.2.0/CHANGELOG.md +105 -0
- elva_cli-1.2.0/CLAUDE.md +6 -0
- elva_cli-1.2.0/CONTRIBUTING.md +79 -0
- elva_cli-1.2.0/PKG-INFO +145 -0
- elva_cli-1.2.0/README.md +111 -0
- elva_cli-1.2.0/RELEASING.md +66 -0
- elva_cli-1.2.0/SECURITY.md +11 -0
- elva_cli-1.2.0/docs/README.md +17 -0
- elva_cli-1.2.0/docs/agent-interface.md +67 -0
- elva_cli-1.2.0/docs/agent-workflow.md +108 -0
- elva_cli-1.2.0/docs/ai-plans.md +81 -0
- elva_cli-1.1.0rc2/PKG-INFO → elva_cli-1.2.0/docs/commands.md +163 -309
- elva_cli-1.2.0/docs/contracts.md +101 -0
- elva_cli-1.2.0/docs/email-signup.md +67 -0
- elva_cli-1.2.0/docs/exit-codes.md +184 -0
- elva_cli-1.2.0/docs/local-source.md +80 -0
- elva_cli-1.2.0/docs/privacy.md +40 -0
- elva_cli-1.2.0/docs/repository-readiness.md +33 -0
- elva_cli-1.2.0/docs/troubleshooting.md +23 -0
- elva_cli-1.2.0/examples/customer-orders/README.md +12 -0
- elva_cli-1.2.0/examples/customer-orders/artifact.json +47 -0
- elva_cli-1.2.0/llms.txt +19 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/pyproject.toml +5 -2
- elva_cli-1.2.0/scripts/smoke_wheel.py +116 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/_version.py +2 -2
- elva_cli-1.2.0/src/elva_cli/assets/agent-artifact.schema.json +564 -0
- elva_cli-1.2.0/src/elva_cli/assets/elva-mcp/SKILL.md +99 -0
- elva_cli-1.2.0/src/elva_cli/assets/elva-mcp/agents/openai.yaml +6 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/auth/models.py +7 -1
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/auth/session.py +25 -9
- elva_cli-1.2.0/src/elva_cli/commands/agent.py +255 -0
- elva_cli-1.2.0/src/elva_cli/commands/apply.py +26 -0
- elva_cli-1.2.0/src/elva_cli/commands/auth.py +159 -0
- elva_cli-1.2.0/src/elva_cli/commands/contract.py +263 -0
- elva_cli-1.2.0/src/elva_cli/commands/insights.py +102 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/commands/mcp.py +111 -0
- elva_cli-1.2.0/src/elva_cli/commands/plan.py +34 -0
- elva_cli-1.2.0/src/elva_cli/commands/prompt.py +232 -0
- elva_cli-1.2.0/src/elva_cli/commands/repo.py +158 -0
- elva_cli-1.2.0/src/elva_cli/commands/schema.py +85 -0
- elva_cli-1.2.0/src/elva_cli/core/agent_artifact.py +252 -0
- elva_cli-1.2.0/src/elva_cli/core/agent_setup.py +51 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/api/http.py +19 -4
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/api/targets.py +10 -9
- elva_cli-1.2.0/src/elva_cli/core/api/timeout.py +27 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/collections.py +9 -3
- elva_cli-1.2.0/src/elva_cli/core/services/agent_artifact.py +30 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/auth.py +5 -2
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/auth_result.py +21 -0
- elva_cli-1.2.0/src/elva_cli/core/services/contract.py +281 -0
- elva_cli-1.2.0/src/elva_cli/core/services/contract_result.py +27 -0
- elva_cli-1.2.0/src/elva_cli/core/services/email_auth.py +290 -0
- elva_cli-1.2.0/src/elva_cli/core/services/insights.py +113 -0
- elva_cli-1.2.0/src/elva_cli/core/services/insights_result.py +19 -0
- elva_cli-1.2.0/src/elva_cli/core/services/local_source.py +112 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/mcp.py +2 -14
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/mcp_common.py +19 -3
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/mcp_create.py +25 -4
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/mcp_publish.py +16 -3
- elva_cli-1.2.0/src/elva_cli/core/services/plan.py +206 -0
- elva_cli-1.2.0/src/elva_cli/core/services/plan_result.py +14 -0
- elva_cli-1.2.0/src/elva_cli/core/services/repo.py +397 -0
- elva_cli-1.2.0/src/elva_cli/core/services/repo_result.py +60 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/whoami.py +5 -1
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/workspace_list.py +10 -3
- elva_cli-1.2.0/src/elva_cli/core/source_snapshot.py +319 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/main.py +82 -3
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/registry.py +9 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/settings/models.py +4 -2
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/settings/writer.py +6 -1
- elva_cli-1.2.0/src/elva_cli/ui/input.py +18 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/ui/renderables/__init__.py +4 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/ui/renderables/auth.py +17 -0
- elva_cli-1.2.0/src/elva_cli/ui/renderables/contract.py +58 -0
- elva_cli-1.2.0/src/elva_cli/ui/renderables/insights.py +47 -0
- elva_cli-1.2.0/src/elva_cli/ui/renderables/plan.py +31 -0
- elva_cli-1.2.0/src/elva_cli/ui/renderables/repo.py +69 -0
- elva_cli-1.2.0/tests/__init__.py +0 -0
- elva_cli-1.2.0/tests/cli/__init__.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/cli/conftest.py +11 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/cli/test_auth_register_command.py +3 -3
- elva_cli-1.2.0/tests/cli/test_insights_contract.py +433 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/cli/test_never_blocks.py +6 -0
- elva_cli-1.2.0/tests/cli/test_regressions.py +136 -0
- elva_cli-1.2.0/tests/cli/test_repo.py +435 -0
- elva_cli-1.2.0/tests/conftest.py +32 -0
- elva_cli-1.2.0/tests/fixtures/agent-artifact.json +47 -0
- elva_cli-1.2.0/tests/isolation/sitecustomize.py +27 -0
- elva_cli-1.2.0/tests/unit/test_agent_artifact.py +213 -0
- elva_cli-1.2.0/tests/unit/test_cli_validation_regressions.py +131 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_collections_flow.py +4 -4
- elva_cli-1.2.0/tests/unit/test_email_auth.py +271 -0
- elva_cli-1.2.0/tests/unit/test_insights_contract.py +61 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_login_flow.py +7 -5
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_mcp_create_flow.py +4 -4
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_mcp_flow.py +6 -6
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_mcp_logs_flow.py +3 -3
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_mcp_publish_flow.py +4 -4
- elva_cli-1.2.0/tests/unit/test_plan.py +144 -0
- elva_cli-1.2.0/tests/unit/test_prompt_workflow.py +171 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_register_flow.py +6 -4
- elva_cli-1.2.0/tests/unit/test_repo.py +42 -0
- elva_cli-1.2.0/tests/unit/test_source_snapshot.py +268 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_targets.py +28 -5
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_workspace_list.py +18 -0
- elva_cli-1.1.0rc2/CHANGELOG.md +0 -40
- elva_cli-1.1.0rc2/README.md +0 -733
- elva_cli-1.1.0rc2/src/elva_cli/commands/auth.py +0 -51
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/__init__.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/__main__.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/auth/__init__.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/auth/store.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/commands/__init__.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/commands/collection.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/commands/config.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/commands/import_.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/commands/whoami.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/commands/workspace.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/context.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/__init__.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/api/__init__.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/api/collections.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/api/identity.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/openapi_ops.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/__init__.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/config.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/import_postman.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/import_result.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/import_spec.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/mcp_create_result.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/mcp_logs.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/mcp_logs_result.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/mcp_result.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/postman_result.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/whoami_result.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/workspace_list_result.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/workspace_switch.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/services/workspace_switch_result.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/spec/__init__.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/spec/detect.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/spec/fetch.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/core/spec/normalize.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/errors.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/logging.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/safe_text.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/settings/__init__.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/settings/loader.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/settings/paths.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/telemetry.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/ui/__init__.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/ui/console.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/ui/output.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/ui/prompts.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/ui/renderables/base.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/ui/renderables/collection.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/ui/renderables/config.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/ui/renderables/import_spec.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/ui/renderables/mcp.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/ui/renderables/mcp_create.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/ui/renderables/mcp_logs.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/ui/renderables/postman.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/ui/renderables/whoami.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/ui/renderables/workspace.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/ui/secrets.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/ui/theme.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/ui/views/__init__.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/src/elva_cli/update.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/cli/test_auth_logout_command.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/cli/test_cli_exit_codes.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/cli/test_collection_command.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/cli/test_config_command.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/cli/test_config_write.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/cli/test_import_command.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/cli/test_import_postman_command.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/cli/test_lazy_imports.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/cli/test_mcp_command.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/cli/test_mcp_create_command.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/cli/test_mcp_logs_command.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/cli/test_mcp_publish_command.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/cli/test_output_streams.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/cli/test_whoami_command.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/cli/test_workspace_switch_command.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_boundary.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_collection_endpoints.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_collection_endpoints_flow.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_collection_show.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_context.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_credentials.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_error_boundary.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_errors.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_exit_codes.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_http.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_import_flow.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_interactivity.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_logout_flow.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_mcp_create_operations.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_openapi_ops.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_output.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_postman_flow.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_prompts.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_refresh_client.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_safe_output.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_secret_input.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_secrets.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_session.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_settings_loader.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_settings_writer.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_spec_detect.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_spec_fetch.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_token_store.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_whoami_flow.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_workspace_render.py +0 -0
- {elva_cli-1.1.0rc2 → elva_cli-1.2.0}/tests/unit/test_workspace_switch.py +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Report a reproducible CLI problem
|
|
3
|
+
body:
|
|
4
|
+
- type: input
|
|
5
|
+
id: version
|
|
6
|
+
attributes:
|
|
7
|
+
label: CLI version and installation method
|
|
8
|
+
validations:
|
|
9
|
+
required: true
|
|
10
|
+
- type: input
|
|
11
|
+
id: environment
|
|
12
|
+
attributes:
|
|
13
|
+
label: OS, shell and Python version
|
|
14
|
+
- type: textarea
|
|
15
|
+
id: reproduction
|
|
16
|
+
attributes:
|
|
17
|
+
label: Synthetic reproduction
|
|
18
|
+
description: Include commands and redacted errors. Do not include tokens, verification codes or customer data.
|
|
19
|
+
validations:
|
|
20
|
+
required: true
|
|
21
|
+
- type: textarea
|
|
22
|
+
id: result
|
|
23
|
+
attributes:
|
|
24
|
+
label: Expected and actual results
|
|
25
|
+
description: Include exit code and JSON status when available.
|
|
26
|
+
validations:
|
|
27
|
+
required: true
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Describe a developer or agent workflow need
|
|
3
|
+
body:
|
|
4
|
+
- type: textarea
|
|
5
|
+
id: problem
|
|
6
|
+
attributes:
|
|
7
|
+
label: Workflow and problem
|
|
8
|
+
validations:
|
|
9
|
+
required: true
|
|
10
|
+
- type: textarea
|
|
11
|
+
id: outcome
|
|
12
|
+
attributes:
|
|
13
|
+
label: Desired outcome
|
|
14
|
+
validations:
|
|
15
|
+
required: true
|
|
16
|
+
- type: textarea
|
|
17
|
+
id: constraints
|
|
18
|
+
attributes:
|
|
19
|
+
label: Constraints and current workaround
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
## Change
|
|
2
|
+
|
|
3
|
+
Describe the user-visible problem and resulting behavior.
|
|
4
|
+
|
|
5
|
+
## Validation
|
|
6
|
+
|
|
7
|
+
State checks run and gaps. Distinguish fixtures, real services, packaged CLI and
|
|
8
|
+
native-agent validation.
|
|
9
|
+
|
|
10
|
+
## Compatibility and docs
|
|
11
|
+
|
|
12
|
+
For public behavior changes, note help/docs, JSON/exit codes, backend requirements,
|
|
13
|
+
and changes to source uploads, credentials, drafts or publication. Omit inapplicable
|
|
14
|
+
sections. Do not include secrets or customer data.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: ci-${{ github.ref }}
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
wheel-and-minimum-typer:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
with:
|
|
21
|
+
fetch-depth: 0
|
|
22
|
+
- uses: astral-sh/setup-uv@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.11"
|
|
25
|
+
- run: uv build
|
|
26
|
+
- run: |
|
|
27
|
+
uv venv /tmp/wheel
|
|
28
|
+
uv pip install --python /tmp/wheel/bin/python dist/*.whl typer==0.27.1
|
|
29
|
+
/tmp/wheel/bin/python scripts/smoke_wheel.py
|
|
30
|
+
|
|
31
|
+
lint:
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@v4
|
|
35
|
+
- uses: astral-sh/setup-uv@v5
|
|
36
|
+
with:
|
|
37
|
+
enable-cache: true
|
|
38
|
+
- run: uv sync --extra dev
|
|
39
|
+
- run: uv run ruff check .
|
|
40
|
+
- run: uv run ruff format --check .
|
|
41
|
+
- run: uv run mypy
|
|
42
|
+
|
|
43
|
+
test:
|
|
44
|
+
runs-on: ${{ matrix.os }}
|
|
45
|
+
strategy:
|
|
46
|
+
fail-fast: false
|
|
47
|
+
matrix:
|
|
48
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
49
|
+
python: ["3.11", "3.12", "3.13"]
|
|
50
|
+
steps:
|
|
51
|
+
- uses: actions/checkout@v4
|
|
52
|
+
- uses: astral-sh/setup-uv@v5
|
|
53
|
+
with:
|
|
54
|
+
enable-cache: true
|
|
55
|
+
python-version: ${{ matrix.python }}
|
|
56
|
+
- run: uv sync --extra dev
|
|
57
|
+
- run: uv run pytest
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
name: installer
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths: ["install/**", ".github/workflows/installer.yml"]
|
|
7
|
+
pull_request:
|
|
8
|
+
paths: ["install/**", ".github/workflows/installer.yml"]
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
concurrency:
|
|
15
|
+
group: installer-${{ github.ref }}
|
|
16
|
+
cancel-in-progress: false
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
check:
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
timeout-minutes: 10
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
- uses: actions/setup-node@v4
|
|
25
|
+
with:
|
|
26
|
+
node-version: "22"
|
|
27
|
+
- run: npm install --global firebase-tools@15.32.1
|
|
28
|
+
- name: Prepare installer
|
|
29
|
+
run: |
|
|
30
|
+
sh -n install/install.sh
|
|
31
|
+
mkdir -p install/public
|
|
32
|
+
cp install/install.sh install/public/install.sh
|
|
33
|
+
- name: Test hosting
|
|
34
|
+
run: >-
|
|
35
|
+
firebase emulators:exec
|
|
36
|
+
--project demo-elva-cli-install
|
|
37
|
+
--config install/firebase.json
|
|
38
|
+
--only hosting
|
|
39
|
+
"sh install/test-hosting.sh"
|
|
40
|
+
|
|
41
|
+
deploy:
|
|
42
|
+
if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request'
|
|
43
|
+
needs: check
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
timeout-minutes: 10
|
|
46
|
+
environment: installer
|
|
47
|
+
permissions:
|
|
48
|
+
contents: read
|
|
49
|
+
id-token: write
|
|
50
|
+
steps:
|
|
51
|
+
- uses: actions/checkout@v4
|
|
52
|
+
- uses: actions/setup-node@v4
|
|
53
|
+
with:
|
|
54
|
+
node-version: "22"
|
|
55
|
+
- run: npm install --global firebase-tools@15.32.1
|
|
56
|
+
- name: Prepare installer
|
|
57
|
+
run: |
|
|
58
|
+
mkdir -p install/public
|
|
59
|
+
cp install/install.sh install/public/install.sh
|
|
60
|
+
- uses: google-github-actions/auth@v3
|
|
61
|
+
with:
|
|
62
|
+
workload_identity_provider: ${{ vars.ELVA_INSTALLER_WIF_PROVIDER }}
|
|
63
|
+
service_account: ${{ vars.ELVA_INSTALLER_DEPLOY_SA }}
|
|
64
|
+
- name: Deploy installer
|
|
65
|
+
run: >-
|
|
66
|
+
firebase deploy
|
|
67
|
+
--project elva-marketing-prod
|
|
68
|
+
--config install/firebase.json
|
|
69
|
+
--only hosting
|
|
70
|
+
--non-interactive
|
|
71
|
+
- name: Verify published script
|
|
72
|
+
run: |
|
|
73
|
+
curl --fail --silent --show-error --retry 5 --retry-all-errors \
|
|
74
|
+
'https://elva-cli-install.web.app/?revision=${{ github.sha }}' \
|
|
75
|
+
-o /tmp/published-install.sh
|
|
76
|
+
cmp install/install.sh /tmp/published-install.sh
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
with:
|
|
17
|
+
fetch-depth: 0
|
|
18
|
+
|
|
19
|
+
- uses: astral-sh/setup-uv@v5
|
|
20
|
+
|
|
21
|
+
- run: uv build
|
|
22
|
+
|
|
23
|
+
- name: Reject unpublishable versions
|
|
24
|
+
run: |
|
|
25
|
+
version=$(ls dist/*.whl | head -1 | sed -E 's/.*elva_cli-(.+)-py3.*/\1/')
|
|
26
|
+
echo "built version: $version"
|
|
27
|
+
case "$version" in
|
|
28
|
+
*+*) echo "::error::'$version' has a PEP 440 local segment; PyPI will reject it. Build from an exact tag." ; exit 1 ;;
|
|
29
|
+
*dev*) echo "::error::'$version' is a dev version; the tag is missing or HEAD is past it." ; exit 1 ;;
|
|
30
|
+
esac
|
|
31
|
+
|
|
32
|
+
- run: uvx twine check dist/*
|
|
33
|
+
|
|
34
|
+
- name: Smoke test the wheel in a clean environment
|
|
35
|
+
run: |
|
|
36
|
+
python3 -m venv /tmp/smoke
|
|
37
|
+
/tmp/smoke/bin/pip install --quiet dist/*.whl
|
|
38
|
+
/tmp/smoke/bin/python scripts/smoke_wheel.py
|
|
39
|
+
|
|
40
|
+
- uses: actions/upload-artifact@v4
|
|
41
|
+
with:
|
|
42
|
+
name: dist
|
|
43
|
+
path: dist/
|
|
44
|
+
|
|
45
|
+
testpypi:
|
|
46
|
+
if: github.event_name == 'workflow_dispatch'
|
|
47
|
+
needs: build
|
|
48
|
+
runs-on: ubuntu-latest
|
|
49
|
+
environment: testpypi
|
|
50
|
+
permissions:
|
|
51
|
+
id-token: write
|
|
52
|
+
steps:
|
|
53
|
+
- uses: actions/download-artifact@v4
|
|
54
|
+
with:
|
|
55
|
+
name: dist
|
|
56
|
+
path: dist/
|
|
57
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
58
|
+
with:
|
|
59
|
+
repository-url: https://test.pypi.org/legacy/
|
|
60
|
+
|
|
61
|
+
pypi:
|
|
62
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
63
|
+
needs: build
|
|
64
|
+
runs-on: ubuntu-latest
|
|
65
|
+
environment: pypi
|
|
66
|
+
permissions:
|
|
67
|
+
id-token: write
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/download-artifact@v4
|
|
70
|
+
with:
|
|
71
|
+
name: dist
|
|
72
|
+
path: dist/
|
|
73
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
74
|
+
|
|
75
|
+
binaries:
|
|
76
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
77
|
+
needs: build
|
|
78
|
+
strategy:
|
|
79
|
+
fail-fast: false
|
|
80
|
+
matrix:
|
|
81
|
+
include:
|
|
82
|
+
- { runner: ubuntu-latest, asset: elva-linux-x86_64 }
|
|
83
|
+
- { runner: ubuntu-24.04-arm, asset: elva-linux-aarch64 }
|
|
84
|
+
- { runner: macos-15-intel, asset: elva-darwin-x86_64 }
|
|
85
|
+
- { runner: macos-latest, asset: elva-darwin-arm64 }
|
|
86
|
+
runs-on: ${{ matrix.runner }}
|
|
87
|
+
steps:
|
|
88
|
+
- uses: actions/download-artifact@v4
|
|
89
|
+
with:
|
|
90
|
+
name: dist
|
|
91
|
+
path: dist/
|
|
92
|
+
|
|
93
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
94
|
+
|
|
95
|
+
- name: Build ${{ matrix.asset }}
|
|
96
|
+
env:
|
|
97
|
+
PYAPP_EXEC_SPEC: elva_cli.main:main
|
|
98
|
+
PYAPP_PYTHON_VERSION: "3.12"
|
|
99
|
+
PYAPP_DISTRIBUTION_EMBED: "1"
|
|
100
|
+
run: |
|
|
101
|
+
export PYAPP_PROJECT_PATH="$PWD/$(ls dist/*.whl | head -1)"
|
|
102
|
+
echo "embedding $PYAPP_PROJECT_PATH"
|
|
103
|
+
cargo install pyapp --force --locked --root out
|
|
104
|
+
mv out/bin/pyapp "${{ matrix.asset }}"
|
|
105
|
+
chmod +x "${{ matrix.asset }}"
|
|
106
|
+
|
|
107
|
+
- name: It runs, and reports the version we built
|
|
108
|
+
run: |
|
|
109
|
+
set +e
|
|
110
|
+
got="$(./${{ matrix.asset }} --version 2>&1)"
|
|
111
|
+
rc=$?
|
|
112
|
+
set -e
|
|
113
|
+
echo "$got"
|
|
114
|
+
if [ $rc -ne 0 ]; then
|
|
115
|
+
echo "::error::${{ matrix.asset }} exited $rc"
|
|
116
|
+
exit 1
|
|
117
|
+
fi
|
|
118
|
+
version="$(ls dist/*.whl | head -1 | sed -E 's/.*elva_cli-(.+)-py3.*/\1/')"
|
|
119
|
+
case "$got" in
|
|
120
|
+
"elva $version "*) ;;
|
|
121
|
+
*) echo "::error::expected version $version, got: $got"; exit 1 ;;
|
|
122
|
+
esac
|
|
123
|
+
|
|
124
|
+
- uses: actions/upload-artifact@v4
|
|
125
|
+
with:
|
|
126
|
+
name: ${{ matrix.asset }}
|
|
127
|
+
path: ${{ matrix.asset }}
|
|
128
|
+
|
|
129
|
+
publish-binaries:
|
|
130
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
131
|
+
needs: binaries
|
|
132
|
+
runs-on: ubuntu-latest
|
|
133
|
+
permissions:
|
|
134
|
+
contents: write
|
|
135
|
+
steps:
|
|
136
|
+
- uses: actions/download-artifact@v4
|
|
137
|
+
with:
|
|
138
|
+
pattern: elva-*
|
|
139
|
+
path: bin/
|
|
140
|
+
merge-multiple: true
|
|
141
|
+
|
|
142
|
+
- name: Checksums
|
|
143
|
+
working-directory: bin
|
|
144
|
+
run: |
|
|
145
|
+
chmod +x elva-*
|
|
146
|
+
sha256sum elva-* > SHA256SUMS
|
|
147
|
+
cat SHA256SUMS
|
|
148
|
+
|
|
149
|
+
- name: Upload to the release
|
|
150
|
+
env:
|
|
151
|
+
GH_TOKEN: ${{ github.token }}
|
|
152
|
+
run: |
|
|
153
|
+
case "$GITHUB_REF_NAME" in
|
|
154
|
+
*-*) prerelease="--prerelease" ;;
|
|
155
|
+
*) prerelease="" ;;
|
|
156
|
+
esac
|
|
157
|
+
gh release view "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1 \
|
|
158
|
+
|| gh release create "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" \
|
|
159
|
+
--title "$GITHUB_REF_NAME" --generate-notes $prerelease
|
|
160
|
+
gh release upload "$GITHUB_REF_NAME" bin/* --repo "$GITHUB_REPOSITORY" --clobber
|
elva_cli-1.2.0/AGENTS.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Working on Elva CLI
|
|
2
|
+
|
|
3
|
+
This file guides changes to the CLI source. Agents consuming Elva should use the
|
|
4
|
+
[canonical skill](src/elva_cli/assets/elva-mcp/SKILL.md), installed by `elva agent setup`,
|
|
5
|
+
and the [agent interface](docs/agent-interface.md).
|
|
6
|
+
|
|
7
|
+
## Preserve behavior
|
|
8
|
+
|
|
9
|
+
Keep terminal I/O at the command/UI boundary and expensive imports lazy. Every
|
|
10
|
+
interactive input needs an unattended equivalent. Preserve stable JSON fields,
|
|
11
|
+
exit codes, retry IDs, and draft/publication separation. The existing-agent path
|
|
12
|
+
sends generated API artifacts; never silently switch it to source upload or Elva AI.
|
|
13
|
+
Use synthetic data and isolated profiles. Real services, email and publication
|
|
14
|
+
must stay within the user's authorized scope. Do not commit secrets or private data.
|
|
15
|
+
|
|
16
|
+
## Validate and document
|
|
17
|
+
|
|
18
|
+
Follow [CONTRIBUTING.md](CONTRIBUTING.md). Run relevant tests; complete checks are
|
|
19
|
+
`ruff check .`, `ruff format --check .`, `mypy`, and `pytest`. Check changed examples
|
|
20
|
+
and links. Align `uv.lock` after dependency changes. Update help, guides and changelog
|
|
21
|
+
for public behavior changes. Keep the bundled skill canonical and include required
|
|
22
|
+
assets in distributions. Do not edit generated `_version.py`. Report actual checks
|
|
23
|
+
and distinguish fixtures from production, runtime and native-agent validation.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
### Repository documentation
|
|
6
|
+
- Add an agent-first quickstart, shareable skill link, recovery/privacy guides,
|
|
7
|
+
contributor instructions, offline example and issue/PR templates.
|
|
8
|
+
- Restore features onto current main, retaining standalone installer support.
|
|
9
|
+
|
|
10
|
+
### Email-only CLI onboarding
|
|
11
|
+
|
|
12
|
+
- Add `auth signup` / `auth register` with email-only verification, automatic account
|
|
13
|
+
and default workspace setup, `auth verify --code-stdin`, and `auth resume`.
|
|
14
|
+
- Preserve a generated API artifact locally with `--continue-artifact`; return its
|
|
15
|
+
next command after login without source upload or another signup form.
|
|
16
|
+
- Bind signup proof and newly saved credentials to their API origin, recover lost
|
|
17
|
+
responses, keep codes out of arguments/output, and acknowledge durable storage.
|
|
18
|
+
- Teach the bundled agent skill to complete onboarding with authorized email access.
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Existing-agent API artifacts
|
|
22
|
+
|
|
23
|
+
- Add `agent setup`, `agent schema`, `agent validate`, and `agent create`.
|
|
24
|
+
- Bundle discoverable Claude Code/Codex instructions for generating an API definition locally.
|
|
25
|
+
- Import only sanitized API artifacts; create resumable collection/contract/MCP drafts without Elva AI or GitHub.
|
|
26
|
+
- Require the matching artifact-plan backend before release.
|
|
27
|
+
|
|
28
|
+
### Prompt from a local checkout
|
|
29
|
+
- Add root `--prompt` to scan raw source with Elva AI, generate OpenAPI collections,
|
|
30
|
+
select customer endpoints/fields, and create a reviewed draft contract and MCP.
|
|
31
|
+
- No GitHub connection or manually authored specification is required.
|
|
32
|
+
- Add audience/API URL follow-ups, bounded filtered uploads, independent ignore
|
|
33
|
+
rules, secret redaction, auth options, `--plan-only` and `--resume` recovery.
|
|
34
|
+
- Preserve source collections on planning retries and keep draft publication governed.
|
|
35
|
+
|
|
36
|
+
### Workspace defaults, API insights and contracts
|
|
37
|
+
- Select the default Elva workspace automatically when no selection is configured,
|
|
38
|
+
including accounts with several workspaces. Mark that default in `workspace list`.
|
|
39
|
+
- Add `insights checks`, `insights review`, and `insights show`, with JSON output
|
|
40
|
+
and an optional overall-score gate for CI.
|
|
41
|
+
- Add `contract list/show/create/update/sync/approve/reject/publish/delete`.
|
|
42
|
+
Creation is draft-only; publication is explicit and reports partial results.
|
|
43
|
+
- Support PAT workspace discovery and scoped collection/contract reads and
|
|
44
|
+
lifecycle actions with the matching backend, preserving membership and roles.
|
|
45
|
+
|
|
46
|
+
### GitHub repository sync
|
|
47
|
+
- Add `repo list`, `repo connect`, `repo sync`, and `repo status` using Elva's
|
|
48
|
+
existing linked GitHub account and scan pipeline.
|
|
49
|
+
- Support remote branch selection, explicit AI extraction, workspace scoping,
|
|
50
|
+
resumable bounded waits, JSON results, and collection change summaries.
|
|
51
|
+
- Preserve reconnect settings, refuse unscoped backends before mutations, and
|
|
52
|
+
report partial connection, failed scans and skipped collection sync accurately.
|
|
53
|
+
- Require the matching workspace-scoped repository backend before CLI rollout.
|
|
54
|
+
|
|
55
|
+
### CLI validation fixes
|
|
56
|
+
- Support Windows source snapshots without POSIX-only open flags, retaining regular-file
|
|
57
|
+
and file-identity checks, and read installed skills consistently as UTF-8 on repeat setup.
|
|
58
|
+
- Isolate interactive tests from all CI provider flags and make newline, permission and
|
|
59
|
+
oversized-input test cases portable across the supported OS/Python matrix.
|
|
60
|
+
- Return complete MCP endpoints, including the workspace component, consistently
|
|
61
|
+
from create, show, and publish; drafts have no connection URL.
|
|
62
|
+
- Preserve Ctrl-C exit status 130, honor `timeout` / `ELVA_TIMEOUT` in every HTTP
|
|
63
|
+
transport, and reject non-finite timeouts before changing config files.
|
|
64
|
+
- Report denied access as `ELVA_FORBIDDEN` (exit 3) without deleting credentials.
|
|
65
|
+
- Require Typer 0.27.1 or newer, matching the vendored Click API the CLI uses.
|
|
66
|
+
- Correct the endpoints-to-MCP pipeline and distinguish source docs from PyPI 0.5.0.
|
|
67
|
+
- Isolate test profiles on macOS as well as Linux/Windows; smoke-test wheel commands.
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
### Added
|
|
71
|
+
- **Identify as a first-class refresh client (ELVA-200).** Every request now
|
|
72
|
+
sends `X-Elva-Client: cli` and a `User-Agent: elva-cli/<version>`. The refresh
|
|
73
|
+
and CLI-login exchanges carry the marker so the backend routes them on the
|
|
74
|
+
body-token path and, once its compatibility flag is turned off, does not
|
|
75
|
+
reject the CLI as an unmarked client.
|
|
76
|
+
- **Refresh-and-retry on 401.** An idempotent request (GET/HEAD) that returns
|
|
77
|
+
401 on a token that looked valid now forces one refresh and retries once.
|
|
78
|
+
Non-idempotent requests (the spec upload) are never auto-replayed.
|
|
79
|
+
- **Backoff on transient refresh failures.** A refresh that hits 429/5xx or a
|
|
80
|
+
network error is retried with backoff (1s/2s/4s) before surfacing as a
|
|
81
|
+
transient `ApiError` (exit 5); it never forces a re-login.
|
|
82
|
+
|
|
83
|
+
### Changed
|
|
84
|
+
- Refresh continues to happen proactively ~60s before the access token expires
|
|
85
|
+
and to persist the rotated token atomically (temp file + rename, 0600) before
|
|
86
|
+
the response is used — unchanged, but now covered by explicit tests.
|
|
87
|
+
- **`elva import spec --url` now fetches through Elva and uploads like a file.**
|
|
88
|
+
The URL is fetched via Elva's `fetch-file` proxy (the same path the web app
|
|
89
|
+
uses, so a spec host only Elva can reach still works), a JSON spec is stored
|
|
90
|
+
as YAML to match a web-app import instead of one minified line, and `--name`
|
|
91
|
+
now defaults from the fetched spec's `info.title`. `--dry-run --url` reports
|
|
92
|
+
the real title/version/endpoint count/size, and a spec URL that 404s or times
|
|
93
|
+
out is now a usage error (exit 2) rather than a late server rejection. Local
|
|
94
|
+
`.json` files are converted to YAML on import for the same consistency.
|
|
95
|
+
|
|
96
|
+
### Compatibility
|
|
97
|
+
This version works with **both** the flagged and the unflagged backend:
|
|
98
|
+
- While the backend keeps `AUTH_ALLOW_BODY_REFRESH_TOKEN` on, unmarked body
|
|
99
|
+
refreshes still work, so **older CLI versions keep working** too.
|
|
100
|
+
- Once the backend turns that flag off (this CLI version being the minimum
|
|
101
|
+
supported), the server rejects unmarked and legacy ("family-less") refresh
|
|
102
|
+
tokens with `401 REFRESH_TOKEN_LEGACY`. This CLI maps that to
|
|
103
|
+
*"Your session has expired. Run `elva auth login` to sign in again."*
|
|
104
|
+
(exit code 3). **Older CLI versions stop working at that point** and users
|
|
105
|
+
must upgrade and re-login once.
|
elva_cli-1.2.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Elva CLI development
|
|
2
|
+
|
|
3
|
+
Follow [AGENTS.md](AGENTS.md) when changing this repository. To create an MCP from
|
|
4
|
+
another API repository, use the [Elva skill](src/elva_cli/assets/elva-mcp/SKILL.md)
|
|
5
|
+
and [agent interface](docs/agent-interface.md). This file does not install that skill
|
|
6
|
+
into another project; use `elva agent setup`.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Contributing to Elva CLI
|
|
2
|
+
|
|
3
|
+
Use GitHub issues for reproducible bugs and feature requests. Report vulnerabilities
|
|
4
|
+
privately using [SECURITY.md](SECURITY.md).
|
|
5
|
+
|
|
6
|
+
## Setup
|
|
7
|
+
|
|
8
|
+
Use Python 3.11 or newer. Clone the repository and check out the intended branch:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
git clone https://github.com/Theneo-Inc/theneo-elva-cli.git
|
|
12
|
+
cd theneo-elva-cli
|
|
13
|
+
python3 -m venv .venv
|
|
14
|
+
source .venv/bin/activate
|
|
15
|
+
python -m pip install -e ".[dev]"
|
|
16
|
+
elva --version
|
|
17
|
+
elva --help
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
In PowerShell, use `py -m venv .venv` and `.venv\Scripts\Activate.ps1`.
|
|
21
|
+
Alternatively, run `uv sync --locked --extra dev` and `uv run elva --help`.
|
|
22
|
+
When changing dependencies, run `uv lock`, review its diff and commit `uv.lock`
|
|
23
|
+
with `pyproject.toml`. Verify freshness with `uv lock --check`.
|
|
24
|
+
|
|
25
|
+
## Checks
|
|
26
|
+
|
|
27
|
+
Run focused tests while editing, then the complete checks before merging:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
ruff check .
|
|
31
|
+
ruff format --check .
|
|
32
|
+
mypy
|
|
33
|
+
pytest
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Plain `mypy` checks source and tests; `mypy src` does not match CI. CI also defines
|
|
37
|
+
Linux/macOS/Windows coverage for Python 3.11–3.13 and a clean-wheel/minimum-Typer
|
|
38
|
+
check. Record actual results; a configured matrix is not evidence that it passed.
|
|
39
|
+
|
|
40
|
+
Tests use synthetic data and isolated CLI profiles. Preserve that isolation.
|
|
41
|
+
Use real services, email, source upload or publication only in the user's authorized
|
|
42
|
+
scope and environment. Never include tokens or customer data in fixtures.
|
|
43
|
+
|
|
44
|
+
## Architecture
|
|
45
|
+
|
|
46
|
+
- `commands/`: Typer options and command orchestration.
|
|
47
|
+
- `core/services/`: service calls and typed results.
|
|
48
|
+
- `core/api/`: HTTP transport and API target resolution.
|
|
49
|
+
- `core/spec/`: API format detection and normalization.
|
|
50
|
+
- `core/agent_*.py`: artifact validation and skill installation.
|
|
51
|
+
- `auth/`: credentials, browser/email sessions and refresh.
|
|
52
|
+
- `settings/`: profiles, configuration and precedence.
|
|
53
|
+
- `ui/`: terminal output and prompts.
|
|
54
|
+
- `assets/elva-mcp/`: canonical installed skill.
|
|
55
|
+
|
|
56
|
+
These paths are under `src/elva_cli/`. Keep terminal I/O at the command/UI boundary
|
|
57
|
+
and expensive imports lazy. Every interactive input needs an unattended equivalent.
|
|
58
|
+
Preserve exit codes, JSON contracts, retry IDs and the distinction between drafts
|
|
59
|
+
and publication. Keep Python and backend artifact schemas aligned.
|
|
60
|
+
|
|
61
|
+
## Documentation and PRs
|
|
62
|
+
|
|
63
|
+
Keep the README focused on onboarding and detailed commands in `docs/`. Update help,
|
|
64
|
+
the relevant guide and changelog for public behavior changes. Maintain one canonical
|
|
65
|
+
skill in `src/elva_cli/assets/elva-mcp/`.
|
|
66
|
+
|
|
67
|
+
Validate examples offline and check relative links:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
elva --json agent validate --from examples/customer-orders/artifact.json
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The example is synthetic. Local validation, resource creation, publication, live
|
|
74
|
+
runtime access and native agent discovery are separate checks.
|
|
75
|
+
|
|
76
|
+
PRs should describe the problem, resulting behavior, validation and any backend
|
|
77
|
+
compatibility requirements. Do not edit generated `src/elva_cli/_version.py`.
|
|
78
|
+
See [AGENTS.md](AGENTS.md), [RELEASING.md](RELEASING.md) and
|
|
79
|
+
[repository readiness](docs/repository-readiness.md).
|