codee-agent 0.7.3__tar.gz → 0.7.5__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 (97) hide show
  1. {codee_agent-0.7.3 → codee_agent-0.7.5}/PKG-INFO +1 -1
  2. {codee_agent-0.7.3 → codee_agent-0.7.5}/pyproject.toml +1 -1
  3. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/admin.py +6 -1
  4. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/admin_service.py +3 -3
  5. codee_agent-0.7.5/src/codee/test_admin.py +41 -0
  6. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/test_admin_service.py +62 -2
  7. {codee_agent-0.7.3 → codee_agent-0.7.5}/LICENSE +0 -0
  8. {codee_agent-0.7.3 → codee_agent-0.7.5}/README.md +0 -0
  9. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/.gitignore +0 -0
  10. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/__init__.py +0 -0
  11. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/admin_api.py +0 -0
  12. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/admin_cli.py +0 -0
  13. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/agent_cli.py +0 -0
  14. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/coding_agents.py +0 -0
  15. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/executor.py +0 -0
  16. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/init_cli.py +0 -0
  17. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/lib/__init__.py +0 -0
  18. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/lib/claude_key_rotation.py +0 -0
  19. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/lib/cron_describe.py +0 -0
  20. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/lib/mcp_config.py +0 -0
  21. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/lib/runs_db.py +0 -0
  22. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/lib/runtime_control.py +0 -0
  23. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/lib/test_claude_key_rotation.py +0 -0
  24. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/lib/test_mcp_config.py +0 -0
  25. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/lib/test_runs_db.py +0 -0
  26. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/lib/test_trigger_cron_skills.py +0 -0
  27. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/lib/test_trigger_issue_skills.py +0 -0
  28. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/lib/trigger_aws_sqs_skills.py +0 -0
  29. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/lib/trigger_cron_skills.py +0 -0
  30. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/lib/trigger_email_skills.py +0 -0
  31. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/lib/trigger_issue_skills.py +0 -0
  32. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/mail_server.py +0 -0
  33. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/setup_wizard.py +0 -0
  34. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/start_cli.py +0 -0
  35. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/tasks_providers.py +0 -0
  36. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/templates/AGENTS.md +0 -0
  37. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/templates/CLAUDE.md +0 -0
  38. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/templates/skills/aws-sqs-alarm-response/SKILL.md +0 -0
  39. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/templates/skills/cron-research-5xx-errors/SKILL.md +0 -0
  40. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/templates/skills/story-code-reviewer/SKILL.md +0 -0
  41. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/templates/skills/story-developer/SKILL.md +0 -0
  42. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/templates/skills/story-planner/SKILL.md +0 -0
  43. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/templates/skills/story-planner/assets/readme-template.md +0 -0
  44. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/templates/skills/story-qa/SKILL.md +0 -0
  45. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/templates/skills/story-security-reviewer/SKILL.md +0 -0
  46. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/templates/skills/task-code-reviewer/SKILL.md +0 -0
  47. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/templates/skills/task-developer/SKILL.md +0 -0
  48. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/templates/skills/task-qa/SKILL.md +0 -0
  49. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/templates/skills/task-security-reviewer/SKILL.md +0 -0
  50. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/test_admin_api.py +0 -0
  51. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/test_admin_cli.py +0 -0
  52. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/test_agent_cli.py +0 -0
  53. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/test_coding_agents.py +0 -0
  54. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/test_executor.py +0 -0
  55. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/test_init_cli.py +0 -0
  56. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/test_memory_index.py +0 -0
  57. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/test_setup_wizard.py +0 -0
  58. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/test_start_cli.py +0 -0
  59. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee/workflow_graph.py +0 -0
  60. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_admin/__init__.py +0 -0
  61. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_admin/codee_admin.py +0 -0
  62. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_agent_abstract/__init__.py +0 -0
  63. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_agent_abstract/provider.py +0 -0
  64. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_agent_claude_code/__init__.py +0 -0
  65. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_agent_claude_code/account.py +0 -0
  66. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_agent_claude_code/credentials.py +0 -0
  67. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_agent_claude_code/oauth.py +0 -0
  68. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_agent_claude_code/provider.py +0 -0
  69. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_agent_claude_code/test.py +0 -0
  70. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_agent_claude_code/usage.py +0 -0
  71. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_agent_codex/__init__.py +0 -0
  72. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_agent_codex/provider.py +0 -0
  73. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_agent_codex/test.py +0 -0
  74. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_agent_github_copilot/__init__.py +0 -0
  75. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_agent_github_copilot/provider.py +0 -0
  76. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_agent_github_copilot/test.py +0 -0
  77. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_agent_opencode/__init__.py +0 -0
  78. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_agent_opencode/provider.py +0 -0
  79. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_agent_opencode/test.py +0 -0
  80. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_database/__init__.py +0 -0
  81. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_database/claude_code_accounts.py +0 -0
  82. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_database/database.py +0 -0
  83. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_database/oauth_tokens.py +0 -0
  84. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_main_context/__init__.py +0 -0
  85. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_main_context/context.py +0 -0
  86. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_main_context/logging.py +0 -0
  87. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_main_context/test_context.py +0 -0
  88. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_main_context/test_logging.py +0 -0
  89. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_tasks_abstract/__init__.py +0 -0
  90. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_tasks_abstract/provider.py +0 -0
  91. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_tasks_azure_devops/__init__.py +0 -0
  92. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_tasks_azure_devops/oauth.py +0 -0
  93. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_tasks_azure_devops/provider.py +0 -0
  94. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_tasks_azure_devops/test.py +0 -0
  95. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_tasks_jira/__init__.py +0 -0
  96. {codee_agent-0.7.3 → codee_agent-0.7.5}/src/codee_tasks_jira/provider.py +0 -0
  97. {codee_agent-0.7.3 → codee_agent-0.7.5}/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.7.3
