code-agnostic 0.4.0__tar.gz → 0.5.1__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.
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/PKG-INFO +1 -1
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/__init__.py +1 -1
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/agents/claude.py +1 -1
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/agents/codex.py +2 -2
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/agents/parser.py +2 -2
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/apps_service.py +2 -2
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/claude/service.py +0 -7
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/codex/config_repository.py +2 -2
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/codex/service.py +1 -1
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/common/framework.py +2 -2
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/common/interfaces/service.py +18 -2
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/common/schema.py +1 -1
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/copilot/service.py +1 -5
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/cursor/service.py +1 -3
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/opencode/service.py +1 -5
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/cli/aliases.py +3 -1
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/cli/commands/workspaces.py +2 -1
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/cli/helpers.py +9 -2
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/cli/options.py +17 -6
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/executor.py +7 -7
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/imports/adapters.py +6 -2
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/imports/service.py +13 -10
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/planner.py +57 -66
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/project_artifacts.py +6 -2
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/rules/compilers.py +2 -1
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/rules/parser.py +2 -1
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/skills/parser.py +6 -3
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/status.py +4 -4
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/tui/renderers.py +3 -1
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/tui/sections.py +5 -1
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/tui/tables.py +6 -5
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic.egg-info/PKG-INFO +1 -1
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/pyproject.toml +6 -1
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/LICENSE +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/README.md +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/__main__.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/agents/__init__.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/agents/compilers.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/agents/copilot.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/agents/models.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/agents/opencode.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/__init__.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/app_id.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/claude/__init__.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/claude/config_repository.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/claude/mapper.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/codex/__init__.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/codex/mapper.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/codex/schema.json +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/codex/schema_repository.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/common/__init__.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/common/compiled_planning.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/common/interfaces/__init__.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/common/interfaces/mapper.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/common/interfaces/repositories.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/common/loader.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/common/models.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/common/symlink_planning.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/common/utils.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/copilot/__init__.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/copilot/config_repository.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/copilot/mapper.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/cursor/__init__.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/cursor/config_repository.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/cursor/mapper.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/cursor/schema.json +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/cursor/schema_repository.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/opencode/__init__.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/opencode/config_repository.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/opencode/mapper.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/opencode/schema.json +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/apps/opencode/schema_repository.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/cli/__init__.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/cli/commands/__init__.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/cli/commands/agents.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/cli/commands/apply.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/cli/commands/apps.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/cli/commands/explain_lossiness.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/cli/commands/import_.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/cli/commands/mcp.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/cli/commands/plan.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/cli/commands/projects.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/cli/commands/restore.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/cli/commands/rules.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/cli/commands/skills.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/cli/commands/status.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/cli/commands/validate.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/constants.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/core/__init__.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/core/project_repository.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/core/repository.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/core/workspace_repository.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/errors.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/generated_artifacts.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/git_exclude_service.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/imports/__init__.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/imports/filesystem.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/imports/models.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/lossiness.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/mcp_service.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/models.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/rules/__init__.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/rules/models.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/rules/repository.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/skills/__init__.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/skills/compilers.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/skills/install_sources.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/skills/models.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/spec/__init__.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/spec/loaders.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/spec/schemas/agent.v1.schema.json +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/spec/schemas/mcp.base.schema.json +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/spec/schemas/mcp.v1.schema.json +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/spec/schemas/rule.v1.schema.json +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/spec/schemas/skill.v1.schema.json +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/tui/__init__.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/tui/enums.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/tui/import_selector.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/utils.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/validation.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/workspace_artifacts.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic/workspaces.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic.egg-info/SOURCES.txt +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic.egg-info/dependency_links.txt +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic.egg-info/entry_points.txt +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic.egg-info/requires.txt +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/code_agnostic.egg-info/top_level.txt +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/setup.cfg +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_agents.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_aliases.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_apply_apps.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_apply_codex.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_apply_cursor.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_apply_mcp_cleanup.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_apply_target.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_apps.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_disable_cleanup.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_explain_lossiness.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_flags.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_git_exclude.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_import.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_import_interactive.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_mcp.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_module_organization.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_plan.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_projects.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_restore.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_rules.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_skills.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_status.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_validate.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_workspace_resolution.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_cli_workspaces.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_common_mcp_to_dto.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_common_repository.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_compiled_planning.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_dto_to_common_mcp.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_git_exclude_service.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_mcp_service.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_planner_executor.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_planner_rules.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_project_config_sync.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_skill_install_sources.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_symlink_planning.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_sync_plan_model.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_transactional_executor.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_utils.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_version.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_workspace_config_sync.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_workspace_repo_status.py +0 -0
- {code_agnostic-0.4.0 → code_agnostic-0.5.1}/tests/test_workspaces.py +0 -0
|
@@ -7,9 +7,9 @@ from pathlib import Path
|
|
|
7
7
|
from typing import Any
|
|
8
8
|
|
|
9
9
|
try:
|
|
10
|
-
import tomllib
|
|
10
|
+
import tomllib # type: ignore[import-not-found]
|
|
11
11
|
except ModuleNotFoundError: # pragma: no cover
|
|
12
|
-
import tomli as tomllib
|
|
12
|
+
import tomli as tomllib
|
|
13
13
|
|
|
14
14
|
import tomlkit
|
|
15
15
|
|
|
@@ -83,7 +83,7 @@ def parse_agent(path: Path) -> Agent:
|
|
|
83
83
|
|
|
84
84
|
|
|
85
85
|
def serialize_agent(agent: Agent, *, target_app: str | None = None) -> str:
|
|
86
|
-
fm: dict = {}
|
|
86
|
+
fm: dict[str, Any] = {}
|
|
87
87
|
if agent.metadata.name:
|
|
88
88
|
fm["name"] = agent.metadata.name
|
|
89
89
|
if agent.metadata.description:
|
|
@@ -105,7 +105,7 @@ def serialize_agent(agent: Agent, *, target_app: str | None = None) -> str:
|
|
|
105
105
|
if nickname_candidates:
|
|
106
106
|
fm["nickname_candidates"] = list(nickname_candidates)
|
|
107
107
|
|
|
108
|
-
tools: dict = {}
|
|
108
|
+
tools: dict[str, Any] = {}
|
|
109
109
|
if agent.metadata.tools.read is not True:
|
|
110
110
|
tools["read"] = agent.metadata.tools.read
|
|
111
111
|
if agent.metadata.tools.write is not True:
|
|
@@ -7,7 +7,6 @@ from code_agnostic.apps.common.framework import (
|
|
|
7
7
|
list_registered_app_services,
|
|
8
8
|
)
|
|
9
9
|
from code_agnostic.apps.common.interfaces.service import IAppConfigService
|
|
10
|
-
from code_agnostic.apps.common.interfaces.repositories import ISourceRepository
|
|
11
10
|
from code_agnostic.apps.common.symlink_planning import (
|
|
12
11
|
load_state_links,
|
|
13
12
|
load_state_paths,
|
|
@@ -15,6 +14,7 @@ from code_agnostic.apps.common.symlink_planning import (
|
|
|
15
14
|
plan_stale_group,
|
|
16
15
|
)
|
|
17
16
|
from code_agnostic.core.project_repository import ProjectConfigRepository
|
|
17
|
+
from code_agnostic.core.repository import CoreRepository
|
|
18
18
|
from code_agnostic.core.workspace_repository import WorkspaceConfigRepository
|
|
19
19
|
from code_agnostic.executor import SyncExecutor
|
|
20
20
|
from code_agnostic.models import Action, AppStatusRow, AppSyncStatus, SyncPlan
|
|
@@ -24,7 +24,7 @@ from code_agnostic.utils import read_json_safe, write_json
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class AppsService:
|
|
27
|
-
def __init__(self, core_repository:
|
|
27
|
+
def __init__(self, core_repository: CoreRepository) -> None:
|
|
28
28
|
self.core_repository = core_repository
|
|
29
29
|
|
|
30
30
|
@property
|
|
@@ -12,7 +12,6 @@ from code_agnostic.apps.common.framework import RegisteredAppConfigService
|
|
|
12
12
|
from code_agnostic.apps.common.interfaces.mapper import IAppMCPMapper
|
|
13
13
|
from code_agnostic.apps.common.interfaces.repositories import IAppConfigRepository
|
|
14
14
|
from code_agnostic.apps.common.models import MCPServerDTO
|
|
15
|
-
from code_agnostic.errors import InvalidConfigSchemaError
|
|
16
15
|
from code_agnostic.models import Action, ActionKind, ActionStatus
|
|
17
16
|
from code_agnostic.skills.compilers import ClaudeSkillCompiler
|
|
18
17
|
from code_agnostic.skills.parser import parse_skill
|
|
@@ -57,12 +56,6 @@ class ClaudeConfigService(RegisteredAppConfigService):
|
|
|
57
56
|
def mcp_config_key(self) -> str:
|
|
58
57
|
return "mcpServers"
|
|
59
58
|
|
|
60
|
-
def validate_config(self, payload: Any) -> None:
|
|
61
|
-
if not isinstance(payload, dict):
|
|
62
|
-
raise InvalidConfigSchemaError(
|
|
63
|
-
self.repository.config_path, "must be a JSON object"
|
|
64
|
-
)
|
|
65
|
-
|
|
66
59
|
def build_action_payload(self, payload: dict[str, Any]) -> Any:
|
|
67
60
|
return payload
|
|
68
61
|
|
|
@@ -3,9 +3,9 @@ from pathlib import Path
|
|
|
3
3
|
from typing import Any
|
|
4
4
|
|
|
5
5
|
try:
|
|
6
|
-
import tomllib
|
|
6
|
+
import tomllib # type: ignore[import-not-found]
|
|
7
7
|
except ModuleNotFoundError: # pragma: no cover
|
|
8
|
-
import tomli as tomllib
|
|
8
|
+
import tomli as tomllib
|
|
9
9
|
|
|
10
10
|
import tomlkit
|
|
11
11
|
|
|
@@ -88,7 +88,7 @@ class CodexConfigService(RegisteredAppConfigService):
|
|
|
88
88
|
def mcp_config_key(self) -> str:
|
|
89
89
|
return "mcp_servers"
|
|
90
90
|
|
|
91
|
-
def
|
|
91
|
+
def _validate_schema(self, payload: dict[str, Any]) -> None:
|
|
92
92
|
error = next(iter(self._validator.iter_errors(payload)), None)
|
|
93
93
|
if error is not None:
|
|
94
94
|
raise InvalidConfigSchemaError(
|
|
@@ -20,12 +20,12 @@ class AppServiceRegistryMeta(ABCMeta):
|
|
|
20
20
|
bases: tuple[type, ...],
|
|
21
21
|
namespace: dict[str, Any],
|
|
22
22
|
**kwargs: Any,
|
|
23
|
-
):
|
|
23
|
+
) -> "AppServiceRegistryMeta":
|
|
24
24
|
cls = super().__new__(mcls, name, bases, namespace, **kwargs)
|
|
25
25
|
app_id = getattr(cls, "APP_ID", None)
|
|
26
26
|
is_abstract = bool(getattr(cls, "__abstractmethods__", False))
|
|
27
27
|
if app_id is not None and not is_abstract:
|
|
28
|
-
mcls._registry[app_id] = cast(type["RegisteredAppConfigService"], cls)
|
|
28
|
+
mcls._registry[app_id] = cast(type["RegisteredAppConfigService"], cls)
|
|
29
29
|
return cls
|
|
30
30
|
|
|
31
31
|
|
|
@@ -12,6 +12,7 @@ from code_agnostic.apps.common.interfaces.repositories import IAppConfigReposito
|
|
|
12
12
|
from code_agnostic.apps.common.interfaces.repositories import ISourceRepository
|
|
13
13
|
from code_agnostic.apps.common.models import MCPServerDTO
|
|
14
14
|
from code_agnostic.apps.common.utils import apply_mcp_servers
|
|
15
|
+
from code_agnostic.errors import InvalidConfigSchemaError
|
|
15
16
|
from code_agnostic.apps.common.symlink_planning import (
|
|
16
17
|
load_state_links,
|
|
17
18
|
load_state_paths,
|
|
@@ -59,9 +60,24 @@ class IAppConfigService(ABC):
|
|
|
59
60
|
"""Native config key that holds the MCP server map for this editor."""
|
|
60
61
|
raise NotImplementedError
|
|
61
62
|
|
|
62
|
-
@abstractmethod
|
|
63
63
|
def validate_config(self, payload: Any) -> None:
|
|
64
|
-
|
|
64
|
+
"""Single validation contract for every editor config.
|
|
65
|
+
|
|
66
|
+
Empty/absent config is always valid; anything present must be a JSON
|
|
67
|
+
object; schema-backed editors add their own checks via
|
|
68
|
+
``_validate_schema``.
|
|
69
|
+
"""
|
|
70
|
+
if payload is None or payload == {}:
|
|
71
|
+
return
|
|
72
|
+
if not isinstance(payload, dict):
|
|
73
|
+
raise InvalidConfigSchemaError(
|
|
74
|
+
self.repository.config_path, "must be a JSON object"
|
|
75
|
+
)
|
|
76
|
+
self._validate_schema(payload)
|
|
77
|
+
|
|
78
|
+
def _validate_schema(self, payload: dict[str, Any]) -> None:
|
|
79
|
+
"""Editor-specific validation hook. Default: no schema."""
|
|
80
|
+
return
|
|
65
81
|
|
|
66
82
|
@abstractmethod
|
|
67
83
|
def build_action_payload(self, payload: dict[str, Any]) -> Any:
|
|
@@ -51,6 +51,6 @@ class JsonSchemaRepository(ISchemaRepository):
|
|
|
51
51
|
now = time.time()
|
|
52
52
|
if cached and now - cached[0] < self.ttl_seconds:
|
|
53
53
|
return cached[1]
|
|
54
|
-
schema = json.loads(path.read_text(encoding="utf-8"))
|
|
54
|
+
schema: dict[str, Any] = json.loads(path.read_text(encoding="utf-8"))
|
|
55
55
|
_SCHEMA_CACHE[key] = (now, schema)
|
|
56
56
|
return schema
|
|
@@ -55,11 +55,7 @@ class CopilotConfigService(RegisteredAppConfigService):
|
|
|
55
55
|
def mcp_config_key(self) -> str:
|
|
56
56
|
return "mcpServers"
|
|
57
57
|
|
|
58
|
-
def
|
|
59
|
-
if not isinstance(payload, dict):
|
|
60
|
-
raise InvalidConfigSchemaError(
|
|
61
|
-
self.repository.config_path, "must be a JSON object"
|
|
62
|
-
)
|
|
58
|
+
def _validate_schema(self, payload: dict[str, Any]) -> None:
|
|
63
59
|
mcp_servers = payload.get("mcpServers")
|
|
64
60
|
if mcp_servers is not None and not isinstance(mcp_servers, dict):
|
|
65
61
|
raise InvalidConfigSchemaError(
|
|
@@ -68,9 +68,7 @@ class CursorConfigService(RegisteredAppConfigService):
|
|
|
68
68
|
def mcp_config_key(self) -> str:
|
|
69
69
|
return "mcpServers"
|
|
70
70
|
|
|
71
|
-
def
|
|
72
|
-
if payload == {}:
|
|
73
|
-
return
|
|
71
|
+
def _validate_schema(self, payload: dict[str, Any]) -> None:
|
|
74
72
|
error = next(iter(self._validator.iter_errors(payload)), None)
|
|
75
73
|
if error is not None:
|
|
76
74
|
raise InvalidConfigSchemaError(
|
|
@@ -104,11 +104,7 @@ class OpenCodeConfigService(RegisteredAppConfigService):
|
|
|
104
104
|
def mcp_config_key(self) -> str:
|
|
105
105
|
return "mcp"
|
|
106
106
|
|
|
107
|
-
def
|
|
108
|
-
if not isinstance(payload, dict):
|
|
109
|
-
raise InvalidConfigSchemaError(
|
|
110
|
-
self.repository.config_path, "must be a JSON object"
|
|
111
|
-
)
|
|
107
|
+
def _validate_schema(self, payload: dict[str, Any]) -> None:
|
|
112
108
|
for error in self._validator.iter_errors(payload):
|
|
113
109
|
if _is_unknown_provider_model_enum_error(error):
|
|
114
110
|
continue
|
|
@@ -14,7 +14,9 @@ class AliasedGroup(click.Group):
|
|
|
14
14
|
def get_command(self, ctx: click.Context, cmd_name: str) -> click.Command | None:
|
|
15
15
|
return super().get_command(ctx, self.ALIASES.get(cmd_name, cmd_name))
|
|
16
16
|
|
|
17
|
-
def resolve_command(
|
|
17
|
+
def resolve_command(
|
|
18
|
+
self, ctx: click.Context, args: list[str]
|
|
19
|
+
) -> tuple[str | None, click.Command | None, list[str]]:
|
|
18
20
|
if args and args[0] in self.ALIASES:
|
|
19
21
|
args[0] = self.ALIASES[args[0]]
|
|
20
22
|
return super().resolve_command(ctx, args)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Workspaces group commands."""
|
|
2
2
|
|
|
3
3
|
from pathlib import Path
|
|
4
|
+
from typing import Any
|
|
4
5
|
|
|
5
6
|
import click
|
|
6
7
|
from rich.console import Console
|
|
@@ -63,7 +64,7 @@ def workspaces_list(obj: dict[str, str]) -> None:
|
|
|
63
64
|
core = CoreRepository()
|
|
64
65
|
workspace_service = WorkspaceService()
|
|
65
66
|
|
|
66
|
-
overview: list[dict] = []
|
|
67
|
+
overview: list[dict[str, Any]] = []
|
|
67
68
|
try:
|
|
68
69
|
workspaces = core.load_workspaces()
|
|
69
70
|
except SyncAppError as exc:
|
|
@@ -7,7 +7,12 @@ import click
|
|
|
7
7
|
from code_agnostic.apps.apps_service import AppsService
|
|
8
8
|
from code_agnostic.core.repository import CoreRepository
|
|
9
9
|
from code_agnostic.errors import SyncAppError
|
|
10
|
-
from code_agnostic.models import
|
|
10
|
+
from code_agnostic.models import (
|
|
11
|
+
ActionStatus,
|
|
12
|
+
EditorStatusRow,
|
|
13
|
+
EditorSyncStatus,
|
|
14
|
+
SyncPlan,
|
|
15
|
+
)
|
|
11
16
|
|
|
12
17
|
|
|
13
18
|
def _workspace_entries_by_name(core: CoreRepository) -> dict[str, dict[str, str]]:
|
|
@@ -64,7 +69,9 @@ def reject_symlinked_source_dir(path: Path, resource_type: str) -> None:
|
|
|
64
69
|
)
|
|
65
70
|
|
|
66
71
|
|
|
67
|
-
def status_row_for_app(
|
|
72
|
+
def status_row_for_app(
|
|
73
|
+
app_name: str, plan: SyncPlan, apps: AppsService
|
|
74
|
+
) -> EditorStatusRow:
|
|
68
75
|
if not apps.is_enabled(app_name):
|
|
69
76
|
return EditorStatusRow(
|
|
70
77
|
name=app_name,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Shared option decorators for CLI commands."""
|
|
2
2
|
|
|
3
3
|
from collections.abc import Callable
|
|
4
|
+
from typing import Any
|
|
4
5
|
|
|
5
6
|
import click
|
|
6
7
|
|
|
@@ -38,7 +39,9 @@ def _import_source_values() -> list[str]:
|
|
|
38
39
|
]
|
|
39
40
|
|
|
40
41
|
|
|
41
|
-
def app_option(
|
|
42
|
+
def app_option(
|
|
43
|
+
required: bool = False,
|
|
44
|
+
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
42
45
|
return click.option(
|
|
43
46
|
"-a",
|
|
44
47
|
"--app",
|
|
@@ -49,7 +52,9 @@ def app_option(required: bool = False) -> Callable:
|
|
|
49
52
|
)
|
|
50
53
|
|
|
51
54
|
|
|
52
|
-
def manageable_app_option(
|
|
55
|
+
def manageable_app_option(
|
|
56
|
+
required: bool = True,
|
|
57
|
+
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
53
58
|
return click.option(
|
|
54
59
|
"-a",
|
|
55
60
|
"--app",
|
|
@@ -59,7 +64,9 @@ def manageable_app_option(required: bool = True) -> Callable:
|
|
|
59
64
|
)
|
|
60
65
|
|
|
61
66
|
|
|
62
|
-
def import_app_option(
|
|
67
|
+
def import_app_option(
|
|
68
|
+
required: bool = True,
|
|
69
|
+
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
63
70
|
return click.option(
|
|
64
71
|
"-a",
|
|
65
72
|
"--app",
|
|
@@ -69,7 +76,9 @@ def import_app_option(required: bool = True) -> Callable:
|
|
|
69
76
|
)
|
|
70
77
|
|
|
71
78
|
|
|
72
|
-
def workspace_option(
|
|
79
|
+
def workspace_option(
|
|
80
|
+
required: bool = False,
|
|
81
|
+
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
73
82
|
return click.option(
|
|
74
83
|
"-w",
|
|
75
84
|
"--workspace",
|
|
@@ -79,7 +88,9 @@ def workspace_option(required: bool = False) -> Callable:
|
|
|
79
88
|
)
|
|
80
89
|
|
|
81
90
|
|
|
82
|
-
def project_option(
|
|
91
|
+
def project_option(
|
|
92
|
+
required: bool = False,
|
|
93
|
+
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
83
94
|
return click.option(
|
|
84
95
|
"--project",
|
|
85
96
|
required=required,
|
|
@@ -88,5 +99,5 @@ def project_option(required: bool = False) -> Callable:
|
|
|
88
99
|
)
|
|
89
100
|
|
|
90
101
|
|
|
91
|
-
def verbose_option() -> Callable:
|
|
102
|
+
def verbose_option() -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
92
103
|
return click.option("-v", "--verbose", is_flag=True, default=False)
|
|
@@ -7,13 +7,13 @@ from pathlib import Path
|
|
|
7
7
|
from typing import Any
|
|
8
8
|
from typing import Protocol
|
|
9
9
|
|
|
10
|
-
from code_agnostic.apps.common.interfaces.repositories import ISourceRepository
|
|
11
10
|
from code_agnostic.constants import (
|
|
12
11
|
SYNC_REVISIONS_DIRNAME,
|
|
13
12
|
SYNC_STAGING_DIRNAME,
|
|
14
13
|
SYNC_STATE_FILENAME,
|
|
15
14
|
)
|
|
16
15
|
from code_agnostic.core.project_repository import ProjectConfigRepository
|
|
16
|
+
from code_agnostic.core.repository import CoreRepository
|
|
17
17
|
from code_agnostic.core.workspace_repository import WorkspaceConfigRepository
|
|
18
18
|
from code_agnostic.models import Action, ActionKind, ActionStatus, SyncPlan
|
|
19
19
|
from code_agnostic.utils import write_json
|
|
@@ -21,7 +21,7 @@ from code_agnostic.utils import write_json
|
|
|
21
21
|
|
|
22
22
|
@dataclass
|
|
23
23
|
class ExecutionContext:
|
|
24
|
-
core:
|
|
24
|
+
core: CoreRepository
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
@dataclass(frozen=True)
|
|
@@ -189,7 +189,7 @@ class WriteRuleHandler:
|
|
|
189
189
|
|
|
190
190
|
|
|
191
191
|
class SyncExecutor:
|
|
192
|
-
def __init__(self, core:
|
|
192
|
+
def __init__(self, core: CoreRepository) -> None:
|
|
193
193
|
self.context = ExecutionContext(core=core)
|
|
194
194
|
self.handlers: dict[ActionKind, ActionHandler] = {
|
|
195
195
|
ActionKind.WRITE_JSON: WriteJsonHandler(),
|
|
@@ -421,12 +421,12 @@ class SyncExecutor:
|
|
|
421
421
|
if workspace is not None and project is not None:
|
|
422
422
|
raise ValueError("Choose only one scope: workspace or project.")
|
|
423
423
|
|
|
424
|
-
if workspace is
|
|
425
|
-
root = self.context.core.root
|
|
426
|
-
elif workspace is not None:
|
|
424
|
+
if workspace is not None:
|
|
427
425
|
root = self.context.core.workspace_config_dir(workspace)
|
|
428
|
-
|
|
426
|
+
elif project is not None:
|
|
429
427
|
root = self.context.core.project_config_dir(project)
|
|
428
|
+
else:
|
|
429
|
+
root = self.context.core.root
|
|
430
430
|
|
|
431
431
|
revision_record = self._build_revision_record(
|
|
432
432
|
root=root, workspace=workspace, project=project, revision_id="restore"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
2
|
from pathlib import Path
|
|
3
|
+
from typing import Any, cast
|
|
3
4
|
|
|
4
5
|
from code_agnostic.apps.app_id import AppId
|
|
5
6
|
from code_agnostic.apps.codex.config_repository import CodexConfigRepository
|
|
@@ -24,8 +25,11 @@ class ImportAdapter:
|
|
|
24
25
|
mapper: IAppMCPMapper
|
|
25
26
|
config_repository: object
|
|
26
27
|
|
|
27
|
-
def load_mcp_payload(self) -> dict:
|
|
28
|
-
return
|
|
28
|
+
def load_mcp_payload(self) -> dict[str, Any]:
|
|
29
|
+
return cast(
|
|
30
|
+
"dict[str, Any]",
|
|
31
|
+
self.config_repository.load_mcp_payload(), # type: ignore[attr-defined]
|
|
32
|
+
)
|
|
29
33
|
|
|
30
34
|
|
|
31
35
|
def create_import_adapter(app: str, source_root: Path | None = None) -> ImportAdapter:
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
|
+
from typing import Any
|
|
2
3
|
|
|
3
4
|
from code_agnostic.agents.codex import normalize_codex_agent_filename, parse_codex_agent
|
|
4
5
|
from code_agnostic.agents.parser import serialize_agent
|
|
@@ -8,7 +9,7 @@ from code_agnostic.apps.common.models import MCPServerDTO
|
|
|
8
9
|
from code_agnostic.apps.common.utils import common_mcp_to_dto, dto_to_common_mcp
|
|
9
10
|
from code_agnostic.core.repository import CoreRepository
|
|
10
11
|
from code_agnostic.errors import InvalidConfigSchemaError, InvalidJsonFormatError
|
|
11
|
-
from code_agnostic.imports.adapters import create_import_adapter
|
|
12
|
+
from code_agnostic.imports.adapters import ImportAdapter, create_import_adapter
|
|
12
13
|
from code_agnostic.imports.filesystem import (
|
|
13
14
|
content_equal,
|
|
14
15
|
copy_path,
|
|
@@ -261,7 +262,9 @@ class ImportService:
|
|
|
261
262
|
unsupported.append(ImportSection.AGENTS)
|
|
262
263
|
return unsupported
|
|
263
264
|
|
|
264
|
-
def _plan_mcp(
|
|
265
|
+
def _plan_mcp(
|
|
266
|
+
self, adapter: ImportAdapter, conflict_policy: ConflictPolicy
|
|
267
|
+
) -> tuple[list[ImportAction], list[str], list[str]]:
|
|
265
268
|
actions: list[ImportAction] = []
|
|
266
269
|
errors: list[str] = []
|
|
267
270
|
skipped: list[str] = []
|
|
@@ -272,7 +275,7 @@ class ImportService:
|
|
|
272
275
|
return actions, [str(exc)], skipped
|
|
273
276
|
|
|
274
277
|
if not source_dto:
|
|
275
|
-
source_config = adapter.config_repository.config_path
|
|
278
|
+
source_config = adapter.config_repository.config_path # type: ignore[attr-defined]
|
|
276
279
|
if source_config.exists():
|
|
277
280
|
skipped.append(
|
|
278
281
|
f"No MCP servers found in source config: {source_config}"
|
|
@@ -368,7 +371,7 @@ class ImportService:
|
|
|
368
371
|
else:
|
|
369
372
|
skipped.append(f"MCP server skipped due to conflict: {name}")
|
|
370
373
|
|
|
371
|
-
normalized_payload = {}
|
|
374
|
+
normalized_payload: dict[str, Any] = {}
|
|
372
375
|
existing_schema = existing_payload.get("$schema")
|
|
373
376
|
if isinstance(existing_schema, str) and existing_schema:
|
|
374
377
|
normalized_payload["$schema"] = existing_schema
|
|
@@ -399,7 +402,7 @@ class ImportService:
|
|
|
399
402
|
target_dir: Path,
|
|
400
403
|
conflict_policy: ConflictPolicy,
|
|
401
404
|
follow_symlinks: bool,
|
|
402
|
-
):
|
|
405
|
+
) -> tuple[list[ImportAction], list[str], list[str]]:
|
|
403
406
|
actions: list[ImportAction] = []
|
|
404
407
|
errors: list[str] = []
|
|
405
408
|
skipped: list[str] = []
|
|
@@ -518,10 +521,10 @@ class ImportService:
|
|
|
518
521
|
|
|
519
522
|
def _plan_codex_agents(
|
|
520
523
|
self,
|
|
521
|
-
adapter,
|
|
524
|
+
adapter: ImportAdapter,
|
|
522
525
|
conflict_policy: ConflictPolicy,
|
|
523
526
|
follow_symlinks: bool,
|
|
524
|
-
):
|
|
527
|
+
) -> tuple[list[ImportAction], list[str], list[str]]:
|
|
525
528
|
actions: list[ImportAction] = []
|
|
526
529
|
errors: list[str] = []
|
|
527
530
|
skipped: list[str] = []
|
|
@@ -584,10 +587,10 @@ class ImportService:
|
|
|
584
587
|
|
|
585
588
|
def _plan_copilot_agents(
|
|
586
589
|
self,
|
|
587
|
-
adapter,
|
|
590
|
+
adapter: ImportAdapter,
|
|
588
591
|
conflict_policy: ConflictPolicy,
|
|
589
592
|
follow_symlinks: bool,
|
|
590
|
-
):
|
|
593
|
+
) -> tuple[list[ImportAction], list[str], list[str]]:
|
|
591
594
|
actions: list[ImportAction] = []
|
|
592
595
|
errors: list[str] = []
|
|
593
596
|
skipped: list[str] = []
|
|
@@ -707,7 +710,7 @@ class ImportService:
|
|
|
707
710
|
section: ImportSection,
|
|
708
711
|
detail_name: str,
|
|
709
712
|
target: Path,
|
|
710
|
-
payload: dict,
|
|
713
|
+
payload: dict[str, Any],
|
|
711
714
|
conflict_policy: ConflictPolicy,
|
|
712
715
|
) -> tuple[ImportAction, str | None, str | None]:
|
|
713
716
|
existing_payload, existing_error = read_json_safe(target)
|