spec-kitty-cli 0.12.1__py3-none-any.whl

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 (242) hide show
  1. spec_kitty_cli-0.12.1.dist-info/METADATA +1767 -0
  2. spec_kitty_cli-0.12.1.dist-info/RECORD +242 -0
  3. spec_kitty_cli-0.12.1.dist-info/WHEEL +4 -0
  4. spec_kitty_cli-0.12.1.dist-info/entry_points.txt +2 -0
  5. spec_kitty_cli-0.12.1.dist-info/licenses/LICENSE +21 -0
  6. specify_cli/__init__.py +171 -0
  7. specify_cli/acceptance.py +627 -0
  8. specify_cli/agent_utils/README.md +157 -0
  9. specify_cli/agent_utils/__init__.py +9 -0
  10. specify_cli/agent_utils/status.py +356 -0
  11. specify_cli/cli/__init__.py +6 -0
  12. specify_cli/cli/commands/__init__.py +46 -0
  13. specify_cli/cli/commands/accept.py +189 -0
  14. specify_cli/cli/commands/agent/__init__.py +22 -0
  15. specify_cli/cli/commands/agent/config.py +382 -0
  16. specify_cli/cli/commands/agent/context.py +191 -0
  17. specify_cli/cli/commands/agent/feature.py +1057 -0
  18. specify_cli/cli/commands/agent/release.py +11 -0
  19. specify_cli/cli/commands/agent/tasks.py +1253 -0
  20. specify_cli/cli/commands/agent/workflow.py +801 -0
  21. specify_cli/cli/commands/context.py +246 -0
  22. specify_cli/cli/commands/dashboard.py +85 -0
  23. specify_cli/cli/commands/implement.py +973 -0
  24. specify_cli/cli/commands/init.py +827 -0
  25. specify_cli/cli/commands/init_help.py +62 -0
  26. specify_cli/cli/commands/merge.py +755 -0
  27. specify_cli/cli/commands/mission.py +240 -0
  28. specify_cli/cli/commands/ops.py +265 -0
  29. specify_cli/cli/commands/orchestrate.py +640 -0
  30. specify_cli/cli/commands/repair.py +175 -0
  31. specify_cli/cli/commands/research.py +165 -0
  32. specify_cli/cli/commands/sync.py +364 -0
  33. specify_cli/cli/commands/upgrade.py +249 -0
  34. specify_cli/cli/commands/validate_encoding.py +186 -0
  35. specify_cli/cli/commands/validate_tasks.py +186 -0
  36. specify_cli/cli/commands/verify.py +310 -0
  37. specify_cli/cli/helpers.py +123 -0
  38. specify_cli/cli/step_tracker.py +91 -0
  39. specify_cli/cli/ui.py +192 -0
  40. specify_cli/core/__init__.py +53 -0
  41. specify_cli/core/agent_context.py +311 -0
  42. specify_cli/core/config.py +96 -0
  43. specify_cli/core/context_validation.py +362 -0
  44. specify_cli/core/dependency_graph.py +351 -0
  45. specify_cli/core/git_ops.py +129 -0
  46. specify_cli/core/multi_parent_merge.py +323 -0
  47. specify_cli/core/paths.py +260 -0
  48. specify_cli/core/project_resolver.py +110 -0
  49. specify_cli/core/stale_detection.py +263 -0
  50. specify_cli/core/tool_checker.py +79 -0
  51. specify_cli/core/utils.py +43 -0
  52. specify_cli/core/vcs/__init__.py +114 -0
  53. specify_cli/core/vcs/detection.py +341 -0
  54. specify_cli/core/vcs/exceptions.py +85 -0
  55. specify_cli/core/vcs/git.py +1304 -0
  56. specify_cli/core/vcs/jujutsu.py +1208 -0
  57. specify_cli/core/vcs/protocol.py +285 -0
  58. specify_cli/core/vcs/types.py +249 -0
  59. specify_cli/core/version_checker.py +261 -0
  60. specify_cli/core/worktree.py +506 -0
  61. specify_cli/dashboard/__init__.py +28 -0
  62. specify_cli/dashboard/diagnostics.py +204 -0
  63. specify_cli/dashboard/handlers/__init__.py +17 -0
  64. specify_cli/dashboard/handlers/api.py +143 -0
  65. specify_cli/dashboard/handlers/base.py +65 -0
  66. specify_cli/dashboard/handlers/features.py +390 -0
  67. specify_cli/dashboard/handlers/router.py +81 -0
  68. specify_cli/dashboard/handlers/static.py +50 -0
  69. specify_cli/dashboard/lifecycle.py +541 -0
  70. specify_cli/dashboard/scanner.py +437 -0
  71. specify_cli/dashboard/server.py +123 -0
  72. specify_cli/dashboard/static/dashboard/dashboard.css +722 -0
  73. specify_cli/dashboard/static/dashboard/dashboard.js +1424 -0
  74. specify_cli/dashboard/static/spec-kitty.png +0 -0
  75. specify_cli/dashboard/templates/__init__.py +36 -0
  76. specify_cli/dashboard/templates/index.html +258 -0
  77. specify_cli/doc_generators.py +621 -0
  78. specify_cli/doc_state.py +408 -0
  79. specify_cli/frontmatter.py +384 -0
  80. specify_cli/gap_analysis.py +915 -0
  81. specify_cli/gitignore_manager.py +300 -0
  82. specify_cli/guards.py +145 -0
  83. specify_cli/legacy_detector.py +83 -0
  84. specify_cli/manifest.py +286 -0
  85. specify_cli/merge/__init__.py +63 -0
  86. specify_cli/merge/executor.py +653 -0
  87. specify_cli/merge/forecast.py +215 -0
  88. specify_cli/merge/ordering.py +126 -0
  89. specify_cli/merge/preflight.py +230 -0
  90. specify_cli/merge/state.py +185 -0
  91. specify_cli/merge/status_resolver.py +354 -0
  92. specify_cli/mission.py +654 -0
  93. specify_cli/missions/documentation/command-templates/implement.md +309 -0
  94. specify_cli/missions/documentation/command-templates/plan.md +275 -0
  95. specify_cli/missions/documentation/command-templates/review.md +344 -0
  96. specify_cli/missions/documentation/command-templates/specify.md +206 -0
  97. specify_cli/missions/documentation/command-templates/tasks.md +189 -0
  98. specify_cli/missions/documentation/mission.yaml +113 -0
  99. specify_cli/missions/documentation/templates/divio/explanation-template.md +192 -0
  100. specify_cli/missions/documentation/templates/divio/howto-template.md +168 -0
  101. specify_cli/missions/documentation/templates/divio/reference-template.md +179 -0
  102. specify_cli/missions/documentation/templates/divio/tutorial-template.md +146 -0
  103. specify_cli/missions/documentation/templates/generators/jsdoc.json.template +18 -0
  104. specify_cli/missions/documentation/templates/generators/sphinx-conf.py.template +36 -0
  105. specify_cli/missions/documentation/templates/plan-template.md +269 -0
  106. specify_cli/missions/documentation/templates/release-template.md +222 -0
  107. specify_cli/missions/documentation/templates/spec-template.md +172 -0
  108. specify_cli/missions/documentation/templates/task-prompt-template.md +140 -0
  109. specify_cli/missions/documentation/templates/tasks-template.md +159 -0
  110. specify_cli/missions/research/command-templates/merge.md +388 -0
  111. specify_cli/missions/research/command-templates/plan.md +125 -0
  112. specify_cli/missions/research/command-templates/review.md +144 -0
  113. specify_cli/missions/research/command-templates/tasks.md +225 -0
  114. specify_cli/missions/research/mission.yaml +115 -0
  115. specify_cli/missions/research/templates/data-model-template.md +33 -0
  116. specify_cli/missions/research/templates/plan-template.md +161 -0
  117. specify_cli/missions/research/templates/research/evidence-log.csv +18 -0
  118. specify_cli/missions/research/templates/research/source-register.csv +18 -0
  119. specify_cli/missions/research/templates/research-template.md +35 -0
  120. specify_cli/missions/research/templates/spec-template.md +64 -0
  121. specify_cli/missions/research/templates/task-prompt-template.md +148 -0
  122. specify_cli/missions/research/templates/tasks-template.md +114 -0
  123. specify_cli/missions/software-dev/command-templates/accept.md +75 -0
  124. specify_cli/missions/software-dev/command-templates/analyze.md +183 -0
  125. specify_cli/missions/software-dev/command-templates/checklist.md +286 -0
  126. specify_cli/missions/software-dev/command-templates/clarify.md +157 -0
  127. specify_cli/missions/software-dev/command-templates/constitution.md +432 -0
  128. specify_cli/missions/software-dev/command-templates/dashboard.md +101 -0
  129. specify_cli/missions/software-dev/command-templates/implement.md +41 -0
  130. specify_cli/missions/software-dev/command-templates/merge.md +383 -0
  131. specify_cli/missions/software-dev/command-templates/plan.md +171 -0
  132. specify_cli/missions/software-dev/command-templates/review.md +32 -0
  133. specify_cli/missions/software-dev/command-templates/specify.md +321 -0
  134. specify_cli/missions/software-dev/command-templates/tasks.md +566 -0
  135. specify_cli/missions/software-dev/mission.yaml +100 -0
  136. specify_cli/missions/software-dev/templates/plan-template.md +132 -0
  137. specify_cli/missions/software-dev/templates/spec-template.md +116 -0
  138. specify_cli/missions/software-dev/templates/task-prompt-template.md +140 -0
  139. specify_cli/missions/software-dev/templates/tasks-template.md +159 -0
  140. specify_cli/orchestrator/__init__.py +75 -0
  141. specify_cli/orchestrator/agent_config.py +224 -0
  142. specify_cli/orchestrator/agents/__init__.py +170 -0
  143. specify_cli/orchestrator/agents/augment.py +112 -0
  144. specify_cli/orchestrator/agents/base.py +243 -0
  145. specify_cli/orchestrator/agents/claude.py +112 -0
  146. specify_cli/orchestrator/agents/codex.py +106 -0
  147. specify_cli/orchestrator/agents/copilot.py +137 -0
  148. specify_cli/orchestrator/agents/cursor.py +139 -0
  149. specify_cli/orchestrator/agents/gemini.py +115 -0
  150. specify_cli/orchestrator/agents/kilocode.py +94 -0
  151. specify_cli/orchestrator/agents/opencode.py +132 -0
  152. specify_cli/orchestrator/agents/qwen.py +96 -0
  153. specify_cli/orchestrator/config.py +455 -0
  154. specify_cli/orchestrator/executor.py +642 -0
  155. specify_cli/orchestrator/integration.py +1230 -0
  156. specify_cli/orchestrator/monitor.py +898 -0
  157. specify_cli/orchestrator/scheduler.py +832 -0
  158. specify_cli/orchestrator/state.py +508 -0
  159. specify_cli/orchestrator/testing/__init__.py +122 -0
  160. specify_cli/orchestrator/testing/availability.py +346 -0
  161. specify_cli/orchestrator/testing/fixtures.py +684 -0
  162. specify_cli/orchestrator/testing/paths.py +218 -0
  163. specify_cli/plan_validation.py +107 -0
  164. specify_cli/scripts/debug-dashboard-scan.py +61 -0
  165. specify_cli/scripts/tasks/acceptance_support.py +695 -0
  166. specify_cli/scripts/tasks/task_helpers.py +506 -0
  167. specify_cli/scripts/tasks/tasks_cli.py +848 -0
  168. specify_cli/scripts/validate_encoding.py +180 -0
  169. specify_cli/task_metadata_validation.py +274 -0
  170. specify_cli/tasks_support.py +447 -0
  171. specify_cli/template/__init__.py +47 -0
  172. specify_cli/template/asset_generator.py +206 -0
  173. specify_cli/template/github_client.py +334 -0
  174. specify_cli/template/manager.py +193 -0
  175. specify_cli/template/renderer.py +99 -0
  176. specify_cli/templates/AGENTS.md +190 -0
  177. specify_cli/templates/POWERSHELL_SYNTAX.md +229 -0
  178. specify_cli/templates/agent-file-template.md +35 -0
  179. specify_cli/templates/checklist-template.md +42 -0
  180. specify_cli/templates/claudeignore-template +58 -0
  181. specify_cli/templates/command-templates/accept.md +141 -0
  182. specify_cli/templates/command-templates/analyze.md +253 -0
  183. specify_cli/templates/command-templates/checklist.md +352 -0
  184. specify_cli/templates/command-templates/clarify.md +224 -0
  185. specify_cli/templates/command-templates/constitution.md +432 -0
  186. specify_cli/templates/command-templates/dashboard.md +175 -0
  187. specify_cli/templates/command-templates/implement.md +190 -0
  188. specify_cli/templates/command-templates/merge.md +374 -0
  189. specify_cli/templates/command-templates/plan.md +171 -0
  190. specify_cli/templates/command-templates/research.md +88 -0
  191. specify_cli/templates/command-templates/review.md +510 -0
  192. specify_cli/templates/command-templates/specify.md +321 -0
  193. specify_cli/templates/command-templates/status.md +92 -0
  194. specify_cli/templates/command-templates/tasks.md +199 -0
  195. specify_cli/templates/git-hooks/pre-commit +22 -0
  196. specify_cli/templates/git-hooks/pre-commit-agent-check +37 -0
  197. specify_cli/templates/git-hooks/pre-commit-encoding-check +142 -0
  198. specify_cli/templates/plan-template.md +108 -0
  199. specify_cli/templates/spec-template.md +118 -0
  200. specify_cli/templates/task-prompt-template.md +165 -0
  201. specify_cli/templates/tasks-template.md +161 -0
  202. specify_cli/templates/vscode-settings.json +13 -0
  203. specify_cli/text_sanitization.py +225 -0
  204. specify_cli/upgrade/__init__.py +18 -0
  205. specify_cli/upgrade/detector.py +239 -0
  206. specify_cli/upgrade/metadata.py +182 -0
  207. specify_cli/upgrade/migrations/__init__.py +65 -0
  208. specify_cli/upgrade/migrations/base.py +80 -0
  209. specify_cli/upgrade/migrations/m_0_10_0_python_only.py +359 -0
  210. specify_cli/upgrade/migrations/m_0_10_12_constitution_cleanup.py +99 -0
  211. specify_cli/upgrade/migrations/m_0_10_14_update_implement_slash_command.py +176 -0
  212. specify_cli/upgrade/migrations/m_0_10_1_populate_slash_commands.py +174 -0
  213. specify_cli/upgrade/migrations/m_0_10_2_update_slash_commands.py +172 -0
  214. specify_cli/upgrade/migrations/m_0_10_6_workflow_simplification.py +174 -0
  215. specify_cli/upgrade/migrations/m_0_10_8_fix_memory_structure.py +252 -0
  216. specify_cli/upgrade/migrations/m_0_10_9_repair_templates.py +168 -0
  217. specify_cli/upgrade/migrations/m_0_11_0_workspace_per_wp.py +182 -0
  218. specify_cli/upgrade/migrations/m_0_11_1_improved_workflow_templates.py +173 -0
  219. specify_cli/upgrade/migrations/m_0_11_1_update_implement_slash_command.py +160 -0
  220. specify_cli/upgrade/migrations/m_0_11_2_improved_workflow_templates.py +173 -0
  221. specify_cli/upgrade/migrations/m_0_11_3_workflow_agent_flag.py +114 -0
  222. specify_cli/upgrade/migrations/m_0_12_0_documentation_mission.py +155 -0
  223. specify_cli/upgrade/migrations/m_0_12_1_remove_kitty_specs_from_gitignore.py +183 -0
  224. specify_cli/upgrade/migrations/m_0_2_0_specify_to_kittify.py +80 -0
  225. specify_cli/upgrade/migrations/m_0_4_8_gitignore_agents.py +118 -0
  226. specify_cli/upgrade/migrations/m_0_5_0_encoding_hooks.py +141 -0
  227. specify_cli/upgrade/migrations/m_0_6_5_commands_rename.py +169 -0
  228. specify_cli/upgrade/migrations/m_0_6_7_ensure_missions.py +228 -0
  229. specify_cli/upgrade/migrations/m_0_7_2_worktree_commands_dedup.py +89 -0
  230. specify_cli/upgrade/migrations/m_0_7_3_update_scripts.py +114 -0
  231. specify_cli/upgrade/migrations/m_0_8_0_remove_active_mission.py +82 -0
  232. specify_cli/upgrade/migrations/m_0_8_0_worktree_agents_symlink.py +148 -0
  233. specify_cli/upgrade/migrations/m_0_9_0_frontmatter_only_lanes.py +346 -0
  234. specify_cli/upgrade/migrations/m_0_9_1_complete_lane_migration.py +656 -0
  235. specify_cli/upgrade/migrations/m_0_9_2_research_mission_templates.py +221 -0
  236. specify_cli/upgrade/registry.py +121 -0
  237. specify_cli/upgrade/runner.py +284 -0
  238. specify_cli/validators/__init__.py +14 -0
  239. specify_cli/validators/paths.py +154 -0
  240. specify_cli/validators/research.py +428 -0
  241. specify_cli/verify_enhanced.py +270 -0
  242. specify_cli/workspace_context.py +224 -0
