apcore-cli 0.7.0__tar.gz → 0.8.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.
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/CHANGELOG.md +202 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/PKG-INFO +61 -20
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/README.md +58 -17
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/examples/README.md +38 -54
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/pyproject.toml +3 -3
- apcore_cli-0.8.0/src/apcore_cli/__init__.py +196 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/__main__.py +6 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/builtin_group.py +101 -12
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/cli.py +38 -8
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/config.py +31 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/discovery.py +31 -8
- apcore_cli-0.8.0/src/apcore_cli/exit_codes.py +76 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/factory.py +77 -105
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/output.py +52 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/ref_resolver.py +18 -2
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/schema_parser.py +9 -3
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/security/audit.py +10 -2
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/security/config_encryptor.py +23 -9
- apcore_cli-0.8.0/src/apcore_cli/security/sandbox.py +271 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/strategy.py +6 -1
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/system_cmd.py +52 -25
- apcore_cli-0.8.0/src/apcore_cli/system_usage.py +167 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_apcli_integration.py +18 -21
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_approval.py +21 -11
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_bugfixes.py +1 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_builtin_group.py +87 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_cli.py +87 -5
- apcore_cli-0.8.0/tests/test_exit_codes.py +58 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_factory_fe13.py +43 -22
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_integration.py +5 -3
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_list_command_filters.py +14 -5
- apcore_cli-0.8.0/tests/test_output_format_markdown_skill.py +126 -0
- apcore_cli-0.8.0/tests/test_public_api.py +92 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_ref_resolver.py +58 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_schema_parser.py +8 -5
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_security/test_audit.py +63 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_security/test_config_encryptor.py +26 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_security/test_sandbox.py +132 -45
- apcore_cli-0.8.0/tests/test_system_usage.py +257 -0
- apcore_cli-0.8.0/tests/test_validate.py +227 -0
- apcore_cli-0.7.0/commands/ops.py +0 -4
- apcore_cli-0.7.0/htmlcov/.gitignore +0 -2
- apcore_cli-0.7.0/htmlcov/class_index.html +0 -551
- apcore_cli-0.7.0/htmlcov/coverage_html_cb_bcae5fc4.js +0 -735
- apcore_cli-0.7.0/htmlcov/favicon_32_cb_58284776.png +0 -0
- apcore_cli-0.7.0/htmlcov/function_index.html +0 -1931
- apcore_cli-0.7.0/htmlcov/index.html +0 -306
- apcore_cli-0.7.0/htmlcov/keybd_closed_cb_ce680311.png +0 -0
- apcore_cli-0.7.0/htmlcov/status.json +0 -1
- apcore_cli-0.7.0/htmlcov/style_cb_a5a05ca4.css +0 -389
- apcore_cli-0.7.0/htmlcov/z_2a36de3398a45e2f___init___py.html +0 -105
- apcore_cli-0.7.0/htmlcov/z_2a36de3398a45e2f_audit_py.html +0 -169
- apcore_cli-0.7.0/htmlcov/z_2a36de3398a45e2f_auth_py.html +0 -171
- apcore_cli-0.7.0/htmlcov/z_2a36de3398a45e2f_config_encryptor_py.html +0 -249
- apcore_cli-0.7.0/htmlcov/z_2a36de3398a45e2f_sandbox_py.html +0 -241
- apcore_cli-0.7.0/htmlcov/z_4d276f71fa2bf6ca___init___py.html +0 -184
- apcore_cli-0.7.0/htmlcov/z_4d276f71fa2bf6ca__sandbox_runner_py.html +0 -122
- apcore_cli-0.7.0/htmlcov/z_4d276f71fa2bf6ca_approval_py.html +0 -352
- apcore_cli-0.7.0/htmlcov/z_4d276f71fa2bf6ca_builtin_group_py.html +0 -475
- apcore_cli-0.7.0/htmlcov/z_4d276f71fa2bf6ca_cli_py.html +0 -1173
- apcore_cli-0.7.0/htmlcov/z_4d276f71fa2bf6ca_config_py.html +0 -238
- apcore_cli-0.7.0/htmlcov/z_4d276f71fa2bf6ca_discovery_py.html +0 -545
- apcore_cli-0.7.0/htmlcov/z_4d276f71fa2bf6ca_display_helpers_py.html +0 -127
- apcore_cli-0.7.0/htmlcov/z_4d276f71fa2bf6ca_exposure_py.html +0 -227
- apcore_cli-0.7.0/htmlcov/z_4d276f71fa2bf6ca_factory_py.html +0 -833
- apcore_cli-0.7.0/htmlcov/z_4d276f71fa2bf6ca_init_cmd_py.html +0 -287
- apcore_cli-0.7.0/htmlcov/z_4d276f71fa2bf6ca_output_py.html +0 -467
- apcore_cli-0.7.0/htmlcov/z_4d276f71fa2bf6ca_ref_resolver_py.html +0 -227
- apcore_cli-0.7.0/htmlcov/z_4d276f71fa2bf6ca_schema_parser_py.html +0 -295
- apcore_cli-0.7.0/htmlcov/z_4d276f71fa2bf6ca_shell_py.html +0 -739
- apcore_cli-0.7.0/htmlcov/z_4d276f71fa2bf6ca_strategy_py.html +0 -307
- apcore_cli-0.7.0/htmlcov/z_4d276f71fa2bf6ca_system_cmd_py.html +0 -566
- apcore_cli-0.7.0/src/apcore_cli/__init__.py +0 -87
- apcore_cli-0.7.0/src/apcore_cli/security/sandbox.py +0 -168
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/.github/CODEOWNERS +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/.github/copilot-ignore +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/.github/workflows/ci.yml +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/.gitignore +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/.gitmessage +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/.pre-commit-config.yaml +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/CLAUDE.md +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/LICENSE +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/Makefile +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/examples/extensions/math/add.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/examples/extensions/math/multiply.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/examples/extensions/sysutil/disk.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/examples/extensions/sysutil/env.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/examples/extensions/sysutil/info.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/examples/extensions/text/reverse.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/examples/extensions/text/upper.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/examples/extensions/text/wordcount.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/examples/run_examples.sh +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/planning/approval-gate.md +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/planning/config-resolver.md +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/planning/core-dispatcher.md +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/planning/discovery.md +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/planning/exposure-filtering.md +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/planning/grouped-commands.md +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/planning/output-formatter.md +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/planning/overview.md +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/planning/schema-parser.md +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/planning/security-manager.md +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/planning/shell-integration.md +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/planning/state.json +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/_sandbox_runner.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/approval.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/display_helpers.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/exposure.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/init_cmd.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/security/__init__.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/security/auth.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/shell.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/src/apcore_cli/validate.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/__init__.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/conformance/__init__.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/conformance/test_apcli_visibility.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/conftest.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_config.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_discovery.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_discovery_fe13.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_display_helpers.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_e2e.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_exposure.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_init_cmd.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_output.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_output_format_exec.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_sandbox_runner.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_security/__init__.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_security/test_auth.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_shell.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_strategy.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_system_cmd.py +0 -0
- {apcore_cli-0.7.0 → apcore_cli-0.8.0}/tests/test_toolkit_integration.py +0 -0
|
@@ -6,6 +6,208 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
8
|
|
|
9
|
+
## [0.8.0] - 2026-05-08
|
|
10
|
+
|
|
11
|
+
### Removed
|
|
12
|
+
|
|
13
|
+
- **D9-001 — FE-13 §11.2 deprecation shims removed**. The 13 hidden root-level
|
|
14
|
+
shims (`list`, `describe`, `exec`, `init`, `validate`, `health`, `usage`,
|
|
15
|
+
`enable`, `disable`, `reload`, `config`, `completion`, `describe-pipeline`)
|
|
16
|
+
installed by `_register_deprecation_shims` and the `__is_deprecation_shim__`
|
|
17
|
+
collision-handling path in `extra_commands` wiring have been deleted along
|
|
18
|
+
with the `_DEPRECATED_ROOT_COMMANDS` table. Use the canonical
|
|
19
|
+
`apcli <command>` paths instead. Calls like `apcore-cli list` now exit
|
|
20
|
+
non-zero with Click's "No such command" message — the warning window
|
|
21
|
+
documented as "removed in v0.8" is closed.
|
|
22
|
+
|
|
23
|
+
### Deprecated
|
|
24
|
+
|
|
25
|
+
- **`CliModuleNotFoundError` alias** — the symbol still resolves to
|
|
26
|
+
`ModuleNotFoundError` (see D1-002 in Changed) but is scheduled for
|
|
27
|
+
removal in v0.10.0. Update imports to
|
|
28
|
+
`from apcore_cli import ModuleNotFoundError`.
|
|
29
|
+
|
|
30
|
+
### Security
|
|
31
|
+
|
|
32
|
+
- **D10-001 — `Sandbox` per-stream output cap** (`sandbox.py:155`). The previous
|
|
33
|
+
implementation summed `stdout + stderr` against a single `max_output_bytes`
|
|
34
|
+
budget — a runaway child writing only to stderr could starve the stdout
|
|
35
|
+
budget and vice versa, and the diagnostic on overflow did not name the
|
|
36
|
+
offending stream. Each stream now has an independent byte budget matching
|
|
37
|
+
Rust and TypeScript; the overflow error names the stream that tripped the
|
|
38
|
+
cap.
|
|
39
|
+
- **D11-W2 — `Sandbox` switched from `subprocess.run` to `subprocess.Popen`
|
|
40
|
+
with threaded chunked reads** (`sandbox.py:155`). `capture_output=True`
|
|
41
|
+
buffered the entire child stdio into parent memory before the cap was
|
|
42
|
+
checked, so a child producing GBs of output could OOM the parent before
|
|
43
|
+
the limit was enforced. The new implementation streams stdout/stderr
|
|
44
|
+
through reader threads with bounded buffers and kills the child as soon
|
|
45
|
+
as either stream exceeds its cap. Memory consumption is now bounded by
|
|
46
|
+
`2 × max_output_bytes` regardless of child output volume.
|
|
47
|
+
- **D11-003 — `ConfigEncryptor` v1 decryption honours
|
|
48
|
+
`APCORE_CLI_CONFIG_PASSPHRASE`** (`config_encryptor.py:128`). `_aes_decrypt_v1`
|
|
49
|
+
hard-coded the host:user material, so v1 ciphertext encrypted by the Rust
|
|
50
|
+
or TypeScript SDKs under a passphrase failed to decrypt on Python.
|
|
51
|
+
Decryption now tries the passphrase-derived key first when the env var is
|
|
52
|
+
set, falling back to host:user material — matching TypeScript
|
|
53
|
+
`aesDecryptV1`. Cross-SDK config bundles are now portable.
|
|
54
|
+
- **D11-008 — `AuditLogger._get_user` fallback chain now includes `LOGNAME`**
|
|
55
|
+
(`audit.py:66`). The canonical chain per `security.md` (D11-W1) is
|
|
56
|
+
`getlogin → pwd.getpwuid → USER → LOGNAME → USERNAME → unknown`. Python
|
|
57
|
+
previously skipped `LOGNAME`, so audit-log `user` fields diverged from
|
|
58
|
+
Rust/TS on hosts where only `LOGNAME` is set (some container runtimes,
|
|
59
|
+
cron jobs).
|
|
60
|
+
|
|
61
|
+
### Added
|
|
62
|
+
|
|
63
|
+
- **`builtin_group_name="apcli"` kwarg on `create_cli`** — downstream branded CLIs that embed apcore-cli can now expose the built-in commands under a custom namespace (e.g. `mycorp-cli admin health` instead of `mycorp-cli apcli health`). `ApcliGroup` gains a `name` parameter (with property accessor) threaded through `from_cli_config` / `from_yaml` / `_build`. Default `"apcli"` is unchanged. Validated against `/^[a-z][a-z0-9_-]*$/`; invalid values exit 2. `RESERVED_GROUP_NAMES` collision check now consults `GroupedModuleGroup._reserved_group_names` (instance attribute, defaults to the static frozenset; factory replaces with the resolved name). Env var `APCORE_CLI_APCLI` and config keys `apcli.*` deliberately do NOT rename — they are apcore-cli-internal toggles, not user-facing. Cross-SDK parity with TypeScript `createCli({ builtinGroupName })`. New `DEFAULT_BUILTIN_GROUP_NAME` constant exported from `apcore_cli.builtin_group`.
|
|
64
|
+
- **`_exit_on_system_error(e)` helper in `system_cmd.py`** — centralizes the canonical error→exit-code mapping for system-management subcommands, replacing 7 sites that previously used bare `sys.exit(1)` (audit D11-B-002, see Fixed).
|
|
65
|
+
- **5 new tests in `tests/test_builtin_group.py`** — `TestBuiltinGroupRename` class covers default name, custom name via both factories, validation of valid/invalid name shapes (5 valid + 6 invalid forms each).
|
|
66
|
+
- **D1-001 — 13 `register_*_command` factories + `configure_man_help`
|
|
67
|
+
re-exported from `apcore_cli` package root**. Embedders that compose
|
|
68
|
+
their own root command tree no longer need to reach into private
|
|
69
|
+
submodules (`apcore_cli.commands.list_cmd`, etc.). All TS/Rust
|
|
70
|
+
`register_*` counterparts now have a Python public-API equivalent.
|
|
71
|
+
- **D1-003 — `apcore_cli.exit_codes` module** with 24 `EXIT_*` integer
|
|
72
|
+
constants, an `EXIT_CODES` mapping dict, and an `exit_code_for_error()`
|
|
73
|
+
helper. Mirrors TS `errors.ts` `EXIT_CODES` + `exitCodeForError` and
|
|
74
|
+
Rust `src/lib.rs` `EXIT_*` constants. Embedders can now map exceptions
|
|
75
|
+
to documented exit codes without re-implementing the table.
|
|
76
|
+
- **D1-007 — `format_module_list`, `format_module_detail`,
|
|
77
|
+
`resolve_format` re-exported from package root**. The
|
|
78
|
+
output-formatter feature spec declares these as Contracts; previously
|
|
79
|
+
only `format_exec_result` was public.
|
|
80
|
+
- **D1-W1 — `APCLI_SUBCOMMAND_NAMES` re-exported from `apcore_cli`**.
|
|
81
|
+
Matches Rust `lib.rs` and is now in `__all__` for static-analysis
|
|
82
|
+
tooling.
|
|
83
|
+
- **D1-W2 — `ApcliConfig` TypedDict** added to the public surface,
|
|
84
|
+
mirroring the TypeScript type alias and Rust struct so embedders have
|
|
85
|
+
a static contract for the `apcli.*` config block.
|
|
86
|
+
- **D1-W3 — `register_config_namespace()` helper + module-level
|
|
87
|
+
`DEFAULTS` constant** in `config.py`. The package still registers the
|
|
88
|
+
namespace at import time, but embedders can now invoke the helper
|
|
89
|
+
explicitly (parity with `apcore-cli-typescript`).
|
|
90
|
+
- **D1-W5 — Core dispatcher embedder API re-exported from package
|
|
91
|
+
root**: `build_module_command`, `collect_input`, `validate_module_id`,
|
|
92
|
+
`set_audit_logger`, `set_verbose_help`, `set_docs_url`. Embedders no
|
|
93
|
+
longer have to import from `apcore_cli.cli` directly. Matches Rust
|
|
94
|
+
`lib.rs:186-190` and TS `index.ts:18`. New `tests/test_public_api.py`
|
|
95
|
+
pins the surface against future drift.
|
|
96
|
+
- **D1-info-1 — typed `ApcliGroupError` exception**
|
|
97
|
+
(`builtin_group.py:107`). Cross-SDK parity with Rust `ApcliGroupError`;
|
|
98
|
+
embedders previously had no stable error class to match on for
|
|
99
|
+
built-in-group config validation. `ApcliGroupError(ValueError)`
|
|
100
|
+
preserves backwards compat — existing `except ValueError` callers
|
|
101
|
+
still catch it. The invalid-name regex check in `__init__` now raises
|
|
102
|
+
`ApcliGroupError`. Re-exported from `apcore_cli`.
|
|
103
|
+
|
|
104
|
+
### Fixed
|
|
105
|
+
|
|
106
|
+
- **D11-B-006 — `discovery.py:208` sort direction inverted**. `apcli list --sort calls|errors|latency` now defaults to DESCENDING (highest call count first) per spec T-LST-04, matching Rust `discovery.rs:209` and TypeScript `discovery.ts:186`. Previously the user's raw `--reverse` flag (default False) was passed directly to `sort_modules_by_usage(..., reverse=...)`, producing ASCENDING output by default — the inverse of the spec. Fix passes `reverse=not reverse` for the data path AND adds a re-sort at the call site for the audit-log-empty fallback so id-fallback continues to default ASCENDING per spec.
|
|
107
|
+
- **D11-B-002 — `system_cmd.py` collapsed every error to exit 1**. The 7 `except Exception as e: sys.exit(1)` sites bypassed Python's own `_ERROR_CODE_MAP` (canonical 44/46/47/77) — scripted operators could not distinguish "module not found" from "ACL denied" from generic failure. All 7 sites now route through the new `_exit_on_system_error(e)` helper which calls `exit_code_for_error(e)` from `apcore_cli.exit_codes`. The 4 audit-log entries previously hardcoding `exit_code=1` now log the resolved code.
|
|
108
|
+
- **D11-NEW-005 — RESERVED_PROPERTY_NAMES no longer raises generic `ValueError`**. `schema_to_click_options` previously raised `ValueError` when a schema property collided with a built-in CLI option — opaque to scripted callers and inconsistent with the neighbour flag-collision branch (which already exited 48). Now writes a user-facing `Error:` line to stderr and calls `sys.exit(48)` per spec, matching TS `process.exit(EXIT_CODES.SCHEMA_CIRCULAR_REF)` and Rust `CliError::SchemaParserFailure → EXIT_SCHEMA_CIRCULAR_REF`. Tests tightened from `pytest.raises((ValueError, Exception))` to `pytest.raises(SystemExit)` with `code == 48` assertion.
|
|
109
|
+
- **D9-NEW-002 — `ref_resolver.py` `allOf required` not deduplicated**. `_resolve_node`'s `allOf` branch concatenated parent `required` + each branch's `required` without dedup, producing duplicate entries in the merged schema's `required` array. JSON Schema validators ignore duplicates so observable validation behaviour was unchanged, but cross-SDK byte-comparison tooling (and the `anyOf`/`oneOf` paths, which already deduped) flagged the divergence. Fix: explicit seen-set dedup preserving first-seen order, matching TS `[...new Set(...)]` and Rust `merge_allof`.
|
|
110
|
+
- **D10-003 — `build_module_command` leaked `RefResolverError`
|
|
111
|
+
tracebacks** (`cli.py:538`). The `resolve_refs` catch clause re-raised
|
|
112
|
+
unchanged, so callers saw a Python traceback instead of a clean
|
|
113
|
+
documented exit code. Now translates `CircularRefError` /
|
|
114
|
+
`MaxDepthExceededError` to `sys.exit(48)` and `UnresolvableRefError`
|
|
115
|
+
(plus generic `RefResolverError`) to `sys.exit(45)`, mirroring
|
|
116
|
+
`schema_parser.py:111` and the Rust/TS contracts.
|
|
117
|
+
- **D11-NEW-003 — `ref_resolver` `max_depth` over-counted plain nested
|
|
118
|
+
`properties`** (`ref_resolver.py`). `_resolve_node` previously
|
|
119
|
+
incremented `depth + 1` when recursing into nested `properties`
|
|
120
|
+
values, so a schema with >32 levels of nested objects (no `$ref` at
|
|
121
|
+
all) was rejected with `MaxDepthExceededError`. The spec wording is
|
|
122
|
+
"Maximum `$ref` resolution recursion depth" — `$ref` hops along a
|
|
123
|
+
single chain, not total stack depth. `depth` is now only incremented
|
|
124
|
+
on `$ref` traversal, aligning with Rust `ref_resolver.rs:297`. Also
|
|
125
|
+
adds 4 regression tests for `anyOf`/`oneOf` sibling-required
|
|
126
|
+
preservation and `anyOf` overlap dedup.
|
|
127
|
+
- **D10-info-1 — `APCORE_CLI_APCLI` env var not trimmed on read**
|
|
128
|
+
(`builtin_group.py:414`). Spec invariant 2 requires the parser to be
|
|
129
|
+
case-insensitive AND trim-on-read. Surrounding whitespace previously
|
|
130
|
+
caused a silent Tier-3/Tier-4 fall-through. Now strips before
|
|
131
|
+
lowercasing, matching Rust/TS.
|
|
132
|
+
- **D11-010 — `AuditLogger` write-failure warnings deduplicated**
|
|
133
|
+
(`audit.py:55`). Previously warned on every failed write, flooding
|
|
134
|
+
logs when an audit dir is unwritable. An instance flag now gates the
|
|
135
|
+
warning so it fires once per logger instance, matching the TS
|
|
136
|
+
`writeFailureWarned` flag.
|
|
137
|
+
|
|
138
|
+
### Changed
|
|
139
|
+
|
|
140
|
+
- **`apcli system *` and `apcli strategy describe-pipeline` `--format` choices**
|
|
141
|
+
expanded from `[table, json]` to `[table, json, csv, yaml, jsonl]`, matching
|
|
142
|
+
the existing `apcli list` / `apcli exec` choice set. `markdown` and `skill`
|
|
143
|
+
are deliberately excluded from these subcommands — their payloads are
|
|
144
|
+
health / strategy results, not `ScannedModule` data. Issue
|
|
145
|
+
[#20](https://github.com/aiperceivable/apcore-cli/issues/20).
|
|
146
|
+
- **Dependency bump**: requires `apcore >= 0.21.0` (was `>= 0.19.0`) and the
|
|
147
|
+
optional `[toolkit]` extra now requires `apcore-toolkit >= 0.6` (was `>= 0.5`).
|
|
148
|
+
Aligns with upstream `apcore 0.21.0` (Module.preview / PreflightResult.predicted_changes,
|
|
149
|
+
ephemeral.* namespace pilot) and `apcore-toolkit 0.6.0` (surface-aware formatters).
|
|
150
|
+
No CLI-visible behavioural breaks — apcore 0.20→0.21 deprecations
|
|
151
|
+
(`TaskStore.put`/`save`, `TaskStatus.RETRYING`, `CircuitOpenError`) keep
|
|
152
|
+
legacy aliases for one minor release; the cli does not call those surfaces directly.
|
|
153
|
+
- **D1-002 — `CliModuleNotFoundError` renamed to `ModuleNotFoundError`**
|
|
154
|
+
for cross-language port-ability with TS / Rust `ModuleNotFoundError`.
|
|
155
|
+
The class intentionally shadows `builtins.ModuleNotFoundError` inside
|
|
156
|
+
the `apcore_cli` namespace. A deprecation alias
|
|
157
|
+
`CliModuleNotFoundError = ModuleNotFoundError` is kept for backwards
|
|
158
|
+
compatibility and will be removed in v0.10.0. Reverses the D2-001
|
|
159
|
+
rename which predated the cross-SDK parity policy.
|
|
160
|
+
- **Issue #19 — drop "apcore" branding from embedded-mode `--help`**:
|
|
161
|
+
`create_cli()` now resolves the top-level CLI description from the new
|
|
162
|
+
`description=` parameter (defaults to `f"{prog_name} CLI"`), the `apcli`
|
|
163
|
+
subgroup advertises itself as `Built-in commands` rather than
|
|
164
|
+
`apcore-cli built-in commands`, and the `--verbose` option / footer drop
|
|
165
|
+
the trailing `apcore` from `(including built-in apcore options)`. Standalone
|
|
166
|
+
bin entry (`apcore_cli/__main__.py:main()`) passes
|
|
167
|
+
`description="<prog> — execute apcore modules from the command line"`
|
|
168
|
+
explicitly so the standalone surface is unchanged.
|
|
169
|
+
|
|
170
|
+
### Added
|
|
171
|
+
|
|
172
|
+
- **`--format markdown` and `--format skill`** for `apcli list` and `apcli describe`
|
|
173
|
+
(issue [#20](https://github.com/aiperceivable/apcore-cli/issues/20)). Both
|
|
174
|
+
delegate to `apcore_toolkit.format_module(s)` (≥0.6) so the output is
|
|
175
|
+
byte-identical to the same toolkit call in the TypeScript and Rust SDKs.
|
|
176
|
+
`--format skill` produces vendor-neutral SKILL.md content directly loadable
|
|
177
|
+
by Claude Code (`.claude/skills/<id>/SKILL.md`) and Gemini CLI
|
|
178
|
+
(`.gemini/skills/<id>/SKILL.md`):
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
apcli describe users.create --format skill > .claude/skills/users.create/SKILL.md
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
A new internal adapter `_descriptor_to_scanned()` maps `ModuleDescriptor`
|
|
185
|
+
(apcore registry) to `ScannedModule` (apcore-toolkit). A `ClickException` with
|
|
186
|
+
a clear install hint is raised if the optional `[toolkit]` extra is missing.
|
|
187
|
+
- **Issue #18 — host-app `--version` opt-in**: new `version: str | None = None`
|
|
188
|
+
parameter on `create_cli()`. When supplied, registers `-V/--version` with
|
|
189
|
+
the host's version string. **When omitted, the `--version` flag is no
|
|
190
|
+
longer registered** — embedded CLIs that do not opt in stop leaking the
|
|
191
|
+
SDK's own version through `-V/--version`. The standalone bin entry
|
|
192
|
+
passes `version=apcore_cli.__version__` explicitly so the
|
|
193
|
+
`apcore-cli` binary's behaviour is preserved.
|
|
194
|
+
- **Issue #19 — `description: str | None = None`** on `create_cli()`.
|
|
195
|
+
- **Issue #17 — `system.usage` aggregator + `list --sort calls|errors|latency`**:
|
|
196
|
+
new module `apcore_cli.system_usage` reads `~/.apcore-cli/audit.jsonl`,
|
|
197
|
+
filters by period (default 24h), and returns per-module aggregates
|
|
198
|
+
(`calls`, `errors`, `avg latency_ms`). `list --sort {calls,errors,latency}`
|
|
199
|
+
now consults the aggregator instead of falling back to id-sort with a
|
|
200
|
+
buried `logger.warning`. When the audit log has no entries in the period
|
|
201
|
+
window the discovery layer prints a user-visible note to stderr
|
|
202
|
+
(`note: no usage data available for --sort <field>; sorted by id. ...`)
|
|
203
|
+
and falls back to id-sort. Module-protocol registration of
|
|
204
|
+
`system.usage.summary` / `system.usage.module` as registry-callable
|
|
205
|
+
built-ins is tracked as a follow-up — today the readers are invoked
|
|
206
|
+
directly by the discovery layer.
|
|
207
|
+
- New file: `apcore_cli/system_usage.py`.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
9
211
|
## [0.7.0] - 2026-04-23
|
|
10
212
|
|
|
11
213
|
### Changed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: apcore-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Terminal adapter for apcore — execute AI-Perceivable modules from the command line
|
|
5
5
|
Project-URL: Homepage, https://aiperceivable.com
|
|
6
6
|
Project-URL: Repository, https://github.com/aiperceivable/apcore-cli-python
|
|
@@ -21,7 +21,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
21
21
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
22
22
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
23
|
Requires-Python: >=3.11
|
|
24
|
-
Requires-Dist: apcore>=0.
|
|
24
|
+
Requires-Dist: apcore>=0.21.0
|
|
25
25
|
Requires-Dist: click>=8.1
|
|
26
26
|
Requires-Dist: cryptography>=41.0
|
|
27
27
|
Requires-Dist: jsonschema>=4.20
|
|
@@ -37,7 +37,7 @@ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
|
37
37
|
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
38
38
|
Requires-Dist: ruff>=0.1; extra == 'dev'
|
|
39
39
|
Provides-Extra: toolkit
|
|
40
|
-
Requires-Dist: apcore-toolkit>=0.
|
|
40
|
+
Requires-Dist: apcore-toolkit>=0.6; extra == 'toolkit'
|
|
41
41
|
Description-Content-Type: text/markdown
|
|
42
42
|
|
|
43
43
|
<div align="center">
|
|
@@ -50,7 +50,7 @@ Terminal adapter for apcore. Execute AI-Perceivable modules from the command lin
|
|
|
50
50
|
|
|
51
51
|
[](LICENSE)
|
|
52
52
|
[](https://python.org)
|
|
53
|
-
[](https://github.com/aiperceivable/apcore-cli-python/actions/workflows/ci.yml)
|
|
54
54
|
|
|
55
55
|
| | |
|
|
56
56
|
|---|---|
|
|
@@ -90,7 +90,11 @@ Terminal adapter for apcore. Execute AI-Perceivable modules from the command lin
|
|
|
90
90
|
pip install apcore-cli
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
-
Requires Python 3.11+ and `apcore >= 0.
|
|
93
|
+
Requires Python 3.11+ and `apcore >= 0.21.0`. The optional `toolkit` extra requires `apcore-toolkit >= 0.6`:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
pip install "apcore-cli[toolkit]"
|
|
97
|
+
```
|
|
94
98
|
|
|
95
99
|
## Quick Start
|
|
96
100
|
|
|
@@ -159,13 +163,22 @@ cli = create_cli(registry=registry, executor=executor, prog_name="myapp")
|
|
|
159
163
|
|
|
160
164
|
#### Python API
|
|
161
165
|
|
|
162
|
-
The `apcore_cli` package
|
|
166
|
+
The `apcore_cli` package re-exports the following public surface (see [`src/apcore_cli/__init__.py`](src/apcore_cli/__init__.py) for the canonical `__all__`):
|
|
163
167
|
|
|
164
168
|
| Export | Description |
|
|
165
169
|
|--------|-------------|
|
|
166
170
|
| `__version__` | Package version string |
|
|
167
|
-
| `create_cli(...)` | Factory that builds a ready-to-invoke `click.Group`. See the [`create_cli` reference](https://github.com/aiperceivable/apcore-cli) in the docs site for the full
|
|
171
|
+
| `create_cli(...)` | Factory that builds a ready-to-invoke `click.Group`. See the [`create_cli` reference](https://github.com/aiperceivable/apcore-cli) in the docs site for the full 13-parameter signature: `extensions_dir`, `prog_name`, `commands_dir`, `binding_path`, `registry`, `executor`, `extra_commands`, `app`, `expose`, **`apcli`** (FE-13 P0 break), `allowed_prefixes`, `version`, `description`. The `app`, `allowed_prefixes`, `version`, and `description` parameters were added in v0.8.0. |
|
|
172
|
+
| `ApcliGroup`, `ApcliMode`, `RESERVED_GROUP_NAMES` | FE-13 built-in `apcli` group surface (P0 break in v0.8.0). |
|
|
168
173
|
| `ExposureFilter` | Declarative filter controlling which modules are exposed by the CLI (FE-12). |
|
|
174
|
+
| `CliApprovalHandler`, `check_approval` | TTY-aware HITL approval handler / helper (FE-11). |
|
|
175
|
+
| `ConfigResolver` | 4-tier config precedence resolver (CLI flag > env var > config file > default). |
|
|
176
|
+
| `AuditLogger` | Append-only JSON Lines audit logger (`~/.apcore-cli/audit.jsonl`). |
|
|
177
|
+
| `AuthProvider` | API-key authentication provider (keyring-backed). |
|
|
178
|
+
| `ConfigEncryptor` | AES-256-GCM helper for encrypted config blobs. |
|
|
179
|
+
| `Sandbox` | Subprocess sandbox for isolated module execution. |
|
|
180
|
+
| `resolve_refs`, `schema_to_click_options`, `format_exec_result` | Schema/output helper functions. |
|
|
181
|
+
| `ApprovalDeniedError`, `ApprovalTimeoutError`, `AuthenticationError`, `ConfigDecryptionError`, `ModuleExecutionError`, `CliModuleNotFoundError`, `SchemaValidationError` | Typed error classes raised by the SDK (mapped to documented exit codes). |
|
|
169
182
|
|
|
170
183
|
**Exposure filtering** — restrict which modules are visible at the CLI layer without touching the underlying registry:
|
|
171
184
|
|
|
@@ -195,24 +208,26 @@ cli = create_cli(
|
|
|
195
208
|
cli = create_cli(registry=registry, executor=executor, extra_commands=[my_custom_click_cmd])
|
|
196
209
|
```
|
|
197
210
|
|
|
198
|
-
Or
|
|
211
|
+
Or build the CLI with a pre-populated registry and executor and full control over the `apcli` built-in group:
|
|
199
212
|
|
|
200
213
|
```python
|
|
201
|
-
import click
|
|
202
214
|
from apcore import Registry, Executor
|
|
203
|
-
from apcore_cli
|
|
215
|
+
from apcore_cli import create_cli, ApcliMode
|
|
204
216
|
|
|
205
217
|
registry = Registry(extensions_dir="./extensions")
|
|
206
218
|
registry.discover()
|
|
207
219
|
executor = Executor(registry)
|
|
208
220
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
221
|
+
cli = create_cli(
|
|
222
|
+
registry=registry,
|
|
223
|
+
executor=executor,
|
|
224
|
+
apcli=ApcliMode.ALL, # or "all" / "none" / {"mode": "include", "include": [...]}
|
|
225
|
+
)
|
|
226
|
+
cli(standalone_mode=True)
|
|
214
227
|
```
|
|
215
228
|
|
|
229
|
+
> **Note:** `apcore_cli.cli.LazyModuleGroup` and `GroupedModuleGroup` are advanced internal classes used by `create_cli`. They are subject to change between releases — prefer `create_cli(...)` for stable embedding.
|
|
230
|
+
|
|
216
231
|
## Adding Custom Commands
|
|
217
232
|
|
|
218
233
|
### Fastest way (30 seconds)
|
|
@@ -304,7 +319,7 @@ apcore-cli [OPTIONS] COMMAND [ARGS]
|
|
|
304
319
|
|
|
305
320
|
### Built-in Commands
|
|
306
321
|
|
|
307
|
-
apcore-cli ships with
|
|
322
|
+
apcore-cli ships with 13 built-in commands, all accessible under the `apcli` subgroup (e.g. `apcore-cli apcli list`). Root-level shims emit a deprecation warning in v0.8.x and are scheduled for removal in v0.9. Use `apcore-cli apcli <subcommand>` to avoid the warning.
|
|
308
323
|
|
|
309
324
|
**Module invocation**
|
|
310
325
|
|
|
@@ -338,7 +353,8 @@ apcore-cli ships with 14 built-in commands, all accessible under the `apcli` sub
|
|
|
338
353
|
| Command | Description |
|
|
339
354
|
|---------|-------------|
|
|
340
355
|
| `apcli completion <shell>` | Generate shell completion script (bash/zsh/fish) |
|
|
341
|
-
|
|
356
|
+
|
|
357
|
+
The full-program man page is reachable via the root flag combination `apcore-cli --help --man` (powered by `configure_man_help()`); there is no standalone `apcli man` subcommand.
|
|
342
358
|
|
|
343
359
|
### Module Execution Options
|
|
344
360
|
|
|
@@ -401,6 +417,7 @@ apcore-cli uses a 4-tier configuration precedence:
|
|
|
401
417
|
| `APCORE_CLI_APPROVAL_TIMEOUT` | Approval-gate timeout in seconds (v0.6.0) | `60` |
|
|
402
418
|
| `APCORE_CLI_STRATEGY` | Default execution strategy (v0.6.0) | `standard` |
|
|
403
419
|
| `APCORE_CLI_GROUP_DEPTH` | Depth of automatic command grouping by `.` segments (v0.6.0) | `1` |
|
|
420
|
+
| `APCORE_CLI_APCLI` | FE-13 visibility for the `apcli` built-in group: `all`, `none`, `include`, `exclude`, or `auto` (v0.8.0). Overrides the `apcli:` block in `apcore.yaml`. | `auto` |
|
|
404
421
|
|
|
405
422
|
### Config File (`apcore.yaml`)
|
|
406
423
|
|
|
@@ -416,8 +433,32 @@ cli:
|
|
|
416
433
|
approval_timeout: 60 # v0.6.0
|
|
417
434
|
strategy: standard # v0.6.0
|
|
418
435
|
group_depth: 1 # v0.6.0
|
|
436
|
+
apcli: # v0.8.0 (FE-13)
|
|
437
|
+
mode: all # all | none | include | exclude
|
|
438
|
+
include: [] # used when mode == include
|
|
439
|
+
exclude: [] # used when mode == exclude
|
|
419
440
|
```
|
|
420
441
|
|
|
442
|
+
### `apcli` built-in group visibility (FE-13)
|
|
443
|
+
|
|
444
|
+
> **P0 breaking change in v0.8.0** — all built-ins were moved under the `apcli` group; the `BUILTIN_COMMANDS` constant has been retired.
|
|
445
|
+
|
|
446
|
+
The visibility of the `apcli` group is resolved through a 4-tier decision chain:
|
|
447
|
+
|
|
448
|
+
1. **`create_cli(apcli=...)` kwarg** (highest) — accepts an `ApcliMode` enum, a string (`"all"`, `"none"`, `"include"`, `"exclude"`), or a dict (`{"mode": "include", "include": ["list", "describe"]}`).
|
|
449
|
+
2. **`APCORE_CLI_APCLI` env var** — `all`, `none`, `include`, `exclude`, or `auto`.
|
|
450
|
+
3. **`apcli:` block in `apcore.yaml`** — see the example above.
|
|
451
|
+
4. **Embedded vs. standalone default** (lowest) — standalone `apcore-cli` defaults to `all`; CLIs embedded via `create_cli(app=...)` default to `none` so that host applications opt in explicitly. The `auto` sentinel selects this default and is intended for env/config use only — it is not a user-facing `ApcliMode` value.
|
|
452
|
+
|
|
453
|
+
The four user-visible modes are:
|
|
454
|
+
|
|
455
|
+
| Mode | Behavior |
|
|
456
|
+
|------|----------|
|
|
457
|
+
| `all` | All 13 `apcli` subcommands are exposed. |
|
|
458
|
+
| `none` | The `apcli` group is hidden entirely. |
|
|
459
|
+
| `include` | Only the subcommands listed in `include` are exposed. |
|
|
460
|
+
| `exclude` | All subcommands except those listed in `exclude` are exposed. |
|
|
461
|
+
|
|
421
462
|
## Features
|
|
422
463
|
|
|
423
464
|
- **Auto-discovery** -- all modules in the extensions directory are found and exposed as CLI commands
|
|
@@ -432,7 +473,7 @@ cli:
|
|
|
432
473
|
- **Schema validation** -- inputs validated against JSON Schema before execution, with `$ref`/`allOf`/`anyOf`/`oneOf` resolution
|
|
433
474
|
- **Security** -- API key auth (keyring + AES-256-GCM), append-only audit logging, subprocess sandboxing
|
|
434
475
|
- **Shell completions** -- `apcore-cli apcli completion bash|zsh|fish` generates completion scripts with dynamic module ID completion
|
|
435
|
-
- **Man pages** -- `apcore-cli
|
|
476
|
+
- **Man pages** -- `apcore-cli --help --man` prints a full-program roff man page to stdout, powered by `configure_man_help()` (also exposed for embedded CLIs to opt in)
|
|
436
477
|
- **Documentation URL** -- `set_docs_url()` sets a base URL; per-command help shows `Docs: {url}/commands/{name}`, man page SEE ALSO links to the full docs site
|
|
437
478
|
- **Audit logging** -- all executions logged to `~/.apcore-cli/audit.jsonl` with SHA-256 input hashing
|
|
438
479
|
|
|
@@ -519,8 +560,8 @@ apcore-cli apcli completion bash >> ~/.bashrc
|
|
|
519
560
|
apcore-cli apcli completion zsh >> ~/.zshrc
|
|
520
561
|
apcore-cli apcli completion fish > ~/.config/fish/completions/apcore-cli.fish
|
|
521
562
|
|
|
522
|
-
# Man pages
|
|
523
|
-
apcore-cli
|
|
563
|
+
# Man pages (full-program roff output)
|
|
564
|
+
apcore-cli --help --man | man -l -
|
|
524
565
|
|
|
525
566
|
# Run all examples at once
|
|
526
567
|
bash examples/run_examples.sh
|
|
@@ -8,7 +8,7 @@ Terminal adapter for apcore. Execute AI-Perceivable modules from the command lin
|
|
|
8
8
|
|
|
9
9
|
[](LICENSE)
|
|
10
10
|
[](https://python.org)
|
|
11
|
-
[](https://github.com/aiperceivable/apcore-cli-python/actions/workflows/ci.yml)
|
|
12
12
|
|
|
13
13
|
| | |
|
|
14
14
|
|---|---|
|
|
@@ -48,7 +48,11 @@ Terminal adapter for apcore. Execute AI-Perceivable modules from the command lin
|
|
|
48
48
|
pip install apcore-cli
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
Requires Python 3.11+ and `apcore >= 0.
|
|
51
|
+
Requires Python 3.11+ and `apcore >= 0.21.0`. The optional `toolkit` extra requires `apcore-toolkit >= 0.6`:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install "apcore-cli[toolkit]"
|
|
55
|
+
```
|
|
52
56
|
|
|
53
57
|
## Quick Start
|
|
54
58
|
|
|
@@ -117,13 +121,22 @@ cli = create_cli(registry=registry, executor=executor, prog_name="myapp")
|
|
|
117
121
|
|
|
118
122
|
#### Python API
|
|
119
123
|
|
|
120
|
-
The `apcore_cli` package
|
|
124
|
+
The `apcore_cli` package re-exports the following public surface (see [`src/apcore_cli/__init__.py`](src/apcore_cli/__init__.py) for the canonical `__all__`):
|
|
121
125
|
|
|
122
126
|
| Export | Description |
|
|
123
127
|
|--------|-------------|
|
|
124
128
|
| `__version__` | Package version string |
|
|
125
|
-
| `create_cli(...)` | Factory that builds a ready-to-invoke `click.Group`. See the [`create_cli` reference](https://github.com/aiperceivable/apcore-cli) in the docs site for the full
|
|
129
|
+
| `create_cli(...)` | Factory that builds a ready-to-invoke `click.Group`. See the [`create_cli` reference](https://github.com/aiperceivable/apcore-cli) in the docs site for the full 13-parameter signature: `extensions_dir`, `prog_name`, `commands_dir`, `binding_path`, `registry`, `executor`, `extra_commands`, `app`, `expose`, **`apcli`** (FE-13 P0 break), `allowed_prefixes`, `version`, `description`. The `app`, `allowed_prefixes`, `version`, and `description` parameters were added in v0.8.0. |
|
|
130
|
+
| `ApcliGroup`, `ApcliMode`, `RESERVED_GROUP_NAMES` | FE-13 built-in `apcli` group surface (P0 break in v0.8.0). |
|
|
126
131
|
| `ExposureFilter` | Declarative filter controlling which modules are exposed by the CLI (FE-12). |
|
|
132
|
+
| `CliApprovalHandler`, `check_approval` | TTY-aware HITL approval handler / helper (FE-11). |
|
|
133
|
+
| `ConfigResolver` | 4-tier config precedence resolver (CLI flag > env var > config file > default). |
|
|
134
|
+
| `AuditLogger` | Append-only JSON Lines audit logger (`~/.apcore-cli/audit.jsonl`). |
|
|
135
|
+
| `AuthProvider` | API-key authentication provider (keyring-backed). |
|
|
136
|
+
| `ConfigEncryptor` | AES-256-GCM helper for encrypted config blobs. |
|
|
137
|
+
| `Sandbox` | Subprocess sandbox for isolated module execution. |
|
|
138
|
+
| `resolve_refs`, `schema_to_click_options`, `format_exec_result` | Schema/output helper functions. |
|
|
139
|
+
| `ApprovalDeniedError`, `ApprovalTimeoutError`, `AuthenticationError`, `ConfigDecryptionError`, `ModuleExecutionError`, `CliModuleNotFoundError`, `SchemaValidationError` | Typed error classes raised by the SDK (mapped to documented exit codes). |
|
|
127
140
|
|
|
128
141
|
**Exposure filtering** — restrict which modules are visible at the CLI layer without touching the underlying registry:
|
|
129
142
|
|
|
@@ -153,24 +166,26 @@ cli = create_cli(
|
|
|
153
166
|
cli = create_cli(registry=registry, executor=executor, extra_commands=[my_custom_click_cmd])
|
|
154
167
|
```
|
|
155
168
|
|
|
156
|
-
Or
|
|
169
|
+
Or build the CLI with a pre-populated registry and executor and full control over the `apcli` built-in group:
|
|
157
170
|
|
|
158
171
|
```python
|
|
159
|
-
import click
|
|
160
172
|
from apcore import Registry, Executor
|
|
161
|
-
from apcore_cli
|
|
173
|
+
from apcore_cli import create_cli, ApcliMode
|
|
162
174
|
|
|
163
175
|
registry = Registry(extensions_dir="./extensions")
|
|
164
176
|
registry.discover()
|
|
165
177
|
executor = Executor(registry)
|
|
166
178
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
179
|
+
cli = create_cli(
|
|
180
|
+
registry=registry,
|
|
181
|
+
executor=executor,
|
|
182
|
+
apcli=ApcliMode.ALL, # or "all" / "none" / {"mode": "include", "include": [...]}
|
|
183
|
+
)
|
|
184
|
+
cli(standalone_mode=True)
|
|
172
185
|
```
|
|
173
186
|
|
|
187
|
+
> **Note:** `apcore_cli.cli.LazyModuleGroup` and `GroupedModuleGroup` are advanced internal classes used by `create_cli`. They are subject to change between releases — prefer `create_cli(...)` for stable embedding.
|
|
188
|
+
|
|
174
189
|
## Adding Custom Commands
|
|
175
190
|
|
|
176
191
|
### Fastest way (30 seconds)
|
|
@@ -262,7 +277,7 @@ apcore-cli [OPTIONS] COMMAND [ARGS]
|
|
|
262
277
|
|
|
263
278
|
### Built-in Commands
|
|
264
279
|
|
|
265
|
-
apcore-cli ships with
|
|
280
|
+
apcore-cli ships with 13 built-in commands, all accessible under the `apcli` subgroup (e.g. `apcore-cli apcli list`). Root-level shims emit a deprecation warning in v0.8.x and are scheduled for removal in v0.9. Use `apcore-cli apcli <subcommand>` to avoid the warning.
|
|
266
281
|
|
|
267
282
|
**Module invocation**
|
|
268
283
|
|
|
@@ -296,7 +311,8 @@ apcore-cli ships with 14 built-in commands, all accessible under the `apcli` sub
|
|
|
296
311
|
| Command | Description |
|
|
297
312
|
|---------|-------------|
|
|
298
313
|
| `apcli completion <shell>` | Generate shell completion script (bash/zsh/fish) |
|
|
299
|
-
|
|
314
|
+
|
|
315
|
+
The full-program man page is reachable via the root flag combination `apcore-cli --help --man` (powered by `configure_man_help()`); there is no standalone `apcli man` subcommand.
|
|
300
316
|
|
|
301
317
|
### Module Execution Options
|
|
302
318
|
|
|
@@ -359,6 +375,7 @@ apcore-cli uses a 4-tier configuration precedence:
|
|
|
359
375
|
| `APCORE_CLI_APPROVAL_TIMEOUT` | Approval-gate timeout in seconds (v0.6.0) | `60` |
|
|
360
376
|
| `APCORE_CLI_STRATEGY` | Default execution strategy (v0.6.0) | `standard` |
|
|
361
377
|
| `APCORE_CLI_GROUP_DEPTH` | Depth of automatic command grouping by `.` segments (v0.6.0) | `1` |
|
|
378
|
+
| `APCORE_CLI_APCLI` | FE-13 visibility for the `apcli` built-in group: `all`, `none`, `include`, `exclude`, or `auto` (v0.8.0). Overrides the `apcli:` block in `apcore.yaml`. | `auto` |
|
|
362
379
|
|
|
363
380
|
### Config File (`apcore.yaml`)
|
|
364
381
|
|
|
@@ -374,8 +391,32 @@ cli:
|
|
|
374
391
|
approval_timeout: 60 # v0.6.0
|
|
375
392
|
strategy: standard # v0.6.0
|
|
376
393
|
group_depth: 1 # v0.6.0
|
|
394
|
+
apcli: # v0.8.0 (FE-13)
|
|
395
|
+
mode: all # all | none | include | exclude
|
|
396
|
+
include: [] # used when mode == include
|
|
397
|
+
exclude: [] # used when mode == exclude
|
|
377
398
|
```
|
|
378
399
|
|
|
400
|
+
### `apcli` built-in group visibility (FE-13)
|
|
401
|
+
|
|
402
|
+
> **P0 breaking change in v0.8.0** — all built-ins were moved under the `apcli` group; the `BUILTIN_COMMANDS` constant has been retired.
|
|
403
|
+
|
|
404
|
+
The visibility of the `apcli` group is resolved through a 4-tier decision chain:
|
|
405
|
+
|
|
406
|
+
1. **`create_cli(apcli=...)` kwarg** (highest) — accepts an `ApcliMode` enum, a string (`"all"`, `"none"`, `"include"`, `"exclude"`), or a dict (`{"mode": "include", "include": ["list", "describe"]}`).
|
|
407
|
+
2. **`APCORE_CLI_APCLI` env var** — `all`, `none`, `include`, `exclude`, or `auto`.
|
|
408
|
+
3. **`apcli:` block in `apcore.yaml`** — see the example above.
|
|
409
|
+
4. **Embedded vs. standalone default** (lowest) — standalone `apcore-cli` defaults to `all`; CLIs embedded via `create_cli(app=...)` default to `none` so that host applications opt in explicitly. The `auto` sentinel selects this default and is intended for env/config use only — it is not a user-facing `ApcliMode` value.
|
|
410
|
+
|
|
411
|
+
The four user-visible modes are:
|
|
412
|
+
|
|
413
|
+
| Mode | Behavior |
|
|
414
|
+
|------|----------|
|
|
415
|
+
| `all` | All 13 `apcli` subcommands are exposed. |
|
|
416
|
+
| `none` | The `apcli` group is hidden entirely. |
|
|
417
|
+
| `include` | Only the subcommands listed in `include` are exposed. |
|
|
418
|
+
| `exclude` | All subcommands except those listed in `exclude` are exposed. |
|
|
419
|
+
|
|
379
420
|
## Features
|
|
380
421
|
|
|
381
422
|
- **Auto-discovery** -- all modules in the extensions directory are found and exposed as CLI commands
|
|
@@ -390,7 +431,7 @@ cli:
|
|
|
390
431
|
- **Schema validation** -- inputs validated against JSON Schema before execution, with `$ref`/`allOf`/`anyOf`/`oneOf` resolution
|
|
391
432
|
- **Security** -- API key auth (keyring + AES-256-GCM), append-only audit logging, subprocess sandboxing
|
|
392
433
|
- **Shell completions** -- `apcore-cli apcli completion bash|zsh|fish` generates completion scripts with dynamic module ID completion
|
|
393
|
-
- **Man pages** -- `apcore-cli
|
|
434
|
+
- **Man pages** -- `apcore-cli --help --man` prints a full-program roff man page to stdout, powered by `configure_man_help()` (also exposed for embedded CLIs to opt in)
|
|
394
435
|
- **Documentation URL** -- `set_docs_url()` sets a base URL; per-command help shows `Docs: {url}/commands/{name}`, man page SEE ALSO links to the full docs site
|
|
395
436
|
- **Audit logging** -- all executions logged to `~/.apcore-cli/audit.jsonl` with SHA-256 input hashing
|
|
396
437
|
|
|
@@ -477,8 +518,8 @@ apcore-cli apcli completion bash >> ~/.bashrc
|
|
|
477
518
|
apcore-cli apcli completion zsh >> ~/.zshrc
|
|
478
519
|
apcore-cli apcli completion fish > ~/.config/fish/completions/apcore-cli.fish
|
|
479
520
|
|
|
480
|
-
# Man pages
|
|
481
|
-
apcore-cli
|
|
521
|
+
# Man pages (full-program roff output)
|
|
522
|
+
apcore-cli --help --man | man -l -
|
|
482
523
|
|
|
483
524
|
# Run all examples at once
|
|
484
525
|
bash examples/run_examples.sh
|