codexmgr 0.1.3__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {codexmgr-0.1.3 → codexmgr-0.2.0}/PKG-INFO +70 -23
- {codexmgr-0.1.3 → codexmgr-0.2.0}/README.md +69 -22
- {codexmgr-0.1.3 → codexmgr-0.2.0}/pyproject.toml +1 -1
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/__init__.py +1 -1
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/commands/codex_jit.py +20 -1
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/commands/health.py +48 -0
- codexmgr-0.2.0/src/codexmgr/commands/rules.py +115 -0
- codexmgr-0.2.0/src/codexmgr/custom_agents/__init__.py +1 -0
- codexmgr-0.2.0/src/codexmgr/custom_agents/cli.py +120 -0
- codexmgr-0.2.0/src/codexmgr/custom_agents/config.py +165 -0
- codexmgr-0.2.0/src/codexmgr/custom_agents/copies.py +164 -0
- codexmgr-0.2.0/src/codexmgr/custom_agents/listing.py +131 -0
- codexmgr-0.2.0/src/codexmgr/custom_agents/resolution.py +95 -0
- codexmgr-0.2.0/src/codexmgr/custom_agents/sources.py +135 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/interface/cli.py +8 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/interface/parser.py +26 -0
- codexmgr-0.2.0/src/codexmgr/interface/parsers/agents.py +27 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/packages/config.py +26 -3
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/packages/mutation.py +15 -1
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/project/apply.py +81 -1
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/project/generated.py +18 -1
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/project/state.py +10 -0
- codexmgr-0.2.0/src/codexmgr/rules/__init__.py +1 -0
- codexmgr-0.2.0/src/codexmgr/rules/config.py +193 -0
- codexmgr-0.2.0/src/codexmgr/rules/copies.py +198 -0
- codexmgr-0.2.0/src/codexmgr/rules/listing.py +135 -0
- codexmgr-0.2.0/src/codexmgr/rules/resolution.py +180 -0
- codexmgr-0.2.0/src/codexmgr/rules/sources.py +146 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/tui/app.py +50 -53
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/tui/items.py +37 -0
- codexmgr-0.2.0/src/codexmgr/tui/mutations.py +170 -0
- codexmgr-0.2.0/src/codexmgr/tui/package_state.py +214 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/tui/rendering.py +24 -2
- codexmgr-0.2.0/src/codexmgr/tui/rule_items.py +58 -0
- codexmgr-0.2.0/src/codexmgr/tui/sections.py +203 -0
- codexmgr-0.2.0/src/codexmgr/tui/staged_packages.py +99 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/tui/state.py +52 -95
- codexmgr-0.2.0/tests/test_agents_cli.py +245 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_apply_check_cli.py +73 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_codex_cli.py +83 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_packages_cli.py +164 -0
- codexmgr-0.2.0/tests/test_rules_cli.py +264 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_status_doctor_cli.py +146 -1
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_tui_app.py +75 -14
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_tui_state.py +147 -1
- {codexmgr-0.1.3 → codexmgr-0.2.0}/uv.lock +1 -1
- codexmgr-0.1.3/src/codexmgr/tui/mutations.py +0 -97
- {codexmgr-0.1.3 → codexmgr-0.2.0}/.github/actions/install_package/action.yml +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/.github/workflows/py_test.yml +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/.github/workflows/version_publish_main.yml +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/.gitignore +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/pytest.toml +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/agents/__init__.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/agents/file.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/agents/manager.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/agents/renderer.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/commands/__init__.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/commands/codex.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/commands/config_mutations.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/commands/navigation.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/core/__init__.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/core/errors.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/core/options.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/core/paths.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/core/toml_io.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/hooks/__init__.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/hooks/config.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/hooks/copies.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/hooks/listing.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/hooks/merge.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/hooks/resolution.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/hooks/sources.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/interface/__init__.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/interface/parsers/__init__.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/interface/parsers/mcp.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/mcp/__init__.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/mcp/apply.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/mcp/cli.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/mcp/config.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/mcp/discovery.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/mcp/fields.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/mcp/tables.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/packages/__init__.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/packages/cli.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/packages/listing.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/packages/sources.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/project/__init__.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/project/config.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/project/snapshot.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/project/sync.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/py.typed +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/skills/__init__.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/skills/config.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/skills/copies.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/skills/listing.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/skills/resolution.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/skills/sources.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/tui/__init__.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/tui/cli.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/tui/diff.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/tui/models.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/tui/package_refs.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/tui/package_selection.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/conftest.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_agents_file.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_agentsmd_list_cli.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_agentsmd_tools_cli.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_cd_cli.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_cli.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_empty_skill_config_cli.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_home_resolution_cli.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_hooks_cli.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_mcp_apply_cli.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_mcp_cli.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_package_metadata.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_paths.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_python_compatibility.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_renderer.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_skill_copies_cli.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_skill_home_sources_cli.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_skill_list_cli.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_skills_cli.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_sync_cli.py +0 -0
- {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_toml_io.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codexmgr
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Manage project-local Codex configuration from reusable templates
|
|
5
5
|
Keywords: agents,cli,codex,configuration,skills
|
|
6
6
|
Classifier: Development Status :: 4 - Beta
|
|
@@ -34,7 +34,9 @@ The tool is intentionally narrow:
|
|
|
34
34
|
- compose reusable AGENTS.md instruction fragments
|
|
35
35
|
- enable or disable Codex skills per project
|
|
36
36
|
- enable or disable reusable Codex hook bundles per project
|
|
37
|
-
- enable or disable
|
|
37
|
+
- enable or disable project custom agents from reusable TOML files
|
|
38
|
+
- enable or disable reusable rule files copied into project-local `.rules/`
|
|
39
|
+
- enable or disable packaged sets of AGENTS.md, agent, skill, hook, and rule settings
|
|
38
40
|
- enable, disable, inspect, and update safe project-local MCP overrides
|
|
39
41
|
- use an interactive terminal UI for common project management tasks
|
|
40
42
|
- write reproducible lock data for the resolved project configuration
|
|
@@ -100,14 +102,16 @@ This updates `.codex/codexmgr.toml`, runs `apply`, writes
|
|
|
100
102
|
|
|
101
103
|
- `.codex/codexmgr.toml`: source configuration edited by CLI commands or by
|
|
102
104
|
hand
|
|
103
|
-
- `.codex/codexmgr.lock`: resolved template, skill, hook, and MCP state
|
|
104
|
-
`apply`
|
|
105
|
+
- `.codex/codexmgr.lock`: resolved template, agent, skill, hook, and MCP state
|
|
106
|
+
written by `apply`
|
|
105
107
|
- `.codex/config.toml`: Codex config updated with `[[skills.config]]` entries
|
|
106
108
|
and `[mcp_servers.<id>]` overrides
|
|
107
109
|
- `.codex/hooks.json`: Codex hook config updated with enabled reusable hook
|
|
108
110
|
bundles while preserving unmanaged local hooks
|
|
109
111
|
- `.codex/hooks/<name>`: project-local copies of enabled hook bundle support
|
|
110
112
|
files
|
|
113
|
+
- `.codex/agents/<name>.toml`: project-local copies of enabled custom agents
|
|
114
|
+
- `.rules/<path>`: project-local copies of enabled reusable rule files
|
|
111
115
|
- `AGENTS.md`: project instructions, with only the managed block replaced
|
|
112
116
|
|
|
113
117
|
The managed AGENTS.md block is:
|
|
@@ -122,8 +126,8 @@ Manual content outside this block is preserved. If the block is missing,
|
|
|
122
126
|
|
|
123
127
|
## Project Configuration
|
|
124
128
|
|
|
125
|
-
`.codex/codexmgr.toml` supports AGENTS.md templates,
|
|
126
|
-
overrides:
|
|
129
|
+
`.codex/codexmgr.toml` supports AGENTS.md templates, custom-agent state, skill
|
|
130
|
+
state, hook state, and MCP overrides:
|
|
127
131
|
|
|
128
132
|
```toml
|
|
129
133
|
[agents_md]
|
|
@@ -133,10 +137,18 @@ src = ["coding", "/absolute/or/project-relative/template.toml"]
|
|
|
133
137
|
enabled = ["review-helper"]
|
|
134
138
|
disabled = ["experimental-skill", "skills/local-disabled"]
|
|
135
139
|
|
|
140
|
+
[agents]
|
|
141
|
+
enabled = ["rule-retriever"]
|
|
142
|
+
disabled = ["experimental-agent"]
|
|
143
|
+
|
|
136
144
|
[hooks]
|
|
137
145
|
enabled = ["repo-rules"]
|
|
138
146
|
disabled = ["experimental-hook"]
|
|
139
147
|
|
|
148
|
+
[rules]
|
|
149
|
+
enabled = ["react/", "python/testing.md"]
|
|
150
|
+
disabled = ["react/materials/"]
|
|
151
|
+
|
|
140
152
|
[mcp.servers.browsermcp]
|
|
141
153
|
enabled = true
|
|
142
154
|
bearer_token_env_var = "BROWSERMCP_TOKEN"
|
|
@@ -155,33 +167,49 @@ Path-like skill values resolve to either a `SKILL.md` file or a directory
|
|
|
155
167
|
containing `SKILL.md`. Missing skills are written as name-based entries so Codex
|
|
156
168
|
can resolve them later.
|
|
157
169
|
|
|
170
|
+
Named custom agents resolve from `$CODEXMGR_HOME/agents/<name>.toml`. Enabled
|
|
171
|
+
agents are copied into `.codex/agents/<name>.toml` on every apply. Disabled
|
|
172
|
+
agents remove their managed copy only when the lock records the file as
|
|
173
|
+
codexmgr-managed.
|
|
174
|
+
|
|
158
175
|
Named hooks resolve from `$CODEXMGR_HOME/hooks/<name>/hooks.json`. Enabled hook
|
|
159
176
|
bundles are merged into `.codex/hooks.json` on every apply with
|
|
160
177
|
`codexmanager_meta` added to each managed handler. Existing unmanaged hooks are
|
|
161
178
|
preserved. Bundle files other than the root `hooks.json` are copied into
|
|
162
179
|
`.codex/hooks/<name>`.
|
|
163
180
|
|
|
181
|
+
Rule refs resolve under `$CODEXMGR_HOME/rules/` and are POSIX-style relative
|
|
182
|
+
paths. Folder refs are stored with a trailing slash and copy all regular files
|
|
183
|
+
recursively into `.rules/` while preserving relative paths. File refs copy one
|
|
184
|
+
file. Extensionless refs prefer an existing `<ref>.md`. Enabled refs expand
|
|
185
|
+
first, then disabled file or folder refs remove entries from that candidate set.
|
|
186
|
+
First-time applies refuse to overwrite unmanaged `.rules/...` files.
|
|
187
|
+
|
|
164
188
|
Packaged configurations resolve from
|
|
165
189
|
`$CODEXMGR_HOME/packages/<name>/config.toml`. A package config is a TOML
|
|
166
|
-
document that can contain root `agentsmd`, `hooks`, and `
|
|
167
|
-
plus optional profile tables:
|
|
190
|
+
document that can contain root `agentsmd`, `agents`, `hooks`, `skills`, and `rules`
|
|
191
|
+
string lists plus optional profile tables:
|
|
168
192
|
|
|
169
193
|
```toml
|
|
170
194
|
agentsmd = []
|
|
195
|
+
agents = ["rule-retriever"]
|
|
171
196
|
hooks = ["repo-rules"]
|
|
172
197
|
skills = ["repo-rule-manager"]
|
|
198
|
+
rules = ["react/"]
|
|
173
199
|
|
|
174
200
|
[profiles.strict]
|
|
175
201
|
agentsmd = ["strict-coding"]
|
|
202
|
+
agents = ["strict-agent"]
|
|
176
203
|
hooks = ["strict-rules"]
|
|
177
204
|
skills = ["strict-review"]
|
|
205
|
+
rules = ["python/testing.md"]
|
|
178
206
|
```
|
|
179
207
|
|
|
180
208
|
`codexmgr package enable <name>` validates package AGENTS.md and hook
|
|
181
209
|
references, then updates `.codex/codexmgr.toml` as if the corresponding
|
|
182
210
|
`agentsmd add`, `hooks enable`, and `skill enable` commands had been run.
|
|
183
211
|
`codexmgr package disable <name>` removes package AGENTS.md entries when
|
|
184
|
-
present and disables the package skills and
|
|
212
|
+
present and disables the package skills, hooks, agents, and rules.
|
|
185
213
|
|
|
186
214
|
Package profiles are merged with the root package entries:
|
|
187
215
|
|
|
@@ -205,10 +233,13 @@ unless `--no-sync` was explicitly requested.
|
|
|
205
233
|
## Interactive TUI
|
|
206
234
|
|
|
207
235
|
`codexmgr tui` opens a Textual-based terminal UI for managing project-local
|
|
208
|
-
configuration. It shows AGENTS.md templates, skills, hooks,
|
|
209
|
-
server enable overrides in selectable lists. Changes are
|
|
210
|
-
you navigate and toggle entries. Press `s` to save; the
|
|
211
|
-
`.codex/codexmgr.toml` once and runs `apply` once unless
|
|
236
|
+
configuration. It shows AGENTS.md templates, skills, hooks, custom agents,
|
|
237
|
+
rules, packages, and MCP server enable overrides in selectable lists. Changes are
|
|
238
|
+
staged in memory while you navigate and toggle entries. Press `s` to save; the
|
|
239
|
+
save writes `.codex/codexmgr.toml` once and runs `apply` once unless
|
|
240
|
+
`--no-sync` was used.
|
|
241
|
+
For resources with explicit enable and disable lists, `space` cycles the
|
|
242
|
+
highlighted row through available, enabled, and disabled states.
|
|
212
243
|
Package profiles appear as separate selectable rows under their package.
|
|
213
244
|
|
|
214
245
|
```bash
|
|
@@ -270,9 +301,15 @@ codexmgr init-template agentsmd <name>
|
|
|
270
301
|
codexmgr skill list
|
|
271
302
|
codexmgr skill enable [--no-sync] <name-or-skill-path> [...]
|
|
272
303
|
codexmgr skill disable [--no-sync] <name-or-skill-path> [...]
|
|
304
|
+
codexmgr agents list
|
|
305
|
+
codexmgr agents enable [--no-sync] <agent-name> [...]
|
|
306
|
+
codexmgr agents disable [--no-sync] <agent-name> [...]
|
|
273
307
|
codexmgr hooks list
|
|
274
308
|
codexmgr hooks enable [--no-sync] <hook-name> [...]
|
|
275
309
|
codexmgr hooks disable [--no-sync] <hook-name> [...]
|
|
310
|
+
codexmgr rules list
|
|
311
|
+
codexmgr rules enable [--no-sync] <rule-ref> [...]
|
|
312
|
+
codexmgr rules disable [--no-sync] <rule-ref> [...]
|
|
276
313
|
codexmgr package list
|
|
277
314
|
codexmgr package enable [--no-sync] <package-name> [...] [--profile <name> [...]]
|
|
278
315
|
codexmgr package disable [--no-sync] <package-name> [...] [--profile <name> [...]]
|
|
@@ -294,8 +331,10 @@ codexmgr codex <args...>
|
|
|
294
331
|
|
|
295
332
|
`apply` reads `.codex/codexmgr.toml`, resolves configured sources, writes
|
|
296
333
|
`.codex/codexmgr.lock`, updates `.codex/config.toml` skill entries when a
|
|
297
|
-
`[skills]` table is configured,
|
|
298
|
-
configured, writes
|
|
334
|
+
`[skills]` table is configured, copies `.codex/agents/<name>.toml` files when
|
|
335
|
+
`[agents]` is configured, writes `.codex/hooks.json` when `[hooks]` is
|
|
336
|
+
configured, copies `.rules/<path>` files when `[rules]` is configured, writes
|
|
337
|
+
local `[mcp_servers.<id>]` overrides when `[mcp]` is
|
|
299
338
|
configured, and refreshes the generated `AGENTS.md` block when `[agents_md]` is
|
|
300
339
|
configured.
|
|
301
340
|
|
|
@@ -309,11 +348,11 @@ the directory in a file explorer, and `codexmgr cd --terminal` to open a new
|
|
|
309
348
|
terminal there.
|
|
310
349
|
|
|
311
350
|
`doctor` checks project setup, home environment variables, project TOML syntax,
|
|
312
|
-
referenced snippets, enabled skills, enabled
|
|
313
|
-
files.
|
|
351
|
+
referenced snippets, enabled skills, enabled custom agents, enabled hook
|
|
352
|
+
bundles, enabled rules, and stale generated files.
|
|
314
353
|
|
|
315
|
-
`status` prints the resolved homes, configured snippets, skills,
|
|
316
|
-
whether generated files are in sync.
|
|
354
|
+
`status` prints the resolved homes, configured snippets, skills, custom agents,
|
|
355
|
+
hooks, rules, and whether generated files are in sync.
|
|
317
356
|
|
|
318
357
|
`codexmgr codex` can run with a just-in-time package/profile overlay without
|
|
319
358
|
changing `.codex/codexmgr.toml`. Put Codex arguments after `--` when using this
|
|
@@ -413,13 +452,21 @@ marks configured hook bundles as enabled, disabled, or missing.
|
|
|
413
452
|
config. `hooks enable` and `hooks disable` keep enabled and disabled lists
|
|
414
453
|
mutually exclusive. Repeated commands keep one entry.
|
|
415
454
|
|
|
455
|
+
`rules list` prints available `$CODEXMGR_HOME/rules/**` files and folders and
|
|
456
|
+
marks configured rule refs as enabled, disabled, or missing.
|
|
457
|
+
|
|
458
|
+
`rules enable` validates and canonicalizes refs before writing config.
|
|
459
|
+
`rules disable` canonicalizes existing refs and permits missing exclusions.
|
|
460
|
+
Enabled and disabled lists are exact-ref mutually exclusive, so parent enables
|
|
461
|
+
and child disables can intentionally coexist.
|
|
462
|
+
|
|
416
463
|
`package list` prints available `$CODEXMGR_HOME/packages/*/config.toml`
|
|
417
464
|
entries in sorted order.
|
|
418
465
|
|
|
419
|
-
`package enable` and `package disable` proxy to existing AGENTS.md,
|
|
420
|
-
hook project-config mutations. Package state is not tracked
|
|
421
|
-
resulting `[agents_md]`, `[skills]`, and `[
|
|
422
|
-
truth.
|
|
466
|
+
`package enable` and `package disable` proxy to existing AGENTS.md, custom-agent,
|
|
467
|
+
skill, hook, and rule project-config mutations. Package state is not tracked
|
|
468
|
+
separately; the resulting `[agents_md]`, `[agents]`, `[skills]`, `[hooks]`, and `[rules]`
|
|
469
|
+
tables remain the source of truth.
|
|
423
470
|
|
|
424
471
|
`codex` forwards arguments to the real `codex` command. Values from
|
|
425
472
|
`.codex/config.toml` are flattened into `-c key=value` overrides. User-provided
|
|
@@ -11,7 +11,9 @@ The tool is intentionally narrow:
|
|
|
11
11
|
- compose reusable AGENTS.md instruction fragments
|
|
12
12
|
- enable or disable Codex skills per project
|
|
13
13
|
- enable or disable reusable Codex hook bundles per project
|
|
14
|
-
- enable or disable
|
|
14
|
+
- enable or disable project custom agents from reusable TOML files
|
|
15
|
+
- enable or disable reusable rule files copied into project-local `.rules/`
|
|
16
|
+
- enable or disable packaged sets of AGENTS.md, agent, skill, hook, and rule settings
|
|
15
17
|
- enable, disable, inspect, and update safe project-local MCP overrides
|
|
16
18
|
- use an interactive terminal UI for common project management tasks
|
|
17
19
|
- write reproducible lock data for the resolved project configuration
|
|
@@ -77,14 +79,16 @@ This updates `.codex/codexmgr.toml`, runs `apply`, writes
|
|
|
77
79
|
|
|
78
80
|
- `.codex/codexmgr.toml`: source configuration edited by CLI commands or by
|
|
79
81
|
hand
|
|
80
|
-
- `.codex/codexmgr.lock`: resolved template, skill, hook, and MCP state
|
|
81
|
-
`apply`
|
|
82
|
+
- `.codex/codexmgr.lock`: resolved template, agent, skill, hook, and MCP state
|
|
83
|
+
written by `apply`
|
|
82
84
|
- `.codex/config.toml`: Codex config updated with `[[skills.config]]` entries
|
|
83
85
|
and `[mcp_servers.<id>]` overrides
|
|
84
86
|
- `.codex/hooks.json`: Codex hook config updated with enabled reusable hook
|
|
85
87
|
bundles while preserving unmanaged local hooks
|
|
86
88
|
- `.codex/hooks/<name>`: project-local copies of enabled hook bundle support
|
|
87
89
|
files
|
|
90
|
+
- `.codex/agents/<name>.toml`: project-local copies of enabled custom agents
|
|
91
|
+
- `.rules/<path>`: project-local copies of enabled reusable rule files
|
|
88
92
|
- `AGENTS.md`: project instructions, with only the managed block replaced
|
|
89
93
|
|
|
90
94
|
The managed AGENTS.md block is:
|
|
@@ -99,8 +103,8 @@ Manual content outside this block is preserved. If the block is missing,
|
|
|
99
103
|
|
|
100
104
|
## Project Configuration
|
|
101
105
|
|
|
102
|
-
`.codex/codexmgr.toml` supports AGENTS.md templates,
|
|
103
|
-
overrides:
|
|
106
|
+
`.codex/codexmgr.toml` supports AGENTS.md templates, custom-agent state, skill
|
|
107
|
+
state, hook state, and MCP overrides:
|
|
104
108
|
|
|
105
109
|
```toml
|
|
106
110
|
[agents_md]
|
|
@@ -110,10 +114,18 @@ src = ["coding", "/absolute/or/project-relative/template.toml"]
|
|
|
110
114
|
enabled = ["review-helper"]
|
|
111
115
|
disabled = ["experimental-skill", "skills/local-disabled"]
|
|
112
116
|
|
|
117
|
+
[agents]
|
|
118
|
+
enabled = ["rule-retriever"]
|
|
119
|
+
disabled = ["experimental-agent"]
|
|
120
|
+
|
|
113
121
|
[hooks]
|
|
114
122
|
enabled = ["repo-rules"]
|
|
115
123
|
disabled = ["experimental-hook"]
|
|
116
124
|
|
|
125
|
+
[rules]
|
|
126
|
+
enabled = ["react/", "python/testing.md"]
|
|
127
|
+
disabled = ["react/materials/"]
|
|
128
|
+
|
|
117
129
|
[mcp.servers.browsermcp]
|
|
118
130
|
enabled = true
|
|
119
131
|
bearer_token_env_var = "BROWSERMCP_TOKEN"
|
|
@@ -132,33 +144,49 @@ Path-like skill values resolve to either a `SKILL.md` file or a directory
|
|
|
132
144
|
containing `SKILL.md`. Missing skills are written as name-based entries so Codex
|
|
133
145
|
can resolve them later.
|
|
134
146
|
|
|
147
|
+
Named custom agents resolve from `$CODEXMGR_HOME/agents/<name>.toml`. Enabled
|
|
148
|
+
agents are copied into `.codex/agents/<name>.toml` on every apply. Disabled
|
|
149
|
+
agents remove their managed copy only when the lock records the file as
|
|
150
|
+
codexmgr-managed.
|
|
151
|
+
|
|
135
152
|
Named hooks resolve from `$CODEXMGR_HOME/hooks/<name>/hooks.json`. Enabled hook
|
|
136
153
|
bundles are merged into `.codex/hooks.json` on every apply with
|
|
137
154
|
`codexmanager_meta` added to each managed handler. Existing unmanaged hooks are
|
|
138
155
|
preserved. Bundle files other than the root `hooks.json` are copied into
|
|
139
156
|
`.codex/hooks/<name>`.
|
|
140
157
|
|
|
158
|
+
Rule refs resolve under `$CODEXMGR_HOME/rules/` and are POSIX-style relative
|
|
159
|
+
paths. Folder refs are stored with a trailing slash and copy all regular files
|
|
160
|
+
recursively into `.rules/` while preserving relative paths. File refs copy one
|
|
161
|
+
file. Extensionless refs prefer an existing `<ref>.md`. Enabled refs expand
|
|
162
|
+
first, then disabled file or folder refs remove entries from that candidate set.
|
|
163
|
+
First-time applies refuse to overwrite unmanaged `.rules/...` files.
|
|
164
|
+
|
|
141
165
|
Packaged configurations resolve from
|
|
142
166
|
`$CODEXMGR_HOME/packages/<name>/config.toml`. A package config is a TOML
|
|
143
|
-
document that can contain root `agentsmd`, `hooks`, and `
|
|
144
|
-
plus optional profile tables:
|
|
167
|
+
document that can contain root `agentsmd`, `agents`, `hooks`, `skills`, and `rules`
|
|
168
|
+
string lists plus optional profile tables:
|
|
145
169
|
|
|
146
170
|
```toml
|
|
147
171
|
agentsmd = []
|
|
172
|
+
agents = ["rule-retriever"]
|
|
148
173
|
hooks = ["repo-rules"]
|
|
149
174
|
skills = ["repo-rule-manager"]
|
|
175
|
+
rules = ["react/"]
|
|
150
176
|
|
|
151
177
|
[profiles.strict]
|
|
152
178
|
agentsmd = ["strict-coding"]
|
|
179
|
+
agents = ["strict-agent"]
|
|
153
180
|
hooks = ["strict-rules"]
|
|
154
181
|
skills = ["strict-review"]
|
|
182
|
+
rules = ["python/testing.md"]
|
|
155
183
|
```
|
|
156
184
|
|
|
157
185
|
`codexmgr package enable <name>` validates package AGENTS.md and hook
|
|
158
186
|
references, then updates `.codex/codexmgr.toml` as if the corresponding
|
|
159
187
|
`agentsmd add`, `hooks enable`, and `skill enable` commands had been run.
|
|
160
188
|
`codexmgr package disable <name>` removes package AGENTS.md entries when
|
|
161
|
-
present and disables the package skills and
|
|
189
|
+
present and disables the package skills, hooks, agents, and rules.
|
|
162
190
|
|
|
163
191
|
Package profiles are merged with the root package entries:
|
|
164
192
|
|
|
@@ -182,10 +210,13 @@ unless `--no-sync` was explicitly requested.
|
|
|
182
210
|
## Interactive TUI
|
|
183
211
|
|
|
184
212
|
`codexmgr tui` opens a Textual-based terminal UI for managing project-local
|
|
185
|
-
configuration. It shows AGENTS.md templates, skills, hooks,
|
|
186
|
-
server enable overrides in selectable lists. Changes are
|
|
187
|
-
you navigate and toggle entries. Press `s` to save; the
|
|
188
|
-
`.codex/codexmgr.toml` once and runs `apply` once unless
|
|
213
|
+
configuration. It shows AGENTS.md templates, skills, hooks, custom agents,
|
|
214
|
+
rules, packages, and MCP server enable overrides in selectable lists. Changes are
|
|
215
|
+
staged in memory while you navigate and toggle entries. Press `s` to save; the
|
|
216
|
+
save writes `.codex/codexmgr.toml` once and runs `apply` once unless
|
|
217
|
+
`--no-sync` was used.
|
|
218
|
+
For resources with explicit enable and disable lists, `space` cycles the
|
|
219
|
+
highlighted row through available, enabled, and disabled states.
|
|
189
220
|
Package profiles appear as separate selectable rows under their package.
|
|
190
221
|
|
|
191
222
|
```bash
|
|
@@ -247,9 +278,15 @@ codexmgr init-template agentsmd <name>
|
|
|
247
278
|
codexmgr skill list
|
|
248
279
|
codexmgr skill enable [--no-sync] <name-or-skill-path> [...]
|
|
249
280
|
codexmgr skill disable [--no-sync] <name-or-skill-path> [...]
|
|
281
|
+
codexmgr agents list
|
|
282
|
+
codexmgr agents enable [--no-sync] <agent-name> [...]
|
|
283
|
+
codexmgr agents disable [--no-sync] <agent-name> [...]
|
|
250
284
|
codexmgr hooks list
|
|
251
285
|
codexmgr hooks enable [--no-sync] <hook-name> [...]
|
|
252
286
|
codexmgr hooks disable [--no-sync] <hook-name> [...]
|
|
287
|
+
codexmgr rules list
|
|
288
|
+
codexmgr rules enable [--no-sync] <rule-ref> [...]
|
|
289
|
+
codexmgr rules disable [--no-sync] <rule-ref> [...]
|
|
253
290
|
codexmgr package list
|
|
254
291
|
codexmgr package enable [--no-sync] <package-name> [...] [--profile <name> [...]]
|
|
255
292
|
codexmgr package disable [--no-sync] <package-name> [...] [--profile <name> [...]]
|
|
@@ -271,8 +308,10 @@ codexmgr codex <args...>
|
|
|
271
308
|
|
|
272
309
|
`apply` reads `.codex/codexmgr.toml`, resolves configured sources, writes
|
|
273
310
|
`.codex/codexmgr.lock`, updates `.codex/config.toml` skill entries when a
|
|
274
|
-
`[skills]` table is configured,
|
|
275
|
-
configured, writes
|
|
311
|
+
`[skills]` table is configured, copies `.codex/agents/<name>.toml` files when
|
|
312
|
+
`[agents]` is configured, writes `.codex/hooks.json` when `[hooks]` is
|
|
313
|
+
configured, copies `.rules/<path>` files when `[rules]` is configured, writes
|
|
314
|
+
local `[mcp_servers.<id>]` overrides when `[mcp]` is
|
|
276
315
|
configured, and refreshes the generated `AGENTS.md` block when `[agents_md]` is
|
|
277
316
|
configured.
|
|
278
317
|
|
|
@@ -286,11 +325,11 @@ the directory in a file explorer, and `codexmgr cd --terminal` to open a new
|
|
|
286
325
|
terminal there.
|
|
287
326
|
|
|
288
327
|
`doctor` checks project setup, home environment variables, project TOML syntax,
|
|
289
|
-
referenced snippets, enabled skills, enabled
|
|
290
|
-
files.
|
|
328
|
+
referenced snippets, enabled skills, enabled custom agents, enabled hook
|
|
329
|
+
bundles, enabled rules, and stale generated files.
|
|
291
330
|
|
|
292
|
-
`status` prints the resolved homes, configured snippets, skills,
|
|
293
|
-
whether generated files are in sync.
|
|
331
|
+
`status` prints the resolved homes, configured snippets, skills, custom agents,
|
|
332
|
+
hooks, rules, and whether generated files are in sync.
|
|
294
333
|
|
|
295
334
|
`codexmgr codex` can run with a just-in-time package/profile overlay without
|
|
296
335
|
changing `.codex/codexmgr.toml`. Put Codex arguments after `--` when using this
|
|
@@ -390,13 +429,21 @@ marks configured hook bundles as enabled, disabled, or missing.
|
|
|
390
429
|
config. `hooks enable` and `hooks disable` keep enabled and disabled lists
|
|
391
430
|
mutually exclusive. Repeated commands keep one entry.
|
|
392
431
|
|
|
432
|
+
`rules list` prints available `$CODEXMGR_HOME/rules/**` files and folders and
|
|
433
|
+
marks configured rule refs as enabled, disabled, or missing.
|
|
434
|
+
|
|
435
|
+
`rules enable` validates and canonicalizes refs before writing config.
|
|
436
|
+
`rules disable` canonicalizes existing refs and permits missing exclusions.
|
|
437
|
+
Enabled and disabled lists are exact-ref mutually exclusive, so parent enables
|
|
438
|
+
and child disables can intentionally coexist.
|
|
439
|
+
|
|
393
440
|
`package list` prints available `$CODEXMGR_HOME/packages/*/config.toml`
|
|
394
441
|
entries in sorted order.
|
|
395
442
|
|
|
396
|
-
`package enable` and `package disable` proxy to existing AGENTS.md,
|
|
397
|
-
hook project-config mutations. Package state is not tracked
|
|
398
|
-
resulting `[agents_md]`, `[skills]`, and `[
|
|
399
|
-
truth.
|
|
443
|
+
`package enable` and `package disable` proxy to existing AGENTS.md, custom-agent,
|
|
444
|
+
skill, hook, and rule project-config mutations. Package state is not tracked
|
|
445
|
+
separately; the resulting `[agents_md]`, `[agents]`, `[skills]`, `[hooks]`, and `[rules]`
|
|
446
|
+
tables remain the source of truth.
|
|
400
447
|
|
|
401
448
|
`codex` forwards arguments to the real `codex` command. Values from
|
|
402
449
|
`.codex/config.toml` are flattened into `-c key=value` overrides. User-provided
|
|
@@ -82,7 +82,7 @@ def build_jit_project_state(
|
|
|
82
82
|
codexmgr_home,
|
|
83
83
|
request.profiles,
|
|
84
84
|
)
|
|
85
|
-
apply_package_entries_to_config(overlay, entries, enabled=True)
|
|
85
|
+
apply_package_entries_to_config(overlay, entries, codexmgr_home, enabled=True)
|
|
86
86
|
return build_project_state_from_config(overlay, cwd, codex_home, codexmgr_home)
|
|
87
87
|
|
|
88
88
|
|
|
@@ -205,7 +205,26 @@ def _state_paths(state: ProjectBuild) -> list[Path]:
|
|
|
205
205
|
*(generated_file.path for generated_file in state.files),
|
|
206
206
|
*(skill_copy.target for skill_copy in state.skill_copies),
|
|
207
207
|
*(hook_copy.target for hook_copy in state.hook_copies),
|
|
208
|
+
*(agent_copy.target for agent_copy in state.agent_copies),
|
|
209
|
+
*(_rule_root(rule_copy.target) for rule_copy in state.rule_copies),
|
|
208
210
|
*state.obsolete_file_targets,
|
|
209
211
|
*state.obsolete_skill_copy_targets,
|
|
210
212
|
*state.obsolete_hook_copy_targets,
|
|
213
|
+
*state.obsolete_agent_copy_targets,
|
|
214
|
+
*(_rule_root(target) for target in state.obsolete_rule_copy_targets),
|
|
211
215
|
]
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def _rule_root(path: Path) -> Path:
|
|
219
|
+
"""Return the `.rules` ancestor for a rule file path.
|
|
220
|
+
|
|
221
|
+
Args:
|
|
222
|
+
path: Rule copy path or obsolete rule target.
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
The nearest `.rules` ancestor, or the original path when absent.
|
|
226
|
+
"""
|
|
227
|
+
for parent in [path, *path.parents]:
|
|
228
|
+
if parent.name == ".rules":
|
|
229
|
+
return parent
|
|
230
|
+
return path
|
|
@@ -7,9 +7,11 @@ from typing import TextIO
|
|
|
7
7
|
from ..agents.manager import resolve_locked_agents_md
|
|
8
8
|
from ..core.errors import CommandError
|
|
9
9
|
from ..core.paths import project_codex_dir
|
|
10
|
+
from ..custom_agents.listing import configured_agent_lists, missing_enabled_agents
|
|
10
11
|
from ..project.config import agents_md_sources, load_required_project_config
|
|
11
12
|
from ..project.sync import generated_file_diffs
|
|
12
13
|
from ..hooks.listing import configured_hook_lists, missing_enabled_hooks
|
|
14
|
+
from ..rules.listing import configured_rule_lists, missing_enabled_rules
|
|
13
15
|
from ..skills.listing import configured_skill_lists, missing_enabled_skills
|
|
14
16
|
|
|
15
17
|
|
|
@@ -33,6 +35,8 @@ def run_status(
|
|
|
33
35
|
config = load_required_project_config(cwd)
|
|
34
36
|
enabled, disabled = configured_skill_lists(cwd)
|
|
35
37
|
enabled_hooks, disabled_hooks = configured_hook_lists(cwd)
|
|
38
|
+
enabled_agents, disabled_agents = configured_agent_lists(cwd)
|
|
39
|
+
enabled_rules, disabled_rules = configured_rule_lists(cwd)
|
|
36
40
|
diffs = generated_file_diffs(cwd, codex_home, codexmgr_home)
|
|
37
41
|
lines = [
|
|
38
42
|
f"Project: {cwd}",
|
|
@@ -43,6 +47,10 @@ def run_status(
|
|
|
43
47
|
f"Disabled skills: {_format_values(disabled)}",
|
|
44
48
|
f"Enabled hooks: {_format_values(enabled_hooks)}",
|
|
45
49
|
f"Disabled hooks: {_format_values(disabled_hooks)}",
|
|
50
|
+
f"Enabled agents: {_format_values(enabled_agents)}",
|
|
51
|
+
f"Disabled agents: {_format_values(disabled_agents)}",
|
|
52
|
+
f"Enabled rules: {_format_values(enabled_rules)}",
|
|
53
|
+
f"Disabled rules: {_format_values(disabled_rules)}",
|
|
46
54
|
f"Generated files: {_sync_state(diffs)}",
|
|
47
55
|
]
|
|
48
56
|
lines.extend(f" {diff.relative_path}" for diff in diffs)
|
|
@@ -81,6 +89,8 @@ def run_doctor(
|
|
|
81
89
|
_check_agents_sources(config, cwd, codexmgr_home, report)
|
|
82
90
|
_check_missing_enabled_skills(cwd, codex_home, codexmgr_home, report)
|
|
83
91
|
_check_missing_enabled_hooks(cwd, codexmgr_home, report)
|
|
92
|
+
_check_missing_enabled_agents(cwd, codexmgr_home, report)
|
|
93
|
+
_check_missing_enabled_rules(cwd, codexmgr_home, report)
|
|
84
94
|
_check_generated_files(cwd, codex_home, codexmgr_home, report)
|
|
85
95
|
|
|
86
96
|
has_errors = any(line.startswith("ERROR ") for line in report)
|
|
@@ -188,6 +198,44 @@ def _check_missing_enabled_hooks(
|
|
|
188
198
|
report.append(f"ERROR Missing enabled hook: {hook}")
|
|
189
199
|
|
|
190
200
|
|
|
201
|
+
def _check_missing_enabled_agents(
|
|
202
|
+
cwd: Path,
|
|
203
|
+
codexmgr_home: Path,
|
|
204
|
+
report: list[str],
|
|
205
|
+
) -> None:
|
|
206
|
+
"""Check that enabled custom-agent references resolve.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
cwd: Project directory whose configured custom agents should be checked.
|
|
210
|
+
codexmgr_home: codexmgr home used to resolve custom-agent sources.
|
|
211
|
+
report: Mutable diagnostic report receiving any error.
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
None.
|
|
215
|
+
"""
|
|
216
|
+
for agent in missing_enabled_agents(cwd, codexmgr_home):
|
|
217
|
+
report.append(f"ERROR Missing enabled agent: {agent}")
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def _check_missing_enabled_rules(
|
|
221
|
+
cwd: Path,
|
|
222
|
+
codexmgr_home: Path,
|
|
223
|
+
report: list[str],
|
|
224
|
+
) -> None:
|
|
225
|
+
"""Check that enabled reusable rule references resolve.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
cwd: Project directory whose configured rules should be checked.
|
|
229
|
+
codexmgr_home: codexmgr home used to resolve reusable rules.
|
|
230
|
+
report: Mutable diagnostic report receiving any error.
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
None.
|
|
234
|
+
"""
|
|
235
|
+
for rule in missing_enabled_rules(cwd, codexmgr_home):
|
|
236
|
+
report.append(f"ERROR Missing enabled rule: {rule}")
|
|
237
|
+
|
|
238
|
+
|
|
191
239
|
def _check_generated_files(
|
|
192
240
|
cwd: Path,
|
|
193
241
|
codex_home: Path,
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""CLI helpers for reusable rule management commands."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import TextIO
|
|
6
|
+
|
|
7
|
+
from ..core.paths import config_path
|
|
8
|
+
from ..core.toml_io import load_optional_toml_file, write_toml_file
|
|
9
|
+
from ..project.apply import apply_project_config
|
|
10
|
+
from ..project.config import require_codex_dir
|
|
11
|
+
from ..rules.config import set_rule_state_in_config
|
|
12
|
+
from ..rules.listing import rule_list_lines
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def run_rules_command(
|
|
16
|
+
args: argparse.Namespace,
|
|
17
|
+
cwd: Path,
|
|
18
|
+
codex_home: Path,
|
|
19
|
+
codexmgr_home: Path,
|
|
20
|
+
stdout: TextIO,
|
|
21
|
+
) -> int:
|
|
22
|
+
"""Run a parsed rules command.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
args: Parsed rules command namespace.
|
|
26
|
+
cwd: Project directory for project-local operations.
|
|
27
|
+
codex_home: Codex home used by apply.
|
|
28
|
+
codexmgr_home: Codexmgr home containing source rules.
|
|
29
|
+
stdout: Stream for command output.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
A process-style exit code.
|
|
33
|
+
"""
|
|
34
|
+
if args.rules_command == "list":
|
|
35
|
+
_write_optional_lines(stdout, rule_list_lines(cwd, codexmgr_home))
|
|
36
|
+
return 0
|
|
37
|
+
enabled = args.rules_command == "enable"
|
|
38
|
+
rules = _set_rule_many(args.rules, cwd, codexmgr_home, enabled=enabled)
|
|
39
|
+
verb = "Enabled" if enabled else "Disabled"
|
|
40
|
+
return _finish_config_change(
|
|
41
|
+
[f"{verb} {rule}" for rule in rules],
|
|
42
|
+
args.no_sync,
|
|
43
|
+
cwd,
|
|
44
|
+
codex_home,
|
|
45
|
+
codexmgr_home,
|
|
46
|
+
stdout,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _set_rule_many(
|
|
51
|
+
rules: list[str],
|
|
52
|
+
cwd: Path,
|
|
53
|
+
codexmgr_home: Path,
|
|
54
|
+
*,
|
|
55
|
+
enabled: bool,
|
|
56
|
+
) -> list[str]:
|
|
57
|
+
"""Set multiple rule states with one config write.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
rules: Rule refs to update.
|
|
61
|
+
cwd: Project directory whose codexmgr.toml should be updated.
|
|
62
|
+
codexmgr_home: Codexmgr home containing source rules.
|
|
63
|
+
enabled: Desired rule state.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Canonical rule refs that were updated.
|
|
67
|
+
"""
|
|
68
|
+
require_codex_dir(cwd)
|
|
69
|
+
config = load_optional_toml_file(config_path(cwd))
|
|
70
|
+
updated = [
|
|
71
|
+
set_rule_state_in_config(config, rule, codexmgr_home, enabled=enabled)
|
|
72
|
+
for rule in rules
|
|
73
|
+
]
|
|
74
|
+
write_toml_file(config_path(cwd), config)
|
|
75
|
+
return updated
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _finish_config_change(
|
|
79
|
+
messages: list[str],
|
|
80
|
+
no_sync: bool,
|
|
81
|
+
cwd: Path,
|
|
82
|
+
codex_home: Path,
|
|
83
|
+
codexmgr_home: Path,
|
|
84
|
+
stdout: TextIO,
|
|
85
|
+
) -> int:
|
|
86
|
+
"""Apply generated files after a rules mutation unless opted out.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
messages: Command-specific success messages.
|
|
90
|
+
no_sync: Whether to skip automatic apply.
|
|
91
|
+
cwd: Project directory whose configuration changed.
|
|
92
|
+
codex_home: Codex home for apply.
|
|
93
|
+
codexmgr_home: Codexmgr home for apply.
|
|
94
|
+
stdout: Stream for command output.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
Zero when mutation and optional apply succeed.
|
|
98
|
+
"""
|
|
99
|
+
output = list(messages)
|
|
100
|
+
if not no_sync:
|
|
101
|
+
apply_project_config(cwd, codex_home, codexmgr_home)
|
|
102
|
+
output.append("Applied project Codex configuration")
|
|
103
|
+
stdout.write("\n".join(output) + "\n")
|
|
104
|
+
return 0
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _write_optional_lines(stdout: TextIO, lines: list[str]) -> None:
|
|
108
|
+
"""Write lines only when present.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
stdout: Stream for command output.
|
|
112
|
+
lines: Lines to write.
|
|
113
|
+
"""
|
|
114
|
+
if lines:
|
|
115
|
+
stdout.write("\n".join(lines) + "\n")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Manage project-local Codex custom-agent files."""
|