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.
- spec_kitty_cli-0.12.1.dist-info/METADATA +1767 -0
- spec_kitty_cli-0.12.1.dist-info/RECORD +242 -0
- spec_kitty_cli-0.12.1.dist-info/WHEEL +4 -0
- spec_kitty_cli-0.12.1.dist-info/entry_points.txt +2 -0
- spec_kitty_cli-0.12.1.dist-info/licenses/LICENSE +21 -0
- specify_cli/__init__.py +171 -0
- specify_cli/acceptance.py +627 -0
- specify_cli/agent_utils/README.md +157 -0
- specify_cli/agent_utils/__init__.py +9 -0
- specify_cli/agent_utils/status.py +356 -0
- specify_cli/cli/__init__.py +6 -0
- specify_cli/cli/commands/__init__.py +46 -0
- specify_cli/cli/commands/accept.py +189 -0
- specify_cli/cli/commands/agent/__init__.py +22 -0
- specify_cli/cli/commands/agent/config.py +382 -0
- specify_cli/cli/commands/agent/context.py +191 -0
- specify_cli/cli/commands/agent/feature.py +1057 -0
- specify_cli/cli/commands/agent/release.py +11 -0
- specify_cli/cli/commands/agent/tasks.py +1253 -0
- specify_cli/cli/commands/agent/workflow.py +801 -0
- specify_cli/cli/commands/context.py +246 -0
- specify_cli/cli/commands/dashboard.py +85 -0
- specify_cli/cli/commands/implement.py +973 -0
- specify_cli/cli/commands/init.py +827 -0
- specify_cli/cli/commands/init_help.py +62 -0
- specify_cli/cli/commands/merge.py +755 -0
- specify_cli/cli/commands/mission.py +240 -0
- specify_cli/cli/commands/ops.py +265 -0
- specify_cli/cli/commands/orchestrate.py +640 -0
- specify_cli/cli/commands/repair.py +175 -0
- specify_cli/cli/commands/research.py +165 -0
- specify_cli/cli/commands/sync.py +364 -0
- specify_cli/cli/commands/upgrade.py +249 -0
- specify_cli/cli/commands/validate_encoding.py +186 -0
- specify_cli/cli/commands/validate_tasks.py +186 -0
- specify_cli/cli/commands/verify.py +310 -0
- specify_cli/cli/helpers.py +123 -0
- specify_cli/cli/step_tracker.py +91 -0
- specify_cli/cli/ui.py +192 -0
- specify_cli/core/__init__.py +53 -0
- specify_cli/core/agent_context.py +311 -0
- specify_cli/core/config.py +96 -0
- specify_cli/core/context_validation.py +362 -0
- specify_cli/core/dependency_graph.py +351 -0
- specify_cli/core/git_ops.py +129 -0
- specify_cli/core/multi_parent_merge.py +323 -0
- specify_cli/core/paths.py +260 -0
- specify_cli/core/project_resolver.py +110 -0
- specify_cli/core/stale_detection.py +263 -0
- specify_cli/core/tool_checker.py +79 -0
- specify_cli/core/utils.py +43 -0
- specify_cli/core/vcs/__init__.py +114 -0
- specify_cli/core/vcs/detection.py +341 -0
- specify_cli/core/vcs/exceptions.py +85 -0
- specify_cli/core/vcs/git.py +1304 -0
- specify_cli/core/vcs/jujutsu.py +1208 -0
- specify_cli/core/vcs/protocol.py +285 -0
- specify_cli/core/vcs/types.py +249 -0
- specify_cli/core/version_checker.py +261 -0
- specify_cli/core/worktree.py +506 -0
- specify_cli/dashboard/__init__.py +28 -0
- specify_cli/dashboard/diagnostics.py +204 -0
- specify_cli/dashboard/handlers/__init__.py +17 -0
- specify_cli/dashboard/handlers/api.py +143 -0
- specify_cli/dashboard/handlers/base.py +65 -0
- specify_cli/dashboard/handlers/features.py +390 -0
- specify_cli/dashboard/handlers/router.py +81 -0
- specify_cli/dashboard/handlers/static.py +50 -0
- specify_cli/dashboard/lifecycle.py +541 -0
- specify_cli/dashboard/scanner.py +437 -0
- specify_cli/dashboard/server.py +123 -0
- specify_cli/dashboard/static/dashboard/dashboard.css +722 -0
- specify_cli/dashboard/static/dashboard/dashboard.js +1424 -0
- specify_cli/dashboard/static/spec-kitty.png +0 -0
- specify_cli/dashboard/templates/__init__.py +36 -0
- specify_cli/dashboard/templates/index.html +258 -0
- specify_cli/doc_generators.py +621 -0
- specify_cli/doc_state.py +408 -0
- specify_cli/frontmatter.py +384 -0
- specify_cli/gap_analysis.py +915 -0
- specify_cli/gitignore_manager.py +300 -0
- specify_cli/guards.py +145 -0
- specify_cli/legacy_detector.py +83 -0
- specify_cli/manifest.py +286 -0
- specify_cli/merge/__init__.py +63 -0
- specify_cli/merge/executor.py +653 -0
- specify_cli/merge/forecast.py +215 -0
- specify_cli/merge/ordering.py +126 -0
- specify_cli/merge/preflight.py +230 -0
- specify_cli/merge/state.py +185 -0
- specify_cli/merge/status_resolver.py +354 -0
- specify_cli/mission.py +654 -0
- specify_cli/missions/documentation/command-templates/implement.md +309 -0
- specify_cli/missions/documentation/command-templates/plan.md +275 -0
- specify_cli/missions/documentation/command-templates/review.md +344 -0
- specify_cli/missions/documentation/command-templates/specify.md +206 -0
- specify_cli/missions/documentation/command-templates/tasks.md +189 -0
- specify_cli/missions/documentation/mission.yaml +113 -0
- specify_cli/missions/documentation/templates/divio/explanation-template.md +192 -0
- specify_cli/missions/documentation/templates/divio/howto-template.md +168 -0
- specify_cli/missions/documentation/templates/divio/reference-template.md +179 -0
- specify_cli/missions/documentation/templates/divio/tutorial-template.md +146 -0
- specify_cli/missions/documentation/templates/generators/jsdoc.json.template +18 -0
- specify_cli/missions/documentation/templates/generators/sphinx-conf.py.template +36 -0
- specify_cli/missions/documentation/templates/plan-template.md +269 -0
- specify_cli/missions/documentation/templates/release-template.md +222 -0
- specify_cli/missions/documentation/templates/spec-template.md +172 -0
- specify_cli/missions/documentation/templates/task-prompt-template.md +140 -0
- specify_cli/missions/documentation/templates/tasks-template.md +159 -0
- specify_cli/missions/research/command-templates/merge.md +388 -0
- specify_cli/missions/research/command-templates/plan.md +125 -0
- specify_cli/missions/research/command-templates/review.md +144 -0
- specify_cli/missions/research/command-templates/tasks.md +225 -0
- specify_cli/missions/research/mission.yaml +115 -0
- specify_cli/missions/research/templates/data-model-template.md +33 -0
- specify_cli/missions/research/templates/plan-template.md +161 -0
- specify_cli/missions/research/templates/research/evidence-log.csv +18 -0
- specify_cli/missions/research/templates/research/source-register.csv +18 -0
- specify_cli/missions/research/templates/research-template.md +35 -0
- specify_cli/missions/research/templates/spec-template.md +64 -0
- specify_cli/missions/research/templates/task-prompt-template.md +148 -0
- specify_cli/missions/research/templates/tasks-template.md +114 -0
- specify_cli/missions/software-dev/command-templates/accept.md +75 -0
- specify_cli/missions/software-dev/command-templates/analyze.md +183 -0
- specify_cli/missions/software-dev/command-templates/checklist.md +286 -0
- specify_cli/missions/software-dev/command-templates/clarify.md +157 -0
- specify_cli/missions/software-dev/command-templates/constitution.md +432 -0
- specify_cli/missions/software-dev/command-templates/dashboard.md +101 -0
- specify_cli/missions/software-dev/command-templates/implement.md +41 -0
- specify_cli/missions/software-dev/command-templates/merge.md +383 -0
- specify_cli/missions/software-dev/command-templates/plan.md +171 -0
- specify_cli/missions/software-dev/command-templates/review.md +32 -0
- specify_cli/missions/software-dev/command-templates/specify.md +321 -0
- specify_cli/missions/software-dev/command-templates/tasks.md +566 -0
- specify_cli/missions/software-dev/mission.yaml +100 -0
- specify_cli/missions/software-dev/templates/plan-template.md +132 -0
- specify_cli/missions/software-dev/templates/spec-template.md +116 -0
- specify_cli/missions/software-dev/templates/task-prompt-template.md +140 -0
- specify_cli/missions/software-dev/templates/tasks-template.md +159 -0
- specify_cli/orchestrator/__init__.py +75 -0
- specify_cli/orchestrator/agent_config.py +224 -0
- specify_cli/orchestrator/agents/__init__.py +170 -0
- specify_cli/orchestrator/agents/augment.py +112 -0
- specify_cli/orchestrator/agents/base.py +243 -0
- specify_cli/orchestrator/agents/claude.py +112 -0
- specify_cli/orchestrator/agents/codex.py +106 -0
- specify_cli/orchestrator/agents/copilot.py +137 -0
- specify_cli/orchestrator/agents/cursor.py +139 -0
- specify_cli/orchestrator/agents/gemini.py +115 -0
- specify_cli/orchestrator/agents/kilocode.py +94 -0
- specify_cli/orchestrator/agents/opencode.py +132 -0
- specify_cli/orchestrator/agents/qwen.py +96 -0
- specify_cli/orchestrator/config.py +455 -0
- specify_cli/orchestrator/executor.py +642 -0
- specify_cli/orchestrator/integration.py +1230 -0
- specify_cli/orchestrator/monitor.py +898 -0
- specify_cli/orchestrator/scheduler.py +832 -0
- specify_cli/orchestrator/state.py +508 -0
- specify_cli/orchestrator/testing/__init__.py +122 -0
- specify_cli/orchestrator/testing/availability.py +346 -0
- specify_cli/orchestrator/testing/fixtures.py +684 -0
- specify_cli/orchestrator/testing/paths.py +218 -0
- specify_cli/plan_validation.py +107 -0
- specify_cli/scripts/debug-dashboard-scan.py +61 -0
- specify_cli/scripts/tasks/acceptance_support.py +695 -0
- specify_cli/scripts/tasks/task_helpers.py +506 -0
- specify_cli/scripts/tasks/tasks_cli.py +848 -0
- specify_cli/scripts/validate_encoding.py +180 -0
- specify_cli/task_metadata_validation.py +274 -0
- specify_cli/tasks_support.py +447 -0
- specify_cli/template/__init__.py +47 -0
- specify_cli/template/asset_generator.py +206 -0
- specify_cli/template/github_client.py +334 -0
- specify_cli/template/manager.py +193 -0
- specify_cli/template/renderer.py +99 -0
- specify_cli/templates/AGENTS.md +190 -0
- specify_cli/templates/POWERSHELL_SYNTAX.md +229 -0
- specify_cli/templates/agent-file-template.md +35 -0
- specify_cli/templates/checklist-template.md +42 -0
- specify_cli/templates/claudeignore-template +58 -0
- specify_cli/templates/command-templates/accept.md +141 -0
- specify_cli/templates/command-templates/analyze.md +253 -0
- specify_cli/templates/command-templates/checklist.md +352 -0
- specify_cli/templates/command-templates/clarify.md +224 -0
- specify_cli/templates/command-templates/constitution.md +432 -0
- specify_cli/templates/command-templates/dashboard.md +175 -0
- specify_cli/templates/command-templates/implement.md +190 -0
- specify_cli/templates/command-templates/merge.md +374 -0
- specify_cli/templates/command-templates/plan.md +171 -0
- specify_cli/templates/command-templates/research.md +88 -0
- specify_cli/templates/command-templates/review.md +510 -0
- specify_cli/templates/command-templates/specify.md +321 -0
- specify_cli/templates/command-templates/status.md +92 -0
- specify_cli/templates/command-templates/tasks.md +199 -0
- specify_cli/templates/git-hooks/pre-commit +22 -0
- specify_cli/templates/git-hooks/pre-commit-agent-check +37 -0
- specify_cli/templates/git-hooks/pre-commit-encoding-check +142 -0
- specify_cli/templates/plan-template.md +108 -0
- specify_cli/templates/spec-template.md +118 -0
- specify_cli/templates/task-prompt-template.md +165 -0
- specify_cli/templates/tasks-template.md +161 -0
- specify_cli/templates/vscode-settings.json +13 -0
- specify_cli/text_sanitization.py +225 -0
- specify_cli/upgrade/__init__.py +18 -0
- specify_cli/upgrade/detector.py +239 -0
- specify_cli/upgrade/metadata.py +182 -0
- specify_cli/upgrade/migrations/__init__.py +65 -0
- specify_cli/upgrade/migrations/base.py +80 -0
- specify_cli/upgrade/migrations/m_0_10_0_python_only.py +359 -0
- specify_cli/upgrade/migrations/m_0_10_12_constitution_cleanup.py +99 -0
- specify_cli/upgrade/migrations/m_0_10_14_update_implement_slash_command.py +176 -0
- specify_cli/upgrade/migrations/m_0_10_1_populate_slash_commands.py +174 -0
- specify_cli/upgrade/migrations/m_0_10_2_update_slash_commands.py +172 -0
- specify_cli/upgrade/migrations/m_0_10_6_workflow_simplification.py +174 -0
- specify_cli/upgrade/migrations/m_0_10_8_fix_memory_structure.py +252 -0
- specify_cli/upgrade/migrations/m_0_10_9_repair_templates.py +168 -0
- specify_cli/upgrade/migrations/m_0_11_0_workspace_per_wp.py +182 -0
- specify_cli/upgrade/migrations/m_0_11_1_improved_workflow_templates.py +173 -0
- specify_cli/upgrade/migrations/m_0_11_1_update_implement_slash_command.py +160 -0
- specify_cli/upgrade/migrations/m_0_11_2_improved_workflow_templates.py +173 -0
- specify_cli/upgrade/migrations/m_0_11_3_workflow_agent_flag.py +114 -0
- specify_cli/upgrade/migrations/m_0_12_0_documentation_mission.py +155 -0
- specify_cli/upgrade/migrations/m_0_12_1_remove_kitty_specs_from_gitignore.py +183 -0
- specify_cli/upgrade/migrations/m_0_2_0_specify_to_kittify.py +80 -0
- specify_cli/upgrade/migrations/m_0_4_8_gitignore_agents.py +118 -0
- specify_cli/upgrade/migrations/m_0_5_0_encoding_hooks.py +141 -0
- specify_cli/upgrade/migrations/m_0_6_5_commands_rename.py +169 -0
- specify_cli/upgrade/migrations/m_0_6_7_ensure_missions.py +228 -0
- specify_cli/upgrade/migrations/m_0_7_2_worktree_commands_dedup.py +89 -0
- specify_cli/upgrade/migrations/m_0_7_3_update_scripts.py +114 -0
- specify_cli/upgrade/migrations/m_0_8_0_remove_active_mission.py +82 -0
- specify_cli/upgrade/migrations/m_0_8_0_worktree_agents_symlink.py +148 -0
- specify_cli/upgrade/migrations/m_0_9_0_frontmatter_only_lanes.py +346 -0
- specify_cli/upgrade/migrations/m_0_9_1_complete_lane_migration.py +656 -0
- specify_cli/upgrade/migrations/m_0_9_2_research_mission_templates.py +221 -0
- specify_cli/upgrade/registry.py +121 -0
- specify_cli/upgrade/runner.py +284 -0
- specify_cli/validators/__init__.py +14 -0
- specify_cli/validators/paths.py +154 -0
- specify_cli/validators/research.py +428 -0
- specify_cli/verify_enhanced.py +270 -0
- 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
|
+
)
|