codee-agent 0.5.4__tar.gz → 0.5.6__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.
Files changed (81) hide show
  1. {codee_agent-0.5.4 → codee_agent-0.5.6}/PKG-INFO +1 -1
  2. {codee_agent-0.5.4 → codee_agent-0.5.6}/pyproject.toml +1 -1
  3. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/test_admin_service.py +1 -1
  4. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_agent_claude_code/provider.py +10 -6
  5. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_agent_claude_code/test.py +14 -0
  6. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_agent_github_copilot/provider.py +12 -6
  7. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_agent_github_copilot/test.py +11 -1
  8. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_tasks_azure_devops/provider.py +4 -2
  9. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_tasks_azure_devops/test.py +1 -1
  10. {codee_agent-0.5.4 → codee_agent-0.5.6}/LICENSE +0 -0
  11. {codee_agent-0.5.4 → codee_agent-0.5.6}/README.md +0 -0
  12. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/.gitignore +0 -0
  13. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/__init__.py +0 -0
  14. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/admin.py +0 -0
  15. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/admin_api.py +0 -0
  16. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/admin_cli.py +0 -0
  17. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/admin_service.py +0 -0
  18. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/agent_cli.py +0 -0
  19. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/coding_agents.py +0 -0
  20. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/executor.py +0 -0
  21. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/init_cli.py +0 -0
  22. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/lib/__init__.py +0 -0
  23. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/lib/cron_describe.py +0 -0
  24. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/lib/mcp_config.py +0 -0
  25. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/lib/runs_db.py +0 -0
  26. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/lib/test_mcp_config.py +0 -0
  27. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/lib/test_runs_db.py +0 -0
  28. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/lib/test_trigger_cron_skills.py +0 -0
  29. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/lib/test_trigger_issue_skills.py +0 -0
  30. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/lib/trigger_aws_sqs_skills.py +0 -0
  31. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/lib/trigger_cron_skills.py +0 -0
  32. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/lib/trigger_email_skills.py +0 -0
  33. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/lib/trigger_issue_skills.py +0 -0
  34. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/mail_server.py +0 -0
  35. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/setup_wizard.py +0 -0
  36. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/start_cli.py +0 -0
  37. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/tasks_providers.py +0 -0
  38. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/templates/AGENTS.md +0 -0
  39. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/templates/CLAUDE.md +0 -0
  40. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/templates/skills/aws-sqs-alarm-response/SKILL.md +0 -0
  41. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/templates/skills/cron-research-5xx-errors/SKILL.md +0 -0
  42. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/templates/skills/story-code-reviewer/SKILL.md +0 -0
  43. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/templates/skills/story-developer/SKILL.md +0 -0
  44. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/templates/skills/story-planner/SKILL.md +0 -0
  45. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/templates/skills/story-planner/assets/readme-template.md +0 -0
  46. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/templates/skills/story-qa/SKILL.md +0 -0
  47. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/templates/skills/story-security-reviewer/SKILL.md +0 -0
  48. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/templates/skills/task-code-reviewer/SKILL.md +0 -0
  49. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/templates/skills/task-developer/SKILL.md +0 -0
  50. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/templates/skills/task-qa/SKILL.md +0 -0
  51. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/templates/skills/task-security-reviewer/SKILL.md +0 -0
  52. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/test_admin_api.py +0 -0
  53. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/test_admin_cli.py +0 -0
  54. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/test_agent_cli.py +0 -0
  55. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/test_executor.py +0 -0
  56. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/test_init_cli.py +0 -0
  57. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/test_memory_index.py +0 -0
  58. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/test_setup_wizard.py +0 -0
  59. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/test_start_cli.py +0 -0
  60. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee/workflow_graph.py +0 -0
  61. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_admin/__init__.py +0 -0
  62. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_admin/codee_admin.py +0 -0
  63. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_agent_abstract/__init__.py +0 -0
  64. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_agent_abstract/provider.py +0 -0
  65. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_agent_claude_code/__init__.py +0 -0
  66. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_agent_github_copilot/__init__.py +0 -0
  67. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_database/__init__.py +0 -0
  68. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_database/database.py +0 -0
  69. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_database/oauth_tokens.py +0 -0
  70. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_main_context/__init__.py +0 -0
  71. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_main_context/context.py +0 -0
  72. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_main_context/logging.py +0 -0
  73. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_main_context/test_context.py +0 -0
  74. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_main_context/test_logging.py +0 -0
  75. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_tasks_abstract/__init__.py +0 -0
  76. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_tasks_abstract/provider.py +0 -0
  77. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_tasks_azure_devops/__init__.py +0 -0
  78. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_tasks_azure_devops/oauth.py +0 -0
  79. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_tasks_jira/__init__.py +0 -0
  80. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_tasks_jira/provider.py +0 -0
  81. {codee_agent-0.5.4 → codee_agent-0.5.6}/src/codee_tasks_jira/test.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codee-agent
