lite-kits 0.1.1__py3-none-any.whl → 0.3.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 (63) hide show
  1. lite_kits/__init__.py +56 -4
  2. lite_kits/cli.py +696 -185
  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 +140 -0
  7. lite_kits/core/installer.py +236 -351
  8. lite_kits/core/manifest.py +146 -146
  9. lite_kits/core/validator.py +146 -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.1.dist-info/METADATA +259 -0
  38. lite_kits-0.3.1.dist-info/RECORD +41 -0
  39. {lite_kits-0.1.1.dist-info → lite_kits-0.3.1.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.1.dist-info}/WHEEL +0 -0
  63. {lite_kits-0.1.1.dist-info → lite_kits-0.3.1.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,140 @@
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[str] = None) -> List[str]:
28
+ """
29
+ Auto-detect which AI agents are present.
30
+
31
+ Args:
32
+ preferred: Explicit agent preference (overrides auto-detection)
33
+
34
+ Returns:
35
+ List of agent names sorted by priority
36
+ """
37
+ # If explicit preference, validate and return
38
+ if preferred:
39
+ config = self.manifest.get_agent_config(preferred)
40
+ if not config:
41
+ raise ValueError(f"Unknown agent: {preferred}")
42
+ if not config.get('supported', False):
43
+ raise ValueError(f"Agent not supported: {preferred}")
44
+ return [preferred]
45
+
46
+ # Auto-detect from manifest
47
+ detected = []
48
+ agents = self.manifest.manifest.get('agents', {})
49
+
50
+ for agent_name, config in agents.items():
51
+ if not config.get('supported', False):
52
+ continue
53
+
54
+ marker_dir = self.target_dir / config['marker_dir']
55
+ # Check if marker dir exists OR its parent exists (for nested dirs like .github/prompts)
56
+ # This allows detection even if subdirectory doesn't exist yet (will be created on install)
57
+ parent_dir = marker_dir.parent
58
+ if marker_dir.exists() or (parent_dir != self.target_dir and parent_dir.exists()):
59
+ detected.append({
60
+ 'name': agent_name,
61
+ 'priority': config.get('priority', 999)
62
+ })
63
+
64
+ # Sort by priority (lower = higher)
65
+ detected.sort(key=lambda x: x['priority'])
66
+ return [agent['name'] for agent in detected]
67
+
68
+ def detect_shells(self, preferred: Optional[str] = None) -> List[str]:
69
+ """
70
+ Determine which shells to install for.
71
+
72
+ Args:
73
+ preferred: Explicit shell preference (overrides auto-detection)
74
+
75
+ Returns:
76
+ List of shell names
77
+ """
78
+ # If explicit preference, validate and return
79
+ if preferred:
80
+ config = self.manifest.manifest.get('shells', {}).get(preferred)
81
+ if not config:
82
+ raise ValueError(f"Unknown shell: {preferred}")
83
+ if not config.get('supported', False):
84
+ raise ValueError(f"Shell not supported: {preferred}")
85
+ return [preferred]
86
+
87
+ # Check if shell detection is enabled
88
+ options = self.manifest.manifest.get('options', {})
89
+ if not options.get('auto_detect_shells', True):
90
+ return []
91
+
92
+ # Get all supported shells
93
+ shells_config = self.manifest.manifest.get('shells', {})
94
+ detected = []
95
+
96
+ for shell_name, config in shells_config.items():
97
+ if not config.get('supported', False):
98
+ continue
99
+
100
+ detected.append({
101
+ 'name': shell_name,
102
+ 'priority': config.get('priority', 999)
103
+ })
104
+
105
+ # Sort by priority
106
+ detected.sort(key=lambda x: x['priority'])
107
+
108
+ # Return all or just primary based on options
109
+ if options.get('prefer_all_shells', False):
110
+ return [shell['name'] for shell in detected]
111
+
112
+ return [detected[0]['name']] if detected else []
113
+
114
+ def is_spec_kit_project(self) -> bool:
115
+ """
116
+ Check if target is a spec-kit project.
117
+
118
+ Returns:
119
+ True if spec-kit markers found
120
+ """
121
+ spec_config = self.manifest.manifest.get('spec_kit', {})
122
+ markers = spec_config.get('markers', [])
123
+ require_any = spec_config.get('require_any', True)
124
+
125
+ found = []
126
+ for marker in markers:
127
+ path = self.target_dir / marker['path']
128
+
129
+ if marker.get('type') == 'directory':
130
+ if path.is_dir():
131
+ found.append(marker['path'])
132
+ else:
133
+ if path.exists():
134
+ found.append(marker['path'])
135
+
136
+ # Check requirement
137
+ if require_any:
138
+ return len(found) > 0
139
+
140
+ return len(found) == len(markers)