lite-kits 0.1.1__py3-none-any.whl → 0.3.2__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 (63) hide show
  1. lite_kits/__init__.py +56 -4
  2. lite_kits/cli.py +782 -189
  3. lite_kits/core/__init__.py +6 -0
  4. lite_kits/core/banner.py +1 -1
  5. lite_kits/core/conflict_checker.py +115 -0
  6. lite_kits/core/detector.py +177 -0
  7. lite_kits/core/installer.py +242 -351
  8. lite_kits/core/manifest.py +146 -146
  9. lite_kits/core/validator.py +183 -0
  10. lite_kits/kits/README.md +6 -6
  11. lite_kits/kits/dev/README.md +241 -241
  12. lite_kits/kits/dev/{claude/commands → commands/.claude}/audit.md +143 -143
  13. lite_kits/kits/dev/{claude/commands → commands/.claude}/cleanup.md +2 -2
  14. lite_kits/kits/{git/claude/commands → dev/commands/.claude}/commit.md +2 -2
  15. lite_kits/kits/{project/claude/commands → dev/commands/.claude}/orient.md +3 -4
  16. lite_kits/kits/{git/claude/commands → dev/commands/.claude}/pr.md +1 -1
  17. lite_kits/kits/{git/claude/commands → dev/commands/.claude}/review.md +202 -202
  18. lite_kits/kits/{project/claude/commands → dev/commands/.claude}/stats.md +162 -162
  19. lite_kits/kits/{project/github/prompts → dev/commands/.github}/audit.prompt.md +143 -143
  20. lite_kits/kits/{git/github/prompts → dev/commands/.github}/cleanup.prompt.md +2 -2
  21. lite_kits/kits/{git/github/prompts → dev/commands/.github}/commit.prompt.md +2 -2
  22. lite_kits/kits/dev/{github/prompts → commands/.github}/orient.prompt.md +3 -4
  23. lite_kits/kits/{git/github/prompts → dev/commands/.github}/pr.prompt.md +1 -1
  24. lite_kits/kits/{git/github/prompts → dev/commands/.github}/review.prompt.md +202 -202
  25. lite_kits/kits/dev/{github/prompts → commands/.github}/stats.prompt.md +163 -163
  26. lite_kits/kits/kits.yaml +497 -180
  27. lite_kits/kits/multiagent/README.md +6 -6
  28. lite_kits/kits/multiagent/{claude/commands → commands/.claude}/sync.md +331 -331
  29. lite_kits/kits/multiagent/{github/prompts → commands/.github}/sync.prompt.md +73 -69
  30. lite_kits/kits/multiagent/memory/git-worktrees-protocol.md +370 -370
  31. lite_kits/kits/multiagent/memory/parallel-work-protocol.md +536 -536
  32. lite_kits/kits/multiagent/memory/pr-workflow-guide.md +275 -275
  33. lite_kits/kits/multiagent/templates/collaboration-structure/README.md +166 -166
  34. lite_kits/kits/multiagent/templates/decision.md +79 -79
  35. lite_kits/kits/multiagent/templates/handoff.md +95 -95
  36. lite_kits/kits/multiagent/templates/session-log.md +68 -68
  37. lite_kits-0.3.2.dist-info/METADATA +259 -0
  38. lite_kits-0.3.2.dist-info/RECORD +41 -0
  39. {lite_kits-0.1.1.dist-info → lite_kits-0.3.2.dist-info}/licenses/LICENSE +21 -21
  40. lite_kits/kits/dev/claude/commands/commit.md +0 -612
  41. lite_kits/kits/dev/claude/commands/orient.md +0 -146
  42. lite_kits/kits/dev/claude/commands/pr.md +0 -593
  43. lite_kits/kits/dev/claude/commands/review.md +0 -202
  44. lite_kits/kits/dev/claude/commands/stats.md +0 -162
  45. lite_kits/kits/dev/github/prompts/audit.prompt.md +0 -143
  46. lite_kits/kits/dev/github/prompts/cleanup.prompt.md +0 -382
  47. lite_kits/kits/dev/github/prompts/commit.prompt.md +0 -591
  48. lite_kits/kits/dev/github/prompts/pr.prompt.md +0 -603
  49. lite_kits/kits/dev/github/prompts/review.prompt.md +0 -202
  50. lite_kits/kits/git/README.md +0 -365
  51. lite_kits/kits/git/claude/commands/cleanup.md +0 -361
  52. lite_kits/kits/git/scripts/bash/get-git-context.sh +0 -208
  53. lite_kits/kits/git/scripts/powershell/Get-GitContext.ps1 +0 -242
  54. lite_kits/kits/project/README.md +0 -228
  55. lite_kits/kits/project/claude/commands/audit.md +0 -143
  56. lite_kits/kits/project/claude/commands/review.md +0 -112
  57. lite_kits/kits/project/github/prompts/orient.prompt.md +0 -150
  58. lite_kits/kits/project/github/prompts/review.prompt.md +0 -112
  59. lite_kits/kits/project/github/prompts/stats.prompt.md +0 -163
  60. lite_kits-0.1.1.dist-info/METADATA +0 -447
  61. lite_kits-0.1.1.dist-info/RECORD +0 -58
  62. {lite_kits-0.1.1.dist-info → lite_kits-0.3.2.dist-info}/WHEEL +0 -0
  63. {lite_kits-0.1.1.dist-info → lite_kits-0.3.2.dist-info}/entry_points.txt +0 -0