3
- Version: 0.5.4
3
+ Version: 0.5.6
4
4
  Summary: A virtual co-worker that picks up Jira and Azure DevOps tasks and solves them with coding agents.
5
5
  Keywords: ai,agent,jira,azure-devops,claude-code,github-copilot,automation
6
6
  Author: Denis Kibalko
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "codee-agent"
3
- version = "0.5.4"
3
+ version = "0.5.6"
4
4
  description = "A virtual co-worker that picks up Jira and Azure DevOps tasks and solves them with coding agents."
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -1719,7 +1719,7 @@ class SetupTasksMcpTest(unittest.TestCase):
1719
1719
  config = self._config(root)
1720
1720
  self.assertEqual(config["mcpServers"]["ado"], {
1721
1721
  "command": "npx",
1722
- "args": ["-y", "@azure-devops/mcp", "acme",
1722
+ "args": ["-y", "@azure-devops/mcp@2.8.0", "acme",
1723
1723
  "--authentication", "azcli"],
1724
1724
  })
1725
1725
  self.assertEqual(config["servers"]["ado"]["type"], "stdio")
@@ -72,31 +72,35 @@ class ClaudeCodeAgent(AbstractCodingAgent):
72
72
  cmd,
73
73
  capture_output=True,
74
74
  text=True,
75
+ encoding="utf-8",
76
+ errors="replace",
75
77
  timeout=self.TIMEOUT_SECONDS,
76
78
  cwd=self._cwd,
77
79
  )
78
80
  except subprocess.TimeoutExpired:
79
81
  raise RuntimeError("Claude CLI timed out after 2 hours")
80
82
 
83
+ stdout = result.stdout or ""
84
+ stderr = result.stderr or ""
81
85
  log.debug("claude exited %d (%d bytes stdout, %d bytes stderr)",
82
- result.returncode, len(result.stdout), len(result.stderr))
86
+ result.returncode, len(stdout), len(stderr))
83
87
 
84
88
  # Raise on any non-success so callers retry. Over-limit exits non-zero;
85
89
  # a completed-but-errored run sets is_error in the JSON.
86
90
  if result.returncode != 0:
87
91
  raise RuntimeError(
88
- f"Claude CLI exited {result.returncode}: {result.stderr.strip()[:500]}"
92
+ f"Claude CLI exited {result.returncode}: {stderr.strip()[:500]}"
89
93
  )
90
94
 
91
95
  try:
92
- response = json.loads(result.stdout)
96
+ response = json.loads(stdout)
93
97
  except json.JSONDecodeError:
94
- return result.stdout
98
+ return stdout
95
99
  if isinstance(response, dict):
96
100
  if response.get("is_error"):
97
101
  raise RuntimeError(
98
102
  f"Claude run errored ({response.get('subtype', 'unknown')}): "
99
103
  f"{str(response.get('result', ''))[:500]}"
100
104
  )
