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,182 @@
|
|
|
1
|
+
"""Migration: Workspace-per-WP model with dependency tracking (0.11.0)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from importlib.resources import files
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Dict, List, Optional, Tuple
|
|
9
|
+
|
|
10
|
+
from specify_cli.template.manager import get_local_repo_root
|
|
11
|
+
|
|
12
|
+
from ..registry import MigrationRegistry
|
|
13
|
+
from .base import BaseMigration, MigrationResult
|
|
14
|
+
|
|
15
|
+
MIGRATION_ID = "0.11.0_workspace_per_wp"
|
|
16
|
+
MIGRATION_VERSION = "0.11.0"
|
|
17
|
+
MIGRATION_DESCRIPTION = "Workspace-per-WP model with dependency tracking"
|
|
18
|
+
|
|
19
|
+
MISSION_NAME = "software-dev"
|
|
20
|
+
TEMPLATE_FILES = ("specify.md", "plan.md", "tasks.md", "implement.md")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def detect_legacy_worktrees(project_root: Path) -> List[Path]:
|
|
24
|
+
"""Find legacy worktrees (pre-0.11.0)."""
|
|
25
|
+
worktrees_dir = project_root / ".worktrees"
|
|
26
|
+
if not worktrees_dir.exists():
|
|
27
|
+
return []
|
|
28
|
+
|
|
29
|
+
legacy_worktrees: List[Path] = []
|
|
30
|
+
for item in sorted(worktrees_dir.iterdir()):
|
|
31
|
+
if not item.is_dir():
|
|
32
|
+
continue
|
|
33
|
+
|
|
34
|
+
name = item.name
|
|
35
|
+
has_feature_pattern = re.match(r"^\d{3}-", name)
|
|
36
|
+
has_wp_suffix = re.search(r"-WP\d{2}$", name)
|
|
37
|
+
|
|
38
|
+
if has_feature_pattern and not has_wp_suffix:
|
|
39
|
+
legacy_worktrees.append(item)
|
|
40
|
+
|
|
41
|
+
return legacy_worktrees
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def validate_upgrade(project_root: Path) -> Tuple[bool, List[str]]:
|
|
45
|
+
"""Validate project is ready for 0.11.0 upgrade."""
|
|
46
|
+
legacy_worktrees = detect_legacy_worktrees(project_root)
|
|
47
|
+
if not legacy_worktrees:
|
|
48
|
+
return True, []
|
|
49
|
+
|
|
50
|
+
errors = [
|
|
51
|
+
"Cannot upgrade to 0.11.0 - legacy worktrees detected:",
|
|
52
|
+
"",
|
|
53
|
+
]
|
|
54
|
+
for worktree in legacy_worktrees:
|
|
55
|
+
errors.append(f" - {worktree.name}")
|
|
56
|
+
|
|
57
|
+
errors.extend(
|
|
58
|
+
[
|
|
59
|
+
"",
|
|
60
|
+
"Action required before upgrade:",
|
|
61
|
+
" 1. Complete features: spec-kitty merge <feature>",
|
|
62
|
+
" 2. OR delete worktrees: git worktree remove .worktrees/<feature>",
|
|
63
|
+
"",
|
|
64
|
+
"Use: spec-kitty list-legacy-features to see all legacy worktrees",
|
|
65
|
+
]
|
|
66
|
+
)
|
|
67
|
+
return False, errors
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _load_template_sources(base) -> Optional[Dict[str, str]]:
|
|
71
|
+
contents: Dict[str, str] = {}
|
|
72
|
+
for name in TEMPLATE_FILES:
|
|
73
|
+
resource = base.joinpath(name)
|
|
74
|
+
if not resource.exists():
|
|
75
|
+
return None
|
|
76
|
+
contents[name] = resource.read_text(encoding="utf-8")
|
|
77
|
+
return contents
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _resolve_template_sources() -> Optional[Dict[str, str]]:
|
|
81
|
+
local_repo = get_local_repo_root()
|
|
82
|
+
if local_repo:
|
|
83
|
+
candidates = [
|
|
84
|
+
local_repo / "src" / "specify_cli" / "missions" / MISSION_NAME / "command-templates", # 011: New location
|
|
85
|
+
local_repo / ".kittify" / "missions" / MISSION_NAME / "command-templates", # Legacy (pre-011)
|
|
86
|
+
]
|
|
87
|
+
for candidate in candidates:
|
|
88
|
+
if candidate.exists():
|
|
89
|
+
contents = _load_template_sources(candidate)
|
|
90
|
+
if contents:
|
|
91
|
+
return contents
|
|
92
|
+
|
|
93
|
+
# 011: Templates packaged in src/specify_cli/missions/
|
|
94
|
+
data_root = files("specify_cli")
|
|
95
|
+
candidate = data_root.joinpath("missions", MISSION_NAME, "command-templates")
|
|
96
|
+
if candidate.exists():
|
|
97
|
+
contents = _load_template_sources(candidate)
|
|
98
|
+
if contents:
|
|
99
|
+
return contents
|
|
100
|
+
|
|
101
|
+
return None
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def update_template_sources(project_root: Path, dry_run: bool = False) -> Tuple[List[str], List[str]]:
|
|
105
|
+
"""Update mission command templates with workspace-per-WP workflow text."""
|
|
106
|
+
changes: List[str] = []
|
|
107
|
+
errors: List[str] = []
|
|
108
|
+
|
|
109
|
+
templates_dir = project_root / ".kittify" / "missions" / MISSION_NAME / "command-templates"
|
|
110
|
+
if not templates_dir.exists():
|
|
111
|
+
errors.append(f"Missing mission templates at {templates_dir}")
|
|
112
|
+
return changes, errors
|
|
113
|
+
|
|
114
|
+
source_templates = _resolve_template_sources()
|
|
115
|
+
if not source_templates:
|
|
116
|
+
errors.append("Unable to locate packaged mission templates for update")
|
|
117
|
+
return changes, errors
|
|
118
|
+
|
|
119
|
+
updated = 0
|
|
120
|
+
for name, content in source_templates.items():
|
|
121
|
+
dest_path = templates_dir / name
|
|
122
|
+
current = dest_path.read_text(encoding="utf-8") if dest_path.exists() else None
|
|
123
|
+
if current == content:
|
|
124
|
+
continue
|
|
125
|
+
|
|
126
|
+
if dry_run:
|
|
127
|
+
changes.append(f"Would update {dest_path}")
|
|
128
|
+
else:
|
|
129
|
+
dest_path.write_text(content, encoding="utf-8")
|
|
130
|
+
changes.append(f"Updated {dest_path}")
|
|
131
|
+
updated += 1
|
|
132
|
+
|
|
133
|
+
if updated == 0:
|
|
134
|
+
changes.append("Templates already up to date")
|
|
135
|
+
|
|
136
|
+
return changes, errors
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@MigrationRegistry.register
|
|
140
|
+
class WorkspacePerWPMigration(BaseMigration):
|
|
141
|
+
"""Upgrade templates for workspace-per-WP model with dependency tracking."""
|
|
142
|
+
|
|
143
|
+
migration_id = MIGRATION_ID
|
|
144
|
+
description = MIGRATION_DESCRIPTION
|
|
145
|
+
target_version = MIGRATION_VERSION
|
|
146
|
+
|
|
147
|
+
def detect(self, project_path: Path) -> bool:
|
|
148
|
+
"""Detect if mission templates need workspace-per-WP updates."""
|
|
149
|
+
templates_dir = project_path / ".kittify" / "missions" / MISSION_NAME / "command-templates"
|
|
150
|
+
if not templates_dir.exists():
|
|
151
|
+
return False
|
|
152
|
+
|
|
153
|
+
source_templates = _resolve_template_sources()
|
|
154
|
+
if not source_templates:
|
|
155
|
+
return False
|
|
156
|
+
|
|
157
|
+
for name, content in source_templates.items():
|
|
158
|
+
dest_path = templates_dir / name
|
|
159
|
+
if not dest_path.exists():
|
|
160
|
+
return True
|
|
161
|
+
if dest_path.read_text(encoding="utf-8") != content:
|
|
162
|
+
return True
|
|
163
|
+
|
|
164
|
+
return False
|
|
165
|
+
|
|
166
|
+
def can_apply(self, project_path: Path) -> tuple[bool, str]:
|
|
167
|
+
"""Block upgrade when legacy worktrees exist."""
|
|
168
|
+
is_valid, errors = validate_upgrade(project_path)
|
|
169
|
+
if not is_valid:
|
|
170
|
+
return False, "\n".join(errors)
|
|
171
|
+
return True, ""
|
|
172
|
+
|
|
173
|
+
def apply(self, project_path: Path, dry_run: bool = False) -> MigrationResult:
|
|
174
|
+
"""Apply the workspace-per-WP migration."""
|
|
175
|
+
changes, errors = update_template_sources(project_path, dry_run=dry_run)
|
|
176
|
+
success = len(errors) == 0
|
|
177
|
+
return MigrationResult(
|
|
178
|
+
success=success,
|
|
179
|
+
changes_made=changes,
|
|
180
|
+
errors=errors,
|
|
181
|
+
warnings=[],
|
|
182
|
+
)
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""Migration: Update workflow templates with end-of-output instructions."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import shutil
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import List
|
|
8
|
+
|
|
9
|
+
from ..registry import MigrationRegistry
|
|
10
|
+
from .base import BaseMigration, MigrationResult
|
|
11
|
+
from .m_0_9_1_complete_lane_migration import get_agent_dirs_for_project
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@MigrationRegistry.register
|
|
15
|
+
class ImprovedWorkflowTemplatesMigration(BaseMigration):
|
|
16
|
+
"""Update implement and review templates with improved agent guidance.
|
|
17
|
+
|
|
18
|
+
This migration addresses workflow command state corruption issues by:
|
|
19
|
+
1. Warning agents about long output (1000+ lines)
|
|
20
|
+
2. Instructing agents to scroll to bottom for completion commands
|
|
21
|
+
3. Emphasizing that Python scripts handle all file updates automatically
|
|
22
|
+
4. Removing manual file editing requirements from instructions
|
|
23
|
+
|
|
24
|
+
The workflow.py commands now repeat completion instructions at the END
|
|
25
|
+
of output, after the long WP prompt content.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
migration_id = "0.11.1_improved_workflow_templates"
|
|
29
|
+
description = "Update workflow templates with end-of-output instructions"
|
|
30
|
+
target_version = "0.11.1"
|
|
31
|
+
|
|
32
|
+
def detect(self, project_path: Path) -> bool:
|
|
33
|
+
"""Check if slash commands need updating with improved guidance."""
|
|
34
|
+
# Check if any agent directory has the old templates (without scroll warning)
|
|
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 implement.md for new structure
|
|
44
|
+
implement_file = agent_dir / "spec-kitty.implement.md"
|
|
45
|
+
if implement_file.exists():
|
|
46
|
+
content = implement_file.read_text(encoding="utf-8")
|
|
47
|
+
# New template has warning about scrolling to bottom
|
|
48
|
+
if "scroll to the BOTTOM" not in content.lower():
|
|
49
|
+
return True
|
|
50
|
+
|
|
51
|
+
# Check review.md for new structure
|
|
52
|
+
review_file = agent_dir / "spec-kitty.review.md"
|
|
53
|
+
if review_file.exists():
|
|
54
|
+
content = review_file.read_text(encoding="utf-8")
|
|
55
|
+
# New template has warning about scrolling to bottom
|
|
56
|
+
if "scroll to the BOTTOM" not in content.lower():
|
|
57
|
+
return True
|
|
58
|
+
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
def can_apply(self, project_path: Path) -> tuple[bool, str]:
|
|
62
|
+
"""Check if we can apply this migration."""
|
|
63
|
+
kittify_dir = project_path / ".kittify"
|
|
64
|
+
if not kittify_dir.exists():
|
|
65
|
+
return False, "No .kittify directory (not a spec-kitty project)"
|
|
66
|
+
|
|
67
|
+
return True, ""
|
|
68
|
+
|
|
69
|
+
def apply(self, project_path: Path, dry_run: bool = False) -> MigrationResult:
|
|
70
|
+
"""Update implement and review slash commands with improved templates."""
|
|
71
|
+
changes: List[str] = []
|
|
72
|
+
warnings: List[str] = []
|
|
73
|
+
errors: List[str] = []
|
|
74
|
+
|
|
75
|
+
missions_dir = project_path / ".kittify" / "missions"
|
|
76
|
+
software_dev_templates = missions_dir / "software-dev" / "command-templates"
|
|
77
|
+
|
|
78
|
+
# Copy updated mission templates from package first (if available)
|
|
79
|
+
try:
|
|
80
|
+
import specify_cli
|
|
81
|
+
except ImportError as exc:
|
|
82
|
+
errors.append(f"Failed to import specify_cli: {exc}")
|
|
83
|
+
return MigrationResult(
|
|
84
|
+
success=False,
|
|
85
|
+
changes_made=changes,
|
|
86
|
+
errors=errors,
|
|
87
|
+
warnings=warnings,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
pkg_root = Path(specify_cli.__file__).parent
|
|
91
|
+
pkg_templates = pkg_root / "missions" / "software-dev" / "command-templates"
|
|
92
|
+
if not pkg_templates.exists():
|
|
93
|
+
pkg_templates = pkg_root / ".kittify" / "missions" / "software-dev" / "command-templates"
|
|
94
|
+
|
|
95
|
+
if pkg_templates.exists():
|
|
96
|
+
if not dry_run:
|
|
97
|
+
software_dev_templates.mkdir(parents=True, exist_ok=True)
|
|
98
|
+
for template_name in ("implement.md", "review.md"):
|
|
99
|
+
src = pkg_templates / template_name
|
|
100
|
+
if not src.exists():
|
|
101
|
+
warnings.append(f"Package template missing: {template_name}")
|
|
102
|
+
continue
|
|
103
|
+
if dry_run:
|
|
104
|
+
changes.append(f"Would update mission template: software-dev/{template_name}")
|
|
105
|
+
else:
|
|
106
|
+
try:
|
|
107
|
+
shutil.copy2(src, software_dev_templates / template_name)
|
|
108
|
+
changes.append(f"Updated mission template: software-dev/{template_name}")
|
|
109
|
+
except OSError as e:
|
|
110
|
+
warnings.append(f"Failed to copy mission template {template_name}: {e}")
|
|
111
|
+
else:
|
|
112
|
+
warnings.append(
|
|
113
|
+
"Mission templates not found in package. "
|
|
114
|
+
"Slash commands may already be updated or require manual repair."
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Update implement.md and review.md in configured agent directories only
|
|
118
|
+
templates_to_update = ["implement.md", "review.md"]
|
|
119
|
+
total_updated = 0
|
|
120
|
+
|
|
121
|
+
# Get agent dirs respecting user's config
|
|
122
|
+
agent_dirs_to_process = get_agent_dirs_for_project(project_path)
|
|
123
|
+
|
|
124
|
+
for agent_root, subdir in agent_dirs_to_process:
|
|
125
|
+
agent_dir = project_path / agent_root / subdir
|
|
126
|
+
|
|
127
|
+
# Skip if directory doesn't exist (respect user deletions)
|
|
128
|
+
if not agent_dir.exists():
|
|
129
|
+
continue
|
|
130
|
+
|
|
131
|
+
updated_count = 0
|
|
132
|
+
for template_name in templates_to_update:
|
|
133
|
+
source_template = software_dev_templates / template_name
|
|
134
|
+
if not source_template.exists():
|
|
135
|
+
continue
|
|
136
|
+
|
|
137
|
+
dest_filename = f"spec-kitty.{template_name}"
|
|
138
|
+
dest_path = agent_dir / dest_filename
|
|
139
|
+
|
|
140
|
+
if dry_run:
|
|
141
|
+
changes.append(f"Would update {agent_root}: {dest_filename}")
|
|
142
|
+
else:
|
|
143
|
+
try:
|
|
144
|
+
dest_path.write_text(
|
|
145
|
+
source_template.read_text(encoding="utf-8"),
|
|
146
|
+
encoding="utf-8",
|
|
147
|
+
)
|
|
148
|
+
updated_count += 1
|
|
149
|
+
except OSError as e:
|
|
150
|
+
warnings.append(f"Failed to update {agent_root}/{dest_filename}: {e}")
|
|
151
|
+
|
|
152
|
+
if updated_count > 0:
|
|
153
|
+
agent_name = agent_root.strip(".")
|
|
154
|
+
changes.append(f"Updated {updated_count} templates for {agent_name}")
|
|
155
|
+
total_updated += updated_count
|
|
156
|
+
|
|
157
|
+
if total_updated > 0:
|
|
158
|
+
changes.append(f"Total: Updated {total_updated} slash command templates across all agents")
|
|
159
|
+
changes.append("Templates now warn agents to scroll to bottom of long output")
|
|
160
|
+
changes.append("Templates emphasize automated file updates (no manual editing)")
|
|
161
|
+
changes.append("Prevents state corruption from incomplete workflows")
|
|
162
|
+
elif not changes:
|
|
163
|
+
warnings.append(
|
|
164
|
+
"No templates were updated (already updated or mission templates missing)"
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
success = len(errors) == 0
|
|
168
|
+
return MigrationResult(
|
|
169
|
+
success=success,
|
|
170
|
+
changes_made=changes,
|
|
171
|
+
errors=errors,
|
|
172
|
+
warnings=warnings,
|
|
173
|
+
)
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""Migration: Update /spec-kitty.implement slash command across all agents.
|
|
2
|
+
|
|
3
|
+
This migration fixes a critical bug where the /spec-kitty.implement slash command
|
|
4
|
+
was severely outdated after the 0.11.0 workspace-per-WP migration.
|
|
5
|
+
|
|
6
|
+
Issue: The slash command only documented step 1 (display prompt via workflow command)
|
|
7
|
+
but did NOT tell agents to run step 2 (create worktree via implement command).
|
|
8
|
+
|
|
9
|
+
This caused agents to see the prompt but never create the workspace, resulting in
|
|
10
|
+
"no such file or directory" errors when trying to cd to .worktrees/.
|
|
11
|
+
|
|
12
|
+
Fix: Copy the correct implement.md template from packaged missions to all 12
|
|
13
|
+
agent directories.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import shutil
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import List, Tuple
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
from importlib.resources import files
|
|
24
|
+
except ImportError:
|
|
25
|
+
from importlib_resources import files # type: ignore
|
|
26
|
+
|
|
27
|
+
from ..registry import MigrationRegistry
|
|
28
|
+
from .base import BaseMigration, MigrationResult
|
|
29
|
+
from .m_0_9_1_complete_lane_migration import get_agent_dirs_for_project
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@MigrationRegistry.register
|
|
33
|
+
class UpdateImplementSlashCommandMigration(BaseMigration):
|
|
34
|
+
"""Update /spec-kitty.implement slash command to show 2-step workflow.
|
|
35
|
+
|
|
36
|
+
The 0.11.0 migration updated mission templates but did NOT update agent
|
|
37
|
+
slash commands. This migration copies the correct implement.md template
|
|
38
|
+
from packaged missions to all agent directories.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
migration_id = "0.11.1_update_implement_slash_command"
|
|
42
|
+
description = "Update /spec-kitty.implement slash command to show 2-step workflow"
|
|
43
|
+
target_version = "0.11.1"
|
|
44
|
+
|
|
45
|
+
MISSION_NAME = "software-dev"
|
|
46
|
+
TEMPLATE_FILE = "implement.md"
|
|
47
|
+
SLASH_COMMAND_FILE = "spec-kitty.implement.md"
|
|
48
|
+
|
|
49
|
+
def detect(self, project_path: Path) -> bool:
|
|
50
|
+
"""Check if any agent has outdated implement slash command."""
|
|
51
|
+
# Check for old single-step pattern that's missing the critical step 2
|
|
52
|
+
old_pattern = "spec-kitty agent workflow implement $ARGUMENTS"
|
|
53
|
+
|
|
54
|
+
agent_dirs = get_agent_dirs_for_project(project_path)
|
|
55
|
+
for agent_dir, subdir in agent_dirs:
|
|
56
|
+
slash_cmd = project_path / agent_dir / subdir / self.SLASH_COMMAND_FILE
|
|
57
|
+
if slash_cmd.exists():
|
|
58
|
+
content = slash_cmd.read_text(encoding="utf-8")
|
|
59
|
+
# If it has the old single-command pattern and NOT the two-step section
|
|
60
|
+
if old_pattern in content and "CRITICAL: This is a TWO-STEP Command" not in content:
|
|
61
|
+
return True
|
|
62
|
+
# If it's missing step 2 entirely
|
|
63
|
+
if "spec-kitty implement WP##" not in content:
|
|
64
|
+
return True
|
|
65
|
+
|
|
66
|
+
return False
|
|
67
|
+
|
|
68
|
+
def can_apply(self, project_path: Path) -> tuple[bool, str]:
|
|
69
|
+
"""Check if we can read the template from packaged missions."""
|
|
70
|
+
# Try to load from packaged data
|
|
71
|
+
try:
|
|
72
|
+
data_root = files("specify_cli")
|
|
73
|
+
template_path = data_root.joinpath(
|
|
74
|
+
"missions", self.MISSION_NAME, "command-templates", self.TEMPLATE_FILE
|
|
75
|
+
)
|
|
76
|
+
if template_path.exists():
|
|
77
|
+
return True, ""
|
|
78
|
+
except Exception as e:
|
|
79
|
+
return False, f"Cannot access packaged missions: {e}"
|
|
80
|
+
|
|
81
|
+
return False, "Template not found in packaged missions"
|
|
82
|
+
|
|
83
|
+
def apply(self, project_path: Path, dry_run: bool = False) -> MigrationResult:
|
|
84
|
+
"""Update implement slash command across all agent directories."""
|
|
85
|
+
changes: List[str] = []
|
|
86
|
+
warnings: List[str] = []
|
|
87
|
+
errors: List[str] = []
|
|
88
|
+
|
|
89
|
+
# Load template from packaged missions
|
|
90
|
+
try:
|
|
91
|
+
data_root = files("specify_cli")
|
|
92
|
+
template_path = data_root.joinpath(
|
|
93
|
+
"missions", self.MISSION_NAME, "command-templates", self.TEMPLATE_FILE
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
if not template_path.exists():
|
|
97
|
+
errors.append("Template not found in packaged missions")
|
|
98
|
+
return MigrationResult(
|
|
99
|
+
success=False,
|
|
100
|
+
changes_made=changes,
|
|
101
|
+
errors=errors,
|
|
102
|
+
warnings=warnings,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
template_content = template_path.read_text(encoding="utf-8")
|
|
106
|
+
except Exception as e:
|
|
107
|
+
errors.append(f"Failed to read template: {e}")
|
|
108
|
+
return MigrationResult(
|
|
109
|
+
success=False,
|
|
110
|
+
changes_made=changes,
|
|
111
|
+
errors=errors,
|
|
112
|
+
warnings=warnings,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
# Update configured agent directories
|
|
116
|
+
agents_updated = 0
|
|
117
|
+
agent_dirs = get_agent_dirs_for_project(project_path)
|
|
118
|
+
for agent_dir, subdir in agent_dirs:
|
|
119
|
+
agent_path = project_path / agent_dir / subdir
|
|
120
|
+
slash_cmd = agent_path / self.SLASH_COMMAND_FILE
|
|
121
|
+
|
|
122
|
+
# Skip if agent directory doesn't exist
|
|
123
|
+
if not agent_path.exists():
|
|
124
|
+
continue
|
|
125
|
+
|
|
126
|
+
# Check if command needs updating
|
|
127
|
+
needs_update = False
|
|
128
|
+
if slash_cmd.exists():
|
|
129
|
+
current_content = slash_cmd.read_text(encoding="utf-8")
|
|
130
|
+
if current_content != template_content:
|
|
131
|
+
needs_update = True
|
|
132
|
+
else:
|
|
133
|
+
needs_update = True
|
|
134
|
+
|
|
135
|
+
if needs_update:
|
|
136
|
+
if dry_run:
|
|
137
|
+
changes.append(f"Would update: {agent_dir}/{subdir}/{self.SLASH_COMMAND_FILE}")
|
|
138
|
+
else:
|
|
139
|
+
try:
|
|
140
|
+
slash_cmd.write_text(template_content, encoding="utf-8")
|
|
141
|
+
changes.append(f"Updated: {agent_dir}/{subdir}/{self.SLASH_COMMAND_FILE}")
|
|
142
|
+
agents_updated += 1
|
|
143
|
+
except Exception as e:
|
|
144
|
+
errors.append(f"Failed to update {agent_dir}/{subdir}: {e}")
|
|
145
|
+
|
|
146
|
+
if agents_updated > 0:
|
|
147
|
+
if dry_run:
|
|
148
|
+
changes.append(f"Would update {agents_updated} agent directories")
|
|
149
|
+
else:
|
|
150
|
+
changes.append(f"Updated {agents_updated} agent directories")
|
|
151
|
+
else:
|
|
152
|
+
changes.append("No agent directories needed updates")
|
|
153
|
+
|
|
154
|
+
success = len(errors) == 0
|
|
155
|
+
return MigrationResult(
|
|
156
|
+
success=success,
|
|
157
|
+
changes_made=changes,
|
|
158
|
+
errors=errors,
|
|
159
|
+
warnings=warnings,
|
|
160
|
+
)
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""Migration: Update workflow templates with end-of-output instructions."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import shutil
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import List
|
|
8
|
+
|
|
9
|
+
from ..registry import MigrationRegistry
|
|
10
|
+
from .base import BaseMigration, MigrationResult
|
|
11
|
+
from .m_0_9_1_complete_lane_migration import get_agent_dirs_for_project
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@MigrationRegistry.register
|
|
15
|
+
class ImprovedWorkflowTemplatesMigration(BaseMigration):
|
|
16
|
+
"""Update implement and review templates with improved agent guidance.
|
|
17
|
+
|
|
18
|
+
This migration addresses workflow command state corruption issues by:
|
|
19
|
+
1. Warning agents about long output (1000+ lines)
|
|
20
|
+
2. Instructing agents to scroll to bottom for completion commands
|
|
21
|
+
3. Emphasizing that Python scripts handle all file updates automatically
|
|
22
|
+
4. Removing manual file editing requirements from instructions
|
|
23
|
+
|
|
24
|
+
The workflow.py commands now repeat completion instructions at the END
|
|
25
|
+
of output, after the long WP prompt content.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
migration_id = "0.11.2_improved_workflow_templates"
|
|
29
|
+
description = "Update workflow templates with end-of-output instructions and --agent requirement"
|
|
30
|
+
target_version = "0.11.2"
|
|
31
|
+
|
|
32
|
+
def detect(self, project_path: Path) -> bool:
|
|
33
|
+
"""Check if slash commands need updating with improved guidance."""
|
|
34
|
+
# Check if any agent directory has the old templates (without scroll warning)
|
|
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 implement.md for new structure
|
|
44
|
+
implement_file = agent_dir / "spec-kitty.implement.md"
|
|
45
|
+
if implement_file.exists():
|
|
46
|
+
content = implement_file.read_text(encoding="utf-8")
|
|
47
|
+
# New template has warning about scrolling to bottom
|
|
48
|
+
if "scroll to the BOTTOM" not in content.lower():
|
|
49
|
+
return True
|
|
50
|
+
|
|
51
|
+
# Check review.md for new structure
|
|
52
|
+
review_file = agent_dir / "spec-kitty.review.md"
|
|
53
|
+
if review_file.exists():
|
|
54
|
+
content = review_file.read_text(encoding="utf-8")
|
|
55
|
+
# New template has warning about scrolling to bottom
|
|
56
|
+
if "scroll to the BOTTOM" not in content.lower():
|
|
57
|
+
return True
|
|
58
|
+
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
def can_apply(self, project_path: Path) -> tuple[bool, str]:
|
|
62
|
+
"""Check if we can apply this migration."""
|
|
63
|
+
kittify_dir = project_path / ".kittify"
|
|
64
|
+
if not kittify_dir.exists():
|
|
65
|
+
return False, "No .kittify directory (not a spec-kitty project)"
|
|
66
|
+
|
|
67
|
+
return True, ""
|
|
68
|
+
|
|
69
|
+
def apply(self, project_path: Path, dry_run: bool = False) -> MigrationResult:
|
|
70
|
+
"""Update implement and review slash commands with improved templates."""
|
|
71
|
+
changes: List[str] = []
|
|
72
|
+
warnings: List[str] = []
|
|
73
|
+
errors: List[str] = []
|
|
74
|
+
|
|
75
|
+
missions_dir = project_path / ".kittify" / "missions"
|
|
76
|
+
software_dev_templates = missions_dir / "software-dev" / "command-templates"
|
|
77
|
+
|
|
78
|
+
# Copy updated mission templates from package first (if available)
|
|
79
|
+
try:
|
|
80
|
+
import specify_cli
|
|
81
|
+
except ImportError as exc:
|
|
82
|
+
errors.append(f"Failed to import specify_cli: {exc}")
|
|
83
|
+
return MigrationResult(
|
|
84
|
+
success=False,
|
|
85
|
+
changes_made=changes,
|
|
86
|
+
errors=errors,
|
|
87
|
+
warnings=warnings,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
pkg_root = Path(specify_cli.__file__).parent
|
|
91
|
+
pkg_templates = pkg_root / "missions" / "software-dev" / "command-templates"
|
|
92
|
+
if not pkg_templates.exists():
|
|
93
|
+
pkg_templates = pkg_root / ".kittify" / "missions" / "software-dev" / "command-templates"
|
|
94
|
+
|
|
95
|
+
if pkg_templates.exists():
|
|
96
|
+
if not dry_run:
|
|
97
|
+
software_dev_templates.mkdir(parents=True, exist_ok=True)
|
|
98
|
+
for template_name in ("implement.md", "review.md"):
|
|
99
|
+
src = pkg_templates / template_name
|
|
100
|
+
if not src.exists():
|
|
101
|
+
warnings.append(f"Package template missing: {template_name}")
|
|
102
|
+
continue
|
|
103
|
+
if dry_run:
|
|
104
|
+
changes.append(f"Would update mission template: software-dev/{template_name}")
|
|
105
|
+
else:
|
|
106
|
+
try:
|
|
107
|
+
shutil.copy2(src, software_dev_templates / template_name)
|
|
108
|
+
changes.append(f"Updated mission template: software-dev/{template_name}")
|
|
109
|
+
except OSError as e:
|
|
110
|
+
warnings.append(f"Failed to copy mission template {template_name}: {e}")
|
|
111
|
+
else:
|
|
112
|
+
warnings.append(
|
|
113
|
+
"Mission templates not found in package. "
|
|
114
|
+
"Slash commands may already be updated or require manual repair."
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Update implement.md and review.md in configured agent directories only
|
|
118
|
+
templates_to_update = ["implement.md", "review.md"]
|
|
119
|
+
total_updated = 0
|
|
120
|
+
|
|
121
|
+
# Get agent dirs respecting user's config
|
|
122
|
+
agent_dirs_to_process = get_agent_dirs_for_project(project_path)
|
|
123
|
+
|
|
124
|
+
for agent_root, subdir in agent_dirs_to_process:
|
|
125
|
+
agent_dir = project_path / agent_root / subdir
|
|
126
|
+
|
|
127
|
+
# Skip if directory doesn't exist (respect user deletions)
|
|
128
|
+
if not agent_dir.exists():
|
|
129
|
+
continue
|
|
130
|
+
|
|
131
|
+
updated_count = 0
|
|
132
|
+
for template_name in templates_to_update:
|
|
133
|
+
source_template = software_dev_templates / template_name
|
|
134
|
+
if not source_template.exists():
|
|
135
|
+
continue
|
|
136
|
+
|
|
137
|
+
dest_filename = f"spec-kitty.{template_name}"
|
|
138
|
+
dest_path = agent_dir / dest_filename
|
|
139
|
+
|
|
140
|
+
if dry_run:
|
|
141
|
+
changes.append(f"Would update {agent_root}: {dest_filename}")
|
|
142
|
+
else:
|
|
143
|
+
try:
|
|
144
|
+
dest_path.write_text(
|
|
145
|
+
source_template.read_text(encoding="utf-8"),
|
|
146
|
+
encoding="utf-8",
|
|
147
|
+
)
|
|
148
|
+
updated_count += 1
|
|
149
|
+
except OSError as e:
|
|
150
|
+
warnings.append(f"Failed to update {agent_root}/{dest_filename}: {e}")
|
|
151
|
+
|
|
152
|
+
if updated_count > 0:
|
|
153
|
+
agent_name = agent_root.strip(".")
|
|
154
|
+
changes.append(f"Updated {updated_count} templates for {agent_name}")
|
|
155
|
+
total_updated += updated_count
|
|
156
|
+
|
|
157
|
+
if total_updated > 0:
|
|
158
|
+
changes.append(f"Total: Updated {total_updated} slash command templates across all agents")
|
|
159
|
+
changes.append("Templates now warn agents to scroll to bottom of long output")
|
|
160
|
+
changes.append("Templates emphasize automated file updates (no manual editing)")
|
|
161
|
+
changes.append("Prevents state corruption from incomplete workflows")
|
|
162
|
+
elif not changes:
|
|
163
|
+
warnings.append(
|
|
164
|
+
"No templates were updated (already updated or mission templates missing)"
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
success = len(errors) == 0
|
|
168
|
+
return MigrationResult(
|
|
169
|
+
success=success,
|
|
170
|
+
changes_made=changes,
|
|
171
|
+
errors=errors,
|
|
172
|
+
warnings=warnings,
|
|
173
|
+
)
|