@theglitchking/babel-fish 1.0.2 → 2.0.1

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 (58) hide show
  1. package/.claude/install.sh +665 -0
  2. package/.claude/project-map/PROJECT_MAP.md +61 -0
  3. package/.claude/project-map/__pycache__/generate.cpython-312.pyc +0 -0
  4. package/.claude/project-map/checksums.json +6 -0
  5. package/.claude/project-map/generate.py +1494 -0
  6. package/.claude/project-map/grader.py +583 -0
  7. package/.claude/project-map/learned-vocabulary.json +1 -0
  8. package/.claude/project-map/mine-sessions.py +419 -0
  9. package/.claude/project-map/reports/install-report.md +54 -0
  10. package/.claude/project-map/reports/iteration-01-report.md +54 -0
  11. package/.claude/project-map/reports/iteration-01-score.json +7 -0
  12. package/.claude/project-map/sections/01-vocabulary.md +8 -0
  13. package/.claude/project-map/sections/02-service-topology.md +6 -0
  14. package/.claude/project-map/sections/03-environment.md +6 -0
  15. package/.claude/project-map/sections/04-api-routes.md +6 -0
  16. package/.claude/project-map/sections/05-data-models.md +4 -0
  17. package/.claude/project-map/sections/06-schemas.md +4 -0
  18. package/.claude/project-map/sections/07-services.md +6 -0
  19. package/.claude/project-map/sections/08-background-jobs.md +5 -0
  20. package/.claude/project-map/sections/09-frontend-features.md +4 -0
  21. package/.claude/project-map/sections/10-tools-commands.md +8 -0
  22. package/.claude/project-map/sections/11-migrations.md +4 -0
  23. package/.claude/project-map/sections/12-import-chains.md +7 -0
  24. package/.claude/project-map/sections/13-frontend-backend-map.md +8 -0
  25. package/.claude/project-map/sections/14-reverse-proxy.md +4 -0
  26. package/.claude/project-map/sections/15-auth-config.md +6 -0
  27. package/.claude/project-map/sections/16-infra-profile.md +13 -0
  28. package/.claude/project-map/sections/17-learned-vocabulary.md +7 -0
  29. package/.claude/project-map/sections/18-dead-code.md +9 -0
  30. package/.claude/project-map/sections/19-doc-pointers.md +5 -0
  31. package/.claude/project-map/stack.json +12 -0
  32. package/.claude/rules/operational-runbook.md +40 -0
  33. package/.claude/rules/project-vocabulary.md +25 -0
  34. package/.claude/scripts/detect-stack.sh +222 -0
  35. package/.claude/scripts/ensure-python.sh +100 -0
  36. package/.claude/scripts/statusline.sh +27 -0
  37. package/.claude/scripts/validate.sh +59 -0
  38. package/.claude/settings.json +6 -0
  39. package/.claude/settings.local.json +6 -0
  40. package/.claude/skills/babel-fish-developer-skill/SKILL.md +56 -0
  41. package/.claude/templates/SKILL.md.template +56 -0
  42. package/.claude/templates/operational-runbook.md.template +40 -0
  43. package/.claude/templates/project-vocabulary.md.template +25 -0
  44. package/.claude-plugin/marketplace.json +2 -2
  45. package/.claude-plugin/plugin.json +1 -1
  46. package/.githooks/install.sh +4 -0
  47. package/.githooks/pre-commit +22 -0
  48. package/CHANGELOG.md +88 -0
  49. package/README.md +21 -0
  50. package/bin/babel-fish.js +78 -71
  51. package/commands/policy.md +16 -0
  52. package/commands/relink.md +6 -0
  53. package/commands/status.md +6 -0
  54. package/commands/update.md +6 -0
  55. package/hooks/hooks.json +15 -0
  56. package/hooks/session-start.js +11 -0
  57. package/package.json +19 -3
  58. package/scripts/link-skills.js +31 -0
