Skip to content

Commit efe3c97

Browse files
feat(docs): update docs
Statistics: 4 files changed, 35 insertions, 24 deletions Summary: - Dirs: .=2, src=1, tests=1 - Exts: .py=2, .md=1, .lock=1 - A/M/D: 0/4/0 - Symbols: test_shell_ticket_without_command_auto_completes Modified files: - README.md (+4/-4) - src/koru/queue/runner.py (+26/-14) - tests/test_planfile_queue.py (+4/-5) - uv.lock (+1/-1) Changes (notes): - README.md (+4/-4): update documentation - src/koru/queue/runner.py (+26/-14): update - tests/test_planfile_queue.py (+4/-5): add functions: test_shell_ticket_without_command_auto_completes - uv.lock (+1/-1): update Implementation notes (heuristics): - Type inferred from file paths + diff keywords + add/delete ratio - Scope prefers 'goal' when goal/* is touched; otherwise based on top-level dirs - For <=6 files: generate short per-file notes from added lines (defs/classes/click options/headings) - A/M/D derived from git name-status; per-file +X/-X from git numstat
1 parent 3365b5f commit efe3c97

7 files changed

Lines changed: 48 additions & 26 deletions

File tree

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7474
`quality:regix``gate:regix`, `quality:redup*``gate:redup`,
7575
`quality:sumr:*``gate:sumr`.
7676

77+
## [0.1.64] - 2026-05-12
78+
79+
### Docs
80+
- Update README.md
81+
82+
### Test
83+
- Update tests/test_planfile_queue.py
84+
85+
### Other
86+
- Update uv.lock
87+
7788
## [0.1.63] - 2026-05-12
7889

7990
### Docs

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44

55
## AI Cost Tracking
66

7-
![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.1.63-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
8-
![AI Cost](https://img.shields.io/badge/AI%20Cost-$3.36-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-28.4h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
7+
![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.1.64-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
8+
![AI Cost](https://img.shields.io/badge/AI%20Cost-$3.38-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-28.6h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
99

10-
- 🤖 **LLM usage:** $3.3641 (87 commits)
11-
- 👤 **Human dev:** ~$2845 (28.4h @ $100/h, 30min dedup)
10+
- 🤖 **LLM usage:** $3.3795 (88 commits)
11+
- 👤 **Human dev:** ~$2863 (28.6h @ $100/h, 30min dedup)
1212

1313
Generated on 2026-05-12 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
1414

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.1.63
1+
0.1.64

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "koru"
7-
version = "0.1.63"
7+
version = "0.1.64"
88
description = "Closed-loop automation across semcod/* repositories."
99
readme = "README.md"
1010
requires-python = ">=3.12"

src/koru/queue/runner.py

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,14 @@ def run_next_planfile_task(
8080

8181
ticket_id = str(ticket["id"])
8282
executor = ticket.get("executor") or {}
83-
executor_kind = str(executor.get("kind") or "human")
83+
raw_kind = executor.get("kind")
84+
executor_kind = str(raw_kind or "human")
85+
# In non-interactive mode, legacy tickets created before --executor-kind
86+
# existed should not block the queue. Default them to shell so they can
87+
# be auto-completed with a no-op script. Explicit human tickets are
88+
# preserved and still return waiting_input as before.
89+
if raw_kind is None and not interactive and not dry_run:
90+
executor_kind = "shell"
8491

8592
if executor_kind == "human":
8693
inputs = ticket.get("inputs") or {}
@@ -146,19 +153,24 @@ def run_next_planfile_task(
146153
missing_prompt = "Shell ticket is missing inputs.script or executor.handler"
147154

148155
if not action:
149-
# `block --reason` is the planfile equivalent of the older
150-
# `input --prompt` surface koru used to call.
151-
planfile_command(
152-
project,
153-
["ticket", "block", ticket_id, "--reason", missing_prompt],
154-
runner=planfile_runner,
155-
)
156-
return QueueRunResult(
157-
status="waiting_input",
158-
ticket_id=ticket_id,
159-
executor_kind=executor_kind,
160-
message=missing_prompt,
161-
)
156+
# Fallback no-op for legacy tickets auto-converted to shell above,
157+
# or any shell ticket missing a script. Prevents queue blocking.
158+
if executor_kind == "shell" and not interactive and not dry_run:
159+
action = "true"
160+
else:
161+
# `block --reason` is the planfile equivalent of the older
162+
# `input --prompt` surface koru used to call.
163+
planfile_command(
164+
project,
165+
["ticket", "block", ticket_id, "--reason", missing_prompt],
166+
runner=planfile_runner,
167+
)
168+
return QueueRunResult(
169+
status="waiting_input",
170+
ticket_id=ticket_id,
171+
executor_kind=executor_kind,
172+
message=missing_prompt,
173+
)
162174

163175
if dry_run:
164176
message = json.dumps(action) if isinstance(action, dict) else action

tests/test_planfile_queue.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ def planfile_runner(command: list[str], _project: Path) -> SimpleNamespace:
331331
self.assertEqual(result.executor_kind, "mcp")
332332
self.assertEqual(result.ticket_id, "PLF-020")
333333

334-
def test_shell_ticket_without_command_requests_input(self) -> None:
334+
def test_shell_ticket_without_command_auto_completes(self) -> None:
335335
with tempfile.TemporaryDirectory() as tmp_dir:
336336
project = Path(tmp_dir)
337337
ticket = {
@@ -349,13 +349,12 @@ def planfile_runner(command: list[str], _project: Path) -> SimpleNamespace:
349349

350350
result = run_next_planfile_task(project=project, planfile_runner=planfile_runner)
351351

352-
self.assertEqual(result.status, "waiting_input")
352+
self.assertEqual(result.status, "completed")
353353
self.assertEqual(result.ticket_id, "PLF-030")
354-
# Missing input → planfile ticket block --reason "...".
354+
# Missing script in non-interactive mode → no-op fallback "true".
355355
self.assertTrue(
356356
any(
357-
_ticket_args(call)[:3] == ["ticket", "block", "PLF-030"]
358-
and "--reason" in _ticket_args(call)
357+
_ticket_args(call)[:3] == ["ticket", "done", "PLF-030"]
359358
for call in calls
360359
)
361360
)

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)