subtask-mcp 0.2.9__tar.gz → 0.2.10__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.
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/PKG-INFO +2 -2
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/README.md +1 -1
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/__init__.py +1 -1
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/stephook.py +31 -27
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask_mcp.egg-info/PKG-INFO +2 -2
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/tests/test_stephook.py +24 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/LICENSE +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/pyproject.toml +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/setup.cfg +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/admission.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/capacity.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/cli.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/config.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/core.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/doctor.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/engines/__init__.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/engines/base.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/engines/claude_api.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/engines/codex.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/engines/demo.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/engines/dsh.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/engines/kimi.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/engines/opencode.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/engines/registry.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/events.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/evidence.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/fastserver.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/gc.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/install/__init__.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/install/claude_plugin.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/install/clients.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/install/commands.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/install/doctor.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/install/fileops.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/install/installer.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/install/ownership.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/install/tomledit.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/jobs.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/ledger.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/narrate.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/policy.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/procid.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/progress.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/redact.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/roi.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/router.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/runners.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/schemacheck.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/server.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/skill/SKILL.md +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/telemetry.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/tools.json +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask/worker.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask_mcp.egg-info/SOURCES.txt +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask_mcp.egg-info/dependency_links.txt +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask_mcp.egg-info/entry_points.txt +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask_mcp.egg-info/requires.txt +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/subtask_mcp.egg-info/top_level.txt +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/tests/test_concurrency.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/tests/test_engines.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/tests/test_falsify.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/tests/test_independent_client.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/tests/test_install.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/tests/test_live.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/tests/test_protocol.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/tests/test_routing_results.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/tests/test_schema.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/tests/test_security.py +0 -0
- {subtask_mcp-0.2.9 → subtask_mcp-0.2.10}/tests/test_subtask.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: subtask-mcp
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.10
|
|
4
4
|
Summary: Background sub-agents for Claude Code, Codex, Kimi and OpenCode, over MCP or CLI, with a spend cap
|
|
5
5
|
License: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/tedin7/subtask
|
|
@@ -70,7 +70,7 @@ The distribution is `subtask-mcp` (the PyPI name `subtask` is an unrelated
|
|
|
70
70
|
project). Full guide, per client, with native commands: [docs/install.md](docs/install.md).
|
|
71
71
|
|
|
72
72
|
```sh
|
|
73
|
-
uv tool install "git+https://github.com/tedin7/subtask@v0.2.
|
|
73
|
+
uv tool install "git+https://github.com/tedin7/subtask@v0.2.10" # or: uv tool install /path/to/checkout
|
|
74
74
|
subtask install --client all # prints the plan for every detected client
|
|
75
75
|
subtask install --client all --yes # applies it: MCP server + skill
|
|
76
76
|
subtask doctor --client all # checks app, config entry and a real handshake
|
|
@@ -39,7 +39,7 @@ The distribution is `subtask-mcp` (the PyPI name `subtask` is an unrelated
|
|
|
39
39
|
project). Full guide, per client, with native commands: [docs/install.md](docs/install.md).
|
|
40
40
|
|
|
41
41
|
```sh
|
|
42
|
-
uv tool install "git+https://github.com/tedin7/subtask@v0.2.
|
|
42
|
+
uv tool install "git+https://github.com/tedin7/subtask@v0.2.10" # or: uv tool install /path/to/checkout
|
|
43
43
|
subtask install --client all # prints the plan for every detected client
|
|
44
44
|
subtask install --client all --yes # applies it: MCP server + skill
|
|
45
45
|
subtask doctor --client all # checks app, config entry and a real handshake
|
|
@@ -43,36 +43,40 @@ def _text(content: object) -> str:
|
|
|
43
43
|
return ""
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
def read_transcript(path: str | None
|
|
47
|
-
"""(last user request, recent agent actions) from a Claude Code session transcript.
|
|
46
|
+
def read_transcript(path: str | None) -> tuple[str, list[str]]:
|
|
47
|
+
"""(last user request, recent agent actions) from a Claude Code session transcript.
|
|
48
|
+
|
|
49
|
+
The whole file is streamed line by line: the request can sit before megabytes of tool output.
|
|
50
|
+
Lines that are not user prompts or tool calls are skipped without being parsed.
|
|
51
|
+
"""
|
|
48
52
|
if not path or not Path(path).is_file():
|
|
49
53
|
return "", []
|
|
50
|
-
with open(path, "rb") as fh:
|
|
51
|
-
fh.seek(0, 2)
|
|
52
|
-
fh.seek(max(0, fh.tell() - max_bytes))
|
|
53
|
-
lines = fh.read().decode("utf-8", errors="replace").splitlines()
|
|
54
54
|
request, actions = "", []
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
55
|
+
with open(path, "rb") as fh:
|
|
56
|
+
for raw in fh:
|
|
57
|
+
if b'"tool_use"' not in raw and b'"type":"user"' not in raw and b'"type": "user"' not in raw:
|
|
58
|
+
continue
|
|
59
|
+
try:
|
|
60
|
+
row = json.loads(raw)
|
|
61
|
+
except (json.JSONDecodeError, UnicodeDecodeError):
|
|
62
|
+
continue
|
|
63
|
+
msg = row.get("message") if isinstance(row, dict) else None
|
|
64
|
+
if not isinstance(msg, dict):
|
|
65
|
+
continue
|
|
66
|
+
content = msg.get("content")
|
|
67
|
+
if row.get("type") == "user":
|
|
68
|
+
is_tool_result = isinstance(content, list) and any(
|
|
69
|
+
isinstance(b, dict) and b.get("type") == "tool_result" for b in content
|
|
70
|
+
)
|
|
71
|
+
text = _text(content).strip()
|
|
72
|
+
if text and not is_tool_result and not text.startswith("<"):
|
|
73
|
+
request, actions = text, [] # a new request starts a new chain of actions
|
|
74
|
+
elif row.get("type") == "assistant" and isinstance(content, list):
|
|
75
|
+
for b in content:
|
|
76
|
+
if isinstance(b, dict) and b.get("type") == "tool_use":
|
|
77
|
+
actions.append(_action(b.get("name", ""), b.get("input") or {}))
|
|
78
|
+
actions = actions[-12:]
|
|
79
|
+
return request[-2000:], [a for a in actions if a]
|
|
76
80
|
|
|
77
81
|
|
|
78
82
|
def _action(name: str, args: dict) -> str:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: subtask-mcp
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.10
|
|
4
4
|
Summary: Background sub-agents for Claude Code, Codex, Kimi and OpenCode, over MCP or CLI, with a spend cap
|
|
5
5
|
License: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/tedin7/subtask
|
|
@@ -70,7 +70,7 @@ The distribution is `subtask-mcp` (the PyPI name `subtask` is an unrelated
|
|
|
70
70
|
project). Full guide, per client, with native commands: [docs/install.md](docs/install.md).
|
|
71
71
|
|
|
72
72
|
```sh
|
|
73
|
-
uv tool install "git+https://github.com/tedin7/subtask@v0.2.
|
|
73
|
+
uv tool install "git+https://github.com/tedin7/subtask@v0.2.10" # or: uv tool install /path/to/checkout
|
|
74
74
|
subtask install --client all # prints the plan for every detected client
|
|
75
75
|
subtask install --client all --yes # applies it: MCP server + skill
|
|
76
76
|
subtask doctor --client all # checks app, config entry and a real handshake
|
|
@@ -87,3 +87,27 @@ def test_cli_hook_exits_zero_and_prints_json_only(home, tmp_path):
|
|
|
87
87
|
bad = subprocess.run([sys.executable, "-m", "subtask.cli", "narrate-hook"], input="not json",
|
|
88
88
|
capture_output=True, text=True, timeout=30, check=False) # fmt: skip
|
|
89
89
|
assert bad.returncode == 0
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_request_far_back_in_a_large_transcript_is_found(tmp_path):
|
|
93
|
+
"""The request can sit before megabytes of tool output: the whole file is read, line by line."""
|
|
94
|
+
from subtask import stephook
|
|
95
|
+
|
|
96
|
+
rows = [{"type": "user", "message": {"role": "user", "content": "ripara i 10 errori"}}]
|
|
97
|
+
big = "x" * 50_000
|
|
98
|
+
rows += [
|
|
99
|
+
{"type": "user", "message": {"role": "user", "content": [{"type": "tool_result", "content": big}]}}
|
|
100
|
+
] * 40
|
|
101
|
+
rows += [
|
|
102
|
+
{
|
|
103
|
+
"type": "assistant",
|
|
104
|
+
"message": {
|
|
105
|
+
"content": [{"type": "tool_use", "name": "Bash", "input": {"command": "git commit -m x"}}]
|
|
106
|
+
},
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
path = tmp_path / "big.jsonl"
|
|
110
|
+
path.write_text("\n".join(json.dumps(r) for r in rows))
|
|
111
|
+
assert path.stat().st_size > 1_000_000
|
|
112
|
+
request, actions = stephook.read_transcript(str(path))
|
|
113
|
+
assert request == "ripara i 10 errori" and actions == ["Bash git commit -m x"]
|
|
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
|
|
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
|
|
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
|
|
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
|