3
+ Version: 0.7.5
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,codex,opencode,automation
6
6
  Author: Denis Kibalko
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "codee-agent"
3
- version = "0.7.3"
3
+ version = "0.7.5"
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"
@@ -785,8 +785,13 @@ class AdminState(rx.State):
785
785
  self.last_24h_runs = dashboard["counts"]["last_24h"]
786
786
  self.hourly_runs = dashboard["hourly"]
787
787
 
788
- def toggle_pause(self) -> None:
788
+ def toggle_pause(self) -> Any:
789
789
  self.paused = SERVICE.set_paused(not self.paused)
790
+ if self.paused:
791
+ message = "New agents won't be spawned."
792
+ if self.active_jobs:
793
+ message += " Currently running agents will continue until completion."
794
+ return rx.toast.info(message)
790
795
 
791
796
  @rx.event(background=True)
792
797
  async def poll_dashboard(self) -> None:
@@ -514,8 +514,9 @@ MOVE_VERB_RE = re.compile(
514
514
  # status, whose own name may contain a work item word ("Task Ready").
515
515
  MOVE_TARGET_WORDS = {"to", "into", "in", "onto", "back", "at"}
516
516
  WORD_RE = re.compile(r"[\w-]+")
517
- # How many words after the verb are still part of the phrase naming what moves.
518
- MOVE_WINDOW = 4
517
+ # Bound the phrase naming what moves, while allowing coordinated objects such
518
+ # as "the subtask, as well as the story" before the status preposition.
519
+ MOVE_WINDOW = 12
519
520
 
520
521
 
521
522
  def _work_item_terms(name: str) -> tuple[str, ...]:
@@ -592,7 +593,6 @@ class _WorkItemScope:
592
593
  break
593
594
  if lowered in self._own or lowered in self._others:
594
595
  yield lowered
595
- break
596
596
 
597
597
 
598
598
  def _css_string(text: str) -> str:
@@ -0,0 +1,41 @@
1
+ """Dashboard UI event tests."""
2
+
3
+ from types import SimpleNamespace
4
+ from unittest.mock import patch
5
+
6
+ from codee.admin import AdminState
7
+
8
+
9
+ def test_pause_with_running_agents_explains_they_will_finish() -> None:
10
+ state = SimpleNamespace(paused=False, active_jobs=[object()])
11
+ with patch("codee.admin.SERVICE.set_paused", return_value=True) as set_paused, \
12
+ patch("codee.admin.rx.toast.info") as toast:
13
+ result = AdminState.toggle_pause.fn(state)
14
+
15
+ set_paused.assert_called_once_with(True)
16
+ toast.assert_called_once_with(
17
+ "New agents won't be spawned. Currently running agents will continue until completion."
18
+ )
19
+ assert result is toast.return_value
20
+ assert state.paused is True
21
+
22
+
23
+ def test_pause_without_running_agents_only_mentions_new_work() -> None:
24
+ state = SimpleNamespace(paused=False, active_jobs=[])
25
+ with patch("codee.admin.SERVICE.set_paused", return_value=True), \
26
+ patch("codee.admin.rx.toast.info") as toast:
27
+ AdminState.toggle_pause.fn(state)
28
+
29
+ toast.assert_called_once_with("New agents won't be spawned.")
30
+
31
+
32
+ def test_unpause_does_not_show_pause_toast() -> None:
33
+ state = SimpleNamespace(paused=True, active_jobs=[object()])
34
+ with patch("codee.admin.SERVICE.set_paused", return_value=False) as set_paused, \
35
+ patch("codee.admin.rx.toast.info") as toast:
36
+ result = AdminState.toggle_pause.fn(state)
37
+
38
+ set_paused.assert_called_once_with(False)
39
+ toast.assert_not_called()
40
+ assert result is None
41
+ assert state.paused is False
@@ -19,8 +19,9 @@ from codee.admin_service import (
19
19
  MCP_CHECK, TASKS_CHECK, USAGE_CACHE_SECONDS,
20
20
  USAGE_RATE_LIMIT_BACKOFF_SECONDS, WORKFLOW_CACHE_VERSION,
21
21
  WORKFLOW_HUMAN_EDGE_COLOR, AdminService, WorkflowGeneration,
22
- _remove_redundant_skill_transitions, azure_oauth, issue_prompt_task,
23
- normalize_work_items, parse_skill, relative_age_label, repository_name)
22
+ _WorkItemScope, _remove_redundant_skill_transitions, azure_oauth,
23
+ issue_prompt_task, normalize_work_items, parse_skill, relative_age_label,
24
+ repository_name)
24
25
  from codee.lib import runs_db
