claude-dev-env 1.95.0 → 2.0.1
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.
- package/_shared/advisor/CLAUDE.md +2 -2
- package/_shared/advisor/advisor-protocol.md +20 -20
- package/_shared/advisor/scripts/config/advisor_scripts_constants/model_tier_run_validator_constants.py +15 -12
- package/_shared/advisor/scripts/model_tier_run_validator.py +11 -10
- package/_shared/advisor/scripts/tests/test_model_tier_run_validator.py +25 -19
- package/_shared/advisor/scripts/tests/test_tier_model_ids.py +17 -17
- package/_shared/advisor/scripts/tier_model_ids.py +18 -18
- package/_shared/pr-loop/CLAUDE.md +1 -0
- package/_shared/pr-loop/scripts/CLAUDE.md +2 -1
- package/_shared/pr-loop/scripts/README.md +1 -0
- package/_shared/pr-loop/scripts/code_rules_gate.py +253 -1980
- package/_shared/pr-loop/scripts/code_rules_gate_parts/CLAUDE.md +32 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/__init__.py +7 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/added_line_maps.py +268 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/enforcer_loading.py +172 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/gate_arguments.py +70 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/gate_running.py +326 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/git_blob_readers.py +85 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/git_file_sets.py +331 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_running.py +369 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/conftest.py +14 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_added_line_maps.py +118 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_enforcer_loading.py +17 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_gate_arguments.py +29 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_gate_running.py +99 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_git_blob_readers.py +69 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_git_file_sets.py +137 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_staged_test_running.py +116 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_violation_scoping.py +75 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_wrapper_plumb_check.py +49 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/violation_scoping.py +328 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/wrapper_plumb_check.py +206 -0
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/code_rules_gate_constants.py +24 -17
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/reviews_disabled_constants.py +1 -0
- package/_shared/pr-loop/scripts/reviews_disabled.py +19 -2
- package/_shared/pr-loop/scripts/test_code_rules_gate.py +278 -0
- package/_shared/pr-loop/scripts/tests/test_code_rules_gate_constants.py +6 -39
- package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +43 -0
- package/_shared/pr-loop/worker-spawn.md +186 -0
- package/agents/code-verifier.md +1 -1
- package/bin/ever-shipped-skills.mjs +3 -0
- package/bin/expand_home_directory_tokens.mjs +1 -1
- package/bin/install.mjs +5 -2
- package/hooks/advisory/refactor_guard.py +3 -4
- package/hooks/blocking/CLAUDE.md +7 -1
- package/hooks/blocking/block_main_commit.py +2 -2
- package/hooks/blocking/claude_md_orphan_file_blocker.py +75 -699
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/CLAUDE.md +28 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/__init__.py +1 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/config/__init__.py +1 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/config/orphan_blocker_constants.py +18 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/decision.py +81 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/references.py +307 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/scan_plan.py +124 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/subtree_scan.py +179 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/conftest.py +10 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/test_decision.py +34 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/test_references.py +42 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/test_scan_plan.py +27 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/test_subtree_scan.py +30 -0
- package/hooks/blocking/code_rules_boolean_mustcheck.py +1 -1
- package/hooks/blocking/code_rules_mock_completeness.py +1 -1
- package/hooks/blocking/code_rules_optional_params.py +2 -2
- package/hooks/blocking/code_rules_shared.py +1 -1
- package/hooks/blocking/code_rules_test_assertions.py +1 -1
- package/hooks/blocking/code_rules_typeddict_stub.py +1 -1
- package/hooks/blocking/gh_pr_author_enforcer.py +1 -1
- package/hooks/blocking/inventory_intent_records/CLAUDE.md +26 -0
- package/hooks/blocking/inventory_intent_records/__init__.py +1 -0
- package/hooks/blocking/inventory_intent_records/config/__init__.py +1 -0
- package/hooks/blocking/inventory_intent_records/config/intent_records_constants.py +20 -0
- package/hooks/blocking/inventory_intent_records/records.py +271 -0
- package/hooks/blocking/inventory_intent_records/tests/conftest.py +10 -0
- package/hooks/blocking/inventory_intent_records/tests/test_records.py +80 -0
- package/hooks/blocking/package_inventory_stale_blocker.py +54 -384
- package/hooks/blocking/package_inventory_stale_blocker_parts/CLAUDE.md +26 -0
- package/hooks/blocking/package_inventory_stale_blocker_parts/__init__.py +1 -0
- package/hooks/blocking/package_inventory_stale_blocker_parts/config/__init__.py +1 -0
- package/hooks/blocking/package_inventory_stale_blocker_parts/config/inventory_blocker_constants.py +16 -0
- package/hooks/blocking/package_inventory_stale_blocker_parts/decision.py +84 -0
- package/hooks/blocking/package_inventory_stale_blocker_parts/inventory_detection.py +307 -0
- package/hooks/blocking/package_inventory_stale_blocker_parts/tests/conftest.py +10 -0
- package/hooks/blocking/package_inventory_stale_blocker_parts/tests/test_decision.py +38 -0
- package/hooks/blocking/package_inventory_stale_blocker_parts/tests/test_inventory_detection.py +61 -0
- package/hooks/blocking/pii_payload_scan.py +138 -42
- package/hooks/blocking/pii_prevention_blocker.py +185 -291
- package/hooks/blocking/pii_prevention_blocker_parts/CLAUDE.md +24 -0
- package/hooks/blocking/pii_prevention_blocker_parts/__init__.py +1 -0
- package/hooks/blocking/pii_prevention_blocker_parts/config/__init__.py +1 -0
- package/hooks/blocking/pii_prevention_blocker_parts/config/repository_resolution_constants.py +28 -0
- package/hooks/blocking/pii_prevention_blocker_parts/repository_exemption.py +214 -0
- package/hooks/blocking/pii_prevention_blocker_parts/repository_resolution.py +208 -0
- package/hooks/blocking/pr_description_command_parser.py +8 -4
- package/hooks/blocking/precommit_code_rules_gate.py +3 -3
- package/hooks/blocking/tdd_enforcer.py +97 -608
- package/hooks/blocking/tdd_enforcer_parts/CLAUDE.md +30 -0
- package/hooks/blocking/tdd_enforcer_parts/__init__.py +1 -0
- package/hooks/blocking/tdd_enforcer_parts/candidate_paths.py +142 -0
- package/hooks/blocking/tdd_enforcer_parts/config/__init__.py +1 -0
- package/hooks/blocking/tdd_enforcer_parts/config/tdd_enforcer_constants.py +32 -0
- package/hooks/blocking/tdd_enforcer_parts/content_analysis.py +268 -0
- package/hooks/blocking/tdd_enforcer_parts/decisions.py +92 -0
- package/hooks/blocking/tdd_enforcer_parts/freshness.py +80 -0
- package/hooks/blocking/tdd_enforcer_parts/git_tracking.py +63 -0
- package/hooks/blocking/tdd_enforcer_parts/path_classification.py +119 -0
- package/hooks/blocking/tdd_enforcer_parts/tests/conftest.py +10 -0
- package/hooks/blocking/tdd_enforcer_parts/tests/test_candidate_paths.py +31 -0
- package/hooks/blocking/tdd_enforcer_parts/tests/test_content_analysis.py +30 -0
- package/hooks/blocking/tdd_enforcer_parts/tests/test_decisions.py +34 -0
- package/hooks/blocking/tdd_enforcer_parts/tests/test_freshness.py +28 -0
- package/hooks/blocking/tdd_enforcer_parts/tests/test_git_tracking.py +48 -0
- package/hooks/blocking/tdd_enforcer_parts/tests/test_path_classification.py +36 -0
- package/hooks/blocking/test_inventory_deadlock_resolution.py +154 -0
- package/hooks/blocking/test_pii_payload_scan.py +168 -0
- package/hooks/blocking/test_tdd_enforcer_restore.py +108 -0
- package/hooks/blocking/test_verifier_verdict_minter.py +55 -158
- package/hooks/blocking/tests/conftest.py +10 -0
- package/hooks/blocking/tests/test_pii_prevention_blocker.py +260 -0
- package/hooks/blocking/tests/test_repository_exemption.py +105 -0
- package/hooks/blocking/tests/test_repository_resolution.py +108 -0
- package/hooks/diagnostic/hook_log_extractor.py +12 -10
- package/hooks/git-hooks/post_commit.py +3 -4
- package/hooks/hooks_constants/CLAUDE.md +2 -2
- package/hooks/hooks_constants/banned_identifiers_constants.py +0 -1
- package/hooks/hooks_constants/code_rules_path_utils_constants.py +1 -1
- package/hooks/hooks_constants/local_identity.py +59 -8
- package/hooks/hooks_constants/pii_prevention_constants.py +0 -6
- package/hooks/hooks_constants/test_local_identity.py +105 -3
- package/hooks/pyproject.toml +13 -36
- package/hooks/session/plugin_data_dir_cleanup.py +0 -1
- package/hooks/validation/mypy_validator.py +2 -2
- package/hooks/validators/health_check.py +1 -0
- package/hooks/validators/mypy_integration.py +2 -0
- package/hooks/validators/ruff_integration.py +3 -0
- package/hooks/workflow/auto_formatter.py +5 -4
- package/package.json +1 -1
- package/scripts/CLAUDE.md +4 -0
- package/scripts/dev_env_scripts_constants/CLAUDE.md +6 -4
- package/scripts/dev_env_scripts_constants/code_review_constants.py +71 -0
- package/scripts/dev_env_scripts_constants/grok_worker_constants.py +435 -0
- package/scripts/dev_env_scripts_constants/timing.py +7 -1
- package/scripts/grok_headless_runner.py +294 -0
- package/scripts/grok_worker_preflight.py +410 -0
- package/scripts/invoke_code_review.py +463 -0
- package/scripts/resolve_worker_spawn.py +619 -0
- package/scripts/spawn_grok_batch.py +672 -0
- package/scripts/test_grok_headless_runner.py +626 -0
- package/scripts/test_grok_worker_preflight.py +1054 -0
- package/scripts/test_invoke_code_review.py +672 -0
- package/scripts/test_resolve_worker_spawn.py +1014 -0
- package/scripts/test_spawn_grok_batch.py +1017 -0
- package/skills/CLAUDE.md +5 -3
- package/skills/_shared/pr-loop/scripts/build_audit_prompt.py +72 -13
- package/skills/_shared/pr-loop/scripts/build_fix_prompt.py +121 -14
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +78 -0
- package/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +121 -0
- package/skills/_shared/pr-loop/scripts/test_build_fix_prompt.py +196 -6
- package/skills/autoconverge/CLAUDE.md +3 -3
- package/skills/autoconverge/SKILL.md +9 -3
- package/skills/autoconverge/reference/CLAUDE.md +2 -2
- package/skills/autoconverge/reference/convergence.md +33 -11
- package/skills/autoconverge/reference/stop-conditions.md +16 -5
- package/skills/autoconverge/workflow/CLAUDE.md +2 -1
- package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +7 -2
- package/skills/autoconverge/workflow/converge.codex-gate.test.mjs +300 -0
- package/skills/autoconverge/workflow/converge.contract.test.mjs +5 -5
- package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +29 -29
- package/skills/autoconverge/workflow/converge.fix-progress.test.mjs +1 -1
- package/skills/autoconverge/workflow/converge.mjs +200 -16
- package/skills/bugteam/CLAUDE.md +2 -2
- package/skills/bugteam/CONSTRAINTS.md +3 -2
- package/skills/bugteam/PROMPTS.md +7 -6
- package/skills/bugteam/SKILL.md +18 -13
- package/skills/bugteam/reference/audit-and-teammates.md +215 -35
- package/skills/bugteam/reference/design-rationale.md +1 -1
- package/skills/bugteam/reference/obstacles/CLAUDE.md +1 -1
- package/skills/bugteam/reference/team-setup.md +8 -2
- package/skills/codex-review/CLAUDE.md +46 -0
- package/skills/codex-review/SKILL.md +181 -0
- package/skills/codex-review/reference/CLAUDE.md +15 -0
- package/skills/codex-review/reference/cli-contract.md +253 -0
- package/skills/codex-review/reference/loop-integration.md +118 -0
- package/skills/codex-review/scripts/codex_down_classifier.py +98 -0
- package/skills/codex-review/scripts/codex_review_scripts_constants/CLAUDE.md +18 -0
- package/skills/codex-review/scripts/codex_review_scripts_constants/__init__.py +1 -0
- package/skills/codex-review/scripts/codex_review_scripts_constants/classifier_constants.py +35 -0
- package/skills/codex-review/scripts/codex_review_scripts_constants/codex_usage_probe_constants.py +86 -0
- package/skills/codex-review/scripts/codex_review_scripts_constants/findings_constants.py +18 -0
- package/skills/codex-review/scripts/codex_review_scripts_constants/run_constants.py +45 -0
- package/skills/codex-review/scripts/codex_usage_probe.py +573 -0
- package/skills/codex-review/scripts/fixtures/auth_failure_synthetic.txt +1 -0
- package/skills/codex-review/scripts/fixtures/config_load_failure_v0.125.0.txt +1 -0
- package/skills/codex-review/scripts/fixtures/freeform_findings_v0.144.3.txt +6 -0
- package/skills/codex-review/scripts/fixtures/model_rejection_v0.125.0.jsonl +5 -0
- package/skills/codex-review/scripts/fixtures/structured_findings.txt +13 -0
- package/skills/codex-review/scripts/fixtures/success_stream_v0.144.3.jsonl +6 -0
- package/skills/codex-review/scripts/fixtures/unknown_failure_synthetic.txt +1 -0
- package/skills/codex-review/scripts/fixtures/usage_limit_synthetic.txt +1 -0
- package/skills/codex-review/scripts/parse_codex_findings.py +207 -0
- package/skills/codex-review/scripts/run_codex_review.py +415 -0
- package/skills/codex-review/scripts/test_codex_down_classifier.py +143 -0
- package/skills/codex-review/scripts/test_codex_usage_probe.py +678 -0
- package/skills/codex-review/scripts/test_parse_codex_findings.py +130 -0
- package/skills/codex-review/scripts/test_run_codex_review.py +812 -0
- package/skills/codex-review/test_skill_scaffold.py +192 -0
- package/skills/grok-spawn/CLAUDE.md +28 -0
- package/skills/grok-spawn/SKILL.md +226 -0
- package/skills/grok-spawn/reference/flag-profiles.md +132 -0
- package/skills/grok-spawn/reference/worker-briefs.md +152 -0
- package/skills/grokify/SKILL.md +9 -1
- package/skills/grokify/capability-claims.test.mjs +28 -0
- package/skills/grokify/evals/README.md +72 -0
- package/skills/grokify/evals/parse-payload.test.mjs +171 -0
- package/skills/grokify/evals/run-capability-evals.mjs +545 -0
- package/skills/orchestrator/SKILL.md +42 -29
- package/skills/orchestrator-refresh/SKILL.md +17 -9
- package/skills/pr-converge/SKILL.md +34 -13
- package/skills/pr-converge/reference/convergence-gates.md +42 -15
- package/skills/pr-converge/reference/fix-protocol.md +1 -1
- package/skills/pr-converge/reference/ground-rules.md +1 -1
- package/skills/pr-converge/reference/per-tick.md +130 -42
- package/skills/pr-converge/reference/state-schema.md +10 -0
- package/skills/pr-converge/scripts/CLAUDE.md +2 -0
- package/skills/pr-converge/scripts/_pr_converge_path_setup.py +5 -1
- package/skills/pr-converge/scripts/check_convergence.py +605 -29
- package/skills/pr-converge/scripts/check_convergence_availability.py +232 -0
- package/skills/pr-converge/scripts/check_convergence_gates.py +279 -235
- package/skills/pr-converge/scripts/check_convergence_thread_gates.py +1 -1
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/convergence_gate_constants.py +36 -2
- package/skills/pr-converge/scripts/test__pr_converge_path_setup.py +4 -0
- package/skills/pr-converge/scripts/test_check_convergence.py +71 -3
- package/skills/pr-converge/scripts/test_check_convergence_availability.py +326 -0
- package/skills/pr-converge/scripts/test_check_convergence_codex.py +507 -0
- package/skills/pr-converge/scripts/test_check_convergence_contract.py +89 -17
- package/skills/pr-converge/scripts/test_check_convergence_fixture.py +179 -0
- package/skills/pr-converge/scripts/test_check_convergence_gates.py +84 -68
- package/skills/pr-converge/scripts/test_check_convergence_thread_gates.py +24 -0
- package/skills/pr-converge/test_step5_host_branch.py +106 -0
- package/skills/pr-loop-cloud-transport/SKILL.md +2 -0
- package/skills/reviewer-gates/SKILL.md +7 -5
- package/skills/team-advisor/SKILL.md +7 -7
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# CLI contract
|
|
2
|
+
|
|
3
|
+
Observed shape of the Codex CLI review surface the skill classifies from. Fixture capture baseline: `codex` 0.144.3. Scripts under `../scripts/` implement this contract.
|
|
4
|
+
|
|
5
|
+
## Wrapper entrypoint
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
run_codex_review(
|
|
9
|
+
repository_directory=<repo root Path>,
|
|
10
|
+
run_state_directory=<run-state Path>,
|
|
11
|
+
base_branch=<branch> | is_uncommitted=True | commit_sha=<sha> | is_prompt_target=True,
|
|
12
|
+
)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Exactly one target among `base_branch`, `is_uncommitted`, `commit_sha`, and `is_prompt_target`. Zero or more than one raises `ValueError`.
|
|
16
|
+
|
|
17
|
+
### Return shape (`CodexReviewOutcome`)
|
|
18
|
+
|
|
19
|
+
Capture only — skill-level classes `down` / `clean` / `findings` are **not** produced here.
|
|
20
|
+
|
|
21
|
+
| Field | Meaning |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `outcome_class` | `completed` or `codex_down` |
|
|
24
|
+
| `exit_code` | Last process exit code, or a sentinel when none ran (`127` missing binary, `124` timeout, `70` decode error) |
|
|
25
|
+
| `binary_version` | Parsed `codex --version` string, or empty |
|
|
26
|
+
| `jsonl_path` | Path to captured JSONL (`codex-review.jsonl` under the run-state directory), or `None` when review did not run |
|
|
27
|
+
| `agent_message` | Last `agent_message` text from the JSONL stream (stderr text when the run fails with empty agent text) |
|
|
28
|
+
|
|
29
|
+
Detail classes from `classify_codex_run` are a separate step (see Failure classes). They are not fields on `CodexReviewOutcome`.
|
|
30
|
+
|
|
31
|
+
## Command shape
|
|
32
|
+
|
|
33
|
+
### Classifying path: `codex exec … review --json`
|
|
34
|
+
|
|
35
|
+
Skill classification (Step 4) reads only the JSONL stream from the classifying path. The wrapper builds:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
codex exec [exec-options] review --json <one-target>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
| Target | Flag / payload |
|
|
42
|
+
|---|---|
|
|
43
|
+
| Uncommitted | `--uncommitted` |
|
|
44
|
+
| Base branch | `--base <BRANCH>` |
|
|
45
|
+
| Commit | `--commit <SHA>` |
|
|
46
|
+
| Custom instructions | positional PROMPT (`CUSTOM_INSTRUCTIONS_PROMPT`: freeform one-line summary, `Review comment:` heading, then `- [P#]` bullets — not fenced JSON) |
|
|
47
|
+
|
|
48
|
+
`CODEX_MODEL_PIN` is empty in the shipped constants, so `-m` is omitted unless a pin is set.
|
|
49
|
+
|
|
50
|
+
`--json` is required for a classifiable success stream. Without `--json`, stdout is not a Step 4 input.
|
|
51
|
+
|
|
52
|
+
### Ordering rule
|
|
53
|
+
|
|
54
|
+
`codex exec` options belong **before** the `review` subcommand. Review options such as `--json` and `--uncommitted` follow `review`.
|
|
55
|
+
|
|
56
|
+
- Parses: `codex exec review --json --uncommitted`
|
|
57
|
+
- Fails (exit 2, usage on stderr): trailing `-C <DIR>` after `review` (`unexpected argument '-C' found`)
|
|
58
|
+
|
|
59
|
+
Run from the target repo directory (the wrapper sets `cwd` to `repository_directory`), or place `-C <DIR>` before `review`.
|
|
60
|
+
|
|
61
|
+
### `codex review` (non-classifying)
|
|
62
|
+
|
|
63
|
+
Plain `codex review` is a non-interactive review form. It is **not** the skill classifying path: bare `codex review --json` is not a supported classifiable form on the observed CLI (0.144.3). Do not feed plain `codex review` stdout into skill classification.
|
|
64
|
+
|
|
65
|
+
| Form | Role |
|
|
66
|
+
|---|---|
|
|
67
|
+
| `[PROMPT]` | Optional custom review instructions; `-` reads stdin |
|
|
68
|
+
| `-c` / `--config key=value` | Dotted-path overrides, values parsed as TOML |
|
|
69
|
+
| `--uncommitted` | Staged + unstaged + untracked |
|
|
70
|
+
| `--base <BRANCH>` | Diff against a base branch |
|
|
71
|
+
| `--commit <SHA>` | Diff for a commit |
|
|
72
|
+
| `--title <TITLE>` | Review title |
|
|
73
|
+
| `--enable` / `--disable <FEATURE>` | Feature toggles |
|
|
74
|
+
|
|
75
|
+
Exactly one target among `PROMPT`, `--uncommitted`, `--base`, and `--commit`. The four targets are mutually exclusive: a flag target never carries a positional `[PROMPT]`, and the custom-instructions text is itself the fourth target (PROMPT mode only). The same target flags apply under `codex exec … review`.
|
|
76
|
+
|
|
77
|
+
Observed rejection when a flag target is combined with `[PROMPT]` (fixture capture: `codex` 0.144.3):
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
error: the argument '--uncommitted' cannot be used with '[PROMPT]'
|
|
81
|
+
Usage: codex exec review --json --uncommitted [PROMPT]
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Exit code 2.
|
|
85
|
+
|
|
86
|
+
### `codex exec` options (before `review`)
|
|
87
|
+
|
|
88
|
+
| Option | Role |
|
|
89
|
+
|---|---|
|
|
90
|
+
| `-c` / `--config` | Config override |
|
|
91
|
+
| `-i` / `--image` | Image input |
|
|
92
|
+
| `-m` / `--model` | Model id |
|
|
93
|
+
| `--oss` | OSS path |
|
|
94
|
+
| `-p` / `--profile` | Profile |
|
|
95
|
+
| `-s` / `--sandbox <read-only\|workspace-write\|danger-full-access>` | Sandbox mode |
|
|
96
|
+
| `--full-auto` | Full auto |
|
|
97
|
+
| `--dangerously-bypass-approvals-and-sandbox` | Bypass approvals and sandbox |
|
|
98
|
+
| `-C` / `--cd <DIR>` | Working directory |
|
|
99
|
+
| `--json` | JSONL event stream on stdout (required for classification) |
|
|
100
|
+
| `-o` / `--output-last-message` | Write last message to a path |
|
|
101
|
+
|
|
102
|
+
## Probe
|
|
103
|
+
|
|
104
|
+
The wrapper probes before every review. Any failure returns `outcome_class=codex_down` and does not run the review.
|
|
105
|
+
|
|
106
|
+
| Step | Command | Pass rule |
|
|
107
|
+
|---|---|---|
|
|
108
|
+
| Version | `codex --version` | Exit 0; version string parsed from stdout |
|
|
109
|
+
| Shape | `codex exec review --help` | Exit 0; help text contains each required flag as a **whole token** |
|
|
110
|
+
|
|
111
|
+
### Minimum shape signals
|
|
112
|
+
|
|
113
|
+
The `review` subcommand is proven by the probe itself: a CLI without it exits non-zero on `codex exec review --help`, which is already a `codex_down` signal.
|
|
114
|
+
|
|
115
|
+
Required whole-token flags:
|
|
116
|
+
|
|
117
|
+
| Signal | Role |
|
|
118
|
+
|---|---|
|
|
119
|
+
| `--uncommitted` | Staged + unstaged + untracked target |
|
|
120
|
+
| `--base` | Base-branch target |
|
|
121
|
+
| `--commit` | Commit-SHA target |
|
|
122
|
+
| `--json` | JSONL event stream on stdout |
|
|
123
|
+
|
|
124
|
+
Longer lookalikes (`--baseline`, `--uncommitted-only`, `--commit-message`) do not satisfy the required target flags.
|
|
125
|
+
|
|
126
|
+
### Fail-closed rule
|
|
127
|
+
|
|
128
|
+
Any missing signal, non-zero probe exit, missing binary, timeout, or decode failure is `codex_down` (skill class `down`). Do not continue to a review invoke when the probe fails.
|
|
129
|
+
|
|
130
|
+
## Success stream
|
|
131
|
+
|
|
132
|
+
With `--json`, a successful run writes JSONL on stdout and exits 0. The wrapper writes stdout to `run_state_directory/codex-review.jsonl`.
|
|
133
|
+
|
|
134
|
+
Fixture: `../scripts/fixtures/success_stream_v0.144.3.jsonl`.
|
|
135
|
+
|
|
136
|
+
Typical event order:
|
|
137
|
+
|
|
138
|
+
1. `thread.started` — includes `thread_id`
|
|
139
|
+
2. `turn.started`
|
|
140
|
+
3. `item.started` / `item.completed` pairs for `command_execution` items
|
|
141
|
+
4. `item.completed` with `"type":"agent_message"` — review text body
|
|
142
|
+
5. `turn.completed` — `usage` object (`input_tokens`, `cached_input_tokens`, `output_tokens`, `reasoning_output_tokens`)
|
|
143
|
+
|
|
144
|
+
The wrapper extracts the last `item.completed` / `agent_message` / `text` as `agent_message`.
|
|
145
|
+
|
|
146
|
+
### Finding text shapes
|
|
147
|
+
|
|
148
|
+
`parse_codex_findings` reads `agent_message` and never drops non-empty text.
|
|
149
|
+
|
|
150
|
+
| Priority | Shape | Fixture |
|
|
151
|
+
|---|---|---|
|
|
152
|
+
| 1 | Fenced JSON array of objects with keys `title`, `priority`, `file`, `line_range`, `body` | `../scripts/fixtures/structured_findings.txt` |
|
|
153
|
+
| 2 | Freeform bullets `- [P1] <title> — <path>:<start>-<end>` plus body paragraphs | `../scripts/fixtures/freeform_findings_v0.144.3.txt` |
|
|
154
|
+
| 3 | Floor: one unstructured finding whose `body` is the raw text | any non-empty unmatched text |
|
|
155
|
+
|
|
156
|
+
Empty agent text or a structured empty array (`[]`) yields zero findings (`clean` for gate callers).
|
|
157
|
+
|
|
158
|
+
## Failure classes
|
|
159
|
+
|
|
160
|
+
All observed CLI failures map to wrapper `outcome_class=codex_down`. Every nonzero review exit maps to `codex_down`. Wrapper `outcome_class` is the capture success signal: a shape-probe miss can still return `codex_down` when the help process exits 0 but required flags are missing. Callers that need a detail class run `classify_codex_run(exit_code=..., stream_text=...)` separately — that helper treats exit 0 as `completed` and every nonzero exit as `codex_down` plus a detail class. Fixtures under `../scripts/fixtures/` are the source of truth for observed shapes.
|
|
161
|
+
|
|
162
|
+
| Detail class | Outcome | Fixture | Observed shape |
|
|
163
|
+
|---|---|---|---|
|
|
164
|
+
| `completed` | `completed` | `success_stream_v0.144.3.jsonl` | Exit 0; JSONL success stream |
|
|
165
|
+
| `config_error` | `codex_down` | `config_load_failure_v0.125.0.txt` | Exit 1; plain stderr, e.g. `Error loading config.toml: unknown variant 'default', expected 'fast' or 'flex' in 'service_tier'` |
|
|
166
|
+
| `model_error` | `codex_down` | `model_rejection_v0.125.0.jsonl` | Exit 1; JSONL `error` with embedded 400 `invalid_request_error` (`model is not supported` / `requires a newer version of Codex`), then interrupted agent message, then `turn.failed` |
|
|
167
|
+
| `usage_limit` | `codex_down` | `usage_limit_synthetic.txt` | Exit 1; phrase markers such as rate limit, too many requests, `http 429`, ` (429)`, credits exhausted, out of credits, api quota, usage quota (bare status numbers alone are not markers) |
|
|
168
|
+
| `auth_failure` | `codex_down` | `auth_failure_synthetic.txt` | Exit 1; phrase markers such as unauthorized, authentication failed, login required, not authenticated (bare status numbers alone are not markers) |
|
|
169
|
+
| `unknown` | `codex_down` | `unknown_failure_synthetic.txt` | Exit nonzero with no known marker (also empty stream on nonzero exit) |
|
|
170
|
+
|
|
171
|
+
Probe and process failures (missing binary exit `127`, timeout exit `124`, decode error exit `70`, shape probe miss) also return `outcome_class=codex_down` from the wrapper. Skill step 4 maps these to skill class `down`. Detail classification is optional for those paths.
|
|
172
|
+
|
|
173
|
+
CLI parse errors (exit 2, usage on stderr, no JSONL) are `codex_down` with detail `unknown` unless a marker matches.
|
|
174
|
+
|
|
175
|
+
## Wrapper capture boundary
|
|
176
|
+
|
|
177
|
+
Entrypoint: `scripts/run_codex_review.py` → `run_codex_review(...)`.
|
|
178
|
+
|
|
179
|
+
The wrapper is **capture only**. It returns one of two classes:
|
|
180
|
+
|
|
181
|
+
| Wrapper class | Meaning |
|
|
182
|
+
|---|---|
|
|
183
|
+
| `completed` | Review process exited 0; JSONL stream written under `run_state_directory` |
|
|
184
|
+
| `codex_down` | Binary missing, timeout, decode failure, shape miss, or non-zero review exit |
|
|
185
|
+
|
|
186
|
+
Skill-level classes `down` / `clean` / `findings` are **not** produced here. The skill (Step 4) maps:
|
|
187
|
+
|
|
188
|
+
| Skill class | Source |
|
|
189
|
+
|---|---|
|
|
190
|
+
| `down` | Wrapper `codex_down` |
|
|
191
|
+
| `clean` | Wrapper `completed` and findings parse empty |
|
|
192
|
+
| `findings` | Wrapper `completed` and findings parse non-empty |
|
|
193
|
+
|
|
194
|
+
### Caller contracts
|
|
195
|
+
|
|
196
|
+
- Create `run_state_directory` before calling the wrapper; the wrapper writes `codex-review.jsonl` into that directory and does not create parents.
|
|
197
|
+
- A missing `repository_directory` or `run_state_directory` raises `ValueError`. Both are checked before any Codex process starts, so a bad path costs no review run.
|
|
198
|
+
- Treat `outcome_class` as the capture success signal; do not treat `exit_code == 0` alone as success.
|
|
199
|
+
- `codex-review.jsonl` holds the stream's own line endings, so the captured file matches the bytes Codex wrote to stdout.
|
|
200
|
+
|
|
201
|
+
## Skill classification map
|
|
202
|
+
|
|
203
|
+
Skill steps and loop re-entry use three skill-level classes. This page's raw CLI failure name is `codex_down` only.
|
|
204
|
+
|
|
205
|
+
| Skill class (`SKILL.md` Step 4) | Maps from this page | Signal |
|
|
206
|
+
|---|---|---|
|
|
207
|
+
| `down` | Any `codex_down` row; unrecognized probe shape | Non-usable review |
|
|
208
|
+
| `clean` | Wrapper `completed` and `parse_codex_findings(agent_message)` empty (blank text or structured `[]`) | Usable review, zero addressable findings |
|
|
209
|
+
| `findings` | Wrapper `completed` and `parse_codex_findings(agent_message)` non-empty (fenced JSON objects, freeform `- [P#]` bullets, or floor text) | Usable review with addressable findings |
|
|
210
|
+
|
|
211
|
+
## Auth surface
|
|
212
|
+
|
|
213
|
+
Placeholders only — never commit real tokens, hosts, or account ids.
|
|
214
|
+
|
|
215
|
+
| Mode | How |
|
|
216
|
+
|---|---|
|
|
217
|
+
| ChatGPT / file store | Credentials under the Codex home directory as `auth.json`. `CODEX_HOME` relocates that directory. `cli_auth_credentials_store = "file"` in `config.toml` pins the file store. |
|
|
218
|
+
| API key (exec only) | `CODEX_API_KEY=<YOUR_API_KEY>` authenticates a single `codex exec` invocation. |
|
|
219
|
+
| Access-token login | Pipe an enterprise access token into `codex login --with-access-token` (token from a secret store; never inline). |
|
|
220
|
+
|
|
221
|
+
The same `config.toml` serves the desktop app and the CLI. A value one accepts can fail the other's parser; that path surfaces as the `config_error` row above.
|
|
222
|
+
|
|
223
|
+
The wrapper inherits the process environment, so `CODEX_HOME` and `CODEX_API_KEY` pass through when set.
|
|
224
|
+
|
|
225
|
+
## Cloud runbook
|
|
226
|
+
|
|
227
|
+
End-to-end path for a headless host (CI runner, remote agent, or cloud VM). Every account-specific value is a placeholder.
|
|
228
|
+
|
|
229
|
+
1. **Install the CLI.** `npm install -g @openai/codex` (or pin a version that still exposes `codex exec review --json` with `--base` / `--uncommitted` / `--commit`).
|
|
230
|
+
2. **Supply one auth mode from a secret store.**
|
|
231
|
+
- File store: write `auth.json` under `CODEX_HOME=<CODEX_HOME_DIR>` with credentials from the secret store, and set `cli_auth_credentials_store = "file"`.
|
|
232
|
+
- API key: export `CODEX_API_KEY` from the secret store for the process that runs the wrapper.
|
|
233
|
+
- Access token: `printf '%s' "$CODEX_ACCESS_TOKEN" | codex login --with-access-token`.
|
|
234
|
+
3. **Fetch a resolvable base ref** when the target is a PR base branch. A bare `git fetch origin <BASE_BRANCH>` only updates `FETCH_HEAD` on a shallow or unconfigured remote and does **not** create `refs/heads/<BASE_BRANCH>`. Create or update a named ref the wrapper can pass to `--base`:
|
|
235
|
+
|
|
236
|
+
```text
|
|
237
|
+
git fetch origin <BASE_BRANCH>:refs/remotes/origin/<BASE_BRANCH>
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Then pass that remote-tracking name as `base_branch` (for example `origin/<BASE_BRANCH>`), or create a local branch that points at the same commit (`git branch -f <BASE_BRANCH> origin/<BASE_BRANCH>`) and pass the local name.
|
|
241
|
+
4. **Run the wrapper** from the repo root with a writable run-state directory:
|
|
242
|
+
|
|
243
|
+
```text
|
|
244
|
+
run_codex_review(
|
|
245
|
+
repository_directory=<REPO_ROOT>,
|
|
246
|
+
run_state_directory=<RUN_STATE_DIR>,
|
|
247
|
+
base_branch=origin/<BASE_BRANCH>, # PR loops — same ref the fetch step created
|
|
248
|
+
# or is_uncommitted=True # standalone
|
|
249
|
+
)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
5. **Parse JSONL / agent text.** On `outcome_class=completed`, call `parse_codex_findings(agent_message)`.
|
|
253
|
+
6. **Classify failures.** On nonzero exit or `outcome_class=codex_down`, call `classify_codex_run(exit_code=..., stream_text=<stdout+stderr>)` when a detail class is needed. Every non-completed detail class is gate-level `codex_down` (fail closed; orchestrators bypass the clean-SHA requirement rather than block forever — see [loop-integration.md](loop-integration.md)).
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Loop integration
|
|
2
|
+
|
|
3
|
+
How `codex-review` plugs into PR-loop orchestrators and standalone runs. Orchestrator-owned detail lives in the linked pages; this page states each rule once and points outward.
|
|
4
|
+
|
|
5
|
+
## Target selection
|
|
6
|
+
|
|
7
|
+
| Caller context | Target |
|
|
8
|
+
|---|---|
|
|
9
|
+
| PR loop (`pr-converge`, `autoconverge`, `bugteam`, or an open PR on the branch) | Diff against the PR base branch (`base_branch=<pr.base.ref>` / `--base`) |
|
|
10
|
+
| Standalone (no PR) | Uncommitted work (`is_uncommitted=True` / `--uncommitted`: staged + unstaged + untracked) |
|
|
11
|
+
|
|
12
|
+
Do not invent a synthetic commit range when a base branch is available. Wrapper argv and probe rules live in [cli-contract.md](cli-contract.md).
|
|
13
|
+
|
|
14
|
+
## Classification vocabulary
|
|
15
|
+
|
|
16
|
+
Orchestrators re-enter on the skill-level classes from `SKILL.md` Step 4. CLI failures map through `codex_down` in [cli-contract.md](cli-contract.md).
|
|
17
|
+
|
|
18
|
+
| Skill class | CLI observation | Orchestrator next step |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| `down` | `codex_down` / probe miss | Mark the Codex gate skipped or stop per the caller's policy |
|
|
21
|
+
| `clean` | Success stream, no finding bullets | End the Codex gate |
|
|
22
|
+
| `findings` | Success stream with finding bullets | Shared fix path or `pr-fix-protocol` (see Findings handoff) |
|
|
23
|
+
|
|
24
|
+
## Where the gate sits
|
|
25
|
+
|
|
26
|
+
### `pr-converge` (tick-driven)
|
|
27
|
+
|
|
28
|
+
After the terminal Bugbot gate confirms HEAD (or sets `bugbot_down`) and **before** the machine convergence checklist:
|
|
29
|
+
|
|
30
|
+
1. Opt-out probe (`reviews_disabled.py --reviewer codex`)
|
|
31
|
+
2. Usage probe (`codex_usage_probe.py` → `is_codex_review_required`)
|
|
32
|
+
3. Skill / wrapper against the PR base branch
|
|
33
|
+
4. Classify → stamp, fix, or bypass
|
|
34
|
+
5. Convergence checklist (`check_convergence.py`)
|
|
35
|
+
|
|
36
|
+
Owner docs: [pr-converge per-tick Codex step](../../pr-converge/reference/per-tick.md#codex-review-step-conditional) and [convergence gate (g)](../../pr-converge/reference/convergence-gates.md#g-codex-review-gate-conditional-required).
|
|
37
|
+
|
|
38
|
+
### `autoconverge` (single autonomous run)
|
|
39
|
+
|
|
40
|
+
Phase order ends with terminal confirmation gates: Bugbot → Copilot → **CODEX** → FINALIZE (`check_convergence.py`).
|
|
41
|
+
|
|
42
|
+
The CODEX phase calls `runCodexGate(head)`, classifies via `classifyCodexGateOutcome`, then:
|
|
43
|
+
|
|
44
|
+
| Outcome kind | Loop action |
|
|
45
|
+
|---|---|
|
|
46
|
+
| `skip-token` | Set `codexDown`, clear stamp, advance to FINALIZE |
|
|
47
|
+
| `skip-usage` | Clear stamp (no down flag), advance to FINALIZE |
|
|
48
|
+
| `down` | Set `codexDown`, clear stamp, advance to FINALIZE |
|
|
49
|
+
| `fix` (non–code-standard) | Apply fixes via the shared fix path; re-enter CONVERGE |
|
|
50
|
+
| `fix` (standards-only) | Defer via `openStandardsFollowUpOnce`; stamp `codexCleanAt = head`; advance to FINALIZE |
|
|
51
|
+
| `clean` | Stamp `codexCleanAt = head`; advance to FINALIZE |
|
|
52
|
+
| `retry` | Re-run the gate on the same HEAD |
|
|
53
|
+
|
|
54
|
+
Owner doc: [autoconverge convergence CODEX phase](../../autoconverge/reference/convergence.md).
|
|
55
|
+
|
|
56
|
+
## Threshold rule
|
|
57
|
+
|
|
58
|
+
Shared helper only — never restate the numeric percent in callers.
|
|
59
|
+
|
|
60
|
+
- Probe: `python "$HOME/.claude/skills/codex-review/scripts/codex_usage_probe.py"` → JSON `{percent_left, window_reset, source}`.
|
|
61
|
+
- Decision: `is_codex_review_required(percent_left)` from the same module.
|
|
62
|
+
- **Required** only when `percent_left` is known and strictly greater than `WEEKLY_USAGE_GATE_THRESHOLD_PERCENT` (constant in `codex_review_scripts_constants/codex_usage_probe_constants.py`).
|
|
63
|
+
- **Skipped** when `percent_left` is null or at/below the threshold. Skip never blocks ready; do not stamp a clean SHA.
|
|
64
|
+
|
|
65
|
+
`check_convergence.py` applies the same helper on the machine checklist so agent path and checklist stay aligned.
|
|
66
|
+
|
|
67
|
+
## Opt-out token
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
python "$HOME/.claude/_shared/pr-loop/scripts/reviews_disabled.py" --reviewer codex
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
| Exit | Meaning |
|
|
74
|
+
|---|---|
|
|
75
|
+
| 0 | `CLAUDE_REVIEWS_DISABLED` lists `codex` — treat as bypass (`codex_down` / `codexDown`); do not probe usage or run the wrapper |
|
|
76
|
+
| 1 | Continue |
|
|
77
|
+
|
|
78
|
+
Gate semantics for the token live in `reviewer-gates`. This skill does not re-parse the env var.
|
|
79
|
+
|
|
80
|
+
`check_convergence.py` also honors an exported `codex` token (and `--codex-down`) so a re-check without flags still bypasses.
|
|
81
|
+
|
|
82
|
+
## State fields
|
|
83
|
+
|
|
84
|
+
| Field | pr-converge (job state / checklist) | autoconverge (run locals → checklist flags) |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| Clean stamp | `codex_clean_at` — HEAD SHA of last clean skill run, or `null` | `codexCleanAt` → `--codex-clean-at <SHA>` |
|
|
87
|
+
| Down / bypass | `codex_down` — `true` on wrapper `codex_down`, opt-out token, or explicit `--codex-down` | `codexDown` → `--codex-down` |
|
|
88
|
+
|
|
89
|
+
Rules (stated once):
|
|
90
|
+
|
|
91
|
+
- Stamp equals `current_head` only when the threshold rule requires a review.
|
|
92
|
+
- Push invalidates both fields (reset stamp to `null`, down to `false`); the next Codex entry re-probes opt-out and usage.
|
|
93
|
+
- While down/bypass is true, the machine gate never blocks ready.
|
|
94
|
+
|
|
95
|
+
Schema detail: [pr-converge state schema](../../pr-converge/reference/state-schema.md). Checklist labels and detail strings: [convergence gate (g)](../../pr-converge/reference/convergence-gates.md#g-codex-review-gate-conditional-required).
|
|
96
|
+
|
|
97
|
+
## Findings handoff
|
|
98
|
+
|
|
99
|
+
Split by caller — do not mix orchestrator vocabularies.
|
|
100
|
+
|
|
101
|
+
| Caller | On `findings` |
|
|
102
|
+
|---|---|
|
|
103
|
+
| Standalone `/codex-review` | Invoke `pr-fix-protocol` by name with the findings payload, PR scope, and worktree path. That protocol owns test-first fixes, commit, push, and reply-and-resolve when threads exist. |
|
|
104
|
+
| `pr-converge` terminal Codex step | Apply the **shared fix protocol** (same family as other pr-converge findings). Reset push-invalidated markers (all `*_clean_at`, `merge_state_status`, `bugbot_down`, `bugbot_acknowledged_at`, `codex_down`); set `phase = CODE_REVIEW`; schedule the next wakeup. Owner: [pr-converge per-tick Codex step](../../pr-converge/reference/per-tick.md#codex-review-step-conditional). |
|
|
105
|
+
| `autoconverge` CODEX phase | Do **not** call `pr-fix-protocol` by name. Route from the CODEX outcome table above — non-code-standard findings use the orchestrator shared fix path (`applyFixes`) and re-enter CONVERGE; standards-only findings defer a follow-up, stamp `codexCleanAt`, and advance to FINALIZE with no fix push. Owner: [autoconverge convergence CODEX phase](../../autoconverge/reference/convergence.md). |
|
|
106
|
+
|
|
107
|
+
Codex gate findings are local (no GitHub review thread). Reply-and-resolve applies only when a PR already carries threads from another reviewer.
|
|
108
|
+
|
|
109
|
+
## Re-entry after a fix
|
|
110
|
+
|
|
111
|
+
Orchestrators that keep looping after a push:
|
|
112
|
+
|
|
113
|
+
1. Re-resolve current HEAD (push cleared clean stamps and down flags).
|
|
114
|
+
2. Re-run internal converge / code-review phases as the orchestrator requires (`pr-converge` re-enters at `CODE_REVIEW` after a findings fix; `autoconverge` re-enters CONVERGE after non-standard fixes).
|
|
115
|
+
3. Re-enter the Codex gate against the same target class (PR base branch).
|
|
116
|
+
4. Re-classify: `clean` stamps and ends the Codex gate; `findings` follows the caller-specific handoff table above; `down` / opt-out / usage-skip advances without blocking.
|
|
117
|
+
|
|
118
|
+
Standalone skill re-entry (babysit mode): re-resolve HEAD, re-run the classifying path (`codex exec … review --json`) on the same target class, re-classify.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""Classify Codex run streams into down-detail and gate outcome classes.
|
|
2
|
+
|
|
3
|
+
::
|
|
4
|
+
|
|
5
|
+
classification = classify_codex_run(exit_code=1, stream_text=stderr_text)
|
|
6
|
+
classification.detail_class # usage_limit | auth_failure | ...
|
|
7
|
+
classification.outcome_class # codex_down | completed
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from dataclasses import dataclass
|
|
13
|
+
|
|
14
|
+
from codex_review_scripts_constants.classifier_constants import (
|
|
15
|
+
ALL_AUTH_FAILURE_MARKERS,
|
|
16
|
+
ALL_CONFIG_ERROR_MARKERS,
|
|
17
|
+
ALL_MODEL_ERROR_MARKERS,
|
|
18
|
+
ALL_USAGE_LIMIT_MARKERS,
|
|
19
|
+
FAILURE_CLASS_AUTH_FAILURE,
|
|
20
|
+
FAILURE_CLASS_CONFIG_ERROR,
|
|
21
|
+
FAILURE_CLASS_MODEL_ERROR,
|
|
22
|
+
FAILURE_CLASS_UNKNOWN,
|
|
23
|
+
FAILURE_CLASS_USAGE_LIMIT,
|
|
24
|
+
SUCCESS_EXIT_CODE,
|
|
25
|
+
)
|
|
26
|
+
from codex_review_scripts_constants.run_constants import (
|
|
27
|
+
OUTCOME_CLASS_CODEX_DOWN,
|
|
28
|
+
OUTCOME_CLASS_COMPLETED,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass(frozen=True)
|
|
33
|
+
class CodexRunClassification:
|
|
34
|
+
"""Fine-grained failure class plus the gate-level outcome class.
|
|
35
|
+
|
|
36
|
+
::
|
|
37
|
+
|
|
38
|
+
CodexRunClassification(
|
|
39
|
+
detail_class="config_error",
|
|
40
|
+
outcome_class="codex_down",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
Attributes:
|
|
44
|
+
detail_class: ``completed`` or a failure class name.
|
|
45
|
+
outcome_class: ``completed`` or ``codex_down`` for the conditional gate.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
detail_class: str
|
|
49
|
+
outcome_class: str
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _stream_contains_marker(stream_text: str, all_markers: tuple[str, ...]) -> bool:
|
|
53
|
+
lowered_stream = stream_text.lower()
|
|
54
|
+
return any(each_marker in lowered_stream for each_marker in all_markers)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _classify_failure_detail(stream_text: str) -> str:
|
|
58
|
+
if _stream_contains_marker(stream_text, ALL_CONFIG_ERROR_MARKERS):
|
|
59
|
+
return FAILURE_CLASS_CONFIG_ERROR
|
|
60
|
+
if _stream_contains_marker(stream_text, ALL_MODEL_ERROR_MARKERS):
|
|
61
|
+
return FAILURE_CLASS_MODEL_ERROR
|
|
62
|
+
if _stream_contains_marker(stream_text, ALL_USAGE_LIMIT_MARKERS):
|
|
63
|
+
return FAILURE_CLASS_USAGE_LIMIT
|
|
64
|
+
if _stream_contains_marker(stream_text, ALL_AUTH_FAILURE_MARKERS):
|
|
65
|
+
return FAILURE_CLASS_AUTH_FAILURE
|
|
66
|
+
return FAILURE_CLASS_UNKNOWN
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def classify_codex_run(*, exit_code: int, stream_text: str) -> CodexRunClassification:
|
|
70
|
+
"""Map exit code and stream text to detail and gate outcome classes.
|
|
71
|
+
|
|
72
|
+
::
|
|
73
|
+
|
|
74
|
+
classify_codex_run(exit_code=0, stream_text=success_jsonl)
|
|
75
|
+
# ok: detail_class=completed, outcome_class=completed
|
|
76
|
+
classify_codex_run(exit_code=1, stream_text="rate limit")
|
|
77
|
+
# ok: detail_class=usage_limit, outcome_class=codex_down
|
|
78
|
+
|
|
79
|
+
Exit zero is a completed review. Every other class — including
|
|
80
|
+
``unknown`` for nonzero exits and unparseable text — maps to
|
|
81
|
+
``codex_down`` so the conditional gate fails closed.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
exit_code: Process exit code from the Codex review invocation.
|
|
85
|
+
stream_text: Captured stdout JSONL and/or stderr text.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
Detail class and gate outcome class for the run.
|
|
89
|
+
"""
|
|
90
|
+
if exit_code == SUCCESS_EXIT_CODE:
|
|
91
|
+
return CodexRunClassification(
|
|
92
|
+
detail_class=OUTCOME_CLASS_COMPLETED,
|
|
93
|
+
outcome_class=OUTCOME_CLASS_COMPLETED,
|
|
94
|
+
)
|
|
95
|
+
return CodexRunClassification(
|
|
96
|
+
detail_class=_classify_failure_detail(stream_text),
|
|
97
|
+
outcome_class=OUTCOME_CLASS_CODEX_DOWN,
|
|
98
|
+
)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# codex-review/scripts/codex_review_scripts_constants
|
|
2
|
+
|
|
3
|
+
Python package of named constants imported by codex-review scripts. Importing from this package keeps magic values out of script bodies.
|
|
4
|
+
|
|
5
|
+
## Modules
|
|
6
|
+
|
|
7
|
+
| File | Constants for |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `__init__.py` | Package marker and package docstring. |
|
|
10
|
+
| `run_constants.py` | Binary name, flag strings, custom-instructions prompt, version-probe pattern, timeout default, decode/timeout exit sentinels, flag_token_pattern suffix (whole-token shape match), JSONL keys, and capture outcome class labels for `run_codex_review.py`. |
|
|
11
|
+
| `findings_constants.py` | Finding field keys, fenced-JSON and freeform patterns for `parse_codex_findings.py`. |
|
|
12
|
+
| `classifier_constants.py` | Failure class names and stream markers for `codex_down_classifier.py`. |
|
|
13
|
+
| `run_constants.py` | Binary name, flag strings, custom-instructions prompt, version-probe pattern, timeout default, decode/timeout exit sentinels, flag_token_pattern suffix (whole-token shape match), JSONL keys, JSONL capture filename and newline mode, and capture outcome class labels for `run_codex_review.py`. |
|
|
14
|
+
| `codex_usage_probe_constants.py` | The weekly-usage probe CLI: gate threshold, report JSON keys, app-server JSON-RPC surface, rate-limit field keys, weekly-window sizing, text-status parse patterns, source labels, and exit codes. |
|
|
15
|
+
|
|
16
|
+
## Convention
|
|
17
|
+
|
|
18
|
+
Scripts import from this package at module scope. No constant is defined inline in a script body — the hook enforces this at write time.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Named constants for the codex-review skill scripts."""
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Named constants for the Codex down-classifier."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
FAILURE_CLASS_USAGE_LIMIT = "usage_limit"
|
|
6
|
+
FAILURE_CLASS_AUTH_FAILURE = "auth_failure"
|
|
7
|
+
FAILURE_CLASS_CONFIG_ERROR = "config_error"
|
|
8
|
+
FAILURE_CLASS_MODEL_ERROR = "model_error"
|
|
9
|
+
FAILURE_CLASS_UNKNOWN = "unknown"
|
|
10
|
+
ALL_CONFIG_ERROR_MARKERS = (
|
|
11
|
+
"error loading config.toml",
|
|
12
|
+
"unknown variant",
|
|
13
|
+
)
|
|
14
|
+
ALL_MODEL_ERROR_MARKERS = (
|
|
15
|
+
"invalid_request_error",
|
|
16
|
+
"model is not supported",
|
|
17
|
+
"requires a newer version of codex",
|
|
18
|
+
)
|
|
19
|
+
ALL_USAGE_LIMIT_MARKERS = (
|
|
20
|
+
"rate limit",
|
|
21
|
+
"too many requests",
|
|
22
|
+
"http 429",
|
|
23
|
+
" (429)",
|
|
24
|
+
"credits exhausted",
|
|
25
|
+
"out of credits",
|
|
26
|
+
"api quota",
|
|
27
|
+
"usage quota",
|
|
28
|
+
)
|
|
29
|
+
ALL_AUTH_FAILURE_MARKERS = (
|
|
30
|
+
"unauthorized",
|
|
31
|
+
"authentication failed",
|
|
32
|
+
"login required",
|
|
33
|
+
"not authenticated",
|
|
34
|
+
)
|
|
35
|
+
SUCCESS_EXIT_CODE = 0
|
package/skills/codex-review/scripts/codex_review_scripts_constants/codex_usage_probe_constants.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Constants for the Codex weekly-usage probe CLI.
|
|
2
|
+
|
|
3
|
+
Groups: gate threshold, probe report JSON keys, app-server JSON-RPC surface,
|
|
4
|
+
rate-limit snapshot field keys, weekly-window sizing, parse patterns for
|
|
5
|
+
text status output, source labels, and exit codes.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
WEEKLY_USAGE_GATE_THRESHOLD_PERCENT = 10
|
|
11
|
+
|
|
12
|
+
USAGE_REPORT_KEY_PERCENT_LEFT = "percent_left"
|
|
13
|
+
USAGE_REPORT_KEY_WINDOW_RESET = "window_reset"
|
|
14
|
+
USAGE_REPORT_KEY_SOURCE = "source"
|
|
15
|
+
|
|
16
|
+
CODEX_BINARY_NAME = "codex"
|
|
17
|
+
ALL_APP_SERVER_COMMAND_PARTS = ("app-server", "--listen", "stdio://")
|
|
18
|
+
APP_SERVER_TIMEOUT_SECONDS = 30
|
|
19
|
+
READER_THREAD_JOIN_TIMEOUT_SECONDS = 2
|
|
20
|
+
PROCESS_TREE_WAIT_TIMEOUT_SECONDS = 5
|
|
21
|
+
WINDOWS_OS_NAME = "nt"
|
|
22
|
+
WINDOWS_COMMAND_SHELL = "cmd"
|
|
23
|
+
WINDOWS_COMMAND_SHELL_RUN_FLAG = "/c"
|
|
24
|
+
ALL_WINDOWS_SCRIPT_SUFFIXES = (".cmd", ".bat")
|
|
25
|
+
WINDOWS_TASKKILL_COMMAND = "taskkill"
|
|
26
|
+
WINDOWS_TASKKILL_FORCE_FLAG = "/F"
|
|
27
|
+
WINDOWS_TASKKILL_TREE_FLAG = "/T"
|
|
28
|
+
WINDOWS_TASKKILL_PID_FLAG = "/PID"
|
|
29
|
+
|
|
30
|
+
JSONRPC_VERSION = "2.0"
|
|
31
|
+
JSONRPC_KEY_ID = "id"
|
|
32
|
+
JSONRPC_KEY_METHOD = "method"
|
|
33
|
+
JSONRPC_KEY_PARAMS = "params"
|
|
34
|
+
JSONRPC_KEY_REPLY_BODY = "result"
|
|
35
|
+
JSONRPC_KEY_ERROR = "error"
|
|
36
|
+
JSONRPC_KEY_VERSION = "jsonrpc"
|
|
37
|
+
|
|
38
|
+
INITIALIZE_REQUEST_ID = 1
|
|
39
|
+
RATE_LIMITS_REQUEST_ID = 2
|
|
40
|
+
METHOD_INITIALIZE = "initialize"
|
|
41
|
+
METHOD_INITIALIZED = "initialized"
|
|
42
|
+
METHOD_RATE_LIMITS_READ = "account/rateLimits/read"
|
|
43
|
+
|
|
44
|
+
CLIENT_INFO_KEY = "clientInfo"
|
|
45
|
+
CLIENT_INFO_NAME_KEY = "name"
|
|
46
|
+
CLIENT_INFO_VERSION_KEY = "version"
|
|
47
|
+
CLIENT_INFO_NAME = "codex-usage-probe"
|
|
48
|
+
CLIENT_INFO_VERSION = "1.0.0"
|
|
49
|
+
CAPABILITIES_KEY = "capabilities"
|
|
50
|
+
EXPERIMENTAL_API_KEY = "experimentalApi"
|
|
51
|
+
|
|
52
|
+
RATE_LIMITS_KEY = "rateLimits"
|
|
53
|
+
PRIMARY_WINDOW_KEY = "primary"
|
|
54
|
+
SECONDARY_WINDOW_KEY = "secondary"
|
|
55
|
+
USED_PERCENT_KEY = "usedPercent"
|
|
56
|
+
RESETS_AT_KEY = "resetsAt"
|
|
57
|
+
WINDOW_DURATION_MINS_KEY = "windowDurationMins"
|
|
58
|
+
|
|
59
|
+
WEEKLY_WINDOW_DURATION_MINUTES = 10080
|
|
60
|
+
PERCENT_FULL = 100
|
|
61
|
+
PERCENT_EMPTY = 0
|
|
62
|
+
|
|
63
|
+
SOURCE_APP_SERVER_RATE_LIMITS = "codex app-server account/rateLimits/read"
|
|
64
|
+
SOURCE_TEXT_STATUS = "text-status"
|
|
65
|
+
SOURCE_NO_USAGE_SURFACE = "no-usage-surface"
|
|
66
|
+
|
|
67
|
+
TEXT_WEEKLY_PERCENT_LEFT_PATTERN = (
|
|
68
|
+
r"(?i)weekly(?:\s+(?:limit|usage|cap))?"
|
|
69
|
+
r"[^\n%]{0,40}?"
|
|
70
|
+
r"(?P<percent>\d{1,3}(?:\.\d+)?)\s*%\s*(?:left|remaining)"
|
|
71
|
+
)
|
|
72
|
+
TEXT_WEEKLY_USED_PERCENT_PATTERN = (
|
|
73
|
+
r"(?i)weekly(?:\s+(?:limit|usage|cap))?"
|
|
74
|
+
r"[^\n%]{0,40}?"
|
|
75
|
+
r"(?P<percent>\d{1,3}(?:\.\d+)?)\s*%\s*(?:used|consumed)"
|
|
76
|
+
)
|
|
77
|
+
TEXT_WINDOW_RESET_PATTERN = (
|
|
78
|
+
r"(?i)(?:weekly\s+)?(?:window\s+)?resets?(?:\s+at)?"
|
|
79
|
+
r"[:\s]+(?P<reset>[^\s)\].,;]+)"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
EXIT_CODE_SUCCESS = 0
|
|
83
|
+
EXIT_CODE_CRASH = 1
|
|
84
|
+
|
|
85
|
+
UTF8_ENCODING = "utf-8"
|
|
86
|
+
NEWLINE = "\n"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Named constants for the Codex findings parser."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
FINDING_KEY_TITLE = "title"
|
|
6
|
+
FINDING_KEY_PRIORITY = "priority"
|
|
7
|
+
FINDING_KEY_FILE = "file"
|
|
8
|
+
FINDING_KEY_LINE_RANGE = "line_range"
|
|
9
|
+
FINDING_KEY_BODY = "body"
|
|
10
|
+
FENCED_JSON_BLOCK_PATTERN = r"```(?:json)?\s*\n(.*?)\n```"
|
|
11
|
+
FREEFORM_FINDING_LINE_PATTERN = (
|
|
12
|
+
r"^-\s*\[(?P<priority>P\d+)\]\s+"
|
|
13
|
+
r"(?P<title>.+?)\s+[—–-]\s+"
|
|
14
|
+
r"(?P<file_path>.+?):(?P<line_range>\d+-\d+)\s*$"
|
|
15
|
+
)
|
|
16
|
+
FREEFORM_BULLET_PREFIX = "- ["
|
|
17
|
+
EMPTY_STRING = ""
|
|
18
|
+
NEWLINE = "\n"
|