@@ -0,0 +1,665 @@
1
+ #!/bin/bash
2
+ # ============================================================
3
+ # Babel Fish Plugin — Installer
4
+ # Triggered automatically on plugin installation.
5
+ #
6
+ # What this does:
7
+ # 1. Checks / installs Python >= 3.8
8
+ # 2. Detects project stack
9
+ # 3. Runs generate.py → grades with grader.py (up to 3 iterations)
10
+ # 4. Renders skill + rules files from templates
11
+ # 5. Installs git hooks
12
+ # 6. Prints a final summary with the grade report path
13
+ #
14
+ # Usage:
15
+ # bash .claude/install.sh [project-root]
16
+ # ============================================================
17
+
18
+ set -euo pipefail
19
+
20
+ # ── Help ──────────────────────────────────────────────────────────────────────
21
+ if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
22
+ cat <<'HELP'
23
+
24
+ ╔══════════════════════════════════════════════════════════════════╗
25
+ ║ Babel Fish Plugin — Help ║
26
+ ╚══════════════════════════════════════════════════════════════════╝
27
+
28
+ WHAT IT DOES
29
+ Builds a self-updating developer context system for your repo:
30
+ - Project map split into 19 focused sections (routes, models, infra, etc.)
31
+ - Vocabulary translator: maps plain English to exact file paths
32
+ - Developer skill auto-loaded in every Claude Code session
33
+ - Operational runbook for gotchas and deploy procedures
34
+ - Pre-commit hook that keeps the map current automatically
35
+ - Iterative quality grading (0-100%) with a 90% pass threshold
36
+
37
+ REQUIREMENTS
38
+ - Claude Code >= 1.0.0
39
+ - Python >= 3.8 (auto-installed if missing)
40
+ - bash
41
+ - Optional: pip install pyyaml (for docker-compose parsing)
42
+
43
+ INSTALLATION
44
+ Preview all changes first (nothing is modified):
45
+
46
+ bash .claude/install.sh --dry-run
47
+
48
+ Run the installer:
49
+
50
+ bash .claude/install.sh
51
+
52
+ Or with an explicit project root:
53
+
54
+ bash .claude/install.sh /path/to/your/project
55
+
56
+ One-liner from the internet (checksum-verified):
57
+
58
+ curl -sSL https://raw.githubusercontent.com/TheGlitchKing/babel-fish/main/install.sh | bash
59
+
60
+ Preview before running remotely:
61
+
62
+ curl -sSL https://raw.githubusercontent.com/TheGlitchKing/babel-fish/main/install.sh | bash -s -- --dry-run
63
+
64
+ Via npm (no curl needed):
65
+
66
+ npx @theglitchking/babel-fish dry-run
67
+ npx @theglitchking/babel-fish init
68
+
69
+ Via the Glitch Kingdom Marketplace in Claude Code:
70
+
71
+ /plugin marketplace add TheGlitchKing/glitch-kingdom-of-plugins
72
+ /plugin install TheGlitchKing/babel-fish
73
+
74
+ WHAT HAPPENS ON INSTALL
75
+ 1. Python >= 3.8 is checked and installed if missing
76
+ 2. Stack is detected (language, framework, DB, ORM, auth, infra)
77
+ 3. generate.py runs to build the 19-section project map
78
+ 4. grader.py scores the output 0-100% across 7 categories
79
+ 5. If score < 90%, it retries up to 3 times automatically
80
+ 6. Skills and rules files are rendered from templates
81
+ 7. Pre-commit git hook is installed
82
+ 8. CLAUDE.md is updated with a project map pointer
83
+ 9. A final quality report is written to:
84
+ .claude/project-map/reports/install-report.md
85
+
86
+ POST-INSTALL COMMANDS
87
+ Regenerate the map (forced):
88
+ python .claude/project-map/generate.py --force
89
+
90
+ Regenerate only if files changed (fast, used by pre-commit):
91
+ python .claude/project-map/generate.py
92
+
93
+ Re-grade the current map output:
94
+ python .claude/project-map/grader.py
95
+
96
+ Mine past Claude Code sessions for vocabulary aliases:
97
+ python .claude/project-map/mine-sessions.py
98
+ python .claude/project-map/mine-sessions.py --verbose
99
+ python .claude/project-map/mine-sessions.py --dry-run
100
+
101
+ Re-install git hooks (if you cloned a fresh copy):
102
+ bash .githooks/install.sh
103
+
104
+ Re-run the full installer:
105
+ bash .claude/install.sh
106
+
107
+ USING THE DEVELOPER SKILL
108
+ After install, invoke your project skill in Claude Code:
109
+
110
+ /babel-fish-developer (or /<your-project-slug>-developer)
111
+
112
+ The skill reads PROJECT_MAP.md and loads only the 2-3 sections
113
+ relevant to your current task (typically 5-20KB of context).
114
+
115
+ KEY FILES AFTER INSTALL
116
+ .claude/project-map/PROJECT_MAP.md — Map index + quick routing
117
+ .claude/project-map/sections/01-*.md — Vocabulary translator
118
+ .claude/project-map/sections/04-*.md — API routes
119
+ .claude/project-map/sections/05-*.md — Data models
120
+ .claude/project-map/reports/install-report.md — Quality report
121
+ .claude/rules/project-vocabulary.md — Auto-loaded every session
122
+ .claude/rules/operational-runbook.md — Edit manually to grow over time
123
+ .claude/skills/<slug>-developer-skill/ — Your developer skill
124
+ .githooks/pre-commit — Auto-regenerates map on commit
125
+
126
+ GRADING CATEGORIES (90% to pass)
127
+ Section completeness 25% — All 19 sections generated
128
+ Vocabulary accuracy 20% — Entries map to real files
129
+ Import chain validity 15% — Chains trace to real modules
130
+ Secret safety 15% — No API keys or tokens leaked
131
+ Section size bounds 10% — Each section 0.1-50KB
132
+ Structural integrity 10% — Valid markdown, working TOC links
133
+ Checksum function 5% — Re-run skips when nothing changed
134
+
135
+ EXAMPLES
136
+ # Install on current directory
137
+ bash .claude/install.sh
138
+
139
+ # Install on a specific project
140
+ bash .claude/install.sh /mnt/e/my-project
141
+
142
+ # Force-regenerate after adding new routes
143
+ python .claude/project-map/generate.py --force
144
+
145
+ # Check map quality after a big refactor
146
+ python .claude/project-map/grader.py
147
+
148
+ # See what vocabulary aliases were learned from your sessions
149
+ python .claude/project-map/mine-sessions.py --dry-run --verbose
150
+
151
+ HELP
152
+
153
+ exit 0
154
+ fi
155
+
156
+ # ── Argument parsing ─────────────────────────────────────────────────────────
157
+ DRY_RUN=false
158
+ POSITIONAL=""
159
+ for arg in "$@"; do
160
+ case "$arg" in
161
+ --dry-run) DRY_RUN=true ;;
162
+ -*) ;; # ignore unknown flags
163
+ *) POSITIONAL="$arg" ;;
164
+ esac
165
+ done
166
+
167
+ # Resolve absolute path immediately
168
+ PROJECT_ROOT="$(cd "${POSITIONAL:-$(pwd)}" && pwd)"
169
+ PLUGIN_SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
170
+ CLAUDE_DIR="$PROJECT_ROOT/.claude"
171
+ MAP_DIR="$CLAUDE_DIR/project-map"
172
+ REPORTS_DIR="$MAP_DIR/reports"
173
+ SCRIPTS_DIR="$CLAUDE_DIR/scripts"
174
+ TEMPLATES_DIR="$CLAUDE_DIR/templates"
175
+
176
+ MAX_ITERATIONS=3
177
+ PASS_THRESHOLD=90
178
+ PREVIOUS_SCORE=""
179
+
180
+ # Dry-run helper — prints the action instead of doing it
181
+ _dry() { printf '%b\n' "${YELLOW} [dry-run] $*${RESET}"; }
182
+
183
+ # ── Colors ───────────────────────────────────────────────────────────────────
184
+ CYAN='\033[36m'; GREEN='\033[32m'; YELLOW='\033[33m'; RED='\033[31m'
185
+ BOLD='\033[1m'; RESET='\033[0m'
186
+
187
+ banner() { printf '\n%b\n' "${CYAN}${BOLD}══ $* ══${RESET}"; }
188
+ step() { printf '%b\n' "${CYAN}▶ $*${RESET}"; }
189
+ ok() { printf '%b\n' "${GREEN}✓ $*${RESET}"; }
190
+ warn() { printf '%b\n' "${YELLOW}⚠ $*${RESET}"; }
191
+ fail() { printf '%b\n' "${RED}✗ $*${RESET}"; }
192
+ info() { printf '%b\n' " $*"; }
193
+
194
+
195
+ # ╔══════════════════════════════════════════════════════════════════════════╗
196
+ # ║ HELPER FUNCTIONS (must be defined before main flow) ║
197
+ # ╚══════════════════════════════════════════════════════════════════════════╝
198
+
199
+ _improve_for_next_iteration() {
200
+ local score_json="$1"
201
+ local python_cmd="$3"
202
+
203
+ [ -f "$score_json" ] || return
204
+
205
+ local issues
206
+ issues=$("$python_cmd" -c "
207
+ import json
208
+ d = json.load(open('$score_json'))
209
+ for issue in d.get('issues', []):
210
+ print(issue['category'] + ': ' + issue['issue'])
211
+ " 2>/dev/null || true)
212
+
213
+ if [ -n "$issues" ]; then
214
+ info "Issues from previous iteration:"
215
+ echo "$issues" | while IFS= read -r line; do
216
+ info " → $line"
217
+ done
218
+ fi
219
+ info "Will re-run generate.py with --force for next iteration..."
220
+ }
221
+
222
+ _render_vocabulary() {
223
+ local project_root="$1"
224
+ local name="$2"
225
+ local lang="$3"
226
+ local framework="$4"
227
+ local rules_dir="$5"
228
+ local out="$rules_dir/project-vocabulary.md"
229
+ local template="$TEMPLATES_DIR/project-vocabulary.md.template"
230
+
231
+ if [ -f "$template" ]; then
232
+ sed \
233
+ -e "s|{{PROJECT_NAME}}|$name|g" \
234
+ -e "s|{{LANGUAGE}}|$lang|g" \
235
+ -e "s|{{FRAMEWORK}}|$framework|g" \
236
+ "$template" > "$out"
237
+ else
238
+ cat > "$out" <<VOCAB
239
+ # ${name} — Project Vocabulary
240
+
241
+ > Auto-loaded every session. Maps human language to exact code locations.
242
+
243
+ ## Feature → Code Location
244
+
245
+ | You Say | Frontend | Backend | Model/Table |
246
+ |---------|----------|---------|-------------|
247
+ | _(vocabulary populates as source code is added)_ | | | |
248
+
249
+ ## Quick Actions
250
+
251
+ | You Say | What To Do |
252
+ |---------|-----------|
253
+ | regenerate map | \`python .claude/project-map/generate.py --force\` |
254
+ | grade map | \`python .claude/project-map/grader.py\` |
255
+ VOCAB
256
+ fi
257
+ ok "Rendered: $out"
258
+ }
259
+
260
+ _render_runbook() {
261
+ local name="$2"
262
+ local rules_dir="$3"
263
+ local out="$rules_dir/operational-runbook.md"
264
+ local template="$TEMPLATES_DIR/operational-runbook.md.template"
265
+
266
+ if [ -f "$out" ]; then
267
+ ok "Runbook already exists — preserving: $out"
268
+ return
269
+ fi
270
+
271
+ if [ -f "$template" ]; then
272
+ sed -e "s|{{PROJECT_NAME}}|$name|g" "$template" > "$out"
273
+ else
274
+ cat > "$out" <<RUNBOOK
275
+ # ${name} — Operational Runbook
276
+
277
+ > Auto-loaded every session. Edit this file manually — NOT overwritten on regeneration.
278
+
279
+ ## Environment Differences
280
+
281
+ | | Dev | Staging | Production |
282
+ |---|---|---|---|
283
+ | **URL** | | | |
284
+ | **Database** | | | |
285
+
286
+ ## Known Issues & Workarounds
287
+
288
+ _No known issues documented yet._
289
+
290
+ ## Key Commands
291
+
292
+ | Command | What It Does |
293
+ |---------|-------------|
294
+ | \`python .claude/project-map/generate.py --force\` | Regenerate project map |
295
+ | \`python .claude/project-map/grader.py\` | Grade map quality |
296
+ RUNBOOK
297
+ fi
298
+ ok "Rendered: $out"
299
+ }
300
+
301
+ _render_skill() {
302
+ local project_root="$1"
303
+ local name="$2"
304
+ local slug="$3"
305
+ local lang="$4"
306
+ local framework="$5"
307
+ local skills_dir="$6"
308
+ local out="$skills_dir/SKILL.md"
309
+ local template="$TEMPLATES_DIR/SKILL.md.template"
310
+
311
+ if [ -f "$template" ]; then
312
+ sed \
313
+ -e "s|{{PROJECT_NAME}}|$name|g" \
314
+ -e "s|{{PROJECT_SLUG}}|$slug|g" \
315
+ -e "s|{{LANGUAGE}}|$lang|g" \
316
+ -e "s|{{FRAMEWORK}}|$framework|g" \
317
+ "$template" > "$out"
318
+ else
319
+ cat > "$out" <<SKILL
320
+ ---
321
+ name: ${slug}-developer-skill
322
+ description: |
323
+ Full-stack developer context for ${name} (${lang}/${framework}).
324
+ Invoke when working on any ${name} feature, bug, or infrastructure task.
325
+ ---
326
+
327
+ # /${slug}-developer — ${name} Developer Context
328
+
329
+ ## On Trigger
330
+
331
+ \`\`\`
332
+ Read: .claude/project-map/PROJECT_MAP.md
333
+ \`\`\`
334
+
335
+ Use the Quick Routing table to pick 2-3 sections to load.
336
+
337
+ ## Section Routing
338
+
339
+ | Task | Read These Sections |
340
+ |------|-------------------|
341
+ | Feature / UX work | 01-vocabulary → 09-frontend → 04-routes |
342
+ | Add a model or field | 05-models → 06-schemas → 12-import-chains |
343
+ | Troubleshoot error | 02-topology → 03-environment → 14-proxy |
344
+ | Infrastructure | 16-infra-profile → 02-topology |
345
+ | Auth / security | 15-auth-config |
346
+ | Tools | 10-tools-commands |
347
+
348
+ ## Stack: ${lang} / ${framework}
349
+ SKILL
350
+ fi
351
+ ok "Rendered: $out"
352
+ }
353
+
354
+ _install_git_hooks() {
355
+ local project_root="$1"
356
+ local hooks_dir="$2"
357
+ local pre_commit="$hooks_dir/pre-commit"
358
+
359
+ local hook_snippet='# ── Codebase Mapper: regenerate project map on relevant changes ──
360
+ STAGED_FILES=$(git diff --cached --name-only 2>/dev/null || true)
361
+ EXTENSIONS_PATTERN='"'"'\.(py|ts|tsx|js|jsx|go|java|yaml|yml)$|docker-compose|package\.json|Cargo\.toml|go\.mod'"'"'
362
+ if echo "$STAGED_FILES" | grep -qE "$EXTENSIONS_PATTERN" 2>/dev/null; then
363
+ MAP_SCRIPT=".claude/project-map/generate.py"
364
+ if [ -f "$MAP_SCRIPT" ]; then
365
+ PYTHON=""
366
+ if [ -f ".venv/bin/python3" ]; then PYTHON=".venv/bin/python3"
367
+ elif command -v python3 &>/dev/null; then PYTHON="python3"
368
+ elif command -v python &>/dev/null; then PYTHON="python"
369
+ fi
370
+ if [ -n "$PYTHON" ]; then
371
+ echo "[codebase-mapper] Regenerating project map..."
372
+ if $PYTHON "$MAP_SCRIPT" 2>/dev/null; then
373
+ git add .claude/project-map/PROJECT_MAP.md .claude/project-map/checksums.json \
374
+ .claude/project-map/sections/*.md .claude/project-map/learned-vocabulary.json 2>/dev/null || true
375
+ fi
376
+ fi
377
+ fi
378
+ fi
379
+ # ── End Codebase Mapper ──────────────────────────────────────────────────────'
380
+
381
+ if [ -f "$pre_commit" ]; then
382
+ if ! grep -q 'Codebase Mapper' "$pre_commit" 2>/dev/null; then
383
+ { echo ""; echo "$hook_snippet"; } >> "$pre_commit"
384
+ ok "Appended to existing pre-commit hook"
385
+ else
386
+ ok "pre-commit hook already contains Codebase Mapper snippet"
387
+ fi
388
+ else
389
+ printf '#!/bin/bash\n%s\n' "$hook_snippet" > "$pre_commit"
390
+ ok "Created pre-commit hook"
391
+ fi
392
+
393
+ chmod +x "$pre_commit"
394
+
395
+ cat > "$hooks_dir/install.sh" <<'INSTALL'
396
+ #!/bin/bash
397
+ git config core.hooksPath .githooks
398
+ chmod +x .githooks/*
399
+ echo "Git hooks installed (.githooks/ directory configured)"
400
+ INSTALL
401
+ chmod +x "$hooks_dir/install.sh"
402
+
403
+ if git -C "$project_root" rev-parse --git-dir > /dev/null 2>&1; then
404
+ git -C "$project_root" config core.hooksPath .githooks
405
+ ok "Configured git to use .githooks/"
406
+ fi
407
+ }
408
+
409
+ _update_claude_md() {
410
+ local project_root="$1"
411
+ local name="$2"
412
+ local claude_md="$project_root/.claude/CLAUDE.md"
413
+
414
+ if [ -f "$claude_md" ] && grep -q 'Project Map' "$claude_md" 2>/dev/null; then
415
+ ok "CLAUDE.md already has Project Map section"
416
+ return
417
+ fi
418
+
419
+ local pointer
420
+ pointer=$(cat <<'POINTER'
421
+
422
+ ## Project Map
423
+
424
+ **Project Map**: For any project-specific question, read
425
+ [`.claude/project-map/PROJECT_MAP.md`](.claude/project-map/PROJECT_MAP.md) —
426
+ auto-generated index of routes, models, import chains, infra profile,
427
+ and vocabulary translator. Regenerated automatically on commit.
428
+
429
+ To regenerate manually:
430
+ ```bash
431
+ python .claude/project-map/generate.py --force
432
+ ```
433
+ POINTER
434
+ )
435
+
436
+ if [ -f "$claude_md" ]; then
437
+ echo "$pointer" >> "$claude_md"
438
+ ok "Updated CLAUDE.md with Project Map pointer"
439
+ else
440
+ cat > "$claude_md" <<CLAUDEMD
441
+ # CLAUDE.md
442
+
443
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
444
+
445
+ ## Project Overview
446
+
447
+ **${name}** — see README.md for details.
448
+ ${pointer}
449
+ CLAUDEMD
450
+ ok "Created CLAUDE.md"
451
+ fi
452
+ }
453
+
454
+
455
+ # ╔══════════════════════════════════════════════════════════════════════════╗
456
+ # ║ MAIN FLOW ║
457
+ # ╚══════════════════════════════════════════════════════════════════════════╝
458
+
459
+ printf '%b\n' "
460
+ ${CYAN}${BOLD}
461
+ ╔══════════════════════════════════════════╗
462
+ ║ Babel Fish Plugin Installer ║
463
+ ║ by TheGlitchKing ║
464
+ ╚══════════════════════════════════════════╝
465
+ ${RESET}"
466
+
467
+ info "Project root: $PROJECT_ROOT"
468
+ info "Timestamp: $(date '+%Y-%m-%d %H:%M:%S')"
469
+ echo
470
+
471
+ # ── Dry-run preview ──────────────────────────────────────────────────────────
472
+ if $DRY_RUN; then
473
+ printf '%b\n' "${YELLOW}${BOLD} DRY RUN — nothing will be created or modified${RESET}"
474
+ echo
475
+ printf '%b\n' "${CYAN}${BOLD} Files this installer will create:${RESET}"
476
+ _dry "mkdir -p $CLAUDE_DIR/scripts"
477
+ _dry "mkdir -p $CLAUDE_DIR/templates"
478
+ _dry "mkdir -p $CLAUDE_DIR/project-map/sections"
479
+ _dry "mkdir -p $CLAUDE_DIR/project-map/reports"
480
+ _dry "mkdir -p $CLAUDE_DIR/rules"
481
+ _dry "mkdir -p $CLAUDE_DIR/skills/<project>-developer-skill/"
482
+ _dry "copy scripts/*.sh → $CLAUDE_DIR/scripts/"
483
+ _dry "copy templates/*.template → $CLAUDE_DIR/templates/"
484
+ _dry "copy project-map/*.py → $CLAUDE_DIR/project-map/"
485
+ _dry "write $CLAUDE_DIR/project-map/PROJECT_MAP.md"
486
+ _dry "write $CLAUDE_DIR/project-map/sections/01-vocabulary.md (+ 18 more sections)"
487
+ _dry "write $CLAUDE_DIR/project-map/reports/install-report.md"
488
+ _dry "write $CLAUDE_DIR/rules/project-vocabulary.md"
489
+ _dry "write $CLAUDE_DIR/rules/operational-runbook.md"
490
+ _dry "write $CLAUDE_DIR/skills/<project>-developer-skill/SKILL.md"
491
+ _dry "write .githooks/pre-commit"
492
+ _dry "run git config core.hooksPath .githooks"
493
+ _dry "write/update CLAUDE.md (appends project map pointer)"
494
+ echo
495
+ printf '%b\n' "${CYAN}${BOLD} What the installer will NOT do:${RESET}"
496
+ _dry " — will not modify any of your source files"
497
+ _dry " — will not install packages globally"
498
+ _dry " — will not make network requests (except git clone if run via curl)"
499
+ _dry " — will not run Python with elevated permissions"
500
+ echo
501
+ printf '%b\n' "${GREEN} Run without --dry-run to apply.${RESET}"
502
+ exit 0
503
+ fi
504
+
505
+ # ── Step 0: Bootstrap plugin files into target project ───────────────────────
506
+ # When running from an external source (e.g. marketplace install), copy all
507
+ # plugin scripts, templates, and python files into the target project's .claude/
508
+ if [ "$PLUGIN_SOURCE_DIR" != "$CLAUDE_DIR" ]; then
509
+ mkdir -p "$CLAUDE_DIR/scripts" "$CLAUDE_DIR/templates" "$CLAUDE_DIR/project-map" "$CLAUDE_DIR/rules" "$CLAUDE_DIR/skills"
510
+ cp -r "$PLUGIN_SOURCE_DIR/scripts/." "$CLAUDE_DIR/scripts/"
511
+ cp -r "$PLUGIN_SOURCE_DIR/templates/." "$CLAUDE_DIR/templates/"
512
+ cp -r "$PLUGIN_SOURCE_DIR/project-map/generate.py" "$CLAUDE_DIR/project-map/" 2>/dev/null || true
513
+ cp -r "$PLUGIN_SOURCE_DIR/project-map/grader.py" "$CLAUDE_DIR/project-map/" 2>/dev/null || true
514
+ cp -r "$PLUGIN_SOURCE_DIR/project-map/mine-sessions.py" "$CLAUDE_DIR/project-map/" 2>/dev/null || true
515
+ fi
516
+
517
+ # ── Step 1: Ensure Python ─────────────────────────────────────────────────────
518
+ banner "Step 1: Python"
519
+
520
+ if [ ! -f "$SCRIPTS_DIR/ensure-python.sh" ]; then
521
+ fail "ensure-python.sh not found at $SCRIPTS_DIR/ensure-python.sh"
522
+ exit 2
523
+ fi
524
+
525
+ PYTHON_CMD=$(bash "$SCRIPTS_DIR/ensure-python.sh")
526
+ if [ -z "$PYTHON_CMD" ]; then
527
+ fail "Could not find or install Python >= 3.8"
528
+ exit 2
529
+ fi
530
+
531
+ ok "Python: $("$PYTHON_CMD" --version 2>&1)"
532
+
533
+ # ── Step 2: Detect Stack ──────────────────────────────────────────────────────
534
+ banner "Step 2: Stack Detection"
535
+
536
+ STACK_JSON="$MAP_DIR/stack.json"
537
+ mkdir -p "$MAP_DIR" "$REPORTS_DIR"
538
+
539
+ if [ -f "$SCRIPTS_DIR/detect-stack.sh" ]; then
540
+ bash "$SCRIPTS_DIR/detect-stack.sh" "$PROJECT_ROOT" > "$STACK_JSON" 2>/dev/null || true
541
+ fi
542
+
543
+ if [ -f "$STACK_JSON" ] && "$PYTHON_CMD" -c "import json; json.load(open('$STACK_JSON'))" 2>/dev/null; then
544
+ LANG=$("$PYTHON_CMD" -c "import json; d=json.load(open('$STACK_JSON')); print(d.get('language','unknown'))")
545
+ FRAMEWORK=$("$PYTHON_CMD" -c "import json; d=json.load(open('$STACK_JSON')); print(d.get('framework','unknown'))")
546
+ NAME=$("$PYTHON_CMD" -c "import json; d=json.load(open('$STACK_JSON')); print(d.get('name','project'))")
547
+ SLUG=$("$PYTHON_CMD" -c "import json; d=json.load(open('$STACK_JSON')); print(d.get('slug','project'))")
548
+ ok "Detected: $NAME ($LANG / $FRAMEWORK)"
549
+ else
550
+ warn "Stack detection unavailable — using directory name as defaults"
551
+ NAME=$(basename "$PROJECT_ROOT")
552
+ SLUG=$(echo "$NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g;s/^-//;s/-$//')
553
+ LANG="unknown"
554
+ FRAMEWORK="unknown"
555
+ fi
556
+
557
+ # ── Step 3: Iterative Generation + Grading ────────────────────────────────────
558
+ banner "Step 3: Generate → Grade (up to $MAX_ITERATIONS iterations)"
559
+
560
+ FINAL_SCORE=0
561
+ FINAL_PASSED=false
562
+
563
+ for ITERATION in $(seq 1 $MAX_ITERATIONS); do
564
+ echo
565
+ step "Iteration $ITERATION / $MAX_ITERATIONS"
566
+ echo
567
+
568
+ step "Running generate.py..."
569
+ set +e
570
+ "$PYTHON_CMD" "$MAP_DIR/generate.py" --force \
571
+ --project-root "$PROJECT_ROOT" \
572
+ --stack-json "$STACK_JSON"
573
+ GEN_EXIT=$?
574
+ set -e
575
+ [ $GEN_EXIT -ne 0 ] && warn "generate.py exited with errors (continuing to grade what was produced)"
576
+
577
+ step "Running grader.py..."
578
+ GRADE_ARGS=(--iteration "$ITERATION" --total "$MAX_ITERATIONS" --project-root "$PROJECT_ROOT")
579
+ [ -n "$PREVIOUS_SCORE" ] && GRADE_ARGS+=(--previous-score "$PREVIOUS_SCORE")
580
+
581
+ set +e
582
+ "$PYTHON_CMD" "$MAP_DIR/grader.py" "${GRADE_ARGS[@]}"
583
+ GRADE_EXIT=$?
584
+ set -e
585
+
586
+ SCORE_JSON="$REPORTS_DIR/iteration-$(printf '%02d' "$ITERATION")-score.json"
587
+ if [ -f "$SCORE_JSON" ]; then
588
+ FINAL_SCORE=$("$PYTHON_CMD" -c "import json; print(json.load(open('$SCORE_JSON'))['score'])")
589
+ PASSED=$("$PYTHON_CMD" -c "import json; print(json.load(open('$SCORE_JSON'))['passed'])")
590
+ else
591
+ FINAL_SCORE=0
592
+ PASSED="False"
593
+ fi
594
+
595
+ PREVIOUS_SCORE="$FINAL_SCORE"
596
+
597
+ if [ "$PASSED" = "True" ]; then
598
+ FINAL_PASSED=true
599
+ ok "Score: ${FINAL_SCORE}% — PASSED ✓ (>= ${PASS_THRESHOLD}%)"
600
+ break
601
+ else
602
+ warn "Score: ${FINAL_SCORE}% — below ${PASS_THRESHOLD}% threshold"
603
+ if [ "$ITERATION" -lt "$MAX_ITERATIONS" ]; then
604
+ step "Attempting improvements for iteration $((ITERATION + 1))..."
605
+ _improve_for_next_iteration "$SCORE_JSON" "$MAP_DIR" "$PYTHON_CMD"
606
+ fi
607
+ fi
608
+ done
609
+
610
+ # ── Step 4: Render Templates ──────────────────────────────────────────────────
611
+ banner "Step 4: Render Skills & Rules"
612
+
613
+ RULES_DIR="$CLAUDE_DIR/rules"
614
+ SKILLS_DIR="$CLAUDE_DIR/skills/${SLUG}-developer-skill"
615
+ mkdir -p "$RULES_DIR" "$SKILLS_DIR"
616
+
617
+ _render_vocabulary "$PROJECT_ROOT" "$NAME" "$LANG" "$FRAMEWORK" "$RULES_DIR"
618
+ _render_runbook "$PROJECT_ROOT" "$NAME" "$RULES_DIR"
619
+ _render_skill "$PROJECT_ROOT" "$NAME" "$SLUG" "$LANG" "$FRAMEWORK" "$SKILLS_DIR"
620
+
621
+ # ── Step 5: Git Hooks ─────────────────────────────────────────────────────────
622
+ banner "Step 5: Git Hooks"
623
+
624
+ HOOKS_DIR="$PROJECT_ROOT/.githooks"
625
+ mkdir -p "$HOOKS_DIR"
626
+ _install_git_hooks "$PROJECT_ROOT" "$HOOKS_DIR"
627
+
628
+ # ── Step 6: Update CLAUDE.md ──────────────────────────────────────────────────
629
+ banner "Step 6: Update CLAUDE.md"
630
+ _update_claude_md "$PROJECT_ROOT" "$NAME"
631
+
632
+ # ── Step 7: Final Validation ──────────────────────────────────────────────────
633
+ banner "Step 7: Validation"
634
+
635
+ if [ -f "$SCRIPTS_DIR/validate.sh" ]; then
636
+ bash "$SCRIPTS_DIR/validate.sh" "$PROJECT_ROOT" || true
637
+ else
638
+ warn "validate.sh not found — skipping"
639
+ fi
640
+
641
+ # ── Summary ────���──────────────────────────────────────────────────────────────
642
+ echo
643
+ printf '%b\n' "${CYAN}${BOLD}══════════════════════════════════════════════════${RESET}"
644
+ printf '%b\n' "${BOLD} Installation Complete${RESET}"
645
+ printf '%b\n' "${CYAN}══════════════════════════════════════════════════${RESET}"
646
+ echo
647
+
648
+ if [ "$FINAL_PASSED" = "true" ]; then
649
+ printf '%b\n' " ${GREEN}${BOLD}✓ PASSED${RESET} — Score: ${GREEN}${FINAL_SCORE}%${RESET}"
650
+ else
651
+ printf '%b\n' " ${YELLOW}${BOLD}⚠ COMPLETED WITH WARNINGS${RESET} — Score: ${YELLOW}${FINAL_SCORE}%${RESET}"
652
+ info "Map generated but scored below 90%. Review report for details."
653
+ fi
654
+
655
+ echo
656
+ info "Project Map: .claude/project-map/PROJECT_MAP.md"
657
+ info "Install Report: .claude/project-map/reports/install-report.md"
658
+ info "Developer Skill: /${SLUG}-developer-skill"
659
+ echo
660
+ info "To regenerate:"
661
+ info " $PYTHON_CMD .claude/project-map/generate.py --force"
662
+ info " $PYTHON_CMD .claude/project-map/grader.py"
663
+ echo
664
+ printf '%b\n' "${CYAN}══════════════════════════════════════════════════${RESET}"
665
+ echo