codee-agent 0.7.2__tar.gz → 0.7.4__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 (96) hide show
  1. {codee_agent-0.7.2 → codee_agent-0.7.4}/PKG-INFO +1 -1
  2. {codee_agent-0.7.2 → codee_agent-0.7.4}/pyproject.toml +1 -1
  3. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/admin.py +76 -41
  4. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/admin_service.py +3 -3
  5. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/test_admin_service.py +62 -2
  6. {codee_agent-0.7.2 → codee_agent-0.7.4}/LICENSE +0 -0
  7. {codee_agent-0.7.2 → codee_agent-0.7.4}/README.md +0 -0
  8. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/.gitignore +0 -0
  9. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/__init__.py +0 -0
  10. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/admin_api.py +0 -0
  11. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/admin_cli.py +0 -0
  12. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/agent_cli.py +0 -0
  13. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/coding_agents.py +0 -0
  14. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/executor.py +0 -0
  15. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/init_cli.py +0 -0
  16. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/lib/__init__.py +0 -0
  17. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/lib/claude_key_rotation.py +0 -0
  18. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/lib/cron_describe.py +0 -0
  19. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/lib/mcp_config.py +0 -0
  20. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/lib/runs_db.py +0 -0
  21. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/lib/runtime_control.py +0 -0
  22. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/lib/test_claude_key_rotation.py +0 -0
  23. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/lib/test_mcp_config.py +0 -0
  24. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/lib/test_runs_db.py +0 -0
  25. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/lib/test_trigger_cron_skills.py +0 -0
  26. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/lib/test_trigger_issue_skills.py +0 -0
  27. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/lib/trigger_aws_sqs_skills.py +0 -0
  28. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/lib/trigger_cron_skills.py +0 -0
  29. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/lib/trigger_email_skills.py +0 -0
  30. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/lib/trigger_issue_skills.py +0 -0
  31. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/mail_server.py +0 -0
  32. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/setup_wizard.py +0 -0
  33. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/start_cli.py +0 -0
  34. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/tasks_providers.py +0 -0
  35. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/templates/AGENTS.md +0 -0
  36. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/templates/CLAUDE.md +0 -0
  37. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/templates/skills/aws-sqs-alarm-response/SKILL.md +0 -0
  38. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/templates/skills/cron-research-5xx-errors/SKILL.md +0 -0
  39. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/templates/skills/story-code-reviewer/SKILL.md +0 -0
  40. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/templates/skills/story-developer/SKILL.md +0 -0
  41. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/templates/skills/story-planner/SKILL.md +0 -0
  42. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/templates/skills/story-planner/assets/readme-template.md +0 -0
  43. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/templates/skills/story-qa/SKILL.md +0 -0
  44. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/templates/skills/story-security-reviewer/SKILL.md +0 -0
  45. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/templates/skills/task-code-reviewer/SKILL.md +0 -0
  46. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/templates/skills/task-developer/SKILL.md +0 -0
  47. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/templates/skills/task-qa/SKILL.md +0 -0
  48. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/templates/skills/task-security-reviewer/SKILL.md +0 -0
  49. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/test_admin_api.py +0 -0
  50. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/test_admin_cli.py +0 -0
  51. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/test_agent_cli.py +0 -0
  52. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/test_coding_agents.py +0 -0
  53. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/test_executor.py +0 -0
  54. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/test_init_cli.py +0 -0
  55. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/test_memory_index.py +0 -0
  56. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/test_setup_wizard.py +0 -0
  57. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/test_start_cli.py +0 -0
  58. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee/workflow_graph.py +0 -0
  59. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_admin/__init__.py +0 -0
  60. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_admin/codee_admin.py +0 -0
  61. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_agent_abstract/__init__.py +0 -0
  62. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_agent_abstract/provider.py +0 -0
  63. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_agent_claude_code/__init__.py +0 -0
  64. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_agent_claude_code/account.py +0 -0
  65. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_agent_claude_code/credentials.py +0 -0
  66. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_agent_claude_code/oauth.py +0 -0
  67. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_agent_claude_code/provider.py +0 -0
  68. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_agent_claude_code/test.py +0 -0
  69. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_agent_claude_code/usage.py +0 -0
  70. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_agent_codex/__init__.py +0 -0
  71. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_agent_codex/provider.py +0 -0
  72. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_agent_codex/test.py +0 -0
  73. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_agent_github_copilot/__init__.py +0 -0
  74. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_agent_github_copilot/provider.py +0 -0
  75. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_agent_github_copilot/test.py +0 -0
  76. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_agent_opencode/__init__.py +0 -0
  77. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_agent_opencode/provider.py +0 -0
  78. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_agent_opencode/test.py +0 -0
  79. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_database/__init__.py +0 -0
  80. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_database/claude_code_accounts.py +0 -0
  81. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_database/database.py +0 -0
  82. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_database/oauth_tokens.py +0 -0
  83. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_main_context/__init__.py +0 -0
  84. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_main_context/context.py +0 -0
  85. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_main_context/logging.py +0 -0
  86. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_main_context/test_context.py +0 -0
  87. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_main_context/test_logging.py +0 -0
  88. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_tasks_abstract/__init__.py +0 -0
  89. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_tasks_abstract/provider.py +0 -0
  90. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_tasks_azure_devops/__init__.py +0 -0
  91. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_tasks_azure_devops/oauth.py +0 -0
  92. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_tasks_azure_devops/provider.py +0 -0
  93. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_tasks_azure_devops/test.py +0 -0
  94. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_tasks_jira/__init__.py +0 -0
  95. {codee_agent-0.7.2 → codee_agent-0.7.4}/src/codee_tasks_jira/provider.py +0 -0
  96. {codee_agent-0.7.2 → codee_agent-0.7.4}/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.2
