dotagents-cli 0.7.4__tar.gz → 0.7.5__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.
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/CHANGELOG.md +26 -1
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/PKG-INFO +2 -2
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/pyproject.toml +1 -1
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/AGENTS.md +5 -1
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/__init__.py +1 -1
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/cli/__init__.py +26 -65
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/cli/build_pyz.py +1 -1
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_cli_main.py +1 -1
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_cmds_discovery.py +15 -2
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_fix_cli.py +0 -25
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_fix_init.py +3 -4
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/.gitignore +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/LICENSE +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/README.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/api/agents.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/api/cli.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/api/commands.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/api/context.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/api/env.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/api/fs.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/api/hooks.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/api/merge.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/api/overlays.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/api/reference.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/api/resources.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/api/scope.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/api/skills.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/api/sources.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/api/wrappers.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/changelog.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/guide/authoring.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/guide/commands.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/guide/install.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/guide/overlays.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/guide/private-sync.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/docs/index.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/install.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/mkdocs.yml +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/__main__.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_agents.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_context.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_env.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_fs.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_hooks.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_ignore.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_merge.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_overlay/dotagents/cmds/findings.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_overlay/dotagents/cmds/launch.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_overlay/dotagents/hooks/preinvocation_antigravity_context.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_overlay/dotagents/hooks/pretooluse_codex_env.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_overlay/dotagents/hooks/sessionstart_codex_context.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_overlay/dotagents/templates/AGENTS.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_overlay/dotagents/templates/PROJECT.md +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_overlays.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_resources.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_scope.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_skills.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_sources.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_wrappers.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/cli/_common.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/cli/about.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/cli/context.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/cli/env.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/cli/init.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/cli/overlays.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/cli/path.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/py.typed +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/_helpers.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/_shell.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/conftest.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_about.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_agents.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_api_header.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_audit_leak.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_build_pyz.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_cloud_setup.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_context.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_env.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_env_cli_scope.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_env_format.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_env_into.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_env_regressions.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_env_safety.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_findings_cmd.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_fix_adapters.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_fix_env.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_fix_hooks.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_fix_overlays.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_fix_packaging.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_fix_scope_context.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_fix_skills_adapters.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_git_ssl_revoke.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_hooks.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_ignore.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_init_base.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_last_mile.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_launch_cmd.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_local_additions.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_mcp.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_no_internal_labels.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_overlay_libs.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_overlays_cli.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_overlays_command.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_path_timeout_frontmatter.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_powershell_env_hook.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_quoting_injection_safety.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_scope.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_sources.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_sources_uri.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_wire_hooks.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tests/test_wrappers.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tools/audit.py +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tools/cloud-setup.sh +0 -0
- {dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/tools/pyz_smoke.sh +0 -0
|
@@ -7,6 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.7.5] - 2026-10-14
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- `main()` runs through `duho.run(..., exit=False)`: it always returns the status
|
|
15
|
+
instead of raising `SystemExit` for a message, `--help` or a usage error (the
|
|
16
|
+
console script, `python -m dotagents` and `install.py` exit with it as before, with
|
|
17
|
+
the same statuses and the same text on standard error). Ctrl-C now ends with
|
|
18
|
+
status 130 and no traceback, and a closed pipe on standard output ends with
|
|
19
|
+
status 1, quietly.
|
|
20
|
+
- The `duho` floor moves to `>=0.7.5,<0.8` (from `>=0.6.0,<0.7`); the vendored
|
|
21
|
+
`.pyz` pin (`build-pyz --duho-version`) moves with it. No flag, exit status or
|
|
22
|
+
output changes.
|
|
23
|
+
- Command modules are loaded with duho's own `discover_commands(on_error=...)`
|
|
24
|
+
instead of a copy of its loop built on a private duho name. A module that fails
|
|
25
|
+
to import is still named in a warning and skipped, and the listing order is
|
|
26
|
+
unchanged. A command module may now import a sibling helper file by its bare
|
|
27
|
+
name.
|
|
28
|
+
- `kebab_name` delegates to `duho.text.kebabcase`; its results are unchanged.
|
|
29
|
+
- Discovered commands are listed in discovery order with `discover_commands(sort=False)`
|
|
30
|
+
instead of being re-sorted here, and a command that cannot build its parser is
|
|
31
|
+
found out with `duho.runtime.build_command_parser` instead of a private duho
|
|
32
|
+
helper. Output, exit statuses and which commands are skipped are unchanged.
|
|
33
|
+
|
|
10
34
|
## [0.7.4] - 2026-10-14
|
|
11
35
|
|
|
12
36
|
### Added
|
|
@@ -1417,7 +1441,8 @@ Patch release: the PATH/POSIX-conversion fix above (the only change since 0.3.0)
|
|
|
1417
1441
|
affected module sources (`dotagents.cli`, `duho.presets`) to extracted temp files
|
|
1418
1442
|
before dispatch; a no-op for a plain install.
|
|
1419
1443
|
|
|
1420
|
-
[Unreleased]: https://github.com/jose-pr/dotagents/compare/v0.7.
|
|
1444
|
+
[Unreleased]: https://github.com/jose-pr/dotagents/compare/v0.7.5...HEAD
|
|
1445
|
+
[0.7.5]: https://github.com/jose-pr/dotagents/compare/v0.7.4...v0.7.5
|
|
1421
1446
|
[0.7.4]: https://github.com/jose-pr/dotagents/compare/v0.7.3...v0.7.4
|
|
1422
1447
|
[0.7.3]: https://github.com/jose-pr/dotagents/compare/v0.7.2...v0.7.3
|
|
1423
1448
|
[0.7.2]: https://github.com/jose-pr/dotagents/compare/v0.7.1...v0.7.2
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: dotagents-cli
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.5
|
|
4
4
|
Summary: The dotagents CLI: install and manage a portable ~/.agents config for AI coding agents
|
|
5
5
|
Project-URL: Homepage, https://github.com/jose-pr/dotagents/
|
|
6
6
|
Project-URL: Repository, https://github.com/jose-pr/dotagents
|
|
@@ -23,7 +23,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
23
23
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
24
|
Classifier: Typing :: Typed
|
|
25
25
|
Requires-Python: >=3.9
|
|
26
|
-
Requires-Dist: duho<0.
|
|
26
|
+
Requires-Dist: duho<0.8,>=0.7.5
|
|
27
27
|
Requires-Dist: pathlib-next<0.10,>=0.9.0
|
|
28
28
|
Requires-Dist: tomli>=1.1.0; python_version < '3.11'
|
|
29
29
|
Provides-Extra: dev
|
|
@@ -35,7 +35,7 @@ classifiers = [
|
|
|
35
35
|
# `build-pyz` vendors the floor of each of these (src/dotagents/cli/build_pyz.py);
|
|
36
36
|
# raise a floor and move its pin there in the same change.
|
|
37
37
|
dependencies = [
|
|
38
|
-
"duho>=0.
|
|
38
|
+
"duho>=0.7.5,<0.8",
|
|
39
39
|
"pathlib_next>=0.9.0,<0.10",
|
|
40
40
|
# overlay.toml manifests and TOML registries; tomllib is stdlib from 3.11.
|
|
41
41
|
'tomli>=1.1.0; python_version < "3.11"',
|
|
@@ -74,7 +74,11 @@ are skipped.
|
|
|
74
74
|
## `dotagents.cli`
|
|
75
75
|
|
|
76
76
|
- `main(argv=None) -> int` — the entry point (`dotagents` console script,
|
|
77
|
-
`python -m dotagents`, `install.py`).
|
|
77
|
+
`python -m dotagents`, `install.py`). It always returns the status and never
|
|
78
|
+
raises `SystemExit`: a `SystemExit` raised below it (a message, `--help`, a usage
|
|
79
|
+
error) comes back as its status, the message going to standard error. Ctrl-C
|
|
80
|
+
returns 130 and a closed pipe on standard output returns 1, both without a
|
|
81
|
+
traceback.
|
|
78
82
|
- `class Dotagents(LoggingArgs, Cli)` — the umbrella; field `cmdspath: list[str]`.
|
|
79
83
|
- `CMDS_PATH_ENV = "AGENTS_CMDS_PATH"`.
|
|
80
84
|
- Re-exported for command modules: `DotAgentsArgs`, `_write_stdout` (see below).
|
|
@@ -30,6 +30,8 @@ from pathlib import Path
|
|
|
30
30
|
|
|
31
31
|
import duho
|
|
32
32
|
from duho import Cli, LoggingArgs
|
|
33
|
+
from duho.runtime import build_command_parser
|
|
34
|
+
from duho.text import kebabcase
|
|
33
35
|
|
|
34
36
|
from dotagents import __version__
|
|
35
37
|
|
|
@@ -164,18 +166,7 @@ def _check_buildable(command) -> None:
|
|
|
164
166
|
fields claiming the same flag, a flag the umbrella already owns) would
|
|
165
167
|
otherwise fail every invocation. The parents are the umbrella's options,
|
|
166
168
|
as in `duho.app`, so a clash with them surfaces here too."""
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
base = Dotagents._parser_(add_help=False)
|
|
170
|
-
subparsers = argparse.ArgumentParser(add_help=False).add_subparsers()
|
|
171
|
-
if isinstance(command, type):
|
|
172
|
-
command._parser_(subparsers, parents=[base])
|
|
173
|
-
return
|
|
174
|
-
try:
|
|
175
|
-
from duho.runtime import _register_module_command
|
|
176
|
-
except ImportError: # pragma: no cover -- a later duho without this helper
|
|
177
|
-
return
|
|
178
|
-
_register_module_command(subparsers, command, base, None, Dotagents)
|
|
169
|
+
build_command_parser(command, Dotagents)
|
|
179
170
|
|
|
180
171
|
|
|
181
172
|
def _source_of(command) -> str:
|
|
@@ -207,18 +198,14 @@ def _buildable(commands, file=None) -> "list":
|
|
|
207
198
|
def kebab_name(class_name: str) -> str:
|
|
208
199
|
"""A command class's default subcommand name: ``LeakCheck`` ->
|
|
209
200
|
``leak-check``, ``HTTPServer`` -> ``http-server``, ``my_cmd`` -> ``my-cmd``."""
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
spaced = re.sub(r"(?<=[a-z0-9])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])", "-", class_name)
|
|
213
|
-
return re.sub(r"[-_]+", "-", spaced).strip("-").lower()
|
|
201
|
+
return kebabcase(class_name)
|
|
214
202
|
|
|
215
203
|
|
|
216
204
|
def _named(commands) -> "list":
|
|
217
205
|
"""``commands``, each discovered class that declares no ``_parsername_``
|
|
218
|
-
of its own given the kebab-case of its class name (:func:`kebab_name`)
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
which broke ``dotagents leak-check`` for a module that relied on it."""
|
|
206
|
+
of its own given the kebab-case of its class name (:func:`kebab_name`),
|
|
207
|
+
which is also the name duho gives it. Setting it makes the name readable as
|
|
208
|
+
an attribute, which the command-set keys and the tests rely on."""
|
|
222
209
|
for command in commands:
|
|
223
210
|
if isinstance(command, type) and "_parsername_" not in vars(command):
|
|
224
211
|
command._parsername_ = kebab_name(command.__name__)
|
|
@@ -228,46 +215,19 @@ def _named(commands) -> "list":
|
|
|
228
215
|
def _discover_modules(directory: Path) -> "list":
|
|
229
216
|
"""duho's per-directory discovery, made resilient per MODULE.
|
|
230
217
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
one
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
import; `_commands_in_module` has no public counterpart yet, so it stays
|
|
245
|
-
a private import (see `duho.discovery.import_from_path`'s own docstring:
|
|
246
|
-
it is the public counterpart of the `_unique_module_name` +
|
|
247
|
-
`_import_from_path` pair this module used to call directly)."""
|
|
248
|
-
try:
|
|
249
|
-
from duho.discovery import _commands_in_module, import_from_path
|
|
250
|
-
except ImportError: # pragma: no cover -- a later duho without these internals
|
|
251
|
-
from duho.discovery import discover_commands
|
|
252
|
-
|
|
253
|
-
_LOGGER.warning(
|
|
254
|
-
"duho's discovery internals moved; a broken module in %s now skips "
|
|
255
|
-
"the whole directory, not just itself",
|
|
256
|
-
directory,
|
|
257
|
-
)
|
|
258
|
-
return _named(_buildable(discover_commands(directory)))
|
|
259
|
-
commands = []
|
|
260
|
-
for file in sorted(directory.glob("*.py")):
|
|
261
|
-
if file.name.startswith("_"):
|
|
262
|
-
continue
|
|
263
|
-
try:
|
|
264
|
-
module = import_from_path("duho._discovered." + file.stem, file)
|
|
265
|
-
found = _commands_in_module(module, stem=file.stem)
|
|
266
|
-
except (Exception, SystemExit) as exc: # noqa: BLE001 -- see docstring
|
|
267
|
-
_LOGGER.warning("skipping command module %s: %s", file, _describe(exc))
|
|
268
|
-
continue
|
|
269
|
-
commands.extend(_named(_buildable(found, file)))
|
|
270
|
-
return commands
|
|
218
|
+
Discovery runs before EVERY dotagents invocation (including `env`/`context`
|
|
219
|
+
inside the SessionStart hooks), so one broken user module must not take
|
|
220
|
+
down every command. `on_error` is called for any exception raised importing
|
|
221
|
+
one file, `SystemExit` included (a module that `sys.exit()`s at import is
|
|
222
|
+
not an Exception): the bad module is named, with its exception, and skipped;
|
|
223
|
+
the rest of the directory still loads. A command that imports but cannot
|
|
224
|
+
build its parser is skipped the same way (`_buildable`)."""
|
|
225
|
+
|
|
226
|
+
def skip(source, exc) -> None:
|
|
227
|
+
_LOGGER.warning("skipping command module %s: %s", source, _describe(exc))
|
|
228
|
+
|
|
229
|
+
found = duho.discover_commands(directory, on_error=skip, sort=False)
|
|
230
|
+
return _named(_buildable(found))
|
|
271
231
|
|
|
272
232
|
|
|
273
233
|
def _discover_dir(source, by_name: dict) -> None:
|
|
@@ -522,13 +482,14 @@ def _repoint_zipapp_sources() -> None:
|
|
|
522
482
|
|
|
523
483
|
def main(argv=None) -> int:
|
|
524
484
|
_repoint_zipapp_sources()
|
|
525
|
-
# `duho.app` (not `duho.main`) so
|
|
526
|
-
#
|
|
527
|
-
#
|
|
528
|
-
return duho.
|
|
485
|
+
# `commands=` makes `run` use `duho.app` (not `duho.main`) so the resolved
|
|
486
|
+
# built-ins + discovered set are the commands; dispatch calls each command's
|
|
487
|
+
# `__call__`. `exit=False` returns the status, whatever ended the run.
|
|
488
|
+
return duho.run(
|
|
529
489
|
Dotagents,
|
|
490
|
+
argv,
|
|
491
|
+
exit=False,
|
|
530
492
|
commands=_discover(argv),
|
|
531
|
-
argv=argv,
|
|
532
493
|
name="dotagents",
|
|
533
494
|
)
|
|
534
495
|
|
|
@@ -73,7 +73,7 @@ class BuildPyz(LoggingArgs, Cmd):
|
|
|
73
73
|
# stale pin here ships an artifact `pip install dotagents-cli` would refuse.
|
|
74
74
|
# Pin the FLOOR of each declared range, not the latest patch -- the .pyz then
|
|
75
75
|
# exercises the minimum the metadata promises.
|
|
76
|
-
duho_version: str = "0.
|
|
76
|
+
duho_version: str = "0.7.5"
|
|
77
77
|
"Pinned duho version to vendor."
|
|
78
78
|
("--duho-version",)
|
|
79
79
|
|
|
@@ -130,7 +130,7 @@ def test_reinit_after_overlays_add_keeps_the_overlay_routing(tmp_path):
|
|
|
130
130
|
|
|
131
131
|
|
|
132
132
|
def test_init_with_an_unknown_agent_is_a_usage_error(tmp_path):
|
|
133
|
-
assert _main(["init", "--dest", str(tmp_path / "s"), "--agents", "claud", "--no-hooks"]) ==
|
|
133
|
+
assert _main(["init", "--dest", str(tmp_path / "s"), "--agents", "claud", "--no-hooks"]) == 1
|
|
134
134
|
|
|
135
135
|
|
|
136
136
|
# --------------------------------------------------------------------------
|
|
@@ -224,8 +224,7 @@ class LeakCheck(LoggingArgs, Cmd):
|
|
|
224
224
|
|
|
225
225
|
|
|
226
226
|
def test_a_command_without_parsername_gets_its_kebab_class_name(monkeypatch, tmp_path, capsys):
|
|
227
|
-
"""`_parsername_` is optional:
|
|
228
|
-
dotagents gives it `leak-check` (what duho < 0.6 derived)."""
|
|
227
|
+
"""`_parsername_` is optional: such a class is named `leak-check`."""
|
|
229
228
|
cmds = tmp_path / "extra"
|
|
230
229
|
_write(cmds / "leak_check.py", UNNAMED)
|
|
231
230
|
_write(cmds / "toy.py", TOY)
|
|
@@ -436,3 +435,17 @@ def test_a_module_failing_at_parser_build_does_not_take_the_cli_down(monkeypatch
|
|
|
436
435
|
except SystemExit as exc:
|
|
437
436
|
rc = exc.code
|
|
438
437
|
assert rc == 0
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def test_a_directory_lists_its_commands_by_file_then_definition_order(tmp_path):
|
|
441
|
+
"""The `--help` listing follows the files, not the subcommand names."""
|
|
442
|
+
template = (
|
|
443
|
+
"from duho import Cmd, LoggingArgs\n\n"
|
|
444
|
+
"class {a}(LoggingArgs, Cmd):\n _parsername_ = '{a}'\n\n"
|
|
445
|
+
" def __call__(self) -> int:\n return 0\n\n"
|
|
446
|
+
"class {b}(LoggingArgs, Cmd):\n _parsername_ = '{b}'\n\n"
|
|
447
|
+
" def __call__(self) -> int:\n return 0\n"
|
|
448
|
+
)
|
|
449
|
+
_write(tmp_path / "aa_first.py", template.format(a="zulu", b="alpha"))
|
|
450
|
+
_write(tmp_path / "bb_second.py", template.format(a="mike", b="bravo"))
|
|
451
|
+
assert _names(cli._discover_modules(tmp_path)) == ["zulu", "alpha", "mike", "bravo"]
|
|
@@ -211,31 +211,6 @@ def test_a_command_clashing_with_an_umbrella_flag_is_skipped(monkeypatch, tmp_pa
|
|
|
211
211
|
assert cli.main(["about"]) == 0
|
|
212
212
|
|
|
213
213
|
|
|
214
|
-
def test_moved_duho_internals_are_reported_not_silent(monkeypatch, tmp_path, caplog):
|
|
215
|
-
import builtins
|
|
216
|
-
|
|
217
|
-
cmds = tmp_path / "cmds"
|
|
218
|
-
cmds.mkdir()
|
|
219
|
-
(cmds / "good.py").write_text(GOOD, encoding="utf-8")
|
|
220
|
-
real_import = builtins.__import__
|
|
221
|
-
|
|
222
|
-
def renamed(name, globals=None, locals=None, fromlist=(), level=0):
|
|
223
|
-
# What a duho release that renamed its remaining private helper looks
|
|
224
|
-
# like to `from duho.discovery import _commands_in_module, ...` --
|
|
225
|
-
# and only to it. `import_from_path` is duho's public counterpart
|
|
226
|
-
# (duho >= 0.6.0) and stays importable; `_commands_in_module` has no
|
|
227
|
-
# public counterpart yet, so it is the one still exposed to this risk.
|
|
228
|
-
if name == "duho.discovery" and "_commands_in_module" in (fromlist or ()):
|
|
229
|
-
raise ImportError("cannot import name '_commands_in_module'")
|
|
230
|
-
return real_import(name, globals, locals, fromlist, level)
|
|
231
|
-
|
|
232
|
-
monkeypatch.setattr(builtins, "__import__", renamed)
|
|
233
|
-
with caplog.at_level(logging.WARNING):
|
|
234
|
-
commands = cli._discover_modules(cmds)
|
|
235
|
-
assert "good" in _names(commands)
|
|
236
|
-
assert any("internals moved" in r.getMessage() for r in caplog.records)
|
|
237
|
-
|
|
238
|
-
|
|
239
214
|
# --------------------------------------------------------------------------- #
|
|
240
215
|
# The zipapp-repointed module list is derived, not hand-kept
|
|
241
216
|
# --------------------------------------------------------------------------- #
|
|
@@ -246,16 +246,15 @@ def test_a_bom_in_settings_json_is_accepted_and_not_written_back(tmp_path):
|
|
|
246
246
|
|
|
247
247
|
|
|
248
248
|
@pytest.mark.parametrize("content", [b"{not json", b"\xff\xfe{}"])
|
|
249
|
-
def test_a_corrupt_settings_file_stops_init_before_anything_is_written(content):
|
|
249
|
+
def test_a_corrupt_settings_file_stops_init_before_anything_is_written(content, capsys):
|
|
250
250
|
"""The error fired after AGENTS.md and the CLAUDE.md include were written,
|
|
251
251
|
leaving a half-initialised store."""
|
|
252
252
|
settings = Path.home() / ".claude" / "settings.json"
|
|
253
253
|
settings.parent.mkdir(parents=True)
|
|
254
254
|
settings.write_bytes(content)
|
|
255
255
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
assert str(settings) in str(exc.value)
|
|
256
|
+
assert cli.main(["init", "-g", "--agents", "claude"]) == 1
|
|
257
|
+
assert str(settings) in capsys.readouterr().err
|
|
259
258
|
assert not (Path.home() / ".agents").exists()
|
|
260
259
|
assert not (Path.home() / ".claude" / "CLAUDE.md").exists()
|
|
261
260
|
assert settings.read_bytes() == content
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_overlay/dotagents/cmds/findings.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_overlay/dotagents/templates/AGENTS.md
RENAMED
|
File without changes
|
{dotagents_cli-0.7.4 → dotagents_cli-0.7.5}/src/dotagents/_overlay/dotagents/templates/PROJECT.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|