specweave 1.0.472 → 1.0.474

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 (48) hide show
  1. package/CLAUDE.md +1 -1
  2. package/bin/specweave.js +21 -0
  3. package/dist/src/cli/commands/branch-name.d.ts +17 -0
  4. package/dist/src/cli/commands/branch-name.d.ts.map +1 -0
  5. package/dist/src/cli/commands/branch-name.js +47 -0
  6. package/dist/src/cli/commands/branch-name.js.map +1 -0
  7. package/dist/src/cli/commands/init.d.ts.map +1 -1
  8. package/dist/src/cli/commands/init.js +0 -1
  9. package/dist/src/cli/commands/init.js.map +1 -1
  10. package/dist/src/cli/commands/refresh-plugins.d.ts +6 -13
  11. package/dist/src/cli/commands/refresh-plugins.d.ts.map +1 -1
  12. package/dist/src/cli/commands/refresh-plugins.js +14 -38
  13. package/dist/src/cli/commands/refresh-plugins.js.map +1 -1
  14. package/dist/src/cli/commands/sync-health.d.ts +34 -0
  15. package/dist/src/cli/commands/sync-health.d.ts.map +1 -0
  16. package/dist/src/cli/commands/sync-health.js +175 -0
  17. package/dist/src/cli/commands/sync-health.js.map +1 -0
  18. package/dist/src/cli/commands/sync-setup.d.ts.map +1 -1
  19. package/dist/src/cli/commands/sync-setup.js +15 -1
  20. package/dist/src/cli/commands/sync-setup.js.map +1 -1
  21. package/dist/src/cli/helpers/init/plugin-installer.d.ts +10 -10
  22. package/dist/src/cli/helpers/init/plugin-installer.d.ts.map +1 -1
  23. package/dist/src/cli/helpers/init/plugin-installer.js +52 -197
  24. package/dist/src/cli/helpers/init/plugin-installer.js.map +1 -1
  25. package/dist/src/config/types.d.ts +2 -2
  26. package/dist/src/core/cicd/branch-utils.d.ts +29 -0
  27. package/dist/src/core/cicd/branch-utils.d.ts.map +1 -0
  28. package/dist/src/core/cicd/branch-utils.js +35 -0
  29. package/dist/src/core/cicd/branch-utils.js.map +1 -0
  30. package/dist/src/core/cicd/config-loader.d.ts.map +1 -1
  31. package/dist/src/core/cicd/config-loader.js.map +1 -1
  32. package/dist/src/core/config/types.d.ts +2 -0
  33. package/dist/src/core/config/types.d.ts.map +1 -1
  34. package/dist/src/core/config/types.js +1 -0
  35. package/dist/src/core/config/types.js.map +1 -1
  36. package/dist/src/core/lazy-loading/llm-plugin-detector.d.ts +18 -47
  37. package/dist/src/core/lazy-loading/llm-plugin-detector.d.ts.map +1 -1
  38. package/dist/src/core/lazy-loading/llm-plugin-detector.js +41 -409
  39. package/dist/src/core/lazy-loading/llm-plugin-detector.js.map +1 -1
  40. package/dist/src/init/research/types.d.ts +1 -1
  41. package/dist/src/utils/plugin-copier.d.ts +14 -0
  42. package/dist/src/utils/plugin-copier.d.ts.map +1 -1
  43. package/dist/src/utils/plugin-copier.js +140 -1
  44. package/dist/src/utils/plugin-copier.js.map +1 -1
  45. package/package.json +1 -1
  46. package/plugins/specweave/hooks/user-prompt-submit.sh +14 -291
  47. package/plugins/specweave/skills/team-lead/SKILL.md +43 -39
  48. package/plugins/specweave/skills/team-merge/SKILL.md +51 -33
@@ -1,14 +1,10 @@
1
1
  #!/bin/bash
2
2
 
3
- # SpecWeave UserPromptSubmit Hook (v1.0.343 - vskill Plugin Installation Fix)
3
+ # SpecWeave UserPromptSubmit Hook (v1.0.533 - Native Plugin Installation)
4
4
  # Fires BEFORE user's command executes (prompt-based hook)
5
5
  # Purpose: Auto-load plugins, discipline validation, context injection, instant command execution
6
6
  #
7
7
  # FEATURES:
8
- # - v1.0.272: VSKILL PLUGIN INSTALL - sw-* plugins now installed via vskill instead of
9
- # `claude plugin install`. Includes security scanning (tier1 PASS/CONCERNS/FAIL) and
10
- # vskill.lock fast-path for already-installed plugins. Non-specweave plugins (LSP, etc.)
11
- # still use `claude plugin install`.
12
8
  # - v1.0.201: LSP CLI FALLBACK INSTRUCTIONS - When LSP requested, instruct Claude to use
13
9
  # `specweave lsp` commands instead of Grep. These use TsServerClient for REAL semantic
14
10
  # analysis. Key fix: "find references" now gets semantic refs, not text matches!
@@ -294,11 +290,9 @@ if [[ "$SCOPE_GUARD_RUN" == "true" ]] && command -v jq >/dev/null 2>&1 && comman
294
290
  for plugin_key in $POLLUTED_PLUGINS; do
295
291
  # Uninstall from user scope
296
292
  if timeout 5 claude plugin uninstall "$plugin_key" >/dev/null 2>&1; then
