dkitchen 0.2.0__tar.gz → 0.2.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dkitchen
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: A multi-agent workflow for research repos, with the ding CLI for messaging and waking agent sessions
5
5
  Author: 917Dhj
6
6
  License-Expression: MIT
@@ -30,11 +30,27 @@ Provides-Extra: dev
30
30
  Requires-Dist: pytest>=8; extra == "dev"
31
31
  Dynamic: license-file
32
32
 
33
- # dkitchen
33
+ <p align="center">
34
+ <img src="https://raw.githubusercontent.com/917Dhj/dkitchen/main/docs/assets/dkitchen.png" width="240" alt="Two pixel-art robot chefs: the big one rings a service bell, the small one answers with a pan">
35
+ </p>
34
36
 
35
- **English** | [简体中文](https://github.com/917Dhj/dkitchen/blob/main/README.zh-CN.md)
37
+ <h1 align="center">dkitchen</h1>
36
38
 
37
- **You decide what to cook. Your agents run the kitchen.** 🧑‍🍳
39
+ <p align="center">
40
+ <b>English</b> | <a href="https://github.com/917Dhj/dkitchen/blob/main/README.zh-CN.md">简体中文</a>
41
+ </p>
42
+
43
+ <p align="center">
44
+ <b>You decide what to cook. Your agents run the kitchen.</b> 🧑‍🍳
45
+ </p>
46
+
47
+ <p align="center">
48
+ <a href="https://pypi.org/project/dkitchen/"><img src="https://img.shields.io/pypi/v/dkitchen" alt="PyPI"></a>
49
+ <a href="https://pypi.org/project/dkitchen/"><img src="https://img.shields.io/pypi/pyversions/dkitchen" alt="Python"></a>
50
+ <a href="https://github.com/917Dhj/dkitchen/actions/workflows/tests.yml"><img src="https://github.com/917Dhj/dkitchen/actions/workflows/tests.yml/badge.svg" alt="Tests"></a>
51
+ <a href="https://github.com/917Dhj/dkitchen/blob/main/LICENSE"><img src="https://img.shields.io/github/license/917Dhj/dkitchen" alt="License"></a>
52
+ <a href="https://x.com/dahuoji09"><img src="https://img.shields.io/badge/follow-%40dahuoji09-000000?logo=x" alt="X: @dahuoji09"></a>
53
+ </p>
38
54
 
39
55
  dkitchen is the multi-agent workflow I use every day to run my research repo. It gives a set of Claude Code and Codex sessions fixed stations, a shared way to hand off work through GitHub issues, clear rules for when to stop and ask you, and the tools that tie it together. You keep the decisions only you can make: what to research, what to try, what to spend.
40
56
 
@@ -50,6 +66,10 @@ dkitchen sets up your agents the same way. You are the head chef.
50
66
 
51
67
  ## 🧑‍🍳 The kitchen
52
68
 
69
+ <p align="center">
70
+ <img src="https://raw.githubusercontent.com/917Dhj/dkitchen/main/docs/assets/kitchen.gif" width="100%" alt="A pixel-art kitchen: you talk a design through with the designer, the verifier checks the ticket, the orchestrator rings the bell to start a Codex executor on free GPUs, reviews and merges a PR, and brings you one decision to approve">
71
+ </p>
72
+
53
73
  | Station | In a kitchen | What it does | Runs on |
54
74
  | --- | --- | --- | --- |
55
75
  | 👑 **You** | Head chef | Choose the direction, approve designs and budgets, decide what the results mean for your paper. | You |
@@ -1,8 +1,24 @@
1
- # dkitchen
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/917Dhj/dkitchen/main/docs/assets/dkitchen.png" width="240" alt="Two pixel-art robot chefs: the big one rings a service bell, the small one answers with a pan">
3
+ </p>
2
4
 
3
- **English** | [简体中文](https://github.com/917Dhj/dkitchen/blob/main/README.zh-CN.md)
5
+ <h1 align="center">dkitchen</h1>
4
6
 
5
- **You decide what to cook. Your agents run the kitchen.** 🧑‍🍳
7
+ <p align="center">
8
+ <b>English</b> | <a href="https://github.com/917Dhj/dkitchen/blob/main/README.zh-CN.md">简体中文</a>
9
+ </p>
10
+
11
+ <p align="center">
12
+ <b>You decide what to cook. Your agents run the kitchen.</b> 🧑‍🍳
13
+ </p>
14
+
15
+ <p align="center">
16
+ <a href="https://pypi.org/project/dkitchen/"><img src="https://img.shields.io/pypi/v/dkitchen" alt="PyPI"></a>
17
+ <a href="https://pypi.org/project/dkitchen/"><img src="https://img.shields.io/pypi/pyversions/dkitchen" alt="Python"></a>
18
+ <a href="https://github.com/917Dhj/dkitchen/actions/workflows/tests.yml"><img src="https://github.com/917Dhj/dkitchen/actions/workflows/tests.yml/badge.svg" alt="Tests"></a>
19
+ <a href="https://github.com/917Dhj/dkitchen/blob/main/LICENSE"><img src="https://img.shields.io/github/license/917Dhj/dkitchen" alt="License"></a>
20
+ <a href="https://x.com/dahuoji09"><img src="https://img.shields.io/badge/follow-%40dahuoji09-000000?logo=x" alt="X: @dahuoji09"></a>
21
+ </p>
6
22
 
7
23
  dkitchen is the multi-agent workflow I use every day to run my research repo. It gives a set of Claude Code and Codex sessions fixed stations, a shared way to hand off work through GitHub issues, clear rules for when to stop and ask you, and the tools that tie it together. You keep the decisions only you can make: what to research, what to try, what to spend.
8
24
 
@@ -18,6 +34,10 @@ dkitchen sets up your agents the same way. You are the head chef.
18
34
 
19
35
  ## 🧑‍🍳 The kitchen
20
36
 
37
+ <p align="center">
38
+ <img src="https://raw.githubusercontent.com/917Dhj/dkitchen/main/docs/assets/kitchen.gif" width="100%" alt="A pixel-art kitchen: you talk a design through with the designer, the verifier checks the ticket, the orchestrator rings the bell to start a Codex executor on free GPUs, reviews and merges a PR, and brings you one decision to approve">
39
+ </p>
40
+
21
41
  | Station | In a kitchen | What it does | Runs on |
22
42
  | --- | --- | --- | --- |
23
43
  | 👑 **You** | Head chef | Choose the direction, approve designs and budgets, decide what the results mean for your paper. | You |
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "dkitchen"
7
- version = "0.2.0"
7
+ version = "0.2.2"
8
8
  description = "A multi-agent workflow for research repos, with the ding CLI for messaging and waking agent sessions"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -6,7 +6,8 @@ Wakes on:
6
6
  - status labels being added, and newly opened PRs;
7
7
  - stale tickets: no status label, last comment an executor "in progress" older than --stale-hours,
8
8
  no running `ding run` for the ticket, and no live tmux job whose session name holds issue<N>.
9
- On tickets labelled awaiting-user, executor comments wake only for blocked, done, and waiting on design.
9
+ On tickets labelled awaiting-user, executor comments wake only for blocked, done, and waiting on design,
10
+ or when their "waiting on" names the orchestrator, designer, or verifier.
10
11
  Verifier comments never wake on their own, since the verifier also messages the orchestrator;
11
12
  they are listed in the next batch for reference.
12
13
  The state file keeps the time already reported, so rerunning the same command loses nothing.
@@ -61,14 +62,16 @@ def issue_number(url: str) -> int:
61
62
 
62
63
 
63
64
  def role(body: str, config: Config) -> str:
64
- """The executor by its session line; otherwise the station named at the start of the first line; else the user."""
65
+ """The station named at the start of the first line; otherwise the executor by a line starting with its
66
+ session signature; else the user. A session signature quoted inside a line signs nothing."""
65
67
  stations = config.stations
66
- if "Codex session:" in body:
67
- return stations.executor
68
68
  first = next((line for line in body.splitlines() if line.strip()), "")
69
69
  first = re.sub(r"^[\s#*>]+", "", first)
70
- return next((name for name in (stations.designer, stations.verifier, stations.orchestrator)
71
- if first.startswith(name)), stations.user)
70
+ signed = next((name for name in (stations.designer, stations.verifier, stations.orchestrator)
71
+ if first.startswith(name)), None)
72
+ if signed:
73
+ return signed
74
+ return stations.executor if re.search(r"(?m)^[ \t]*Codex session:", body) else stations.user
72
75
 
73
76
 
74
77
  def fields(body: str, config: Config) -> dict[str, str]:
@@ -85,10 +88,11 @@ def state_and_waiting(body: str, config: Config) -> tuple[str, str]:
85
88
  def executor_wakes(body: str, waiting_user: bool, config: Config) -> bool:
86
89
  state, waiting = state_and_waiting(body, config)
87
90
  status, stations = config.status, config.stations
91
+ names = lambda *who: not waiting.startswith(status.none) and any(name in waiting for name in who)
92
+ kitchen = (stations.orchestrator, stations.designer, stations.verifier)
88
93
  if waiting_user:
89
- return state in {status.blocked, status.done, status.waiting_on_design}
90
- names = (stations.orchestrator, stations.designer, stations.verifier, stations.user)
91
- return state != status.in_progress or (not waiting.startswith(status.none) and any(name in waiting for name in names))
94
+ return state in {status.blocked, status.done, status.waiting_on_design} or names(*kitchen)
95
+ return state != status.in_progress or names(*kitchen, stations.user)
92
96
 
93
97
 
94
98
  def summary(body: str, config: Config) -> str:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dkitchen
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: A multi-agent workflow for research repos, with the ding CLI for messaging and waking agent sessions
5
5
  Author: 917Dhj
6
6
  License-Expression: MIT
@@ -30,11 +30,27 @@ Provides-Extra: dev
30
30
  Requires-Dist: pytest>=8; extra == "dev"
31
31
  Dynamic: license-file
32
32
 
33
- # dkitchen
33
+ <p align="center">
34
+ <img src="https://raw.githubusercontent.com/917Dhj/dkitchen/main/docs/assets/dkitchen.png" width="240" alt="Two pixel-art robot chefs: the big one rings a service bell, the small one answers with a pan">
35
+ </p>
34
36
 
35
- **English** | [简体中文](https://github.com/917Dhj/dkitchen/blob/main/README.zh-CN.md)
37
+ <h1 align="center">dkitchen</h1>
36
38
 
37
- **You decide what to cook. Your agents run the kitchen.** 🧑‍🍳
39
+ <p align="center">
40
+ <b>English</b> | <a href="https://github.com/917Dhj/dkitchen/blob/main/README.zh-CN.md">简体中文</a>
41
+ </p>
42
+
43
+ <p align="center">
44
+ <b>You decide what to cook. Your agents run the kitchen.</b> 🧑‍🍳
45
+ </p>
46
+
47
+ <p align="center">
48
+ <a href="https://pypi.org/project/dkitchen/"><img src="https://img.shields.io/pypi/v/dkitchen" alt="PyPI"></a>
49
+ <a href="https://pypi.org/project/dkitchen/"><img src="https://img.shields.io/pypi/pyversions/dkitchen" alt="Python"></a>
50
+ <a href="https://github.com/917Dhj/dkitchen/actions/workflows/tests.yml"><img src="https://github.com/917Dhj/dkitchen/actions/workflows/tests.yml/badge.svg" alt="Tests"></a>
51
+ <a href="https://github.com/917Dhj/dkitchen/blob/main/LICENSE"><img src="https://img.shields.io/github/license/917Dhj/dkitchen" alt="License"></a>
52
+ <a href="https://x.com/dahuoji09"><img src="https://img.shields.io/badge/follow-%40dahuoji09-000000?logo=x" alt="X: @dahuoji09"></a>
53
+ </p>
38
54
 
39
55
  dkitchen is the multi-agent workflow I use every day to run my research repo. It gives a set of Claude Code and Codex sessions fixed stations, a shared way to hand off work through GitHub issues, clear rules for when to stop and ask you, and the tools that tie it together. You keep the decisions only you can make: what to research, what to try, what to spend.
40
56
 
@@ -50,6 +66,10 @@ dkitchen sets up your agents the same way. You are the head chef.
50
66
 
51
67
  ## 🧑‍🍳 The kitchen
52
68
 
69
+ <p align="center">
70
+ <img src="https://raw.githubusercontent.com/917Dhj/dkitchen/main/docs/assets/kitchen.gif" width="100%" alt="A pixel-art kitchen: you talk a design through with the designer, the verifier checks the ticket, the orchestrator rings the bell to start a Codex executor on free GPUs, reviews and merges a PR, and brings you one decision to approve">
71
+ </p>
72
+
53
73
  | Station | In a kitchen | What it does | Runs on |
54
74
  | --- | --- | --- | --- |
55
75
  | 👑 **You** | Head chef | Choose the direction, approve designs and budgets, decide what the results mean for your paper. | You |
@@ -206,6 +206,8 @@ def executor(block):
206
206
  ("Status: in progress\nWaiting on: Designer, for the prompt\nKey numbers: 1\nNext: wait", False, True),
207
207
  ("Status: done\nWaiting on: none\nKey numbers: 1\nNext: merge", False, True),
208
208
  ("Status: waiting on user\nWaiting on: User\nKey numbers: 1\nNext: wait", True, False),
209
+ ("Status: waiting on user\nWaiting on: User to approve; Orchestrator to merge PR #3\nKey numbers: 1\nNext: merge",
210
+ True, True),
209
211
  ("Status: blocked\nWaiting on: none\nKey numbers: 1\nNext: fix", True, True),
210
212
  ])
211
213
  def test_executor_comments_wake_by_status_and_waiting_on(tmp_path, block, waiting_user, wakes):
@@ -222,6 +224,14 @@ def test_chinese_status_words_and_full_width_colons(tmp_path):
222
224
  assert not watch.executor_wakes(executor("状态: 进行中\n在等: 无\n关键数字: 1\n下一步: 跑"), False, loaded)
223
225
 
224
226
 
227
+ def test_an_awaiting_user_ticket_wakes_when_the_comment_also_waits_on_the_kitchen(tmp_path):
228
+ # #209 issuecomment-6179869282: still waiting on the user, but also asking the orchestrator to merge
229
+ loaded = settings(tmp_path, CHINESE)
230
+ body = executor("状态: 等用户\n在等: 用户批准说话人 1,329 次单次作答;总编排重审合入 PR #314\n关键数字: 0\n下一步: 合入")
231
+ assert watch.executor_wakes(body, True, loaded)
232
+ assert not watch.executor_wakes(executor("状态: 等用户\n在等: 用户批准\n关键数字: 0\n下一步: 等"), True, loaded)
233
+
234
+
225
235
  @pytest.fixture
226
236
  def tree(tmp_path):
227
237
  (tmp_path / "pkg").mkdir()
@@ -279,3 +289,14 @@ def test_log_issue_must_be_positive(capsys):
279
289
  with pytest.raises(SystemExit) as exc:
280
290
  ding.main(["log", "--item", "a", "--issue", "0"])
281
291
  assert exc.value.code == 2
292
+
293
+
294
+ @pytest.mark.parametrize("text", [None, CHINESE])
295
+ def test_a_quoted_session_signature_signs_nothing(tmp_path, text):
296
+ loaded = settings(tmp_path, text)
297
+ stations = loaded.stations
298
+ verifier = (f"## {stations.verifier}{stations.separator}#272 run request check\n\n"
299
+ "| request body | ok: it starts with the status block and contains `Codex session:` |\n")
300
+ assert watch.role(verifier, loaded) == stations.verifier
301
+ assert watch.role("I checked it; the body has `Codex session:` in it.", loaded) == stations.user
302
+ assert watch.role(executor("Status: done\nWaiting on: none\nKey numbers: 1\nNext: merge"), loaded) == stations.executor
File without changes
File without changes
File without changes
File without changes
File without changes