3
+ Version: 0.7.4
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.2"
3
+ version = "0.7.4"
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"
@@ -2151,52 +2151,50 @@ def dashboard_page() -> rx.Component:
2151
2151
 
2152
2152
 
2153
2153
  def skill_card(skill: SkillSummary) -> rx.Component:
2154
- return rx.box(
2155
- rx.vstack(
2156
- rx.hstack(rx.heading(skill.name, size="4"), rx.spacer(),
2157
- rx.badge(skill.type, color_scheme="blue", variant="soft"), width="100%"),
2158
- rx.text(skill.description, color=MUTED, font_size="0.9rem", min_height="2.7rem",
2159
- overflow="hidden"),
2154
+ return rx.vstack(
2155
+ rx.hstack(rx.heading(skill.name, size="4", class_name="skill-card-title"),
2156
+ rx.badge(skill.type, color_scheme="blue", variant="soft"),
2157
+ class_name="skill-card-head", width="100%"),
2158
+ rx.text(skill.description, color=MUTED, font_size="0.9rem",
2159
+ title=skill.description, class_name="skill-card-description"),
2160
+ rx.hstack(
2161
+ rx.icon("bot", size=14, color=SUBTLE_ICON),
2162
+ rx.text(skill.agent, color=MUTED, font_size="0.82rem"),
2163
+ rx.cond(skill.model != "",
2164
+ rx.code(skill.model, font_size="0.72rem",
2165
+ color_scheme="gray")),
2166
+ spacing="2", align="center", width="100%",
2167
+ class_name="skill-card-meta"),
2168
+ rx.cond(
2169
+ skill.issue_status != "",
2160
2170
  rx.hstack(
2161
- rx.icon("bot", size=14, color=SUBTLE_ICON),
2162
- rx.text(skill.agent, color=MUTED, font_size="0.82rem"),
2163
- rx.cond(skill.model != "",
2164
- rx.code(skill.model, font_size="0.72rem",
2165
- color_scheme="gray")),
2166
- spacing="2", align="center", width="100%"),
2167
- rx.cond(
2168
- skill.issue_status != "",
2169
- rx.hstack(
2170
- rx.badge(skill.issue_type, color_scheme="blue",
2171
- variant="outline"),
2172
- rx.icon("circle-dot", size=14, color=SUBTLE_ICON),
2173
- rx.text(skill.issue_status, color=MUTED,
2174
- font_size="0.82rem"),
2175
- spacing="2",
2176
- align="center",
2177
- width="100%",
2178
- background=HOVER,
2179
- padding="0.55rem 0.65rem",
2180
- border_radius="4px",
2181
- ),
2171
+ rx.badge(skill.issue_type, color_scheme="blue",
2172
+ variant="outline"),
2173
+ rx.icon("circle-dot", size=14, color=SUBTLE_ICON),
2174
+ rx.text(skill.issue_status, color=MUTED,
2175
+ font_size="0.82rem", title=skill.issue_status),
2176
+ spacing="2", align="center", width="100%",
2177
+ background=HOVER, padding="0.55rem 0.65rem",
2178
+ border_radius="4px", class_name="skill-card-trigger",
2182
2179
  ),
2183
- rx.button(rx.icon("pencil", size=15), "Edit", variant="soft",
2184
- on_click=AdminState.edit_skill(skill.slug), width="100%"),
2185
- spacing="4", align="start", height="100%", width="100%"),
2186
- padding="1rem", background=SURFACE, border=BORDER, min_height="185px"),
2180
+ ),
2181
+ rx.button(rx.icon("pencil", size=15), "Edit", variant="soft",
2182
+ on_click=AdminState.edit_skill(skill.slug), width="100%",
2183
+ class_name="skill-card-action"),
2184
+ class_name="skill-card", spacing="3", align="start", width="100%")
2187
2185
 
