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,285 @@
1
+ """
2
+ VCS Protocol Module
3
+ ===================
4
+
5
+ This module defines the VCSProtocol interface that GitVCS and JujutsuVCS implement.
6
+ The protocol uses Python's typing.Protocol for structural subtyping.
7
+
8
+ See kitty-specs/015-first-class-jujutsu-vcs-integration/contracts/vcs-protocol.py
9
+ for the complete interface contract.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from pathlib import Path
15
+ from typing import Protocol, runtime_checkable
16
+
17
+ from .types import (
18
+ ChangeInfo,
19
+ ConflictInfo,
20
+ SyncResult,
21
+ VCSBackend,
22
+ VCSCapabilities,
23
+ WorkspaceCreateResult,
24
+ WorkspaceInfo,
25
+ )
26
+
27
+
28
+ @runtime_checkable
29
+ class VCSProtocol(Protocol):
30
+ """
31
+ Interface contract for VCS backends.
32
+
33
+ Both GitVCS and JujutsuVCS must implement this protocol.
34
+ Operations not supported by a backend should raise VCSCapabilityError.
35
+
36
+ This protocol is runtime-checkable, so you can use:
37
+ isinstance(obj, VCSProtocol)
38
+ to verify an object implements the interface.
39
+ """
40
+
41
+ @property
42
+ def backend(self) -> VCSBackend:
43
+ """Return which backend this is (GIT or JUJUTSU)."""
44
+ ...
45
+
46
+ @property
47
+ def capabilities(self) -> VCSCapabilities:
48
+ """Return capabilities of this backend."""
49
+ ...
50
+
51
+ # =========================================================================
52
+ # Workspace Operations (Core - Required)
53
+ # =========================================================================
54
+
55
+ def create_workspace(
56
+ self,
57
+ workspace_path: Path,
58
+ workspace_name: str,
59
+ base_branch: str | None = None,
60
+ base_commit: str | None = None,
61
+ ) -> WorkspaceCreateResult:
62
+ """
63
+ Create a new workspace for a work package.
64
+
65
+ Args:
66
+ workspace_path: Where to create the workspace
67
+ workspace_name: Name for the workspace (e.g., "015-feature-WP01")
68
+ base_branch: Branch to base on (for --base flag)
69
+ base_commit: Specific commit to base on (alternative to branch)
70
+
71
+ Returns:
72
+ WorkspaceCreateResult with workspace info or error
73
+
74
+ Implementation notes:
75
+ - Git: Uses `git worktree add`
76
+ - jj: Uses `jj workspace add`
77
+ """
78
+ ...
79
+
80
+ def remove_workspace(self, workspace_path: Path) -> bool:
81
+ """
82
+ Remove a workspace and clean up.
83
+
84
+ Args:
85
+ workspace_path: Path to the workspace to remove
86
+
87
+ Returns:
88
+ True if successful, False otherwise
89
+
90
+ Implementation notes:
91
+ - Git: Uses `git worktree remove`
92
+ - jj: Uses `jj workspace forget` + directory removal
93
+ """
94
+ ...
95
+
96
+ def get_workspace_info(self, workspace_path: Path) -> WorkspaceInfo | None:
97
+ """
98
+ Get information about a workspace.
99
+
100
+ Args:
101
+ workspace_path: Path to the workspace
102
+
103
+ Returns:
104
+ WorkspaceInfo or None if not a valid workspace
105
+ """
106
+ ...
107
+
108
+ def list_workspaces(self, repo_root: Path) -> list[WorkspaceInfo]:
109
+ """
110
+ List all workspaces for a repository.
111
+
112
+ Args:
113
+ repo_root: Root of the repository
114
+
115
+ Returns:
116
+ List of WorkspaceInfo for all workspaces
117
+ """
118
+ ...
119
+
120
+ # =========================================================================
121
+ # Synchronization Operations (Core - Required)
122
+ # =========================================================================
123
+
124
+ def sync_workspace(self, workspace_path: Path) -> SyncResult:
125
+ """
126
+ Synchronize workspace with upstream changes.
127
+
128
+ This is the key operation that differs between backends:
129
+ - Git: Fetch + rebase, conflicts block the operation
130
+ - jj: update-stale, conflicts are stored (non-blocking)
131
+
132
+ Args:
133
+ workspace_path: Path to the workspace to sync
134
+
135
+ Returns:
136
+ SyncResult with status, conflicts, and changes integrated
137
+ """
138
+ ...
139
+
140
+ def is_workspace_stale(self, workspace_path: Path) -> bool:
141
+ """
142
+ Check if workspace needs sync (base has changed).
143
+
144
+ Args:
145
+ workspace_path: Path to the workspace
146
+
147
+ Returns:
148
+ True if sync is needed, False if up-to-date
149
+ """
150
+ ...
151
+
152
+ # =========================================================================
153
+ # Conflict Operations (Core - Required)
154
+ # =========================================================================
155
+
156
+ def detect_conflicts(self, workspace_path: Path) -> list[ConflictInfo]:
157
+ """
158
+ Detect conflicts in a workspace.
159
+
160
+ Args:
161
+ workspace_path: Path to the workspace
162
+
163
+ Returns:
164
+ List of ConflictInfo for all conflicted files
165
+
166
+ Implementation notes:
167
+ - Git: Parse conflict markers in working tree
168
+ - jj: Query jj status for conflict state
169
+ """
170
+ ...
171
+
172
+ def has_conflicts(self, workspace_path: Path) -> bool:
173
+ """
174
+ Check if workspace has any unresolved conflicts.
175
+
176
+ Args:
177
+ workspace_path: Path to the workspace
178
+
179
+ Returns:
180
+ True if conflicts exist, False otherwise
181
+ """
182
+ ...
183
+
184
+ # =========================================================================
185
+ # Commit/Change Operations (Core - Required)
186
+ # =========================================================================
187
+
188
+ def get_current_change(self, workspace_path: Path) -> ChangeInfo | None:
189
+ """
190
+ Get info about current working copy commit/change.
191
+
192
+ Args:
193
+ workspace_path: Path to the workspace
194
+
195
+ Returns:
196
+ ChangeInfo for current HEAD/working copy, None if invalid
197
+ """
198
+ ...
199
+
200
+ def get_changes(
201
+ self,
202
+ repo_path: Path,
203
+ revision_range: str | None = None,
204
+ limit: int | None = None,
205
+ ) -> list[ChangeInfo]:
206
+ """
207
+ Get list of changes/commits.
208
+
209
+ Args:
210
+ repo_path: Repository path
211
+ revision_range: Git revision range or jj revset
212
+ limit: Maximum number to return
213
+
214
+ Returns:
215
+ List of ChangeInfo
216
+ """
217
+ ...
218
+
219
+ def commit(
220
+ self,
221
+ workspace_path: Path,
222
+ message: str,
223
+ paths: list[Path] | None = None,
224
+ ) -> ChangeInfo | None:
225
+ """
226
+ Create a commit with current changes.
227
+
228
+ Args:
229
+ workspace_path: Workspace to commit in
230
+ message: Commit message
231
+ paths: Specific paths to commit (None = all)
232
+
233
+ Returns:
234
+ ChangeInfo for new commit, None if nothing to commit
235
+
236
+ Implementation notes:
237
+ - Git: git add + git commit
238
+ - jj: jj describe (working copy already committed)
239
+ """
240
+ ...
241
+
242
+ # =========================================================================
243
+ # Repository Operations (Core - Required)
244
+ # =========================================================================
245
+
246
+ def init_repo(
247
+ self,
248
+ path: Path,
249
+ colocate: bool = True,
250
+ ) -> bool:
251
+ """
252
+ Initialize a new repository.
253
+
254
+ Args:
255
+ path: Where to initialize
256
+ colocate: If jj, whether to colocate with git
257
+
258
+ Returns:
259
+ True if successful, False otherwise
260
+ """
261
+ ...
262
+
263
+ def is_repo(self, path: Path) -> bool:
264
+ """
265
+ Check if path is inside a repository of this backend type.
266
+
267
+ Args:
268
+ path: Path to check
269
+
270
+ Returns:
271
+ True if valid repository of this backend type
272
+ """
273
+ ...
274
+
275
+ def get_repo_root(self, path: Path) -> Path | None:
276
+ """
277
+ Get root directory of repository containing path.
278
+
279
+ Args:
280
+ path: Path within the repository
281
+
282
+ Returns:
283
+ Repository root or None if not in a repo
284
+ """
285
+ ...
@@ -0,0 +1,249 @@
1
+ """
2
+ VCS Types Module
3
+ ================
4
+
5
+ This module defines all enums and dataclasses for VCS operations.
6
+ These types are backend-agnostic and used by both GitVCS and JujutsuVCS.
7
+
8
+ See kitty-specs/015-first-class-jujutsu-vcs-integration/data-model.md for full documentation.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from dataclasses import dataclass
14
+ from datetime import datetime
15
+ from enum import Enum
16
+ from pathlib import Path
17
+ from typing import Literal
18
+
19
+
20
+ # =============================================================================
21
+ # Enums
22
+ # =============================================================================
23
+
24
+
25
+ class VCSBackend(str, Enum):
26
+ """Supported VCS backends."""
27
+
28
+ GIT = "git"
29
+ JUJUTSU = "jj"
30
+
31
+
32
+ class SyncStatus(str, Enum):
33
+ """Result status of a sync operation."""
34
+
35
+ UP_TO_DATE = "up_to_date"
36
+ SYNCED = "synced"
37
+ CONFLICTS = "conflicts"
38
+ FAILED = "failed"
39
+
40
+
41
+ class ConflictType(str, Enum):
42
+ """Types of file conflicts."""
43
+
44
+ CONTENT = "content" # Both sides modified same lines
45
+ MODIFY_DELETE = "modify_delete" # One side modified, other deleted
46
+ ADD_ADD = "add_add" # Both sides added same file differently
47
+ RENAME_RENAME = "rename_rename" # Both sides renamed differently
48
+ RENAME_DELETE = "rename_delete" # One renamed, other deleted
49
+
50
+
51
+ # =============================================================================
52
+ # Dataclasses
53
+ # =============================================================================
54
+
55
+
56
+ @dataclass(frozen=True)
57
+ class VCSCapabilities:
58
+ """
59
+ Describes what a VCS backend can do.
60
+
61
+ Used for feature detection and capability checking before operations.
62
+ """
63
+
64
+ supports_auto_rebase: bool # jj: True, git: False
65
+ supports_conflict_storage: bool # jj: True, git: False (conflicts block)
66
+ supports_operation_log: bool # jj: True, git: partial (reflog)
67
+ supports_change_ids: bool # jj: True, git: False
68
+ supports_workspaces: bool # jj: True (native), git: True (worktrees)
69
+ supports_colocated: bool # jj: True, git: N/A
70
+ supports_operation_undo: bool # jj: True, git: False
71
+
72
+
73
+ @dataclass
74
+ class ChangeInfo:
75
+ """
76
+ Represents a single commit/change with metadata for automation.
77
+
78
+ For jj, change_id is stable across rebases. For git, change_id is None.
79
+ """
80
+
81
+ # Identity
82
+ change_id: str | None # jj Change ID (stable across rebases), None for git
83
+ commit_id: str # Git SHA or jj commit ID
84
+
85
+ # Metadata
86
+ message: str # First line of commit message
87
+ message_full: str # Full commit message
88
+ author: str # Author name
89
+ author_email: str # Author email
90
+ timestamp: datetime # Commit timestamp (UTC)
91
+
92
+ # Relationships
93
+ parents: list[str] # Parent commit IDs
94
+ is_merge: bool # True if multiple parents
95
+
96
+ # State
97
+ is_conflicted: bool # True if this commit has stored conflicts (jj)
98
+ is_empty: bool # True if no file changes
99
+
100
+
101
+ @dataclass
102
+ class ConflictInfo:
103
+ """
104
+ Represents a conflict in a file.
105
+
106
+ In git, conflicts block operations and must be resolved immediately.
107
+ In jj, conflicts are stored in the commit and can be resolved later.
108
+ """
109
+
110
+ file_path: Path # Relative path from workspace root
111
+ conflict_type: ConflictType # Type of conflict
112
+ line_ranges: list[tuple[int, int]] | None # Start/end lines, None if whole-file
113
+ sides: int # Number of sides (2 for normal, 3+ for octopus in jj)
114
+ is_resolved: bool # True if conflict markers removed
115
+
116
+ # Content (for automation)
117
+ our_content: str | None # "Ours" side content (abbreviated)
118
+ their_content: str | None # "Theirs" side content (abbreviated)
119
+ base_content: str | None # Common ancestor content (if available)
120
+
121
+
122
+ @dataclass
123
+ class SyncResult:
124
+ """
125
+ Result of synchronizing a workspace with upstream changes.
126
+
127
+ The status field indicates the outcome:
128
+ - UP_TO_DATE: No sync needed
129
+ - SYNCED: Successfully updated, no conflicts
130
+ - CONFLICTS: Updated but has conflicts to resolve
131
+ - FAILED: Sync failed (network, permissions, etc.)
132
+ """
133
+
134
+ status: SyncStatus
135
+ conflicts: list[ConflictInfo]
136
+ files_updated: int # Number of files changed
137
+ files_added: int # Number of new files
138
+ files_deleted: int # Number of removed files
139
+ changes_integrated: list[ChangeInfo] # Commits pulled in during sync
140
+ message: str # Human-readable summary message
141
+
142
+
143
+ @dataclass
144
+ class WorkspaceInfo:
145
+ """
146
+ Represents a VCS workspace (git worktree or jj workspace).
147
+
148
+ A workspace is an isolated working directory for a work package.
149
+ """
150
+
151
+ # Identity
152
+ name: str # Workspace name (e.g., "015-feature-WP01")
153
+ path: Path # Absolute path to workspace directory
154
+
155
+ # State
156
+ backend: VCSBackend # Which VCS backend
157
+ is_colocated: bool # True if both .jj/ and .git/ present
158
+
159
+ # Branch/Change tracking
160
+ current_branch: str | None # Git branch name, None for detached/jj
161
+ current_change_id: str | None # jj Change ID of working copy
162
+ current_commit_id: str # Current HEAD commit
163
+
164
+ # Relationship to base
165
+ base_branch: str | None # Branch this was created from (--base flag)
166
+ base_commit_id: str | None # Commit this was branched from
167
+
168
+ # Health
169
+ is_stale: bool # True if base has changed (needs sync)
170
+ has_conflicts: bool # True if workspace has unresolved conflicts
171
+ has_uncommitted: bool # True if working copy has changes (git only)
172
+
173
+
174
+ @dataclass
175
+ class OperationInfo:
176
+ """
177
+ Entry in the operation log (primarily jj, approximated for git).
178
+
179
+ jj has full operation log with complete undo capability.
180
+ git approximates via reflog but with limited undo.
181
+ """
182
+
183
+ operation_id: str # jj operation ID or git reflog index
184
+ timestamp: datetime # When operation occurred
185
+ description: str # What the operation did
186
+ heads: list[str] # Commit IDs of all heads after operation
187
+ working_copy_commit: str # Working copy commit after operation
188
+ is_undoable: bool # Can this operation be undone?
189
+ parent_operation: str | None # Previous operation ID
190
+
191
+
192
+ @dataclass
193
+ class WorkspaceCreateResult:
194
+ """Result of creating a workspace."""
195
+
196
+ success: bool
197
+ workspace: WorkspaceInfo | None
198
+ error: str | None
199
+
200
+
201
+ @dataclass
202
+ class ProjectVCSConfig:
203
+ """
204
+ Project-level VCS configuration stored in .kittify/config.yaml.
205
+
206
+ Controls default VCS selection and backend-specific settings.
207
+ """
208
+
209
+ preferred: Literal["auto", "jj", "git"] = "auto"
210
+ jj_min_version: str = "0.20.0"
211
+ jj_colocate: bool = True
212
+
213
+
214
+ @dataclass
215
+ class FeatureVCSConfig:
216
+ """
217
+ Per-feature VCS selection stored in feature's meta.json.
218
+
219
+ Once set, vcs cannot be changed (locked at feature creation).
220
+ """
221
+
222
+ vcs: VCSBackend
223
+ vcs_locked_at: datetime # When VCS choice was locked
224
+
225
+
226
+ # =============================================================================
227
+ # Capability Constants
228
+ # =============================================================================
229
+
230
+
231
+ GIT_CAPABILITIES = VCSCapabilities(
232
+ supports_auto_rebase=False,
233
+ supports_conflict_storage=False,
234
+ supports_operation_log=True, # via reflog, limited
235
+ supports_change_ids=False,
236
+ supports_workspaces=True,
237
+ supports_colocated=False,
238
+ supports_operation_undo=False,
239
+ )
240
+
241
+ JJ_CAPABILITIES = VCSCapabilities(
242
+ supports_auto_rebase=True,
243
+ supports_conflict_storage=True,
244
+ supports_operation_log=True,
245
+ supports_change_ids=True,
246
+ supports_workspaces=True,
247
+ supports_colocated=True,
248
+ supports_operation_undo=True,
249
+ )