coding-agent-cli 0.1.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.
Files changed (82) hide show
  1. coding_agent_cli-0.1.0/.editorconfig +12 -0
  2. coding_agent_cli-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +31 -0
  3. coding_agent_cli-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  4. coding_agent_cli-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +17 -0
  5. coding_agent_cli-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +11 -0
  6. coding_agent_cli-0.1.0/.github/dependabot.yml +6 -0
  7. coding_agent_cli-0.1.0/.github/workflows/ci.yml +47 -0
  8. coding_agent_cli-0.1.0/.github/workflows/pr-title.yml +18 -0
  9. coding_agent_cli-0.1.0/.github/workflows/release.yml +116 -0
  10. coding_agent_cli-0.1.0/.gitignore +8 -0
  11. coding_agent_cli-0.1.0/.release-please-manifest.json +3 -0
  12. coding_agent_cli-0.1.0/AGENTS.md +47 -0
  13. coding_agent_cli-0.1.0/CHANGELOG.md +12 -0
  14. coding_agent_cli-0.1.0/CLAUDE.md +1 -0
  15. coding_agent_cli-0.1.0/CODE_OF_CONDUCT.md +30 -0
  16. coding_agent_cli-0.1.0/CONTRIBUTING.md +91 -0
  17. coding_agent_cli-0.1.0/LICENSE +21 -0
  18. coding_agent_cli-0.1.0/PKG-INFO +217 -0
  19. coding_agent_cli-0.1.0/README.md +194 -0
  20. coding_agent_cli-0.1.0/SECURITY.md +26 -0
  21. coding_agent_cli-0.1.0/docs/plans/coding-agent-cli/.handover.md +30 -0
  22. coding_agent_cli-0.1.0/docs/plans/coding-agent-cli/DESIGN.md +300 -0
  23. coding_agent_cli-0.1.0/docs/plans/coding-agent-cli/PLAN.md +265 -0
  24. coding_agent_cli-0.1.0/docs/plans/coding-agent-cli/journal-phase4.md +169 -0
  25. coding_agent_cli-0.1.0/docs/plans/coding-agent-cli/journal-phase5.md +195 -0
  26. coding_agent_cli-0.1.0/pyproject.toml +65 -0
  27. coding_agent_cli-0.1.0/release-please-config.json +21 -0
  28. coding_agent_cli-0.1.0/src/coding_agent_cli/__init__.py +47 -0
  29. coding_agent_cli-0.1.0/src/coding_agent_cli/_args.py +66 -0
  30. coding_agent_cli-0.1.0/src/coding_agent_cli/_classify.py +170 -0
  31. coding_agent_cli-0.1.0/src/coding_agent_cli/_drivers/__init__.py +1 -0
  32. coding_agent_cli-0.1.0/src/coding_agent_cli/_drivers/_common.py +330 -0
  33. coding_agent_cli-0.1.0/src/coding_agent_cli/_drivers/_usage.py +77 -0
  34. coding_agent_cli-0.1.0/src/coding_agent_cli/_drivers/agy.py +340 -0
  35. coding_agent_cli-0.1.0/src/coding_agent_cli/_drivers/claude.py +304 -0
  36. coding_agent_cli-0.1.0/src/coding_agent_cli/_drivers/codex.py +333 -0
  37. coding_agent_cli-0.1.0/src/coding_agent_cli/_drivers/codex_rollout.py +439 -0
  38. coding_agent_cli-0.1.0/src/coding_agent_cli/_drivers/pi.py +333 -0
  39. coding_agent_cli-0.1.0/src/coding_agent_cli/_platform.py +171 -0
  40. coding_agent_cli-0.1.0/src/coding_agent_cli/_process.py +338 -0
  41. coding_agent_cli-0.1.0/src/coding_agent_cli/api.py +190 -0
  42. coding_agent_cli-0.1.0/src/coding_agent_cli/events.py +109 -0
  43. coding_agent_cli-0.1.0/src/coding_agent_cli/py.typed +0 -0
  44. coding_agent_cli-0.1.0/src/coding_agent_cli/registry.py +67 -0
  45. coding_agent_cli-0.1.0/src/coding_agent_cli/types.py +90 -0
  46. coding_agent_cli-0.1.0/tests/__init__.py +0 -0
  47. coding_agent_cli-0.1.0/tests/cli_stub.py +144 -0
  48. coding_agent_cli-0.1.0/tests/conftest.py +1 -0
  49. coding_agent_cli-0.1.0/tests/fixtures/fake_cli/echo_stdin.py +8 -0
  50. coding_agent_cli-0.1.0/tests/fixtures/fake_cli/emit_both.py +6 -0
  51. coding_agent_cli-0.1.0/tests/fixtures/fake_cli/exit_now.py +5 -0
  52. coding_agent_cli-0.1.0/tests/fixtures/fake_cli/exit_status.py +6 -0
  53. coding_agent_cli-0.1.0/tests/fixtures/fake_cli/fake_cli.py +46 -0
  54. coding_agent_cli-0.1.0/tests/fixtures/fake_cli/grandchild.py +10 -0
  55. coding_agent_cli-0.1.0/tests/fixtures/fake_cli/long_line.py +6 -0
  56. coding_agent_cli-0.1.0/tests/fixtures/fake_cli/many_lines.py +6 -0
  57. coding_agent_cli-0.1.0/tests/fixtures/fake_cli/non_utf8.py +6 -0
  58. coding_agent_cli-0.1.0/tests/fixtures/fake_cli/sleeper.py +6 -0
  59. coding_agent_cli-0.1.0/tests/fixtures/fake_cli/spawn_and_sleep.py +11 -0
  60. coding_agent_cli-0.1.0/tests/fixtures/usage/agy.jsonl +6 -0
  61. coding_agent_cli-0.1.0/tests/fixtures/usage/claude.jsonl +12 -0
  62. coding_agent_cli-0.1.0/tests/fixtures/usage/codex.jsonl +7 -0
  63. coding_agent_cli-0.1.0/tests/fixtures/usage/pi.jsonl +55 -0
  64. coding_agent_cli-0.1.0/tests/launchers.py +42 -0
  65. coding_agent_cli-0.1.0/tests/test_agy_driver.py +723 -0
  66. coding_agent_cli-0.1.0/tests/test_api_contract.py +135 -0
  67. coding_agent_cli-0.1.0/tests/test_args.py +42 -0
  68. coding_agent_cli-0.1.0/tests/test_classify.py +88 -0
  69. coding_agent_cli-0.1.0/tests/test_claude_driver.py +735 -0
  70. coding_agent_cli-0.1.0/tests/test_codex_driver.py +692 -0
  71. coding_agent_cli-0.1.0/tests/test_codex_rollout.py +610 -0
  72. coding_agent_cli-0.1.0/tests/test_events.py +68 -0
  73. coding_agent_cli-0.1.0/tests/test_live.py +41 -0
  74. coding_agent_cli-0.1.0/tests/test_packaging.py +53 -0
  75. coding_agent_cli-0.1.0/tests/test_pi_driver.py +746 -0
  76. coding_agent_cli-0.1.0/tests/test_process.py +394 -0
  77. coding_agent_cli-0.1.0/tests/test_registry.py +55 -0
  78. coding_agent_cli-0.1.0/tests/test_stream.py +53 -0
  79. coding_agent_cli-0.1.0/tests/test_types.py +101 -0
  80. coding_agent_cli-0.1.0/tests/test_usage.py +87 -0
  81. coding_agent_cli-0.1.0/tests/toy_driver.py +68 -0
  82. coding_agent_cli-0.1.0/uv.lock +156 -0
