apcore-cli 0.2.0__tar.gz → 0.2.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.
Files changed (64) hide show
  1. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/CHANGELOG.md +24 -0
  2. apcore_cli-0.2.2/CLAUDE.md +30 -0
  3. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/PKG-INFO +23 -55
  4. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/README.md +16 -48
  5. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/planning/schema-parser.md +1 -1
  6. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/pyproject.toml +7 -7
  7. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/src/apcore_cli/__main__.py +12 -1
  8. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/src/apcore_cli/cli.py +15 -4
  9. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/src/apcore_cli/config.py +2 -1
  10. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/src/apcore_cli/schema_parser.py +5 -5
  11. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/tests/test_config.py +1 -0
  12. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/tests/test_schema_parser.py +13 -2
  13. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/.github/CODEOWNERS +0 -0
  14. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/.github/copilot-ignore +0 -0
  15. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/.github/workflows/ci.yml +0 -0
  16. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/.gitignore +0 -0
  17. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/.gitmessage +0 -0
  18. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/.pre-commit-config.yaml +0 -0
  19. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/examples/extensions/math/add.py +0 -0
  20. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/examples/extensions/math/multiply.py +0 -0
  21. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/examples/extensions/sysutil/disk.py +0 -0
  22. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/examples/extensions/sysutil/env.py +0 -0
  23. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/examples/extensions/sysutil/info.py +0 -0
  24. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/examples/extensions/text/reverse.py +0 -0
  25. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/examples/extensions/text/upper.py +0 -0
  26. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/examples/extensions/text/wordcount.py +0 -0
  27. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/examples/run_examples.sh +0 -0
  28. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/planning/approval-gate.md +0 -0
  29. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/planning/config-resolver.md +0 -0
  30. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/planning/core-dispatcher.md +0 -0
  31. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/planning/discovery.md +0 -0
  32. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/planning/output-formatter.md +0 -0
  33. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/planning/overview.md +0 -0
  34. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/planning/security-manager.md +0 -0
  35. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/planning/shell-integration.md +0 -0
  36. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/planning/state.json +0 -0
  37. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/src/apcore_cli/__init__.py +0 -0
  38. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/src/apcore_cli/_sandbox_runner.py +0 -0
  39. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/src/apcore_cli/approval.py +0 -0
  40. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/src/apcore_cli/discovery.py +0 -0
  41. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/src/apcore_cli/output.py +0 -0
  42. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/src/apcore_cli/ref_resolver.py +0 -0
  43. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/src/apcore_cli/security/__init__.py +0 -0
  44. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/src/apcore_cli/security/audit.py +0 -0
  45. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/src/apcore_cli/security/auth.py +0 -0
  46. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/src/apcore_cli/security/config_encryptor.py +0 -0
  47. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/src/apcore_cli/security/sandbox.py +0 -0
  48. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/src/apcore_cli/shell.py +0 -0
  49. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/tests/__init__.py +0 -0
  50. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/tests/conftest.py +0 -0
  51. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/tests/test_approval.py +0 -0
  52. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/tests/test_bugfixes.py +0 -0
  53. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/tests/test_cli.py +0 -0
  54. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/tests/test_discovery.py +0 -0
  55. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/tests/test_e2e.py +0 -0
  56. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/tests/test_integration.py +0 -0
  57. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/tests/test_output.py +0 -0
  58. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/tests/test_ref_resolver.py +0 -0
  59. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/tests/test_security/__init__.py +0 -0
  60. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/tests/test_security/test_audit.py +0 -0
  61. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/tests/test_security/test_auth.py +0 -0
  62. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/tests/test_security/test_config_encryptor.py +0 -0
  63. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/tests/test_security/test_sandbox.py +0 -0
  64. {apcore_cli-0.2.0 → apcore_cli-0.2.2}/tests/test_shell.py +0 -0
