@softspark/ai-toolkit 2.0.0 → 2.0.2
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.
- package/CHANGELOG.md +14 -0
- package/package.json +1 -1
- package/scripts/migrate.py +54 -28
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,20 @@ Versioning follows [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## v2.0.2 — Clean Legacy Directory Removal (2026-04-12)
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **Migration cleanup** — `~/.ai-toolkit/` is now fully removed after migration instead of leaving an empty directory with a `.migrated` marker
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## v2.0.1 — Migration Hook Path Fix (2026-04-12)
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- **settings.json hook paths** — migration now rewrites ALL hook commands (including plugin hooks with non-toolkit `_source` tags like `memory-pack`, `enterprise-pack`) from `~/.ai-toolkit/hooks/` to `~/.softspark/ai-toolkit/hooks/`
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
10
24
|
## v2.0.0 — SoftSpark Namespace Migration (2026-04-12)
|
|
11
25
|
|
|
12
26
|
### BREAKING CHANGES
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softspark/ai-toolkit",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "Professional-grade AI coding toolkit: 92 skills, 44 agents, multi-platform support (Claude, Cursor, Windsurf, Copilot, Gemini, Cline, Roo Code, Aider, Augment, Google Antigravity), machine-enforced safety constitution, persona presets, skill security auditor, expanded lifecycle hooks, 11 plugin packs, and benchmark tooling.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
package/scripts/migrate.py
CHANGED
|
@@ -21,7 +21,6 @@ import json
|
|
|
21
21
|
import os
|
|
22
22
|
import shutil
|
|
23
23
|
import sys
|
|
24
|
-
from datetime import datetime, timezone
|
|
25
24
|
from pathlib import Path
|
|
26
25
|
|
|
27
26
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
@@ -36,14 +35,16 @@ from paths import (
|
|
|
36
35
|
)
|
|
37
36
|
|
|
38
37
|
|
|
39
|
-
MIGRATED_MARKER = LEGACY_DATA_DIR / ".migrated"
|
|
40
|
-
|
|
41
|
-
|
|
42
38
|
def needs_migration() -> bool:
|
|
43
|
-
"""Check if legacy directory exists and
|
|
39
|
+
"""Check if legacy directory exists and needs migration.
|
|
40
|
+
|
|
41
|
+
Returns True only when ~/.ai-toolkit/ exists AND contains real data
|
|
42
|
+
(not just an empty dir). After migration the directory is removed entirely.
|
|
43
|
+
"""
|
|
44
44
|
if not LEGACY_DATA_DIR.is_dir():
|
|
45
45
|
return False
|
|
46
|
-
|
|
46
|
+
# Empty dir (or only hidden files) — nothing to migrate
|
|
47
|
+
if not any(LEGACY_DATA_DIR.iterdir()):
|
|
47
48
|
return False
|
|
48
49
|
# Don't migrate if AI_TOOLKIT_HOME is set (custom setup)
|
|
49
50
|
if os.environ.get("AI_TOOLKIT_HOME"):
|
|
@@ -77,11 +78,10 @@ def migrate_home_directory(dry_run: bool = False) -> bool:
|
|
|
77
78
|
else:
|
|
78
79
|
# Clean move
|
|
79
80
|
shutil.move(str(LEGACY_DATA_DIR), str(TOOLKIT_DATA_DIR))
|
|
80
|
-
# Recreate legacy dir for marker
|
|
81
|
-
LEGACY_DATA_DIR.mkdir(parents=True, exist_ok=True)
|
|
82
81
|
|
|
83
|
-
#
|
|
84
|
-
|
|
82
|
+
# Remove legacy directory entirely
|
|
83
|
+
if LEGACY_DATA_DIR.exists():
|
|
84
|
+
shutil.rmtree(str(LEGACY_DATA_DIR), ignore_errors=True)
|
|
85
85
|
|
|
86
86
|
print(f" Migrated: {TOOLKIT_DATA_DIR}")
|
|
87
87
|
return True
|
|
@@ -103,21 +103,6 @@ def _merge_directories(src: Path, dst: Path) -> None:
|
|
|
103
103
|
shutil.move(str(item), str(dest_item))
|
|
104
104
|
|
|
105
105
|
|
|
106
|
-
def _write_marker() -> None:
|
|
107
|
-
"""Write .migrated marker pointing to new location."""
|
|
108
|
-
LEGACY_DATA_DIR.mkdir(parents=True, exist_ok=True)
|
|
109
|
-
now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
110
|
-
marker_data = {
|
|
111
|
-
"migrated_to": str(TOOLKIT_DATA_DIR),
|
|
112
|
-
"migrated_at": now,
|
|
113
|
-
"message": "ai-toolkit data has moved to ~/.softspark/ai-toolkit/. "
|
|
114
|
-
"This directory is kept as a marker. Safe to delete.",
|
|
115
|
-
}
|
|
116
|
-
with open(MIGRATED_MARKER, "w", encoding="utf-8") as f:
|
|
117
|
-
json.dump(marker_data, f, indent=2)
|
|
118
|
-
f.write("\n")
|
|
119
|
-
|
|
120
|
-
|
|
121
106
|
def migrate_project_configs(dry_run: bool = False) -> int:
|
|
122
107
|
"""Rename .ai-toolkit.json → .softspark-toolkit.json in registered projects.
|
|
123
108
|
|
|
@@ -163,8 +148,49 @@ def migrate_project_configs(dry_run: bool = False) -> int:
|
|
|
163
148
|
return count
|
|
164
149
|
|
|
165
150
|
|
|
151
|
+
def migrate_settings_json(dry_run: bool = False) -> int:
|
|
152
|
+
"""Rewrite hook commands in ~/.claude/settings.json from old to new path.
|
|
153
|
+
|
|
154
|
+
Replaces ALL occurrences of .ai-toolkit/hooks/ with .softspark/ai-toolkit/hooks/
|
|
155
|
+
in hook command strings, regardless of _source tag. This catches plugin hooks
|
|
156
|
+
(memory-pack, enterprise-pack, etc.) that merge-hooks.py doesn't strip.
|
|
157
|
+
|
|
158
|
+
Returns the number of commands rewritten.
|
|
159
|
+
"""
|
|
160
|
+
settings_path = Path.home() / ".claude" / "settings.json"
|
|
161
|
+
if not settings_path.is_file():
|
|
162
|
+
return 0
|
|
163
|
+
|
|
164
|
+
try:
|
|
165
|
+
with open(settings_path, encoding="utf-8") as f:
|
|
166
|
+
data = json.load(f)
|
|
167
|
+
except (json.JSONDecodeError, OSError):
|
|
168
|
+
return 0
|
|
169
|
+
|
|
170
|
+
hooks = data.get("hooks", {})
|
|
171
|
+
old_prefix = ".ai-toolkit/hooks/"
|
|
172
|
+
new_prefix = ".softspark/ai-toolkit/hooks/"
|
|
173
|
+
count = 0
|
|
174
|
+
|
|
175
|
+
for entries in hooks.values():
|
|
176
|
+
for entry in entries:
|
|
177
|
+
for hook in entry.get("hooks", []):
|
|
178
|
+
cmd = hook.get("command", "")
|
|
179
|
+
if old_prefix in cmd and new_prefix not in cmd:
|
|
180
|
+
hook["command"] = cmd.replace(old_prefix, new_prefix)
|
|
181
|
+
count += 1
|
|
182
|
+
|
|
183
|
+
if count > 0 and not dry_run:
|
|
184
|
+
with open(settings_path, "w", encoding="utf-8") as f:
|
|
185
|
+
json.dump(data, f, indent=4, ensure_ascii=False)
|
|
186
|
+
f.write("\n")
|
|
187
|
+
print(f" Rewritten: {count} hook path(s) in settings.json")
|
|
188
|
+
|
|
189
|
+
return count
|
|
190
|
+
|
|
191
|
+
|
|
166
192
|
def run_full_migration(dry_run: bool = False) -> bool:
|
|
167
|
-
"""Run complete migration: home directory + project configs.
|
|
193
|
+
"""Run complete migration: home directory + project configs + settings.json.
|
|
168
194
|
|
|
169
195
|
Returns True if any migration was performed.
|
|
170
196
|
"""
|
|
@@ -174,6 +200,7 @@ def run_full_migration(dry_run: bool = False) -> bool:
|
|
|
174
200
|
count = migrate_project_configs(dry_run=dry_run)
|
|
175
201
|
if count > 0:
|
|
176
202
|
print(f" Migrated {count} project config(s)")
|
|
203
|
+
migrate_settings_json(dry_run=dry_run)
|
|
177
204
|
|
|
178
205
|
return migrated
|
|
179
206
|
|
|
@@ -189,8 +216,7 @@ def main() -> None:
|
|
|
189
216
|
|
|
190
217
|
if success:
|
|
191
218
|
print()
|
|
192
|
-
print("Migration complete.
|
|
193
|
-
print("migration marker and can be safely deleted.")
|
|
219
|
+
print("Migration complete. ~/.ai-toolkit/ has been removed.")
|
|
194
220
|
elif not dry_run:
|
|
195
221
|
print("Migration skipped.")
|
|
196
222
|
|