25
26
  from codee_agent_claude_code import oauth as claude_oauth
26
27
  from codee_agent_claude_code.account import AccountUnavailable
@@ -1291,6 +1292,65 @@ class AdminServiceIssueTriggerTest(unittest.TestCase):
1291
1292
  agent.run.call_args.args[0],
1292
1293
  )
1293
1294
 
1295
+ def test_coordinated_move_includes_both_work_items(self) -> None:
1296
+ story = _WorkItemScope("story", ("story", "task"))
1297
+ task = _WorkItemScope("task", ("story", "task"))
1298
+ for evidence in (
1299
+ "Move the subtask and the story to AI Human Response Requested",
1300
+ "Move the subtask **and** the story to **AI Human Response Requested**",
1301
+ "Move the subtask, as well as the story, to AI Human Response Requested",
1302
+ "Move the story and the subtask to AI Human Response Requested",
1303
+ ):
1304
+ with self.subTest(evidence=evidence):
1305
+ self.assertEqual(story.other_work_item(evidence), "")
1306
+ self.assertEqual(task.other_work_item(
1307
+ "Move the story and the task to AI Human Response Requested"), "")
1308
+ self.assertEqual(story.other_work_item(
1309
+ "Move the subtask to AI Human Response Requested"), "subtask")
1310
+ self.assertEqual(task.other_work_item(
1311
+ "Move the story to AI Human Response Requested"), "story")
1312
+
1313
+ def test_generate_workflow_accepts_coordinated_story_transition(self) -> None:
1314
+ evidence = (
1315
+ "Move the subtask and the story to AI Human Response Requested"
1316
+ )
1317
+ with tempfile.TemporaryDirectory() as temporary_directory:
1318
+ root = Path(temporary_directory)
1319
+ skills_dir = root / ".claude" / "skills"
1320
+ skill_dir = skills_dir / "story-developer"
1321
+ skill_dir.mkdir(parents=True)
1322
+ (skill_dir / "SKILL.md").write_text(
1323
+ "---\nname: story-developer\ndisable-model-invocation: true\n"
1324
+ "x-codee-trigger: issue\nx-codee-issue-status: [Ready]\n"
1325
+ "x-codee-issue-type: story\n---\n" + evidence + "\n"
1326
+ )
1327
+ agent = Mock()
1328
+ agent.run.return_value = json.dumps({
1329
+ "statuses": ["Ready", "AI Human Response Requested"],
1330
+ "transitions": [{
1331
+ "source": "Ready", "target": "AI Human Response Requested",
1332
+ "label": "story-developer", "evidence": evidence,
1333
+ }],
1334
+ "final_statuses": ["AI Human Response Requested"],
1335
+ })
1336
+ service = AdminService.__new__(AdminService)
1337
+ service.root = root
1338
+ service.skills_dir = skills_dir
1339
+ service.data_dir = root / ".codee"
1340
+ service.context = Mock(
1341
+ settings=Settings(coding_agent=CodingAgent.CLAUDE_CODE))
1342
+
1343
+ with patch.dict("codee.admin_service.CODING_AGENTS", {
1344
+ CodingAgent.CLAUDE_CODE: Mock(return_value=agent),
1345
+ }):
1346
+ workflow = service.generate_workflow()["story"]
1347
+
1348
+ self.assertEqual(agent.continue_conversation.call_count, 0)
1349
+ self.assertEqual(
1350
+ [node["data"]["label"] for node in workflow["nodes"]],
1351
+ ["Ready", "AI Human Response Requested"],
1352
+ )
1353
+
1294
1354
  def test_generate_workflow_rejects_a_transition_that_moves_a_subtask(self) -> None:
1295
1355
  """A story skill moves its subtasks too, and those are not story statuses."""
1296
1356
  with tempfile.TemporaryDirectory() as temporary_directory:
File without changes
File without changes