@@ -0,0 +1,176 @@
1
+ """Migration: Update /spec-kitty.implement slash command across all agents (0.10.14).
2
+
3
+ IMPORTANT: This is a backport of m_0_11_1_update_implement_slash_command.py
4
+ for the 0.10.x release stream. It addresses the same bug for users on 0.10.x
5
+ before they upgrade to 0.11.x.
6
+
7
+ This migration fixes a critical bug where the /spec-kitty.implement slash command
8
+ was severely outdated after the 0.10.0-0.10.13 releases.
9
+
10
+ Issue: The slash command only documented step 1 (display prompt via workflow command)
11
+ but did NOT tell agents to run step 2 (create worktree via implement command).
12
+
13
+ This caused agents to see the prompt but never create the workspace, resulting in
14
+ "no such file or directory" errors when trying to cd to .worktrees/.
15
+
16
+ Fix: Copy the correct implement.md template from packaged missions to all 12
17
+ agent directories.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import shutil
23
+ from pathlib import Path
24
+ from typing import List, Tuple
25
+
26
+ try:
27
+ from importlib.resources import files
28
+ except ImportError:
29
+ from importlib_resources import files # type: ignore
30
+
31
+ from ..registry import MigrationRegistry
32
+ from .base import BaseMigration, MigrationResult
33
+ from .m_0_9_1_complete_lane_migration import get_agent_dirs_for_project
34
+
35
+
36
+ @MigrationRegistry.register
37
+ class UpdateImplementSlashCommandMigration_0_10_14(BaseMigration):
38
+ """Update /spec-kitty.implement slash command to show 2-step workflow (0.10.x).
39
+
40
+ This is a backport of the 0.11.1 migration for the 0.10.x release stream.
41
+ """
42
+
43
+ migration_id = "0.10.14_update_implement_slash_command"
44
+ description = "Update /spec-kitty.implement slash command to show 2-step workflow (0.10.x backport)"
45
+ target_version = "0.10.14"
46
+
47
+ MISSION_NAME = "software-dev"
48
+ TEMPLATE_FILE = "implement.md"
49
+ SLASH_COMMAND_FILE = "spec-kitty.implement.md"
50
+
51
+ def detect(self, project_path: Path) -> bool:
52
+ """Check if any agent has outdated implement slash command."""
53
+ # Check for old single-step pattern that's missing the critical step 2
54
+ old_pattern = "spec-kitty agent workflow implement $ARGUMENTS"
55
+
56
+ agent_dirs = get_agent_dirs_for_project(project_path)
57
+ for agent_dir, subdir in agent_dirs:
58
+ slash_cmd = project_path / agent_dir / subdir / self.SLASH_COMMAND_FILE
59
+ if slash_cmd.exists():
60
+ content = slash_cmd.read_text(encoding="utf-8")
61
+ # If it has the old single-command pattern and NOT the two-step section
62
+ if old_pattern in content and "CRITICAL: This is a TWO-STEP Command" not in content:
63
+ return True
64
+ # If it's missing step 2 entirely
65
+ if "spec-kitty implement WP##" not in content:
66
+ return True
67
+
68
+ return False
69
+
70
+ def can_apply(self, project_path: Path) -> tuple[bool, str]:
71
+ """Check if we can read the template from packaged missions."""
72
+ # For 0.10.x: Try packaged missions (should work post-0.10.8)
73
+ try:
74
+ data_root = files("specify_cli")
75
+ template_path = data_root.joinpath(
76
+ "missions", self.MISSION_NAME, "command-templates", self.TEMPLATE_FILE
77
+ )
78
+ if template_path.exists():
79
+ return True, ""
80
+ except Exception as e:
81
+ return False, f"Cannot access packaged missions: {e}"
82
+
83
+ # Fallback: Try legacy .kittify location (pre-0.11.0)
84
+ legacy_path = project_path / ".kittify" / "missions" / self.MISSION_NAME / "command-templates" / self.TEMPLATE_FILE
85
+ if legacy_path.exists():
86
+ return True, ""
87
+
88
+ return False, "Template not found in packaged missions or legacy location"
89
+
90
+ def apply(self, project_path: Path, dry_run: bool = False) -> MigrationResult:
91
+ """Update implement slash command across all agent directories."""
92
+ changes: List[str] = []
93
+ warnings: List[str] = []
94
+ errors: List[str] = []
95
+
96
+ # Load template from packaged missions or legacy location
97
+ template_content = None
98
+ template_source = None
99
+
100
+ try:
101
+ # Try packaged missions first (0.10.8+)
102
+ data_root = files("specify_cli")
103
+ template_path = data_root.joinpath(
104
+ "missions", self.MISSION_NAME, "command-templates", self.TEMPLATE_FILE
105
+ )
106
+
107
+ if template_path.exists():
108
+ template_content = template_path.read_text(encoding="utf-8")
109
+ template_source = "packaged missions"
110
+ except Exception:
111
+ pass
112
+
113
+ # Fallback to legacy location (pre-0.11.0)
114
+ if not template_content:
115
+ legacy_path = project_path / ".kittify" / "missions" / self.MISSION_NAME / "command-templates" / self.TEMPLATE_FILE
116
+ if legacy_path.exists():
117
+ template_content = legacy_path.read_text(encoding="utf-8")
118
+ template_source = "legacy .kittify/missions"
119
+
120
+ if not template_content:
121
+ errors.append("Template not found in packaged missions or legacy location")
122
+ return MigrationResult(
123
+ success=False,
124
+ changes_made=changes,
125
+ errors=errors,
126
+ warnings=warnings,
127
+ )
128
+
129
+ changes.append(f"Using template from: {template_source}")
130
+
131
+ # Update configured agent directories
132
+ agents_updated = 0
133
+ agent_dirs = get_agent_dirs_for_project(project_path)
134
+ for agent_dir, subdir in agent_dirs:
135
+ agent_path = project_path / agent_dir / subdir
136
+ slash_cmd = agent_path / self.SLASH_COMMAND_FILE
137
+
138
+ # Skip if agent directory doesn't exist
139
+ if not agent_path.exists():
140
+ continue
141
+
142
+ # Check if command needs updating
143
+ needs_update = False
144
+ if slash_cmd.exists():
145
+ current_content = slash_cmd.read_text(encoding="utf-8")
146
+ if current_content != template_content:
147
+ needs_update = True
148
+ else:
149
+ needs_update = True
150
+
151
+ if needs_update:
152
+ if dry_run:
153
+ changes.append(f"Would update: {agent_dir}/{subdir}/{self.SLASH_COMMAND_FILE}")
154
+ else:
155
+ try:
156
+ slash_cmd.write_text(template_content, encoding="utf-8")
157
+ changes.append(f"Updated: {agent_dir}/{subdir}/{self.SLASH_COMMAND_FILE}")
158
+ agents_updated += 1
159
+ except Exception as e:
160
+ errors.append(f"Failed to update {agent_dir}/{subdir}: {e}")
161
+
162
+ if agents_updated > 0:
163
+ if dry_run:
164
+ changes.append(f"Would update {agents_updated} agent directories")
165
+ else:
166
+ changes.append(f"Updated {agents_updated} agent directories")
167
+ else:
168
+ changes.append("No agent directories needed updates")
169
+
170
+ success = len(errors) == 0
171
+ return MigrationResult(
172
+ success=success,
173
+ changes_made=changes,
174
+ errors=errors,
175
+ warnings=warnings,
176
+ )
@@ -0,0 +1,174 @@
1
+ """Migration: Populate missing slash commands from mission templates."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from typing import List
7
+
8
+ from ..registry import MigrationRegistry
9
+ from .base import BaseMigration, MigrationResult
10
+ from .m_0_9_1_complete_lane_migration import get_agent_dirs_for_project
11
+
12
+
13
+ @MigrationRegistry.register
14
+ class PopulateSlashCommandsMigration(BaseMigration):
15
+ """Populate agent command directories from mission templates if missing.
16
+
17
+ Some v0.9.x projects initialized before proper template extraction
18
+ may have empty agent command directories. This migration ensures
19
+ all projects have slash commands available.
20
+
21
+ This migration:
22
+ 1. Checks if agent command directories are empty or missing slash commands
23
+ 2. Finds mission command templates (software-dev or active mission)
24
+ 3. Copies templates to all agent directories with spec-kitty. prefix
25
+ 4. Handles all 12 supported agents
26
+ """
27
+
28
+ migration_id = "0.10.1_populate_slash_commands"
29
+ description = "Populate missing slash commands from mission templates"
30
+ target_version = "0.10.1"
31
+
32
+ def detect(self, project_path: Path) -> bool:
33
+ """Check if slash commands are missing from agent directories."""
34
+ # Check .claude/commands/ directory
35
+ claude_commands = project_path / ".claude" / "commands"
36
+
37
+ # If directory doesn't exist or is empty, migration needed
38
+ if not claude_commands.exists():
39
+ return True
40
+
41
+ # Check if it has spec-kitty commands
42
+ slash_commands = list(claude_commands.glob("spec-kitty.*.md"))
43
+ if len(slash_commands) == 0:
44
+ return True
45
+
46
+ # If we have fewer than expected commands (should be ~10+), migration needed
47
+ if len(slash_commands) < 8:
48
+ return True
49
+
50
+ return False
51
+
52
+ def can_apply(self, project_path: Path) -> tuple[bool, str]:
53
+ """Check if we have mission templates to copy from."""
54
+ # Check for mission templates
55
+ missions_dir = project_path / ".kittify" / "missions"
56
+ if not missions_dir.exists():
57
+ return False, "No missions directory found"
58
+
59
+ # Look for software-dev mission (most common)
60
+ software_dev_templates = missions_dir / "software-dev" / "command-templates"
61
+ if software_dev_templates.exists():
62
+ return True, ""
63
+
64
+ # Look for any mission with command-templates
65
+ for mission_dir in missions_dir.iterdir():
66
+ if mission_dir.is_dir():
67
+ templates = mission_dir / "command-templates"
68
+ if templates.exists():
69
+ return True, ""
70
+
71
+ return False, "No mission command templates found"
72
+
73
+ def apply(self, project_path: Path, dry_run: bool = False) -> MigrationResult:
74
+ """Populate slash commands from mission templates."""
75
+ changes: List[str] = []
76
+ warnings: List[str] = []
77
+ errors: List[str] = []
78
+
79
+ # Find mission templates
80
+ missions_dir = project_path / ".kittify" / "missions"
81
+
82
+ # Prefer software-dev, fallback to first available mission
83
+ command_templates_dir = None
84
+ software_dev_templates = missions_dir / "software-dev" / "command-templates"
85
+
86
+ if software_dev_templates.exists():
87
+ command_templates_dir = software_dev_templates
88
+ mission_name = "software-dev"
89
+ else:
90
+ # Find first mission with templates
91
+ for mission_dir in sorted(missions_dir.iterdir()):
92
+ if mission_dir.is_dir():
93
+ templates = mission_dir / "command-templates"
94
+ if templates.exists():
95
+ command_templates_dir = templates
96
+ mission_name = mission_dir.name
97
+ break
98
+
99
+ if not command_templates_dir:
100
+ errors.append("No mission command templates found")
101
+ return MigrationResult(
102
+ success=False,
103
+ changes_made=changes,
104
+ errors=errors,
105
+ warnings=warnings,
106
+ )
107
+
108
+ # Populate agent command directories (respecting user config)
109
+ total_created = 0
110
+ agent_dirs_to_process = get_agent_dirs_for_project(project_path)
111
+
112
+ for agent_root, subdir in agent_dirs_to_process:
113
+ agent_dir = project_path / agent_root / subdir
114
+
115
+ # Only process if parent directory exists (agent was configured during init)
116
+ if agent_dir.parent.exists():
117
+ created = self._populate_agent_commands(
118
+ command_templates_dir,
119
+ agent_dir,
120
+ "md",
121
+ dry_run,
122
+ changes
123
+ )
124
+ if created > 0:
125
+ agent_name = agent_root.strip(".")
126
+ changes.append(f"Created {created} slash commands for {agent_name} from {mission_name}")
127
+ total_created += created
128
+
129
+ success = len(errors) == 0
130
+ return MigrationResult(
131
+ success=success,
132
+ changes_made=changes,
133
+ errors=errors,
134
+ warnings=warnings,
135
+ )
136
+
137
+ def _populate_agent_commands(
138
+ self,
139
+ templates_dir: Path,
140
+ output_dir: Path,
141
+ extension: str,
142
+ dry_run: bool,
143
+ changes: List[str]
144
+ ) -> int:
145
+ """Copy command templates to agent directory."""
146
+ created_count = 0
147
+
148
+ # Create directory if needed
149
+ if not output_dir.exists():
150
+ if dry_run:
151
+ changes.append(f"Would create: {output_dir}")
152
+ else:
153
+ output_dir.mkdir(parents=True, exist_ok=True)
154
+ changes.append(f"Created: {output_dir}")
155
+
156
+ # Copy each template
157
+ for template_path in sorted(templates_dir.glob("*.md")):
158
+ filename = f"spec-kitty.{template_path.stem}.{extension}" if extension else f"spec-kitty.{template_path.stem}"
159
+ dest_path = output_dir / filename
160
+
161
+ # Skip if already exists
162
+ if dest_path.exists():
163
+ continue
164
+
165
+ if dry_run:
166
+ changes.append(f"Would create: {dest_path.name}")
167
+ else:
168
+ # Simple copy - no variable substitution needed for basic setup
169
+ dest_path.write_text(template_path.read_text(encoding="utf-8"), encoding="utf-8")
170
+ changes.append(f"Created: {dest_path.name}")
171
+
172
+ created_count += 1
173
+
174
+ return created_count
@@ -0,0 +1,172 @@
1
+ """Migration: Update slash commands to Python CLI and flat structure."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from typing import List
7
+
8
+ from ..registry import MigrationRegistry
9
+ from .base import BaseMigration, MigrationResult
10
+ from .m_0_9_1_complete_lane_migration import get_agent_dirs_for_project
11
+
12
+
13
+ @MigrationRegistry.register
14
+ class UpdateSlashCommandsMigration(BaseMigration):
15
+ """Update all agent slash commands to use Python CLI and flat tasks/ structure.
16
+
17
+ This migration addresses two critical issues from feature 008 and 007:
18
+ 1. Slash commands still referenced deleted bash scripts (feature 008 bug)
19
+ 2. Slash commands instructed agents to create subdirectories (feature 007 violation)
20
+
21
+ This migration:
22
+ 1. Detects if slash commands have old bash script references
23
+ 2. Detects if slash commands have subdirectory instructions
24
+ 3. Re-copies templates from mission to get latest Python CLI + flat structure
25
+ 4. Updates ALL 12 supported agent directories
26
+ """
27
+
28
+ migration_id = "0.10.2_update_slash_commands"
29
+ description = "Update slash commands to Python CLI and flat structure"
30
+ target_version = "0.10.2"
31
+
32
+ def detect(self, project_path: Path) -> bool:
33
+ """Check if slash commands need updating."""
34
+ # Check agent directories respecting user config
35
+ agent_dirs = get_agent_dirs_for_project(project_path)
36
+
37
+ for agent_root, subdir in agent_dirs:
38
+ agent_dir = project_path / agent_root / subdir
39
+
40
+ if not agent_dir.exists():
41
+ continue
42
+
43
+ # Check for bash script references (old) or subdirectory references
44
+ for cmd_file in agent_dir.glob("spec-kitty.*.md"):
45
+ content = cmd_file.read_text(encoding="utf-8")
46
+ # Check for bash/PowerShell scripts
47
+ if ".kittify/scripts/bash/" in content or "scripts/bash/" in content:
48
+ return True
49
+ if ".kittify/scripts/powershell/" in content or "scripts/powershell/" in content:
50
+ return True
51
+ # Check for subdirectory violations (feature 007)
52
+ if "tasks/planned/" in content or "tasks/doing/" in content:
53
+ # Exclude "WRONG" examples
54
+ if "WRONG" not in content or content.count("tasks/planned/") > 2:
55
+ return True
56
+
57
+ return False
58
+
59
+ def can_apply(self, project_path: Path) -> tuple[bool, str]:
60
+ """Check if we have mission templates to copy from."""
61
+ missions_dir = project_path / ".kittify" / "missions"
62
+ if not missions_dir.exists():
63
+ return False, "No missions directory found"
64
+
65
+ # Look for software-dev mission
66
+ software_dev_templates = missions_dir / "software-dev" / "command-templates"
67
+ if software_dev_templates.exists():
68
+ return True, ""
69
+
70
+ # Look for any mission with command-templates
71
+ for mission_dir in missions_dir.iterdir():
72
+ if mission_dir.is_dir():
73
+ templates = mission_dir / "command-templates"
74
+ if templates.exists():
75
+ return True, ""
76
+
77
+ return False, "No mission command templates found"
78
+
79
+ def apply(self, project_path: Path, dry_run: bool = False) -> MigrationResult:
80
+ """Update slash commands with latest templates."""
81
+ changes: List[str] = []
82
+ warnings: List[str] = []
83
+ errors: List[str] = []
84
+
85
+ missions_dir = project_path / ".kittify" / "missions"
86
+ claude_commands = project_path / ".claude" / "commands"
87
+
88
+ # Find mission templates
89
+ command_templates_dir = None
90
+ software_dev_templates = missions_dir / "software-dev" / "command-templates"
91
+
92
+ if software_dev_templates.exists():
93
+ command_templates_dir = software_dev_templates
94
+ mission_name = "software-dev"
95
+ else:
96
+ # Find first mission with templates
97
+ for mission_dir in sorted(missions_dir.iterdir()):
98
+ if mission_dir.is_dir():
99
+ templates = mission_dir / "command-templates"
100
+ if templates.exists():
101
+ command_templates_dir = templates
102
+ mission_name = mission_dir.name
103
+ break
104
+
105
+ if not command_templates_dir:
106
+ errors.append("No mission command templates found")
107
+ return MigrationResult(
108
+ success=False,
109
+ changes_made=changes,
110
+ errors=errors,
111
+ warnings=warnings,
112
+ )
113
+
114
+ # Update slash commands in configured agent directories (overwrite existing)
115
+ total_updated = 0
116
+ agent_dirs = get_agent_dirs_for_project(project_path)
117
+
118
+ for agent_root, subdir in agent_dirs:
119
+ agent_dir = project_path / agent_root / subdir
120
+
121
+ if not agent_dir.exists():
122
+ continue
123
+
124
+ updated_count = 0
125
+ for template_path in sorted(command_templates_dir.glob("*.md")):
126
+ filename = f"spec-kitty.{template_path.stem}.md"
127
+ dest_path = agent_dir / filename
128
+
129
+ if dry_run:
130
+ changes.append(f"Would update {agent_root}: {dest_path.name}")
131
+ else:
132
+ dest_path.write_text(template_path.read_text(encoding="utf-8"), encoding="utf-8")
133
+ updated_count += 1
134
+
135
+ if updated_count > 0:
136
+ agent_name = agent_root.strip(".")
137
+ changes.append(f"Updated {updated_count} slash commands for {agent_name}")
138
+ total_updated += updated_count
139
+
140
+ if total_updated > 0:
141
+ changes.append(f"Total: Updated {total_updated} slash commands from {mission_name} mission")
142
+ changes.append("Slash commands now use Python CLI (no bash scripts)")
143
+ changes.append("Slash commands now enforce flat tasks/ structure (feature 007)")
144
+
145
+ commands_dir = project_path / ".kittify" / "commands"
146
+ if commands_dir.exists():
147
+ toml_files = list(commands_dir.glob("*.toml"))
148
+ for toml_file in toml_files:
149
+ if dry_run:
150
+ changes.append(f"Would remove legacy {toml_file.name}")
151
+ else:
152
+ try:
153
+ toml_file.unlink()
154
+ changes.append(f"Removed legacy {toml_file.name}")
155
+ except OSError as e:
156
+ warnings.append(f"Failed to remove {toml_file.name}: {e}")
157
+
158
+ if not dry_run:
159
+ try:
160
+ if not any(commands_dir.iterdir()):
161
+ commands_dir.rmdir()
162
+ changes.append("Removed empty .kittify/commands/ directory")
163
+ except OSError as e:
164
+ warnings.append(f"Failed to remove .kittify/commands/: {e}")
165
+
166
+ success = len(errors) == 0
167
+ return MigrationResult(
168
+ success=success,
169
+ changes_made=changes,
170
+ errors=errors,
171
+ warnings=warnings,
172
+ )