297
- # v1.0.272: sw-* plugins reinstall via vskill, LSP plugins via claude CLI
298
293
  if [[ "$plugin_key" == sw-*@specweave ]]; then
299
- # Extract plugin name from "sw-name@specweave" format
300
- _sw_name="${plugin_key%%@*}"
301
- if install_plugin_via_vskill "$_sw_name"; then
294
+ # Reinstall at project scope via native Claude plugin system (v1.0.533)
295
+ if timeout 10 claude plugin install "$plugin_key" --scope project >/dev/null 2>&1; then
302
296
  [[ -n "$MIGRATED" ]] && MIGRATED="$MIGRATED, "
303
297
  MIGRATED="${MIGRATED}${plugin_key}"
304
298
  fi
@@ -480,71 +474,6 @@ check_plugin_in_vskill_lock() {
480
474
  fi
481
475
  }
482
476
 
483
- # Helper: Install plugin via vskill (v1.0.272, fixed v1.0.343, v1.0.344: --repo)
484
- # Uses npx vskill install with --repo anton-abyzov/specweave for sw-* plugins.
485
- # Args: $1=plugin name (e.g., "sw-github")
486
- # Returns: 0 if installed successfully, 1 if failed
487
- # Sets VSKILL_INSTALL_OUTPUT with stdout/stderr for scan result display
488
- # v1.0.344 (0394): Uses --repo anton-abyzov/specweave instead of local marketplace directory
489
- install_plugin_via_vskill() {
490
- local plugin="$1"
491
- VSKILL_INSTALL_OUTPUT=""
492
-
493
- if command -v npx >/dev/null 2>&1; then
494
- if command -v timeout >/dev/null 2>&1; then
495
- VSKILL_INSTALL_OUTPUT=$(timeout 30 npx vskill install --repo anton-abyzov/specweave --plugin "$plugin" --agent claude-code --force --yes 2>&1) || true
496
- else
497
- VSKILL_INSTALL_OUTPUT=$(npx vskill install --repo anton-abyzov/specweave --plugin "$plugin" --agent claude-code --force --yes 2>&1) || true
498
- fi
499
- else
500
- VSKILL_INSTALL_OUTPUT="vskill not available (npx not found)"
501
- return 1
502
- fi
503
-
504
- # Check if install succeeded
505
- if echo "$VSKILL_INSTALL_OUTPUT" | grep -qiE "(installed|Installed)"; then
506
- return 0
507
- else
508
- return 1
509
- fi
510
- }
511
-
512
- # Domain skill plugins in vskill marketplace (per-category plugins).
513
- # Each is a standalone plugin: mobile@vskill, skills@vskill.
514
- # Skills are invoked as plugin:skill (e.g., mobile:react-native).
515
- # v1.0.397: Reduced to plugins with actual directories on disk. Phantom entries removed.
516
- VSKILL_REPO_PLUGINS="mobile skills"
517
-
518
- # Check if plugin name is a vskill marketplace plugin
519
- is_vskill_repo_plugin() {
520
- local plugin="$1"
521
- echo " $VSKILL_REPO_PLUGINS " | grep -q " $plugin "
522
- }
523
-
524
- # Install vskill marketplace plugin via --repo flag. (fixed v1.0.343: add→install)
525
- # Args: $1=plugin name (e.g., "frontend")
526
- install_vskill_repo_plugin() {
527
- local plugin="$1"
528
- VSKILL_INSTALL_OUTPUT=""
529
- if command -v npx >/dev/null 2>&1; then
530
- if command -v timeout >/dev/null 2>&1; then
531
- VSKILL_INSTALL_OUTPUT=$(timeout 30 npx vskill install --repo anton-abyzov/vskill --plugin "$plugin" --agent claude-code --force --yes 2>&1) || true
532
- else
533
- VSKILL_INSTALL_OUTPUT=$(npx vskill install --repo anton-abyzov/vskill --plugin "$plugin" --agent claude-code --force --yes 2>&1) || true
534
- fi
535
- else
536
- VSKILL_INSTALL_OUTPUT="vskill not available (npx not found)"
537
- return 1
538
- fi
539
-
540
- # Check if install succeeded
541
- if echo "$VSKILL_INSTALL_OUTPUT" | grep -qiE "(installed|Installed)"; then
542
- return 0
543
- else
544
- return 1
545
- fi
546
- }
547
-
548
477
  # Helper: Check if plugin is installed by reading installed_plugins.json (v1.0.175)
549
478
  # This is the SOURCE OF TRUTH - more reliable than `claude plugin list` which can have timing issues.
550
479
  # Args: $1=plugin name (e.g., "frontend"), $2=marketplace (e.g., "vskill")