101
- return response.get("result", result.stdout)
102
- return result.stdout
105
+ return response.get("result", stdout)
106
+ return stdout
@@ -34,6 +34,20 @@ class ClaudeCodeRunTest(unittest.TestCase):
34
34
 
35
35
  self.assertEqual(cmd[cmd.index("--model") + 1], "opus")
36
36
 
37
+ def test_cli_output_is_decoded_as_utf8(self) -> None:
38
+ with patch("subprocess.run", return_value=_completed()) as run:
39
+ self.agent.run("/do-it CORE-1", SESSION)
40
+
41
+ self.assertEqual(run.call_args.kwargs["encoding"], "utf-8")
42
+ self.assertEqual(run.call_args.kwargs["errors"], "replace")
43
+
44
+ def test_missing_captured_streams_do_not_raise_type_error(self) -> None:
45
+ completed = subprocess.CompletedProcess(
46
+ args=["claude"], returncode=0, stdout=None, stderr=None)
47
+
48
+ with patch("subprocess.run", return_value=completed):
49
+ self.assertEqual(self.agent.run("/do-it CORE-1", SESSION), "")
50
+
37
51
  def test_the_best_model_is_a_version_free_alias(self) -> None:
38
52
  # The alias tracks the newest Opus, so no release needs an edit here.
39
53
  self.assertEqual(ClaudeCodeAgent.best_model(), "opus")
@@ -102,16 +102,20 @@ class GitHubCopilotAgent(AbstractCodingAgent):
102
102
  cmd,
103
103
  capture_output=True,
104
104
  text=True,
105
+ encoding="utf-8",
106
+ errors="replace",
105
107
  timeout=self.TIMEOUT_SECONDS,
106
108
  cwd=self._cwd,
107
109
  )
108
110
  except subprocess.TimeoutExpired:
109
111
  raise RuntimeError("Copilot CLI timed out after 2 hours")
110
112
 
113
+ stdout = result.stdout or ""
114
+ stderr = result.stderr or ""
111
115
  log.debug("copilot exited %d (%d bytes stdout, %d bytes stderr)",
112
- result.returncode, len(result.stdout), len(result.stderr))
116
+ result.returncode, len(stdout), len(stderr))
113
117
 
114
- reply, outcome, errors = _parse_events(result.stdout)
118
+ reply, outcome, errors = _parse_events(stdout)
115
119
 
116
120
  # Raise on any non-success so callers retry. A run that fails before the
117
121
  # session starts (bad model, no auth) exits non-zero with nothing on
@@ -119,22 +123,22 @@ class GitHubCopilotAgent(AbstractCodingAgent):
119
123
  if result.returncode != 0:
120
124
  raise RuntimeError(
121
125
  f"Copilot CLI exited {result.returncode}: "
122
- f"{_detail(errors, result.stderr)}"
126
+ f"{_detail(errors, stderr)}"
123
127
  )
124
128
  if outcome is None:
125
129
  # Not the JSONL we know how to read — hand back whatever it printed
126
130
  # rather than failing a run that the CLI itself called successful.
127
131
  log.warning(
128
132
  "copilot produced no result event; returning raw output")
129
- return result.stdout
133
+ return stdout
130
134
  if outcome.get("exitCode"):
131
135
  raise RuntimeError(
132
136
  f"Copilot run errored (exit code {outcome['exitCode']}): "
133
- f"{_detail(errors, result.stderr)}"
137
+ f"{_detail(errors, stderr)}"
134
138
  )
135
139
  if not reply:
136
140
  raise RuntimeError(
137
- f"Copilot run produced no response: {_detail(errors, result.stderr)}"
141
+ f"Copilot run produced no response: {_detail(errors, stderr)}"
138
142
  )
139
143
  return reply
140
144
 
@@ -152,6 +156,8 @@ def _fetch_acp_models() -> list[AgentModel]:
152
156
  stdout=subprocess.PIPE,
153
157
  stderr=subprocess.PIPE,
