-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstall.py
More file actions
150 lines (123 loc) · 4.44 KB
/
install.py
File metadata and controls
150 lines (123 loc) · 4.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#!/usr/bin/env python3
"""Cross-platform installer for Claude Code Spinner."""
import json
import os
import platform
import shutil
import sys
from datetime import datetime
from pathlib import Path
def find_python():
exe = sys.executable
if exe:
return exe
for name in ("python3", "python", "py"):
if shutil.which(name):
return name
return "python3"
def read_settings(path):
if not path.exists():
return {}
try:
return json.loads(path.read_text(encoding="utf-8"))
except Exception:
return {}
def write_settings(path, settings):
path.write_text(json.dumps(settings, indent=2, ensure_ascii=False), encoding="utf-8")
def remove_existing_spinner_hooks(blocks):
if not blocks or not isinstance(blocks, list):
return []
return [
b for b in blocks
if not (isinstance(b, dict) and any(
isinstance(h, dict) and "claude_code_spinner" in h.get("command", "")
for h in b.get("hooks", [])
))
]
def main():
home = Path(os.environ.get("CLAUDE_SPINNER_HOME", Path.home()))
claude_dir = home / ".claude"
install_dir = claude_dir / "claude-code-spinner"
settings_path = claude_dir / "settings.json"
claude_dir.mkdir(parents=True, exist_ok=True)
install_dir.mkdir(parents=True, exist_ok=True)
src = Path(__file__).parent / "claude_code_spinner.py"
dst = install_dir / "claude_code_spinner.py"
shutil.copy2(src, dst)
commands_dir = claude_dir / "commands"
commands_dir.mkdir(parents=True, exist_ok=True)
cmd_src = Path(__file__).parent / "spinner.md"
cmd_dst = commands_dir / "spinner.md"
if cmd_src.exists():
shutil.copy2(cmd_src, cmd_dst)
if settings_path.exists():
ts = datetime.now().strftime("%Y%m%d-%H%M%S")
shutil.copy2(settings_path, settings_path.with_suffix(f".{ts}.bak"))
settings = read_settings(settings_path)
python = find_python()
script = str(dst)
if not platform.system() == "Windows":
os.chmod(dst, 0o755)
hook_cmd = f'"{python}" "{script}" hook'
# Hooks: overlay daemon lifecycle
if "hooks" not in settings or not isinstance(settings["hooks"], dict):
settings["hooks"] = {}
hook_block = {"hooks": [{"type": "command", "command": hook_cmd}]}
for event in ("SessionStart", "UserPromptSubmit", "Stop", "StopFailure", "SessionEnd"):
existing = settings["hooks"].get(event, [])
if not isinstance(existing, list):
existing = []
settings["hooks"][event] = remove_existing_spinner_hooks(existing) + [hook_block]
# StatusLine: optional, disabled by default
# Only set if user doesn't already have one
sl_cmd = f'"{python}" "{script}" statusline'
if "statusLine" not in settings:
settings["statusLine"] = {
"type": "command",
"command": sl_cmd,
"padding": 1,
"refreshInterval": 1,
}
write_settings(settings_path, settings)
# Default config
config_path = install_dir / "config.json"
if not config_path.exists():
config_path.write_text(json.dumps({
"spinner": "auto",
"theme": "sprite",
"position": "top-right",
"margin_row": 1,
"margin_col": 2,
"max_width_ratio": 0.25,
"max_height_ratio": 0.33,
"color": "1;36",
"idle_clear": True,
"debug": False,
"statusline": {
"enabled": False,
"spinner": "variation_3",
"label": "CRT",
"show_model": True,
"show_git": True,
"show_cost": True,
"show_elapsed": True,
},
}, indent=2), encoding="utf-8")
print(f"\n Installed: {dst}")
print(f" Config: {config_path}")
print(f" Settings: {settings_path}")
if cmd_src.exists():
print(f" Command: {cmd_dst} (/spinner)")
print(f"\n Restart Claude Code to activate.\n")
print(f" Slash commands (after restart):")
print(f" /spinner status")
print(f" /spinner enable")
print(f" /spinner disable")
print(f"\n CLI commands:")
print(f' {python} "{script}" list')
print(f' {python} "{script}" preview variation_1 --duration 8')
print(f' {python} "{script}" preview variation_3')
print()
if __name__ == "__main__":
print("\n Claude Code Spinner - Installer\n")
main()