apcore-cli 0.3.0__tar.gz → 0.3.1__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.3.0 → apcore_cli-0.3.1}/CHANGELOG.md +20 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/PKG-INFO +3 -3
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/README.md +1 -1
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/pyproject.toml +2 -2
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/src/apcore_cli/__main__.py +29 -3
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/src/apcore_cli/cli.py +1 -1
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/src/apcore_cli/init_cmd.py +5 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/src/apcore_cli/shell.py +8 -2
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/.github/CODEOWNERS +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/.github/copilot-ignore +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/.github/workflows/ci.yml +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/.gitignore +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/.gitmessage +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/.pre-commit-config.yaml +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/CLAUDE.md +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/commands/ops.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/examples/extensions/math/add.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/examples/extensions/math/multiply.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/examples/extensions/sysutil/disk.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/examples/extensions/sysutil/env.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/examples/extensions/sysutil/info.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/examples/extensions/text/reverse.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/examples/extensions/text/upper.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/examples/extensions/text/wordcount.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/examples/run_examples.sh +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/planning/approval-gate.md +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/planning/config-resolver.md +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/planning/core-dispatcher.md +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/planning/discovery.md +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/planning/grouped-commands.md +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/planning/output-formatter.md +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/planning/overview.md +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/planning/schema-parser.md +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/planning/security-manager.md +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/planning/shell-integration.md +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/planning/state.json +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/src/apcore_cli/__init__.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/src/apcore_cli/_sandbox_runner.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/src/apcore_cli/approval.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/src/apcore_cli/config.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/src/apcore_cli/discovery.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/src/apcore_cli/display_helpers.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/src/apcore_cli/output.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/src/apcore_cli/ref_resolver.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/src/apcore_cli/schema_parser.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/src/apcore_cli/security/__init__.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/src/apcore_cli/security/audit.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/src/apcore_cli/security/auth.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/src/apcore_cli/security/config_encryptor.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/src/apcore_cli/security/sandbox.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/tests/__init__.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/tests/conftest.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/tests/test_approval.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/tests/test_bugfixes.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/tests/test_cli.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/tests/test_config.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/tests/test_discovery.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/tests/test_e2e.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/tests/test_init_cmd.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/tests/test_integration.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/tests/test_output.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/tests/test_ref_resolver.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/tests/test_schema_parser.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/tests/test_security/__init__.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/tests/test_security/test_audit.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/tests/test_security/test_auth.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/tests/test_security/test_config_encryptor.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/tests/test_security/test_sandbox.py +0 -0
- {apcore_cli-0.3.0 → apcore_cli-0.3.1}/tests/test_shell.py +0 -0
|
@@ -5,6 +5,26 @@ All notable changes to apcore-cli (Python SDK) will be documented in this file.
|
|
|
5
5
|
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
|
+
## [0.3.1] - 2026-03-27
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **DisplayResolver integration** — `__main__.py` integrates `DisplayResolver` from `apcore-toolkit` (optional) when `--binding` option is provided; gracefully skipped when not installed.
|
|
13
|
+
- **`init` to `BUILTIN_COMMANDS`** — `init` subcommand is now registered in the builtin commands set.
|
|
14
|
+
- **`APCORE_AUTH_API_KEY` to man page** — environment variable documented in generated roff man page.
|
|
15
|
+
- **Grouped shell completion with `_APCORE_GRP`** — bash/zsh/fish completion scripts now support two-level group/command completion via the `_APCORE_GRP` environment variable (`shell.py`).
|
|
16
|
+
- **Path traversal validation for `--dir` in `init` command** — rejects paths containing `..` segments to prevent directory escape (`init_cmd.py`).
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- **`RegistryWriter` API call** — constructor now called without parameters; fixes `TypeError` introduced by upstream API change.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- `apcore` dependency bumped to `>=0.14.0`.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
8
28
|
## [0.3.0] - 2026-03-23
|
|
9
29
|
|
|
10
30
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: apcore-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
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
|
|
@@ -20,7 +20,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
20
20
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
21
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
22
|
Requires-Python: >=3.11
|
|
23
|
-
Requires-Dist: apcore>=0.
|
|
23
|
+
Requires-Dist: apcore>=0.14.0
|
|
24
24
|
Requires-Dist: click>=8.1
|
|
25
25
|
Requires-Dist: cryptography>=41.0
|
|
26
26
|
Requires-Dist: jsonschema>=4.20
|
|
@@ -85,7 +85,7 @@ Terminal adapter for apcore. Execute AI-Perceivable modules from the command lin
|
|
|
85
85
|
pip install apcore-cli
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
Requires Python 3.11+ and `apcore >= 0.
|
|
88
|
+
Requires Python 3.11+ and `apcore >= 0.14.0`.
|
|
89
89
|
|
|
90
90
|
## Quick Start
|
|
91
91
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "apcore-cli"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.1"
|
|
8
8
|
description = "Terminal adapter for apcore — execute AI-Perceivable modules from the command line"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "Apache-2.0"
|
|
@@ -26,7 +26,7 @@ classifiers = [
|
|
|
26
26
|
"Environment :: Console",
|
|
27
27
|
]
|
|
28
28
|
dependencies = [
|
|
29
|
-
"apcore>=0.
|
|
29
|
+
"apcore>=0.14.0",
|
|
30
30
|
"click>=8.1",
|
|
31
31
|
"jsonschema>=4.20",
|
|
32
32
|
"rich>=13.0",
|
|
@@ -45,10 +45,16 @@ def _extract_commands_dir(argv: list[str] | None = None) -> str | None:
|
|
|
45
45
|
return _extract_argv_option(argv, "--commands-dir")
|
|
46
46
|
|
|
47
47
|
|
|
48
|
+
def _extract_binding_path(argv: list[str] | None = None) -> str | None:
|
|
49
|
+
"""Extract --binding value from argv before Click parses it."""
|
|
50
|
+
return _extract_argv_option(argv, "--binding")
|
|
51
|
+
|
|
52
|
+
|
|
48
53
|
def create_cli(
|
|
49
54
|
extensions_dir: str | None = None,
|
|
50
55
|
prog_name: str | None = None,
|
|
51
56
|
commands_dir: str | None = None,
|
|
57
|
+
binding_path: str | None = None,
|
|
52
58
|
) -> click.Group:
|
|
53
59
|
"""Create the CLI application.
|
|
54
60
|
|
|
@@ -62,6 +68,9 @@ def create_cli(
|
|
|
62
68
|
commands_dir: Directory containing convention-based modules.
|
|
63
69
|
When set, scans for plain-function modules and registers
|
|
64
70
|
them via ConventionScanner (requires apcore-toolkit).
|
|
71
|
+
binding_path: Path to binding.yaml file or directory for display resolution.
|
|
72
|
+
When set, applies DisplayResolver to convention-scanned modules
|
|
73
|
+
(requires apcore-toolkit).
|
|
65
74
|
"""
|
|
66
75
|
if prog_name is None:
|
|
67
76
|
prog_name = os.path.basename(sys.argv[0]) or "apcore-cli"
|
|
@@ -138,8 +147,17 @@ def create_cli(
|
|
|
138
147
|
conv_scanner = ConventionScanner()
|
|
139
148
|
conv_modules = conv_scanner.scan(commands_dir)
|
|
140
149
|
if conv_modules:
|
|
141
|
-
|
|
142
|
-
|
|
150
|
+
if binding_path is not None:
|
|
151
|
+
try:
|
|
152
|
+
from apcore_toolkit import DisplayResolver
|
|
153
|
+
|
|
154
|
+
display_resolver = DisplayResolver()
|
|
155
|
+
conv_modules = display_resolver.resolve(conv_modules, binding_path=binding_path)
|
|
156
|
+
logger.info("DisplayResolver: applied binding from %s", binding_path)
|
|
157
|
+
except ImportError:
|
|
158
|
+
logger.warning("DisplayResolver not available in apcore-toolkit")
|
|
159
|
+
writer = RegistryWriter()
|
|
160
|
+
writer.write(conv_modules, registry)
|
|
143
161
|
logger.info("Convention scanner: registered %d modules from %s", len(conv_modules), commands_dir)
|
|
144
162
|
except ImportError:
|
|
145
163
|
logger.warning("apcore-toolkit not installed — convention module scanning unavailable")
|
|
@@ -182,6 +200,12 @@ def create_cli(
|
|
|
182
200
|
default=None,
|
|
183
201
|
help="Path to convention-based commands directory.",
|
|
184
202
|
)
|
|
203
|
+
@click.option(
|
|
204
|
+
"--binding",
|
|
205
|
+
"binding_opt",
|
|
206
|
+
default=None,
|
|
207
|
+
help="Path to binding.yaml file or directory for display resolution.",
|
|
208
|
+
)
|
|
185
209
|
@click.option(
|
|
186
210
|
"--log-level",
|
|
187
211
|
default=None,
|
|
@@ -193,6 +217,7 @@ def create_cli(
|
|
|
193
217
|
ctx: click.Context,
|
|
194
218
|
extensions_dir_opt: str | None = None,
|
|
195
219
|
commands_dir_opt: str | None = None,
|
|
220
|
+
binding_opt: str | None = None,
|
|
196
221
|
log_level: str | None = None,
|
|
197
222
|
) -> None:
|
|
198
223
|
if log_level is not None:
|
|
@@ -228,7 +253,8 @@ def main(prog_name: str | None = None) -> None:
|
|
|
228
253
|
"""
|
|
229
254
|
ext_dir = _extract_extensions_dir()
|
|
230
255
|
cmd_dir = _extract_commands_dir()
|
|
231
|
-
|
|
256
|
+
bind_path = _extract_binding_path()
|
|
257
|
+
cli = create_cli(extensions_dir=ext_dir, prog_name=prog_name, commands_dir=cmd_dir, binding_path=bind_path)
|
|
232
258
|
cli(standalone_mode=True)
|
|
233
259
|
|
|
234
260
|
|
|
@@ -27,7 +27,7 @@ if TYPE_CHECKING:
|
|
|
27
27
|
|
|
28
28
|
logger = logging.getLogger("apcore_cli.cli")
|
|
29
29
|
|
|
30
|
-
BUILTIN_COMMANDS = ["
|
|
30
|
+
BUILTIN_COMMANDS = ["completion", "describe", "exec", "init", "list", "man"]
|
|
31
31
|
|
|
32
32
|
# Module-level audit logger, set during CLI init
|
|
33
33
|
_audit_logger: AuditLogger | None = None
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import sys
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
|
|
7
8
|
import click
|
|
@@ -59,6 +60,10 @@ def register_init_command(cli: click.Group) -> None:
|
|
|
59
60
|
|
|
60
61
|
MODULE_ID is the module identifier (e.g., ops.deploy, user.create).
|
|
61
62
|
"""
|
|
63
|
+
if output_dir is not None and ".." in Path(output_dir).parts:
|
|
64
|
+
click.echo("Error: Output directory must not contain '..' path components.", err=True)
|
|
65
|
+
sys.exit(2)
|
|
66
|
+
|
|
62
67
|
# Parse module_id into parts
|
|
63
68
|
parts = module_id.rsplit(".", 1)
|
|
64
69
|
if len(parts) == 2:
|
|
@@ -59,7 +59,7 @@ def _generate_bash_completion(prog_name: str) -> str:
|
|
|
59
59
|
"\n"
|
|
60
60
|
" if [[ ${COMP_CWORD} -eq 1 ]]; then\n"
|
|
61
61
|
f" local all_ids=$({groups_and_top_cmd})\n"
|
|
62
|
-
' local builtins="exec list
|
|
62
|
+
' local builtins="completion describe exec init list man"\n'
|
|
63
63
|
' COMPREPLY=( $(compgen -W "${builtins} ${all_ids}" -- ${cur}) )\n'
|
|
64
64
|
" return 0\n"
|
|
65
65
|
" fi\n"
|
|
@@ -124,6 +124,7 @@ def _generate_zsh_completion(prog_name: str) -> str:
|
|
|
124
124
|
" 'list:List available modules'\n"
|
|
125
125
|
" 'describe:Show module metadata and schema'\n"
|
|
126
126
|
" 'completion:Generate shell completion script'\n"
|
|
127
|
+
" 'init:Scaffolding commands'\n"
|
|
127
128
|
" 'man:Generate man page'\n"
|
|
128
129
|
" )\n"
|
|
129
130
|
"\n"
|
|
@@ -208,6 +209,8 @@ def _generate_fish_completion(prog_name: str) -> str:
|
|
|
208
209
|
f'complete -c {quoted} -n "__fish_use_subcommand"'
|
|
209
210
|
' -a completion -d "Generate shell completion script"\n'
|
|
210
211
|
f'complete -c {quoted} -n "__fish_use_subcommand"'
|
|
212
|
+
' -a init -d "Scaffolding commands"\n'
|
|
213
|
+
f'complete -c {quoted} -n "__fish_use_subcommand"'
|
|
211
214
|
' -a man -d "Generate man page"\n'
|
|
212
215
|
f'complete -c {quoted} -n "__fish_use_subcommand"'
|
|
213
216
|
f' -a "({groups_and_top_cmd})" -d "Module group or command"\n'
|
|
@@ -304,6 +307,9 @@ def _generate_man_page(command_name: str, command: click.Command | None, prog_na
|
|
|
304
307
|
"Global apcore logging verbosity. One of: DEBUG, INFO, WARNING, ERROR. "
|
|
305
308
|
"Used as fallback when \\fBAPCORE_CLI_LOGGING_LEVEL\\fR is not set. Default: WARNING."
|
|
306
309
|
)
|
|
310
|
+
sections.append(".TP")
|
|
311
|
+
sections.append("\\fBAPCORE_AUTH_API_KEY\\fR")
|
|
312
|
+
sections.append("API key for authenticating with the apcore registry.")
|
|
307
313
|
|
|
308
314
|
sections.append(".SH EXIT CODES")
|
|
309
315
|
exit_codes = [
|
|
@@ -380,7 +386,7 @@ def register_shell_commands(cli: click.Group, prog_name: str = "apcore-cli") ->
|
|
|
380
386
|
parent_group = parent.command
|
|
381
387
|
cmd = parent_group.commands.get(command) if isinstance(parent_group, click.Group) else None
|
|
382
388
|
|
|
383
|
-
known_builtins = {"
|
|
389
|
+
known_builtins = {"completion", "describe", "exec", "init", "list", "man"}
|
|
384
390
|
if cmd is None and command not in known_builtins:
|
|
385
391
|
click.echo(f"Error: Unknown command '{command}'.", err=True)
|
|
386
392
|
sys.exit(2)
|
|
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
|