kingdom-cli 0.2__tar.gz → 0.2.1__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.
- {kingdom_cli-0.2/src/kingdom_cli.egg-info → kingdom_cli-0.2.1}/PKG-INFO +45 -23
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/README.md +44 -22
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/pyproject.toml +2 -1
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/agent.py +81 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/cli.py +985 -201
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/config.py +104 -30
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/council/base.py +14 -7
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/council/council.py +11 -3
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/harness.py +2 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/state.py +100 -20
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/thread.py +26 -8
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/ticket.py +27 -5
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/tui/app.py +417 -147
- kingdom_cli-0.2.1/src/kingdom/tui/chat.tcss +116 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/tui/poll.py +23 -9
- kingdom_cli-0.2.1/src/kingdom/tui/terminal.py +43 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/tui/widgets.py +61 -81
- {kingdom_cli-0.2 → kingdom_cli-0.2.1/src/kingdom_cli.egg-info}/PKG-INFO +45 -23
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom_cli.egg-info/SOURCES.txt +3 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_agent.py +67 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_cli.py +169 -2
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_cli_council.py +137 -2
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_cli_peasant.py +257 -2
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_cli_ticket.py +647 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_cli_ticket_current.py +2 -2
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_config.py +90 -25
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_done.py +57 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_harness.py +27 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_init.py +73 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_state.py +174 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_thread.py +149 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_tui.py +742 -59
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_tui_clipboard.py +66 -1
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_tui_integration.py +239 -22
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_tui_poll.py +85 -14
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_tui_reply.py +58 -16
- kingdom_cli-0.2.1/tests/test_tui_terminal.py +82 -0
- kingdom_cli-0.2.1/tests/test_tui_thinking_persistence.py +191 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_tui_widgets.py +8 -0
- kingdom_cli-0.2/tests/test_tui_thinking_persistence.py +0 -159
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/LICENSE +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/setup.cfg +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/__init__.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/__main__.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/breakdown.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/council/__init__.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/council/bundle.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/council/worker.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/design.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/parsing.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/session.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/skill/SKILL.md +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/skill/__init__.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/skill/references/__init__.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/skill/references/council.md +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/skill/references/peasants.md +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/skill/references/tickets.md +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/synthesis.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/tui/__init__.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom/tui/clipboard.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom_cli.egg-info/dependency_links.txt +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom_cli.egg-info/entry_points.txt +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom_cli.egg-info/requires.txt +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/src/kingdom_cli.egg-info/top_level.txt +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_breakdown.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_cli_design_breakdown.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_cli_status.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_cli_whoami.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_council.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_design.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_parsing.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_session.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_skill.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_synthesis.py +0 -0
- {kingdom_cli-0.2 → kingdom_cli-0.2.1}/tests/test_ticket.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kingdom-cli
|
|
3
|
-
Version: 0.2
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: A markdown file-based CLI for software development with multi-agent council design, markdown tickets, and background worker loops.
|
|
5
5
|
Author: James Robinson-Bohnslav
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -48,49 +48,71 @@ Gastown minus the polecats.
|
|
|
48
48
|
uv tool install kingdom-cli
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
##
|
|
51
|
+
## Workflow Scales
|
|
52
|
+
|
|
53
|
+
`kd` scales down gracefully. You pick the parts of the workflow that fit the size of the work.
|
|
54
|
+
|
|
55
|
+
### Full workflow (new features)
|
|
52
56
|
|
|
53
|
-
|
|
57
|
+
Design with the council, break into tickets, dispatch peasants, review, and merge.
|
|
54
58
|
|
|
55
59
|
```bash
|
|
56
|
-
kd start
|
|
60
|
+
kd start # initialize branch session
|
|
61
|
+
kd chat --new # discuss design with the council TUI
|
|
62
|
+
kd design approve # lock in the design
|
|
63
|
+
kd breakdown # generate tickets from the design
|
|
64
|
+
kd peasant start <id> # dispatch parallel workers
|
|
65
|
+
kd done # archive and clean up
|
|
57
66
|
```
|
|
58
67
|
|
|
59
|
-
|
|
68
|
+
### Medium workflow (refactors, smaller features)
|
|
60
69
|
|
|
61
|
-
|
|
70
|
+
Pull tickets into a branch, work them directly or with peasants. No design phase needed.
|
|
62
71
|
|
|
63
72
|
```bash
|
|
64
|
-
kd
|
|
73
|
+
kd start
|
|
74
|
+
kd tk pull <id> <id> # pull backlog tickets onto this branch
|
|
75
|
+
kd tk start <id> # work tickets one at a time
|
|
76
|
+
kd tk close <id>
|
|
77
|
+
kd done
|
|
65
78
|
```
|
|
66
79
|
|
|
67
|
-
|
|
80
|
+
### Lightweight workflow (bug fixes)
|
|
81
|
+
|
|
82
|
+
Work a single ticket, close it, make a PR. Or batch several bug-fix tickets on one branch.
|
|
68
83
|
|
|
69
84
|
```bash
|
|
70
|
-
kd
|
|
85
|
+
kd start
|
|
86
|
+
kd tk create "fix: login redirect loop"
|
|
87
|
+
kd tk start <id>
|
|
88
|
+
# ... fix the bug ...
|
|
89
|
+
kd tk close <id>
|
|
90
|
+
kd done
|
|
71
91
|
```
|
|
72
92
|
|
|
73
|
-
|
|
93
|
+
Design docs, council sessions, and peasant workers are all optional. A branch with one ticket and no design doc is a perfectly valid `kd` workflow.
|
|
94
|
+
|
|
95
|
+
## Getting Started
|
|
74
96
|
|
|
75
97
|
```bash
|
|
76
|
-
kd
|
|
77
|
-
kd
|
|
98
|
+
kd init # one-time: create .kd/ directory
|
|
99
|
+
kd start # start a session on the current branch
|
|
78
100
|
```
|
|
79
101
|
|
|
80
|
-
|
|
81
|
-
- Serial: tell Claude Code or Codex to work tickets directly, or run `kd work <id>`.
|
|
82
|
-
- Parallel: dispatch peasants in worktrees.
|
|
102
|
+
Configure council agent CLIs in `.kd/config.json` (check effective config with `kd config show`).
|
|
83
103
|
|
|
84
|
-
|
|
85
|
-
kd peasant start <id>
|
|
86
|
-
kd peasant status
|
|
87
|
-
```
|
|
104
|
+
## Chat Modes
|
|
88
105
|
|
|
89
|
-
|
|
106
|
+
The council chat TUI (`kd chat`) supports four modes, configured via `council.chat.mode`:
|
|
90
107
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
108
|
+
| Mode | First turn | Auto-turns | Default |
|
|
109
|
+
|------|-----------|------------|---------|
|
|
110
|
+
| `natural` | parallel broadcast | shuffled round-robin | yes |
|
|
111
|
+
| `round_robin` | sequential fixed-order | sequential fixed-order | |
|
|
112
|
+
| `manual` | only @mentioned | only @mentioned | |
|
|
113
|
+
| `broadcast` | parallel to all | parallel to all | |
|
|
114
|
+
|
|
115
|
+
LLM-to-LLM @mentions in responses automatically bump the mentioned member to the front of the auto-turn queue.
|
|
94
116
|
|
|
95
117
|
## How It Works
|
|
96
118
|
|
|
@@ -21,49 +21,71 @@ Gastown minus the polecats.
|
|
|
21
21
|
uv tool install kingdom-cli
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
##
|
|
24
|
+
## Workflow Scales
|
|
25
|
+
|
|
26
|
+
`kd` scales down gracefully. You pick the parts of the workflow that fit the size of the work.
|
|
27
|
+
|
|
28
|
+
### Full workflow (new features)
|
|
25
29
|
|
|
26
|
-
|
|
30
|
+
Design with the council, break into tickets, dispatch peasants, review, and merge.
|
|
27
31
|
|
|
28
32
|
```bash
|
|
29
|
-
kd start
|
|
33
|
+
kd start # initialize branch session
|
|
34
|
+
kd chat --new # discuss design with the council TUI
|
|
35
|
+
kd design approve # lock in the design
|
|
36
|
+
kd breakdown # generate tickets from the design
|
|
37
|
+
kd peasant start <id> # dispatch parallel workers
|
|
38
|
+
kd done # archive and clean up
|
|
30
39
|
```
|
|
31
40
|
|
|
32
|
-
|
|
41
|
+
### Medium workflow (refactors, smaller features)
|
|
33
42
|
|
|
34
|
-
|
|
43
|
+
Pull tickets into a branch, work them directly or with peasants. No design phase needed.
|
|
35
44
|
|
|
36
45
|
```bash
|
|
37
|
-
kd
|
|
46
|
+
kd start
|
|
47
|
+
kd tk pull <id> <id> # pull backlog tickets onto this branch
|
|
48
|
+
kd tk start <id> # work tickets one at a time
|
|
49
|
+
kd tk close <id>
|
|
50
|
+
kd done
|
|
38
51
|
```
|
|
39
52
|
|
|
40
|
-
|
|
53
|
+
### Lightweight workflow (bug fixes)
|
|
54
|
+
|
|
55
|
+
Work a single ticket, close it, make a PR. Or batch several bug-fix tickets on one branch.
|
|
41
56
|
|
|
42
57
|
```bash
|
|
43
|
-
kd
|
|
58
|
+
kd start
|
|
59
|
+
kd tk create "fix: login redirect loop"
|
|
60
|
+
kd tk start <id>
|
|
61
|
+
# ... fix the bug ...
|
|
62
|
+
kd tk close <id>
|
|
63
|
+
kd done
|
|
44
64
|
```
|
|
45
65
|
|
|
46
|
-
|
|
66
|
+
Design docs, council sessions, and peasant workers are all optional. A branch with one ticket and no design doc is a perfectly valid `kd` workflow.
|
|
67
|
+
|
|
68
|
+
## Getting Started
|
|
47
69
|
|
|
48
70
|
```bash
|
|
49
|
-
kd
|
|
50
|
-
kd
|
|
71
|
+
kd init # one-time: create .kd/ directory
|
|
72
|
+
kd start # start a session on the current branch
|
|
51
73
|
```
|
|
52
74
|
|
|
53
|
-
|
|
54
|
-
- Serial: tell Claude Code or Codex to work tickets directly, or run `kd work <id>`.
|
|
55
|
-
- Parallel: dispatch peasants in worktrees.
|
|
75
|
+
Configure council agent CLIs in `.kd/config.json` (check effective config with `kd config show`).
|
|
56
76
|
|
|
57
|
-
|
|
58
|
-
kd peasant start <id>
|
|
59
|
-
kd peasant status
|
|
60
|
-
```
|
|
77
|
+
## Chat Modes
|
|
61
78
|
|
|
62
|
-
|
|
79
|
+
The council chat TUI (`kd chat`) supports four modes, configured via `council.chat.mode`:
|
|
63
80
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
81
|
+
| Mode | First turn | Auto-turns | Default |
|
|
82
|
+
|------|-----------|------------|---------|
|
|
83
|
+
| `natural` | parallel broadcast | shuffled round-robin | yes |
|
|
84
|
+
| `round_robin` | sequential fixed-order | sequential fixed-order | |
|
|
85
|
+
| `manual` | only @mentioned | only @mentioned | |
|
|
86
|
+
| `broadcast` | parallel to all | parallel to all | |
|
|
87
|
+
|
|
88
|
+
LLM-to-LLM @mentions in responses automatically bump the mentioned member to the front of the auto-turn queue.
|
|
67
89
|
|
|
68
90
|
## How It Works
|
|
69
91
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "kingdom-cli"
|
|
3
|
-
version = "0.2"
|
|
3
|
+
version = "0.2.1"
|
|
4
4
|
description = "A markdown file-based CLI for software development with multi-agent council design, markdown tickets, and background worker loops."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -42,6 +42,7 @@ where = ["src"]
|
|
|
42
42
|
|
|
43
43
|
[tool.setuptools.package-data]
|
|
44
44
|
"kingdom.skill" = ["*.md", "references/*.md"]
|
|
45
|
+
"kingdom.tui" = ["*.tcss"]
|
|
45
46
|
|
|
46
47
|
[dependency-groups]
|
|
47
48
|
dev = [
|
|
@@ -646,3 +646,84 @@ def extract_stream_thinking(line: str, backend: str) -> str | None:
|
|
|
646
646
|
if extractor is None:
|
|
647
647
|
return None
|
|
648
648
|
return extractor(line)
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
# ---------------------------------------------------------------------------
|
|
652
|
+
# Stream tool-use extractors — extract tool invocation names from NDJSON
|
|
653
|
+
# ---------------------------------------------------------------------------
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
def extract_claude_stream_tool_use(line: str) -> str | None:
|
|
657
|
+
"""Extract tool name from a Claude Code stream-json NDJSON line.
|
|
658
|
+
|
|
659
|
+
Claude Code emits ``content_block_start`` with a ``tool_use`` block
|
|
660
|
+
containing the tool name (e.g. "Read", "Bash", "Write").
|
|
661
|
+
"""
|
|
662
|
+
try:
|
|
663
|
+
event = json.loads(line)
|
|
664
|
+
except json.JSONDecodeError:
|
|
665
|
+
return None
|
|
666
|
+
if not isinstance(event, dict):
|
|
667
|
+
return None
|
|
668
|
+
if event.get("type") == "stream_event":
|
|
669
|
+
event = event.get("event", {})
|
|
670
|
+
if event.get("type") == "content_block_start":
|
|
671
|
+
block = event.get("content_block", {})
|
|
672
|
+
if block.get("type") == "tool_use":
|
|
673
|
+
return block.get("name")
|
|
674
|
+
return None
|
|
675
|
+
|
|
676
|
+
|
|
677
|
+
def extract_cursor_stream_tool_use(line: str) -> str | None:
|
|
678
|
+
"""Extract tool name from a Cursor stream-json NDJSON line.
|
|
679
|
+
|
|
680
|
+
Cursor emits ``{"type": "tool_call", "subtype": "started", ...}``
|
|
681
|
+
when a tool invocation begins. The ``name`` field may or may not
|
|
682
|
+
be present depending on the Cursor version.
|
|
683
|
+
"""
|
|
684
|
+
try:
|
|
685
|
+
event = json.loads(line)
|
|
686
|
+
except json.JSONDecodeError:
|
|
687
|
+
return None
|
|
688
|
+
if not isinstance(event, dict):
|
|
689
|
+
return None
|
|
690
|
+
if event.get("type") == "tool_call" and event.get("subtype") == "started":
|
|
691
|
+
return event.get("name") or "tool"
|
|
692
|
+
return None
|
|
693
|
+
|
|
694
|
+
|
|
695
|
+
def extract_codex_stream_tool_use(line: str) -> str | None:
|
|
696
|
+
"""Extract tool name from a Codex NDJSON line.
|
|
697
|
+
|
|
698
|
+
Codex emits ``item.completed`` events for tool calls with
|
|
699
|
+
``item.type == "function_call"``.
|
|
700
|
+
"""
|
|
701
|
+
try:
|
|
702
|
+
event = json.loads(line)
|
|
703
|
+
except json.JSONDecodeError:
|
|
704
|
+
return None
|
|
705
|
+
if not isinstance(event, dict):
|
|
706
|
+
return None
|
|
707
|
+
if event.get("type") == "item.completed":
|
|
708
|
+
item = event.get("item", {})
|
|
709
|
+
if item.get("type") == "function_call":
|
|
710
|
+
return item.get("name", "tool")
|
|
711
|
+
return None
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
STREAM_TOOL_USE_EXTRACTORS: dict[str, StreamExtractor] = {
|
|
715
|
+
"claude_code": extract_claude_stream_tool_use,
|
|
716
|
+
"codex": extract_codex_stream_tool_use,
|
|
717
|
+
"cursor": extract_cursor_stream_tool_use,
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
|
|
721
|
+
def extract_stream_tool_use(line: str, backend: str) -> str | None:
|
|
722
|
+
"""Extract tool name from a single NDJSON line for the given backend.
|
|
723
|
+
|
|
724
|
+
Returns the tool name string, or None for non-tool-use events.
|
|
725
|
+
"""
|
|
726
|
+
extractor = STREAM_TOOL_USE_EXTRACTORS.get(backend)
|
|
727
|
+
if extractor is None:
|
|
728
|
+
return None
|
|
729
|
+
return extractor(line)
|