@@ -0,0 +1,12 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ insert_final_newline = true
7
+ trim_trailing_whitespace = true
8
+ indent_style = space
9
+ indent_size = 4
10
+
11
+ [*.{yml,yaml,toml,md}]
12
+ indent_size = 2
@@ -0,0 +1,31 @@
1
+ name: Bug report
2
+ description: Something does not work as documented
3
+ labels: [bug]
4
+ body:
5
+ - type: textarea
6
+ id: what
7
+ attributes:
8
+ label: What happened
9
+ description: Include the `Result.outcome` and `Result.error` if relevant. Remove prompts, tokens, and private paths.
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: repro
14
+ attributes:
15
+ label: Steps to reproduce
16
+ render: python
17
+ validations:
18
+ required: true
19
+ - type: textarea
20
+ id: expected
21
+ attributes:
22
+ label: Expected behavior
23
+ validations:
24
+ required: true
25
+ - type: input
26
+ id: versions
27
+ attributes:
28
+ label: Versions
29
+ description: coding-agent-cli, Python, OS, and the CLI's `--version` output
30
+ validations:
31
+ required: true
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Security vulnerability
4
+ url: https://github.com/sitien173/coding-agent-cli/security/advisories/new
5
+ about: Report security problems privately.
@@ -0,0 +1,17 @@
1
+ name: Feature request
2
+ description: Suggest a new driver, option, or behavior
3
+ labels: [enhancement]
4
+ body:
5
+ - type: textarea
6
+ id: problem
7
+ attributes:
8
+ label: Problem
9
+ description: What are you trying to do, and what blocks you today?
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: proposal
14
+ attributes:
15
+ label: Proposal
16
+ validations:
17
+ required: true
@@ -0,0 +1,11 @@
1
+ ## Summary
2
+
3
+ <!-- What changes and why. Link the issue: Fixes #123 -->
4
+
5
+ ## Checklist
6
+
7
+ - [ ] `uv run ruff format --check`, `uv run ruff check`, `uv run pyright`, and `uv run pytest` pass
8
+ - [ ] Tests cover the change
9
+ - [ ] PR title follows Conventional Commits, such as `feat: add X` or `fix(codex): handle Y`
10
+ - [ ] README updated if public behavior or signatures changed
11
+ - [ ] No driver adds a permission, approval, or sandbox-bypass flag
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: github-actions
4
+ directory: /
5
+ schedule:
6
+ interval: monthly
@@ -0,0 +1,47 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: ci-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ lint:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v7
21
+ - uses: astral-sh/setup-uv@v10.3.3
22
+ with:
23
+ python-version: "3.12"
24
+ - run: uv sync --locked
25
+ - run: uv run ruff format --check
26
+ - run: uv run ruff check
27
+ - run: uv run pyright
28
+
29
+ test:
30
+ strategy:
31
+ fail-fast: false
32
+ matrix:
33
+ include:
34
+ - { os: ubuntu-latest, python: "3.12" }
35
+ - { os: macos-latest, python: "3.12" }
36
+ - { os: windows-latest, python: "3.12" }
37
+ - { os: ubuntu-latest, python: "3.13" }
38
+ - { os: ubuntu-latest, python: "3.14" }
39
+ runs-on: ${{ matrix.os }}
40
+ steps:
41
+ - uses: actions/checkout@v7
42
+ - uses: astral-sh/setup-uv@v10.3.3
43
+ with:
44
+ python-version: ${{ matrix.python }}
45
+ - run: uv sync --locked
46
+ - run: uv run pytest
47
+ - run: uv run pyright
@@ -0,0 +1,18 @@
1
+ name: PR title
2
+
3
+ # Squash merges use the PR title as the commit message, and release-please reads those commits.
4
+
5
+ on:
6
+ pull_request_target:
7
+ types: [opened, edited, reopened, synchronize]
8
+
9
+ permissions:
10
+ pull-requests: read
11
+
12
+ jobs:
13
+ conventional:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: amannn/action-semantic-pull-request@v6
17
+ env:
18
+ GITHUB_TOKEN: ${{ github.token }}
@@ -0,0 +1,116 @@
1
+ name: Release
2
+
3
+ # Pushes to main run release-please, which keeps a release PR open with the next version and changelog.
4
+ # Merging that PR creates the tag and GitHub Release, then this workflow builds and publishes to PyPI.
5
+ # Pushing a v* tag by hand also publishes; use it for the first release.
6
+
7
+ on:
8
+ push:
9
+ branches: [main]
10
+ tags: ["v*"]
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ concurrency:
16
+ group: release-${{ github.ref }}
17
+ cancel-in-progress: false
18
+
19
+ jobs:
20
+ release-please:
21
+ if: github.ref == 'refs/heads/main'
22
+ runs-on: ubuntu-latest
23
+ permissions:
24
+ contents: write
25
+ pull-requests: write
26
+ outputs:
27
+ release_created: ${{ steps.release.outputs.release_created }}
28
+ tag_name: ${{ steps.release.outputs.tag_name }}
29
+ steps:
30
+ - id: release
31
+ uses: googleapis/release-please-action@v5
32
+ # release-please bumps pyproject.toml but not uv.lock, so `uv sync --locked` would fail on the release PR.
33
+ - if: steps.release.outputs.pr
34
+ uses: actions/checkout@v7
35
+ with:
36
+ ref: ${{ fromJSON(steps.release.outputs.pr).headBranchName }}
37
+ - if: steps.release.outputs.pr
38
+ uses: astral-sh/setup-uv@v10.3.3
39
+ - if: steps.release.outputs.pr
40
+ run: |
41
+ uv lock
42
+ if ! git diff --quiet uv.lock; then
43
+ git config user.name "github-actions[bot]"
44
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
45
+ git commit -am "chore: update uv.lock for release"
46
+ git push
47
+ fi
48
+
49
+ build:
50
+ needs: release-please
51
+ if: >-
52
+ !failure() && !cancelled() &&
53
+ (needs.release-please.outputs.release_created == 'true' || startsWith(github.ref, 'refs/tags/v'))
54
+ runs-on: ubuntu-latest
55
+ outputs:
56
+ tag: ${{ steps.tag.outputs.tag }}
57
+ steps:
58
+ - id: tag
59
+ run: echo "tag=${RP_TAG:-$GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT"
60
+ env:
61
+ RP_TAG: ${{ needs.release-please.outputs.tag_name }}
62
+ - uses: actions/checkout@v7
63
+ with:
64
+ ref: ${{ steps.tag.outputs.tag }}
65
+ - uses: astral-sh/setup-uv@v10.3.3
66
+ with:
67
+ python-version: "3.12"
68
+ - name: Check tag matches package version
69
+ run: |
70
+ version=$(uv version --short)
71
+ test "v$version" = "$TAG" || { echo "::error::tag $TAG does not match version $version"; exit 1; }
72
+ env:
73
+ TAG: ${{ steps.tag.outputs.tag }}
74
+ - run: uv sync --locked
75
+ - run: uv run pytest
76
+ - run: uv build
77
+ - uses: actions/upload-artifact@v7
78
+ with:
79
+ name: dist
80
+ path: dist/
81
+
82
+ publish:
83
+ needs: build
84
+ if: ${{ !failure() && !cancelled() && needs.build.result == 'success' }}
85
+ runs-on: ubuntu-latest
86
+ environment:
87
+ name: pypi
88
+ url: https://pypi.org/project/coding-agent-cli/
89
+ permissions:
90
+ id-token: write
91
+ steps:
92
+ - uses: actions/download-artifact@v8
93
+ with:
94
+ name: dist
95
+ path: dist/
96
+ - uses: pypa/gh-action-pypi-publish@v1.14.3
97
+
98
+ github-release:
99
+ needs: [build, publish]
100
+ if: ${{ !failure() && !cancelled() && needs.publish.result == 'success' }}
101
+ runs-on: ubuntu-latest
102
+ permissions:
103
+ contents: write
104
+ steps:
105
+ - uses: actions/download-artifact@v8
106
+ with:
107
+ name: dist
108
+ path: dist/
109
+ - name: Attach artifacts, creating the release for hand-pushed tags
110
+ run: |
111
+ gh release view "$TAG" >/dev/null 2>&1 || gh release create "$TAG" --verify-tag --generate-notes --title "$TAG"
112
+ gh release upload "$TAG" dist/* --clobber
113
+ env:
114
+ GH_TOKEN: ${{ github.token }}
115
+ GH_REPO: ${{ github.repository }}
116
+ TAG: ${{ needs.build.outputs.tag }}
@@ -0,0 +1,8 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ dist/
5
+ build/
6
+ *.egg-info/
7
+ .pytest_cache/
8
+ .ruff_cache/
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.1.0"
3
+ }
@@ -0,0 +1,47 @@
1
+ # AGENTS.md
2
+
3
+ Guidance for AI coding agents working in this repository. Humans should read [CONTRIBUTING.md](CONTRIBUTING.md), which this file follows.
4
+
5
+ ## Project
6
+
7
+ `coding-agent-cli` is a stdlib-only Python 3.12+ library. It runs coding-agent CLIs (`claude`, `codex`, `pi`, `agy`) as subprocesses, streams typed events, and returns a classified `Result`.
8
+
9
+ ## Layout
10
+
11
+ | Path | Contents |
12
+ |---|---|
13
+ | `src/coding_agent_cli/api.py` | Public entry points: `run`, `stream`, `run_sync`, `check` |
14
+ | `src/coding_agent_cli/types.py`, `events.py` | Public frozen dataclasses |
15
+ | `src/coding_agent_cli/registry.py` | `Driver` protocol and `DriverRegistry` |
16
+ | `src/coding_agent_cli/_process.py`, `_platform.py` | Subprocess transport and process-tree kill |
17
+ | `src/coding_agent_cli/_args.py`, `_classify.py` | Argument validation and outcome classification |
18
+ | `src/coding_agent_cli/_drivers/` | Built-in drivers and shared `CliDriver` helpers |
19
+ | `tests/fixtures/fake_cli/` | Fake CLIs used by all unit tests |
20
+ | `docs/plans/coding-agent-cli/` | Design, plan, and phase journals |
21
+
22
+ ## Commands
23
+
24
+ Prefix uv commands with `export VIRTUAL_ENV=;` if a foreign virtualenv is active.
25
+
26
+ ```bash
27
+ uv sync
28
+ uv run ruff format && uv run ruff check --fix
29
+ uv run pyright
30
+ uv run pytest
31
+ ```
32
+
33
+ All four must pass before you finish. Do not run `pytest -m live` unless asked; it calls real CLIs and spends tokens.
34
+
35
+ ## Hard rules
36
+
37
+ - Never add a runtime dependency.
38
+ - Never make a driver add a permission, approval, or sandbox-bypass flag.
39
+ - Never log prompts, argv, or environment values.
40
+ - Every exit path must kill the process tree and delete temp files.
41
+ - Reuse helpers in `_drivers/_common.py` and `_args.py` before writing new ones.
42
+ - Keep public signatures in sync with the README examples.
43
+ - Do not push, tag, or publish.
44
+
45
+ ## Style
46
+
47
+ Follow the coding standard in [CONTRIBUTING.md](CONTRIBUTING.md#coding-standard). Match the surrounding code. Keep diffs minimal and add a test for every behavior change.
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ First release. Extracted from the CLI-driver layer of Refract.
6
+
7
+ - `run`, `stream`, `run_sync`, and `check` entry points for running coding-agent CLIs from Python.
8
+ - Typed events with a strictly increasing `sequence`, ending with exactly one `RunCompleted`.
9
+ - A classified `Result` with `Outcome` and `Diagnostic`.
10
+ - Built-in drivers for `claude`, `pi`, `codex`, and `agy`, and a `DriverRegistry` for custom drivers.
11
+ - Process-tree cleanup on completion, cancel, timeout, and callback failure.
12
+ - No permission or approval flag is ever added; callers pass them through `args`.
@@ -0,0 +1 @@
1
+ @AGENTS.md
@@ -0,0 +1,30 @@
1
+ # Code of Conduct
2
+
3
+ This project adopts the [Contributor Covenant, version 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/).
4
+
5
+ ## Our pledge
6
+
7
+ We pledge to make participation in this project a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
8
+
9
+ ## Expected behavior
10
+
11
+ - Show empathy and kindness toward other people.
12
+ - Respect differing opinions, viewpoints, and experiences.
13
+ - Give and gracefully accept constructive feedback.
14
+ - Take responsibility for mistakes and learn from them.
15
+
16
+ ## Unacceptable behavior
17
+
18
+ - Sexualized language or imagery, and sexual attention or advances of any kind.
19
+ - Trolling, insulting or derogatory comments, and personal or political attacks.
20
+ - Public or private harassment.
21
+ - Publishing others' private information without their explicit permission.
22
+ - Other conduct that could reasonably be considered inappropriate in a professional setting.
23
+
24
+ ## Reporting
25
+
26
+ Report unacceptable behavior to the maintainer, [@sitien173](https://github.com/sitien173), by private contact through GitHub. You can also use GitHub's [report content](https://docs.github.com/en/communities/maintaining-your-safety-on-github/reporting-abuse-or-spam) feature. Reports are reviewed promptly and kept confidential.
27
+
28
+ ## Enforcement
29
+
30
+ The maintainer may remove, edit, or reject comments, commits, code, issues, and other contributions that violate this code, and may warn, suspend, or ban contributors. The full enforcement guidelines are in the [Contributor Covenant](https://www.contributor-covenant.org/version/2/1/code_of_conduct/#enforcement-guidelines).
@@ -0,0 +1,91 @@
1
+ # Contributing
2
+
3
+ Thanks for helping improve coding-agent-cli. This guide covers setup, the coding standard, and how changes get merged.
4
+
5
+ ## Ground rules
6
+
7
+ - Be respectful. All participation follows the [Code of Conduct](CODE_OF_CONDUCT.md).
8
+ - Report security problems privately. See [SECURITY.md](SECURITY.md). Do not open a public issue.
9
+ - Open an issue before a large change, so the design can be agreed first.
10
+
11
+ ## Setup
12
+
13
+ You need Python 3.12 or later and [uv](https://docs.astral.sh/uv/).
14
+
15
+ ```bash
16
+ git clone https://github.com/sitien173/coding-agent-cli.git
17
+ cd coding-agent-cli
18
+ uv sync
19
+ ```
20
+
21
+ ## Checks
22
+
23
+ Every pull request must pass the same checks CI runs:
24
+
25
+ ```bash
26
+ uv run ruff format --check
27
+ uv run ruff check
28
+ uv run pyright
29
+ uv run pytest
30
+ ```
31
+
32
+ `uv run ruff format` and `uv run ruff check --fix` correct most style problems.
33
+
34
+ Live tests run the real CLIs and are excluded by default. Run them only with the CLIs installed and logged in:
35
+
36
+ ```bash
37
+ uv run pytest -m live -rP
38
+ ```
39
+
40
+ ## Coding standard
41
+
42
+ ### Style
43
+
44
+ - Ruff formats and lints the code. The line length is 120. Configuration lives in `pyproject.toml`.
45
+ - Pyright checks types. New code is fully annotated, and `pyright` must report 0 errors.
46
+ - Write `from __future__ import annotations` at the top of each module.
47
+ - Public names are listed in `__all__`. Modules and names that start with `_` are private.
48
+
49
+ ### Design rules
50
+
51
+ - **No runtime dependencies.** The library uses the standard library only.
52
+ - **No implicit permissions.** A driver never adds a permission, approval, or sandbox-bypass flag. Callers pass these through `Request.args`.
53
+ - **No leaked processes.** Every exit path kills the CLI's whole process tree: completion, cancel, timeout, and a raising callback.
54
+ - **No sensitive logging.** Never log prompts, argv, or environment values.
55
+ - **Typed, frozen values.** Requests, results, and events are frozen dataclasses. Unknown values are `None`, never zero.
56
+ - **One `RunCompleted`.** Each run emits exactly one, last, after the process tree is gone, with a strictly increasing `sequence`.
57
+
58
+ ### Tests
59
+
60
+ - Every behavior change comes with a test. Write the failing test first when you can.
61
+ - Tests use the fake CLIs in `tests/fixtures/fake_cli`. Unit tests never call a real coding-agent CLI.
62
+ - A new driver needs argv tests proving it adds no permission flag for any option combination.
63
+
64
+ ### Adding a driver
65
+
66
+ 1. Subclass `CliDriver` in `src/coding_agent_cli/_drivers/`. Follow `claude.py` or `pi.py`.
67
+ 2. Declare the driver-owned transport flags and the `portable_flags` it supports.
68
+ 3. Register it in `_builtin_drivers()` in `registry.py`.
69
+ 4. Add a driver test module, argv policy tests, and a row in each README table.
70
+
71
+ ## Commits and pull requests
72
+
73
+ - Use [Conventional Commits](https://www.conventionalcommits.org/): `feat:`, `fix:`, `docs:`, `test:`, `refactor:`, `chore:`. Mark breaking changes with `!`, as in `feat!:`.
74
+ - Pull requests are squash-merged, so the PR title becomes the commit message. A check enforces the Conventional Commits format on PR titles.
75
+ - Keep each pull request to one change. Every changed line should trace to that change.
76
+ - Do not edit `CHANGELOG.md` or the version by hand. Both are generated from commit messages at release time.
77
+ - Fill in the pull request template.
78
+
79
+ ## Releases
80
+
81
+ Releases are automated with [release-please](https://github.com/googleapis/release-please):
82
+
83
+ 1. Each push to `main` updates an open release PR. It bumps the version in `pyproject.toml`, `__init__.py`, and `uv.lock`, and adds the changelog entry.
84
+ 2. While the version is below 1.0, `feat:` bumps the minor version and `fix:` bumps the patch version. A breaking change also bumps the minor version.
85
+ 3. A maintainer merges the release PR when ready. The workflow tags `vX.Y.Z`, creates the GitHub Release, tests, builds, publishes to PyPI through trusted publishing, and attaches the wheel and sdist to the release.
86
+
87
+ Publishing waits for approval on the `pypi` environment. Pushing a `vX.Y.Z` tag by hand runs the same build and publish; the tag must match the version in `pyproject.toml`.
88
+
89
+ ## License
90
+
91
+ By contributing, you agree that your contributions are licensed under the [MIT License](LICENSE).
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 sitien173
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.