@@ -1,13 +1,19 @@
1
1
  """Core modules for lite-kits."""
2
2
 
3
3
  from .banner import diagonal_reveal_banner, show_loading_spinner, show_static_banner
4
+ from .conflict_checker import ConflictChecker
5
+ from .detector import Detector
4
6
  from .installer import Installer
5
7
  from .manifest import KitManifest
8
+ from .validator import Validator
6
9
 
7
10
  __all__ = [
8
11
  "diagonal_reveal_banner",
9
12
  "show_loading_spinner",
10
13
  "show_static_banner",
14
+ "ConflictChecker",
15
+ "Detector",
11
16
  "Installer",
12
17
  "KitManifest",
18
+ "Validator",
13
19
  ]
lite_kits/core/banner.py CHANGED
@@ -145,7 +145,7 @@ def show_static_banner():
145
145
  def show_loading_spinner(message="Loading kits..."):
146
146
  with console.status(f"[bold bright_cyan]{message}", spinner="dots"):
147
147
  time.sleep(1.5)
148
- console.print("[green] Done![/green]")
148
+ console.print("[green][OK] Done![/green]")
149
149
 
150
150
  if __name__ == "__main__":
151
151
  console.clear()
@@ -0,0 +1,115 @@
1
+ """
2
+ File conflict detection for installer.
3
+
4
+ Checks for existing files that would be overwritten.
5
+ """
6
+
7
+ from pathlib import Path
8
+ from typing import Dict, List
9
+
10
+ from .manifest import KitManifest
11
+
12
+
13
+ class ConflictChecker:
14
+ """Detects file conflicts before installation."""
15
+
16
+ def __init__(self, target_dir: Path, kits_dir: Path, manifest: KitManifest):
17
+ """
18
+ Initialize conflict checker.
19
+
20
+ Args:
21
+ target_dir: Target project directory
22
+ kits_dir: Kits source directory
23
+ manifest: Loaded kit manifest
24
+ """
25
+ self.target_dir = target_dir
26
+ self.kits_dir = kits_dir
27
+ self.manifest = manifest
28
+
29
+ def check_conflicts(
30
+ self,
31
+ kits: List[str],
32
+ agents: List[str],
33
+ shells: List[str]
34
+ ) -> Dict:
35
+ """
36
+ Check for file conflicts.
37
+
38
+ Args:
39
+ kits: List of kit names to check
40
+ agents: List of agent names
41
+ shells: List of shell names
42
+
43
+ Returns:
44
+ Dict with conflict details
45
+ """
46
+ result = {
47
+ 'conflicts': [],
48
+ 'overwrites': [],
49
+ 'safe': [],
50
+ 'has_conflicts': False
51
+ }
52
+
53
+ for kit_name in kits:
54
+ # Check agent files
55
+ for agent in agents:
56
+ self._check_file_group(kit_name, agent, result)
57
+
58
+ # Check shell files
59
+ for shell in shells:
60
+ self._check_file_group(kit_name, shell, result)
61
+
62
+ # Check agent-agnostic files
63
+ all_files = self.manifest.get_kit_files(kit_name, agent=None)
64
+ for file_info in all_files:
65
+ # Skip agent/shell-specific
66
+ if file_info.get('type') in ['command', 'prompt', 'script']:
67
+ continue
68
+
69
+ self._check_file(file_info, result)
70
+
71
+ result['has_conflicts'] = len(result['conflicts']) > 0
72
+ return result
73
+
74
+ def _check_file_group(self, kit_name: str, agent_or_shell: str, result: Dict):
75
+ """Check a group of files for an agent/shell."""
76
+ files = self.manifest.get_kit_files(kit_name, agent=agent_or_shell)
77
+
78
+ for file_info in files:
79
+ if file_info.get('status') == 'planned':
80
+ continue
81
+
82
+ self._check_file(file_info, result)
83
+
84
+ def _check_file(self, file_info: Dict, result: Dict):
85
+ """Check a single file for conflicts."""
86
+ target_path = self.target_dir / file_info['path']
87
+
88
+ if not target_path.exists():
89
+ if file_info['path'] not in result['safe']:
90
+ result['safe'].append(file_info['path'])
91
+ return
92
+
93
+ # File exists, check if content differs
94
+ source_path = self.kits_dir / file_info['source']
95
+
96
+ if not source_path.exists():
97
+ return
98
+
99
+ try:
100
+ source_content = source_path.read_text(encoding='utf-8')
101
+ target_content = target_path.read_text(encoding='utf-8')
102
+
103
+ if source_content != target_content:
104
+ if file_info['path'] not in result['conflicts']:
105
+ result['conflicts'].append(file_info['path'])
106
+ result['overwrites'].append({
107
+ 'path': file_info['path'],
108
+ 'source': file_info['source'],
109
+ 'size_current': target_path.stat().st_size,
110
+ 'size_new': source_path.stat().st_size,
111
+ })
112
+ except Exception:
113
+ # If can't read/compare, treat as conflict
114
+ if file_info['path'] not in result['conflicts']:
115
+ result['conflicts'].append(file_info['path'])
@@ -0,0 +1,177 @@
1
+ """
2
+ Agent and shell detection for lite-kits installer.
3
+
4
+ Detects which AI agents and shell environments are present in a project.
5
+ """
6
+
7
+ from pathlib import Path
8
+ from typing import List, Optional
9
+
10
+ from .manifest import KitManifest
11
+
12
+
13
+ class Detector:
14
+ """Detects agents and shells in target project."""
15
+
16
+ def __init__(self, target_dir: Path, manifest: KitManifest):
17
+ """
18
+ Initialize detector.
19
+
20
+ Args:
21
+ target_dir: Target project directory
22
+ manifest: Loaded kit manifest
23
+ """
24
+ self.target_dir = target_dir
25
+ self.manifest = manifest
26
+
27
+ def detect_agents(self, preferred: Optional[List[str]] = None) -> List[str]:
28
+ """
29
+ Auto-detect which AI agents are present.
30
+
31
+ Args:
32
+ preferred: List of explicit agent preferences (overrides auto-detection)
33
+
34
+ Returns:
35
+ List of agent names sorted by priority
36
+ """
37
+ # If explicit preferences, validate and return
38
+ if preferred:
39
+ validated = []
40
+ for agent_name in preferred:
41
+ config = self.manifest.get_agent_config(agent_name)
42
+ if not config:
43
+ # Build helpful error message with valid options
44
+ agents = self.manifest.manifest.get('agents', {})
45
+ valid_agents = [
46
+ name for name, cfg in agents.items()
47
+ if cfg.get('supported', False)
48
+ ]
49
+ valid_list = ', '.join(valid_agents)
50
+ raise ValueError(
51
+ f"Unknown agent: '{agent_name}'\n"
52
+ f"Valid options: {valid_list}"
53
+ )
54
+ if not config.get('supported', False):
55
+ raise ValueError(f"Agent not supported: {agent_name}")
56
+ validated.append(agent_name)
57
+ return validated
58
+
59
+ # Auto-detect from manifest
60
+ detected = []
61
+ agents = self.manifest.manifest.get('agents', {})
62
+
63
+ for agent_name, config in agents.items():
64
+ if not config.get('supported', False):
65
+ continue
66
+
67
+ marker_dir = self.target_dir / config['marker_dir']
68
+ # Check if marker dir exists OR its parent exists (for nested dirs like .github/prompts)
69
+ # This allows detection even if subdirectory doesn't exist yet (will be created on install)
70
+ parent_dir = marker_dir.parent
71
+ if marker_dir.exists() or (parent_dir != self.target_dir and parent_dir.exists()):
72
+ detected.append({
73
+ 'name': agent_name,
74
+ 'priority': config.get('priority', 999)
75
+ })
76
+
77
+ # Sort by priority (lower = higher)
78
+ detected.sort(key=lambda x: x['priority'])
79
+ return [agent['name'] for agent in detected]
80
+
81
+ def detect_shells(self, preferred: Optional[List[str]] = None) -> List[str]:
82
+ """
83
+ Determine which shells to install for.
84
+
85
+ Args:
86
+ preferred: List of explicit shell preferences (overrides auto-detection)
87
+
88
+ Returns:
89
+ List of shell names
90
+ """
91
+ # Shell aliases for common shorthands
92
+ shell_aliases = {
93
+ 'ps': 'powershell',
94
+ 'pwsh': 'powershell',
95
+ 'sh': 'bash',
96
+ }
97
+
98
+ # If explicit preferences, validate and return
99
+ if preferred:
100
+ validated = []
101
+ for shell_name in preferred:
102
+ # Normalize shell name using aliases
103
+ normalized = shell_aliases.get(shell_name.lower(), shell_name.lower())
104
+
105
+ config = self.manifest.manifest.get('shells', {}).get(normalized)
106
+ if not config:
107
+ # Build helpful error message with valid options
108
+ shells_config = self.manifest.manifest.get('shells', {})
109
+ valid_shells = [
110
+ name for name, cfg in shells_config.items()
111
+ if cfg.get('supported', False)
112
+ ]
113
+ valid_list = ', '.join(valid_shells)
114
+ raise ValueError(
115
+ f"Unknown shell: '{shell_name}'\n"
116
+ f"Valid options: {valid_list}\n"
117
+ f"Aliases: ps/pwsh->powershell, sh->bash"
118
+ )
119
+ if not config.get('supported', False):
120
+ raise ValueError(f"Shell not supported: {normalized}")
121
+ validated.append(normalized)
122
+ return validated
123
+
124
+ # Check if shell detection is enabled
125
+ options = self.manifest.manifest.get('options', {})
126
+ if not options.get('auto_detect_shells', True):
127
+ return []
128
+
129
+ # Get all supported shells
130
+ shells_config = self.manifest.manifest.get('shells', {})
131
+ detected = []
132
+
133
+ for shell_name, config in shells_config.items():
134
+ if not config.get('supported', False):
135
+ continue
136
+
137
+ detected.append({
138
+ 'name': shell_name,
139
+ 'priority': config.get('priority', 999)
140
+ })
141
+
142
+ # Sort by priority
143
+ detected.sort(key=lambda x: x['priority'])
144
+
145
+ # Return all or just primary based on options
146
+ if options.get('prefer_all_shells', False):
147
+ return [shell['name'] for shell in detected]
148
+
149
+ return [detected[0]['name']] if detected else []
150
+
151
+ def is_spec_kit_project(self) -> bool:
152
+ """
153
+ Check if target is a spec-kit project.
154
+
155
+ Returns:
156
+ True if spec-kit markers found
157
+ """
158
+ spec_config = self.manifest.manifest.get('spec_kit', {})
159
+ markers = spec_config.get('markers', [])
160
+ require_any = spec_config.get('require_any', True)
161
+
162
+ found = []
163
+ for marker in markers:
164
+ path = self.target_dir / marker['path']
165
+
166
+ if marker.get('type') == 'directory':
167
+ if path.is_dir():
168
+ found.append(marker['path'])
169
+ else:
170
+ if path.exists():
171
+ found.append(marker['path'])
172
+
173
+ # Check requirement
174
+ if require_any:
175
+ return len(found) > 0
176
+
177
+ return len(found) == len(markers)