codexapi 0.6.6__tar.gz → 0.6.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.
- {codexapi-0.6.6/src/codexapi.egg-info → codexapi-0.6.7}/PKG-INFO +6 -1
- {codexapi-0.6.6 → codexapi-0.6.7}/README.md +5 -0
- {codexapi-0.6.6 → codexapi-0.6.7}/pyproject.toml +1 -1
- {codexapi-0.6.6 → codexapi-0.6.7}/src/codexapi/__init__.py +1 -1
- {codexapi-0.6.6 → codexapi-0.6.7}/src/codexapi/cli.py +18 -0
- {codexapi-0.6.6 → codexapi-0.6.7}/src/codexapi/gh_integration.py +31 -1
- {codexapi-0.6.6 → codexapi-0.6.7/src/codexapi.egg-info}/PKG-INFO +6 -1
- {codexapi-0.6.6 → codexapi-0.6.7}/LICENSE +0 -0
- {codexapi-0.6.6 → codexapi-0.6.7}/setup.cfg +0 -0
- {codexapi-0.6.6 → codexapi-0.6.7}/src/codexapi/__main__.py +0 -0
- {codexapi-0.6.6 → codexapi-0.6.7}/src/codexapi/agent.py +0 -0
- {codexapi-0.6.6 → codexapi-0.6.7}/src/codexapi/foreach.py +0 -0
- {codexapi-0.6.6 → codexapi-0.6.7}/src/codexapi/pushover.py +0 -0
- {codexapi-0.6.6 → codexapi-0.6.7}/src/codexapi/ralph.py +0 -0
- {codexapi-0.6.6 → codexapi-0.6.7}/src/codexapi/rate_limits.py +0 -0
- {codexapi-0.6.6 → codexapi-0.6.7}/src/codexapi/science.py +0 -0
- {codexapi-0.6.6 → codexapi-0.6.7}/src/codexapi/task.py +0 -0
- {codexapi-0.6.6 → codexapi-0.6.7}/src/codexapi/taskfile.py +0 -0
- {codexapi-0.6.6 → codexapi-0.6.7}/src/codexapi/watch.py +0 -0
- {codexapi-0.6.6 → codexapi-0.6.7}/src/codexapi/welfare.py +0 -0
- {codexapi-0.6.6 → codexapi-0.6.7}/src/codexapi.egg-info/SOURCES.txt +0 -0
- {codexapi-0.6.6 → codexapi-0.6.7}/src/codexapi.egg-info/dependency_links.txt +0 -0
- {codexapi-0.6.6 → codexapi-0.6.7}/src/codexapi.egg-info/entry_points.txt +0 -0
- {codexapi-0.6.6 → codexapi-0.6.7}/src/codexapi.egg-info/requires.txt +0 -0
- {codexapi-0.6.6 → codexapi-0.6.7}/src/codexapi.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: codexapi
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.7
|
|
4
4
|
Summary: Minimal Python API for running the Codex CLI.
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: codex,agent,cli,openai
|
|
@@ -94,6 +94,11 @@ Take tasks from a GitHub Project (requires `gh-task`):
|
|
|
94
94
|
```bash
|
|
95
95
|
codexapi task -p owner/projects/3 -n "Your Name" -s Ready task_a.yaml task_b.yaml
|
|
96
96
|
```
|
|
97
|
+
Filter project issues by title before taking them:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
codexapi task -p owner/projects/3 -n "Your Name" --only-matching "/n300/" task_a.yaml task_b.yaml
|
|
101
|
+
```
|
|
97
102
|
Reset owned tasks on a GitHub Project back to Ready:
|
|
98
103
|
|
|
99
104
|
```bash
|
|
@@ -79,6 +79,11 @@ Take tasks from a GitHub Project (requires `gh-task`):
|
|
|
79
79
|
```bash
|
|
80
80
|
codexapi task -p owner/projects/3 -n "Your Name" -s Ready task_a.yaml task_b.yaml
|
|
81
81
|
```
|
|
82
|
+
Filter project issues by title before taking them:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
codexapi task -p owner/projects/3 -n "Your Name" --only-matching "/n300/" task_a.yaml task_b.yaml
|
|
86
|
+
```
|
|
82
87
|
Reset owned tasks on a GitHub Project back to Ready:
|
|
83
88
|
|
|
84
89
|
```bash
|
|
@@ -1106,6 +1106,13 @@ def main(argv=None):
|
|
|
1106
1106
|
"--name",
|
|
1107
1107
|
help="Owner label name for gh-task when using --project.",
|
|
1108
1108
|
)
|
|
1109
|
+
task_parser.add_argument(
|
|
1110
|
+
"--only-matching",
|
|
1111
|
+
help=(
|
|
1112
|
+
"When using --project, only take issues whose title matches this regex. "
|
|
1113
|
+
"Useful for filtering tasks by hardware encoded in the issue title/path."
|
|
1114
|
+
),
|
|
1115
|
+
)
|
|
1109
1116
|
task_parser.add_argument(
|
|
1110
1117
|
"task_args",
|
|
1111
1118
|
nargs="*",
|
|
@@ -1419,6 +1426,11 @@ def main(argv=None):
|
|
|
1419
1426
|
raise SystemExit("--name is required with --project.")
|
|
1420
1427
|
if not args.task_args:
|
|
1421
1428
|
raise SystemExit("task --project requires one or more task files.")
|
|
1429
|
+
if args.only_matching is not None:
|
|
1430
|
+
try:
|
|
1431
|
+
re.compile(args.only_matching)
|
|
1432
|
+
except re.error as exc:
|
|
1433
|
+
raise SystemExit(f"--only-matching regex is invalid: {exc}") from None
|
|
1422
1434
|
from .gh_integration import GhTaskRunner, project_url
|
|
1423
1435
|
from gh_task.errors import TakeError
|
|
1424
1436
|
|
|
@@ -1430,6 +1442,7 @@ def main(argv=None):
|
|
|
1430
1442
|
args.name,
|
|
1431
1443
|
args.task_args,
|
|
1432
1444
|
args.status,
|
|
1445
|
+
args.only_matching,
|
|
1433
1446
|
args.cwd,
|
|
1434
1447
|
args.yolo,
|
|
1435
1448
|
args.flags,
|
|
@@ -1457,6 +1470,7 @@ def main(argv=None):
|
|
|
1457
1470
|
args.name,
|
|
1458
1471
|
args.task_args,
|
|
1459
1472
|
args.status,
|
|
1473
|
+
args.only_matching,
|
|
1460
1474
|
args.cwd,
|
|
1461
1475
|
args.yolo,
|
|
1462
1476
|
args.flags,
|
|
@@ -1482,6 +1496,8 @@ def main(argv=None):
|
|
|
1482
1496
|
raise SystemExit(
|
|
1483
1497
|
"task -f --item requires {{item}} in the task file."
|
|
1484
1498
|
)
|
|
1499
|
+
if args.only_matching is not None:
|
|
1500
|
+
raise SystemExit("--only-matching is only supported with --project.")
|
|
1485
1501
|
if args.check is not None:
|
|
1486
1502
|
raise SystemExit("--check is not allowed with -f.")
|
|
1487
1503
|
if args.max_iterations is not None:
|
|
@@ -1553,6 +1569,8 @@ def main(argv=None):
|
|
|
1553
1569
|
raise SystemExit("--loop is only supported with -p.")
|
|
1554
1570
|
if args.item is not None:
|
|
1555
1571
|
raise SystemExit("--item is only supported with -f.")
|
|
1572
|
+
if args.only_matching is not None:
|
|
1573
|
+
raise SystemExit("--only-matching is only supported with --project.")
|
|
1556
1574
|
if args.max_iterations is None:
|
|
1557
1575
|
args.max_iterations = DEFAULT_MAX_ITERATIONS
|
|
1558
1576
|
if args.max_iterations < 0:
|
|
@@ -5,6 +5,7 @@ from pathlib import Path
|
|
|
5
5
|
|
|
6
6
|
from tqdm import tqdm
|
|
7
7
|
|
|
8
|
+
from gh_task.errors import TakeError
|
|
8
9
|
from gh_task.project import Project, UPDATE_STATUS_MUTATION
|
|
9
10
|
|
|
10
11
|
from .taskfile import TaskFile
|
|
@@ -138,6 +139,34 @@ def _match_task_file(issue, task_map):
|
|
|
138
139
|
return matches[0][1]
|
|
139
140
|
|
|
140
141
|
|
|
142
|
+
def _take_matching_issue(project, status, only_matching):
|
|
143
|
+
"""Take the first available issue whose title matches only_matching.
|
|
144
|
+
|
|
145
|
+
only_matching is a regular expression. When unset/empty, this behaves like
|
|
146
|
+
Project.take(status=...).
|
|
147
|
+
"""
|
|
148
|
+
if not only_matching:
|
|
149
|
+
return project.take(status=status, return_issue=True)
|
|
150
|
+
try:
|
|
151
|
+
pattern = re.compile(only_matching)
|
|
152
|
+
except re.error as exc:
|
|
153
|
+
raise ValueError(f"Invalid only-matching regex {only_matching!r}: {exc}") from exc
|
|
154
|
+
status_name = project._resolve_status_name(status)
|
|
155
|
+
# Filter by title before fetching labels so we don't spam GitHub REST calls for
|
|
156
|
+
# obviously unsupported issues.
|
|
157
|
+
for issue in project._list_items():
|
|
158
|
+
if (issue.status or "").lower() != status_name.lower():
|
|
159
|
+
continue
|
|
160
|
+
title = issue.title or ""
|
|
161
|
+
if not pattern.search(title):
|
|
162
|
+
continue
|
|
163
|
+
if not project._issue_matches_label(issue):
|
|
164
|
+
continue
|
|
165
|
+
if project._try_take(issue, wait_seconds=1.0, strict=False):
|
|
166
|
+
return issue
|
|
167
|
+
raise TakeError(f"No available issues to take in status '{status_name}' matching {only_matching!r}")
|
|
168
|
+
|
|
169
|
+
|
|
141
170
|
def _strip_progress_section(body):
|
|
142
171
|
if not body:
|
|
143
172
|
return ""
|
|
@@ -275,13 +304,14 @@ class GhTaskRunner:
|
|
|
275
304
|
name,
|
|
276
305
|
task_files,
|
|
277
306
|
status="Ready",
|
|
307
|
+
only_matching=None,
|
|
278
308
|
cwd=None,
|
|
279
309
|
yolo=True,
|
|
280
310
|
flags=None,
|
|
281
311
|
):
|
|
282
312
|
task_map = _task_file_map(task_files)
|
|
283
313
|
self.project = Project(project, name, has_label=list(task_map))
|
|
284
|
-
self.issue = self.project
|
|
314
|
+
self.issue = _take_matching_issue(self.project, status, only_matching)
|
|
285
315
|
self.issue = self.project.get_issue(self.issue)
|
|
286
316
|
try:
|
|
287
317
|
task_path = _match_task_file(self.issue, task_map)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: codexapi
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.7
|
|
4
4
|
Summary: Minimal Python API for running the Codex CLI.
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: codex,agent,cli,openai
|
|
@@ -94,6 +94,11 @@ Take tasks from a GitHub Project (requires `gh-task`):
|
|
|
94
94
|
```bash
|
|
95
95
|
codexapi task -p owner/projects/3 -n "Your Name" -s Ready task_a.yaml task_b.yaml
|
|
96
96
|
```
|
|
97
|
+
Filter project issues by title before taking them:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
codexapi task -p owner/projects/3 -n "Your Name" --only-matching "/n300/" task_a.yaml task_b.yaml
|
|
101
|
+
```
|
|
97
102
|
Reset owned tasks on a GitHub Project back to Ready:
|
|
98
103
|
|
|
99
104
|
```bash
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|