154
158
  text=True,
159
+ encoding="utf-8",
160
+ errors="replace",
155
161
  bufsize=1,
156
162
  cwd=Path.cwd(),
157
163
  )
@@ -71,6 +71,14 @@ class CopilotRunTest(unittest.TestCase):
71
71
  for flag in ("--allow-all", "--no-ask-user", "--output-format"):
72
72
  self.assertIn(flag, cmd)
73
73
  self.assertEqual(self.captured.call_args.kwargs["cwd"], Path("/repo"))
74
+ self.assertEqual(self.captured.call_args.kwargs["encoding"], "utf-8")
75
+ self.assertEqual(self.captured.call_args.kwargs["errors"], "replace")
76
+
77
+ def test_missing_captured_streams_do_not_raise_type_error(self) -> None:
78
+ completed = subprocess.CompletedProcess(
79
+ args=["copilot"], returncode=0, stdout=None, stderr=None)
80
+
81
+ self.assertEqual(self._run(completed), "")
74
82
 
75
83
  def test_the_skill_model_is_passed_on_the_command_line(self) -> None:
76
84
  stdout = _stream(_event("assistant.message", {"content": "ok"}),
@@ -194,7 +202,7 @@ class CopilotModelCatalogTest(unittest.TestCase):
194
202
  {"name": "nameless"}, # no id at all: unusable, skipped
195
203
  ]}}
196
204
 
197
- with patch("codee_agent_github_copilot.provider.subprocess.Popen"), \
205
+ with patch("codee_agent_github_copilot.provider.subprocess.Popen") as popen, \
198
206
  patch("codee_agent_github_copilot.provider._send"), \
199
207
  patch("codee_agent_github_copilot.provider._await_result",
200
208
  return_value=result):
@@ -202,6 +210,8 @@ class CopilotModelCatalogTest(unittest.TestCase):
202
210
 
203
211
  self.assertEqual([(m.id, m.name) for m in models],
204
212
  [("claude-opus-5", "Claude Opus 5"), ("gpt-5.4", "gpt-5.4")])
213
+ self.assertEqual(popen.call_args.kwargs["encoding"], "utf-8")
214
+ self.assertEqual(popen.call_args.kwargs["errors"], "replace")
205
215
 
206
216
  def test_an_unavailable_cli_yields_no_models_rather_than_raising(self) -> None:
207
217
  with patch("codee_agent_github_copilot.provider.subprocess.Popen",
@@ -44,8 +44,10 @@ _FIELDS = [
44
44
  _PRIORITY_NAMES = {1: "Highest", 2: "High", 3: "Medium", 4: "Low"}
45
45
 
46
46
  # Microsoft's own Azure DevOps MCP server, run from npm through `npx` so
47
- # nothing has to be installed alongside it.
48
- MCP_SERVER_PACKAGE = "@azure-devops/mcp"
47
+ # nothing has to be installed alongside it. Version 2.8.0 keeps work item
48
+ # creation compatible with coding agents that stringify the consolidated
49
+ # write tool's fields parameter introduced in 2.9.0.
50
+ MCP_SERVER_PACKAGE = "@azure-devops/mcp@2.8.0"
49
51
 
50
52
  # Ceiling the WIQL query is capped at, matching the JIRA provider's page size.
51
53
  _MAX_TASKS = 50
@@ -629,7 +629,7 @@ class AzureDevOpsMcpTest(unittest.TestCase):
629
629
 
630
630
  self.assertEqual(server.name, "ado")
631
631
  self.assertEqual(server.command, "npx")
632
- self.assertEqual(server.args, ["-y", "@azure-devops/mcp", "acme",
632
+ self.assertEqual(server.args, ["-y", "@azure-devops/mcp@2.8.0", "acme",
633
633
  "--authentication", "azcli"])
634
634
  # It signs in through `az login`, so it carries no credentials of ours.
635
635
  self.assertEqual(server.env, {})
File without changes
File without changes