cli-agent-runner 0.1.1__tar.gz → 0.1.7__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.
- cli_agent_runner-0.1.7/.githooks/commit-msg +33 -0
- cli_agent_runner-0.1.7/.github/workflows/ci.yml +105 -0
- cli_agent_runner-0.1.7/CHANGELOG.md +293 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/CONTRIBUTING.md +8 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/PKG-INFO +7 -12
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/README.md +6 -11
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/README.zh.md +1 -6
- cli_agent_runner-0.1.7/agent_runner/__init__.py +54 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/_docgen.py +2 -0
- cli_agent_runner-0.1.7/agent_runner/_registry.py +23 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/_version.py +2 -2
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/agent_runtime.py +8 -19
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/api.py +20 -6
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/api_types.py +54 -4
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/cli/common.py +19 -1
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/cli/init_cmd.py +8 -2
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/cli/install_cmd.py +1 -1
- cli_agent_runner-0.1.7/agent_runner/config.py +148 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/defenses.py +6 -6
- cli_agent_runner-0.1.7/agent_runner/detector_helpers.py +115 -0
- cli_agent_runner-0.1.7/agent_runner/events.py +130 -0
- cli_agent_runner-0.1.7/agent_runner/hooks.py +143 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/monitor.py +107 -39
- cli_agent_runner-0.1.7/agent_runner/presets/aider.toml +30 -0
- cli_agent_runner-0.1.7/agent_runner/presets/claude.toml +29 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/prompt_loader.py +3 -2
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/runner.py +99 -19
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/scaffold.py +26 -40
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/startup_check.py +4 -1
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/docs/README.md +9 -6
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/docs/architecture.md +19 -24
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/docs/commands.md +1 -1
- cli_agent_runner-0.1.7/docs/configuration.md +130 -0
- cli_agent_runner-0.1.7/docs/plugins.md +311 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/docs/quickstart.md +39 -11
- cli_agent_runner-0.1.7/docs/recipes/aider.md +117 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/docs/runbook.md +14 -3
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/conftest.py +27 -0
- cli_agent_runner-0.1.7/tests/contract/test_public_api_surface.py +130 -0
- cli_agent_runner-0.1.7/tests/integration/test_context_enricher_namespacing.py +57 -0
- cli_agent_runner-0.1.7/tests/integration/test_plugin_detector_loaded.py +105 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/integration/test_run_one_round_with_fake_agent.py +39 -0
- cli_agent_runner-0.1.7/tests/integration/test_scaffold_presets.py +80 -0
- cli_agent_runner-0.1.1/tests/invariants/test_phase2_architecture.py → cli_agent_runner-0.1.7/tests/invariants/test_architecture.py +2 -19
- cli_agent_runner-0.1.7/tests/invariants/test_event_kind_registry.py +74 -0
- cli_agent_runner-0.1.1/tests/invariants/test_phase2_module_sizes.py → cli_agent_runner-0.1.7/tests/invariants/test_module_sizes.py +10 -10
- cli_agent_runner-0.1.7/tests/invariants/test_no_ai_signatures.py +83 -0
- cli_agent_runner-0.1.7/tests/invariants/test_peek_schema_version.py +78 -0
- cli_agent_runner-0.1.7/tests/invariants/test_round_result_stable.py +75 -0
- cli_agent_runner-0.1.7/tests/literate/__init__.py +0 -0
- cli_agent_runner-0.1.7/tests/unit/__init__.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_agent_runtime.py +23 -12
- cli_agent_runner-0.1.7/tests/unit/test_auto_stop_gating.py +91 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_cli_init_install.py +27 -0
- cli_agent_runner-0.1.7/tests/unit/test_config.py +413 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_defenses.py +26 -2
- cli_agent_runner-0.1.7/tests/unit/test_detector_helpers.py +141 -0
- cli_agent_runner-0.1.7/tests/unit/test_detector_protocol.py +69 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_docgen.py +1 -1
- cli_agent_runner-0.1.7/tests/unit/test_events.py +150 -0
- cli_agent_runner-0.1.7/tests/unit/test_hook_failure_isolation.py +77 -0
- cli_agent_runner-0.1.7/tests/unit/test_hooks.py +139 -0
- cli_agent_runner-0.1.7/tests/unit/test_init_entry_points.py +107 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_monitor_detectors.py +55 -0
- cli_agent_runner-0.1.7/tests/unit/test_presets.py +87 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_prompt_loader.py +66 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_scaffold.py +38 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_service_unit.py +1 -1
- cli_agent_runner-0.1.1/.github/workflows/ci.yml +0 -57
- cli_agent_runner-0.1.1/CHANGELOG.md +0 -62
- cli_agent_runner-0.1.1/agent_runner/__init__.py +0 -3
- cli_agent_runner-0.1.1/agent_runner/config.py +0 -92
- cli_agent_runner-0.1.1/agent_runner/critic.py +0 -33
- cli_agent_runner-0.1.1/agent_runner/events.py +0 -53
- cli_agent_runner-0.1.1/docs/configuration.md +0 -78
- cli_agent_runner-0.1.1/tests/invariants/test_event_kind_registry.py +0 -39
- cli_agent_runner-0.1.1/tests/unit/test_config.py +0 -115
- cli_agent_runner-0.1.1/tests/unit/test_critic.py +0 -27
- cli_agent_runner-0.1.1/tests/unit/test_events.py +0 -79
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/.codecov.yml +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/.github/workflows/release.yml +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/.gitignore +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/.vulture-whitelist.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/CODE_OF_CONDUCT.md +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/LICENSE +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/SECURITY.md +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/cli/__init__.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/cli/__main__.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/cli/monitor_cmd.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/cli/peek_cmd.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/cli/round_cmd.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/cli/serve_cmd.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/cli/service_cmd.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/context_store.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/lifecycle.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/metrics.py +0 -0
- {cli_agent_runner-0.1.1/tests → cli_agent_runner-0.1.7/agent_runner/presets}/__init__.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/round_view.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/service_unit.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/agent_runner/vcs_state.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/build.sh +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/deploy/example-agent-runner.toml +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/deploy/launchd.plist.tmpl +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/deploy/run-loop.sh +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/deploy/systemd.service.tmpl +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/pyproject.toml +0 -0
- {cli_agent_runner-0.1.1/tests/e2e → cli_agent_runner-0.1.7/tests}/__init__.py +0 -0
- {cli_agent_runner-0.1.1/tests/integration → cli_agent_runner-0.1.7/tests/contract}/__init__.py +0 -0
- {cli_agent_runner-0.1.1/tests/invariants → cli_agent_runner-0.1.7/tests/e2e}/__init__.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/e2e/conftest.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/e2e/test_e2e_graceful_stop.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/e2e/test_e2e_install_systemd.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/e2e/test_e2e_monitor_remote.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/e2e/test_e2e_round_lifecycle.py +0 -0
- {cli_agent_runner-0.1.1/tests/literate → cli_agent_runner-0.1.7/tests/integration}/__init__.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/integration/test_install_dry_run.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/integration/test_monitor_seeded.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/integration/test_run_loop_backoff.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/integration/test_serve_loop.py +0 -0
- {cli_agent_runner-0.1.1/tests/unit → cli_agent_runner-0.1.7/tests/invariants}/__init__.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/invariants/test_atomic_write_enforced.py +0 -0
- /cli_agent_runner-0.1.1/tests/invariants/test_phase2_catalogs.py → /cli_agent_runner-0.1.7/tests/invariants/test_catalogs.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/invariants/test_docs_generated.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/invariants/test_module_boundaries.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/invariants/test_no_pytest_skip_on_parse_fail.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/invariants/test_repo_constants_patched_in_tests.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/invariants/test_stash_uses_sha_not_index.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/literate/parser.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/literate/test_parser.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/literate/test_quickstart.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_api_observation.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_api_service.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_api_types.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_cli.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_cli_common.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_cli_service_peek_monitor.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_context_store.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_lifecycle.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_metrics.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_monitor_assembly.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_monitor_remote.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_peek_argparse.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_round_view.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_runner.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_startup_check.py +0 -0
- {cli_agent_runner-0.1.1 → cli_agent_runner-0.1.7}/tests/unit/test_vcs_state.py +0 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Reject commit messages that contain AI-tool attribution.
|
|
3
|
+
#
|
|
4
|
+
# Rationale: this repository's history is curated to credit only the human
|
|
5
|
+
# author. AI-tool trailers (Co-Authored-By: Claude, 🤖 Generated with ..., etc.)
|
|
6
|
+
# create false "claude" / "anthropic" entries in GitHub's Contributors widget
|
|
7
|
+
# and bloat commit log noise.
|
|
8
|
+
#
|
|
9
|
+
# Activate per clone: git config core.hooksPath .githooks
|
|
10
|
+
# Bypass (rarely needed): git commit --no-verify
|
|
11
|
+
|
|
12
|
+
MSG_FILE="$1"
|
|
13
|
+
|
|
14
|
+
# Strip git-comment lines before checking
|
|
15
|
+
CONTENT=$(grep -v '^#' "$MSG_FILE" || true)
|
|
16
|
+
|
|
17
|
+
# Case-insensitive regex; tab/space tolerant
|
|
18
|
+
FORBIDDEN_REGEX='([Cc]o-[Aa]uthored-[Bb]y:|🤖|[Gg]enerated with [Cc]laude|[Gg]enerated with \[Cursor\]|noreply@anthropic\.com)'
|
|
19
|
+
|
|
20
|
+
if printf '%s\n' "$CONTENT" | grep -E -q "$FORBIDDEN_REGEX"; then
|
|
21
|
+
echo "" >&2
|
|
22
|
+
echo "commit-msg hook: AI-tool attribution detected in commit message." >&2
|
|
23
|
+
echo "" >&2
|
|
24
|
+
echo "Offending lines:" >&2
|
|
25
|
+
printf '%s\n' "$CONTENT" | grep -E -n "$FORBIDDEN_REGEX" | sed 's/^/ /' >&2
|
|
26
|
+
echo "" >&2
|
|
27
|
+
echo "Strip Co-Authored-By trailers, 🤖, 'Generated with ...', and" >&2
|
|
28
|
+
echo "noreply@anthropic.com refs, then retry." >&2
|
|
29
|
+
echo "" >&2
|
|
30
|
+
echo "(Bypass: git commit --no-verify — use sparingly, requires explicit" >&2
|
|
31
|
+
echo " review since CI lint-commits job will also reject the push.)" >&2
|
|
32
|
+
exit 1
|
|
33
|
+
fi
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
# Cancel in-flight runs on the same PR ref when a new push lands.
|
|
10
|
+
# Push-to-main runs always complete (cancel-in-progress only on PRs).
|
|
11
|
+
concurrency:
|
|
12
|
+
group: ci-${{ github.ref }}
|
|
13
|
+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
lint-commits:
|
|
17
|
+
name: lint commit messages (no AI-tool attribution)
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
timeout-minutes: 2
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
with:
|
|
23
|
+
# PR: scan only new commits the PR introduces (base..head).
|
|
24
|
+
# Push to main: scan the just-pushed commits (before..after).
|
|
25
|
+
# fetch-depth=0 ensures both refs are available.
|
|
26
|
+
fetch-depth: 0
|
|
27
|
+
- name: scan new commit messages
|
|
28
|
+
env:
|
|
29
|
+
GH_EVENT: ${{ github.event_name }}
|
|
30
|
+
BEFORE_SHA: ${{ github.event.before }}
|
|
31
|
+
BASE_REF: ${{ github.event.pull_request.base.sha }}
|
|
32
|
+
HEAD_REF: ${{ github.event.pull_request.head.sha }}
|
|
33
|
+
run: |
|
|
34
|
+
set -euo pipefail
|
|
35
|
+
if [ "$GH_EVENT" = "pull_request" ]; then
|
|
36
|
+
RANGE="${BASE_REF}..${HEAD_REF}"
|
|
37
|
+
else
|
|
38
|
+
# push event; before is 0..0 on first push or branch creation
|
|
39
|
+
if [ -z "${BEFORE_SHA:-}" ] || [ "$BEFORE_SHA" = "0000000000000000000000000000000000000000" ]; then
|
|
40
|
+
RANGE="HEAD~1..HEAD"
|
|
41
|
+
else
|
|
42
|
+
RANGE="${BEFORE_SHA}..HEAD"
|
|
43
|
+
fi
|
|
44
|
+
fi
|
|
45
|
+
echo "Scanning commit-message bodies in $RANGE"
|
|
46
|
+
# Collect messages joined by NUL bytes; grep -P for fixed alternation.
|
|
47
|
+
BODIES=$(git log --format='%B%x00' "$RANGE" || true)
|
|
48
|
+
if [ -z "$BODIES" ]; then
|
|
49
|
+
echo " (no commits in range)"
|
|
50
|
+
exit 0
|
|
51
|
+
fi
|
|
52
|
+
PATTERN='(Co-Authored-By:|🤖|Generated with Claude|Generated with \[Cursor\]|noreply@anthropic\.com)'
|
|
53
|
+
if printf '%s' "$BODIES" | grep -i -E -q "$PATTERN"; then
|
|
54
|
+
echo "::error::AI-tool attribution detected in new commit messages."
|
|
55
|
+
echo "Offending lines:"
|
|
56
|
+
printf '%s' "$BODIES" | grep -i -n -E "$PATTERN" || true
|
|
57
|
+
echo ""
|
|
58
|
+
echo "Strip Co-Authored-By trailers, 🤖, 'Generated with ...',"
|
|
59
|
+
echo "and noreply@anthropic.com refs, then force-push the fixed range."
|
|
60
|
+
exit 1
|
|
61
|
+
fi
|
|
62
|
+
echo " clean"
|
|
63
|
+
|
|
64
|
+
test:
|
|
65
|
+
name: test py${{ matrix.python }} / ${{ matrix.os }}
|
|
66
|
+
runs-on: ${{ matrix.os }}
|
|
67
|
+
timeout-minutes: 15
|
|
68
|
+
strategy:
|
|
69
|
+
fail-fast: false
|
|
70
|
+
matrix:
|
|
71
|
+
python: ["3.11", "3.12", "3.13"]
|
|
72
|
+
os: [ubuntu-latest, macos-latest]
|
|
73
|
+
# Steps below mirror ./build.sh check, inlined for per-step Actions UI
|
|
74
|
+
# granularity AND because coverage requires extra pytest flags not in
|
|
75
|
+
# the local `test` task. CONTRIBUTING.md states the parity intentionally.
|
|
76
|
+
steps:
|
|
77
|
+
- uses: actions/checkout@v4
|
|
78
|
+
with:
|
|
79
|
+
fetch-depth: 0
|
|
80
|
+
- uses: actions/setup-python@v5
|
|
81
|
+
with:
|
|
82
|
+
python-version: ${{ matrix.python }}
|
|
83
|
+
cache: pip
|
|
84
|
+
- name: install
|
|
85
|
+
run: pip install -e ".[dev]"
|
|
86
|
+
- name: ruff
|
|
87
|
+
run: |
|
|
88
|
+
ruff check .
|
|
89
|
+
ruff format --check .
|
|
90
|
+
- name: tests with coverage
|
|
91
|
+
run: pytest -q --ignore=tests/e2e --ignore=tests/literate --cov --cov-report=xml --cov-report=term
|
|
92
|
+
- name: docs CI gate
|
|
93
|
+
run: |
|
|
94
|
+
python -m agent_runner._docgen
|
|
95
|
+
git diff --exit-code docs/
|
|
96
|
+
- name: literate quickstart
|
|
97
|
+
run: pytest tests/literate/ -q
|
|
98
|
+
- name: upload coverage
|
|
99
|
+
if: matrix.python == '3.12' && matrix.os == 'ubuntu-latest'
|
|
100
|
+
uses: codecov/codecov-action@v4
|
|
101
|
+
with:
|
|
102
|
+
files: ./coverage.xml
|
|
103
|
+
fail_ci_if_error: false
|
|
104
|
+
env:
|
|
105
|
+
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.7] - 2026-05-13
|
|
11
|
+
|
|
12
|
+
### Migration for existing 0.1.6 users (DOWNSTREAM CONSUMERS READ THIS)
|
|
13
|
+
|
|
14
|
+
If you maintain an `agent-runner.toml` by hand (rather than via `agent-runner init`),
|
|
15
|
+
you must add an `[agent.env]` block to preserve the Claude self-update suppression
|
|
16
|
+
that 0.1.6 injected implicitly. **Without this, mid-loop self-updates can race with
|
|
17
|
+
the supervisor.**
|
|
18
|
+
|
|
19
|
+
Add to your `agent-runner.toml`:
|
|
20
|
+
|
|
21
|
+
```toml
|
|
22
|
+
[agent.env]
|
|
23
|
+
DISABLE_AUTOUPDATER = "1"
|
|
24
|
+
CLAUDE_CODE_EFFORT_LEVEL = "xhigh"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Or regenerate cleanly:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
agent-runner init --preset claude --force
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Plugin authors (Argus Gateway, etc.): no public API was renamed or removed
|
|
34
|
+
from your import surface. The deleted symbols (`agent_runner.agent_runtime.CRITICAL_ENV_DEFAULTS`,
|
|
35
|
+
`agent_runner.agent_runtime.merge_critical_envs`) were internal — not part of
|
|
36
|
+
the documented plugin API. A new public-API contract test
|
|
37
|
+
(`tests/contract/test_public_api_surface.py`) locks in `api_types`, `events`,
|
|
38
|
+
`hooks`, `monitor`, `detector_helpers` import surfaces so future refactors
|
|
39
|
+
can't silently drop names you rely on.
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
- `agent-runner init --preset {claude,aider}` selects between bundled CLI presets
|
|
43
|
+
(default: `claude`). New preset directory: `agent_runner/presets/`.
|
|
44
|
+
- `[agent.env]` TOML block — per-CLI env injections, replacing the hardcoded
|
|
45
|
+
`CRITICAL_ENV_DEFAULTS` constant. Empty dict by default.
|
|
46
|
+
- `docs/recipes/aider.md` — aider integration recipe.
|
|
47
|
+
- `tests/contract/test_public_api_surface.py` — public-API surface snapshot for
|
|
48
|
+
plugin authors.
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
- Core code (`agent_runtime.py`, `config.py`, `runner.py`, `scaffold.py`,
|
|
52
|
+
`defenses.py`) is now truly provider-agnostic: zero hardcoded Claude defaults.
|
|
53
|
+
Claude remains the reference example throughout the docs, but its specifics
|
|
54
|
+
live in `agent_runner/presets/claude.toml` (shipped as package data).
|
|
55
|
+
- `MonitorConfig.auth_fail_hint` default is now empty string; per-CLI hint
|
|
56
|
+
comes from the preset.
|
|
57
|
+
- `PEEK_SCHEMA_VERSION` bumped 1.3 → 1.4. `InitResult` gains `preset: str` field.
|
|
58
|
+
- `agent_runner/defenses.py` `critical_envs_injection` row now reads from
|
|
59
|
+
`cfg.agent.env.keys()` (not the deleted constant); state is "active" iff
|
|
60
|
+
the config defines any env injections, else "off".
|
|
61
|
+
|
|
62
|
+
### Removed
|
|
63
|
+
- `agent_runner.agent_runtime.CRITICAL_ENV_DEFAULTS` constant.
|
|
64
|
+
- `agent_runner.agent_runtime.merge_critical_envs()` function.
|
|
65
|
+
- `agent_runner.config._DEFAULT_AUTH_HINT` constant's Claude-specific default
|
|
66
|
+
string (replaced with `""`; per-CLI hint now in preset files).
|
|
67
|
+
|
|
68
|
+
## [0.1.6] - 2026-05-12
|
|
69
|
+
|
|
70
|
+
Zero-feature maintenance release — internal cleanup pass after the 0.1.x plugin
|
|
71
|
+
extension surface completed in 0.1.5. No runtime behavior change for users
|
|
72
|
+
without plugins; plugin authors written against 0.1.5 keep working unchanged.
|
|
73
|
+
|
|
74
|
+
### Changed
|
|
75
|
+
- Public `Alert.severity` / `Alert.auto_action` and `Detector.severity` /
|
|
76
|
+
`Detector.auto_action` are now typed with `Severity = Literal["info", "warning",
|
|
77
|
+
"critical"]` and `AutoAction = Literal["none", "stop_service"]` aliases
|
|
78
|
+
exported from `agent_runner.api_types`. Plain-string values continue to work
|
|
79
|
+
- `__version__` is read from the hatch-vcs generated `_version.py` instead of a
|
|
80
|
+
hardcoded constant; released packages report the actual release version
|
|
81
|
+
- Internal duplication reduced: shared `agent_runner._registry.ensure_unique`
|
|
82
|
+
for hooks + detectors registries; `cli/common.emit()` plugin-namespace imports
|
|
83
|
+
hoisted to module top; `events.parse_iso_ms` centralizes the ISO-8601 trailing-`Z`
|
|
84
|
+
parsing workaround; `MonitorConfig.auto_stop_on` default now references the
|
|
85
|
+
`_DEFAULT_AUTO_STOP_ON` constant
|
|
86
|
+
- `monitor.dual_source_silence` is now TOCTOU-safe (uses `try/except
|
|
87
|
+
FileNotFoundError` instead of `exists()` + `stat()`)
|
|
88
|
+
- `api._poll_once` short-circuits when no plugin detectors are registered,
|
|
89
|
+
skipping `assemble_project_state` (saves a file read per local poll and an
|
|
90
|
+
SSH round-trip per remote poll)
|
|
91
|
+
- `agent_runner/__init__.py` plugin loaders share a single
|
|
92
|
+
`_load_plugins_from_group` helper
|
|
93
|
+
- `monitor._alert` no longer asserts builtin detector names against
|
|
94
|
+
`KNOWN_ALERT_KINDS` (assertion was redundant and would crash under
|
|
95
|
+
`python -O`); test + docgen layers continue to validate the builtin name set
|
|
96
|
+
|
|
97
|
+
### Removed
|
|
98
|
+
- `agent_runner.critic` — empty Protocol stub for an unimplemented Critic
|
|
99
|
+
concept that was retired during the framework-first redesign
|
|
100
|
+
- `[llm]` commented block from the scaffold TOML template and its corresponding
|
|
101
|
+
section in `docs/configuration.md` — unused placeholder
|
|
102
|
+
- Legacy phase nomenclature from source docstrings, error messages, and CLI
|
|
103
|
+
help text; `tests/invariants/test_phase2_*.py` files renamed to drop the
|
|
104
|
+
`phase2_` prefix
|
|
105
|
+
|
|
106
|
+
### Backward compatibility
|
|
107
|
+
- Existing `agent-runner.toml` files continue to load (the removed `[llm]`
|
|
108
|
+
block was never parsed by the supervisor)
|
|
109
|
+
- Plugin code written for 0.1.5 continues to work — Protocol contracts and
|
|
110
|
+
`peek --json` schema 1.3 unchanged
|
|
111
|
+
|
|
112
|
+
## [0.1.5] - 2026-05-12
|
|
113
|
+
|
|
114
|
+
### Added
|
|
115
|
+
- `agent_runner.api_types.Detector` — public Protocol for plugin detectors
|
|
116
|
+
(attributes `name`, `severity`, `auto_action`; method `detect(state) -> Alert | None`).
|
|
117
|
+
`@runtime_checkable` — plugin classes structurally satisfying the shape are accepted
|
|
118
|
+
- `agent_runner.monitor.register_detector(detector)` and `plugin_detectors()` — public
|
|
119
|
+
registration API + sorted list of currently-registered detector names
|
|
120
|
+
- `agent_runner.monitor.run_plugin_detectors(state)` — invokes each registered plugin
|
|
121
|
+
detector with the assembled `ProjectState`; per-detector exceptions surface as
|
|
122
|
+
`UserWarning` (round continues)
|
|
123
|
+
- `agent_runner` package now also discovers and loads entry_points in group
|
|
124
|
+
`agent_runner.detectors` at first import; failures degrade to `UserWarning`
|
|
125
|
+
- `agent_runner.detector_helpers` module — three production-tested helpers for
|
|
126
|
+
plugin detector authors:
|
|
127
|
+
- `cumulative_window_check(events, *, kind, window_s, min_count)` —
|
|
128
|
+
sliding-window event counter; robust against wall-clock skew at boundaries
|
|
129
|
+
- `dual_source_silence(scheduler_log, round_log, threshold_s)` — both-source
|
|
130
|
+
silence check; avoids false positives during long rounds when only the
|
|
131
|
+
scheduler log is stale
|
|
132
|
+
- `phase_filter(state, *, exclude_phases)` — skip detection during phases
|
|
133
|
+
that intentionally produce no commits (e.g., retrospective rounds)
|
|
134
|
+
- `MonitorConfig.auto_stop_on: list[str]` — explicit allow-list of detector
|
|
135
|
+
names whose `stop_service` action is honored. Defaults to
|
|
136
|
+
`["oauth_fail", "disk_critical"]` (builtin pair); operators must add plugin
|
|
137
|
+
detector names to opt them into auto-stop
|
|
138
|
+
- `monitor.on_alert` gains `allowed_stop_names: list[str] | None` keyword
|
|
139
|
+
argument; backward-compatible default falls back to the legacy builtin pair
|
|
140
|
+
- `peek --json` schema bumped to `"1.3"`; new `plugins.detectors: list[str]`
|
|
141
|
+
surfaces what's registered
|
|
142
|
+
- `docs/plugins.md` gains a Detector Protocol chapter + DetectorHelpers
|
|
143
|
+
chapter with worked examples for each helper
|
|
144
|
+
|
|
145
|
+
### Changed
|
|
146
|
+
- `agent_runner.api._poll_once` now concatenates builtin detector alerts
|
|
147
|
+
with plugin detector alerts (`run_plugin_detectors(state)`) before returning
|
|
148
|
+
- `agent_runner.api.monitor_loop` threads `cfg.monitor.auto_stop_on` into
|
|
149
|
+
`monitor.on_alert` for strict gating
|
|
150
|
+
- `tests/invariants/test_peek_schema_version.py` tightened to require
|
|
151
|
+
`schema_version >= "1.3"` and the `plugins.detectors` list shape
|
|
152
|
+
|
|
153
|
+
### Backward compatibility
|
|
154
|
+
- Zero plugins installed → monitor behavior identical to 0.1.4
|
|
155
|
+
- Existing 9 builtin detectors keep their current signatures unchanged
|
|
156
|
+
- Existing `agent-runner.toml` files load without modification; default
|
|
157
|
+
`auto_stop_on` matches the previously-implicit behavior
|
|
158
|
+
- `on_alert(...)` callers without the new kwarg continue to work via the
|
|
159
|
+
default `["oauth_fail", "disk_critical"]` allow-list
|
|
160
|
+
|
|
161
|
+
## [0.1.4] - 2026-05-12
|
|
162
|
+
|
|
163
|
+
### Added
|
|
164
|
+
- `agent_runner.hooks` module — three Protocol-typed plugin extension points:
|
|
165
|
+
`PreRoundHook` (runs after lock acquire, before context write),
|
|
166
|
+
`ContextEnricher` (returns a per-plugin slice stitched into `round-context.json`
|
|
167
|
+
under `base_context[enricher.name]`), and `PostRoundHook` (runs after agent exit,
|
|
168
|
+
before `round_end` event)
|
|
169
|
+
- `agent_runner.hooks.HookContext` — narrow runtime context passed to all hooks
|
|
170
|
+
(`work_dir`, `log_dir`, `project`, `round_num`, `phase`, `agent_name`); does NOT
|
|
171
|
+
expose the full `Config` so internal refactors remain safe
|
|
172
|
+
- `agent_runner.hooks.register_pre_round_hook` / `register_context_enricher` /
|
|
173
|
+
`register_post_round_hook` — public registration API; rejects duplicate `name`
|
|
174
|
+
- `agent_runner.hooks.plugin_context_enrichers()` — sorted list of registered
|
|
175
|
+
enricher names, surfaced via `peek --json`
|
|
176
|
+
- `agent_runner.api_types.RoundResult` — promoted from `runner.py`; superset of
|
|
177
|
+
the prior internal fields plus `phase`, `started_at`, `ended_at`, `log_path` for
|
|
178
|
+
stable `PostRoundHook` consumption
|
|
179
|
+
- `agent_runner` package now also discovers and loads three new entry_points groups
|
|
180
|
+
at first import: `agent_runner.pre_round_hooks`, `agent_runner.context_enrichers`,
|
|
181
|
+
`agent_runner.post_round_hooks`; plugin failures degrade to a `UserWarning`
|
|
182
|
+
- Built-in event kind `hook_failed` — emitted by the runner whenever a plugin hook
|
|
183
|
+
raises; payload includes `{hook_name, hook_kind, error_type, error_message, traceback}`
|
|
184
|
+
with traceback truncated to 2KB (head 1KB + tail 1KB joined by `[truncated]`)
|
|
185
|
+
- `peek --json` schema bumped to `"1.2"`; new `plugins.context_enrichers: list[str]`
|
|
186
|
+
- `docs/plugins.md` — new chapter with end-to-end ContextEnricher example
|
|
187
|
+
- New invariant `tests/invariants/test_round_result_stable.py` guards `RoundResult`
|
|
188
|
+
field set + types across future minors
|
|
189
|
+
|
|
190
|
+
### Changed
|
|
191
|
+
- `agent_runner.runner.run_one_round` integrates hooks at three checkpoints; each
|
|
192
|
+
call is wrapped in `try/except` and surfaces failures via `hook_failed`
|
|
193
|
+
- `tests/invariants/test_peek_schema_version.py` tightened to require
|
|
194
|
+
`schema_version >= "1.2"` and the `plugins.context_enrichers` list shape
|
|
195
|
+
|
|
196
|
+
### Backward compatibility
|
|
197
|
+
- Zero plugins installed → runner behavior identical to 0.1.3
|
|
198
|
+
- `RoundResult` field set is a superset; every prior field is preserved
|
|
199
|
+
- Existing 0.1.x user `agent-runner.toml` files load without modification
|
|
200
|
+
|
|
201
|
+
## [0.1.3] - 2026-05-12
|
|
202
|
+
|
|
203
|
+
### Added
|
|
204
|
+
- `agent_runner.events.register_event_kind(name, *, source)` — public API for plugins to register custom event kinds
|
|
205
|
+
- `agent_runner.events.plugin_event_kinds()` — sorted list of currently-registered plugin event kind names
|
|
206
|
+
- `agent_runner` package now discovers and loads entry_points in group `agent_runner.event_kinds` at first import; plugin failures degrade to a `UserWarning` instead of crashing the supervisor
|
|
207
|
+
- `peek --json` schema bumped to `"1.1"`; new top-level `plugins.event_kinds: list[str]` surfaces what's registered
|
|
208
|
+
- `docs/plugins.md` — plugin authoring stub covering the entry_points convention and the event-kind example
|
|
209
|
+
|
|
210
|
+
### Changed
|
|
211
|
+
- `agent_runner.events.KNOWN_EVENT_KINDS` is now a read-only union view (built-in + plugin) instead of a `frozenset`; `in` and iteration semantics preserved
|
|
212
|
+
- `tests/invariants/test_event_kind_registry.py` rewritten to validate the built-in/plugin split and the registration conflict rules
|
|
213
|
+
- `tests/invariants/test_peek_schema_version.py` tightened to require `schema_version >= "1.1"` and the `plugins.event_kinds` list shape
|
|
214
|
+
|
|
215
|
+
### Backward compatibility
|
|
216
|
+
- Every existing `from agent_runner.events import KNOWN_EVENT_KINDS` import continues to work
|
|
217
|
+
- Every existing `events.emit(...)` callsite continues to work with the same kind strings
|
|
218
|
+
- Existing 0.1.x user `agent-runner.toml` files load without modification
|
|
219
|
+
|
|
220
|
+
## [0.1.2] - 2026-05-12
|
|
221
|
+
|
|
222
|
+
### Added
|
|
223
|
+
- `cfg.agent.name` — optional provider identifier; defaults to `None` (consumers may fall back to `command[0]`)
|
|
224
|
+
- `cfg.prompt.context_injection_mode` — `prepend` (default) / `file` / `none`; controls how round-context reaches the agent
|
|
225
|
+
- `cfg.monitor.auth_fail_patterns` and `cfg.monitor.auth_fail_hint` — generalize the OAuth-fail detector for any provider
|
|
226
|
+
- `cfg.plugins` — placeholder for 0.1.3+ plugin enable/disable; parsed-but-unused in 0.1.2
|
|
227
|
+
- `peek --json` now emits top-level `schema_version: "1.0"` and `plugins: {}` namespace
|
|
228
|
+
|
|
229
|
+
### Changed
|
|
230
|
+
- `startup_check` prompt-smoke error text reframed away from provider-specific wording
|
|
231
|
+
- `scaffold.py` generated TOML annotates `[agent]` block as the reference; encourages swapping for other CLIs
|
|
232
|
+
- Public docs (architecture, quickstart, configuration) reframed: the reference agent is one of many supported CLIs
|
|
233
|
+
- `monitor.detect_oauth_fail` now reads patterns + hint from `cfg.monitor` (SSOT migrated from a hardcoded module constant to `MonitorConfig`)
|
|
234
|
+
|
|
235
|
+
### Backward compatibility
|
|
236
|
+
- All defaults preserve the existing prepend-mode behavior
|
|
237
|
+
- Existing `agent-runner.toml` files continue to load without modification
|
|
238
|
+
- Existing tests pass without modification
|
|
239
|
+
|
|
240
|
+
## [0.1.1] — 2026-05-12
|
|
241
|
+
|
|
242
|
+
Post-release polish: PyPI install path is documented as the primary entry,
|
|
243
|
+
the repository was renamed for naming parity with the distribution, and the
|
|
244
|
+
release workflow now auto-creates GitHub Releases.
|
|
245
|
+
|
|
246
|
+
### Changed
|
|
247
|
+
- README + README.zh now show `pip install cli-agent-runner` as the primary
|
|
248
|
+
install path; the previous `git clone` flow moved to the Development section.
|
|
249
|
+
- Repository renamed from `wan9yu/agent-runner` to `wan9yu/cli-agent-runner`
|
|
250
|
+
for parity with the PyPI distribution name. All in-tree URL references
|
|
251
|
+
updated; GitHub redirects keep old links working.
|
|
252
|
+
|
|
253
|
+
### Build & CI
|
|
254
|
+
- Release workflow now creates a GitHub Release after PyPI publish, attaches
|
|
255
|
+
the sdist + wheel as release artifacts, and pulls release notes from the
|
|
256
|
+
matching CHANGELOG section.
|
|
257
|
+
|
|
258
|
+
## [0.1.0] — 2026-05-12
|
|
259
|
+
|
|
260
|
+
Initial public release on PyPI as `cli-agent-runner`.
|
|
261
|
+
|
|
262
|
+
### Added
|
|
263
|
+
- Three-layer model: Round / Loop / Witness.
|
|
264
|
+
- 13 CLI verbs: `init`, `install`, `uninstall`, `start`, `stop`, `kill`,
|
|
265
|
+
`cancel`, `restart`, `status`, `round`, `serve`, `peek`, `watch`, `monitor`.
|
|
266
|
+
- 11 named defenses (round timeout, process group isolation, orphan stash
|
|
267
|
+
with SHA lock, set-diff classification, smoke check, flock concurrency,
|
|
268
|
+
atomic state writes, event kind registry, and others).
|
|
269
|
+
- 9 monitor detectors (`timeout_rate`, `hung`, `orphan_chain`,
|
|
270
|
+
`disk_warning`, `disk_critical`, `mem_pressure`, `smoke_fail_rate`,
|
|
271
|
+
`oauth_fail`, `network_fail`); `oauth_fail` and `disk_critical` auto-stop
|
|
272
|
+
the service.
|
|
273
|
+
- Local-only and remote (via ssh) monitor modes.
|
|
274
|
+
- Auto-generated docs (`./build.sh docs`) for defenses table, detectors,
|
|
275
|
+
events, config schema, CLI verbs.
|
|
276
|
+
- Literate quickstart: `docs/quickstart.md` is executed as a pytest test.
|
|
277
|
+
- Python public API (`from agent_runner import api`) mirroring CLI verbs.
|
|
278
|
+
- Phase 3 reservation: `[llm]` config section + `agent_runner.critic`
|
|
279
|
+
Protocol stubs (no implementation).
|
|
280
|
+
|
|
281
|
+
### Documentation
|
|
282
|
+
- English README + full Chinese `README.zh.md`.
|
|
283
|
+
- 5 user-facing docs: quickstart, commands, configuration, runbook, architecture.
|
|
284
|
+
|
|
285
|
+
### Build & CI
|
|
286
|
+
- GitHub Actions matrix: Python 3.11/3.12/3.13 × ubuntu / macos.
|
|
287
|
+
- Codecov-uploaded coverage from one canonical matrix cell.
|
|
288
|
+
- Tag-triggered release publishing to PyPI via Trusted Publishing OIDC,
|
|
289
|
+
gated by a manual approval on the `pypi` GitHub environment.
|
|
290
|
+
|
|
291
|
+
[Unreleased]: https://github.com/wan9yu/cli-agent-runner/compare/v0.1.1...HEAD
|
|
292
|
+
[0.1.1]: https://github.com/wan9yu/cli-agent-runner/releases/tag/v0.1.1
|
|
293
|
+
[0.1.0]: https://github.com/wan9yu/cli-agent-runner/releases/tag/v0.1.0
|
|
@@ -9,6 +9,7 @@ git clone https://github.com/wan9yu/cli-agent-runner.git
|
|
|
9
9
|
cd cli-agent-runner
|
|
10
10
|
python3 -m venv .venv && source .venv/bin/activate
|
|
11
11
|
pip install -e ".[dev]"
|
|
12
|
+
git config core.hooksPath .githooks # enables the commit-msg lint hook
|
|
12
13
|
./build.sh check
|
|
13
14
|
```
|
|
14
15
|
|
|
@@ -16,6 +17,13 @@ pip install -e ".[dev]"
|
|
|
16
17
|
+ integration tests, the literate quickstart, and the docs CI gate. It's
|
|
17
18
|
what GitHub Actions runs on every push and PR.
|
|
18
19
|
|
|
20
|
+
`git config core.hooksPath .githooks` activates the in-repo
|
|
21
|
+
[`.githooks/commit-msg`](.githooks/commit-msg) hook which rejects commit
|
|
22
|
+
messages containing `Co-Authored-By:` trailers, robot emojis, or other
|
|
23
|
+
AI-tool attribution patterns. The same check runs in CI (`lint-commits`
|
|
24
|
+
job) and as a pytest invariant (`tests/invariants/test_no_ai_signatures.py`)
|
|
25
|
+
— defense in depth.
|
|
26
|
+
|
|
19
27
|
## Workflow
|
|
20
28
|
|
|
21
29
|
1. Open an issue first for non-trivial changes — saves wasted work on both sides.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cli-agent-runner
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: Restart-on-exit supervisor for autonomous CLI agents
|
|
5
5
|
Project-URL: Homepage, https://github.com/wan9yu/cli-agent-runner
|
|
6
6
|
Project-URL: Documentation, https://github.com/wan9yu/cli-agent-runner#readme
|
|
@@ -37,14 +37,15 @@ Description-Content-Type: text/markdown
|
|
|
37
37
|
|
|
38
38
|
> **[中文](README.zh.md)** · English
|
|
39
39
|
|
|
40
|
-
[](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml) [](https://pypi.org/project/cli-agent-runner/) [](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml) [](https://pypi.org/project/cli-agent-runner/) [](https://pypi.org/project/cli-agent-runner/) [](https://opensource.org/licenses/Apache-2.0) [](https://codecov.io/gh/wan9yu/cli-agent-runner)
|
|
41
41
|
|
|
42
42
|
# agent-runner
|
|
43
43
|
|
|
44
|
-
A restart-on-exit supervisor for autonomous
|
|
45
|
-
Code
|
|
46
|
-
the
|
|
47
|
-
|
|
44
|
+
A restart-on-exit supervisor for autonomous coding CLIs. Tested with Claude
|
|
45
|
+
Code and aider out of the box; any prompt-arg CLI via custom config. Spawn
|
|
46
|
+
the agent round-after-round under defenses that prevent the failure modes
|
|
47
|
+
that bite in production: stuck rounds, orphan commits, OAuth burn loops,
|
|
48
|
+
full disks, runaway memory.
|
|
48
49
|
|
|
49
50
|
```
|
|
50
51
|
┌──────────────────────────────────────────┐
|
|
@@ -130,12 +131,6 @@ agent-runner monitor --json | jq -c # pipe to downstream consumers
|
|
|
130
131
|
- [`docs/runbook.md`](docs/runbook.md) — operator troubleshooting (OAuth, disk, orphan)
|
|
131
132
|
- [`docs/architecture.md`](docs/architecture.md) — 3-layer model, defenses-as-data
|
|
132
133
|
|
|
133
|
-
## Status
|
|
134
|
-
|
|
135
|
-
Phase 2 (operator surface) shipped. Phase 3 (LLM-augmented Critic) reserved —
|
|
136
|
-
`[llm]` config block and `agent_runner.critic` Protocol stubs are in place,
|
|
137
|
-
implementation TBD.
|
|
138
|
-
|
|
139
134
|
## Development
|
|
140
135
|
|
|
141
136
|
```bash
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
> **[中文](README.zh.md)** · English
|
|
2
2
|
|
|
3
|
-
[](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml) [](https://pypi.org/project/cli-agent-runner/) [](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml) [](https://pypi.org/project/cli-agent-runner/) [](https://pypi.org/project/cli-agent-runner/) [](https://opensource.org/licenses/Apache-2.0) [](https://codecov.io/gh/wan9yu/cli-agent-runner)
|
|
4
4
|
|
|
5
5
|
# agent-runner
|
|
6
6
|
|
|
7
|
-
A restart-on-exit supervisor for autonomous
|
|
8
|
-
Code
|
|
9
|
-
the
|
|
10
|
-
|
|
7
|
+
A restart-on-exit supervisor for autonomous coding CLIs. Tested with Claude
|
|
8
|
+
Code and aider out of the box; any prompt-arg CLI via custom config. Spawn
|
|
9
|
+
the agent round-after-round under defenses that prevent the failure modes
|
|
10
|
+
that bite in production: stuck rounds, orphan commits, OAuth burn loops,
|
|
11
|
+
full disks, runaway memory.
|
|
11
12
|
|
|
12
13
|
```
|
|
13
14
|
┌──────────────────────────────────────────┐
|
|
@@ -93,12 +94,6 @@ agent-runner monitor --json | jq -c # pipe to downstream consumers
|
|
|
93
94
|
- [`docs/runbook.md`](docs/runbook.md) — operator troubleshooting (OAuth, disk, orphan)
|
|
94
95
|
- [`docs/architecture.md`](docs/architecture.md) — 3-layer model, defenses-as-data
|
|
95
96
|
|
|
96
|
-
## Status
|
|
97
|
-
|
|
98
|
-
Phase 2 (operator surface) shipped. Phase 3 (LLM-augmented Critic) reserved —
|
|
99
|
-
`[llm]` config block and `agent_runner.critic` Protocol stubs are in place,
|
|
100
|
-
implementation TBD.
|
|
101
|
-
|
|
102
97
|
## Development
|
|
103
98
|
|
|
104
99
|
```bash
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
> 中文 · **[English](README.md)**
|
|
2
2
|
|
|
3
|
-
[](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml) [](https://pypi.org/project/cli-agent-runner/) [](https://github.com/wan9yu/cli-agent-runner/actions/workflows/ci.yml) [](https://pypi.org/project/cli-agent-runner/) [](https://pypi.org/project/cli-agent-runner/) [](https://opensource.org/licenses/Apache-2.0) [](https://codecov.io/gh/wan9yu/cli-agent-runner)
|
|
4
4
|
|
|
5
5
|
# agent-runner
|
|
6
6
|
|
|
@@ -151,11 +151,6 @@ pip install -e ".[dev]"
|
|
|
151
151
|
|
|
152
152
|
只支持 POSIX(Linux / macOS)。Python 3.11+。x86_64 与 aarch64 都跑过。
|
|
153
153
|
|
|
154
|
-
## 项目状态
|
|
155
|
-
|
|
156
|
-
Phase 2(运维界面)已发。Phase 3(LLM Critic)留了接口:`[llm]` 配置段 +
|
|
157
|
-
`agent_runner.critic` Protocol stubs,实现待定。
|
|
158
|
-
|
|
159
154
|
## License
|
|
160
155
|
|
|
161
156
|
[Apache License 2.0](LICENSE).
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Agent Runner — restart-on-exit supervisor for autonomous CLI agents."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
from agent_runner._version import __version__
|
|
7
|
+
except ImportError: # editable install before hatch-vcs has generated _version.py
|
|
8
|
+
__version__ = "0.0.0+unknown"
|
|
9
|
+
|
|
10
|
+
_HOOK_GROUPS = (
|
|
11
|
+
"agent_runner.pre_round_hooks",
|
|
12
|
+
"agent_runner.context_enrichers",
|
|
13
|
+
"agent_runner.post_round_hooks",
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _load_plugins_from_group(group: str) -> None:
|
|
18
|
+
"""Discover and load entry_points in ``group``, isolating per-plugin failures.
|
|
19
|
+
|
|
20
|
+
Called at package import. A broken plugin must not crash the supervisor;
|
|
21
|
+
each failure surfaces as a ``UserWarning``.
|
|
22
|
+
"""
|
|
23
|
+
import warnings
|
|
24
|
+
from importlib.metadata import entry_points
|
|
25
|
+
|
|
26
|
+
for ep in entry_points(group=group):
|
|
27
|
+
try:
|
|
28
|
+
ep.load()
|
|
29
|
+
except Exception as e:
|
|
30
|
+
warnings.warn(
|
|
31
|
+
f"failed to load {group} plugin {ep.name!r}: {e}",
|
|
32
|
+
stacklevel=3,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _load_event_kind_plugins() -> None:
|
|
37
|
+
"""Load plugins that register custom event kinds via ``events.register_event_kind``."""
|
|
38
|
+
_load_plugins_from_group("agent_runner.event_kinds")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _load_hook_plugins() -> None:
|
|
42
|
+
"""Load plugins that register pre_round / context_enricher / post_round hooks."""
|
|
43
|
+
for group in _HOOK_GROUPS:
|
|
44
|
+
_load_plugins_from_group(group)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _load_detector_plugins() -> None:
|
|
48
|
+
"""Load plugins that register custom monitor detectors via ``monitor.register_detector``."""
|
|
49
|
+
_load_plugins_from_group("agent_runner.detectors")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
_load_event_kind_plugins()
|
|
53
|
+
_load_hook_plugins()
|
|
54
|
+
_load_detector_plugins()
|
|
@@ -16,6 +16,7 @@ from pathlib import Path
|
|
|
16
16
|
from agent_runner.config import (
|
|
17
17
|
AgentConfig,
|
|
18
18
|
Config,
|
|
19
|
+
MonitorConfig,
|
|
19
20
|
PromptConfig,
|
|
20
21
|
RuntimeConfig,
|
|
21
22
|
VcsConfig,
|
|
@@ -29,6 +30,7 @@ _SECTIONS = [
|
|
|
29
30
|
("runtime", RuntimeConfig),
|
|
30
31
|
("prompt", PromptConfig),
|
|
31
32
|
("vcs", VcsConfig),
|
|
33
|
+
("monitor", MonitorConfig),
|
|
32
34
|
]
|
|
33
35
|
|
|
34
36
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Shared registry helpers for plugin-extension surfaces.
|
|
2
|
+
|
|
3
|
+
The `name`-keyed unique-registration check is identical across hooks
|
|
4
|
+
(:mod:`agent_runner.hooks`) and detectors (:mod:`agent_runner.monitor`).
|
|
5
|
+
This module is its single source of truth.
|
|
6
|
+
|
|
7
|
+
Event-kind registration in :mod:`agent_runner.events` has DIFFERENT
|
|
8
|
+
semantics (idempotent for same-source re-registration, conflict on
|
|
9
|
+
different-source) and stays in that module.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def ensure_unique(name: str, existing: list, kind: str) -> None:
|
|
16
|
+
"""Raise ValueError if any item in ``existing`` already has ``.name == name``.
|
|
17
|
+
|
|
18
|
+
``kind`` is a short label embedded in the error message (e.g. ``"detector"``,
|
|
19
|
+
``"context_enricher"``).
|
|
20
|
+
"""
|
|
21
|
+
for item in existing:
|
|
22
|
+
if getattr(item, "name", None) == name:
|
|
23
|
+
raise ValueError(f"{kind} {name!r} already registered; refusing to add a second")
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.1.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 1,
|
|
21
|
+
__version__ = version = '0.1.7'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 1, 7)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|