superqode 0.1.8__tar.gz → 0.1.10__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.
- {superqode-0.1.8/src/superqode.egg-info → superqode-0.1.10}/PKG-INFO +1 -1
- {superqode-0.1.8 → superqode-0.1.10}/pyproject.toml +1 -1
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/__init__.py +1 -1
- superqode-0.1.10/src/superqode/agents/data/ampcode.com.toml +69 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/registry.py +13 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/app_main.py +12 -3
- superqode-0.1.10/src/superqode/auth/__init__.py +264 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/commands/acp.py +109 -109
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/commands/auth.py +134 -12
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/execution/resolver.py +40 -2
- {superqode-0.1.8 → superqode-0.1.10/src/superqode.egg-info}/PKG-INFO +1 -1
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode.egg-info/SOURCES.txt +3 -0
- superqode-0.1.10/tests/test_auth.py +181 -0
- {superqode-0.1.8 → superqode-0.1.10}/LICENSE +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/README.md +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/setup.cfg +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/acp/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/acp/client.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/acp/permission_screen.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/acp/types.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/acp_discovery.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agent/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agent/edit_strategies.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agent/loop.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agent/qe_report_templates.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agent/system_prompts.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agent_output.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agent_stream.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/acp_registry.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/client.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/data/augmentcode.com.toml +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/data/cagent.dev.toml +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/data/claude.com.toml +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/data/codeassistant.dev.toml +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/data/codex.openai.com.toml +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/data/fastagent.ai.toml +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/data/geminicli.com.toml +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/data/goose.block.xyz.toml +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/data/junie.jetbrains.com.toml +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/data/kimi.moonshot.cn.toml +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/data/llmlingagent.dev.toml +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/data/molt.bot.toml +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/data/opencode.ai.toml +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/data/stakpak.dev.toml +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/data/vtcode.dev.toml +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/discovery.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/messaging.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/persona.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/schema.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/agents/unified.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/app/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/app/constants.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/app/css.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/app/models.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/app/suggester.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/app/widgets.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/app_enhanced.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/approval.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/atomic.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/commands/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/commands/agents.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/commands/config.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/commands/init.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/commands/providers.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/commands/qe.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/commands/roles.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/commands/serve.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/commands/suggestions.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/commands/superqe.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/config/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/config/loader.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/config/schema.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/core/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/core/roles.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/danger.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/data/superqode-template.yaml +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/design_system.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/dialogs/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/dialogs/base.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/dialogs/model.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/dialogs/provider.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/diff_view.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/enterprise.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/evaluation/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/evaluation/adapters.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/evaluation/behaviors.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/evaluation/engine.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/evaluation/scenarios.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/execution/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/execution/linter.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/execution/modes.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/execution/runner.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/file_explorer.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/file_viewer.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/flash.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/guidance/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/guidance/config.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/guidance/prompts.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/harness/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/harness/accelerator.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/harness/config.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/harness/validator.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/history.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/integrations/superopt_runner.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/logging/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/logging/adapters.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/logging/formatter.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/logging/integration.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/logging/sinks.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/logging/unified_log.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/lsp/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/lsp/client.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/main.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/mcp/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/mcp/auth_storage.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/mcp/client.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/mcp/config.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/mcp/integration.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/mcp/oauth.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/mcp/oauth_callback.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/mcp/types.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/memory/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/memory/feedback.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/memory/store.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/notifications.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/optimization/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/optimization/config.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/permissions/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/permissions/rules.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/plan.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/gateway/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/gateway/base.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/gateway/litellm_gateway.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/gateway/openresponses_gateway.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/health.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/huggingface/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/huggingface/downloader.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/huggingface/endpoints.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/huggingface/hub.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/huggingface/inference.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/huggingface/transformers_runner.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/local/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/local/base.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/local/discovery.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/local/lmstudio.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/local/mlx.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/local/ollama.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/local/sglang.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/local/tgi.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/local/tool_support.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/local/vllm.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/manager.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/models.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/models_dev.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/openresponses/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/openresponses/converters/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/openresponses/converters/messages.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/openresponses/converters/tools.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/openresponses/schema/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/openresponses/schema/models.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/openresponses/streaming/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/openresponses/streaming/parser.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/openresponses/tools/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/openresponses/tools/apply_patch.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/openresponses/tools/code_interpreter.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/openresponses/tools/file_search.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/openresponses/tools/mcp_adapter.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/registry.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/providers/usage.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/pure_mode.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/qr/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/qr/dashboard.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/qr/generator.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/qr/templates.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/safety/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/safety/sandbox.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/safety/warnings.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/server/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/server/lsp_server.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/server/web.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/session/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/session/persistence.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/session/sharing.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/session.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/sidebar.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/stream_view.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/styles/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/acp_runner.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/constitution/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/constitution/evaluator.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/constitution/loader.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/constitution/schema.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/events.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/frameworks/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/frameworks/base.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/frameworks/e2e.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/frameworks/executor.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/frameworks/javascript.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/frameworks/python.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/frameworks/registry.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/mcp_tools/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/mcp_tools/core_tools.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/mcp_tools/registry.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/mcp_tools/testing_tools.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/noise.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/orchestrator.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/roles.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/session.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/skills/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/skills/base.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/skills/core_skills.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/skills/registry.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe/verifier.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/superqe_cli.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tool_call.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tools/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tools/agent_tools.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tools/base.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tools/batch_tool.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tools/diagnostics.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tools/edit_tools.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tools/enhanced_base.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tools/file_tools.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tools/file_tracking.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tools/lsp_tools.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tools/network_tools.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tools/permissions.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tools/question_tool.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tools/search_tools.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tools/shell_tools.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tools/todo_tools.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tools/validation.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tools/web_tools.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tui.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tui_integration.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tui_widgets/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tui_widgets/widgets/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tui_widgets/widgets/progress.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/tui_widgets/widgets/tool_display.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/undo_manager.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/utils/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/utils/error_handling.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/utils/fuzzy.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/agent_collab.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/agent_store.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/agent_switcher.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/animation_manager.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/code_context.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/command_palette.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/connection_status.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/conversation_history.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/diff_indicator.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/enhanced_status_bar.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/enhanced_toast.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/file_browser.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/file_reference.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/issue_timeline.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/leader_key.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/mode_switcher.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/model_picker.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/permission_preview.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/prompt.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/provider_connect.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/pty_shell.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/qe_dashboard.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/resizable_sidebar.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/response_changes.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/response_display.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/rich_tool_display.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/sidebar_panels.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/slash_complete.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/split_view.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/status_bar.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/superqode_display.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/thinking_display.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/throbber.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/toast.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/widgets/unified_output.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/workspace/__init__.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/workspace/artifacts.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/workspace/coordinator.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/workspace/diff_tracker.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/workspace/git_guard.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/workspace/git_snapshot.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/workspace/manager.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/workspace/snapshot.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/workspace/watcher.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode/workspace/worktree.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode.egg-info/dependency_links.txt +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode.egg-info/entry_points.txt +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode.egg-info/requires.txt +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/src/superqode.egg-info/top_level.txt +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/tests/test_acp_client.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/tests/test_cli_commands.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/tests/test_linter_runner.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/tests/test_login_api.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/tests/test_mcp.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/tests/test_mcp_integration.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/tests/test_mcp_live.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/tests/test_orchestrator.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/tests/test_oss_integration.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/tests/test_simple_login.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/tests/test_tools.py +0 -0
- {superqode-0.1.8 → superqode-0.1.10}/tests/test_workspace.py +0 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Schema defined in agent_schema.py
|
|
2
|
+
# https://ampcode.com
|
|
3
|
+
|
|
4
|
+
identity = "ampcode.com"
|
|
5
|
+
name = "Amp"
|
|
6
|
+
short_name = "amp"
|
|
7
|
+
url = "https://ampcode.com"
|
|
8
|
+
protocol = "acp"
|
|
9
|
+
author_name = "Ampcode"
|
|
10
|
+
author_url = "https://ampcode.com"
|
|
11
|
+
publisher_name = "Superagentic AI"
|
|
12
|
+
publisher_url = "https://super-agentic.ai"
|
|
13
|
+
type = "coding"
|
|
14
|
+
description = "AI coding agent by Ampcode. Works in any codebase with full ACP support via acp-amp adapter."
|
|
15
|
+
tags = ["ampcode", "amp", "coding", "acp"]
|
|
16
|
+
run_command."*" = "acp-amp"
|
|
17
|
+
|
|
18
|
+
help = '''
|
|
19
|
+
# Amp
|
|
20
|
+
|
|
21
|
+
AI coding agent by Ampcode. Works in any codebase with full ACP support.
|
|
22
|
+
|
|
23
|
+
- Multi-turn conversations with thread continuity
|
|
24
|
+
- Full tool execution with permission modes
|
|
25
|
+
- MCP server integration
|
|
26
|
+
- Image support
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
Install Amp CLI and the ACP adapter:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Install Amp CLI
|
|
34
|
+
curl -fsSL https://ampcode.com/install.sh | bash
|
|
35
|
+
amp login
|
|
36
|
+
|
|
37
|
+
# Install ACP adapter (Python - recommended)
|
|
38
|
+
uv tool install acp-amp
|
|
39
|
+
|
|
40
|
+
# Alternative: Node.js
|
|
41
|
+
npm install -g @superagenticai/acp-amp
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Requirements:**
|
|
45
|
+
- Amp CLI authenticated (`amp login`)
|
|
46
|
+
- Python 3.10+ with uv (for Python version)
|
|
47
|
+
- Or Node.js 18+ (for Node.js version)
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
**For latest install instructions**: https://superagenticai.github.io/acp-amp/
|
|
52
|
+
**ACP Adapter**: https://github.com/SuperagenticAI/acp-amp
|
|
53
|
+
'''
|
|
54
|
+
|
|
55
|
+
welcome = '''
|
|
56
|
+
Welcome to Amp! 🚀
|
|
57
|
+
|
|
58
|
+
I'm Amp, an AI coding agent by Ampcode. I can help you with:
|
|
59
|
+
- Code analysis and refactoring
|
|
60
|
+
- Bug fixing and debugging
|
|
61
|
+
- Writing new features
|
|
62
|
+
- Code review and optimization
|
|
63
|
+
|
|
64
|
+
Just tell me what you'd like to work on!
|
|
65
|
+
'''
|
|
66
|
+
|
|
67
|
+
[actions."*".install]
|
|
68
|
+
command = "uv tool install acp-amp"
|
|
69
|
+
description = "Install Amp ACP adapter (see https://superagenticai.github.io/acp-amp/ for latest)"
|
|
@@ -247,6 +247,19 @@ AGENTS: Dict[str, AgentDef] = {
|
|
|
247
247
|
connection_type="stdio",
|
|
248
248
|
command="llmling-agent --acp",
|
|
249
249
|
),
|
|
250
|
+
"amp": AgentDef(
|
|
251
|
+
id="amp",
|
|
252
|
+
name="Amp",
|
|
253
|
+
protocol=AgentProtocol.ACP,
|
|
254
|
+
status=AgentStatus.SUPPORTED,
|
|
255
|
+
description="AI coding agent by Ampcode with full ACP support",
|
|
256
|
+
auth_info="Managed via amp login",
|
|
257
|
+
setup_command="uv tool install acp-amp",
|
|
258
|
+
docs_url="https://ampcode.com",
|
|
259
|
+
capabilities=["File editing", "Shell commands", "MCP tools", "Multi-turn"],
|
|
260
|
+
connection_type="stdio",
|
|
261
|
+
command="acp-amp",
|
|
262
|
+
),
|
|
250
263
|
}
|
|
251
264
|
|
|
252
265
|
|
|
@@ -4660,7 +4660,7 @@ team:
|
|
|
4660
4660
|
else:
|
|
4661
4661
|
# Handle all other ACP-compatible agents generically
|
|
4662
4662
|
# This covers: junie, goose, kimi, stakpak, vtcode, auggie,
|
|
4663
|
-
# code-assistant, cagent, fast-agent, llmling-agent
|
|
4663
|
+
# code-assistant, cagent, fast-agent, llmling-agent, amp
|
|
4664
4664
|
acp_agents = {
|
|
4665
4665
|
"junie",
|
|
4666
4666
|
"goose",
|
|
@@ -4672,6 +4672,7 @@ team:
|
|
|
4672
4672
|
"cagent",
|
|
4673
4673
|
"fast-agent",
|
|
4674
4674
|
"llmling-agent",
|
|
4675
|
+
"amp",
|
|
4675
4676
|
}
|
|
4676
4677
|
if short_name in acp_agents:
|
|
4677
4678
|
model_name = self.current_model if self.current_model else "auto"
|
|
@@ -4722,7 +4723,7 @@ team:
|
|
|
4722
4723
|
self._current_file_context = "" # Clear after use
|
|
4723
4724
|
|
|
4724
4725
|
# Route ACP-compatible agents to the JSON-RPC ACP client
|
|
4725
|
-
# All
|
|
4726
|
+
# All 15 official ACP agents support the Agent Client Protocol
|
|
4726
4727
|
acp_agents = (
|
|
4727
4728
|
"opencode",
|
|
4728
4729
|
"claude",
|
|
@@ -4738,6 +4739,7 @@ team:
|
|
|
4738
4739
|
"cagent",
|
|
4739
4740
|
"fast-agent",
|
|
4740
4741
|
"llmling-agent",
|
|
4742
|
+
"amp",
|
|
4741
4743
|
)
|
|
4742
4744
|
if agent_type in acp_agents:
|
|
4743
4745
|
self._run_acp_jsonrpc_client(
|
|
@@ -4979,7 +4981,7 @@ team:
|
|
|
4979
4981
|
self._current_file_context = ""
|
|
4980
4982
|
|
|
4981
4983
|
# Choose command and model display based on agent type
|
|
4982
|
-
# All
|
|
4984
|
+
# All 15 official ACP agents are supported
|
|
4983
4985
|
if agent_type == "gemini":
|
|
4984
4986
|
command = "gemini --experimental-acp"
|
|
4985
4987
|
model_display = f"gemini/{model}" if model and model != "auto" else "gemini/auto"
|
|
@@ -5058,6 +5060,10 @@ team:
|
|
|
5058
5060
|
elif agent_type == "llmling-agent":
|
|
5059
5061
|
command = "llmling-agent --acp"
|
|
5060
5062
|
model_display = f"llmling-agent/{model}" if model else "llmling-agent/auto"
|
|
5063
|
+
elif agent_type == "amp":
|
|
5064
|
+
command = "acp-amp"
|
|
5065
|
+
model_display = f"amp/{model}" if model else "amp/auto"
|
|
5066
|
+
# Amp handles its own authentication via `amp login`
|
|
5061
5067
|
else:
|
|
5062
5068
|
self.call_from_thread(self._stop_thinking)
|
|
5063
5069
|
self.call_from_thread(log.add_error, f"Unsupported ACP agent type: {agent_type}")
|
|
@@ -14862,6 +14868,9 @@ team:
|
|
|
14862
14868
|
"stakpak": "📦", # Package
|
|
14863
14869
|
"vtcode": "🎨", # Paint palette
|
|
14864
14870
|
"openhands": "🤲", # Open hands
|
|
14871
|
+
"amp": "⚡", # Lightning (Amp)
|
|
14872
|
+
"ampcode": "⚡", # Lightning
|
|
14873
|
+
"ampcode.com": "⚡", # Lightning
|
|
14865
14874
|
}
|
|
14866
14875
|
|
|
14867
14876
|
priority_order = {
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Local Auth Storage for SuperQode.
|
|
3
|
+
|
|
4
|
+
Simple, minimal local storage for API keys. Inspired by opencode's approach.
|
|
5
|
+
|
|
6
|
+
Security:
|
|
7
|
+
- File permissions set to 0o600 (owner read/write only)
|
|
8
|
+
- Stored in ~/.superqode/auth.json
|
|
9
|
+
- Never logs or exposes key values
|
|
10
|
+
|
|
11
|
+
This is OPTIONAL - SuperQode still supports BYOK (env vars) as primary.
|
|
12
|
+
Local storage is for users who prefer file-based key management.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
import logging
|
|
19
|
+
import os
|
|
20
|
+
from dataclasses import dataclass
|
|
21
|
+
from datetime import datetime
|
|
22
|
+
from enum import Enum
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
from typing import Any, Dict, Optional, Union
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class AuthType(Enum):
|
|
30
|
+
"""Type of authentication credential."""
|
|
31
|
+
|
|
32
|
+
API = "api" # Simple API key
|
|
33
|
+
OAUTH = "oauth" # OAuth with refresh token
|
|
34
|
+
WELLKNOWN = "wellknown" # Well-known auth (key + token pair)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class ApiAuth:
|
|
39
|
+
"""Simple API key authentication."""
|
|
40
|
+
|
|
41
|
+
type: str = "api"
|
|
42
|
+
key: str = ""
|
|
43
|
+
|
|
44
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
45
|
+
return {"type": self.type, "key": self.key}
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def from_dict(cls, data: Dict[str, Any]) -> "ApiAuth":
|
|
49
|
+
return cls(type=data.get("type", "api"), key=data.get("key", ""))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@dataclass
|
|
53
|
+
class OAuthAuth:
|
|
54
|
+
"""OAuth authentication with refresh token."""
|
|
55
|
+
|
|
56
|
+
type: str = "oauth"
|
|
57
|
+
refresh: str = ""
|
|
58
|
+
access: str = ""
|
|
59
|
+
expires: int = 0
|
|
60
|
+
account_id: Optional[str] = None
|
|
61
|
+
enterprise_url: Optional[str] = None
|
|
62
|
+
|
|
63
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
64
|
+
result = {
|
|
65
|
+
"type": self.type,
|
|
66
|
+
"refresh": self.refresh,
|
|
67
|
+
"access": self.access,
|
|
68
|
+
"expires": self.expires,
|
|
69
|
+
}
|
|
70
|
+
if self.account_id:
|
|
71
|
+
result["account_id"] = self.account_id
|
|
72
|
+
if self.enterprise_url:
|
|
73
|
+
result["enterprise_url"] = self.enterprise_url
|
|
74
|
+
return result
|
|
75
|
+
|
|
76
|
+
@classmethod
|
|
77
|
+
def from_dict(cls, data: Dict[str, Any]) -> "OAuthAuth":
|
|
78
|
+
return cls(
|
|
79
|
+
type=data.get("type", "oauth"),
|
|
80
|
+
refresh=data.get("refresh", ""),
|
|
81
|
+
access=data.get("access", ""),
|
|
82
|
+
expires=data.get("expires", 0),
|
|
83
|
+
account_id=data.get("account_id"),
|
|
84
|
+
enterprise_url=data.get("enterprise_url"),
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
def is_expired(self) -> bool:
|
|
88
|
+
"""Check if access token is expired."""
|
|
89
|
+
return self.expires > 0 and self.expires < int(datetime.now().timestamp())
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@dataclass
|
|
93
|
+
class WellKnownAuth:
|
|
94
|
+
"""Well-known authentication (key + token pair)."""
|
|
95
|
+
|
|
96
|
+
type: str = "wellknown"
|
|
97
|
+
key: str = ""
|
|
98
|
+
token: str = ""
|
|
99
|
+
|
|
100
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
101
|
+
return {"type": self.type, "key": self.key, "token": self.token}
|
|
102
|
+
|
|
103
|
+
@classmethod
|
|
104
|
+
def from_dict(cls, data: Dict[str, Any]) -> "WellKnownAuth":
|
|
105
|
+
return cls(
|
|
106
|
+
type=data.get("type", "wellknown"),
|
|
107
|
+
key=data.get("key", ""),
|
|
108
|
+
token=data.get("token", ""),
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
AuthInfo = Union[ApiAuth, OAuthAuth, WellKnownAuth]
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def parse_auth_info(data: Dict[str, Any]) -> Optional[AuthInfo]:
|
|
116
|
+
"""Parse auth info from dict based on type."""
|
|
117
|
+
auth_type = data.get("type")
|
|
118
|
+
if auth_type == "api":
|
|
119
|
+
return ApiAuth.from_dict(data)
|
|
120
|
+
if auth_type == "oauth":
|
|
121
|
+
return OAuthAuth.from_dict(data)
|
|
122
|
+
if auth_type == "wellknown":
|
|
123
|
+
return WellKnownAuth.from_dict(data)
|
|
124
|
+
return None
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class LocalAuthStorage:
|
|
128
|
+
"""
|
|
129
|
+
Local storage for API keys and OAuth tokens.
|
|
130
|
+
|
|
131
|
+
Stores credentials in ~/.superqode/auth.json with restricted permissions.
|
|
132
|
+
|
|
133
|
+
Usage:
|
|
134
|
+
auth = LocalAuthStorage()
|
|
135
|
+
|
|
136
|
+
# Set API key
|
|
137
|
+
auth.set("anthropic", ApiAuth(key="sk-..."))
|
|
138
|
+
|
|
139
|
+
# Get credentials
|
|
140
|
+
creds = auth.get("anthropic")
|
|
141
|
+
|
|
142
|
+
# Remove
|
|
143
|
+
auth.remove("anthropic")
|
|
144
|
+
|
|
145
|
+
# List all
|
|
146
|
+
all_creds = auth.all()
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
DEFAULT_PATH = Path.home() / ".superqode" / "auth.json"
|
|
150
|
+
|
|
151
|
+
def __init__(self, filepath: Optional[Path] = None):
|
|
152
|
+
self.filepath = filepath or self.DEFAULT_PATH
|
|
153
|
+
self._ensure_dir()
|
|
154
|
+
|
|
155
|
+
def _ensure_dir(self) -> None:
|
|
156
|
+
"""Ensure parent directory exists with proper permissions."""
|
|
157
|
+
parent = self.filepath.parent
|
|
158
|
+
if not parent.exists():
|
|
159
|
+
parent.mkdir(parents=True, mode=0o700)
|
|
160
|
+
|
|
161
|
+
def _read_file(self) -> Dict[str, Any]:
|
|
162
|
+
"""Read auth file, return empty dict if not exists or invalid."""
|
|
163
|
+
if not self.filepath.exists():
|
|
164
|
+
return {}
|
|
165
|
+
try:
|
|
166
|
+
with open(self.filepath) as f:
|
|
167
|
+
return json.load(f)
|
|
168
|
+
except (json.JSONDecodeError, IOError):
|
|
169
|
+
return {}
|
|
170
|
+
|
|
171
|
+
def _write_file(self, data: Dict[str, Any]) -> None:
|
|
172
|
+
"""Write auth file with secure permissions."""
|
|
173
|
+
# Write to temp file first, then rename (atomic)
|
|
174
|
+
temp_path = self.filepath.with_suffix(".tmp")
|
|
175
|
+
with open(temp_path, "w") as f:
|
|
176
|
+
json.dump(data, f, indent=2)
|
|
177
|
+
|
|
178
|
+
# Set permissions before moving
|
|
179
|
+
os.chmod(temp_path, 0o600)
|
|
180
|
+
|
|
181
|
+
# Atomic rename
|
|
182
|
+
temp_path.rename(self.filepath)
|
|
183
|
+
|
|
184
|
+
def get(self, provider_id: str) -> Optional[AuthInfo]:
|
|
185
|
+
"""Get credentials for a provider."""
|
|
186
|
+
data = self._read_file()
|
|
187
|
+
if provider_id not in data:
|
|
188
|
+
return None
|
|
189
|
+
return parse_auth_info(data[provider_id])
|
|
190
|
+
|
|
191
|
+
def all(self) -> Dict[str, AuthInfo]:
|
|
192
|
+
"""Get all stored credentials."""
|
|
193
|
+
data = self._read_file()
|
|
194
|
+
result: Dict[str, AuthInfo] = {}
|
|
195
|
+
for key, value in data.items():
|
|
196
|
+
if isinstance(value, dict):
|
|
197
|
+
parsed = parse_auth_info(value)
|
|
198
|
+
if parsed:
|
|
199
|
+
result[key] = parsed
|
|
200
|
+
return result
|
|
201
|
+
|
|
202
|
+
def set(self, provider_id: str, info: AuthInfo) -> None:
|
|
203
|
+
"""Set credentials for a provider."""
|
|
204
|
+
data = self._read_file()
|
|
205
|
+
data[provider_id] = info.to_dict()
|
|
206
|
+
self._write_file(data)
|
|
207
|
+
logger.debug(f"Saved auth for {provider_id}")
|
|
208
|
+
|
|
209
|
+
def remove(self, provider_id: str) -> bool:
|
|
210
|
+
"""Remove credentials for a provider. Returns True if removed."""
|
|
211
|
+
data = self._read_file()
|
|
212
|
+
if provider_id not in data:
|
|
213
|
+
return False
|
|
214
|
+
del data[provider_id]
|
|
215
|
+
self._write_file(data)
|
|
216
|
+
logger.debug(f"Removed auth for {provider_id}")
|
|
217
|
+
return True
|
|
218
|
+
|
|
219
|
+
def exists(self, provider_id: str) -> bool:
|
|
220
|
+
"""Check if credentials exist for a provider."""
|
|
221
|
+
return provider_id in self._read_file()
|
|
222
|
+
|
|
223
|
+
def clear(self) -> None:
|
|
224
|
+
"""Clear all stored credentials."""
|
|
225
|
+
self._write_file({})
|
|
226
|
+
logger.debug("Cleared all auth")
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
# Singleton instance
|
|
230
|
+
_storage: Optional[LocalAuthStorage] = None
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def get_storage() -> LocalAuthStorage:
|
|
234
|
+
"""Get the singleton auth storage instance."""
|
|
235
|
+
global _storage
|
|
236
|
+
if _storage is None:
|
|
237
|
+
_storage = LocalAuthStorage()
|
|
238
|
+
return _storage
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
# Convenience functions
|
|
242
|
+
def get(provider_id: str) -> Optional[AuthInfo]:
|
|
243
|
+
"""Get credentials for a provider."""
|
|
244
|
+
return get_storage().get(provider_id)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def all() -> Dict[str, AuthInfo]:
|
|
248
|
+
"""Get all stored credentials."""
|
|
249
|
+
return get_storage().all()
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def set(provider_id: str, info: AuthInfo) -> None:
|
|
253
|
+
"""Set credentials for a provider."""
|
|
254
|
+
get_storage().set(provider_id, info)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def remove(provider_id: str) -> bool:
|
|
258
|
+
"""Remove credentials for a provider."""
|
|
259
|
+
return get_storage().remove(provider_id)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def exists(provider_id: str) -> bool:
|
|
263
|
+
"""Check if credentials exist for a provider."""
|
|
264
|
+
return get_storage().exists(provider_id)
|