gsd-antigravity-kit 1.32.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/.agent/skills/gsd/SKILL.md +152 -123
- package/.agent/skills/gsd/VERSION +1 -0
- package/.agent/skills/gsd/assets/templates/user-profile.md +8 -8
- package/.agent/skills/gsd/bin/gsd-tools.cjs +81 -3
- package/.agent/skills/gsd/bin/help-manifest.json +24 -1
- package/.agent/skills/gsd/bin/hooks/gsd-check-update.js +15 -5
- package/.agent/skills/gsd/bin/hooks/gsd-context-monitor.js +1 -1
- package/.agent/skills/gsd/bin/hooks/gsd-phase-boundary.sh +27 -0
- package/.agent/skills/gsd/bin/hooks/gsd-prompt-guard.js +2 -1
- package/.agent/skills/gsd/bin/hooks/gsd-read-guard.js +1 -1
- package/.agent/skills/gsd/bin/hooks/gsd-session-state.sh +33 -0
- package/.agent/skills/gsd/bin/hooks/gsd-statusline.js +5 -5
- package/.agent/skills/gsd/bin/hooks/gsd-validate-commit.sh +47 -0
- package/.agent/skills/gsd/bin/hooks/gsd-workflow-guard.js +1 -1
- package/.agent/skills/gsd/bin/lib/config.cjs +31 -10
- package/.agent/skills/gsd/bin/lib/core.cjs +48 -13
- package/.agent/skills/gsd/bin/lib/frontmatter.cjs +34 -2
- package/.agent/skills/gsd/bin/lib/intel.cjs +660 -0
- package/.agent/skills/gsd/bin/lib/learnings.cjs +378 -0
- package/.agent/skills/gsd/bin/lib/milestone.cjs +13 -4
- package/.agent/skills/gsd/bin/lib/model-profiles.cjs +17 -17
- package/.agent/skills/gsd/bin/lib/profile-output.cjs +31 -31
- package/.agent/skills/gsd/bin/lib/security.cjs +119 -0
- package/.agent/skills/gsd/bin/lib/verify.cjs +15 -15
- package/.agent/skills/gsd/migration_report.md +7 -0
- package/.agent/skills/gsd/references/agents/gsd-code-fixer.md +516 -0
- package/.agent/skills/gsd/references/agents/gsd-code-reviewer.md +355 -0
- package/.agent/skills/gsd/references/agents/gsd-debugger.md +10 -1
- package/.agent/skills/gsd/references/agents/gsd-executor.md +3 -0
- package/.agent/skills/gsd/references/agents/gsd-intel-updater.md +314 -0
- package/.agent/skills/gsd/references/agents/gsd-phase-researcher.md +3 -0
- package/.agent/skills/gsd/references/agents/gsd-plan-checker.md +16 -4
- package/.agent/skills/gsd/references/agents/gsd-planner.md +7 -0
- package/.agent/skills/gsd/references/agents/gsd-user-profiler.md +5 -5
- package/.agent/skills/gsd/references/agents/gsd-verifier.md +55 -1
- package/.agent/skills/gsd/references/agents/profiles/dev.md +21 -0
- package/.agent/skills/gsd/references/agents/profiles/research.md +22 -0
- package/.agent/skills/gsd/references/agents/profiles/review.md +22 -0
- package/.agent/skills/gsd/references/commands/{gsd-add-todo.md → atomic/add-todo.md} +5 -4
- package/.agent/skills/gsd/references/commands/{gsd-check-todos.md → atomic/check-todos.md} +5 -4
- package/.agent/skills/gsd/references/commands/{gsd-cleanup.md → atomic/cleanup.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-do.md → atomic/do.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-help.md → atomic/help.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-join-discord.md → atomic/join-discord.md} +21 -19
- package/.agent/skills/gsd/references/commands/{gsd-note.md → atomic/note.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-session-report.md → atomic/session-report.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-ship.md → atomic/ship.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-stats.md → atomic/stats.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-thread.md → atomic/thread.md} +7 -6
- package/.agent/skills/gsd/references/commands/atomic/undo.md +36 -0
- package/.agent/skills/gsd/references/commands/{gsd-add-backlog.md → milestone/add-backlog.md} +8 -7
- package/.agent/skills/gsd/references/commands/{gsd-audit-milestone.md → milestone/audit-milestone.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-complete-milestone.md → milestone/complete-milestone.md} +6 -4
- package/.agent/skills/gsd/references/commands/{gsd-milestone-summary.md → milestone/milestone-summary.md} +5 -3
- package/.agent/skills/gsd/references/commands/{gsd-new-milestone.md → milestone/new-milestone.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-plan-milestone-gaps.md → milestone/plan-milestone-gaps.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-plant-seed.md → milestone/plant-seed.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-review-backlog.md → milestone/review-backlog.md} +6 -5
- package/.agent/skills/gsd/references/commands/misc/audit-fix.md +35 -0
- package/.agent/skills/gsd/references/commands/{gsd-audit-uat.md → misc/audit-uat.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-next.md → misc/next.md} +6 -3
- package/.agent/skills/gsd/references/commands/{gsd-progress.md → misc/progress.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-verify-work.md → misc/verify-work.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-add-phase.md → phase/add-phase.md} +5 -4
- package/.agent/skills/gsd/references/commands/{gsd-add-tests.md → phase/add-tests.md} +8 -3
- package/.agent/skills/gsd/references/commands/{gsd-discuss-phase.md → phase/discuss-phase.md} +5 -4
- package/.agent/skills/gsd/references/commands/{gsd-execute-phase.md → phase/execute-phase.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-insert-phase.md → phase/insert-phase.md} +5 -4
- package/.agent/skills/gsd/references/commands/{gsd-list-phase-assumptions.md → phase/list-phase-assumptions.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-plan-phase.md → phase/plan-phase.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-remove-phase.md → phase/remove-phase.md} +5 -4
- package/.agent/skills/gsd/references/commands/{gsd-research-phase.md → phase/research-phase.md} +7 -6
- package/.agent/skills/gsd/references/commands/{gsd-secure-phase.md → phase/secure-phase.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-ui-phase.md → phase/ui-phase.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-ui-review.md → phase/ui-review.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-validate-phase.md → phase/validate-phase.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-workstreams.md → phase/workstreams.md} +71 -70
- package/.agent/skills/gsd/references/commands/{gsd-analyze-dependencies.md → project/analyze-dependencies.md} +5 -4
- package/.agent/skills/gsd/references/commands/project/explore.md +29 -0
- package/.agent/skills/gsd/references/commands/project/import.md +38 -0
- package/.agent/skills/gsd/references/commands/project/intel.md +181 -0
- package/.agent/skills/gsd/references/commands/{gsd-list-workspaces.md → project/list-workspaces.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-map-codebase.md → project/map-codebase.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-new-project.md → project/new-project.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-new-workspace.md → project/new-workspace.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-remove-workspace.md → project/remove-workspace.md} +4 -3
- package/.agent/skills/gsd/references/commands/project/scan.md +28 -0
- package/.agent/skills/gsd/references/commands/{gsd-autonomous.md → system/autonomous.md} +4 -3
- package/.agent/skills/gsd/references/commands/system/code-review-fix.md +54 -0
- package/.agent/skills/gsd/references/commands/system/code-review.md +57 -0
- package/.agent/skills/gsd/references/commands/{gsd-debug.md → system/debug.md} +7 -6
- package/.agent/skills/gsd/references/commands/{gsd-docs-update.md → system/docs-update.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-fast.md → system/fast.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-forensics.md → system/forensics.md} +5 -3
- package/.agent/skills/gsd/references/commands/{gsd-health.md → system/health.md} +5 -4
- package/.agent/skills/gsd/references/commands/{gsd-manager.md → system/manager.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-pause-work.md → system/pause-work.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-pr-branch.md → system/pr-branch.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-profile-user.md → system/profile-user.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-quick.md → system/quick.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-reapply-patches.md → system/reapply-patches.md} +25 -7
- package/.agent/skills/gsd/references/commands/{gsd-resume-work.md → system/resume-work.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-review.md → system/review.md} +4 -3
- package/.agent/skills/gsd/references/commands/system/set-profile.md +14 -0
- package/.agent/skills/gsd/references/commands/{gsd-settings.md → system/settings.md} +4 -3
- package/.agent/skills/gsd/references/commands/{gsd-update.md → system/update.md} +4 -3
- package/.agent/skills/gsd/references/docs/agent-contracts.md +79 -0
- package/.agent/skills/gsd/references/docs/common-bug-patterns.md +114 -0
- package/.agent/skills/gsd/references/docs/context-budget.md +49 -0
- package/.agent/skills/gsd/references/docs/domain-probes.md +125 -0
- package/.agent/skills/gsd/references/docs/few-shot-examples/plan-checker.md +73 -0
- package/.agent/skills/gsd/references/docs/few-shot-examples/verifier.md +109 -0
- package/.agent/skills/gsd/references/docs/gate-prompts.md +100 -0
- package/.agent/skills/gsd/references/docs/gates.md +70 -0
- package/.agent/skills/gsd/references/docs/model-profile-resolution.md +2 -0
- package/.agent/skills/gsd/references/docs/model-profiles.md +20 -14
- package/.agent/skills/gsd/references/docs/planning-config.md +216 -1
- package/.agent/skills/gsd/references/docs/revision-loop.md +97 -0
- package/.agent/skills/gsd/references/docs/thinking-models-debug.md +44 -0
- package/.agent/skills/gsd/references/docs/thinking-models-execution.md +50 -0
- package/.agent/skills/gsd/references/docs/thinking-models-planning.md +62 -0
- package/.agent/skills/gsd/references/docs/thinking-models-research.md +50 -0
- package/.agent/skills/gsd/references/docs/thinking-models-verification.md +55 -0
- package/.agent/skills/gsd/references/docs/thinking-partner.md +96 -0
- package/.agent/skills/gsd/references/docs/universal-anti-patterns.md +58 -0
- package/.agent/skills/gsd/references/docs/user-profiling.md +10 -10
- package/.agent/skills/gsd/references/docs/verification-overrides.md +227 -0
- package/.agent/skills/gsd/references/docs/workstream-flag.md +2 -2
- package/.agent/skills/gsd/references/mapping.md +11 -21
- package/.agent/skills/gsd/references/workflows/analyze-dependencies.md +3 -3
- package/.agent/skills/gsd/references/workflows/audit-fix.md +157 -0
- package/.agent/skills/gsd/references/workflows/autonomous.md +22 -1
- package/.agent/skills/gsd/references/workflows/code-review-fix.md +497 -0
- package/.agent/skills/gsd/references/workflows/code-review.md +515 -0
- package/.agent/skills/gsd/references/workflows/discuss-phase-power.md +3 -3
- package/.agent/skills/gsd/references/workflows/discuss-phase.md +20 -0
- package/.agent/skills/gsd/references/workflows/execute-phase.md +103 -0
- package/.agent/skills/gsd/references/workflows/explore.md +139 -0
- package/.agent/skills/gsd/references/workflows/import.md +274 -0
- package/.agent/skills/gsd/references/workflows/inbox.md +384 -0
- package/.agent/skills/gsd/references/workflows/manager.md +5 -5
- package/.agent/skills/gsd/references/workflows/new-milestone.md +1 -1
- package/.agent/skills/gsd/references/workflows/next.md +56 -0
- package/.agent/skills/gsd/references/workflows/plan-phase.md +48 -1
- package/.agent/skills/gsd/references/workflows/quick.md +96 -2
- package/.agent/skills/gsd/references/workflows/review.md +23 -3
- package/.agent/skills/gsd/references/workflows/scan.md +102 -0
- package/.agent/skills/gsd/references/workflows/settings.md +1 -1
- package/.agent/skills/gsd/references/workflows/ui-review.md +2 -2
- package/.agent/skills/gsd/references/workflows/undo.md +312 -0
- package/.agent/skills/gsd/references/workflows/update.md +5 -5
- package/.agent/skills/gsd-converter/SKILL.md +67 -59
- package/.agent/skills/gsd-converter/assets/migration-manifest.json +74 -0
- package/.agent/skills/gsd-converter/references/mapping.md +6 -16
- package/.agent/skills/gsd-converter/scripts/convert.py +419 -80
- package/.agent/skills/gsd-converter/scripts/regression_test.py +33 -0
- package/.agent/skills/selectpaste-update/SKILL.md +46 -0
- package/.agent/skills/selectpaste-update/scripts/sync-commands.py +317 -0
- package/README.md +4 -2
- package/bin/install.js +116 -116
- package/package.json +1 -1
- package/.agent/skills/gsd/references/commands/gsd-set-profile.md +0 -12
- /package/.agent/skills/gsd/references/commands/{gsd-tools.md → system/gsd-tools.md} +0 -0
|
@@ -7,6 +7,15 @@ import subprocess
|
|
|
7
7
|
import json
|
|
8
8
|
from datetime import datetime
|
|
9
9
|
|
|
10
|
+
def load_manifest():
|
|
11
|
+
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
12
|
+
manifest_path = os.path.join(script_dir, '..', 'assets', 'migration-manifest.json')
|
|
13
|
+
if not os.path.exists(manifest_path):
|
|
14
|
+
print(f" ❌ Manifest not found at {manifest_path}")
|
|
15
|
+
sys.exit(1)
|
|
16
|
+
with open(manifest_path, 'r', encoding='utf-8') as f:
|
|
17
|
+
return json.load(f)
|
|
18
|
+
|
|
10
19
|
def setup_args():
|
|
11
20
|
# Force UTF-8 for Windows terminals
|
|
12
21
|
if sys.platform == 'win32':
|
|
@@ -112,18 +121,48 @@ def discover_commands(source_gsd_tools_path):
|
|
|
112
121
|
|
|
113
122
|
return commands
|
|
114
123
|
|
|
115
|
-
def
|
|
124
|
+
def get_command_category(cmd_name):
|
|
125
|
+
"""Categorize GSD commands based on their primary function."""
|
|
126
|
+
atomic = ['add-todo', 'check-todos', 'note', 'ship', 'cleanup', 'undo', 'help', 'do', 'stats', 'thread', 'session-report', 'join-discord']
|
|
127
|
+
phase = ['plan-phase', 'execute-phase', 'research-phase', 'validate-phase', 'discuss-phase', 'remove-phase', 'insert-phase', 'add-phase', 'list-phase-assumptions', 'secure-phase', 'ui-phase', 'ui-review', 'add-tests', 'workstreams']
|
|
128
|
+
milestone = ['new-milestone', 'complete-milestone', 'audit-milestone', 'milestone-summary', 'plan-milestone-gaps', 'review-backlog', 'add-backlog', 'plant-seed']
|
|
129
|
+
project = ['new-project', 'new-workspace', 'list-workspaces', 'remove-workspace', 'map-codebase', 'scan', 'intel', 'analyze-dependencies', 'explore', 'import']
|
|
130
|
+
system = ['gsd-tools', 'health', 'settings', 'profile-user', 'set-profile', 'update', 'pause-work', 'resume-work', 'reapply-patches', 'debug', 'forensics', 'manager', 'autonomous', 'fast', 'quick', 'code-review', 'code-review-fix', 'review', 'docs-update', 'pr-branch']
|
|
131
|
+
|
|
132
|
+
if cmd_name in atomic: return 'atomic'
|
|
133
|
+
if cmd_name in phase: return 'phase'
|
|
134
|
+
if cmd_name in milestone: return 'milestone'
|
|
135
|
+
if cmd_name in project: return 'project'
|
|
136
|
+
if cmd_name in system: return 'system'
|
|
137
|
+
return 'misc'
|
|
138
|
+
|
|
139
|
+
def inject_metadata(file_path, version):
|
|
140
|
+
"""Inject GSD version and migration date into markdown frontmatter."""
|
|
141
|
+
if not file_path.endswith('.md'): return
|
|
142
|
+
try:
|
|
143
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
144
|
+
content = f.read()
|
|
145
|
+
|
|
146
|
+
# Parse frontmatter
|
|
147
|
+
match = re.match(r'^(---\s*\n)(.*?\n)(---)', content, re.DOTALL)
|
|
148
|
+
if match:
|
|
149
|
+
start, mid, end = match.groups()
|
|
150
|
+
# Check if already injected
|
|
151
|
+
if 'gsd-source-version' in mid: return
|
|
152
|
+
|
|
153
|
+
new_meta = f"gsd-source-version: {version}\nmigration-date: {datetime.now().strftime('%Y-%m-%d')}\n"
|
|
154
|
+
new_content = start + mid + new_meta + end + content[match.end():]
|
|
155
|
+
|
|
156
|
+
with open(file_path, 'w', encoding='utf-8') as f:
|
|
157
|
+
f.write(new_content)
|
|
158
|
+
except Exception as e:
|
|
159
|
+
print(f" ⚠️ Failed to inject metadata to {file_path}: {e}")
|
|
160
|
+
|
|
161
|
+
def migrate_files(source_base, target_base, manifest):
|
|
116
162
|
print(f"🚀 Starting migration from {source_base} to {target_base}...")
|
|
117
163
|
|
|
118
|
-
# Define mappings (source_rel, target_rel)
|
|
119
|
-
mappings = [
|
|
120
|
-
('get-shit-done/references', 'references/docs'),
|
|
121
|
-
('get-shit-done/workflows', 'references/workflows'),
|
|
122
|
-
('agents', 'references/agents'),
|
|
123
|
-
('get-shit-done/templates', 'assets/templates'),
|
|
124
|
-
('get-shit-done/bin', 'bin'),
|
|
125
|
-
('hooks', 'bin/hooks')
|
|
126
|
-
]
|
|
164
|
+
# Define mappings (source_rel, target_rel) from manifest
|
|
165
|
+
mappings = [(m['source'], m['target']) for m in manifest['mappings']]
|
|
127
166
|
|
|
128
167
|
for src_rel, tgt_rel in mappings:
|
|
129
168
|
src_path = os.path.join(source_base, src_rel)
|
|
@@ -136,7 +175,17 @@ def migrate_files(source_base, target_base):
|
|
|
136
175
|
|
|
137
176
|
for item in os.listdir(src_path):
|
|
138
177
|
s = os.path.join(src_path, item)
|
|
139
|
-
|
|
178
|
+
|
|
179
|
+
# Special handling for command categorization
|
|
180
|
+
if src_rel == 'commands/gsd/':
|
|
181
|
+
cmd_name = item[:-3] if item.endswith('.md') else item
|
|
182
|
+
category = get_command_category(cmd_name)
|
|
183
|
+
cat_path = os.path.join(tgt_path, category)
|
|
184
|
+
os.makedirs(cat_path, exist_ok=True)
|
|
185
|
+
d = os.path.join(cat_path, item)
|
|
186
|
+
else:
|
|
187
|
+
d = os.path.join(tgt_path, item)
|
|
188
|
+
|
|
140
189
|
if os.path.isdir(s):
|
|
141
190
|
shutil.copytree(s, d, dirs_exist_ok=True)
|
|
142
191
|
else:
|
|
@@ -148,17 +197,16 @@ def migrate_files(source_base, target_base):
|
|
|
148
197
|
skills_src = os.path.join(source_base, 'skills')
|
|
149
198
|
commands_tgt = os.path.join(target_base, 'references/commands')
|
|
150
199
|
if os.path.exists(skills_src):
|
|
151
|
-
print(f" 📁 Migrating modular skills -> references/commands")
|
|
152
|
-
os.
|
|
200
|
+
print(f" 📁 Migrating modular skills -> references/commands/modular")
|
|
201
|
+
modular_tgt = os.path.join(commands_tgt, 'modular')
|
|
202
|
+
os.makedirs(modular_tgt, exist_ok=True)
|
|
153
203
|
for skill_dir in os.listdir(skills_src):
|
|
154
204
|
s_full = os.path.join(skills_src, skill_dir)
|
|
155
205
|
if os.path.isdir(s_full):
|
|
156
206
|
skill_md = os.path.join(s_full, 'SKILL.md')
|
|
157
207
|
if os.path.exists(skill_md):
|
|
158
|
-
# Flatten into references/commands/gsd-name.md
|
|
159
|
-
# Clean up the name (remove gsd- prefix if present for redundancy, or keep it)
|
|
160
208
|
target_name = skill_dir + '.md'
|
|
161
|
-
shutil.copy2(skill_md, os.path.join(
|
|
209
|
+
shutil.copy2(skill_md, os.path.join(modular_tgt, target_name))
|
|
162
210
|
|
|
163
211
|
# Migrate internal documentation (mapping.md)
|
|
164
212
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
@@ -169,34 +217,38 @@ def migrate_files(source_base, target_base):
|
|
|
169
217
|
os.makedirs(os.path.dirname(mapping_tgt), exist_ok=True)
|
|
170
218
|
shutil.copy2(mapping_src, mapping_tgt)
|
|
171
219
|
|
|
172
|
-
def refactor_content(target_base):
|
|
220
|
+
def refactor_content(target_base, version, manifest):
|
|
173
221
|
print("🔧 Refactoring file contents and paths...")
|
|
174
222
|
|
|
175
|
-
|
|
223
|
+
# Load rebranding rules from manifest
|
|
224
|
+
rebranding_rules = manifest.get('rebranding', {}).get('replacements', [])
|
|
225
|
+
replacements = []
|
|
226
|
+
for rule in rebranding_rules:
|
|
227
|
+
replacements.append((re.compile(rule['pattern']), rule['replacement']))
|
|
228
|
+
|
|
229
|
+
# Standard GSD replacements (preserved)
|
|
230
|
+
standard_replacements = [
|
|
176
231
|
# Skill-relative internal references
|
|
177
|
-
(r'@.*?\.claude/commands/gsd/', '@references/commands/'),
|
|
178
|
-
(r'@.*?\.claude/get-shit-done/references/', '@references/docs/'),
|
|
179
|
-
(r'@.*?\.claude/get-shit-done/workflows/', '@references/workflows/'),
|
|
180
|
-
(r'@.*?\.claude/get-shit-done/
|
|
181
|
-
(r'@.*?\.claude/
|
|
182
|
-
(r'@.*?\.claude/
|
|
232
|
+
(re.compile(r'@.*?\.claude/commands/gsd/'), '@references/commands/'),
|
|
233
|
+
(re.compile(r'@.*?\.claude/get-shit-done/references/'), '@references/docs/'),
|
|
234
|
+
(re.compile(r'@.*?\.claude/get-shit-done/workflows/'), '@references/workflows/'),
|
|
235
|
+
(re.compile(r'@.*?\.claude/get-shit-done/contexts/'), '@references/agents/profiles/'),
|
|
236
|
+
(re.compile(r'@.*?\.claude/get-shit-done/templates/'), '@assets/templates/'),
|
|
237
|
+
(re.compile(r'@.*?\.claude/agents/'), '@references/agents/'),
|
|
238
|
+
(re.compile(r'@.*?\.claude/hooks/'), '@bin/hooks/'),
|
|
183
239
|
|
|
184
240
|
# Local filesystem paths
|
|
185
|
-
(r'\.?/?.*?\.claude/agents/', 'references/agents/'),
|
|
186
|
-
(r'\.?/?.*?\.claude/get-shit-done/templates/', 'assets/templates/'),
|
|
187
|
-
(r'\.?/?.*?\.claude/get-shit-done/workflows/', 'references/workflows/'),
|
|
188
|
-
(r'\.?/?.*?\.claude/get-shit-done/
|
|
189
|
-
(r'\.?/?.*?\.claude/
|
|
190
|
-
|
|
191
|
-
# Rebranding
|
|
192
|
-
(r'\bClaude Code\b', 'Antigravity'),
|
|
193
|
-
(r'\bClaude\b', 'Antigravity'),
|
|
194
|
-
(r'\bclaude\b', 'antigravity'),
|
|
195
|
-
(r'\bCLAUDE\b', 'ANTIGRAVITY'),
|
|
196
|
-
(r'generate-antigravity-profile', 'generate-antigravity-profile'), # Ensure double rebrands don't break
|
|
197
|
-
(r'generate-antigravity-md', 'generate-antigravity-md'),
|
|
241
|
+
(re.compile(r'\.?/?.*?\.claude/agents/'), 'references/agents/'),
|
|
242
|
+
(re.compile(r'\.?/?.*?\.claude/get-shit-done/templates/'), 'assets/templates/'),
|
|
243
|
+
(re.compile(r'\.?/?.*?\.claude/get-shit-done/workflows/'), 'references/workflows/'),
|
|
244
|
+
(re.compile(r'\.?/?.*?\.claude/get-shit-done/contexts/'), 'references/agents/profiles/'),
|
|
245
|
+
(re.compile(r'\.?/?.*?\.claude/get-shit-done/bin/'), '.agent/skills/gsd/bin/'),
|
|
246
|
+
(re.compile(r'\.?/?.*?\.claude/hooks/'), '.agent/skills/gsd/bin/hooks/'),
|
|
198
247
|
]
|
|
199
248
|
|
|
249
|
+
# Rebranding aliases to prevent double rebrands breaking things
|
|
250
|
+
# These are handled by the manifest now, but we keep some specific ones if needed
|
|
251
|
+
|
|
200
252
|
exact_replacements = [
|
|
201
253
|
("@~/.claude/commands/gsd/", "@references/commands/"),
|
|
202
254
|
("@$HOME/.claude/commands/gsd/", "@references/commands/"),
|
|
@@ -204,6 +256,8 @@ def refactor_content(target_base):
|
|
|
204
256
|
("@$HOME/.claude/get-shit-done/references/", "@references/docs/"),
|
|
205
257
|
("@~/.claude/get-shit-done/workflows/", "@references/workflows/"),
|
|
206
258
|
("@$HOME/.claude/get-shit-done/workflows/", "@references/workflows/"),
|
|
259
|
+
("@~/.claude/get-shit-done/contexts/", "@references/agents/profiles/"),
|
|
260
|
+
("@$HOME/.claude/get-shit-done/contexts/", "@references/agents/profiles/"),
|
|
207
261
|
("@~/.claude/get-shit-done/templates/", "@assets/templates/"),
|
|
208
262
|
("@$HOME/.claude/get-shit-done/templates/", "@assets/templates/"),
|
|
209
263
|
("@~/.claude/agents/", "@references/agents/"),
|
|
@@ -218,6 +272,7 @@ def refactor_content(target_base):
|
|
|
218
272
|
("path.join(homeDir, '.claude', 'get-shit-done'", "path.join(homeDir, '.gemini', 'antigravity', 'skills', 'gsd'")
|
|
219
273
|
]
|
|
220
274
|
|
|
275
|
+
# Pass 1: Content processing
|
|
221
276
|
for root, dirs, files in os.walk(target_base):
|
|
222
277
|
for file in files:
|
|
223
278
|
file_path = os.path.join(root, file)
|
|
@@ -231,8 +286,25 @@ def refactor_content(target_base):
|
|
|
231
286
|
for exact, repl in exact_replacements:
|
|
232
287
|
new_content = new_content.replace(exact, repl)
|
|
233
288
|
|
|
289
|
+
for pattern, replacement in standard_replacements:
|
|
290
|
+
new_content = pattern.sub(replacement, new_content)
|
|
291
|
+
|
|
234
292
|
for pattern, replacement in replacements:
|
|
235
|
-
new_content =
|
|
293
|
+
new_content = pattern.sub(replacement, new_content)
|
|
294
|
+
|
|
295
|
+
# Pass 2: Categorized path resolution for commands
|
|
296
|
+
# We need to find @references/commands/cmd.md and fix it
|
|
297
|
+
def fix_cmd_path(match):
|
|
298
|
+
p = match.group(1)
|
|
299
|
+
cmd_filename = os.path.basename(p)
|
|
300
|
+
cmd_name = cmd_filename[:-3] if cmd_filename.endswith('.md') else cmd_filename
|
|
301
|
+
category = get_command_category(cmd_name)
|
|
302
|
+
# Special case for modular or injected
|
|
303
|
+
if 'modular' in p: category = 'modular'
|
|
304
|
+
if cmd_name == 'gsd-tools': category = 'system'
|
|
305
|
+
return f"@references/commands/{category}/{cmd_filename}"
|
|
306
|
+
|
|
307
|
+
new_content = re.sub(r'@references/commands/([^/\s]+?\.md)', fix_cmd_path, new_content)
|
|
236
308
|
|
|
237
309
|
if new_content != content:
|
|
238
310
|
with open(file_path, 'w', encoding='utf-8') as f:
|
|
@@ -240,6 +312,13 @@ def refactor_content(target_base):
|
|
|
240
312
|
except Exception as e:
|
|
241
313
|
print(f" ⚠️ Error processing {file_path}: {e}")
|
|
242
314
|
|
|
315
|
+
# Metadata Injection
|
|
316
|
+
for root, dirs, files in os.walk(target_base):
|
|
317
|
+
for file in files:
|
|
318
|
+
file_path = os.path.join(root, file)
|
|
319
|
+
if file.endswith('.md') and 'commands' in root:
|
|
320
|
+
inject_metadata(file_path, version)
|
|
321
|
+
|
|
243
322
|
# Cleanup .bak files
|
|
244
323
|
for root, dirs, files in os.walk(target_base):
|
|
245
324
|
for file in files:
|
|
@@ -320,23 +399,34 @@ def scan_commands(target_base):
|
|
|
320
399
|
commands_dir = os.path.join(target_base, 'references', 'commands')
|
|
321
400
|
commands = []
|
|
322
401
|
if os.path.exists(commands_dir):
|
|
323
|
-
for
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
402
|
+
for root, dirs, files in os.walk(commands_dir):
|
|
403
|
+
for f in sorted(files):
|
|
404
|
+
if f.endswith('.md'):
|
|
405
|
+
cmd_name = f[:-3] # remove .md
|
|
406
|
+
file_path = os.path.join(root, f)
|
|
407
|
+
description = ""
|
|
408
|
+
try:
|
|
409
|
+
with open(file_path, 'r', encoding='utf-8') as cf:
|
|
410
|
+
text = cf.read()
|
|
411
|
+
# Parse frontmatter description
|
|
412
|
+
match = re.search(r'---[\s\S]*?description:\s*["\']?(.*?)["\']?\n[\s\S]*?---', text)
|
|
413
|
+
if match:
|
|
414
|
+
description = match.group(1).strip()
|
|
415
|
+
except Exception as e:
|
|
416
|
+
print(f" ⚠️ Error parsing {f}: {e}")
|
|
417
|
+
|
|
418
|
+
commands.append({'name': cmd_name, 'description': description})
|
|
419
|
+
|
|
420
|
+
# Sort into categories for SKILL.md
|
|
421
|
+
categorized = {}
|
|
422
|
+
for cmd in commands:
|
|
423
|
+
cat = get_command_category(cmd['name'])
|
|
424
|
+
# If it's in a different folder than its category, we should still respect it
|
|
425
|
+
# but for GSD commands we use the categorizer
|
|
426
|
+
if cat not in categorized: categorized[cat] = []
|
|
427
|
+
categorized[cat].append(cmd)
|
|
428
|
+
|
|
429
|
+
return categorized
|
|
340
430
|
|
|
341
431
|
def create_skill_md(target_base, skill_name, version):
|
|
342
432
|
skill_md_path = os.path.join(target_base, 'SKILL.md')
|
|
@@ -345,16 +435,22 @@ def create_skill_md(target_base, skill_name, version):
|
|
|
345
435
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
346
436
|
template_path = os.path.join(script_dir, '..', 'assets', 'gsd_skill_template.md')
|
|
347
437
|
|
|
348
|
-
|
|
438
|
+
categorized_commands = scan_commands(target_base)
|
|
439
|
+
|
|
440
|
+
# Flatten for triggers
|
|
441
|
+
all_commands = []
|
|
442
|
+
for cat in categorized_commands:
|
|
443
|
+
all_commands.extend(categorized_commands[cat])
|
|
349
444
|
|
|
350
445
|
# Format for triggers: - `gsd:command`
|
|
351
|
-
command_triggers_str = "\n".join([f"- `gsd:{cmd['name']}`" for cmd in
|
|
446
|
+
command_triggers_str = "\n".join([f"- `gsd:{cmd['name']}`" for cmd in sorted(all_commands, key=lambda x: x['name'])])
|
|
352
447
|
|
|
353
|
-
# Format for detailed list: bold command name with link
|
|
354
|
-
commands_list_str = "
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
448
|
+
# Format for detailed list: categorized bold command name with link
|
|
449
|
+
commands_list_str = ""
|
|
450
|
+
for cat in sorted(categorized_commands.keys()):
|
|
451
|
+
commands_list_str += f"\n### {cat.capitalize()} Commands\n"
|
|
452
|
+
for cmd in categorized_commands[cat]:
|
|
453
|
+
commands_list_str += f"- **[`gsd:{cmd['name']}`](references/commands/{cat}/{cmd['name']}.md)**: {cmd['description']}\n"
|
|
358
454
|
|
|
359
455
|
if not os.path.exists(template_path):
|
|
360
456
|
print(f" ⚠️ Template not found at {template_path}. Using fallback.")
|
|
@@ -373,32 +469,251 @@ Template missing.
|
|
|
373
469
|
title_name = skill_name.upper()
|
|
374
470
|
date_str = datetime.now().strftime('%Y-%m-%d')
|
|
375
471
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
commands_list=commands_list_str
|
|
384
|
-
)
|
|
385
|
-
except KeyError as e:
|
|
386
|
-
print(f" ⚠️ Error formatting template: {e}")
|
|
387
|
-
content = template_content
|
|
472
|
+
# Use .replace() instead of .format() to avoid issues with literal braces in the template
|
|
473
|
+
content = template_content.replace('{skill_name}', skill_name) \
|
|
474
|
+
.replace('{version}', version) \
|
|
475
|
+
.replace('{title_name}', title_name) \
|
|
476
|
+
.replace('{date}', date_str) \
|
|
477
|
+
.replace('{command_triggers}', command_triggers_str) \
|
|
478
|
+
.replace('{commands_list}', commands_list_str)
|
|
388
479
|
|
|
389
480
|
with open(skill_md_path, 'w', encoding='utf-8') as f:
|
|
390
481
|
f.write(content)
|
|
391
482
|
print(" ✅ Created SKILL.md from template with updated commands")
|
|
392
483
|
|
|
484
|
+
def run_regression_tests(target_base):
|
|
485
|
+
"""Run Phase 2 regression tests on the generated skill."""
|
|
486
|
+
print("🧪 Running regression tests...")
|
|
487
|
+
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
488
|
+
test_script = os.path.join(script_dir, 'regression_test.py')
|
|
489
|
+
|
|
490
|
+
if not os.path.exists(test_script):
|
|
491
|
+
# Create it if it doesn't exist (self-bootstrapping for this turn)
|
|
492
|
+
with open(test_script, 'w', encoding='utf-8') as f:
|
|
493
|
+
f.write("""import os, re, sys
|
|
494
|
+
def test_skill(base):
|
|
495
|
+
print(f" Checking {base}...")
|
|
496
|
+
errors = []
|
|
497
|
+
# 1. Check categorized paths
|
|
498
|
+
cmd_dir = os.path.join(base, 'references', 'commands')
|
|
499
|
+
if not os.path.exists(cmd_dir): return ["Commands dir missing"]
|
|
500
|
+
|
|
501
|
+
for root, dirs, files in os.walk(cmd_dir):
|
|
502
|
+
for f in files:
|
|
503
|
+
if f.endswith('.md'):
|
|
504
|
+
path = os.path.join(root, f)
|
|
505
|
+
with open(path, 'r', encoding='utf-8') as file:
|
|
506
|
+
content = file.read()
|
|
507
|
+
# Check metadata
|
|
508
|
+
if 'gsd-source-version' not in content:
|
|
509
|
+
errors.append(f"Missing metadata in {f}")
|
|
510
|
+
# Check internal inclusions
|
|
511
|
+
inclusions = re.findall(r"@references/commands/([^/]+?\\\\.md)", content)
|
|
512
|
+
if inclusions:
|
|
513
|
+
# Find where they should be
|
|
514
|
+
cmd_name = inclusions[0][:-3]
|
|
515
|
+
category = get_command_category(cmd_name)
|
|
516
|
+
errors.append(f"Broken inclusive path in {f}: {inclusions[0]}. Should be {category}/{inclusions[0]}")
|
|
517
|
+
return errors
|
|
518
|
+
|
|
519
|
+
if __name__ == '__main__':
|
|
520
|
+
target = sys.argv[1] if len(sys.argv) > 1 else '.'
|
|
521
|
+
errs = test_skill(target)
|
|
522
|
+
if errs:
|
|
523
|
+
for e in errs: print(f" ❌ {e}")
|
|
524
|
+
sys.exit(1)
|
|
525
|
+
print(" ✅ Regression tests passed.")
|
|
526
|
+
""")
|
|
527
|
+
|
|
528
|
+
try:
|
|
529
|
+
result = subprocess.run(
|
|
530
|
+
[sys.executable, test_script, target_base],
|
|
531
|
+
check=True,
|
|
532
|
+
capture_output=True,
|
|
533
|
+
text=True,
|
|
534
|
+
encoding='utf-8'
|
|
535
|
+
)
|
|
536
|
+
print(result.stdout)
|
|
537
|
+
except subprocess.CalledProcessError as e:
|
|
538
|
+
print(f" ❌ Regression tests failed!")
|
|
539
|
+
print(e.stdout)
|
|
540
|
+
print(e.stderr)
|
|
541
|
+
return False
|
|
542
|
+
return True
|
|
543
|
+
|
|
544
|
+
def discover_source_structure(source_base):
|
|
545
|
+
"""Scan .claude for directories and identify unmapped ones."""
|
|
546
|
+
print("🔍 Discovering source structure...")
|
|
547
|
+
mappings = [
|
|
548
|
+
'commands/gsd/',
|
|
549
|
+
'get-shit-done/references/',
|
|
550
|
+
'get-shit-done/workflows/',
|
|
551
|
+
'get-shit-done/contexts/',
|
|
552
|
+
'agents/',
|
|
553
|
+
'get-shit-done/templates/',
|
|
554
|
+
'get-shit-done/bin/',
|
|
555
|
+
'hooks/',
|
|
556
|
+
'skills/'
|
|
557
|
+
]
|
|
558
|
+
|
|
559
|
+
# Directories we expect to see as parents but aren't mapped directly
|
|
560
|
+
allowed_parents = ['', 'commands', 'get-shit-done']
|
|
561
|
+
|
|
562
|
+
unmapped = []
|
|
563
|
+
for root, dirs, files in os.walk(source_base):
|
|
564
|
+
rel_root = os.path.relpath(root, source_base).replace('\\', '/')
|
|
565
|
+
if rel_root == '.': rel_root = ''
|
|
566
|
+
|
|
567
|
+
if rel_root not in allowed_parents and not any(rel_root.startswith(m.strip('/')) for m in mappings):
|
|
568
|
+
# This dir itself might be unmapped
|
|
569
|
+
if rel_root + '/' not in mappings:
|
|
570
|
+
unmapped.append(rel_root)
|
|
571
|
+
|
|
572
|
+
# Check subdirs of current root
|
|
573
|
+
for d in dirs:
|
|
574
|
+
full_rel = os.path.join(rel_root, d).replace('\\', '/') + '/'
|
|
575
|
+
if full_rel not in mappings and os.path.dirname(full_rel.strip('/')) in allowed_parents:
|
|
576
|
+
unmapped.append(full_rel)
|
|
577
|
+
|
|
578
|
+
# Deduplicate and filter out parents
|
|
579
|
+
unmapped = sorted(list(set([u for u in unmapped if u.strip('/') not in allowed_parents])))
|
|
580
|
+
|
|
581
|
+
if unmapped:
|
|
582
|
+
print(f" ⚠️ Found unmapped directories in source: {', '.join(unmapped)}")
|
|
583
|
+
else:
|
|
584
|
+
print(" ✅ All recognized source directories are mapped.")
|
|
585
|
+
return unmapped
|
|
586
|
+
|
|
587
|
+
def audit_spec(manifest):
|
|
588
|
+
"""Verify code mappings against internal mapping.md documentation."""
|
|
589
|
+
print("📋 Auditing code against spec (mapping.md)...")
|
|
590
|
+
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
591
|
+
mapping_md_path = os.path.abspath(os.path.join(script_dir, '..', 'references', 'mapping.md'))
|
|
592
|
+
|
|
593
|
+
if not os.path.exists(mapping_md_path):
|
|
594
|
+
print(" ⚠️ mapping.md not found, skipping spec audit.")
|
|
595
|
+
return True
|
|
596
|
+
|
|
597
|
+
try:
|
|
598
|
+
with open(mapping_md_path, 'r', encoding='utf-8') as f:
|
|
599
|
+
content = f.read()
|
|
600
|
+
|
|
601
|
+
# Simple extraction of | .claude/path | ... |
|
|
602
|
+
spec_paths = re.findall(r'\|\s*`\.claude/(.*?)`\s*\|', content)
|
|
603
|
+
code_paths = [m['source'] for m in manifest['mappings']]
|
|
604
|
+
|
|
605
|
+
mismatches = []
|
|
606
|
+
for sp in spec_paths:
|
|
607
|
+
if sp not in code_paths:
|
|
608
|
+
mismatches.append(f"Spec path '{sp}' missing in code")
|
|
609
|
+
for cp in code_paths:
|
|
610
|
+
if cp not in spec_paths:
|
|
611
|
+
mismatches.append(f"Code path '{cp}' missing in spec")
|
|
612
|
+
|
|
613
|
+
if mismatches:
|
|
614
|
+
print(" ❌ Spec Audit Failed:")
|
|
615
|
+
for m in mismatches:
|
|
616
|
+
print(f" - {m}")
|
|
617
|
+
return False
|
|
618
|
+
|
|
619
|
+
print(" ✅ Code mappings are in sync with mapping.md.")
|
|
620
|
+
return True
|
|
621
|
+
except Exception as e:
|
|
622
|
+
print(f" ⚠️ Error during spec audit: {e}")
|
|
623
|
+
return False
|
|
624
|
+
|
|
625
|
+
def verify_migration(target_base):
|
|
626
|
+
"""Pre-flight check for the migrated skill."""
|
|
627
|
+
print("🛡️ Verifying migrated skill integrity...")
|
|
628
|
+
checks = [
|
|
629
|
+
(os.path.join(target_base, 'bin', 'gsd-tools.cjs'), "GSD Tools CLI"),
|
|
630
|
+
(os.path.join(target_base, 'bin', 'help-manifest.json'), "Help Manifest"),
|
|
631
|
+
(os.path.join(target_base, 'references', 'commands'), "Commands Directory"),
|
|
632
|
+
(os.path.join(target_base, 'references', 'agents', 'profiles'), "Context Profiles"),
|
|
633
|
+
(os.path.join(target_base, 'references', 'agents'), "Agents Directory"),
|
|
634
|
+
(os.path.join(target_base, 'SKILL.md'), "Skill Specification")
|
|
635
|
+
]
|
|
636
|
+
|
|
637
|
+
failures = []
|
|
638
|
+
for path, label in checks:
|
|
639
|
+
if not os.path.exists(path):
|
|
640
|
+
failures.append(f"Missing {label}: {path}")
|
|
641
|
+
|
|
642
|
+
# Check if commands dir is empty
|
|
643
|
+
cmd_dir = os.path.join(target_base, 'references', 'commands')
|
|
644
|
+
if os.path.exists(cmd_dir) and not os.listdir(cmd_dir):
|
|
645
|
+
failures.append("Commands directory is empty - migration likely failed to copy core prompts.")
|
|
646
|
+
|
|
647
|
+
if failures:
|
|
648
|
+
print(" ❌ Verification Failed:")
|
|
649
|
+
for f in failures:
|
|
650
|
+
print(f" - {f}")
|
|
651
|
+
return False
|
|
652
|
+
|
|
653
|
+
print(" ✅ Skill integrity verified.")
|
|
654
|
+
return True
|
|
655
|
+
|
|
656
|
+
def sync_mapping_docs(target_base, manifest):
|
|
657
|
+
"""Regenerate mapping.md from manifest to ensure documentation is always in sync."""
|
|
658
|
+
print("📝 Syncing mapping.md documentation from manifest...")
|
|
659
|
+
|
|
660
|
+
docs_to_sync = [
|
|
661
|
+
os.path.join(target_base, 'references', 'mapping.md')
|
|
662
|
+
]
|
|
663
|
+
|
|
664
|
+
# Also sync the converter's own reference if it exists
|
|
665
|
+
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
666
|
+
internal_mapping = os.path.abspath(os.path.join(script_dir, '..', 'references', 'mapping.md'))
|
|
667
|
+
if os.path.exists(internal_mapping):
|
|
668
|
+
docs_to_sync.append(internal_mapping)
|
|
669
|
+
|
|
670
|
+
content = [
|
|
671
|
+
"# Path Mapping Reference",
|
|
672
|
+
"",
|
|
673
|
+
"When converting from a standard GSD installation to an Antigravity Skill, paths are refactored to ensure the skill is self-contained and portable.",
|
|
674
|
+
"",
|
|
675
|
+
"## Directory Mapping",
|
|
676
|
+
"",
|
|
677
|
+
"| Source GSD Path | Target Skill Path | Purpose |",
|
|
678
|
+
"|-----------------|-------------------|---------|"
|
|
679
|
+
]
|
|
680
|
+
|
|
681
|
+
for m in manifest['mappings']:
|
|
682
|
+
content.append(f"| `.claude/{m['source']}` | `{m['target']}` | {m['purpose']} |")
|
|
683
|
+
|
|
684
|
+
content.extend([
|
|
685
|
+
"",
|
|
686
|
+
"## Project Context",
|
|
687
|
+
"References to `@.planning/` are **preserved**, as these refer to the active project's local planning directory, not the skill's own resources.",
|
|
688
|
+
"",
|
|
689
|
+
"---",
|
|
690
|
+
f"*Generated by gsd-converter on {datetime.now().strftime('%Y-%m-%d')}*"
|
|
691
|
+
])
|
|
692
|
+
|
|
693
|
+
markdown = "\n".join(content)
|
|
694
|
+
|
|
695
|
+
for path in docs_to_sync:
|
|
696
|
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
697
|
+
with open(path, 'w', encoding='utf-8') as f:
|
|
698
|
+
f.write(markdown)
|
|
699
|
+
print(f" ✅ {os.path.basename(os.path.dirname(os.path.dirname(path)))} mapping.md updated.")
|
|
700
|
+
|
|
393
701
|
def main():
|
|
394
702
|
args = setup_args()
|
|
703
|
+
manifest = load_manifest()
|
|
395
704
|
|
|
396
705
|
# Enforce 'gsd' as the skill name
|
|
397
706
|
skill_name = 'gsd'
|
|
398
707
|
target_base = os.path.abspath(os.path.join(args.path, skill_name))
|
|
399
708
|
source_base = args.source
|
|
400
709
|
|
|
401
|
-
|
|
710
|
+
# 1. Audit Spec
|
|
711
|
+
audit_spec(manifest)
|
|
712
|
+
|
|
713
|
+
# 2. Discover Structure
|
|
714
|
+
unmapped_dirs = discover_source_structure(source_base)
|
|
715
|
+
|
|
716
|
+
print(f"\n🧹 Cleaning up existing skill folder: {target_base}")
|
|
402
717
|
if os.path.exists(target_base):
|
|
403
718
|
# Retry logic for Windows directory locking issues
|
|
404
719
|
import time
|
|
@@ -424,9 +739,10 @@ def main():
|
|
|
424
739
|
os.makedirs(target_base, exist_ok=True)
|
|
425
740
|
|
|
426
741
|
# 3. Perform migration and refactoring
|
|
427
|
-
migrate_files(source_base, target_base)
|
|
742
|
+
migrate_files(source_base, target_base, manifest)
|
|
428
743
|
|
|
429
|
-
refactor_content(target_base)
|
|
744
|
+
refactor_content(target_base, new_version, manifest)
|
|
745
|
+
sync_mapping_docs(target_base, manifest)
|
|
430
746
|
optimize_gsd_tools(target_base)
|
|
431
747
|
|
|
432
748
|
# 4. Inject Dynamic Help Manifest
|
|
@@ -449,9 +765,12 @@ def main():
|
|
|
449
765
|
|
|
450
766
|
# 5. Inject custom assets
|
|
451
767
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
768
|
+
|
|
769
|
+
# Write VERSION file to skill root
|
|
770
|
+
with open(os.path.join(target_base, 'VERSION'), 'w', encoding='utf-8') as f:
|
|
771
|
+
f.write(new_version)
|
|
772
|
+
|
|
773
|
+
custom_assets = [(a['name'], a['target_rel']) for a in manifest.get('injected_assets', [])]
|
|
455
774
|
for asset_name, target_rel in custom_assets:
|
|
456
775
|
asset_path = os.path.join(script_dir, '..', 'assets', asset_name)
|
|
457
776
|
target_path = os.path.join(target_base, target_rel)
|
|
@@ -468,6 +787,26 @@ def main():
|
|
|
468
787
|
|
|
469
788
|
create_skill_md(target_base, skill_name, new_version)
|
|
470
789
|
|
|
790
|
+
# 6. Final Verification
|
|
791
|
+
verify_migration(target_base)
|
|
792
|
+
|
|
793
|
+
# 7. Regression Testing
|
|
794
|
+
run_regression_tests(target_base)
|
|
795
|
+
|
|
796
|
+
# 8. Generate Report
|
|
797
|
+
report_path = os.path.join(target_base, 'migration_report.md')
|
|
798
|
+
with open(report_path, 'w', encoding='utf-8') as f:
|
|
799
|
+
f.write(f"# GSD Migration Report\n\n")
|
|
800
|
+
f.write(f"- **Timestamp**: {datetime.now().isoformat()}\n")
|
|
801
|
+
f.write(f"- **Version**: {old_version} -> {new_version}\n")
|
|
802
|
+
f.write(f"- **Skill Name**: {skill_name}\n")
|
|
803
|
+
if unmapped_dirs:
|
|
804
|
+
f.write(f"\n### ⚠️ Unmapped Source Directories\n")
|
|
805
|
+
for d in unmapped_dirs:
|
|
806
|
+
f.write(f"- {d}\n")
|
|
807
|
+
else:
|
|
808
|
+
f.write(f"\n✅ All recognized source directories were successfully mapped and migrated.\n")
|
|
809
|
+
|
|
471
810
|
print(f"\n{'='*40}")
|
|
472
811
|
print(f"✨ Dynamic Skill '{skill_name}' is ready at {target_base}")
|
|
473
812
|
print(f"📊 GSD Version: {old_version} -> {new_version}\n")
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import os, re, sys
|
|
2
|
+
def test_skill(base):
|
|
3
|
+
print(f" Checking {base}...")
|
|
4
|
+
errors = []
|
|
5
|
+
# 1. Check categorized paths
|
|
6
|
+
cmd_dir = os.path.join(base, 'references', 'commands')
|
|
7
|
+
if not os.path.exists(cmd_dir): return ["Commands dir missing"]
|
|
8
|
+
|
|
9
|
+
for root, dirs, files in os.walk(cmd_dir):
|
|
10
|
+
for f in files:
|
|
11
|
+
if f.endswith('.md'):
|
|
12
|
+
path = os.path.join(root, f)
|
|
13
|
+
with open(path, 'r', encoding='utf-8') as file:
|
|
14
|
+
content = file.read()
|
|
15
|
+
# Check metadata
|
|
16
|
+
if 'gsd-source-version' not in content:
|
|
17
|
+
errors.append(f"Missing metadata in {f}")
|
|
18
|
+
# Check internal inclusions
|
|
19
|
+
inclusions = re.findall(r"@references/commands/([^/]+?\\.md)", content)
|
|
20
|
+
if inclusions:
|
|
21
|
+
# Find where they should be
|
|
22
|
+
cmd_name = inclusions[0][:-3]
|
|
23
|
+
category = get_command_category(cmd_name)
|
|
24
|
+
errors.append(f"Broken inclusive path in {f}: {inclusions[0]}. Should be {category}/{inclusions[0]}")
|
|
25
|
+
return errors
|
|
26
|
+
|
|
27
|
+
if __name__ == '__main__':
|
|
28
|
+
target = sys.argv[1] if len(sys.argv) > 1 else '.'
|
|
29
|
+
errs = test_skill(target)
|
|
30
|
+
if errs:
|
|
31
|
+
for e in errs: print(f" ❌ {e}")
|
|
32
|
+
sys.exit(1)
|
|
33
|
+
print(" ✅ Regression tests passed.")
|