2188
2186
 
2189
2187
  def agents_card() -> rx.Component:
2190
- return rx.box(
2191
- rx.vstack(
2192
- rx.hstack(rx.heading(AGENTS_FILE, size="4"), rx.spacer(),
2193
- rx.badge("always on", color_scheme="gray", variant="soft"), width="100%"),
2194
- rx.text("Plain-text instructions every coding-agent run loads. Cannot be deleted.",
2195
- color=MUTED, font_size="0.9rem", min_height="2.7rem", overflow="hidden"),
2196
- rx.button(rx.icon("pencil", size=15), "Edit", variant="soft",
2197
- on_click=AdminState.edit_agents, width="100%"),
2198
- spacing="4", align="start", height="100%", width="100%"),
2199
- padding="1rem", background=SURFACE, border=BORDER, min_height="185px")
2188
+ return rx.vstack(
2189
+ rx.hstack(rx.heading(AGENTS_FILE, size="4", class_name="skill-card-title"),
2190
+ rx.badge("always on", color_scheme="gray", variant="soft"),
2191
+ class_name="skill-card-head", width="100%"),
2192
+ rx.text("Plain-text instructions every coding-agent run loads. Cannot be deleted.",
2193
+ color=MUTED, font_size="0.9rem", class_name="skill-card-description"),
2194
+ rx.button(rx.icon("pencil", size=15), "Edit", variant="soft",
2195
+ on_click=AdminState.edit_agents, width="100%",
2196
+ class_name="skill-card-action"),
2197
+ class_name="skill-card", spacing="3", align="start", width="100%")
2200
2198
 
2201
2199
 
2202
2200
  def agents_editor() -> rx.Component:
@@ -3708,6 +3706,43 @@ app = rx.App(
3708
3706
  "button:not(:disabled), [role='button']:not([aria-disabled='true'])": {
3709
3707
  "cursor": "pointer",
3710
3708
  },
3709
+ ".skill-card": {
3710
+ "min_height": "17rem",
3711
+ "height": "100%",
3712
+ "min_width": "0",
3713
+ "padding": "1rem",
3714
+ "background": SURFACE,
3715
+ "border": BORDER,
3716
+ "transition": "border-color 0.15s ease, box-shadow 0.15s ease",
3717
+ },
3718
+ ".skill-card:hover": {
3719
+ "border_color": ACCENT,
3720
+ "box_shadow": "0 4px 16px rgba(24, 39, 75, 0.08)",
3721
+ },
3722
+ ".skill-card-head": {"align_items": "flex-start", "min_width": "0"},
3723
+ ".skill-card-head > :last-child": {"flex_shrink": "0"},
3724
+ ".skill-card-title": {
3725
+ "min_width": "0",
3726
+ "flex": "1",
3727
+ "overflow_wrap": "anywhere",
3728
+ "display": "-webkit-box",
3729
+ "-webkit-box-orient": "vertical",
3730
+ "-webkit-line-clamp": "2",
3731
+ "overflow": "hidden",
3732
+ },
3733
+ ".skill-card-description": {
3734
+ "line_height": "1.45",
3735
+ "display": "-webkit-box",
3736
+ "-webkit-box-orient": "vertical",
3737
+ "-webkit-line-clamp": "3",
3738
+ "overflow": "hidden",
3739
+ },
3740
+ ".skill-card-meta, .skill-card-trigger": {"min_width": "0"},
3741
+ ".skill-card-trigger > :last-child": {
3742
+ "overflow": "hidden", "text_overflow": "ellipsis",
3743
+ "white_space": "nowrap", "min_width": "0",
3744
+ },
3745
+ ".skill-card-action": {"margin_top": "auto"},
3711
3746
  # Expanding halo behind the live dot on in-flight runs.
3712
3747
  "@keyframes codee-ping": {
3713
3748
  "0%": {"transform": "scale(1)", "opacity": "0.55"},
@@ -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:
@@ -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