@softspark/ai-toolkit 1.9.0 → 2.0.0
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 +33 -14
- package/README.md +18 -18
- package/app/ARCHITECTURE.md +3 -3
- package/app/hooks/governance-capture.sh +1 -1
- package/app/hooks/pre-compact-save.sh +1 -1
- package/app/hooks/session-context.sh +1 -1
- package/app/hooks/track-usage.sh +2 -2
- package/app/hooks.json +20 -20
- package/app/plugins/memory-pack/README.md +1 -1
- package/app/plugins/memory-pack/hooks/observation-capture.sh +2 -2
- package/app/plugins/memory-pack/hooks/session-summary.sh +1 -1
- package/app/plugins/memory-pack/scripts/init_db.py +2 -2
- package/app/plugins/memory-pack/skills/mem-search/SKILL.md +3 -3
- package/app/skills/hook-creator/SKILL.md +2 -2
- package/app/skills/mem-search/SKILL.md +3 -3
- package/app/skills/repeat/SKILL.md +1 -1
- package/bin/ai-toolkit.js +9 -4
- package/kb/history/completed/enterprise-config-inheritance-plan-20260412.md +32 -34
- package/kb/history/completed/offline-slm-profile-plan-20260411.md +12 -12
- package/kb/planning/cloud-security-pack-plan.md +3 -3
- package/kb/procedures/maintenance-sop.md +3 -3
- package/kb/reference/architecture-overview.md +5 -5
- package/kb/reference/benchmark-config.md +1 -1
- package/kb/reference/competitive-features-implementation.md +2 -2
- package/kb/reference/enterprise-config-guide.md +9 -9
- package/kb/reference/extension-api.md +1 -1
- package/kb/reference/global-install-model.md +2 -2
- package/kb/reference/hooks-catalog.md +30 -30
- package/kb/reference/integrations.md +3 -3
- package/kb/reference/manifest-install.md +4 -4
- package/kb/reference/plugin-pack-conventions.md +5 -5
- package/kb/reference/stats.md +3 -3
- package/kb/reference/sync.md +3 -3
- package/llms-full.txt +118 -899
- package/llms.txt +0 -1
- package/manifest.json +3 -3
- package/package.json +1 -1
- package/scripts/add_rule.py +3 -2
- package/scripts/benchmark_config.py +3 -1
- package/scripts/compile_slm.py +9 -7
- package/scripts/config_cli.py +7 -7
- package/scripts/config_lock.py +12 -4
- package/scripts/config_merger.py +1 -1
- package/scripts/config_resolver.py +20 -7
- package/scripts/config_scaffold.py +4 -4
- package/scripts/config_validator.py +3 -3
- package/scripts/dir_rules_shared.py +1 -1
- package/scripts/doctor.py +3 -2
- package/scripts/install.py +12 -7
- package/scripts/install_git_hooks.py +1 -1
- package/scripts/install_steps/ai_tools.py +4 -4
- package/scripts/install_steps/hooks.py +1 -1
- package/scripts/install_steps/install_state.py +8 -6
- package/scripts/install_steps/project_registry.py +5 -5
- package/scripts/migrate.py +199 -0
- package/scripts/paths.py +50 -0
- package/scripts/plugin.py +8 -6
- package/scripts/remove_rule.py +5 -4
- package/scripts/stats.py +3 -2
- package/scripts/sync.py +3 -2
- package/scripts/update_projects.py +1 -1
- package/scripts/version_check.py +5 -2
- package/kb/planning/local-dashboard-plan.md +0 -773
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Migrate ai-toolkit data from ~/.ai-toolkit to ~/.softspark/ai-toolkit.
|
|
3
|
+
|
|
4
|
+
Called automatically by install.py and ai-toolkit.js on first run.
|
|
5
|
+
Can also be invoked directly: python3 scripts/migrate.py [--dry-run]
|
|
6
|
+
|
|
7
|
+
Migration steps:
|
|
8
|
+
1. Detect legacy ~/.ai-toolkit directory
|
|
9
|
+
2. Create ~/.softspark/ai-toolkit/
|
|
10
|
+
3. Move all contents (state, hooks, rules, sessions, etc.)
|
|
11
|
+
4. Leave ~/.ai-toolkit/.migrated marker with pointer to new location
|
|
12
|
+
5. Migrate per-project .ai-toolkit.json → .softspark-toolkit.json (via registry)
|
|
13
|
+
|
|
14
|
+
Exit codes:
|
|
15
|
+
0 Migration succeeded or nothing to migrate
|
|
16
|
+
1 Migration failed
|
|
17
|
+
"""
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import json
|
|
21
|
+
import os
|
|
22
|
+
import shutil
|
|
23
|
+
import sys
|
|
24
|
+
from datetime import datetime, timezone
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
|
|
27
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
28
|
+
from paths import (
|
|
29
|
+
LEGACY_DATA_DIR,
|
|
30
|
+
LEGACY_PROJECT_CONFIG,
|
|
31
|
+
LEGACY_PROJECT_LOCK,
|
|
32
|
+
PROJECT_CONFIG_FILENAME,
|
|
33
|
+
PROJECT_LOCK_FILENAME,
|
|
34
|
+
SOFTSPARK_DIR,
|
|
35
|
+
TOOLKIT_DATA_DIR,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
MIGRATED_MARKER = LEGACY_DATA_DIR / ".migrated"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def needs_migration() -> bool:
|
|
43
|
+
"""Check if legacy directory exists and hasn't been migrated yet."""
|
|
44
|
+
if not LEGACY_DATA_DIR.is_dir():
|
|
45
|
+
return False
|
|
46
|
+
if MIGRATED_MARKER.is_file():
|
|
47
|
+
return False
|
|
48
|
+
# Don't migrate if AI_TOOLKIT_HOME is set (custom setup)
|
|
49
|
+
if os.environ.get("AI_TOOLKIT_HOME"):
|
|
50
|
+
return False
|
|
51
|
+
return True
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def migrate_home_directory(dry_run: bool = False) -> bool:
|
|
55
|
+
"""Migrate ~/.ai-toolkit → ~/.softspark/ai-toolkit.
|
|
56
|
+
|
|
57
|
+
Returns True if migration was performed, False if skipped.
|
|
58
|
+
"""
|
|
59
|
+
if not needs_migration():
|
|
60
|
+
return False
|
|
61
|
+
|
|
62
|
+
print()
|
|
63
|
+
print("## Migrating to new directory structure")
|
|
64
|
+
print(f" {LEGACY_DATA_DIR} → {TOOLKIT_DATA_DIR}")
|
|
65
|
+
print()
|
|
66
|
+
|
|
67
|
+
if dry_run:
|
|
68
|
+
print(" (dry-run: no changes made)")
|
|
69
|
+
return False
|
|
70
|
+
|
|
71
|
+
# Create parent ~/.softspark/
|
|
72
|
+
SOFTSPARK_DIR.mkdir(parents=True, exist_ok=True)
|
|
73
|
+
|
|
74
|
+
if TOOLKIT_DATA_DIR.exists():
|
|
75
|
+
# New dir already exists (partial migration?) — merge carefully
|
|
76
|
+
_merge_directories(LEGACY_DATA_DIR, TOOLKIT_DATA_DIR)
|
|
77
|
+
else:
|
|
78
|
+
# Clean move
|
|
79
|
+
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
|
+
|
|
83
|
+
# Write migration marker
|
|
84
|
+
_write_marker()
|
|
85
|
+
|
|
86
|
+
print(f" Migrated: {TOOLKIT_DATA_DIR}")
|
|
87
|
+
return True
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _merge_directories(src: Path, dst: Path) -> None:
|
|
91
|
+
"""Merge src into dst, preferring src files (newer)."""
|
|
92
|
+
for item in src.iterdir():
|
|
93
|
+
if item.name == ".migrated":
|
|
94
|
+
continue
|
|
95
|
+
dest_item = dst / item.name
|
|
96
|
+
if item.is_dir():
|
|
97
|
+
if dest_item.is_dir():
|
|
98
|
+
_merge_directories(item, dest_item)
|
|
99
|
+
else:
|
|
100
|
+
shutil.move(str(item), str(dest_item))
|
|
101
|
+
else:
|
|
102
|
+
# Overwrite with source (legacy has the latest data)
|
|
103
|
+
shutil.move(str(item), str(dest_item))
|
|
104
|
+
|
|
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
|
+
def migrate_project_configs(dry_run: bool = False) -> int:
|
|
122
|
+
"""Rename .ai-toolkit.json → .softspark-toolkit.json in registered projects.
|
|
123
|
+
|
|
124
|
+
Returns the number of projects migrated.
|
|
125
|
+
"""
|
|
126
|
+
registry_file = TOOLKIT_DATA_DIR / "projects.json"
|
|
127
|
+
if not registry_file.is_file():
|
|
128
|
+
return 0
|
|
129
|
+
|
|
130
|
+
try:
|
|
131
|
+
with open(registry_file, encoding="utf-8") as f:
|
|
132
|
+
data = json.load(f)
|
|
133
|
+
projects = data.get("projects", [])
|
|
134
|
+
except (json.JSONDecodeError, OSError):
|
|
135
|
+
return 0
|
|
136
|
+
|
|
137
|
+
count = 0
|
|
138
|
+
for project in projects:
|
|
139
|
+
project_path = Path(project.get("path", ""))
|
|
140
|
+
if not project_path.is_dir():
|
|
141
|
+
continue
|
|
142
|
+
|
|
143
|
+
# Migrate .ai-toolkit.json → .softspark-toolkit.json
|
|
144
|
+
old_config = project_path / LEGACY_PROJECT_CONFIG
|
|
145
|
+
new_config = project_path / PROJECT_CONFIG_FILENAME
|
|
146
|
+
if old_config.is_file() and not new_config.is_file():
|
|
147
|
+
if dry_run:
|
|
148
|
+
print(f" Would rename: {old_config} → {new_config}")
|
|
149
|
+
else:
|
|
150
|
+
old_config.rename(new_config)
|
|
151
|
+
print(f" Renamed: {old_config.name} → {new_config.name} in {project_path}")
|
|
152
|
+
count += 1
|
|
153
|
+
|
|
154
|
+
# Migrate .ai-toolkit.lock.json → .softspark-toolkit.lock.json
|
|
155
|
+
old_lock = project_path / LEGACY_PROJECT_LOCK
|
|
156
|
+
new_lock = project_path / PROJECT_LOCK_FILENAME
|
|
157
|
+
if old_lock.is_file() and not new_lock.is_file():
|
|
158
|
+
if dry_run:
|
|
159
|
+
print(f" Would rename: {old_lock} → {new_lock}")
|
|
160
|
+
else:
|
|
161
|
+
old_lock.rename(new_lock)
|
|
162
|
+
|
|
163
|
+
return count
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def run_full_migration(dry_run: bool = False) -> bool:
|
|
167
|
+
"""Run complete migration: home directory + project configs.
|
|
168
|
+
|
|
169
|
+
Returns True if any migration was performed.
|
|
170
|
+
"""
|
|
171
|
+
migrated = migrate_home_directory(dry_run=dry_run)
|
|
172
|
+
|
|
173
|
+
if migrated and not dry_run:
|
|
174
|
+
count = migrate_project_configs(dry_run=dry_run)
|
|
175
|
+
if count > 0:
|
|
176
|
+
print(f" Migrated {count} project config(s)")
|
|
177
|
+
|
|
178
|
+
return migrated
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def main() -> None:
|
|
182
|
+
dry_run = "--dry-run" in sys.argv
|
|
183
|
+
|
|
184
|
+
if not needs_migration():
|
|
185
|
+
print("Nothing to migrate (no legacy ~/.ai-toolkit found or already migrated).")
|
|
186
|
+
sys.exit(0)
|
|
187
|
+
|
|
188
|
+
success = run_full_migration(dry_run=dry_run)
|
|
189
|
+
|
|
190
|
+
if success:
|
|
191
|
+
print()
|
|
192
|
+
print("Migration complete. The old ~/.ai-toolkit/ directory contains only a")
|
|
193
|
+
print("migration marker and can be safely deleted.")
|
|
194
|
+
elif not dry_run:
|
|
195
|
+
print("Migration skipped.")
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
if __name__ == "__main__":
|
|
199
|
+
main()
|
package/scripts/paths.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Centralized path constants for ai-toolkit.
|
|
2
|
+
|
|
3
|
+
All scripts MUST import paths from here — never hardcode ~/.ai-toolkit or
|
|
4
|
+
~/.softspark/ai-toolkit directly.
|
|
5
|
+
|
|
6
|
+
Supports override via AI_TOOLKIT_HOME env var for testing and custom setups.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
# ---------------------------------------------------------------------------
|
|
14
|
+
# Canonical paths
|
|
15
|
+
# ---------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
SOFTSPARK_DIR = Path(os.environ.get("SOFTSPARK_HOME", Path.home() / ".softspark"))
|
|
18
|
+
|
|
19
|
+
TOOLKIT_DATA_DIR = Path(
|
|
20
|
+
os.environ.get("AI_TOOLKIT_HOME", SOFTSPARK_DIR / "ai-toolkit")
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
# Legacy path (pre-v2.0) — used only by migration detection
|
|
24
|
+
LEGACY_DATA_DIR = Path.home() / ".ai-toolkit"
|
|
25
|
+
|
|
26
|
+
# Sub-directories under TOOLKIT_DATA_DIR
|
|
27
|
+
HOOKS_DIR = TOOLKIT_DATA_DIR / "hooks"
|
|
28
|
+
RULES_DIR = TOOLKIT_DATA_DIR / "rules"
|
|
29
|
+
SESSIONS_DIR = TOOLKIT_DATA_DIR / "sessions"
|
|
30
|
+
COMPACTIONS_DIR = TOOLKIT_DATA_DIR / "compactions"
|
|
31
|
+
CONFIG_CACHE_DIR = TOOLKIT_DATA_DIR / "config-cache"
|
|
32
|
+
COMPILED_DIR = TOOLKIT_DATA_DIR / "compiled"
|
|
33
|
+
|
|
34
|
+
# Files under TOOLKIT_DATA_DIR
|
|
35
|
+
STATE_FILE = TOOLKIT_DATA_DIR / "state.json"
|
|
36
|
+
PROJECTS_FILE = TOOLKIT_DATA_DIR / "projects.json"
|
|
37
|
+
STATS_FILE = TOOLKIT_DATA_DIR / "stats.json"
|
|
38
|
+
GOVERNANCE_LOG = TOOLKIT_DATA_DIR / "governance.log"
|
|
39
|
+
VERSION_CHECK_FILE = TOOLKIT_DATA_DIR / "version-check.json"
|
|
40
|
+
|
|
41
|
+
# Per-project config filenames
|
|
42
|
+
PROJECT_CONFIG_FILENAME = ".softspark-toolkit.json"
|
|
43
|
+
PROJECT_LOCK_FILENAME = ".softspark-toolkit.lock.json"
|
|
44
|
+
|
|
45
|
+
# Legacy per-project config filenames (for migration)
|
|
46
|
+
LEGACY_PROJECT_CONFIG = ".ai-toolkit.json"
|
|
47
|
+
LEGACY_PROJECT_LOCK = ".ai-toolkit.lock.json"
|
|
48
|
+
|
|
49
|
+
# Base config filename (published in npm packages — unchanged)
|
|
50
|
+
BASE_CONFIG_FILENAME = "ai-toolkit.config.json"
|
package/scripts/plugin.py
CHANGED
|
@@ -35,10 +35,12 @@ from _common import toolkit_dir, app_dir
|
|
|
35
35
|
from plugin_schema import resolve_hook_event, validate_manifest, validate_references
|
|
36
36
|
|
|
37
37
|
|
|
38
|
+
from paths import TOOLKIT_DATA_DIR, HOOKS_DIR as _HOOKS_DIR
|
|
39
|
+
|
|
38
40
|
PLUGINS_DIR = app_dir / "plugins"
|
|
39
41
|
CLAUDE_DIR = Path.home() / ".claude"
|
|
40
|
-
HOOKS_DIR =
|
|
41
|
-
PLUGINS_STATE_FILE =
|
|
42
|
+
HOOKS_DIR = _HOOKS_DIR
|
|
43
|
+
PLUGINS_STATE_FILE = TOOLKIT_DATA_DIR / "plugins.json"
|
|
42
44
|
|
|
43
45
|
|
|
44
46
|
# ---------------------------------------------------------------------------
|
|
@@ -156,7 +158,7 @@ def _copy_scripts(name: str, pack_dir: Path, installed_items: list[str]) -> None
|
|
|
156
158
|
plugin_scripts_dir = pack_dir / "scripts"
|
|
157
159
|
if not plugin_scripts_dir.is_dir():
|
|
158
160
|
return
|
|
159
|
-
scripts_dest =
|
|
161
|
+
scripts_dest = TOOLKIT_DATA_DIR / "plugin-scripts" / name
|
|
160
162
|
scripts_dest.mkdir(parents=True, exist_ok=True)
|
|
161
163
|
for script_file in sorted(plugin_scripts_dir.iterdir()):
|
|
162
164
|
if script_file.name.startswith("__"):
|
|
@@ -282,7 +284,7 @@ def remove_pack(name: str) -> bool:
|
|
|
282
284
|
|
|
283
285
|
print(f" Removing: {name}")
|
|
284
286
|
|
|
285
|
-
# 1. Remove plugin hooks from ~/.ai-toolkit/hooks/
|
|
287
|
+
# 1. Remove plugin hooks from ~/.softspark/ai-toolkit/hooks/
|
|
286
288
|
removed = 0
|
|
287
289
|
for hook in HOOKS_DIR.glob(f"plugin-{name}-*.sh"):
|
|
288
290
|
hook.unlink()
|
|
@@ -290,7 +292,7 @@ def remove_pack(name: str) -> bool:
|
|
|
290
292
|
removed += 1
|
|
291
293
|
|
|
292
294
|
# 2. Remove plugin scripts
|
|
293
|
-
scripts_dir =
|
|
295
|
+
scripts_dir = TOOLKIT_DATA_DIR / "plugin-scripts" / name
|
|
294
296
|
if scripts_dir.is_dir():
|
|
295
297
|
shutil.rmtree(scripts_dir)
|
|
296
298
|
print(f" Removed scripts: {scripts_dir}")
|
|
@@ -358,7 +360,7 @@ def update_pack(name: str) -> bool:
|
|
|
358
360
|
# Clean
|
|
359
361
|
# ---------------------------------------------------------------------------
|
|
360
362
|
|
|
361
|
-
MEMORY_DB =
|
|
363
|
+
MEMORY_DB = TOOLKIT_DATA_DIR / "memory.db"
|
|
362
364
|
|
|
363
365
|
# Map plugin names to their clean logic
|
|
364
366
|
CLEANABLE_PLUGINS = {"memory-pack"}
|
package/scripts/remove_rule.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""remove-rule -- Unregister a rule (opposite of add-rule).
|
|
3
3
|
|
|
4
|
-
Removes the rule file from ~/.ai-toolkit/rules/ (so it is no longer
|
|
4
|
+
Removes the rule file from ~/.softspark/ai-toolkit/rules/ (so it is no longer
|
|
5
5
|
re-applied on future 'ai-toolkit install' runs) AND strips its injected
|
|
6
6
|
block from the target CLAUDE.md.
|
|
7
7
|
|
|
@@ -29,11 +29,12 @@ def main() -> None:
|
|
|
29
29
|
|
|
30
30
|
rule_name = sys.argv[1]
|
|
31
31
|
target_dir = Path(sys.argv[2]) if len(sys.argv) > 2 else Path.home()
|
|
32
|
-
|
|
32
|
+
from paths import RULES_DIR
|
|
33
|
+
rules_dir = RULES_DIR
|
|
33
34
|
|
|
34
35
|
removed = 0
|
|
35
36
|
|
|
36
|
-
# 1. Unregister from ~/.ai-toolkit/rules/
|
|
37
|
+
# 1. Unregister from ~/.softspark/ai-toolkit/rules/
|
|
37
38
|
rule_file = rules_dir / f"{rule_name}.md"
|
|
38
39
|
if rule_file.is_file():
|
|
39
40
|
rule_file.unlink()
|
|
@@ -51,7 +52,7 @@ def main() -> None:
|
|
|
51
52
|
if removed == 0:
|
|
52
53
|
print()
|
|
53
54
|
print("Nothing to unregister. To list registered rules:")
|
|
54
|
-
print(" ls
|
|
55
|
+
print(f" ls {rules_dir}/")
|
|
55
56
|
|
|
56
57
|
|
|
57
58
|
if __name__ == "__main__":
|
package/scripts/stats.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""ai-toolkit stats -- Show skill usage statistics.
|
|
3
3
|
|
|
4
|
-
Reads ~/.ai-toolkit/stats.json (populated by track-usage.sh hook)
|
|
4
|
+
Reads ~/.softspark/ai-toolkit/stats.json (populated by track-usage.sh hook)
|
|
5
5
|
and displays a sorted table of skill invocations.
|
|
6
6
|
|
|
7
7
|
Options:
|
|
@@ -15,8 +15,9 @@ import sys
|
|
|
15
15
|
from pathlib import Path
|
|
16
16
|
|
|
17
17
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
18
|
+
from paths import STATS_FILE as _STATS_FILE
|
|
18
19
|
|
|
19
|
-
STATS_FILE =
|
|
20
|
+
STATS_FILE = _STATS_FILE
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
def main() -> None:
|
package/scripts/sync.py
CHANGED
|
@@ -21,9 +21,10 @@ from pathlib import Path
|
|
|
21
21
|
|
|
22
22
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
23
23
|
from _common import toolkit_dir
|
|
24
|
+
from paths import TOOLKIT_DATA_DIR, RULES_DIR as _RULES_DIR
|
|
24
25
|
|
|
25
|
-
CONFIG_DIR =
|
|
26
|
-
RULES_DIR =
|
|
26
|
+
CONFIG_DIR = TOOLKIT_DATA_DIR
|
|
27
|
+
RULES_DIR = _RULES_DIR
|
|
27
28
|
GIST_ID_FILE = CONFIG_DIR / ".gist-id"
|
|
28
29
|
|
|
29
30
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""Update all registered projects in parallel.
|
|
3
3
|
|
|
4
|
-
Reads ~/.ai-toolkit/projects.json and runs install.py --local in each
|
|
4
|
+
Reads ~/.softspark/ai-toolkit/projects.json and runs install.py --local in each
|
|
5
5
|
project directory concurrently using a thread pool.
|
|
6
6
|
|
|
7
7
|
Stdlib-only — no external dependencies.
|
package/scripts/version_check.py
CHANGED
|
@@ -21,7 +21,10 @@ import sys
|
|
|
21
21
|
import time
|
|
22
22
|
from pathlib import Path
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
25
|
+
from paths import VERSION_CHECK_FILE, STATE_FILE
|
|
26
|
+
|
|
27
|
+
CACHE_FILE = VERSION_CHECK_FILE
|
|
25
28
|
CACHE_TTL = 86400 # 24 hours
|
|
26
29
|
PACKAGE_NAME = "@softspark/ai-toolkit"
|
|
27
30
|
|
|
@@ -34,7 +37,7 @@ def _get_installed_version() -> str:
|
|
|
34
37
|
installed/updated, while package.json may be newer if the npm package
|
|
35
38
|
was upgraded but `ai-toolkit update` was not run yet.
|
|
36
39
|
"""
|
|
37
|
-
state_file =
|
|
40
|
+
state_file = STATE_FILE
|
|
38
41
|
if state_file.is_file():
|
|
39
42
|
try:
|
|
40
43
|
with open(state_file, encoding="utf-8") as f:
|