specweave 1.0.301 → 1.0.304

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 (74) hide show
  1. package/dist/plugins/specweave-github/lib/github-ac-comment-poster.d.ts.map +1 -1
  2. package/dist/plugins/specweave-github/lib/github-ac-comment-poster.js +44 -25
  3. package/dist/plugins/specweave-github/lib/github-ac-comment-poster.js.map +1 -1
  4. package/dist/plugins/specweave-github/lib/github-feature-sync-cli.js +6 -0
  5. package/dist/plugins/specweave-github/lib/github-feature-sync-cli.js.map +1 -1
  6. package/dist/plugins/specweave-github/lib/github-feature-sync.d.ts +36 -1
  7. package/dist/plugins/specweave-github/lib/github-feature-sync.d.ts.map +1 -1
  8. package/dist/plugins/specweave-github/lib/github-feature-sync.js +266 -5
  9. package/dist/plugins/specweave-github/lib/github-feature-sync.js.map +1 -1
  10. package/dist/plugins/specweave-github/lib/user-story-content-builder.d.ts +2 -1
  11. package/dist/plugins/specweave-github/lib/user-story-content-builder.d.ts.map +1 -1
  12. package/dist/plugins/specweave-github/lib/user-story-content-builder.js +6 -4
  13. package/dist/plugins/specweave-github/lib/user-story-content-builder.js.map +1 -1
  14. package/dist/plugins/specweave-github/lib/user-story-issue-builder.d.ts.map +1 -1
  15. package/dist/plugins/specweave-github/lib/user-story-issue-builder.js +37 -17
  16. package/dist/plugins/specweave-github/lib/user-story-issue-builder.js.map +1 -1
  17. package/dist/src/cli/commands/refresh-plugins.d.ts.map +1 -1
  18. package/dist/src/cli/commands/refresh-plugins.js +9 -0
  19. package/dist/src/cli/commands/refresh-plugins.js.map +1 -1
  20. package/dist/src/cli/commands/sync-progress.d.ts.map +1 -1
  21. package/dist/src/cli/commands/sync-progress.js +72 -2
  22. package/dist/src/cli/commands/sync-progress.js.map +1 -1
  23. package/dist/src/config/types.d.ts +2 -2
  24. package/dist/src/core/increment/increment-utils.d.ts +27 -4
  25. package/dist/src/core/increment/increment-utils.d.ts.map +1 -1
  26. package/dist/src/core/increment/increment-utils.js +44 -17
  27. package/dist/src/core/increment/increment-utils.js.map +1 -1
  28. package/dist/src/core/increment/template-creator.d.ts +26 -0
  29. package/dist/src/core/increment/template-creator.d.ts.map +1 -1
  30. package/dist/src/core/increment/template-creator.js +179 -20
  31. package/dist/src/core/increment/template-creator.js.map +1 -1
  32. package/dist/src/importers/import-to-increment.d.ts +111 -0
  33. package/dist/src/importers/import-to-increment.d.ts.map +1 -0
  34. package/dist/src/importers/import-to-increment.js +223 -0
  35. package/dist/src/importers/import-to-increment.js.map +1 -0
  36. package/dist/src/importers/increment-external-ref-detector.d.ts +78 -0
  37. package/dist/src/importers/increment-external-ref-detector.d.ts.map +1 -0
  38. package/dist/src/importers/increment-external-ref-detector.js +130 -0
  39. package/dist/src/importers/increment-external-ref-detector.js.map +1 -0
  40. package/dist/src/init/research/types.d.ts +1 -1
  41. package/dist/src/sync/external-issue-auto-creator.d.ts.map +1 -1
  42. package/dist/src/sync/external-issue-auto-creator.js +28 -1
  43. package/dist/src/sync/external-issue-auto-creator.js.map +1 -1
  44. package/dist/src/sync/sync-coordinator.d.ts +6 -0
  45. package/dist/src/sync/sync-coordinator.d.ts.map +1 -1
  46. package/dist/src/sync/sync-coordinator.js +42 -2
  47. package/dist/src/sync/sync-coordinator.js.map +1 -1
  48. package/package.json +1 -1
  49. package/plugins/specweave/hooks/lib/update-active-increment.sh +2 -2
  50. package/plugins/specweave/hooks/lib/update-status-line.sh +2 -2
  51. package/plugins/specweave/hooks/stop-auto-v5.sh +28 -8
  52. package/plugins/specweave/hooks/stop-sync.sh +10 -5
  53. package/plugins/specweave/hooks/universal/fail-fast-wrapper.sh +8 -4
  54. package/plugins/specweave/hooks/user-prompt-submit.sh +130 -112
  55. package/plugins/specweave/hooks/v2/handlers/github-sync-handler.sh +6 -3
  56. package/plugins/specweave/hooks/v2/handlers/project-bridge-handler.sh +4 -3
  57. package/plugins/specweave/skills/auto/SKILL.md +5 -3
  58. package/plugins/specweave/skills/done/SKILL.md +9 -3
  59. package/plugins/specweave/skills/import/SKILL.md +186 -0
  60. package/plugins/specweave/skills/increment/SKILL.md +30 -16
  61. package/plugins/specweave/skills/pm/SKILL.md +29 -2
  62. package/plugins/specweave/skills/pm/phases/00-deep-interview.md +12 -0
  63. package/plugins/specweave/skills/team-lead/SKILL.md +4 -2
  64. package/plugins/specweave/skills/team-merge/SKILL.md +2 -2
  65. package/plugins/specweave-github/lib/github-ac-comment-poster.js +31 -19
  66. package/plugins/specweave-github/lib/github-ac-comment-poster.ts +44 -27
  67. package/plugins/specweave-github/lib/github-feature-sync-cli.js +5 -0
  68. package/plugins/specweave-github/lib/github-feature-sync-cli.ts +7 -1
  69. package/plugins/specweave-github/lib/github-feature-sync.js +274 -6
  70. package/plugins/specweave-github/lib/github-feature-sync.ts +353 -5
  71. package/plugins/specweave-github/lib/user-story-content-builder.js +6 -4
  72. package/plugins/specweave-github/lib/user-story-content-builder.ts +6 -4
  73. package/plugins/specweave-github/lib/user-story-issue-builder.js +26 -11
  74. package/plugins/specweave-github/lib/user-story-issue-builder.ts +37 -19
