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,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
|
+
)
|