humancli 0.2.0__tar.gz → 0.4.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.
- {humancli-0.2.0 → humancli-0.4.0}/.agents/skills/release/SKILL.md +3 -3
- {humancli-0.2.0 → humancli-0.4.0}/.github/workflows/release.yml +2 -2
- {humancli-0.2.0 → humancli-0.4.0}/PKG-INFO +8 -8
- {humancli-0.2.0 → humancli-0.4.0}/README.md +7 -7
- {humancli-0.2.0 → humancli-0.4.0}/pyproject.toml +2 -2
- {humancli-0.2.0/src/agentcli → humancli-0.4.0/src/humancli}/__init__.py +2 -2
- {humancli-0.2.0/src/agentcli → humancli-0.4.0/src/humancli}/_errors.py +2 -2
- {humancli-0.2.0/src/agentcli → humancli-0.4.0/src/humancli}/_output.py +23 -14
- humancli-0.2.0/tests/test_agentcli.py → humancli-0.4.0/tests/test_humancli.py +2 -2
- {humancli-0.2.0 → humancli-0.4.0}/uv.lock +1 -1
- {humancli-0.2.0 → humancli-0.4.0}/.agents/AGENTS.md +0 -0
- {humancli-0.2.0 → humancli-0.4.0}/.github/workflows/ci.yml +0 -0
- {humancli-0.2.0 → humancli-0.4.0}/.gitignore +0 -0
- {humancli-0.2.0 → humancli-0.4.0}/.python-version +0 -0
- {humancli-0.2.0 → humancli-0.4.0}/LICENSE +0 -0
- {humancli-0.2.0/src/agentcli → humancli-0.4.0/src/humancli}/_agents.py +0 -0
- {humancli-0.2.0/src/agentcli → humancli-0.4.0/src/humancli}/_app.py +0 -0
- {humancli-0.2.0/src/agentcli → humancli-0.4.0/src/humancli}/_context.py +0 -0
- {humancli-0.2.0/src/agentcli → humancli-0.4.0/src/humancli}/_help.py +0 -0
- {humancli-0.2.0/src/agentcli → humancli-0.4.0/src/humancli}/_parser.py +0 -0
- {humancli-0.2.0/src/agentcli → humancli-0.4.0/src/humancli}/_schema.py +0 -0
- {humancli-0.2.0/src/agentcli → humancli-0.4.0/src/humancli}/_types.py +0 -0
- {humancli-0.2.0/src/agentcli → humancli-0.4.0/src/humancli}/_wizard.py +0 -0
- {humancli-0.2.0/src/agentcli → humancli-0.4.0/src/humancli}/prompt.py +0 -0
- {humancli-0.2.0/src/agentcli → humancli-0.4.0/src/humancli}/py.typed +0 -0
- {humancli-0.2.0/src/agentcli → humancli-0.4.0/src/humancli}/testing.py +0 -0
|
@@ -7,7 +7,7 @@ description: Prepare and ship an agentcli release. Use when asked to cut a relea
|
|
|
7
7
|
|
|
8
8
|
## Overview
|
|
9
9
|
|
|
10
|
-
Prepare a tagged release that matches the GitHub Actions release workflow. The workflow requires the tag version to match both `pyproject.toml` and `src/
|
|
10
|
+
Prepare a tagged release that matches the GitHub Actions release workflow. The workflow requires the tag version to match both `pyproject.toml` and `src/humancli/__init__.py`.
|
|
11
11
|
|
|
12
12
|
## Workflow
|
|
13
13
|
|
|
@@ -21,7 +21,7 @@ If the current version has a `.dev` suffix, assume the target release version is
|
|
|
21
21
|
Update version strings to match the release tag:
|
|
22
22
|
|
|
23
23
|
- `pyproject.toml`: `project.version = "<major.minor.patch>"`
|
|
24
|
-
- `src/
|
|
24
|
+
- `src/humancli/__init__.py`: `__version__ = "<major.minor.patch>"`
|
|
25
25
|
- `uv.lock`: refresh so the root package version matches (run `uv lock` or `uv sync`).
|
|
26
26
|
|
|
27
27
|
### 3) Run checks
|
|
@@ -45,4 +45,4 @@ If you keep a dev version between releases, bump the minor version (reset patch
|
|
|
45
45
|
|
|
46
46
|
## Notes
|
|
47
47
|
|
|
48
|
-
- The release workflow checks that the tag matches `pyproject.toml` and `src/
|
|
48
|
+
- The release workflow checks that the tag matches `pyproject.toml` and `src/humancli/__init__.py`.
|
|
@@ -36,7 +36,7 @@ jobs:
|
|
|
36
36
|
project_version = pyproject['project']['version']
|
|
37
37
|
|
|
38
38
|
init_version = None
|
|
39
|
-
init_path = Path('src') / '
|
|
39
|
+
init_path = Path('src') / 'humancli' / '__init__.py'
|
|
40
40
|
if init_path.is_file():
|
|
41
41
|
m = re.search(r'__version__\s*=\s*"([^"]+)"', init_path.read_text(encoding='utf-8'))
|
|
42
42
|
if m:
|
|
@@ -46,7 +46,7 @@ jobs:
|
|
|
46
46
|
raise SystemExit(f"Tag {tag!r} does not match pyproject version {project_version!r}")
|
|
47
47
|
if init_version and init_version != project_version:
|
|
48
48
|
raise SystemExit(
|
|
49
|
-
f"src/
|
|
49
|
+
f"src/humancli/__init__.py __version__ {init_version!r} does not match pyproject version {project_version!r}"
|
|
50
50
|
)
|
|
51
51
|
|
|
52
52
|
print(f"OK: tag {tag!r} matches version {project_version!r}")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: humancli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Python CLIs for agents and humans
|
|
5
5
|
Project-URL: Repository, https://github.com/elyase/agentcli
|
|
6
6
|
Project-URL: Issues, https://github.com/elyase/agentcli/issues
|
|
@@ -47,10 +47,10 @@ agentcli builds command-line interfaces that produce structured, parseable outpu
|
|
|
47
47
|
pip install humancli
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
The package installs as `humancli` on PyPI
|
|
50
|
+
The package installs as `humancli` on PyPI and you import it as `humancli`:
|
|
51
51
|
|
|
52
52
|
```python
|
|
53
|
-
from
|
|
53
|
+
from humancli import App
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
## Quick start
|
|
@@ -58,7 +58,7 @@ from agentcli import App
|
|
|
58
58
|
### Single function
|
|
59
59
|
|
|
60
60
|
```python
|
|
61
|
-
from
|
|
61
|
+
from humancli import run
|
|
62
62
|
|
|
63
63
|
def greet(name: str):
|
|
64
64
|
"""Greet someone."""
|
|
@@ -84,7 +84,7 @@ $ greet --llms
|
|
|
84
84
|
### Multi-command app
|
|
85
85
|
|
|
86
86
|
```python
|
|
87
|
-
from
|
|
87
|
+
from humancli import App
|
|
88
88
|
|
|
89
89
|
app = App("my-cli", version="1.0.0")
|
|
90
90
|
|
|
@@ -107,7 +107,7 @@ Parameters before `*` are positional arguments. Parameters after `*` are named o
|
|
|
107
107
|
|
|
108
108
|
```python
|
|
109
109
|
from typing import Annotated, Literal
|
|
110
|
-
from
|
|
110
|
+
from humancli import App, Param
|
|
111
111
|
|
|
112
112
|
app = App("deploy-cli")
|
|
113
113
|
|
|
@@ -156,12 +156,12 @@ def fetch_cases(*, limit: int = 20):
|
|
|
156
156
|
|
|
157
157
|
## Agent discovery
|
|
158
158
|
|
|
159
|
-
Every
|
|
159
|
+
Every humancli app gets built-in flags for agent consumption:
|
|
160
160
|
|
|
161
161
|
- `--llms` — markdown command index
|
|
162
162
|
- `--llms-full` — full JSON schema of all commands
|
|
163
163
|
- `--json` / `--yaml` / `--jsonl` — structured output formats
|
|
164
|
-
- `--mcp` — start as an MCP server (requires `
|
|
164
|
+
- `--mcp` — start as an MCP server (requires `humancli[mcp]`)
|
|
165
165
|
|
|
166
166
|
## Optional extras
|
|
167
167
|
|
|
@@ -10,10 +10,10 @@ agentcli builds command-line interfaces that produce structured, parseable outpu
|
|
|
10
10
|
pip install humancli
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
The package installs as `humancli` on PyPI
|
|
13
|
+
The package installs as `humancli` on PyPI and you import it as `humancli`:
|
|
14
14
|
|
|
15
15
|
```python
|
|
16
|
-
from
|
|
16
|
+
from humancli import App
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
## Quick start
|
|
@@ -21,7 +21,7 @@ from agentcli import App
|
|
|
21
21
|
### Single function
|
|
22
22
|
|
|
23
23
|
```python
|
|
24
|
-
from
|
|
24
|
+
from humancli import run
|
|
25
25
|
|
|
26
26
|
def greet(name: str):
|
|
27
27
|
"""Greet someone."""
|
|
@@ -47,7 +47,7 @@ $ greet --llms
|
|
|
47
47
|
### Multi-command app
|
|
48
48
|
|
|
49
49
|
```python
|
|
50
|
-
from
|
|
50
|
+
from humancli import App
|
|
51
51
|
|
|
52
52
|
app = App("my-cli", version="1.0.0")
|
|
53
53
|
|
|
@@ -70,7 +70,7 @@ Parameters before `*` are positional arguments. Parameters after `*` are named o
|
|
|
70
70
|
|
|
71
71
|
```python
|
|
72
72
|
from typing import Annotated, Literal
|
|
73
|
-
from
|
|
73
|
+
from humancli import App, Param
|
|
74
74
|
|
|
75
75
|
app = App("deploy-cli")
|
|
76
76
|
|
|
@@ -119,12 +119,12 @@ def fetch_cases(*, limit: int = 20):
|
|
|
119
119
|
|
|
120
120
|
## Agent discovery
|
|
121
121
|
|
|
122
|
-
Every
|
|
122
|
+
Every humancli app gets built-in flags for agent consumption:
|
|
123
123
|
|
|
124
124
|
- `--llms` — markdown command index
|
|
125
125
|
- `--llms-full` — full JSON schema of all commands
|
|
126
126
|
- `--json` / `--yaml` / `--jsonl` — structured output formats
|
|
127
|
-
- `--mcp` — start as an MCP server (requires `
|
|
127
|
+
- `--mcp` — start as an MCP server (requires `humancli[mcp]`)
|
|
128
128
|
|
|
129
129
|
## Optional extras
|
|
130
130
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "humancli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.4.0"
|
|
4
4
|
description = "Python CLIs for agents and humans"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -44,7 +44,7 @@ requires = ["hatchling"]
|
|
|
44
44
|
build-backend = "hatchling.build"
|
|
45
45
|
|
|
46
46
|
[tool.hatch.build.targets.wheel]
|
|
47
|
-
packages = ["src/
|
|
47
|
+
packages = ["src/humancli"]
|
|
48
48
|
|
|
49
49
|
[tool.pytest.ini_options]
|
|
50
50
|
testpaths = ["tests"]
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""humancli: Python CLIs for agents and humans."""
|
|
2
2
|
|
|
3
3
|
from ._app import App, run
|
|
4
4
|
from ._context import Context
|
|
5
5
|
from ._errors import AgentCliError, ConfigError, ParseError, ValidationError
|
|
6
6
|
from ._types import Param, Result
|
|
7
7
|
|
|
8
|
-
__version__ = "0.
|
|
8
|
+
__version__ = "0.4.0"
|
|
9
9
|
|
|
10
10
|
__all__ = [
|
|
11
11
|
"AgentCliError",
|
|
@@ -31,13 +31,13 @@ class AgentCliError(Exception):
|
|
|
31
31
|
self.exit_code = exit_code
|
|
32
32
|
|
|
33
33
|
def to_error_info(self) -> ErrorInfo:
|
|
34
|
-
from ._output import ErrorInfo
|
|
34
|
+
from ._output import ErrorInfo, _make_cta
|
|
35
35
|
|
|
36
36
|
return ErrorInfo(
|
|
37
37
|
code=self.code,
|
|
38
38
|
message=self.message,
|
|
39
39
|
retryable=self.retryable,
|
|
40
|
-
|
|
40
|
+
cta=_make_cta(self.cta, description="To fix this:"),
|
|
41
41
|
)
|
|
42
42
|
|
|
43
43
|
|
|
@@ -2,24 +2,30 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import dataclasses
|
|
4
4
|
import json
|
|
5
|
-
from dataclasses import dataclass
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
8
|
from ._errors import AgentCliError
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
@dataclass(frozen=True)
|
|
12
|
+
class CtaBlock:
|
|
13
|
+
description: str = "Suggested commands:"
|
|
14
|
+
commands: list[str] = field(default_factory=list)
|
|
15
|
+
|
|
16
|
+
|
|
11
17
|
@dataclass(frozen=True)
|
|
12
18
|
class ErrorInfo:
|
|
13
19
|
code: str
|
|
14
20
|
message: str
|
|
15
21
|
retryable: bool = False
|
|
16
|
-
|
|
22
|
+
cta: CtaBlock | None = None
|
|
17
23
|
|
|
18
24
|
|
|
19
25
|
@dataclass
|
|
20
26
|
class Meta:
|
|
21
27
|
command: str
|
|
22
|
-
|
|
28
|
+
cta: CtaBlock | None = None
|
|
23
29
|
duration_ms: float | None = None
|
|
24
30
|
streamed: bool = False
|
|
25
31
|
|
|
@@ -32,32 +38,35 @@ class Envelope:
|
|
|
32
38
|
meta: Meta | None = None
|
|
33
39
|
|
|
34
40
|
|
|
41
|
+
def _make_cta(
|
|
42
|
+
commands: list[str] | None, description: str = "Suggested commands:"
|
|
43
|
+
) -> CtaBlock | None:
|
|
44
|
+
if not commands:
|
|
45
|
+
return None
|
|
46
|
+
return CtaBlock(description=description, commands=commands)
|
|
47
|
+
|
|
48
|
+
|
|
35
49
|
def make_success_envelope(
|
|
36
50
|
data: Any,
|
|
37
51
|
*,
|
|
38
52
|
command: str,
|
|
39
53
|
cta: list[str] | None = None,
|
|
40
54
|
) -> Envelope:
|
|
41
|
-
return Envelope(
|
|
42
|
-
ok=True, data=data, meta=Meta(command=command, suggested_commands=cta)
|
|
43
|
-
)
|
|
55
|
+
return Envelope(ok=True, data=data, meta=Meta(command=command, cta=_make_cta(cta)))
|
|
44
56
|
|
|
45
57
|
|
|
46
58
|
def make_error_envelope(error: Exception, *, command: str) -> Envelope:
|
|
47
59
|
if isinstance(error, AgentCliError):
|
|
60
|
+
cta_block = _make_cta(error.cta, description="To fix this:")
|
|
48
61
|
info = ErrorInfo(
|
|
49
62
|
code=error.code,
|
|
50
63
|
message=error.message,
|
|
51
64
|
retryable=error.retryable,
|
|
52
|
-
|
|
65
|
+
cta=cta_block,
|
|
53
66
|
)
|
|
54
67
|
else:
|
|
55
68
|
info = ErrorInfo(code="UNKNOWN", message=str(error), retryable=False)
|
|
56
|
-
return Envelope(
|
|
57
|
-
ok=False,
|
|
58
|
-
error=info,
|
|
59
|
-
meta=Meta(command=command, suggested_commands=info.suggested_commands),
|
|
60
|
-
)
|
|
69
|
+
return Envelope(ok=False, error=info, meta=Meta(command=command, cta=info.cta))
|
|
61
70
|
|
|
62
71
|
|
|
63
72
|
def make_envelope(
|
|
@@ -77,7 +86,7 @@ def make_envelope(
|
|
|
77
86
|
data=data,
|
|
78
87
|
meta=Meta(
|
|
79
88
|
command=command,
|
|
80
|
-
|
|
89
|
+
cta=_make_cta(cta),
|
|
81
90
|
duration_ms=duration_ms,
|
|
82
91
|
streamed=streamed,
|
|
83
92
|
),
|
|
@@ -87,7 +96,7 @@ def make_envelope(
|
|
|
87
96
|
error=error,
|
|
88
97
|
meta=Meta(
|
|
89
98
|
command=command,
|
|
90
|
-
|
|
99
|
+
cta=_make_cta(cta),
|
|
91
100
|
duration_ms=duration_ms,
|
|
92
101
|
streamed=streamed,
|
|
93
102
|
),
|
|
@@ -3,8 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
import unittest
|
|
4
4
|
from typing import Annotated, Literal
|
|
5
5
|
|
|
6
|
-
from
|
|
7
|
-
from
|
|
6
|
+
from humancli import App, Context, Param, Result
|
|
7
|
+
from humancli.testing import CliRunner
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class AgentCliTests(unittest.TestCase):
|
|
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
|