@@ -1,14 +1,14 @@
1
1
  #!/bin/bash
2
2
 
3
- # SpecWeave UserPromptSubmit Hook (v1.0.278 - Direct Plugin Copy)
3
+ # SpecWeave UserPromptSubmit Hook (v1.0.272 - vskill 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.279: VSKILL INSTALL - sw-* plugins installed via vskill at project scope.
9
- # Uses install_plugin_via_vskill(): node <vskill-cli> install <specweave-dir>
10
- # --plugin <name> --plugin-dir <dir> --force, run from SW_PROJECT_ROOT.
11
- # Installs to .claude/commands/<name>/ (project scope). Never ~/.claude/commands/.
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
12
  # - v1.0.201: LSP CLI FALLBACK INSTRUCTIONS - When LSP requested, instruct Claude to use
13
13
  # `specweave lsp` commands instead of Grep. These use TsServerClient for REAL semantic
14
14
  # analysis. Key fix: "find references" now gets semantic refs, not text matches!
@@ -85,12 +85,13 @@ set +e
85
85
  # ==============================================================================
86
86
  INPUT=$(cat 2>/dev/null || echo '{}')
87
87
 
88
- # Use jq if available (10x faster than node), fallback to simple grep
88
+ # Use jq if available (10x faster than node), fallback to portable sed
89
89
  if command -v jq >/dev/null 2>&1; then
90
90
  PROMPT=$(echo "$INPUT" | jq -r '.prompt // ""' 2>/dev/null || echo "")
91
91
  else
92
- # Fallback: extract prompt with grep (no node!)
93
- PROMPT=$(echo "$INPUT" | grep -oP '"prompt"\s*:\s*"\K[^"]*' 2>/dev/null || echo "")
92
+ # Fallback: extract prompt with sed (portable - works on macOS BSD and Linux GNU)
93
+ # Note: grep -oP (PCRE) is NOT available on macOS default BSD grep
94
+ PROMPT=$(echo "$INPUT" | sed -n 's/.*"prompt"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' 2>/dev/null || echo "")
94
95
  fi
95
96
 
96
97
  # ==============================================================================
@@ -154,7 +155,7 @@ if [[ "$PROMPT" =~ ^[[:space:]]*/[Ss][Ww](-[a-zA-Z0-9-]+)?:[a-zA-Z-]+ ]]; then
154
155
  if [[ -z "$FOUND_CONFIG" ]]; then
155
156
  # Check if guard is disabled in config (would fail since no config exists yet)
156
157
  # Extract skill name for error message
157
- SKILL_NAME=$(echo "$PROMPT" | grep -oP '^[[:space:]]*/[Ss][Ww](-[a-zA-Z0-9-]+)?:[a-zA-Z-]+' | tr '[:upper:]' '[:lower:]')
158
+ SKILL_NAME=$(echo "$PROMPT" | grep -oE '^[[:space:]]*/[Ss][Ww](-[a-zA-Z0-9-]+)?:[a-zA-Z-]+' | tr '[:upper:]' '[:lower:]')
158
159
 
159
160
  # Generate helpful error message
160
161
  cat <<EOF
@@ -266,72 +267,61 @@ fi
266
267
 
267
268
  if [[ "$SCOPE_GUARD_RUN" == "true" ]] && command -v jq >/dev/null 2>&1 && command -v claude >/dev/null 2>&1; then
268
269
  USER_SETTINGS="$HOME/.claude/settings.json"
269
- PROJECT_SETTINGS="${SW_PROJECT_ROOT}/.claude/settings.json"
270
270
 
271
- # ---- 1. Clean user-level settings ----
272
- # Remove: sw-* domain plugins at user scope (should be project-scoped via vskill)
273
- # any *@claude-plugins-official (never allowed)
274
- # Exempt: sw@specweave (core plugin, user-scoped by design)
275
271
  if [[ -f "$USER_SETTINGS" ]]; then
