dotagents-cli 0.6.0__tar.gz → 0.6.2__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.6.0 → dotagents_cli-0.6.2}/CHANGELOG.md +31 -1
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/PKG-INFO +2 -2
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/pyproject.toml +1 -1
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/__init__.py +1 -1
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/_hooks.py +13 -2
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/cli/__init__.py +9 -3
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/cli/build_pyz.py +1 -1
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/cli/env.py +9 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_fix_cli.py +7 -4
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_hooks.py +35 -0
- dotagents_cli-0.6.2/tests/test_mcp.py +60 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tools/pyz_smoke.sh +1 -1
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/.gitignore +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/LICENSE +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/README.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/api/agents.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/api/cli.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/api/commands.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/api/context.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/api/env.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/api/fs.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/api/hooks.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/api/merge.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/api/overlays.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/api/reference.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/api/resources.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/api/scope.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/api/skills.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/api/sources.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/api/wrappers.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/changelog.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/guide/authoring.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/guide/commands.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/guide/install.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/guide/overlays.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/guide/private-sync.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/docs/index.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/install.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/mkdocs.yml +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/AGENTS.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/__main__.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/_agents.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/_context.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/_env.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/_fs.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/_merge.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/_overlay/dotagents/cmds/findings.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/_overlay/dotagents/cmds/launch.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/_overlay/dotagents/hooks/preinvocation_antigravity_context.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/_overlay/dotagents/hooks/pretooluse_codex_env.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/_overlay/dotagents/hooks/sessionstart_codex_context.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/_overlay/dotagents/templates/AGENTS.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/_overlay/dotagents/templates/PROJECT.md +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/_overlays.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/_resources.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/_scope.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/_skills.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/_sources.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/_wrappers.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/cli/_common.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/cli/about.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/cli/context.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/cli/init.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/cli/overlays.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/cli/path.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/src/dotagents/py.typed +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/_helpers.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/_shell.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/conftest.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_about.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_agents.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_api_header.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_audit_leak.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_build_pyz.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_cli_main.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_cloud_setup.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_cmds_discovery.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_context.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_env.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_env_cli_scope.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_env_format.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_env_regressions.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_env_safety.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_findings_cmd.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_fix_adapters.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_fix_env.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_fix_hooks.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_fix_init.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_fix_overlays.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_fix_packaging.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_fix_scope_context.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_fix_skills_adapters.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_init_base.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_last_mile.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_launch_cmd.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_overlay_libs.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_overlays_cli.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_overlays_command.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_path_timeout_frontmatter.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_powershell_env_hook.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_review_security.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_scope.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_sources.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_sources_uri.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_wire_hooks.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tests/test_wrappers.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tools/audit.py +0 -0
- {dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/tools/cloud-setup.sh +0 -0
|
@@ -7,6 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.6.2] - 2026-09-28
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- With the `duho` floor bump, every `dotagents` invocation now checks
|
|
15
|
+
`DOTAGENTS_MCP=stdio` and serves its full command tree as an MCP server
|
|
16
|
+
over stdio when set. `env` opts itself out of that tool surface
|
|
17
|
+
(`_mcp_ = False`): its whole point is printing resolved, possibly secret
|
|
18
|
+
values, which should never be a callable MCP tool. Every other command is
|
|
19
|
+
unaffected, and `env` still works normally on the CLI.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- The `duho` floor moves to `>=0.6.0,<0.7` (from `>=0.5.0,<0.6`); the vendored
|
|
24
|
+
`.pyz` pin (`build-pyz --duho-version`) moves with it, per the repo's own
|
|
25
|
+
rule that the two must always agree. No other source change was needed.
|
|
26
|
+
|
|
27
|
+
## [0.6.1] - 2026-09-27
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- Re-running `init` after an upgrade from 0.5.x replaces the `CwdChanged` hooks
|
|
32
|
+
and Codex's `PreToolUse` hook that release wrote, instead of adding the new
|
|
33
|
+
ones beside them (every `cd` ran both, and the old one still wrote the
|
|
34
|
+
unquoted project path). A hook an earlier release wrote is recognised by its
|
|
35
|
+
label and a command that runs dotagents, reads `AGENTS.md` or
|
|
36
|
+
`AGENTS_PROJECT_ROOT`, or runs one of dotagents' hook scripts.
|
|
37
|
+
|
|
10
38
|
## [0.6.0] - 2026-09-25
|
|
11
39
|
|
|
12
40
|
### Added
|
|
@@ -1280,7 +1308,9 @@ Patch release: the PATH/POSIX-conversion fix above (the only change since 0.3.0)
|
|
|
1280
1308
|
affected module sources (`dotagents.cli`, `duho.presets`) to extracted temp files
|
|
1281
1309
|
before dispatch; a no-op for a plain install.
|
|
1282
1310
|
|
|
1283
|
-
[Unreleased]: https://github.com/jose-pr/dotagents/compare/v0.6.
|
|
1311
|
+
[Unreleased]: https://github.com/jose-pr/dotagents/compare/v0.6.2...HEAD
|
|
1312
|
+
[0.6.2]: https://github.com/jose-pr/dotagents/compare/v0.6.1...v0.6.2
|
|
1313
|
+
[0.6.1]: https://github.com/jose-pr/dotagents/compare/v0.6.0...v0.6.1
|
|
1284
1314
|
[0.6.0]: https://github.com/jose-pr/dotagents/compare/v0.5.1...v0.6.0
|
|
1285
1315
|
[0.5.1]: https://github.com/jose-pr/dotagents/compare/v0.5.0...v0.5.1
|
|
1286
1316
|
[0.5.0]: https://github.com/jose-pr/dotagents/compare/v0.4.0...v0.5.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: dotagents-cli
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.2
|
|
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.7,>=0.6.0
|
|
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.6.0,<0.7",
|
|
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"',
|
|
@@ -25,6 +25,7 @@ the ``.pyz``.
|
|
|
25
25
|
from __future__ import annotations
|
|
26
26
|
|
|
27
27
|
import json
|
|
28
|
+
import re
|
|
28
29
|
from pathlib import Path
|
|
29
30
|
from typing import Any, Optional
|
|
30
31
|
|
|
@@ -32,9 +33,19 @@ from typing import Any, Optional
|
|
|
32
33
|
#: Our hooks' statusMessage is `STATUS_PREFIX + label`, so a foreign hook that
|
|
33
34
|
#: happens to use the same generic label ("Loading agent context") is never
|
|
34
35
|
#: taken for ours. The bare label an earlier release wrote is still ours when
|
|
35
|
-
#: the hook's command
|
|
36
|
+
#: the hook's command is recognisably dotagents' (:data:`_LEGACY_COMMAND`), so
|
|
37
|
+
#: those hooks converge to the new one instead of running beside it.
|
|
36
38
|
STATUS_PREFIX = "dotagents: "
|
|
37
39
|
|
|
40
|
+
#: What every command an earlier release wrote contains: `dotagents` itself
|
|
41
|
+
#: (SessionStart, the PowerShell loader), the project pin or `AGENTS.md`
|
|
42
|
+
#: (CwdChanged, which never names dotagents), or one of the deployed hook
|
|
43
|
+
#: scripts (Codex, Antigravity: `python3 ".../pretooluse_codex_env.py"`).
|
|
44
|
+
_LEGACY_COMMAND = re.compile(
|
|
45
|
+
r"dotagents|AGENTS_PROJECT_ROOT|AGENTS\.md"
|
|
46
|
+
r"|(?:sessionstart_codex_context|pretooluse_codex_env|preinvocation_antigravity_context)\.py"
|
|
47
|
+
)
|
|
48
|
+
|
|
38
49
|
#: The hook keys dotagents manages; any other key a user added (a `timeout`,
|
|
39
50
|
#: say) survives a refresh.
|
|
40
51
|
_MANAGED_KEYS = frozenset({"type", "command", "shell", "commandWindows", "statusMessage"})
|
|
@@ -56,7 +67,7 @@ def _labelled_ours(hook: Any, status_message: "Optional[str]") -> bool:
|
|
|
56
67
|
status = hook.get("statusMessage")
|
|
57
68
|
if status == labels[0]:
|
|
58
69
|
return True
|
|
59
|
-
return status == labels[1] and
|
|
70
|
+
return status == labels[1] and bool(_LEGACY_COMMAND.search(str(hook.get("command", ""))))
|
|
60
71
|
|
|
61
72
|
|
|
62
73
|
def build_hook_entry(
|
|
@@ -217,9 +217,15 @@ def _discover_modules(directory: Path) -> "list":
|
|
|
217
217
|
not an Exception. A command that imports but cannot build its parser is
|
|
218
218
|
skipped the same way (`_buildable`). Falls back to duho's own
|
|
219
219
|
per-directory unit, with a warning, if a duho release moves these
|
|
220
|
-
helpers.
|
|
220
|
+
helpers.
|
|
221
|
+
|
|
222
|
+
Uses duho's PUBLIC `import_from_path` (duho >= 0.6.0) for the file
|
|
223
|
+
import; `_commands_in_module` has no public counterpart yet, so it stays
|
|
224
|
+
a private import (see `duho.discovery.import_from_path`'s own docstring:
|
|
225
|
+
it is the public counterpart of the `_unique_module_name` +
|
|
226
|
+
`_import_from_path` pair this module used to call directly)."""
|
|
221
227
|
try:
|
|
222
|
-
from duho.discovery import _commands_in_module,
|
|
228
|
+
from duho.discovery import _commands_in_module, import_from_path
|
|
223
229
|
except ImportError: # pragma: no cover -- a later duho without these internals
|
|
224
230
|
from duho.discovery import discover_commands
|
|
225
231
|
|
|
@@ -234,7 +240,7 @@ def _discover_modules(directory: Path) -> "list":
|
|
|
234
240
|
if file.name.startswith("_"):
|
|
235
241
|
continue
|
|
236
242
|
try:
|
|
237
|
-
module =
|
|
243
|
+
module = import_from_path("duho._discovered." + file.stem, file)
|
|
238
244
|
found = _commands_in_module(module, stem=file.stem)
|
|
239
245
|
except (Exception, SystemExit) as exc: # noqa: BLE001 -- see docstring
|
|
240
246
|
_LOGGER.warning("skipping command module %s: %s", file, _describe(exc))
|
|
@@ -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.6.0"
|
|
77
77
|
"Pinned duho version to vendor."
|
|
78
78
|
("--duho-version",)
|
|
79
79
|
|
|
@@ -539,6 +539,15 @@ class Env(DotAgentsArgs):
|
|
|
539
539
|
|
|
540
540
|
_parsername_ = "env"
|
|
541
541
|
|
|
542
|
+
# Opt out of the MCP tool surface (duho >= 0.6.0): this command's whole
|
|
543
|
+
# point is to print resolved, possibly secret values (see the class
|
|
544
|
+
# docstring's "Output is sensitive" note) -- exactly what an MCP client
|
|
545
|
+
# should never be handed as a callable tool. `_mcp_ = False` on a
|
|
546
|
+
# non-root command class hides it (and any subtree) from `tools/list`
|
|
547
|
+
# and refuses `tools/call` the same way an unknown name would; the CLI
|
|
548
|
+
# itself is unaffected.
|
|
549
|
+
_mcp_ = False
|
|
550
|
+
|
|
542
551
|
format: str = "auto"
|
|
543
552
|
(
|
|
544
553
|
"Output format. Default 'auto' detects the calling shell. Shell forms: "
|
|
@@ -220,10 +220,13 @@ def test_moved_duho_internals_are_reported_not_silent(monkeypatch, tmp_path, cap
|
|
|
220
220
|
real_import = builtins.__import__
|
|
221
221
|
|
|
222
222
|
def renamed(name, globals=None, locals=None, fromlist=(), level=0):
|
|
223
|
-
# What a duho release that renamed its private
|
|
224
|
-
# `from duho.discovery import
|
|
225
|
-
|
|
226
|
-
|
|
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'")
|
|
227
230
|
return real_import(name, globals, locals, fromlist, level)
|
|
228
231
|
|
|
229
232
|
monkeypatch.setattr(builtins, "__import__", renamed)
|
|
@@ -191,3 +191,38 @@ def test_status_match_does_not_touch_a_foreign_hook():
|
|
|
191
191
|
commands = [h["command"] for e in merged for h in e["hooks"]]
|
|
192
192
|
assert "mine" in commands
|
|
193
193
|
assert CMD in commands
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
# The exact commands 0.5.x wrote. CwdChanged never named dotagents, and the
|
|
197
|
+
# Codex loader names only its script, so recognising a legacy hook by
|
|
198
|
+
# "dotagents" in its command left them in place beside the new ones.
|
|
199
|
+
_CWD_051 = (
|
|
200
|
+
'if [ -n "$CLAUDE_ENV_FILE" ] && [ -d .agents ]; then printf "export '
|
|
201
|
+
"AGENTS_PROJECT_ROOT='%s'\\n\" \"$(pwd -W 2>/dev/null || pwd)\" >> \"$CLAUDE_ENV_FILE\"; "
|
|
202
|
+
'fi; [ -f AGENTS.md ] && cat AGENTS.md || true'
|
|
203
|
+
)
|
|
204
|
+
_CWD_051_PS = (
|
|
205
|
+
"if (-not (Get-Command bash -ErrorAction SilentlyContinue)) { if (Test-Path AGENTS.md) "
|
|
206
|
+
"{ Get-Content AGENTS.md -Raw } }"
|
|
207
|
+
)
|
|
208
|
+
_CODEX_051 = 'python3 "/home/u/.codex/hooks/pretooluse_codex_env.py"'
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
@pytest.mark.parametrize("old, label", [
|
|
212
|
+
(_CWD_051, "Checking for AGENTS.md"),
|
|
213
|
+
(_CWD_051_PS, "Checking for AGENTS.md (PowerShell)"),
|
|
214
|
+
(_CODEX_051, "Loading agent env"),
|
|
215
|
+
])
|
|
216
|
+
def test_every_hook_an_earlier_release_wrote_converges(old, label):
|
|
217
|
+
legacy = {"hooks": [{"type": "command", "command": old, "statusMessage": label}]}
|
|
218
|
+
merged, changed = _hooks.merge_hook([legacy], "NEW", status_message=label)
|
|
219
|
+
assert changed and len(merged) == 1, merged
|
|
220
|
+
assert merged[0]["hooks"][0]["command"] == "NEW"
|
|
221
|
+
assert merged[0]["hooks"][0]["statusMessage"] == "dotagents: " + label
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def test_a_foreign_hook_with_our_bare_label_and_unrelated_command_stays():
|
|
225
|
+
foreign = {"hooks": [{"type": "command", "command": "notify-send hi",
|
|
226
|
+
"statusMessage": "Checking for AGENTS.md"}]}
|
|
227
|
+
merged, _ = _hooks.merge_hook([foreign], "NEW", status_message="Checking for AGENTS.md")
|
|
228
|
+
assert merged[0] == foreign and len(merged) == 2
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""`env`'s MCP opt-out (duho >= 0.6.0).
|
|
2
|
+
|
|
3
|
+
`env` prints resolved, possibly secret values (its own docstring's "Output is
|
|
4
|
+
sensitive" note) -- exactly what an MCP client should never be handed as a
|
|
5
|
+
callable tool. It is a compiled, module-level command CLASS (`Env`, one of
|
|
6
|
+
`dotagents.cli._BUILTIN_COMMANDS`, dispatched via `duho.app`'s `commands=`),
|
|
7
|
+
not a discovered `.py` module command, so the opt-out is the class-attribute
|
|
8
|
+
form: `_mcp_ = False` set directly on `Env` (`dotagents/cli/env.py`) -- NOT a
|
|
9
|
+
module-level `_mcp_ = False` in a `cmds/` file, which is the form for a
|
|
10
|
+
discovered module command instead.
|
|
11
|
+
|
|
12
|
+
`test_env_command_is_hidden_from_mcp_tools` drives a REAL
|
|
13
|
+
`DOTAGENTS_MCP=stdio` session (the env-var trigger duho.app checks before
|
|
14
|
+
parsing argv) in a subprocess, under the suite's autouse isolated
|
|
15
|
+
HOME/AGENTS_* (tests/conftest.py) -- never the real `~/.agents`. It asserts
|
|
16
|
+
`dotagents.env` is absent from `tools/list` while `dotagents.about` (an
|
|
17
|
+
ordinary built-in) is still present, then that `env` still works as a normal
|
|
18
|
+
CLI command -- the opt-out only removes it from the MCP surface.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
import json
|
|
22
|
+
import os
|
|
23
|
+
import subprocess
|
|
24
|
+
import sys
|
|
25
|
+
|
|
26
|
+
from dotagents.cli.env import Env
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_env_command_is_hidden_from_mcp_tools():
|
|
30
|
+
request = json.dumps({"jsonrpc": "2.0", "id": 1, "method": "tools/list"})
|
|
31
|
+
env = dict(os.environ)
|
|
32
|
+
env["DOTAGENTS_MCP"] = "stdio"
|
|
33
|
+
|
|
34
|
+
proc = subprocess.run(
|
|
35
|
+
[sys.executable, "-m", "dotagents"],
|
|
36
|
+
input=request + "\n",
|
|
37
|
+
capture_output=True,
|
|
38
|
+
text=True,
|
|
39
|
+
env=env,
|
|
40
|
+
timeout=30,
|
|
41
|
+
)
|
|
42
|
+
assert proc.returncode == 0, proc.stderr
|
|
43
|
+
|
|
44
|
+
lines = [line for line in proc.stdout.splitlines() if line.strip()]
|
|
45
|
+
assert len(lines) == 1, proc.stdout
|
|
46
|
+
response = json.loads(lines[0])
|
|
47
|
+
names = {tool["name"] for tool in response["result"]["tools"]}
|
|
48
|
+
|
|
49
|
+
assert "dotagents.about" in names, names
|
|
50
|
+
assert "dotagents.env" not in names, names
|
|
51
|
+
assert not any(name.startswith("dotagents.env.") for name in names), names
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_env_still_works_on_the_cli(capsys):
|
|
55
|
+
"""The MCP opt-out is MCP-only: `env` dispatches normally on the CLI."""
|
|
56
|
+
command = Env()
|
|
57
|
+
command.format = "json"
|
|
58
|
+
|
|
59
|
+
assert command() == 0
|
|
60
|
+
assert isinstance(json.loads(capsys.readouterr().out), dict)
|
|
@@ -76,7 +76,7 @@ has_re "$h" "$(flag --agents)"
|
|
|
76
76
|
# modules, findings and launch. Matched on the command-list line, since
|
|
77
77
|
# `overlays`' own description mentions its `sync` subcommand.
|
|
78
78
|
h=$(pyz --help)
|
|
79
|
-
has "$h" "{
|
|
79
|
+
has "$h" "{about,build-pyz,context,env,findings,init,launch,overlays,path}"
|
|
80
80
|
lacks "$h" "link-project"
|
|
81
81
|
lacks "$h" "sync-project"
|
|
82
82
|
lacks "$h" "audit"
|
|
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.6.0 → dotagents_cli-0.6.2}/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.6.0 → dotagents_cli-0.6.2}/src/dotagents/_overlay/dotagents/templates/AGENTS.md
RENAMED
|
File without changes
|
{dotagents_cli-0.6.0 → dotagents_cli-0.6.2}/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
|