@@ -1263,176 +1192,13 @@ if [[ "${SPECWEAVE_DISABLE_AUTO_LOAD:-0}" != "1" ]] && [[ "${SPECWEAVE_DISABLE_H
1263
1192
  fi
1264
1193
 
1265
1194
  # ==================================================================
1266
- # PLUGIN INSTALLATION/SUGGESTION (from LLM response)
1195
+ # PLUGIN INSTALLATION/SUGGESTION REMOVED (v1.0.535)
1196
+ # ==================================================================
1197
+ # On-demand plugin installation via `claude plugin install` has been
1198
+ # removed. All plugins are now installed at init time by copying
1199
+ # SKILL.md files directly into .claude/skills/ (project-local).
1200
+ # Use `specweave refresh-plugins` to update plugin skills.
1267
1201
  # ==================================================================
1268
- if [[ "$PLUGIN_AUTOLOAD_ENABLED" == "true" ]]; then
1269
- DETECTED_PLUGINS=$(echo "$JSON_OUTPUT" | jq -r '.plugins[]?' 2>/dev/null | tr '\n' ' ')
1270
-
1271
- if [[ -n "$DETECTED_PLUGINS" ]]; then
1272
- # v1.0.158/v1.0.397: SUGGEST-ONLY MODE (now the default) - suggest with install commands, don't auto-install
1273
- if [[ "$PLUGIN_SUGGEST_ONLY" == "true" ]]; then
1274
- SUGGEST_CMDS=""
1275
- for plugin in $DETECTED_PLUGINS; do
1276
- [[ -z "$plugin" ]] && continue
1277
- if [[ "$plugin" == sw-* ]] || [[ "$plugin" == "sw" ]] || [[ "$plugin" == "docs" ]]; then
1278
- SUGGEST_CMDS="${SUGGEST_CMDS} - **${plugin}**: \`npx vskill install --repo anton-abyzov/specweave --plugin ${plugin} --agent claude-code\`\\n"
1279
- elif is_vskill_repo_plugin "$plugin"; then
1280
- SUGGEST_CMDS="${SUGGEST_CMDS} - **${plugin}**: \`npx vskill install --repo anton-abyzov/vskill --plugin ${plugin} --agent claude-code\`\\n"
1281
- fi
1282
- done
1283
- LLM_REASON=$(echo "$JSON_OUTPUT" | jq -r '.reasoning // empty' 2>/dev/null)
1284
- AUTOLOAD_PLUGINS_MSG="**Suggested plugins for this task**:\\n${SUGGEST_CMDS}"
1285
- [[ -n "$LLM_REASON" ]] && AUTOLOAD_PLUGINS_MSG="${AUTOLOAD_PLUGINS_MSG}*Why*: ${LLM_REASON}\\n"
1286
- AUTOLOAD_PLUGINS_MSG="${AUTOLOAD_PLUGINS_MSG}\\nTo enable auto-install: set \`\"pluginAutoLoad\": { \"suggestOnly\": false }\` in \`.specweave/config.json\`\\n"
1287
- AUTOLOAD_PLUGINS_MSG="${AUTOLOAD_PLUGINS_MSG}After installing, **restart Claude Code** to use new plugins.\\n\\n---\\n"
1288
- PLUGIN_LIST=$(echo "$DETECTED_PLUGINS" | tr ' ' ', ' | sed 's/,$//')
1289
- echo "[$(date -Iseconds)] plugins | suggested=${PLUGIN_LIST} | mode=suggestOnly" >> "$LAZY_LOAD_LOG"
1290
- elif command -v claude >/dev/null 2>&1; then
1291
- # NORMAL MODE - Actually install plugins
1292
- PLUGINS_INSTALLED=""
1293
- PLUGINS_ALREADY=""
1294
-
1295
- # v1.0.210: All plugins install with PROJECT scope by default
1296
- # This prevents global pollution - plugins stay scoped to current project
1297
- SPECWEAVE_PLUGIN_SCOPE="project"
1298
- DEFAULT_PLUGIN_SCOPE="project"
1299
- if [[ -f "$CONFIG_PATH" ]] && command -v jq >/dev/null 2>&1; then
1300
- SCOPE_VAL=$(jq -r '.plugins.scope.specweaveScope // "project"' "$CONFIG_PATH" 2>/dev/null)
1301
- [[ "$SCOPE_VAL" == "user" || "$SCOPE_VAL" == "project" || "$SCOPE_VAL" == "local" ]] && SPECWEAVE_PLUGIN_SCOPE="$SCOPE_VAL"
1302
- SCOPE_VAL=$(jq -r '.plugins.scope.defaultScope // "project"' "$CONFIG_PATH" 2>/dev/null)
1303
- [[ "$SCOPE_VAL" == "user" || "$SCOPE_VAL" == "project" || "$SCOPE_VAL" == "local" ]] && DEFAULT_PLUGIN_SCOPE="$SCOPE_VAL"
1304
- fi
1305
-
1306
- for plugin in $DETECTED_PLUGINS; do
1307
- [[ -z "$plugin" ]] && continue
1308
-
1309
- # v1.0.159: Determine marketplace based on plugin name
1310
- # sw-* plugins → @specweave (via vskill), others → @claude-plugins-official (via claude CLI)
1311
- # v1.0.240 (0198): context7/playwright removed from auto-install
1312
- # v1.0.272 (0232): sw-* plugins now installed via vskill instead of claude plugin install
1313
- # v1.0.344 (0394): docs plugin routes through specweave repo (not vskill)
1314
- if [[ "$plugin" == sw-* ]] || [[ "$plugin" == "sw" ]] || [[ "$plugin" == "docs" ]]; then
1315
- # ---- SW-* PLUGINS: Install via vskill (v1.0.272) ----
1316
- # Fast-path: check vskill.lock first (no CLI invocation needed)
1317
- if check_plugin_in_vskill_lock "$plugin"; then
1318
- [[ -n "$PLUGINS_ALREADY" ]] && PLUGINS_ALREADY="$PLUGINS_ALREADY, "
1319
- PLUGINS_ALREADY="${PLUGINS_ALREADY}${plugin}"
1320
- elif check_plugin_installed_from_json "$plugin" "specweave"; then
1321
- # Fallback: check installed_plugins.json (legacy installations)
1322
- [[ -n "$PLUGINS_ALREADY" ]] && PLUGINS_ALREADY="$PLUGINS_ALREADY, "
1323
- PLUGINS_ALREADY="${PLUGINS_ALREADY}${plugin}"
1324
- else
1325
- # Not installed - install via vskill add
1326
- if install_plugin_via_vskill "$plugin"; then
1327
- [[ -n "$PLUGINS_INSTALLED" ]] && PLUGINS_INSTALLED="$PLUGINS_INSTALLED, "
1328
- PLUGINS_INSTALLED="${PLUGINS_INSTALLED}${plugin}"
1329
-
1330
- # Display scan result if available
1331
- if [[ -n "$VSKILL_INSTALL_OUTPUT" ]]; then
1332
- SCAN_RESULT=$(echo "$VSKILL_INSTALL_OUTPUT" | grep -oE "Score:[[:space:]]*[0-9]+/100[[:space:]]*Verdict:[[:space:]]*[A-Z]+" || true)
1333
- [[ -n "$SCAN_RESULT" ]] && echo "[$(date -Iseconds)] vskill | ${plugin} | ${SCAN_RESULT}" >> "$LAZY_LOAD_LOG"
1334
- fi
1335
- else
1336
- echo "[$(date -Iseconds)] vskill | ${plugin} | FAILED: ${VSKILL_INSTALL_OUTPUT:-unknown}" >> "$LAZY_LOAD_LOG"
1337
- fi
1338
- fi
1339
- elif is_vskill_repo_plugin "$plugin"; then
1340
- # ---- VSKILL MARKETPLACE PLUGINS ----
1341
- # Each category is a standalone plugin (frontend@vskill, backend@vskill, etc.)
1342
- if check_plugin_in_vskill_lock "$plugin"; then
1343
- [[ -n "$PLUGINS_ALREADY" ]] && PLUGINS_ALREADY="$PLUGINS_ALREADY, "
1344
- PLUGINS_ALREADY="${PLUGINS_ALREADY}${plugin}"
1345
- else
1346
- if install_vskill_repo_plugin "$plugin"; then
1347
- [[ -n "$PLUGINS_INSTALLED" ]] && PLUGINS_INSTALLED="$PLUGINS_INSTALLED, "
1348
- PLUGINS_INSTALLED="${PLUGINS_INSTALLED}${plugin}"
1349
-
1350
- # Display scan result if available
1351
- if [[ -n "$VSKILL_INSTALL_OUTPUT" ]]; then
1352
- SCAN_RESULT=$(echo "$VSKILL_INSTALL_OUTPUT" | grep -oE "Score:[[:space:]]*[0-9]+/100[[:space:]]*Verdict:[[:space:]]*[A-Z]+" || true)
1353
- [[ -n "$SCAN_RESULT" ]] && echo "[$(date -Iseconds)] vskill-repo | ${plugin} | ${SCAN_RESULT}" >> "$LAZY_LOAD_LOG"
1354
- fi
1355
- else
1356
- echo "[$(date -Iseconds)] vskill-repo | ${plugin} | FAILED: ${VSKILL_INSTALL_OUTPUT:-unknown}" >> "$LAZY_LOAD_LOG"
1357
- fi
1358
- fi
1359
- else
1360
- # ---- NON-SW PLUGINS: Install via claude CLI (unchanged) ----
1361
- MARKETPLACE="claude-plugins-official"
1362
- PLUGIN_SCOPE="$DEFAULT_PLUGIN_SCOPE"
1363
- FULL_PLUGIN_NAME="${plugin}@${MARKETPLACE}"
1364
- ALREADY_INSTALLED=false
1365
-
1366
- if check_plugin_installed_from_json "$plugin" "$MARKETPLACE"; then
1367
- ALREADY_INSTALLED=true
1368
- else
1369
- CURRENT_PLUGINS=""
1370
- if command -v timeout >/dev/null 2>&1; then
1371
- CURRENT_PLUGINS=$(timeout 10 claude plugin list 2>/dev/null | grep -E "^ ❯ " | sed 's/^ ❯ //' || true)
1372
- else
1373
- CURRENT_PLUGINS=$(claude plugin list 2>/dev/null | grep -E "^ ❯ " | sed 's/^ ❯ //' || true)
1374
- fi
1375
- if echo "$CURRENT_PLUGINS" | grep -q "^${FULL_PLUGIN_NAME}$"; then
1376
- ALREADY_INSTALLED=true
1377
- fi
1378
- fi
1379
-
1380
- if [[ "$ALREADY_INSTALLED" == "true" ]]; then
1381
- [[ -n "$PLUGINS_ALREADY" ]] && PLUGINS_ALREADY="$PLUGINS_ALREADY, "
1382
- PLUGINS_ALREADY="${PLUGINS_ALREADY}${plugin}"
1383
- else
1384
- if command -v timeout >/dev/null 2>&1; then
1385
- OUT=$(timeout 10 claude plugin install "${FULL_PLUGIN_NAME}" --scope "$PLUGIN_SCOPE" 2>&1) || true
1386
- else
1387
- OUT=$(claude plugin install "${FULL_PLUGIN_NAME}" --scope "$PLUGIN_SCOPE" 2>&1) || true
1388
- fi
1389
- if echo "$OUT" | grep -qiE "(success|installed)"; then
1390
- sleep 0.5
1391
- if check_plugin_installed_from_json "$plugin" "$MARKETPLACE"; then
1392
- [[ -n "$PLUGINS_INSTALLED" ]] && PLUGINS_INSTALLED="$PLUGINS_INSTALLED, "
1393
- PLUGINS_INSTALLED="${PLUGINS_INSTALLED}${plugin}"
1394
- else
1395
- [[ -n "$PLUGINS_ALREADY" ]] && PLUGINS_ALREADY="$PLUGINS_ALREADY, "
1396
- PLUGINS_ALREADY="${PLUGINS_ALREADY}${plugin}"
1397
- fi
1398
- fi
1399
- fi
1400
- fi
1401
- done
1402
-
1403
- # Build feedback message
1404
- if [[ -n "$PLUGINS_INSTALLED" ]]; then
1405
- # v1.0.260: Compacted RESTART message (~400 chars vs ~2000 chars)
1406
- # ASCII art boxes were wasting ~1600 chars of the 3000-char context budget.
1407
- AUTOLOAD_PLUGINS_MSG="RESTART REQUIRED: Plugins installed (${PLUGINS_INSTALLED}) but NOT loaded in current session.\\n"
1408
- AUTOLOAD_PLUGINS_MSG="${AUTOLOAD_PLUGINS_MSG}ALL tools BLOCKED (Write, Edit, Bash, Task). DO NOT proceed.\\n"
1409
- AUTOLOAD_PLUGINS_MSG="${AUTOLOAD_PLUGINS_MSG}Restart: VSCode \\\`Cmd+Shift+P\\\` > 'Claude: New Session' | CLI: exit + \\\`claude\\\`\\n"
1410
- AUTOLOAD_PLUGINS_MSG="${AUTOLOAD_PLUGINS_MSG}STOP COMPLETELY. Do NOT help, do NOT implement, do NOT ignore this.\\n"
1411
- elif [[ -n "$PLUGINS_ALREADY" ]]; then
1412
- # v1.0.260: Daily caching — "Using plugins" shown once per day
1413
- # Uses date-based marker (like archive-suggestion) to auto-reset daily
1414
- _PLUGINS_SHOWN_FLAG="${SPECWEAVE_DIR}/state/plugins-shown.marker"
1415
- _TODAY=$(date +%Y-%m-%d)
1416
- _LAST_SHOWN=""
1417
- [[ -f "$_PLUGINS_SHOWN_FLAG" ]] && _LAST_SHOWN=$(cat "$_PLUGINS_SHOWN_FLAG" 2>/dev/null)
1418
- if [[ "$_LAST_SHOWN" != "$_TODAY" ]]; then
1419
- AUTOLOAD_PLUGINS_MSG="🔌 **Using plugins**: ${PLUGINS_ALREADY}\\n"
1420
- mkdir -p "$(dirname "$_PLUGINS_SHOWN_FLAG")" 2>/dev/null
1421
- echo "$_TODAY" > "$_PLUGINS_SHOWN_FLAG" 2>/dev/null
1422
- fi
1423
- fi
1424
- if [[ -n "$AUTOLOAD_PLUGINS_MSG" ]]; then
1425
- # v1.0.260: Skip LLM reasoning to save context budget — it's informational only
1426
- :
1427
- fi
1428
-
1429
- echo "[$(date -Iseconds)] plugins | installed=${PLUGINS_INSTALLED:-none} | already=${PLUGINS_ALREADY:-none}" >> "$LAZY_LOAD_LOG"
1430
-
1431
- # v1.0.240 (0198): Playwright MCP suggestion removed
1432
- # Browser automation handled by @playwright/cli (CLI-only mode)
1433
- fi
1434
- fi
1435
- fi
1436
1202
 
1437
1203
  # ==================================================================
1438
1204
  # EXTRACT ROUTING INFO EARLY (v1.0.155 - needed for agent directives)
@@ -1678,55 +1444,12 @@ After increment, chain domain skills per tech stack (see CLAUDE.md Skill Chainin
1678
1444
  fi
1679
1445
 
1680
1446
  # ==================================================================
1681
- # KEYWORD FALLBACK: PLUGIN INSTALLATION (v1.0.343)
1447
+ # KEYWORD FALLBACK: PLUGIN INSTALLATION — REMOVED (v1.0.535)
1448
+ # ==================================================================
1449
+ # Keyword-based plugin installation removed. All plugins are now
1450
+ # installed at init time via `specweave init` (direct file copy
1451
+ # to .claude/skills/). No on-demand marketplace lookups.
1682
1452
  # ==================================================================
1683
- # When LLM detection fails/times out, try lightweight keyword-based
1684
- # plugin detection. Only installs if plugin NOT already in vskill.lock.
1685
- # Targeted domain keywords (not generic action verbs) to avoid over-installing.
1686
- if [[ "$LLM_DETECTION_FAILED" == "true" && "$PLUGIN_AUTOLOAD_ENABLED" == "true" ]]; then
1687
- FALLBACK_PLUGINS=""
1688
- if echo "$PROMPT" | grep -qiE "(react|vue|angular|next\.?js|svelte|frontend|component|tailwind|CSS|UI design|dashboard)"; then
1689
- check_plugin_in_vskill_lock "frontend" || FALLBACK_PLUGINS="${FALLBACK_PLUGINS}frontend "
1690
- fi
1691
- if echo "$PROMPT" | grep -qiE "(API|REST|GraphQL|\.NET|C#|express|fastapi|django|spring boot|NestJS|backend|database|postgres|mongo)"; then
1692
- check_plugin_in_vskill_lock "backend" || FALLBACK_PLUGINS="${FALLBACK_PLUGINS}backend "
1693
- fi
1694
- if echo "$PROMPT" | grep -qiE "(vitest|playwright|jest|cypress|E2E|unit test|integration test|test coverage|TDD|mutation test)"; then
1695
- check_plugin_in_vskill_lock "testing" || FALLBACK_PLUGINS="${FALLBACK_PLUGINS}testing "
1696
- fi
1697
- if echo "$PROMPT" | grep -qiE "(react native|iOS|android|expo|flutter|swift|kotlin|mobile app)"; then
1698
- check_plugin_in_vskill_lock "mobile" || FALLBACK_PLUGINS="${FALLBACK_PLUGINS}mobile "
1699
- fi
1700
- if echo "$PROMPT" | grep -qiE "(terraform|AWS|Azure|GCP|docker|kubernetes|k8s|CI/CD|github actions|helm)"; then
1701
- check_plugin_in_vskill_lock "infra" || FALLBACK_PLUGINS="${FALLBACK_PLUGINS}infra "
1702
- fi
1703
- if echo "$PROMPT" | grep -qiE "(security scan|vulnerability|OWASP|penetration|CVE|hardening|devsecops)"; then
1704
- check_plugin_in_vskill_lock "security" || FALLBACK_PLUGINS="${FALLBACK_PLUGINS}security "
1705
- fi
1706
- if echo "$PROMPT" | grep -qiE "(kafka|event stream|confluent|schema registry)"; then
1707
- check_plugin_in_vskill_lock "kafka" || FALLBACK_PLUGINS="${FALLBACK_PLUGINS}kafka "
1708
- fi
1709
- if echo "$PROMPT" | grep -qiE "(machine learning|pytorch|tensorflow|LLM|RAG|fine.?tun|hugging.?face|langchain)"; then
1710
- check_plugin_in_vskill_lock "ml" || FALLBACK_PLUGINS="${FALLBACK_PLUGINS}ml "
1711
- fi
1712
- if echo "$PROMPT" | grep -qiE "(stripe|payment|billing|subscription|checkout|PCI)"; then
1713
- check_plugin_in_vskill_lock "payments" || FALLBACK_PLUGINS="${FALLBACK_PLUGINS}payments "
1714
- fi
1715
-
1716
- # Install detected plugins (limit to first 2 to avoid long delays)
1717
- if [[ -n "$FALLBACK_PLUGINS" ]]; then
1718
- FALLBACK_INSTALLED=""
1719
- FALLBACK_COUNT=0
1720
- for fp in $FALLBACK_PLUGINS; do
1721
- [[ "$FALLBACK_COUNT" -ge 2 ]] && break
1722
- if install_vskill_repo_plugin "$fp"; then
1723
- FALLBACK_INSTALLED="${FALLBACK_INSTALLED}${fp} "
1724
- FALLBACK_COUNT=$((FALLBACK_COUNT + 1))
1725
- fi
1726
- done
1727
- [[ -n "$FALLBACK_INSTALLED" ]] && echo "[$(date -Iseconds)] keyword-plugin-fallback | installed=${FALLBACK_INSTALLED}" >> "$LAZY_LOAD_LOG"
1728
- fi
1729
- fi
1730
1453
 
1731
1454
  # ==================================================================
1732
1455
  # KEYWORD FALLBACK FOR INCREMENT DISCIPLINE (v1.0.257)
@@ -31,34 +31,23 @@ hooks:
31
31
 
32
32
  **Before mode detection or any other step**, clean up stale teams from previous runs in this session.
33
33
 
34
- ### Why This Matters
34
+ ### Cleanup Protocol
35
35
 
36
- Teams persist at `~/.claude/teams/` and `~/.claude/tasks/` after completion. If not cleaned up, they pollute the session and may prevent `TeamCreate` from working.
36
+ 1. **First team-lead invocation in this session**: Nothing to clean. Proceed to Section 0.
37
37
 
38
- ### Cleanup Steps
38
+ 2. **Repeat invocation** (you previously ran team-lead and remember the team name + agent names):
39
+ - Send `shutdown_request` to each agent you previously spawned:
40
+ ```typescript
41
+ SendMessage({ type: "shutdown_request", recipient: "<previous-agent-name>" });
42
+ ```
43
+ - Call `TeamDelete()` with the previous team name
44
+ - If `TeamDelete` fails (agents still shutting down), wait 3 seconds, retry once
39
45
 
40
- ```bash
41
- # 1. List existing teams
42
- ls ~/.claude/teams/ 2>/dev/null
43
-
44
- # 2. List existing task directories
45
- ls ~/.claude/tasks/ 2>/dev/null
46
- ```
46
+ 3. **Use a unique team name** for each invocation to avoid collisions:
47
+ - `impl-checkout-1`, `impl-checkout-2`
48
+ - `review-auth-{timestamp}`
47
49
 
48
- **If stale teams exist from a previous run in this session:**
49
-
50
- 1. Call `TeamDelete()` for each stale team that is no longer active
51
- 2. If `TeamDelete` fails (agents still active), send `shutdown_request` to all agents first:
52
- ```typescript
53
- SendMessage({ type: "shutdown_request", recipient: "<agent-name>" });
54
- ```
55
- 3. Then retry `TeamDelete()`
56
-
57
- **If no stale teams or all cleaned up:** Proceed to Increment Pre-Flight (Section 0).
58
-
59
- **CRITICAL**: Use a **unique team name** for each invocation to avoid collisions. Append a timestamp or sequence number:
60
- - `review-pr-1533-1`, `review-pr-1533-2`
61
- - `impl-feature-{timestamp}`
50
+ **Do NOT** inspect the filesystem (`ls`, `jq`, reading config files). You either know the previous team name from this session, or there is nothing to clean.
62
51
 
63
52
  ---
64
53
 
@@ -790,7 +779,7 @@ When an agent is declared stuck:
790
779
  │ ── CLOSURE PHASE (all agents done) ──
791
780
 
792
781
  ├── Step 7: Invoke /sw:team-merge (handles all closure: done, sync, archival)
793
- ├── Step 8: TeamDelete() + kill orphaned tmux panes (MANDATORY)
782
+ ├── Step 8: Shutdown agents → TeamDelete() orphaned pane safety net (Step 9 below)
794
783
  └── Done.
795
784
  ```
796
785
 
@@ -799,29 +788,44 @@ Direct invocation of `/sw:team-lead` without an existing increment will trigger
799
788
 
800
789
  ### Step 9: Post-Completion Cleanup (MANDATORY — NEVER SKIP)
801
790
 
802
- **After delivering results OR after /sw:team-merge, ALWAYS clean up the team AND its tmux panes.**
791
+ **After delivering results OR after /sw:team-merge, clean up the team.**
803
792
 
804
- TeamDelete() only removes filesystem state — it does NOT close tmux panes. You MUST kill orphaned panes manually.
793
+ #### Phase 1: Graceful Agent Shutdown
794
+
795
+ Send `shutdown_request` to every agent you spawned. You know their names — you spawned them via `Task()`.
805
796
 
806
797
  ```typescript
807
- // 1. Clean up team filesystem state
808
- TeamDelete();
798
+ // Replace with your actual agent names from this session
799
+ SendMessage({ type: "shutdown_request", recipient: "<agent-1-name>", content: "Team work complete" });
800
+ SendMessage({ type: "shutdown_request", recipient: "<agent-2-name>", content: "Team work complete" });
801
+ // ... for every agent you spawned
809
802
  ```
810
803
 
811
- ```bash
812
- // 2. Kill orphaned tmux panes (MANDATORY — panes persist after TeamDelete)
813
- // List all panes, kill any teammate panes that are no longer needed
814
- tmux list-panes -a -F '#{pane_id} #{pane_current_command}' 2>/dev/null | grep -i claude | head -20
815
- # Kill specific panes (replace %ID with actual pane IDs from above):
816
- # tmux kill-pane -t %ID
804
+ Harmless if agents already exited. When an agent receives `shutdown_request` and approves, Claude Code handles its pane cleanup natively.
805
+
806
+ #### Phase 2: Destroy Team
817
807
 
818
- // 3. Or kill the entire tmux session if all work is done:
819
- # tmux kill-session -t <session-name>
808
+ ```typescript
809
+ TeamDelete();
820
810
  ```
821
811
 
822
- **Why this matters**: Claude Code only kills panes when the ENTIRE session exits via its cleanup hook. If agents finish but the main session continues, their panes stay open indefinitely — consuming terminal resources and confusing the user.
812
+ If `TeamDelete` fails (agents still shutting down), wait 3 seconds, retry once.
813
+
814
+ #### Phase 3: Orphaned Pane Safety Net (macOS/Linux tmux only)
823
815
 
824
- **If you skip this step**, orphaned tmux panes accumulate and the next `/sw:team-lead` run will fail to spawn agents due to stale team state.
816
+ SpecWeave agents often exit via auto-mode before receiving `shutdown_request`, so their panes survive. This catches those orphans. **Skip entirely on Windows or non-tmux terminals.**
817
+
818
+ ```bash
819
+ if command -v tmux >/dev/null 2>&1 && [ -n "$TMUX" ]; then
820
+ CURRENT_PANE=$(tmux display-message -p '#{pane_id}')
821
+ for pane_id in $(tmux list-panes -a -F '#{pane_id}'); do
822
+ [ "$pane_id" = "$CURRENT_PANE" ] && continue
823
+ if tmux capture-pane -t "$pane_id" -p -S -50 2>/dev/null | grep -q "Resume this session"; then
824
+ tmux kill-pane -t "$pane_id" 2>/dev/null
825
+ fi
826
+ done
827
+ fi
828
+ ```
825
829
 
826
830
  ### --dry-run Output
827
831
 
@@ -104,45 +104,57 @@ For each closed increment, trigger external sync:
104
104
  /sw-jira:push <increment-id>
105
105
  ```
106
106
 
107
- ### Step 6: Archive Team Execution Data
107
+ ### Step 6: Execution Summary
108
108
 
109
- Before destroying the team, preserve execution logs for debugging and tracing:
109
+ The team's durable artifacts are already in `.specweave/increments/` (spec.md, tasks.md, grill-report.json, metadata.json). No additional archival of ephemeral Claude Code state is needed.
110
110
 
111
- ```bash
112
- # Determine team name from current session context
113
- # Read ~/.claude/teams/{team-name}/config.json for team metadata
114
-
115
- TEAM_NAME="<team-name>"
116
- TIMESTAMP=$(date +%Y%m%dT%H%M%S)
117
- ARCHIVE_DIR=".specweave/team-logs/${TEAM_NAME}--${TIMESTAMP}"
111
+ Print a structured execution summary as the final output:
118
112
 
119
- mkdir -p "$ARCHIVE_DIR"
113
+ ```
114
+ Team Execution Summary
115
+ ═══════════════════════
116
+ Team: {team_name}
120
117
 
121
- # Copy team config and message inboxes
122
- cp -r ~/.claude/teams/${TEAM_NAME}/ "$ARCHIVE_DIR/team/"
118
+ Agents:
119
+ {agent-1}: COMPLETED (T-8/8, tests passing)
120
+ {agent-2}: COMPLETED (T-12/12, tests passing)
123
121
 
124
- # Copy shared task list (ownership, status transitions, dependencies)
125
- cp -r ~/.claude/tasks/${TEAM_NAME}/ "$ARCHIVE_DIR/tasks/"
122
+ Increments closed: {list}
123
+ Sync: {GitHub/JIRA status}
126
124
  ```
127
125
 
128
- This preserves:
129
- - **Team config** — members, roles, models, spawn timestamps
130
- - **Message inboxes** — full inter-agent communication history
131
- - **Task list** — ownership, status, dependency chains, completion order
132
-
133
- ### Step 7: Destroy Team Session
126
+ ### Step 7: Shutdown Agents and Destroy Team
134
127
 
135
- After archiving, call `TeamDelete` to clear the session's team context. This allows creating a new team in the same terminal without restarting.
128
+ **7a. Send shutdown_request to all agents** you know from the team session:
136
129
 
130
+ ```typescript
131
+ SendMessage({ type: "shutdown_request", recipient: "<agent-1>", content: "Merge complete" });
132
+ SendMessage({ type: "shutdown_request", recipient: "<agent-2>", content: "Merge complete" });
133
+ // ... for every agent in this team
137
134
  ```
138
- TeamDelete() # Removes ~/.claude/teams/{name}/ and ~/.claude/tasks/{name}/, clears session context
139
- ```
140
135
 
141
- **Important**: `TeamDelete` fails if teammates are still active. Ensure all teammates were shut down in Step 4 (via `/sw:done` which triggers shutdown).
136
+ Harmless if agents already exited.
137
+
138
+ **7b. Destroy team:**
142
139
 
143
- If `TeamDelete` fails due to active members, send shutdown requests to remaining teammates first:
140
+ ```typescript
141
+ TeamDelete()
144
142
  ```
145
- SendMessage({ type: "shutdown_request", recipient: "<teammate-name>", content: "Merge complete, shutting down" })
143
+
144
+ If `TeamDelete` fails (agents still shutting down), wait 3 seconds, retry once.
145
+
146
+ **7c. Orphaned pane safety net (macOS/Linux tmux only — skip on Windows):**
147
+
148
+ ```bash
149
+ if command -v tmux >/dev/null 2>&1 && [ -n "$TMUX" ]; then
150
+ CURRENT_PANE=$(tmux display-message -p '#{pane_id}')
151
+ for pane_id in $(tmux list-panes -a -F '#{pane_id}'); do
152
+ [ "$pane_id" = "$CURRENT_PANE" ] && continue
153
+ if tmux capture-pane -t "$pane_id" -p -S -50 2>/dev/null | grep -q "Resume this session"; then
154
+ tmux kill-pane -t "$pane_id" 2>/dev/null
155
+ fi
156
+ done
157
+ fi
146
158
  ```
147
159
 
148
160
  ## Options
@@ -174,11 +186,17 @@ Syncing to GitHub...
174
186
  0301 -> issue #46 closed
175
187
  0302 -> issue #47 closed
176
188
 
177
- Archiving team execution data...
178
- -> .specweave/team-logs/feature-0300--20260302T143012/
179
-
180
- Cleaning up team session...
181
- -> TeamDelete: session context cleared
182
-
183
- All increments merged, synced, and team archived.
189
+ Team Execution Summary
190
+ ═══════════════════════
191
+ Team: feature-checkout
192
+ Agents:
193
+ shared-agent: COMPLETED (T-4/4, tests passing)
194
+ backend-agent: COMPLETED (T-8/8, tests passing)
195
+ frontend-agent: COMPLETED (T-6/6, tests passing)
196
+ Increments closed: 0300, 0301, 0302
197
+ Sync: GitHub issues #45, #46, #47 closed
198
+
199
+ Shutting down agents... done
200
+ TeamDelete: team cleaned up.
201
+ All increments merged and synced.
184
202
  ```