@@ -5,6 +5,30 @@ 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.2.2] - 2026-03-22
9
+
10
+ ### Changed
11
+ - Rebrand: aipartnerup → aiperceivable
12
+
13
+ ## [0.2.1] - 2026-03-19
14
+
15
+ ### Changed
16
+ - Help text truncation limit increased from 200 to 1000 characters (configurable via `cli.help_text_max_length` config key)
17
+ - `_extract_help`: added `max_length: int = 1000` parameter (`schema_parser.py`)
18
+ - `schema_to_click_options`: added `max_help_length: int = 1000` parameter (`schema_parser.py`)
19
+ - `build_module_command`: added `help_text_max_length: int = 1000` parameter, threaded through to schema parser (`cli.py`)
20
+ - `LazyModuleGroup`: constructor accepts `help_text_max_length: int = 1000`, passes to `build_module_command` (`cli.py`)
21
+ - `create_cli`: resolves `cli.help_text_max_length` from `ConfigResolver` and passes to `LazyModuleGroup` (`__main__.py`)
22
+ - `format_exec_result`: nested dict/list values in table mode now rendered with `json.dumps` instead of `str()` (`output.py`)
23
+
24
+ ### Added
25
+ - `cli.help_text_max_length` config key (default: 1000) in `ConfigResolver.DEFAULTS` (`config.py`)
26
+ - `APCORE_CLI_HELP_TEXT_MAX_LENGTH` environment variable support for configuring help text max length
27
+ - `test_help_truncation_default`: tests default 1000-char truncation
28
+ - `test_help_no_truncation_within_limit`: tests no truncation at 999 chars
29
+ - `test_help_truncation_custom_max`: tests custom max_length parameter
30
+ - 263 tests (up from 261)
31
+
8
32
  ## [0.2.0] - 2026-03-16
9
33
 
10
34
  ### Added
@@ -0,0 +1,30 @@
1
+ # CLAUDE.md — apcore-cli-python
2
+
3
+ ## Build & Test
4
+
5
+ - `pytest` — run all tests. **Must pass before considering any task complete.**
6
+ - `pytest --cov` — run with coverage report.
7
+ - `ruff check .` — lint check.
8
+ - `ruff format .` — format all code. **Run after every code change.**
9
+
10
+ ## Code Style
11
+
12
+ - Python 3.11+ with `from __future__ import annotations`.
13
+ - All code must pass `ruff check` and `ruff format --check`.
14
+ - Type annotations on all public function signatures.
15
+ - Use `click.echo()` for user-facing output, `logger.*` for debug/diagnostic output.
16
+ - Prefer `sys.exit(code)` with exit code constants over raising exceptions for CLI errors.
17
+
18
+ ## Project Conventions
19
+
20
+ - Spec repo (single source of truth): `../apcore-cli/docs/`
21
+ - Package structure: `src/apcore_cli/` with `__init__.py` exporting `__version__` only.
22
+ - Entry point: `apcore_cli.__main__:main`.
23
+ - Security modules live in `src/apcore_cli/security/` sub-package.
24
+ - ConfigResolver.DEFAULTS values are Python-typed (str, int, bool).
25
+ - Tests organized by module: `tests/test_<module>.py`, security tests in `tests/test_security/`.
26
+
27
+ ## Environment
28
+
29
+ - Python >= 3.11
30
+ - Key dependencies: click >= 8.0, rich >= 13.0, jsonschema >= 4.0, pyyaml >= 6.0
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: apcore-cli
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Terminal adapter for apcore — execute AI-Perceivable modules from the command line
5
- Project-URL: Homepage, https://aipartnerup.com
6
- Project-URL: Repository, https://github.com/aipartnerup/apcore-cli-python
7
- Project-URL: Documentation, https://github.com/aipartnerup/apcore-cli-python#readme
8
- Project-URL: Issues, https://github.com/aipartnerup/apcore-cli-python/issues
9
- Author-email: aipartnerup <team@aipartnerup.com>
5
+ Project-URL: Homepage, https://aiperceivable.com
6
+ Project-URL: Repository, https://github.com/aiperceivable/apcore-cli-python
7
+ Project-URL: Documentation, https://github.com/aiperceivable/apcore-cli-python#readme
8
+ Project-URL: Issues, https://github.com/aiperceivable/apcore-cli-python/issues
9
+ Author-email: aiperceivable <team@aiperceivable.com>
10
10
  License-Expression: Apache-2.0