276
- POLLUTED_USER=$(jq -r '
272
+ # Find SpecWeave domain plugins and LSP plugins at user level
273
+ # Exempt: sw@specweave (core plugin, intentionally user-scoped)
274
+ POLLUTED_PLUGINS=$(jq -r '
277
275
  .enabledPlugins // {} | to_entries[]
278
276
  | select(
279
277
  (.key | test("^sw-.*@specweave$")) or
280
- (.key | test("@claude-plugins-official$"))
278
+ (.key | test("-lsp@"))
281
279
  )
282
280
  | .key
283
281
  ' "$USER_SETTINGS" 2>/dev/null)
284
282
 
285
- if [[ -n "$POLLUTED_USER" ]]; then
286
- REMOVED=""
287
- REINSTALLED=""
288
- for plugin_key in $POLLUTED_USER; do
283
+ if [[ -n "$POLLUTED_PLUGINS" ]]; then
284
+ MIGRATED=""
285
+ for plugin_key in $POLLUTED_PLUGINS; do
286
+ # Uninstall from user scope
289
287
  if timeout 5 claude plugin uninstall "$plugin_key" >/dev/null 2>&1; then
288
+ # v1.0.272: sw-* plugins reinstall via vskill, LSP plugins via claude CLI
290
289
  if [[ "$plugin_key" == sw-*@specweave ]]; then
291
- # Reinstall sw-* at project scope via vskill
290
+ # Extract plugin name from "sw-name@specweave" format
292
291
  _sw_name="${plugin_key%%@*}"
293
292
  if install_plugin_via_vskill "$_sw_name"; then
294
- [[ -n "$REINSTALLED" ]] && REINSTALLED="$REINSTALLED, "
295
- REINSTALLED="${REINSTALLED}${plugin_key}"
293
+ [[ -n "$MIGRATED" ]] && MIGRATED="$MIGRATED, "
294
+ MIGRATED="${MIGRATED}${plugin_key}"
295
+ fi
296
+ else
297
+ # LSP and other plugins: reinstall via claude CLI at project scope
298
+ if timeout 10 claude plugin install "$plugin_key" --scope project >/dev/null 2>&1; then
299
+ [[ -n "$MIGRATED" ]] && MIGRATED="$MIGRATED, "
300
+ MIGRATED="${MIGRATED}${plugin_key}"
296
301
  fi
297
302
  fi
298
- # *@claude-plugins-official: uninstall only — never reinstall
299
- [[ -n "$REMOVED" ]] && REMOVED="$REMOVED, "
300
- REMOVED="${REMOVED}${plugin_key}"
301
303
  fi
302
304
  done
303
305
 
304
- if [[ -n "$REMOVED" ]]; then
305
- echo "[$(date -Iseconds)] scope-guard | removed user-level: $REMOVED | reinstalled@project: ${REINSTALLED:-none}" >> "$SW_PROJECT_ROOT/.specweave/state/hook.log" 2>/dev/null || true
306
+ if [[ -n "$MIGRATED" ]]; then
307
+ echo "[$(date -Iseconds)] scope-guard | migrated userproject: $MIGRATED" >> "$SW_PROJECT_ROOT/.specweave/state/hook.log" 2>/dev/null || true
306
308
  fi
307
309
 
308
- # Restore sw@specweave core plugin enabled state (uninstall may collateral-damage it)
309
- SW_ENABLED=$(jq -r '.enabledPlugins."sw@specweave" // "not_set"' "$USER_SETTINGS" 2>/dev/null)
310
- if [[ "$SW_ENABLED" != "true" ]]; then
311
- jq '.enabledPlugins."sw@specweave" = true' "$USER_SETTINGS" > "${USER_SETTINGS}.tmp" 2>/dev/null && \
312
- mv "${USER_SETTINGS}.tmp" "$USER_SETTINGS" 2>/dev/null || true
313
- echo "[$(date -Iseconds)] scope-guard | restored sw@specweave" >> "$SW_PROJECT_ROOT/.specweave/state/hook.log" 2>/dev/null || true
310
+ # CRITICAL FIX: Restore sw@specweave enabled state after uninstall operations
311
+ # The `claude plugin uninstall` commands above may corrupt ~/.claude/settings.json
312
+ # and disable sw@specweave as collateral damage. Re-enable it explicitly.
313
+ if [[ -f "$USER_SETTINGS" ]]; then
314
+ SW_ENABLED=$(jq -r '.enabledPlugins."sw@specweave" // "not_set"' "$USER_SETTINGS" 2>/dev/null)
315
+ if [[ "$SW_ENABLED" != "true" ]]; then
316
+ # Re-enable core plugin (preserves all other settings)
317
+ jq '.enabledPlugins."sw@specweave" = true' "$USER_SETTINGS" > "${USER_SETTINGS}.tmp" 2>/dev/null && \
318
+ mv "${USER_SETTINGS}.tmp" "$USER_SETTINGS" 2>/dev/null || true
319
+ echo "[$(date -Iseconds)] scope-guard | restored sw@specweave enabled state" >> "$SW_PROJECT_ROOT/.specweave/state/hook.log" 2>/dev/null || true
320
+ fi
314
321
  fi
315
322
  fi
316
323
  fi
317
324
 
318
- # ---- 2. Clean project-level settings ----
319
- # Remove any *@claude-plugins-official from project settings — never allowed
320
- if [[ -f "$PROJECT_SETTINGS" ]]; then
321
- POLLUTED_PROJECT=$(jq -r '
322
- .enabledPlugins // {} | to_entries[]
323
- | select(.key | test("@claude-plugins-official$"))
324
- | .key
325
- ' "$PROJECT_SETTINGS" 2>/dev/null)
326
-
327
- if [[ -n "$POLLUTED_PROJECT" ]]; then
328
- for plugin_key in $POLLUTED_PROJECT; do
329
- timeout 5 claude plugin uninstall "$plugin_key" >/dev/null 2>&1 || true
330
- done
331
- echo "[$(date -Iseconds)] scope-guard | removed project official plugins: $POLLUTED_PROJECT" >> "$SW_PROJECT_ROOT/.specweave/state/hook.log" 2>/dev/null || true
332
- fi
333
- fi
334
-
335
325
  # Write today's marker
336
326
  mkdir -p "$(dirname "$SCOPE_GUARD_MARKER")" 2>/dev/null
337
327
  date +%Y-%m-%d > "$SCOPE_GUARD_MARKER" 2>/dev/null || true
@@ -458,9 +448,7 @@ output_approve_with_context() {
458
448
  # Returns: 0 if in lockfile, 1 if not
459
449
  check_plugin_in_vskill_lock() {
460
450
  local plugin="$1"
461
- # Use project root if available, else fall back to CWD
462
- local lock_dir="${SW_PROJECT_ROOT:-$PWD}"
463
- local lockfile="$lock_dir/vskill.lock"
451
+ local lockfile="vskill.lock"
464
452
 
465
453
  # Check project-local lockfile first
466
454
  [[ ! -f "$lockfile" ]] && return 1
@@ -483,59 +471,43 @@ check_plugin_in_vskill_lock() {
483
471
  fi
484
472
  }
485
473
 
486
- # Helper: Install sw-* plugin via vskill (v1.0.279)
487
- # Uses: node <vskill-cli> install <specweave-dir> --plugin <name> --plugin-dir <specweave-dir> --force
488
- # Installs to project scope: ${SW_PROJECT_ROOT}/.claude/commands/<name>/
474
+ # Helper: Install sw-* plugin via vskill (v1.0.272)
475
+ # Uses npx vskill add with --plugin and --plugin-dir flags.
489
476
  # Args: $1=plugin name (e.g., "sw-frontend")
490
477
  # Returns: 0 if installed successfully, 1 if failed
491
- # Sets VSKILL_INSTALL_OUTPUT with status message
478
+ # Sets VSKILL_INSTALL_OUTPUT with stdout/stderr for scan result display
492
479
  install_plugin_via_vskill() {
493
480
  local plugin="$1"
494
- local specweave_dir="${HOME}/.claude/plugins/marketplaces/specweave"
495
- local project_dir="${SW_PROJECT_ROOT:-$PWD}"
496
-
497
- # Find node binary
498
- local node_bin
499
- node_bin=$(command -v node 2>/dev/null)
500
- if [[ -z "$node_bin" ]]; then
501
- VSKILL_INSTALL_OUTPUT="node not found in PATH"
481
+ local plugin_dir="${HOME}/.claude/plugins/marketplaces/specweave"
482
+
483
+ # Verify marketplace directory exists
484
+ if [[ ! -d "$plugin_dir" ]] || [[ ! -f "$plugin_dir/.claude-plugin/marketplace.json" ]]; then
485
+ VSKILL_INSTALL_OUTPUT="marketplace directory not found at $plugin_dir"
502
486
  return 1
503
487
  fi
504
488
 
505
- # Find vskill CLI — check global first, then bundled with specweave
506
- local vskill_cli=""
507
- if command -v vskill >/dev/null 2>&1; then
508
- vskill_cli=$(command -v vskill)
489
+ VSKILL_INSTALL_OUTPUT=""
490
+ if command -v npx >/dev/null 2>&1; then
491
+ if command -v timeout >/dev/null 2>&1; then
492
+ VSKILL_INSTALL_OUTPUT=$(timeout 15 npx vskill add "$plugin_dir" --plugin "$plugin" --plugin-dir "$plugin_dir" --force 2>&1) || true
493
+ else
494
+ VSKILL_INSTALL_OUTPUT=$(npx vskill add "$plugin_dir" --plugin "$plugin" --plugin-dir "$plugin_dir" --force 2>&1) || true
495
+ fi
509
496
  else
510
- # Look for vskill bundled alongside specweave in node_modules
511
- local candidate="${specweave_dir}/../../../node_modules/.bin/vskill"
512
- if [[ -f "$candidate" ]]; then
513
- vskill_cli="$candidate"
497
+ # Fallback: try node with direct path
498
+ local vskill_js="${HOME}/.claude/plugins/marketplaces/specweave/node_modules/.bin/vskill"
499
+ if [[ -f "$vskill_js" ]]; then
500
+ VSKILL_INSTALL_OUTPUT=$(timeout 15 "$vskill_js" add "$plugin_dir" --plugin "$plugin" --plugin-dir "$plugin_dir" --force 2>&1) || true
501
+ else
502
+ VSKILL_INSTALL_OUTPUT="vskill not available (npx not found)"
503
+ return 1
514
504
  fi
515
505
  fi
516
506
 
517
- if [[ -z "$vskill_cli" ]]; then
518
- VSKILL_INSTALL_OUTPUT="vskill not found — install with: npm install -g vskill"
519
- return 1
520
- fi
521
-
522
- # Verify specweave marketplace dir exists
523
- if [[ ! -d "$specweave_dir" ]]; then
524
- VSKILL_INSTALL_OUTPUT="specweave marketplace dir not found at $specweave_dir"
525
- return 1
526
- fi
527
-
528
- # Run vskill install at project scope (cwd = project root)
529
- local output
530
- output=$(cd "$project_dir" && "$node_bin" "$vskill_cli" install "$specweave_dir" \
531
- --plugin "$plugin" --plugin-dir "$specweave_dir" --force 2>&1)
532
- local exit_code=$?
533
-
534
- if [[ $exit_code -eq 0 ]]; then
535
- VSKILL_INSTALL_OUTPUT="installed $plugin via vskill (project scope)"
507
+ # Check if install succeeded
508
+ if echo "$VSKILL_INSTALL_OUTPUT" | grep -qiE "(installed|Installed)"; then
536
509
  return 0
537
510
  else
538
- VSKILL_INSTALL_OUTPUT="vskill install failed for $plugin: $output"
539
511
  return 1
540
512
  fi
541
513
  }
@@ -1144,10 +1116,10 @@ if [[ "${SPECWEAVE_DISABLE_AUTO_LOAD:-0}" != "1" ]] && [[ "${SPECWEAVE_DISABLE_H
1144
1116
  if ! echo "$PROMPT" | grep -qE "^[[:space:]]*/sw:"; then
1145
1117
 
1146
1118
  # BYPASS: Native Claude Code slash commands (e.g., /context, /help, /doctor)
1147
- # Prevents 15s detect-intent timeout -> LLM_DETECTION_FAILED -> keyword fallback
1119
+ # Prevents 15s detect-intent timeout LLM_DETECTION_FAILED keyword fallback
1148
1120
  # that falsely matches "test" as substring inside "/context". Pattern matches
1149
- # /word or /word-word prompts that do not mention specweave.
1150
- if echo "$PROMPT" | grep -qE "^[[:space:]]*/[a-z][a-z0-9-]*([[:space:]]|$)" &&
1121
+ # /word or /word-word prompts that don't mention specweave.
1122
+ if echo "$PROMPT" | grep -qE "^[[:space:]]*/[a-z][a-z0-9-]*([[:space:]]|$)" && \
1151
1123
  ! echo "$PROMPT" | grep -qiE "specweave"; then
1152
1124
  echo '{"decision":"approve"}'
1153
1125
  exit 0
@@ -1231,7 +1203,7 @@ if [[ "${SPECWEAVE_DISABLE_AUTO_LOAD:-0}" != "1" ]] && [[ "${SPECWEAVE_DISABLE_H
1231
1203
  if [[ "$PLUGIN_SUGGEST_ONLY" == "true" ]]; then
1232
1204
  PLUGIN_LIST=$(echo "$DETECTED_PLUGINS" | tr ' ' ', ' | sed 's/,$//')
1233
1205
  AUTOLOAD_PLUGINS_MSG="💡 **Suggested plugins**: ${PLUGIN_LIST}\\n"
1234
- AUTOLOAD_PLUGINS_MSG="${AUTOLOAD_PLUGINS_MSG}To install: \`specweave refresh-plugins --all\`\\n"
1206
+ AUTOLOAD_PLUGINS_MSG="${AUTOLOAD_PLUGINS_MSG}To install: \`npx vskill add ~/.claude/plugins/marketplaces/specweave --plugin <plugin> --plugin-dir ~/.claude/plugins/marketplaces/specweave --force\`\\n"
1235
1207
  AUTOLOAD_PLUGINS_MSG="${AUTOLOAD_PLUGINS_MSG}After installing, restart Claude Code session to use new plugins.\\n"
1236
1208
  LLM_REASON=$(echo "$JSON_OUTPUT" | jq -r '.reasoning // empty' 2>/dev/null)
1237
1209
  [[ -n "$LLM_REASON" ]] && AUTOLOAD_PLUGINS_MSG="${AUTOLOAD_PLUGINS_MSG}*${LLM_REASON}*\\n\\n---\\n"
@@ -1255,10 +1227,13 @@ if [[ "${SPECWEAVE_DISABLE_AUTO_LOAD:-0}" != "1" ]] && [[ "${SPECWEAVE_DISABLE_H
1255
1227
  for plugin in $DETECTED_PLUGINS; do
1256
1228
  [[ -z "$plugin" ]] && continue
1257
1229
 
1258
- # v1.0.279: Only @specweave plugins allowed no claude-plugins-official
1259
- # Install via vskill (project scope: .claude/commands/<name>/)
1230
+ # v1.0.159: Determine marketplace based on plugin name
1231
+ # sw-* plugins → @specweave (via vskill), others → @claude-plugins-official (via claude CLI)
1232
+ # v1.0.240 (0198): context7/playwright removed from auto-install
1233
+ # v1.0.272 (0232): sw-* plugins now installed via vskill instead of claude plugin install
1260
1234
  if [[ "$plugin" == sw-* ]] || [[ "$plugin" == "sw" ]]; then
1261
- # Fast-path: check vskill.lock first
1235
+ # ---- SW-* PLUGINS: Install via vskill (v1.0.272) ----
1236
+ # Fast-path: check vskill.lock first (no CLI invocation needed)
1262
1237
  if check_plugin_in_vskill_lock "$plugin"; then
1263
1238
  [[ -n "$PLUGINS_ALREADY" ]] && PLUGINS_ALREADY="$PLUGINS_ALREADY, "
1264
1239
  PLUGINS_ALREADY="${PLUGINS_ALREADY}${plugin}"
@@ -1267,18 +1242,61 @@ if [[ "${SPECWEAVE_DISABLE_AUTO_LOAD:-0}" != "1" ]] && [[ "${SPECWEAVE_DISABLE_H
1267
1242
  [[ -n "$PLUGINS_ALREADY" ]] && PLUGINS_ALREADY="$PLUGINS_ALREADY, "
1268
1243
  PLUGINS_ALREADY="${PLUGINS_ALREADY}${plugin}"
1269
1244
  else
1270
- # Install via vskill at project scope
1245
+ # Not installed - install via vskill add
1271
1246
  if install_plugin_via_vskill "$plugin"; then
1272
1247
  [[ -n "$PLUGINS_INSTALLED" ]] && PLUGINS_INSTALLED="$PLUGINS_INSTALLED, "
1273
1248
  PLUGINS_INSTALLED="${PLUGINS_INSTALLED}${plugin}"
1274
- echo "[$(date -Iseconds)] vskill | ${plugin} | ${VSKILL_INSTALL_OUTPUT:-ok}" >> "$LAZY_LOAD_LOG"
1249
+
1250
+ # Display scan result if available
1251
+ if [[ -n "$VSKILL_INSTALL_OUTPUT" ]]; then
1252
+ SCAN_RESULT=$(echo "$VSKILL_INSTALL_OUTPUT" | grep -oE "Score:[[:space:]]*[0-9]+/100[[:space:]]*Verdict:[[:space:]]*[A-Z]+" || true)
1253
+ [[ -n "$SCAN_RESULT" ]] && echo "[$(date -Iseconds)] vskill | ${plugin} | ${SCAN_RESULT}" >> "$LAZY_LOAD_LOG"
1254
+ fi
1275
1255
  else
1276
1256
  echo "[$(date -Iseconds)] vskill | ${plugin} | FAILED: ${VSKILL_INSTALL_OUTPUT:-unknown}" >> "$LAZY_LOAD_LOG"
1277
1257
  fi
1278
1258
  fi
1279
1259
  else
1280
- # Non-sw-* plugin detected skip (only @specweave plugins allowed)
1281
- echo "[$(date -Iseconds)] plugins | SKIPPED non-specweave plugin: $plugin" >> "$LAZY_LOAD_LOG"
1260
+ # ---- NON-SW PLUGINS: Install via claude CLI (unchanged) ----
1261
+ MARKETPLACE="claude-plugins-official"
1262
+ PLUGIN_SCOPE="$DEFAULT_PLUGIN_SCOPE"
1263
+ FULL_PLUGIN_NAME="${plugin}@${MARKETPLACE}"
1264
+ ALREADY_INSTALLED=false
1265
+
1266
+ if check_plugin_installed_from_json "$plugin" "$MARKETPLACE"; then
1267
+ ALREADY_INSTALLED=true
1268
+ else
1269
+ CURRENT_PLUGINS=""
1270
+ if command -v timeout >/dev/null 2>&1; then
1271
+ CURRENT_PLUGINS=$(timeout 10 claude plugin list 2>/dev/null | grep -E "^ ❯ " | sed 's/^ ❯ //' || true)
1272
+ else
1273
+ CURRENT_PLUGINS=$(claude plugin list 2>/dev/null | grep -E "^ ❯ " | sed 's/^ ❯ //' || true)
1274
+ fi
1275
+ if echo "$CURRENT_PLUGINS" | grep -q "^${FULL_PLUGIN_NAME}$"; then
1276
+ ALREADY_INSTALLED=true
1277
+ fi
1278
+ fi
1279
+
1280
+ if [[ "$ALREADY_INSTALLED" == "true" ]]; then
1281
+ [[ -n "$PLUGINS_ALREADY" ]] && PLUGINS_ALREADY="$PLUGINS_ALREADY, "
1282
+ PLUGINS_ALREADY="${PLUGINS_ALREADY}${plugin}"
1283
+ else
1284
+ if command -v timeout >/dev/null 2>&1; then
1285
+ OUT=$(timeout 10 claude plugin install "${FULL_PLUGIN_NAME}" --scope "$PLUGIN_SCOPE" 2>&1) || true
1286
+ else
1287
+ OUT=$(claude plugin install "${FULL_PLUGIN_NAME}" --scope "$PLUGIN_SCOPE" 2>&1) || true
1288
+ fi
1289
+ if echo "$OUT" | grep -qiE "(success|installed)"; then
1290
+ sleep 0.5
1291
+ if check_plugin_installed_from_json "$plugin" "$MARKETPLACE"; then
1292
+ [[ -n "$PLUGINS_INSTALLED" ]] && PLUGINS_INSTALLED="$PLUGINS_INSTALLED, "
1293
+ PLUGINS_INSTALLED="${PLUGINS_INSTALLED}${plugin}"
1294
+ else
1295
+ [[ -n "$PLUGINS_ALREADY" ]] && PLUGINS_ALREADY="$PLUGINS_ALREADY, "
1296
+ PLUGINS_ALREADY="${PLUGINS_ALREADY}${plugin}"
1297
+ fi
1298
+ fi
1299
+ fi
1282
1300
  fi
1283
1301
  done
1284
1302
 
@@ -1949,7 +1967,7 @@ if echo "$PROMPT" | grep -qE "^/sw:do($| )"; then
1949
1967
  if command -v jq >/dev/null 2>&1; then
1950
1968
  status=$(jq -r '.status // "unknown"' "$meta" 2>/dev/null)
1951
1969
  else
1952
- status=$(grep -oP '"status"\s*:\s*"\K[^"]*' "$meta" 2>/dev/null || echo "unknown")
1970
+ status=$(sed -n 's/.*"status"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$meta" 2>/dev/null || echo "unknown")
1953
1971
  fi
1954
1972
  if [[ "$status" == "active" || "$status" == "planning" || "$status" == "backlog" || "$status" == "ready_for_review" ]]; then
1955
1973
  DO_INCREMENT_ID=$(basename "$(dirname "$meta")")
@@ -1987,8 +2005,8 @@ if [[ -d "$SPECWEAVE_DIR/increments" ]]; then
1987
2005
  read -r status inc_type < <(jq -r '"\(.status // "unknown") \(.type // "feature")"' "$metadata_file" 2>/dev/null || echo "unknown feature")
1988
2006
  else
1989
2007
  # Fallback: grep (no node!)
1990
- status=$(grep -oP '"status"\s*:\s*"\K[^"]*' "$metadata_file" 2>/dev/null || echo "unknown")
1991
- inc_type=$(grep -oP '"type"\s*:\s*"\K[^"]*' "$metadata_file" 2>/dev/null || echo "feature")
2008
+ status=$(sed -n 's/.*"status"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$metadata_file" 2>/dev/null || echo "unknown")
2009
+ inc_type=$(sed -n 's/.*"type"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$metadata_file" 2>/dev/null || echo "feature")
1992
2010
  fi
1993
2011
 
1994
2012
  if [[ "$status" == "active" || "$status" == "planning" || "$status" == "ready_for_review" ]]; then
@@ -2258,10 +2276,10 @@ if [[ -n "$ACTIVE_INCREMENT" ]]; then
2258
2276
  )
2259
2277
  else
2260
2278
  # Pure grep fallback (no node!)
2261
- TOTAL_TASKS=$(grep -oP '"total"\s*:\s*\K[0-9]+' "$CACHE_FILE" 2>/dev/null | head -1 || echo "0")
2262
- COMPLETED_TASKS=$(grep -oP '"completed"\s*:\s*\K[0-9]+' "$CACHE_FILE" 2>/dev/null | head -1 || echo "0")
2263
- TOTAL_ACS=$(grep -oP '"acsTotal"\s*:\s*\K[0-9]+' "$CACHE_FILE" 2>/dev/null || echo "0")
2264
- COMPLETED_ACS=$(grep -oP '"acsCompleted"\s*:\s*\K[0-9]+' "$CACHE_FILE" 2>/dev/null || echo "0")
2279
+ TOTAL_TASKS=$(sed -n 's/.*"total"[[:space:]]*:[[:space:]]*\([0-9][0-9]*\).*/\1/p' "$CACHE_FILE" 2>/dev/null | head -1 || echo "0")
2280
+ COMPLETED_TASKS=$(sed -n 's/.*"completed"[[:space:]]*:[[:space:]]*\([0-9][0-9]*\).*/\1/p' "$CACHE_FILE" 2>/dev/null | head -1 || echo "0")
2281
+ TOTAL_ACS=$(sed -n 's/.*"acsTotal"[[:space:]]*:[[:space:]]*\([0-9][0-9]*\).*/\1/p' "$CACHE_FILE" 2>/dev/null || echo "0")
2282
+ COMPLETED_ACS=$(sed -n 's/.*"acsCompleted"[[:space:]]*:[[:space:]]*\([0-9][0-9]*\).*/\1/p' "$CACHE_FILE" 2>/dev/null || echo "0")
2265
2283
  fi
2266
2284
 
2267
2285
  # Ensure valid numbers
@@ -144,15 +144,18 @@ touch "$THROTTLE_FILE"
144
144
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] [github-sync] EXECUTING $INC_ID ($SYNC_TYPE) event=$EVENT_TYPE" >> "$THROTTLE_LOG" 2>/dev/null
145
145
 
146
146
  # Cross-platform timeout wrapper
147
+ # FIXED (v1.0.302): Don't suppress stderr from inner commands — only suppress
148
+ # stderr from timeout/gtimeout binary itself (e.g., "command not found").
149
+ # The caller already redirects stderr to log files via 2>&1.
147
150
  run_with_timeout() {
148
151
  local timeout_secs="$1"
149
152
  shift
150
153
  if command -v timeout >/dev/null 2>&1; then
151
- timeout "$timeout_secs" "$@" 2>/dev/null || true
154
+ timeout "$timeout_secs" "$@" || true
152
155
  elif command -v gtimeout >/dev/null 2>&1; then
153
- gtimeout "$timeout_secs" "$@" 2>/dev/null || true
156
+ gtimeout "$timeout_secs" "$@" || true
154
157
  else
155
- "$@" 2>/dev/null || true
158
+ "$@" || true
156
159
  fi
157
160
  }
158
161
 
@@ -79,15 +79,16 @@ for path in \
79
79
  done
80
80
 
81
81
  # Cross-platform timeout wrapper
82
+ # FIXED (v1.0.302): Don't suppress stderr from inner commands
82
83
  run_with_timeout() {
83
84
  local timeout_secs="$1"
84
85
  shift
85
86
  if command -v timeout >/dev/null 2>&1; then
86
- timeout "$timeout_secs" "$@" 2>/dev/null || true
87
+ timeout "$timeout_secs" "$@" || true
87
88
  elif command -v gtimeout >/dev/null 2>&1; then
88
- gtimeout "$timeout_secs" "$@" 2>/dev/null || true
89
+ gtimeout "$timeout_secs" "$@" || true
89
90
  else
90
- "$@" 2>/dev/null || true
91
+ "$@" || true
91
92
  fi
92
93
  }
93
94
 
@@ -47,10 +47,10 @@ argument-hint: "[INCREMENT_IDS...] [OPTIONS]"
47
47
  ## Core Loop
48
48
 
49
49
  ```
50
- IMPLEMENT task -> TEST -> FAIL? -> FIX -> PASS -> mark complete -> NEXT task
50
+ IMPLEMENT task -> TEST -> FAIL? -> FIX -> PASS -> mark complete -> NEXT task -> ... -> ALL DONE -> /sw:done --auto -> CLOSED
51
51
  ```
52
52
 
53
- Stop hook gates exit when tasks/ACs remain. Model enforces quality gates (build/tests/lint) before `/sw:done`.
53
+ Stop hook blocks when tasks/ACs remain. When all work is complete, stop hook blocks with `all_complete_needs_closure` to trigger `/sw:done --auto`. Model enforces quality gates (build/tests/lint) before closure.
54
54
 
55
55
  ## Execution
56
56
 
@@ -182,7 +182,9 @@ Then return to Step 1c-1d to set up the session, then Step 1.5 for the banner.
182
182
  2. Mark tasks complete in tasks.md, update spec.md ACs
183
183
  3. Run tests after each task
184
184
  4. Before `/sw:done`: verify all quality gates from `successCriteria`
185
- 5. On completion output `<!-- auto-complete:DONE -->`
185
+ 5. **Closure**: When all tasks are complete (stop hook blocks with `all_complete_needs_closure`), run `/sw:done --auto <id>` for each increment in the session
186
+ 6. **On success**: If `/sw:done` succeeds, clean up session state (`rm -f` auto-mode.json, turn counter, dedup files) and output `<!-- auto-complete:DONE -->`
187
+ 7. **On failure**: If `/sw:done` fails (gate failure), report the failure and do NOT clean up session state. The stop hook will block again on the next turn for a retry.
186
188
 
187
189
  ## Credential Auto-Execution
188
190
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Close increment with PM 3-gate validation (tasks, tests, docs). Use when all tasks complete and saying "close increment", "we're done", or "finish up".
3
- argument-hint: "<increment-id>"
3
+ argument-hint: "<increment-id> [--auto]"
4
4
  hooks:
5
5
  Stop:
6
6
  - hooks:
@@ -21,11 +21,17 @@ hooks:
21
21
  ## Usage
22
22
 
23
23
  ```
24
- /sw:done <increment-id>
24
+ /sw:done <increment-id> [--auto]
25
25
  ```
26
26
 
27
27
  Argument: Required increment ID (e.g., "001", "0001", "0042", "0153-feature-name"). Numeric portion extracted and zero-padded to 4 digits.
28
28
 
29
+ ## Options
30
+
31
+ | Option | Description |
32
+ |--------|-------------|
33
+ | `--auto` | Skip user confirmation prompt in Step 4 (for `/sw:auto` and `/sw:team-lead` modes). All quality gates (grill, judge-llm, Gate 0, PM gates) still enforced. |
34
+
29
35
  ---
30
36
 
31
37
  ## Workflow
@@ -56,7 +62,7 @@ If closing a SpecWeave framework increment, show post-closure reminders: update
56
62
  - `completed` -> Already closed, warn user
57
63
  - `backlog` / `paused` / `abandoned` -> BLOCK with error
58
64
 
59
- Require explicit user confirmation before closure ("yes" to close, "no" to cancel).
65
+ **User confirmation**: If `--auto` flag is present, skip the explicit user confirmation and proceed directly to closure. Otherwise, require explicit user confirmation before closure ("yes" to close, "no" to cancel). Note: `--auto` does NOT bypass any quality gates (grill, judge-llm, Gate 0, PM gates) — it only skips the interactive confirmation prompt.
60
66
 
61
67
  ### Step 5: Load Increment Context
62
68