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.
- package/CLAUDE.md +1 -1
- package/bin/specweave.js +21 -0
- package/dist/src/cli/commands/branch-name.d.ts +17 -0
- package/dist/src/cli/commands/branch-name.d.ts.map +1 -0
- package/dist/src/cli/commands/branch-name.js +47 -0
- package/dist/src/cli/commands/branch-name.js.map +1 -0
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +0 -1
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/refresh-plugins.d.ts +6 -13
- package/dist/src/cli/commands/refresh-plugins.d.ts.map +1 -1
- package/dist/src/cli/commands/refresh-plugins.js +14 -38
- package/dist/src/cli/commands/refresh-plugins.js.map +1 -1
- package/dist/src/cli/commands/sync-health.d.ts +34 -0
- package/dist/src/cli/commands/sync-health.d.ts.map +1 -0
- package/dist/src/cli/commands/sync-health.js +175 -0
- package/dist/src/cli/commands/sync-health.js.map +1 -0
- package/dist/src/cli/commands/sync-setup.d.ts.map +1 -1
- package/dist/src/cli/commands/sync-setup.js +15 -1
- package/dist/src/cli/commands/sync-setup.js.map +1 -1
- package/dist/src/cli/helpers/init/plugin-installer.d.ts +10 -10
- package/dist/src/cli/helpers/init/plugin-installer.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/plugin-installer.js +52 -197
- package/dist/src/cli/helpers/init/plugin-installer.js.map +1 -1
- package/dist/src/config/types.d.ts +2 -2
- package/dist/src/core/cicd/branch-utils.d.ts +29 -0
- package/dist/src/core/cicd/branch-utils.d.ts.map +1 -0
- package/dist/src/core/cicd/branch-utils.js +35 -0
- package/dist/src/core/cicd/branch-utils.js.map +1 -0
- package/dist/src/core/cicd/config-loader.d.ts.map +1 -1
- package/dist/src/core/cicd/config-loader.js.map +1 -1
- package/dist/src/core/config/types.d.ts +2 -0
- package/dist/src/core/config/types.d.ts.map +1 -1
- package/dist/src/core/config/types.js +1 -0
- package/dist/src/core/config/types.js.map +1 -1
- package/dist/src/core/lazy-loading/llm-plugin-detector.d.ts +18 -47
- package/dist/src/core/lazy-loading/llm-plugin-detector.d.ts.map +1 -1
- package/dist/src/core/lazy-loading/llm-plugin-detector.js +41 -409
- package/dist/src/core/lazy-loading/llm-plugin-detector.js.map +1 -1
- package/dist/src/init/research/types.d.ts +1 -1
- package/dist/src/utils/plugin-copier.d.ts +14 -0
- package/dist/src/utils/plugin-copier.d.ts.map +1 -1
- package/dist/src/utils/plugin-copier.js +140 -1
- package/dist/src/utils/plugin-copier.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/hooks/user-prompt-submit.sh +14 -291
- package/plugins/specweave/skills/team-lead/SKILL.md +43 -39
- 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.
|
|
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
|
-
#
|
|
300
|
-
|
|
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
|
|
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.
|
|
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
|
-
###
|
|
34
|
+
### Cleanup Protocol
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
1. **First team-lead invocation in this session**: Nothing to clean. Proceed to Section 0.
|
|
37
37
|
|
|
38
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
**
|
|
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()
|
|
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,
|
|
791
|
+
**After delivering results OR after /sw:team-merge, clean up the team.**
|
|
803
792
|
|
|
804
|
-
|
|
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
|
-
//
|
|
808
|
-
|
|
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
|
-
|
|
812
|
-
|
|
813
|
-
|
|
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
|
-
|
|
819
|
-
|
|
808
|
+
```typescript
|
|
809
|
+
TeamDelete();
|
|
820
810
|
```
|
|
821
811
|
|
|
822
|
-
|
|
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
|
-
|
|
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:
|
|
107
|
+
### Step 6: Execution Summary
|
|
108
108
|
|
|
109
|
-
|
|
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
|
-
|
|
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
|
-
|
|
113
|
+
```
|
|
114
|
+
Team Execution Summary
|
|
115
|
+
═══════════════════════
|
|
116
|
+
Team: {team_name}
|
|
120
117
|
|
|
121
|
-
|
|
122
|
-
|
|
118
|
+
Agents:
|
|
119
|
+
{agent-1}: COMPLETED (T-8/8, tests passing)
|
|
120
|
+
{agent-2}: COMPLETED (T-12/12, tests passing)
|
|
123
121
|
|
|
124
|
-
|
|
125
|
-
|
|
122
|
+
Increments closed: {list}
|
|
123
|
+
Sync: {GitHub/JIRA status}
|
|
126
124
|
```
|
|
127
125
|
|
|
128
|
-
|
|
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
|
-
|
|
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
|
-
|
|
136
|
+
Harmless if agents already exited.
|
|
137
|
+
|
|
138
|
+
**7b. Destroy team:**
|
|
142
139
|
|
|
143
|
-
|
|
140
|
+
```typescript
|
|
141
|
+
TeamDelete()
|
|
144
142
|
```
|
|
145
|
-
|
|
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
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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
|
```
|