11
11
  Keywords: agent,ai,apcore,automation,cli,command-line,llm,shell,terminal,unix
12
12
  Classifier: Development Status :: 3 - Alpha
@@ -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.13.0
23
+ Requires-Dist: apcore>=0.13.1
24
24
  Requires-Dist: click>=8.1
25
25
  Requires-Dist: cryptography>=41.0
26
26
  Requires-Dist: jsonschema>=4.20
@@ -36,7 +36,7 @@ Requires-Dist: ruff>=0.1; extra == 'dev'
36
36
  Description-Content-Type: text/markdown
37
37
 
38
38
  <div align="center">
39
- <img src="https://raw.githubusercontent.com/aipartnerup/apcore-cli/main/apcore-cli-logo.svg" alt="apcore-cli logo" width="200"/>
39
+ <img src="https://raw.githubusercontent.com/aiperceivable/apcore-cli/main/apcore-cli-logo.svg" alt="apcore-cli logo" width="200"/>
40
40
  </div>
41
41
 
42
42
  # apcore-cli
@@ -45,15 +45,15 @@ Terminal adapter for apcore. Execute AI-Perceivable modules from the command lin
45
45
 
46
46
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
47
47
  [![Python](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://python.org)
48
- [![Tests](https://img.shields.io/badge/tests-261%20passed-brightgreen.svg)]()
48
+ [![Tests](https://img.shields.io/badge/tests-263%20passed-brightgreen.svg)]()
49
49
 
50
50
  | | |
51
51
  |---|---|
52
- | **Python SDK** | [github.com/aipartnerup/apcore-cli-python](https://github.com/aipartnerup/apcore-cli-python) |
53
- | **Spec repo** | [github.com/aipartnerup/apcore-cli](https://github.com/aipartnerup/apcore-cli) |
54
- | **apcore core** | [github.com/aipartnerup/apcore](https://github.com/aipartnerup/apcore) |
52
+ | **Python SDK** | [github.com/aiperceivable/apcore-cli-python](https://github.com/aiperceivable/apcore-cli-python) |
53
+ | **Spec repo** | [github.com/aiperceivable/apcore-cli](https://github.com/aiperceivable/apcore-cli) |
54
+ | **apcore core** | [github.com/aiperceivable/apcore](https://github.com/aiperceivable/apcore) |
55
55
 
56
- **apcore-cli** turns any [apcore](https://github.com/aipartnerup/apcore)-based project into a fully featured CLI tool — with **zero code changes** to your existing modules.
56
+ **apcore-cli** turns any [apcore](https://github.com/aiperceivable/apcore)-based project into a fully featured CLI tool — with **zero code changes** to your existing modules.
57
57
 
58
58
  ```
59
59
  ┌──────────────────┐
@@ -94,7 +94,7 @@ Requires Python 3.11+ and `apcore >= 0.13.0`.
94
94
  The repo includes 8 example modules you can run immediately:
95
95
 
96
96
  ```bash
97
- git clone https://github.com/aipartnerup/apcore-cli-python.git
97
+ git clone https://github.com/aiperceivable/apcore-cli-python.git
98
98
  cd apcore-cli-python
99
99
  pip install -e ".[dev]"
100
100
 
@@ -268,6 +268,7 @@ apcore-cli uses a 4-tier configuration precedence:
268
268
  | `APCORE_LOGGING_LEVEL` | Global apcore log level (fallback when `APCORE_CLI_LOGGING_LEVEL` is unset) | `WARNING` |
269
269
  | `APCORE_AUTH_API_KEY` | API key for remote registry authentication | *(unset)* |
270
270
  | `APCORE_CLI_SANDBOX` | Set to `1` to enable subprocess sandboxing | *(unset)* |
271
+ | `APCORE_CLI_HELP_TEXT_MAX_LENGTH` | Maximum characters for CLI option help text before truncation | `1000` |
271
272
 
272
273
  ### Config File (`apcore.yaml`)
273
274
 
@@ -278,6 +279,8 @@ logging:
278
279
  level: DEBUG
279
280
  sandbox:
280
281
  enabled: false
282
+ cli:
283
+ help_text_max_length: 1000
281
284
  ```
282
285
 
283
286
  ## Features
@@ -317,10 +320,10 @@ apcore-cli (the adapter)
317
320
  |
318
321
  +-- ConfigResolver 4-tier config precedence
319
322
  +-- LazyModuleGroup Dynamic Click command generation
320
- +-- SchemaParser JSON Schema -> Click options
321
- +-- RefResolver $ref / allOf / anyOf / oneOf
322
- +-- ApprovalGate TTY-aware HITL approval
323
- +-- OutputFormatter TTY-adaptive JSON/table output
323
+ +-- schema_parser JSON Schema -> Click options
324
+ +-- ref_resolver $ref / allOf / anyOf / oneOf
325
+ +-- approval TTY-aware HITL approval
326
+ +-- output TTY-adaptive JSON/table output
324
327
  +-- AuditLogger JSON Lines execution logging
325
328
  +-- Sandbox Subprocess isolation
326
329
  |
@@ -412,49 +415,14 @@ apcore-cli --extensions-dir ./extensions greet.hello --name Alice --greeting Hi
412
415
  ## Development
413
416
 
414
417
  ```bash
415
- git clone https://github.com/aipartnerup/apcore-cli-python.git
418
+ git clone https://github.com/aiperceivable/apcore-cli-python.git
416
419
  cd apcore-cli-python
417
420
  pip install -e ".[dev]"
418
- pytest # 261 tests
421
+ pytest # 263 tests
419
422
  pytest --cov # with coverage report
420
423
  bash examples/run_examples.sh # run all examples
421
424
  ```
422
425
 
423
- ### Project Structure
424
-
425
- ```
426
- src/apcore_cli/
427
- ├── __init__.py # Package version
428
- ├── __main__.py # CLI entry point, wiring
429
- ├── cli.py # LazyModuleGroup, build_module_command, collect_input
430
- ├── config.py # ConfigResolver (4-tier precedence)
431
- ├── schema_parser.py # JSON Schema -> Click options
432
- ├── ref_resolver.py # $ref / allOf / anyOf / oneOf resolution
433
- ├── output.py # TTY-adaptive output formatting (rich)
434
- ├── discovery.py # list / describe commands
435
- ├── approval.py # HITL approval gate with timeout
436
- ├── shell.py # bash/zsh/fish completion + man pages
437
- ├── _sandbox_runner.py # Subprocess entry point for sandboxed execution
438
- └── security/
439
- ├── __init__.py # Exports
440
- ├── auth.py # API key authentication
441
- ├── config_encryptor.py # Keyring + AES-256-GCM encrypted config
442
- ├── audit.py # JSON Lines audit logging
443
- └── sandbox.py # Subprocess-based execution isolation
444
-
445
- examples/
446
- ├── run_examples.sh # Run all examples end-to-end
447
- └── extensions/
448
- ├── math/ # math.add, math.multiply
449
- ├── text/ # text.upper, text.reverse, text.wordcount
450
- └── sysutil/ # sysutil.info, sysutil.env, sysutil.disk
451
-
452
- planning/ # Implementation plans (TDD task breakdowns)
453
- ├── overview.md
454
- ├── state.json
455
- └── *.md # Per-feature plans
456
- ```
457
-
458
426
  ## License
459
427
 
460
428
  Apache-2.0
@@ -1,5 +1,5 @@
1
1
  <div align="center">
2
- <img src="https://raw.githubusercontent.com/aipartnerup/apcore-cli/main/apcore-cli-logo.svg" alt="apcore-cli logo" width="200"/>
2
+ <img src="https://raw.githubusercontent.com/aiperceivable/apcore-cli/main/apcore-cli-logo.svg" alt="apcore-cli logo" width="200"/>
3
3
  </div>
4
4
 
5
5
  # apcore-cli
@@ -8,15 +8,15 @@ Terminal adapter for apcore. Execute AI-Perceivable modules from the command lin
8
8
 
9
9
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
10
10
  [![Python](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://python.org)
11
- [![Tests](https://img.shields.io/badge/tests-261%20passed-brightgreen.svg)]()
11
+ [![Tests](https://img.shields.io/badge/tests-263%20passed-brightgreen.svg)]()
12
12
 
13
13
  | | |
14
14
  |---|---|
15
- | **Python SDK** | [github.com/aipartnerup/apcore-cli-python](https://github.com/aipartnerup/apcore-cli-python) |
16
- | **Spec repo** | [github.com/aipartnerup/apcore-cli](https://github.com/aipartnerup/apcore-cli) |
17
- | **apcore core** | [github.com/aipartnerup/apcore](https://github.com/aipartnerup/apcore) |
15
+ | **Python SDK** | [github.com/aiperceivable/apcore-cli-python](https://github.com/aiperceivable/apcore-cli-python) |
16
+ | **Spec repo** | [github.com/aiperceivable/apcore-cli](https://github.com/aiperceivable/apcore-cli) |
17
+ | **apcore core** | [github.com/aiperceivable/apcore](https://github.com/aiperceivable/apcore) |
18
18
 
19
- **apcore-cli** turns any [apcore](https://github.com/aipartnerup/apcore)-based project into a fully featured CLI tool — with **zero code changes** to your existing modules.
19
+ **apcore-cli** turns any [apcore](https://github.com/aiperceivable/apcore)-based project into a fully featured CLI tool — with **zero code changes** to your existing modules.
20
20
 
21
21
  ```
22
22
  ┌──────────────────┐
@@ -57,7 +57,7 @@ Requires Python 3.11+ and `apcore >= 0.13.0`.
57
57
  The repo includes 8 example modules you can run immediately:
58
58
 
59
59
  ```bash
60
- git clone https://github.com/aipartnerup/apcore-cli-python.git
60
+ git clone https://github.com/aiperceivable/apcore-cli-python.git
61
61
  cd apcore-cli-python
62
62
  pip install -e ".[dev]"
63
63
 
@@ -231,6 +231,7 @@ apcore-cli uses a 4-tier configuration precedence:
231
231
  | `APCORE_LOGGING_LEVEL` | Global apcore log level (fallback when `APCORE_CLI_LOGGING_LEVEL` is unset) | `WARNING` |
232
232
  | `APCORE_AUTH_API_KEY` | API key for remote registry authentication | *(unset)* |
233
233
  | `APCORE_CLI_SANDBOX` | Set to `1` to enable subprocess sandboxing | *(unset)* |
234
+ | `APCORE_CLI_HELP_TEXT_MAX_LENGTH` | Maximum characters for CLI option help text before truncation | `1000` |
234
235
 
235
236
  ### Config File (`apcore.yaml`)
236
237
 
@@ -241,6 +242,8 @@ logging:
241
242
  level: DEBUG
242
243
  sandbox:
243
244
  enabled: false
245
+ cli:
246
+ help_text_max_length: 1000
244
247
  ```
245
248
 
246
249
  ## Features
@@ -280,10 +283,10 @@ apcore-cli (the adapter)
280
283
  |
281
284
  +-- ConfigResolver 4-tier config precedence
282
285
  +-- LazyModuleGroup Dynamic Click command generation
283
- +-- SchemaParser JSON Schema -> Click options
284
- +-- RefResolver $ref / allOf / anyOf / oneOf
285
- +-- ApprovalGate TTY-aware HITL approval
286
- +-- OutputFormatter TTY-adaptive JSON/table output
286
+ +-- schema_parser JSON Schema -> Click options
287
+ +-- ref_resolver $ref / allOf / anyOf / oneOf
288
+ +-- approval TTY-aware HITL approval
289
+ +-- output TTY-adaptive JSON/table output
287
290
  +-- AuditLogger JSON Lines execution logging
288
291
  +-- Sandbox Subprocess isolation
289
292
  |
@@ -375,49 +378,14 @@ apcore-cli --extensions-dir ./extensions greet.hello --name Alice --greeting Hi
375
378
  ## Development
376
379
 
377
380
  ```bash
378
- git clone https://github.com/aipartnerup/apcore-cli-python.git
381
+ git clone https://github.com/aiperceivable/apcore-cli-python.git
379
382
  cd apcore-cli-python
380
383
  pip install -e ".[dev]"
381
- pytest # 261 tests
384
+ pytest # 263 tests
382
385
  pytest --cov # with coverage report
383
386
  bash examples/run_examples.sh # run all examples
384
387
  ```
385
388
 
386
- ### Project Structure
387
-
388
- ```
389
- src/apcore_cli/
390
- ├── __init__.py # Package version
391
- ├── __main__.py # CLI entry point, wiring
392
- ├── cli.py # LazyModuleGroup, build_module_command, collect_input
393
- ├── config.py # ConfigResolver (4-tier precedence)
394
- ├── schema_parser.py # JSON Schema -> Click options
395
- ├── ref_resolver.py # $ref / allOf / anyOf / oneOf resolution
396
- ├── output.py # TTY-adaptive output formatting (rich)
397
- ├── discovery.py # list / describe commands
398
- ├── approval.py # HITL approval gate with timeout
399
- ├── shell.py # bash/zsh/fish completion + man pages
400
- ├── _sandbox_runner.py # Subprocess entry point for sandboxed execution
401
- └── security/
402
- ├── __init__.py # Exports
403
- ├── auth.py # API key authentication
404
- ├── config_encryptor.py # Keyring + AES-256-GCM encrypted config
405
- ├── audit.py # JSON Lines audit logging
406
- └── sandbox.py # Subprocess-based execution isolation
407
-
408
- examples/
409
- ├── run_examples.sh # Run all examples end-to-end
410
- └── extensions/
411
- ├── math/ # math.add, math.multiply
412
- ├── text/ # text.upper, text.reverse, text.wordcount
413
- └── sysutil/ # sysutil.info, sysutil.env, sysutil.disk
414
-
415
- planning/ # Implementation plans (TDD task breakdowns)
416
- ├── overview.md
417
- ├── state.json
418
- └── *.md # Per-feature plans
419
- ```
420
-
421
389
  ## License
422
390
 
423
391
  Apache-2.0
@@ -83,7 +83,7 @@
83
83
  - `tests/test_schema_parser.py`:
84
84
  - `test_help_from_x_llm_description`: `x-llm-description` present → used over `description`.
85
85
  - `test_help_from_description`: Only `description` → used.
86
- - `test_help_truncation`: Description > 200 chars → truncated to 197 + "...".
86
+ - `test_help_truncation_default`: Description > 1000 chars (default) → truncated to 997 + "...".
87
87
  - `test_help_none`: No description fields → `None`.
88
88
  - `test_flag_collision_detection`: Properties `foo_bar` and `foo-bar` both map to `--foo-bar` → exit 48.
89
89
 
@@ -4,13 +4,13 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "apcore-cli"
7
- version = "0.2.0"
7
+ version = "0.2.2"
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"
11
11
  requires-python = ">=3.11"
12
12
  authors = [
13
- { name = "aipartnerup", email = "team@aipartnerup.com" },
13
+ { name = "aiperceivable", email = "team@aiperceivable.com" },
14
14
  ]
15
15
  keywords = ["apcore", "cli", "terminal", "ai", "agent", "llm", "command-line", "automation", "shell", "unix"]
16
16
  classifiers = [
@@ -26,7 +26,7 @@ classifiers = [
26
26
  "Environment :: Console",
27
27
  ]
28
28
  dependencies = [
29
- "apcore>=0.13.0",
29
+ "apcore>=0.13.1",
30
30
  "click>=8.1",
31
31
  "jsonschema>=4.20",
32
32
  "rich>=13.0",
@@ -48,10 +48,10 @@ dev = [
48
48
  apcore-cli = "apcore_cli.__main__:main"
49
49
 
50
50
  [project.urls]
51
- Homepage = "https://aipartnerup.com"
52
- Repository = "https://github.com/aipartnerup/apcore-cli-python"
53
- Documentation = "https://github.com/aipartnerup/apcore-cli-python#readme"
54
- Issues = "https://github.com/aipartnerup/apcore-cli-python/issues"
51
+ Homepage = "https://aiperceivable.com"
52
+ Repository = "https://github.com/aiperceivable/apcore-cli-python"
53
+ Documentation = "https://github.com/aiperceivable/apcore-cli-python#readme"
54
+ Issues = "https://github.com/aiperceivable/apcore-cli-python/issues"
55
55
 
56
56
  [tool.hatch.build.targets.wheel]
57
57
  packages = ["src/apcore_cli"]
@@ -65,16 +65,26 @@ def create_cli(extensions_dir: str | None = None, prog_name: str | None = None)
65
65
  apcore_level = _default_level if _default_level <= logging.INFO else logging.ERROR
66
66
  logging.getLogger("apcore").setLevel(apcore_level)
67
67
 
68
+ config = ConfigResolver()
69
+
68
70
  if extensions_dir is not None:
69
71
  ext_dir = extensions_dir
70
72
  else:
71
- config = ConfigResolver()
72
73
  ext_dir = config.resolve(
73
74
  "extensions.root",
74
75
  cli_flag="--extensions-dir",
75
76
  env_var="APCORE_EXTENSIONS_ROOT",
76
77
  )
77
78
 
79
+ help_text_max_length = config.resolve(
80
+ "cli.help_text_max_length",
81
+ env_var="APCORE_CLI_HELP_TEXT_MAX_LENGTH",
82
+ )
83
+ try:
84
+ help_text_max_length = int(help_text_max_length)
85
+ except (TypeError, ValueError):
86
+ help_text_max_length = 1000
87
+
78
88
  ext_dir_missing = not os.path.exists(ext_dir)
79
89
  ext_dir_unreadable = not ext_dir_missing and not os.access(ext_dir, os.R_OK)
80
90
 
@@ -119,6 +129,7 @@ def create_cli(extensions_dir: str | None = None, prog_name: str | None = None)
119
129
  cls=LazyModuleGroup,
120
130
  registry=registry,
121
131
  executor=executor,
132
+ help_text_max_length=help_text_max_length,
122
133
  name=prog_name,
123
134
  help="CLI adapter for the apcore module ecosystem.",
124
135
  )
@@ -41,10 +41,17 @@ def set_audit_logger(audit_logger: AuditLogger | None) -> None:
41
41
  class LazyModuleGroup(click.Group):
42
42
  """Custom Click Group that lazily loads apcore modules as subcommands."""
43
43
 
44
- def __init__(self, registry: Registry, executor: Executor, **kwargs: Any) -> None:
44
+ def __init__(
45
+ self,
46
+ registry: Registry,
47
+ executor: Executor,
48
+ help_text_max_length: int = 1000,
49
+ **kwargs: Any,
50
+ ) -> None:
45
51
  super().__init__(**kwargs)
46
52
  self._registry = registry
47
53
  self._executor = executor
54
+ self._help_text_max_length = help_text_max_length
48
55
  self._module_cache: dict[str, click.Command] = {}
49
56
 
50
57
  def list_commands(self, ctx: click.Context) -> list[str]:
@@ -70,7 +77,7 @@ class LazyModuleGroup(click.Group):
70
77
  if module_def is None:
71
78
  return None
72
79
 
73
- cmd = build_module_command(module_def, self._executor)
80
+ cmd = build_module_command(module_def, self._executor, help_text_max_length=self._help_text_max_length)
74
81
  self._module_cache[cmd_name] = cmd
75
82
  return cmd
76
83
 
@@ -101,7 +108,11 @@ def _get_module_id(module_def: ModuleDescriptor) -> str:
101
108
  return module_def.module_id
102
109
 
103
110
 
104
- def build_module_command(module_def: ModuleDescriptor, executor: Executor) -> click.Command:
111
+ def build_module_command(
112
+ module_def: ModuleDescriptor,
113
+ executor: Executor,
114
+ help_text_max_length: int = 1000,
115
+ ) -> click.Command:
105
116
  """Build a Click command from an apcore module definition.
106
117
 
107
118
  Generates Click options from the module's input_schema, wires up
@@ -137,7 +148,7 @@ def build_module_command(module_def: ModuleDescriptor, executor: Executor) -> cl
137
148
  else:
138
149
  resolved_schema = input_schema
139
150
 
140
- schema_options = schema_to_click_options(resolved_schema)
151
+ schema_options = schema_to_click_options(resolved_schema, max_help_length=help_text_max_length)
141
152
 
142
153
  def callback(**kwargs: Any) -> None:
143
154
  # Separate built-in options from schema-generated kwargs
@@ -18,10 +18,11 @@ class ConfigResolver:
18
18
 
19
19
  DEFAULTS: dict[str, Any] = {
20
20
  "extensions.root": "./extensions",
21
- "logging.level": "INFO",
21
+ "logging.level": "WARNING",
22
22
  "sandbox.enabled": False,
23
23
  "cli.stdin_buffer_limit": 10_485_760, # 10 MB
24
24
  "cli.auto_approve": False,
25
+ "cli.help_text_max_length": 1000,
25
26
  }
26
27
 
27
28
  def __init__(
@@ -50,19 +50,19 @@ def _map_type(prop_name: str, prop_schema: dict) -> Any:
50
50
  return result
51
51
 
52
52
 
53
- def _extract_help(prop_schema: dict) -> str | None:
53
+ def _extract_help(prop_schema: dict, max_length: int = 1000) -> str | None:
54
54
  """Extract help text from schema property, preferring x-llm-description."""
55
55
  text = prop_schema.get("x-llm-description")
56
56
  if not text:
57
57
  text = prop_schema.get("description")
58
58
  if not text:
59
59
  return None
60
- if len(text) > 200:
61
- return text[:197] + "..."
60
+ if max_length > 0 and len(text) > max_length:
61
+ return text[: max_length - 3] + "..."
62
62
  return text
63
63
 
64
64
 
65
- def schema_to_click_options(schema: dict) -> list[click.Option]:
65
+ def schema_to_click_options(schema: dict, max_help_length: int = 1000) -> list[click.Option]:
66
66
  """Convert JSON Schema properties to a list of Click options."""
67
67
  properties = schema.get("properties", {})
68
68
  required_list = schema.get("required", [])
@@ -93,7 +93,7 @@ def schema_to_click_options(schema: dict) -> list[click.Option]:
93
93
 
94
94
  click_type = _map_type(prop_name, prop_schema)
95
95
  is_required = prop_name in required_list
96
- _help_base = _extract_help(prop_schema)
96
+ _help_base = _extract_help(prop_schema, max_length=max_help_length)
97
97
  # Append [required] to help text for user clarity; do NOT set required=True
98
98
  # at the Click level because that would block --input - (STDIN) from working.
99
99
  # Schema-level required validation happens in the callback via jsonschema.validate().
@@ -26,6 +26,7 @@ class TestConfigResolverSkeleton:
26
26
  "logging.level",
27
27
  "sandbox.enabled",
28
28
  "cli.stdin_buffer_limit",
29
+ "cli.help_text_max_length",
29
30
  ]
30
31
  for key in expected_keys:
31
32
  assert key in resolver.DEFAULTS, f"Missing default key: {key}"
@@ -205,9 +205,20 @@ class TestHelpAndCollisions:
205
205
  result = _extract_help({"description": "Regular help"})
206
206
  assert result == "Regular help"
207
207
 
208
- def test_help_truncation(self):
209
- long_text = "x" * 250
208
+ def test_help_truncation_default(self):
209
+ long_text = "x" * 1100
210
210
  result = _extract_help({"description": long_text})
211
+ assert len(result) == 1000
212
+ assert result.endswith("...")
213
+
214
+ def test_help_no_truncation_within_limit(self):
215
+ text = "x" * 999
216
+ result = _extract_help({"description": text})
217
+ assert result == text
218
+
219
+ def test_help_truncation_custom_max(self):
220
+ long_text = "x" * 300
221
+ result = _extract_help({"description": long_text}, max_length=200)
211
222
  assert len(result) == 200
212
223
  assert result.endswith("...")
213
224
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes