code-agnostic 0.3.8__tar.gz → 0.3.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.
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/PKG-INFO +55 -10
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/README.md +54 -9
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/__init__.py +1 -1
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/__main__.py +4 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/codex/schema.json +44 -17
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/opencode/schema.json +5 -11
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/cli/commands/mcp.py +29 -10
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/cli/commands/skills.py +11 -4
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/cli/commands/status.py +21 -4
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/cli/commands/workspaces.py +26 -15
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/cli/helpers.py +5 -1
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/core/repository.py +4 -2
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/executor.py +10 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/imports/service.py +5 -1
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/lossiness.py +30 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/mcp_service.py +4 -2
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/status.py +69 -10
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/tui/renderers.py +73 -2
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/tui/tables.py +1 -1
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/utils.py +2 -2
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic.egg-info/PKG-INFO +55 -10
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/pyproject.toml +1 -1
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_aliases.py +1 -1
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_explain_lossiness.py +32 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_flags.py +1 -1
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_import.py +25 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_mcp.py +7 -4
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_skills.py +1 -1
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_status.py +59 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_workspaces.py +44 -1
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_common_repository.py +20 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_transactional_executor.py +6 -3
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_utils.py +45 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_workspace_config_sync.py +19 -11
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/LICENSE +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/agents/__init__.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/agents/claude.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/agents/codex.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/agents/compilers.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/agents/models.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/agents/opencode.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/agents/parser.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/__init__.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/app_id.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/apps_service.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/claude/__init__.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/claude/config_repository.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/claude/mapper.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/claude/service.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/codex/__init__.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/codex/config_repository.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/codex/mapper.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/codex/schema_repository.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/codex/service.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/common/__init__.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/common/compiled_planning.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/common/framework.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/common/interfaces/__init__.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/common/interfaces/mapper.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/common/interfaces/repositories.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/common/interfaces/service.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/common/loader.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/common/models.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/common/schema.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/common/symlink_planning.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/common/utils.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/cursor/__init__.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/cursor/config_repository.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/cursor/mapper.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/cursor/schema.json +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/cursor/schema_repository.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/cursor/service.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/opencode/__init__.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/opencode/config_repository.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/opencode/mapper.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/opencode/schema_repository.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/apps/opencode/service.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/cli/__init__.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/cli/aliases.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/cli/commands/__init__.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/cli/commands/agents.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/cli/commands/apply.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/cli/commands/apps.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/cli/commands/explain_lossiness.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/cli/commands/import_.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/cli/commands/plan.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/cli/commands/restore.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/cli/commands/rules.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/cli/commands/validate.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/cli/options.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/constants.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/core/__init__.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/core/workspace_repository.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/errors.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/generated_artifacts.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/git_exclude_service.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/imports/__init__.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/imports/adapters.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/imports/filesystem.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/imports/models.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/models.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/planner.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/rules/__init__.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/rules/compilers.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/rules/models.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/rules/parser.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/rules/repository.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/skills/__init__.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/skills/compilers.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/skills/models.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/skills/parser.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/spec/__init__.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/spec/loaders.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/spec/schemas/agent.v1.schema.json +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/spec/schemas/mcp.base.schema.json +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/spec/schemas/mcp.v1.schema.json +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/spec/schemas/rule.v1.schema.json +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/spec/schemas/skill.v1.schema.json +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/tui/__init__.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/tui/enums.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/tui/import_selector.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/tui/sections.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/validation.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/workspace_artifacts.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic/workspaces.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic.egg-info/SOURCES.txt +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic.egg-info/dependency_links.txt +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic.egg-info/entry_points.txt +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic.egg-info/requires.txt +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/code_agnostic.egg-info/top_level.txt +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/setup.cfg +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_agents.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_apply_apps.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_apply_codex.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_apply_cursor.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_apply_target.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_apps.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_git_exclude.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_import_interactive.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_module_organization.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_plan.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_restore.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_rules.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_validate.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_cli_workspace_resolution.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_common_mcp_to_dto.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_compiled_planning.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_dto_to_common_mcp.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_git_exclude_service.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_mcp_service.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_planner_executor.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_planner_rules.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_symlink_planning.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_sync_plan_model.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_version.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_workspace_repo_status.py +0 -0
- {code_agnostic-0.3.8 → code_agnostic-0.3.10}/tests/test_workspaces.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-agnostic
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.10
|
|
4
4
|
Summary: Centralized hub for LLM coding config: MCP, skills, rules, and agents.
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -64,6 +64,21 @@ Legacy single-file rules, `skills/<name>/SKILL.md`, and markdown agents are stil
|
|
|
64
64
|
|
|
65
65
|
Today the implementation is still mixed: some assets are compiled and some are symlinked. The active migration plan is to move to generated outputs everywhere with a strict compiler contract instead of implicit per-app behavior.
|
|
66
66
|
|
|
67
|
+
## Scope model
|
|
68
|
+
|
|
69
|
+
`code-agnostic` has two managed source scopes today:
|
|
70
|
+
|
|
71
|
+
- global source config under `~/.config/code-agnostic/`, synced to enabled
|
|
72
|
+
user-level app config;
|
|
73
|
+
- workspace source config under `~/.config/code-agnostic/workspaces/<name>/`,
|
|
74
|
+
propagated into repos inside a registered workspace.
|
|
75
|
+
|
|
76
|
+
Project-local skill folders that users create directly inside a repo, such as
|
|
77
|
+
`.agents/skills` or `.opencode/skills`, are app-native inputs but are not
|
|
78
|
+
managed as source by `code-agnostic` yet. First-class project-scoped installs
|
|
79
|
+
are planned so a single registered project can have managed local source config
|
|
80
|
+
without bypassing the hub.
|
|
81
|
+
|
|
67
82
|
## Install
|
|
68
83
|
|
|
69
84
|
```bash
|
|
@@ -121,6 +136,10 @@ code-agnostic apply
|
|
|
121
136
|
| Import from | yes | yes | yes | yes |
|
|
122
137
|
| Interactive import (TUI) | yes | yes | yes | yes |
|
|
123
138
|
|
|
139
|
+
`yes` means the resource type is synced for that editor. Some metadata is still
|
|
140
|
+
target-specific or lossy; run `code-agnostic explain-lossiness` to see fields
|
|
141
|
+
that are omitted or rejected for a selected target.
|
|
142
|
+
|
|
124
143
|
Cursor workspace propagation writes repo-local MCP, skills, and agents when those resources exist in the workspace source config.
|
|
125
144
|
|
|
126
145
|
OpenCode workspace configs include the shared workspace `AGENTS.md` natively via `instructions`, so repos under the workspace get both repo-local and shared workspace instructions. Codex repos receive workspace instructions through a generated `AGENTS.override.md`, which is added to each repo's `.git/info/exclude`. Claude Code receives workspace instructions through generated `CLAUDE.local.md` files, never by editing committed `CLAUDE.md`.
|
|
@@ -137,10 +156,15 @@ Plan-then-apply workflow. Preview every change before it touches disk.
|
|
|
137
156
|
code-agnostic validate # check canonical source files
|
|
138
157
|
code-agnostic plan -a cursor # dry-run for one editor
|
|
139
158
|
code-agnostic plan # dry-run for all
|
|
140
|
-
code-agnostic apply # apply changes
|
|
141
|
-
code-agnostic status # check drift
|
|
159
|
+
code-agnostic apply # apply changes for all enabled editors
|
|
160
|
+
code-agnostic status # check drift and disabled app states
|
|
161
|
+
code-agnostic explain-lossiness # show fields omitted or rejected per editor
|
|
142
162
|
```
|
|
143
163
|
|
|
164
|
+
Bare `plan` and `apply` target every enabled editor; bare `status` also shows
|
|
165
|
+
disabled app states. Use `-a codex`, `-a cursor`, `-a opencode`, or `-a claude`
|
|
166
|
+
when you want one editor at a time.
|
|
167
|
+
|
|
144
168
|
If managed outputs need repair after an apply, restore the active synced revision:
|
|
145
169
|
|
|
146
170
|
```bash
|
|
@@ -162,19 +186,31 @@ Env vars without a value (`--env GITHUB_TOKEN`) are stored as `${GITHUB_TOKEN}`
|
|
|
162
186
|
|
|
163
187
|
### Rules with metadata
|
|
164
188
|
|
|
165
|
-
|
|
189
|
+
New rules should use bundle directories with schema-validated metadata and a
|
|
190
|
+
separate prompt body:
|
|
166
191
|
|
|
167
|
-
```
|
|
168
|
-
|
|
192
|
+
```text
|
|
193
|
+
rules/python-style/
|
|
194
|
+
├── meta.yaml
|
|
195
|
+
└── prompt.md
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
```yaml
|
|
199
|
+
# rules/python-style/meta.yaml
|
|
200
|
+
spec_version: v1
|
|
201
|
+
kind: rule
|
|
169
202
|
description: "Python coding standards"
|
|
170
203
|
globs: ["*.py"]
|
|
171
204
|
always_apply: false
|
|
172
|
-
|
|
205
|
+
```
|
|
173
206
|
|
|
207
|
+
```markdown
|
|
208
|
+
<!-- rules/python-style/prompt.md -->
|
|
174
209
|
Always use type hints. Prefer dataclasses over dicts.
|
|
175
210
|
```
|
|
176
211
|
|
|
177
212
|
Cross-compiled per editor: Cursor gets `.mdc` files with native frontmatter, OpenCode/Codex get `AGENTS.md` sections.
|
|
213
|
+
Legacy single-file rule markdown with YAML frontmatter remains supported for migration.
|
|
178
214
|
|
|
179
215
|
```bash
|
|
180
216
|
code-agnostic rules list
|
|
@@ -183,7 +219,10 @@ code-agnostic rules remove --name python-style
|
|
|
183
219
|
|
|
184
220
|
### Skills and agents
|
|
185
221
|
|
|
186
|
-
|
|
222
|
+
Use bundle directories for new skills and agents, then let `code-agnostic`
|
|
223
|
+
cross-compile them per editor. Install or edit skills in the `code-agnostic`
|
|
224
|
+
source of truth, then run `plan` / `apply`; do not hand-copy generated skills
|
|
225
|
+
into `.codex`, `.cursor`, `.agents`, or OpenCode directories.
|
|
187
226
|
|
|
188
227
|
```bash
|
|
189
228
|
code-agnostic skills list
|
|
@@ -213,7 +252,7 @@ That command should copy the skill into the source of truth and then run the nor
|
|
|
213
252
|
|
|
214
253
|
### Workspaces
|
|
215
254
|
|
|
216
|
-
Register workspace directories. Workspace rules are compiled into a canonical `AGENTS.md` at the workspace root. Repos keep their own repo-specific `AGENTS.md`; Codex receives the workspace rules through generated, git-excluded `AGENTS.override.md` files, while OpenCode workspace configs reference the shared workspace file through `instructions`. Claude receives generated `CLAUDE.local.md` files and project MCP entries in `~/.claude.json["projects"][absolute_repo_path]["mcpServers"]`.
|
|
255
|
+
Register workspace directories. Workspace rules are compiled into a canonical `AGENTS.md` at the workspace root. Repos keep their own repo-specific `AGENTS.md`; Codex receives the workspace rules through generated, git-excluded `AGENTS.override.md` files, while OpenCode workspace configs reference the shared workspace file through `instructions`. Claude receives generated `CLAUDE.local.md` files and project MCP entries in `~/.claude.json["projects"][absolute_repo_path]["mcpServers"]`. Workspace source config, skills, and agents are propagated into repo-local generated paths for OpenCode, Cursor, Codex, and Claude; user-created project-local skill folders remain unmanaged until project-scoped installs are supported.
|
|
217
256
|
|
|
218
257
|
Cursor propagation intentionally stays to repo-local MCP, skills, and agents; it does not copy the shared workspace `AGENTS.md` into child repos.
|
|
219
258
|
|
|
@@ -245,6 +284,12 @@ code-agnostic import apply -a cursor --include mcp --on-conflict overwrite
|
|
|
245
284
|
code-agnostic import plan -a codex -i # interactive TUI picker
|
|
246
285
|
```
|
|
247
286
|
|
|
287
|
+
`import plan` previews what will be copied into the hub; `import apply` writes
|
|
288
|
+
only the selected sections. Conflicts are skipped by default, so rerun with
|
|
289
|
+
`--on-conflict overwrite` only after reviewing the preview. Use `--include`,
|
|
290
|
+
`--exclude`, `--source-root`, and `--follow-symlinks` to narrow what gets
|
|
291
|
+
imported.
|
|
292
|
+
|
|
248
293
|
### CLI conventions
|
|
249
294
|
|
|
250
295
|
All commands use named flags (`-a`, `-w`, `-v`). Singular aliases work too: `app` = `apps`, `workspace` = `workspaces`.
|
|
@@ -264,7 +309,7 @@ The compiler migration is documented in:
|
|
|
264
309
|
|
|
265
310
|
- [x] Plan/apply/status sync engine
|
|
266
311
|
- [x] MCP server sync across editors
|
|
267
|
-
- [x] Skills and agents sync
|
|
312
|
+
- [x] Skills and agents sync across editors
|
|
268
313
|
- [x] Workspace propagation into git repos
|
|
269
314
|
- [x] Import from existing editor configs
|
|
270
315
|
- [x] Consistent CLI with named flags and aliases
|
|
@@ -39,6 +39,21 @@ Legacy single-file rules, `skills/<name>/SKILL.md`, and markdown agents are stil
|
|
|
39
39
|
|
|
40
40
|
Today the implementation is still mixed: some assets are compiled and some are symlinked. The active migration plan is to move to generated outputs everywhere with a strict compiler contract instead of implicit per-app behavior.
|
|
41
41
|
|
|
42
|
+
## Scope model
|
|
43
|
+
|
|
44
|
+
`code-agnostic` has two managed source scopes today:
|
|
45
|
+
|
|
46
|
+
- global source config under `~/.config/code-agnostic/`, synced to enabled
|
|
47
|
+
user-level app config;
|
|
48
|
+
- workspace source config under `~/.config/code-agnostic/workspaces/<name>/`,
|
|
49
|
+
propagated into repos inside a registered workspace.
|
|
50
|
+
|
|
51
|
+
Project-local skill folders that users create directly inside a repo, such as
|
|
52
|
+
`.agents/skills` or `.opencode/skills`, are app-native inputs but are not
|
|
53
|
+
managed as source by `code-agnostic` yet. First-class project-scoped installs
|
|
54
|
+
are planned so a single registered project can have managed local source config
|
|
55
|
+
without bypassing the hub.
|
|
56
|
+
|
|
42
57
|
## Install
|
|
43
58
|
|
|
44
59
|
```bash
|
|
@@ -96,6 +111,10 @@ code-agnostic apply
|
|
|
96
111
|
| Import from | yes | yes | yes | yes |
|
|
97
112
|
| Interactive import (TUI) | yes | yes | yes | yes |
|
|
98
113
|
|
|
114
|
+
`yes` means the resource type is synced for that editor. Some metadata is still
|
|
115
|
+
target-specific or lossy; run `code-agnostic explain-lossiness` to see fields
|
|
116
|
+
that are omitted or rejected for a selected target.
|
|
117
|
+
|
|
99
118
|
Cursor workspace propagation writes repo-local MCP, skills, and agents when those resources exist in the workspace source config.
|
|
100
119
|
|
|
101
120
|
OpenCode workspace configs include the shared workspace `AGENTS.md` natively via `instructions`, so repos under the workspace get both repo-local and shared workspace instructions. Codex repos receive workspace instructions through a generated `AGENTS.override.md`, which is added to each repo's `.git/info/exclude`. Claude Code receives workspace instructions through generated `CLAUDE.local.md` files, never by editing committed `CLAUDE.md`.
|
|
@@ -112,10 +131,15 @@ Plan-then-apply workflow. Preview every change before it touches disk.
|
|
|
112
131
|
code-agnostic validate # check canonical source files
|
|
113
132
|
code-agnostic plan -a cursor # dry-run for one editor
|
|
114
133
|
code-agnostic plan # dry-run for all
|
|
115
|
-
code-agnostic apply # apply changes
|
|
116
|
-
code-agnostic status # check drift
|
|
134
|
+
code-agnostic apply # apply changes for all enabled editors
|
|
135
|
+
code-agnostic status # check drift and disabled app states
|
|
136
|
+
code-agnostic explain-lossiness # show fields omitted or rejected per editor
|
|
117
137
|
```
|
|
118
138
|
|
|
139
|
+
Bare `plan` and `apply` target every enabled editor; bare `status` also shows
|
|
140
|
+
disabled app states. Use `-a codex`, `-a cursor`, `-a opencode`, or `-a claude`
|
|
141
|
+
when you want one editor at a time.
|
|
142
|
+
|
|
119
143
|
If managed outputs need repair after an apply, restore the active synced revision:
|
|
120
144
|
|
|
121
145
|
```bash
|
|
@@ -137,19 +161,31 @@ Env vars without a value (`--env GITHUB_TOKEN`) are stored as `${GITHUB_TOKEN}`
|
|
|
137
161
|
|
|
138
162
|
### Rules with metadata
|
|
139
163
|
|
|
140
|
-
|
|
164
|
+
New rules should use bundle directories with schema-validated metadata and a
|
|
165
|
+
separate prompt body:
|
|
141
166
|
|
|
142
|
-
```
|
|
143
|
-
|
|
167
|
+
```text
|
|
168
|
+
rules/python-style/
|
|
169
|
+
├── meta.yaml
|
|
170
|
+
└── prompt.md
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
```yaml
|
|
174
|
+
# rules/python-style/meta.yaml
|
|
175
|
+
spec_version: v1
|
|
176
|
+
kind: rule
|
|
144
177
|
description: "Python coding standards"
|
|
145
178
|
globs: ["*.py"]
|
|
146
179
|
always_apply: false
|
|
147
|
-
|
|
180
|
+
```
|
|
148
181
|
|
|
182
|
+
```markdown
|
|
183
|
+
<!-- rules/python-style/prompt.md -->
|
|
149
184
|
Always use type hints. Prefer dataclasses over dicts.
|
|
150
185
|
```
|
|
151
186
|
|
|
152
187
|
Cross-compiled per editor: Cursor gets `.mdc` files with native frontmatter, OpenCode/Codex get `AGENTS.md` sections.
|
|
188
|
+
Legacy single-file rule markdown with YAML frontmatter remains supported for migration.
|
|
153
189
|
|
|
154
190
|
```bash
|
|
155
191
|
code-agnostic rules list
|
|
@@ -158,7 +194,10 @@ code-agnostic rules remove --name python-style
|
|
|
158
194
|
|
|
159
195
|
### Skills and agents
|
|
160
196
|
|
|
161
|
-
|
|
197
|
+
Use bundle directories for new skills and agents, then let `code-agnostic`
|
|
198
|
+
cross-compile them per editor. Install or edit skills in the `code-agnostic`
|
|
199
|
+
source of truth, then run `plan` / `apply`; do not hand-copy generated skills
|
|
200
|
+
into `.codex`, `.cursor`, `.agents`, or OpenCode directories.
|
|
162
201
|
|
|
163
202
|
```bash
|
|
164
203
|
code-agnostic skills list
|
|
@@ -188,7 +227,7 @@ That command should copy the skill into the source of truth and then run the nor
|
|
|
188
227
|
|
|
189
228
|
### Workspaces
|
|
190
229
|
|
|
191
|
-
Register workspace directories. Workspace rules are compiled into a canonical `AGENTS.md` at the workspace root. Repos keep their own repo-specific `AGENTS.md`; Codex receives the workspace rules through generated, git-excluded `AGENTS.override.md` files, while OpenCode workspace configs reference the shared workspace file through `instructions`. Claude receives generated `CLAUDE.local.md` files and project MCP entries in `~/.claude.json["projects"][absolute_repo_path]["mcpServers"]`.
|
|
230
|
+
Register workspace directories. Workspace rules are compiled into a canonical `AGENTS.md` at the workspace root. Repos keep their own repo-specific `AGENTS.md`; Codex receives the workspace rules through generated, git-excluded `AGENTS.override.md` files, while OpenCode workspace configs reference the shared workspace file through `instructions`. Claude receives generated `CLAUDE.local.md` files and project MCP entries in `~/.claude.json["projects"][absolute_repo_path]["mcpServers"]`. Workspace source config, skills, and agents are propagated into repo-local generated paths for OpenCode, Cursor, Codex, and Claude; user-created project-local skill folders remain unmanaged until project-scoped installs are supported.
|
|
192
231
|
|
|
193
232
|
Cursor propagation intentionally stays to repo-local MCP, skills, and agents; it does not copy the shared workspace `AGENTS.md` into child repos.
|
|
194
233
|
|
|
@@ -220,6 +259,12 @@ code-agnostic import apply -a cursor --include mcp --on-conflict overwrite
|
|
|
220
259
|
code-agnostic import plan -a codex -i # interactive TUI picker
|
|
221
260
|
```
|
|
222
261
|
|
|
262
|
+
`import plan` previews what will be copied into the hub; `import apply` writes
|
|
263
|
+
only the selected sections. Conflicts are skipped by default, so rerun with
|
|
264
|
+
`--on-conflict overwrite` only after reviewing the preview. Use `--include`,
|
|
265
|
+
`--exclude`, `--source-root`, and `--follow-symlinks` to narrow what gets
|
|
266
|
+
imported.
|
|
267
|
+
|
|
223
268
|
### CLI conventions
|
|
224
269
|
|
|
225
270
|
All commands use named flags (`-a`, `-w`, `-v`). Singular aliases work too: `app` = `apps`, `workspace` = `workspaces`.
|
|
@@ -239,7 +284,7 @@ The compiler migration is documented in:
|
|
|
239
284
|
|
|
240
285
|
- [x] Plan/apply/status sync engine
|
|
241
286
|
- [x] MCP server sync across editors
|
|
242
|
-
- [x] Skills and agents sync
|
|
287
|
+
- [x] Skills and agents sync across editors
|
|
243
288
|
- [x] Workspace propagation into git repos
|
|
244
289
|
- [x] Import from existing editor configs
|
|
245
290
|
- [x] Consistent CLI with named flags and aliases
|
|
@@ -16,6 +16,7 @@ from code_agnostic.cli.commands.skills import skills
|
|
|
16
16
|
from code_agnostic.cli.commands.status import status
|
|
17
17
|
from code_agnostic.cli.commands.validate import validate
|
|
18
18
|
from code_agnostic.cli.commands.workspaces import workspaces
|
|
19
|
+
from code_agnostic.errors import SyncAppError
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
@click.group(
|
|
@@ -52,6 +53,9 @@ def main() -> int:
|
|
|
52
53
|
except click.exceptions.Exit as exc:
|
|
53
54
|
code = exc.exit_code
|
|
54
55
|
return code if isinstance(code, int) else 1
|
|
56
|
+
except SyncAppError as exc:
|
|
57
|
+
click.ClickException(str(exc)).show()
|
|
58
|
+
return 2
|
|
55
59
|
except click.ClickException as exc:
|
|
56
60
|
exc.show()
|
|
57
61
|
return 2
|
|
@@ -102,6 +102,14 @@
|
|
|
102
102
|
"additionalProperties": false,
|
|
103
103
|
"description": "Config values for a single app/connector.",
|
|
104
104
|
"properties": {
|
|
105
|
+
"approvals_reviewer": {
|
|
106
|
+
"allOf": [
|
|
107
|
+
{
|
|
108
|
+
"$ref": "#/definitions/ApprovalsReviewer"
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
"description": "Reviewer for approval prompts from this app, overriding the thread default."
|
|
112
|
+
},
|
|
105
113
|
"default_tools_approval_mode": {
|
|
106
114
|
"allOf": [
|
|
107
115
|
{
|
|
@@ -347,6 +355,22 @@
|
|
|
347
355
|
},
|
|
348
356
|
"type": "object"
|
|
349
357
|
},
|
|
358
|
+
"CodeModeConfigToml": {
|
|
359
|
+
"additionalProperties": false,
|
|
360
|
+
"properties": {
|
|
361
|
+
"enabled": {
|
|
362
|
+
"type": "boolean"
|
|
363
|
+
},
|
|
364
|
+
"excluded_tool_namespaces": {
|
|
365
|
+
"description": "Exact tool namespaces to omit from the code-mode nested tool surface.",
|
|
366
|
+
"items": {
|
|
367
|
+
"type": "string"
|
|
368
|
+
},
|
|
369
|
+
"type": "array"
|
|
370
|
+
}
|
|
371
|
+
},
|
|
372
|
+
"type": "object"
|
|
373
|
+
},
|
|
350
374
|
"ConfigProfile": {
|
|
351
375
|
"additionalProperties": false,
|
|
352
376
|
"description": "Collection of common configuration options that a user can define as a unit in `config.toml`.",
|
|
@@ -402,7 +426,7 @@
|
|
|
402
426
|
"type": "boolean"
|
|
403
427
|
},
|
|
404
428
|
"code_mode": {
|
|
405
|
-
"
|
|
429
|
+
"$ref": "#/definitions/FeatureToml_for_CodeModeConfigToml"
|
|
406
430
|
},
|
|
407
431
|
"code_mode_only": {
|
|
408
432
|
"type": "boolean"
|
|
@@ -548,9 +572,6 @@
|
|
|
548
572
|
"request_rule": {
|
|
549
573
|
"type": "boolean"
|
|
550
574
|
},
|
|
551
|
-
"responses_websocket_response_processed": {
|
|
552
|
-
"type": "boolean"
|
|
553
|
-
},
|
|
554
575
|
"responses_websockets": {
|
|
555
576
|
"type": "boolean"
|
|
556
577
|
},
|
|
@@ -593,6 +614,9 @@
|
|
|
593
614
|
"terminal_resize_reflow": {
|
|
594
615
|
"type": "boolean"
|
|
595
616
|
},
|
|
617
|
+
"terminal_visualization_instructions": {
|
|
618
|
+
"type": "boolean"
|
|
619
|
+
},
|
|
596
620
|
"tool_call_mcp_elicitation": {
|
|
597
621
|
"type": "boolean"
|
|
598
622
|
},
|
|
@@ -822,6 +846,16 @@
|
|
|
822
846
|
}
|
|
823
847
|
]
|
|
824
848
|
},
|
|
849
|
+
"FeatureToml_for_CodeModeConfigToml": {
|
|
850
|
+
"anyOf": [
|
|
851
|
+
{
|
|
852
|
+
"type": "boolean"
|
|
853
|
+
},
|
|
854
|
+
{
|
|
855
|
+
"$ref": "#/definitions/CodeModeConfigToml"
|
|
856
|
+
}
|
|
857
|
+
]
|
|
858
|
+
},
|
|
825
859
|
"FeatureToml_for_MultiAgentV2ConfigToml": {
|
|
826
860
|
"anyOf": [
|
|
827
861
|
{
|
|
@@ -2472,15 +2506,8 @@
|
|
|
2472
2506
|
"type": "string"
|
|
2473
2507
|
},
|
|
2474
2508
|
"ReasoningEffort": {
|
|
2475
|
-
"description": "
|
|
2476
|
-
"
|
|
2477
|
-
"none",
|
|
2478
|
-
"minimal",
|
|
2479
|
-
"low",
|
|
2480
|
-
"medium",
|
|
2481
|
-
"high",
|
|
2482
|
-
"xhigh"
|
|
2483
|
-
],
|
|
2509
|
+
"description": "A non-empty reasoning effort value advertised by the model.",
|
|
2510
|
+
"minLength": 1,
|
|
2484
2511
|
"type": "string"
|
|
2485
2512
|
},
|
|
2486
2513
|
"ReasoningSummary": {
|
|
@@ -4525,7 +4552,7 @@
|
|
|
4525
4552
|
"type": "boolean"
|
|
4526
4553
|
},
|
|
4527
4554
|
"code_mode": {
|
|
4528
|
-
"
|
|
4555
|
+
"$ref": "#/definitions/FeatureToml_for_CodeModeConfigToml"
|
|
4529
4556
|
},
|
|
4530
4557
|
"code_mode_only": {
|
|
4531
4558
|
"type": "boolean"
|
|
@@ -4671,9 +4698,6 @@
|
|
|
4671
4698
|
"request_rule": {
|
|
4672
4699
|
"type": "boolean"
|
|
4673
4700
|
},
|
|
4674
|
-
"responses_websocket_response_processed": {
|
|
4675
|
-
"type": "boolean"
|
|
4676
|
-
},
|
|
4677
4701
|
"responses_websockets": {
|
|
4678
4702
|
"type": "boolean"
|
|
4679
4703
|
},
|
|
@@ -4716,6 +4740,9 @@
|
|
|
4716
4740
|
"terminal_resize_reflow": {
|
|
4717
4741
|
"type": "boolean"
|
|
4718
4742
|
},
|
|
4743
|
+
"terminal_visualization_instructions": {
|
|
4744
|
+
"type": "boolean"
|
|
4745
|
+
},
|
|
4719
4746
|
"tool_call_mcp_elicitation": {
|
|
4720
4747
|
"type": "boolean"
|
|
4721
4748
|
},
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
},
|
|
58
58
|
"branch": {
|
|
59
59
|
"type": "string",
|
|
60
|
-
"description": "Branch or ref
|
|
60
|
+
"description": "Branch or ref to clone and inspect"
|
|
61
61
|
}
|
|
62
62
|
},
|
|
63
63
|
"required": [
|
|
@@ -154,12 +154,6 @@
|
|
|
154
154
|
"websearch": {
|
|
155
155
|
"$ref": "#/$defs/PermissionActionConfig"
|
|
156
156
|
},
|
|
157
|
-
"repo_clone": {
|
|
158
|
-
"$ref": "#/$defs/PermissionRuleConfig"
|
|
159
|
-
},
|
|
160
|
-
"repo_overview": {
|
|
161
|
-
"$ref": "#/$defs/PermissionRuleConfig"
|
|
162
|
-
},
|
|
163
157
|
"lsp": {
|
|
164
158
|
"$ref": "#/$defs/PermissionRuleConfig"
|
|
165
159
|
},
|
|
@@ -797,6 +791,9 @@
|
|
|
797
791
|
"type": "string",
|
|
798
792
|
"$ref": "https://models.dev/model-schema.json#/$defs/Model"
|
|
799
793
|
},
|
|
794
|
+
"variant": {
|
|
795
|
+
"type": "string"
|
|
796
|
+
},
|
|
800
797
|
"subtask": {
|
|
801
798
|
"type": "boolean"
|
|
802
799
|
}
|
|
@@ -961,9 +958,6 @@
|
|
|
961
958
|
"explore": {
|
|
962
959
|
"$ref": "#/$defs/AgentConfig"
|
|
963
960
|
},
|
|
964
|
-
"scout": {
|
|
965
|
-
"$ref": "#/$defs/AgentConfig"
|
|
966
|
-
},
|
|
967
961
|
"title": {
|
|
968
962
|
"$ref": "#/$defs/AgentConfig"
|
|
969
963
|
},
|
|
@@ -1179,7 +1173,7 @@
|
|
|
1179
1173
|
},
|
|
1180
1174
|
"prune": {
|
|
1181
1175
|
"type": "boolean",
|
|
1182
|
-
"description": "Enable pruning of old tool outputs (default:
|
|
1176
|
+
"description": "Enable pruning of old tool outputs (default: false)"
|
|
1183
1177
|
},
|
|
1184
1178
|
"tail_turns": {
|
|
1185
1179
|
"minimum": 0,
|
|
@@ -5,6 +5,7 @@ from rich.console import Console
|
|
|
5
5
|
|
|
6
6
|
from code_agnostic.cli.options import workspace_option
|
|
7
7
|
from code_agnostic.core.repository import CoreRepository
|
|
8
|
+
from code_agnostic.errors import SyncAppError
|
|
8
9
|
from code_agnostic.imports.models import ConflictPolicy
|
|
9
10
|
from code_agnostic.mcp_service import MCPManagementService
|
|
10
11
|
from code_agnostic.tui import SyncConsoleUI
|
|
@@ -17,12 +18,17 @@ def _parse_env_pair(raw: str) -> tuple[str, str]:
|
|
|
17
18
|
return raw, f"${{{raw}}}"
|
|
18
19
|
|
|
19
20
|
|
|
20
|
-
@click.group(
|
|
21
|
+
@click.group(
|
|
22
|
+
help=(
|
|
23
|
+
"Manage source MCP server definitions. Commands use global source by "
|
|
24
|
+
"default; pass -w/--workspace for workspace source."
|
|
25
|
+
)
|
|
26
|
+
)
|
|
21
27
|
def mcp() -> None:
|
|
22
28
|
pass
|
|
23
29
|
|
|
24
30
|
|
|
25
|
-
@mcp.command("list", help="List
|
|
31
|
+
@mcp.command("list", help="List global MCP servers, or workspace servers with -w.")
|
|
26
32
|
@workspace_option()
|
|
27
33
|
@click.pass_obj
|
|
28
34
|
def mcp_list(obj: dict[str, str], workspace: str | None) -> None:
|
|
@@ -31,17 +37,27 @@ def mcp_list(obj: dict[str, str], workspace: str | None) -> None:
|
|
|
31
37
|
service = MCPManagementService(core)
|
|
32
38
|
try:
|
|
33
39
|
servers = service.list_servers(workspace=workspace)
|
|
34
|
-
except ValueError as exc:
|
|
40
|
+
except (ValueError, SyncAppError) as exc:
|
|
35
41
|
raise click.ClickException(str(exc))
|
|
42
|
+
scope = f"workspace:{workspace}" if workspace else "global"
|
|
36
43
|
rows = [
|
|
37
|
-
[name, dto.command or dto.url or ""]
|
|
44
|
+
[name, scope, dto.command or dto.url or ""]
|
|
45
|
+
for name, dto in sorted(servers.items())
|
|
38
46
|
]
|
|
47
|
+
empty_message = (
|
|
48
|
+
f"No workspace MCP servers configured for {workspace}."
|
|
49
|
+
if workspace
|
|
50
|
+
else "No global MCP servers configured."
|
|
51
|
+
)
|
|
39
52
|
ui.render_list(
|
|
40
|
-
"mcp servers",
|
|
53
|
+
"mcp servers",
|
|
54
|
+
["Server", "Scope", "Command / URL"],
|
|
55
|
+
rows,
|
|
56
|
+
empty_message,
|
|
41
57
|
)
|
|
42
58
|
|
|
43
59
|
|
|
44
|
-
@mcp.command("add", help="Add
|
|
60
|
+
@mcp.command("add", help="Add a global MCP server, or a workspace server with -w.")
|
|
45
61
|
@click.argument("name")
|
|
46
62
|
@click.option("--command", default=None, help="Command for stdio server.")
|
|
47
63
|
@click.option(
|
|
@@ -101,12 +117,14 @@ def mcp_add(
|
|
|
101
117
|
workspace=workspace,
|
|
102
118
|
on_conflict=ConflictPolicy(on_conflict),
|
|
103
119
|
)
|
|
104
|
-
except ValueError as exc:
|
|
120
|
+
except (ValueError, SyncAppError) as exc:
|
|
105
121
|
raise click.ClickException(str(exc))
|
|
106
122
|
click.echo(msg)
|
|
107
123
|
|
|
108
124
|
|
|
109
|
-
@mcp.command(
|
|
125
|
+
@mcp.command(
|
|
126
|
+
"remove", help="Remove a global MCP server, or a workspace server with -w."
|
|
127
|
+
)
|
|
110
128
|
@click.argument("name")
|
|
111
129
|
@workspace_option()
|
|
112
130
|
@click.pass_obj
|
|
@@ -115,8 +133,9 @@ def mcp_remove(obj: dict[str, str], name: str, workspace: str | None) -> None:
|
|
|
115
133
|
service = MCPManagementService(core)
|
|
116
134
|
try:
|
|
117
135
|
removed = service.remove_server(name, workspace=workspace)
|
|
118
|
-
except ValueError as exc:
|
|
136
|
+
except (ValueError, SyncAppError) as exc:
|
|
119
137
|
raise click.ClickException(str(exc))
|
|
120
138
|
if not removed:
|
|
121
139
|
raise click.ClickException(f"Server not found: {name}")
|
|
122
|
-
|
|
140
|
+
scope = f"workspace:{workspace}" if workspace else "global"
|
|
141
|
+
click.echo(f"Removed {scope} MCP server: {name}")
|
|
@@ -12,12 +12,18 @@ from code_agnostic.tui import SyncConsoleUI
|
|
|
12
12
|
from code_agnostic.utils import compact_home_path
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
@click.group(
|
|
15
|
+
@click.group(
|
|
16
|
+
help=(
|
|
17
|
+
"Manage source skill definitions. Commands use global source by default; "
|
|
18
|
+
"pass -w/--workspace for workspace source. Repo-local skill folders are "
|
|
19
|
+
"unmanaged until project-scoped installs are supported."
|
|
20
|
+
)
|
|
21
|
+
)
|
|
16
22
|
def skills() -> None:
|
|
17
23
|
pass
|
|
18
24
|
|
|
19
25
|
|
|
20
|
-
@skills.command("list", help="List
|
|
26
|
+
@skills.command("list", help="List global skills, or workspace skills with -w.")
|
|
21
27
|
@workspace_option()
|
|
22
28
|
@click.pass_obj
|
|
23
29
|
def skills_list(obj: dict[str, str], workspace: str | None) -> None:
|
|
@@ -49,7 +55,7 @@ def skills_list(obj: dict[str, str], workspace: str | None) -> None:
|
|
|
49
55
|
)
|
|
50
56
|
|
|
51
57
|
|
|
52
|
-
@skills.command("remove", help="Remove a skill
|
|
58
|
+
@skills.command("remove", help="Remove a global skill, or a workspace skill with -w.")
|
|
53
59
|
@click.option("--name", required=True, help="Skill name to remove.")
|
|
54
60
|
@workspace_option()
|
|
55
61
|
@click.pass_obj
|
|
@@ -60,4 +66,5 @@ def skills_remove(obj: dict[str, str], name: str, workspace: str | None) -> None
|
|
|
60
66
|
if not skill_dir.exists():
|
|
61
67
|
raise click.ClickException(f"Skill not found: {name}")
|
|
62
68
|
shutil.rmtree(skill_dir)
|
|
63
|
-
|
|
69
|
+
scope = f"workspace:{workspace}" if workspace else "global"
|
|
70
|
+
click.echo(f"Removed {scope} skill: {name}")
|
|
@@ -7,7 +7,13 @@ from code_agnostic.apps.apps_service import AppsService
|
|
|
7
7
|
from code_agnostic.cli.helpers import status_row_for_app
|
|
8
8
|
from code_agnostic.cli.options import app_option, verbose_option
|
|
9
9
|
from code_agnostic.core.repository import CoreRepository
|
|
10
|
-
from code_agnostic.
|
|
10
|
+
from code_agnostic.errors import SyncAppError
|
|
11
|
+
from code_agnostic.models import (
|
|
12
|
+
EditorStatusRow,
|
|
13
|
+
EditorSyncStatus,
|
|
14
|
+
WorkspaceStatusRow,
|
|
15
|
+
WorkspaceSyncStatus,
|
|
16
|
+
)
|
|
11
17
|
from code_agnostic.status import StatusService
|
|
12
18
|
from code_agnostic.tui import SyncConsoleUI
|
|
13
19
|
|
|
@@ -50,9 +56,20 @@ def status(obj: dict[str, str], app: str, verbose: bool) -> None:
|
|
|
50
56
|
|
|
51
57
|
status_service = StatusService()
|
|
52
58
|
enabled_services = apps._resolve_services_for_target(normalized_target)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
try:
|
|
60
|
+
workspace_rows = status_service.build_workspace_status(
|
|
61
|
+
core, app_services=enabled_services
|
|
62
|
+
)
|
|
63
|
+
except SyncAppError as exc:
|
|
64
|
+
workspace_rows = [
|
|
65
|
+
WorkspaceStatusRow(
|
|
66
|
+
name="workspaces",
|
|
67
|
+
path=str(core.workspaces_path),
|
|
68
|
+
status=WorkspaceSyncStatus.ERROR,
|
|
69
|
+
detail=str(exc),
|
|
70
|
+
repos=[],
|
|
71
|
+
)
|
|
72
|
+
]
|
|
56
73
|
ui.render_status(
|
|
57
74
|
editor_rows,
|
|
58
75
|
workspace_rows,
|