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.
- package/dist/plugins/specweave-github/lib/github-ac-comment-poster.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-ac-comment-poster.js +44 -25
- package/dist/plugins/specweave-github/lib/github-ac-comment-poster.js.map +1 -1
- package/dist/plugins/specweave-github/lib/github-feature-sync-cli.js +6 -0
- package/dist/plugins/specweave-github/lib/github-feature-sync-cli.js.map +1 -1
- package/dist/plugins/specweave-github/lib/github-feature-sync.d.ts +36 -1
- package/dist/plugins/specweave-github/lib/github-feature-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-feature-sync.js +266 -5
- package/dist/plugins/specweave-github/lib/github-feature-sync.js.map +1 -1
- package/dist/plugins/specweave-github/lib/user-story-content-builder.d.ts +2 -1
- package/dist/plugins/specweave-github/lib/user-story-content-builder.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/user-story-content-builder.js +6 -4
- package/dist/plugins/specweave-github/lib/user-story-content-builder.js.map +1 -1
- package/dist/plugins/specweave-github/lib/user-story-issue-builder.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/user-story-issue-builder.js +37 -17
- package/dist/plugins/specweave-github/lib/user-story-issue-builder.js.map +1 -1
- package/dist/src/cli/commands/refresh-plugins.d.ts.map +1 -1
- package/dist/src/cli/commands/refresh-plugins.js +9 -0
- package/dist/src/cli/commands/refresh-plugins.js.map +1 -1
- package/dist/src/cli/commands/sync-progress.d.ts.map +1 -1
- package/dist/src/cli/commands/sync-progress.js +72 -2
- package/dist/src/cli/commands/sync-progress.js.map +1 -1
- package/dist/src/config/types.d.ts +2 -2
- package/dist/src/core/increment/increment-utils.d.ts +27 -4
- package/dist/src/core/increment/increment-utils.d.ts.map +1 -1
- package/dist/src/core/increment/increment-utils.js +44 -17
- package/dist/src/core/increment/increment-utils.js.map +1 -1
- package/dist/src/core/increment/template-creator.d.ts +26 -0
- package/dist/src/core/increment/template-creator.d.ts.map +1 -1
- package/dist/src/core/increment/template-creator.js +179 -20
- package/dist/src/core/increment/template-creator.js.map +1 -1
- package/dist/src/importers/import-to-increment.d.ts +111 -0
- package/dist/src/importers/import-to-increment.d.ts.map +1 -0
- package/dist/src/importers/import-to-increment.js +223 -0
- package/dist/src/importers/import-to-increment.js.map +1 -0
- package/dist/src/importers/increment-external-ref-detector.d.ts +78 -0
- package/dist/src/importers/increment-external-ref-detector.d.ts.map +1 -0
- package/dist/src/importers/increment-external-ref-detector.js +130 -0
- package/dist/src/importers/increment-external-ref-detector.js.map +1 -0
- package/dist/src/init/research/types.d.ts +1 -1
- package/dist/src/sync/external-issue-auto-creator.d.ts.map +1 -1
- package/dist/src/sync/external-issue-auto-creator.js +28 -1
- package/dist/src/sync/external-issue-auto-creator.js.map +1 -1
- package/dist/src/sync/sync-coordinator.d.ts +6 -0
- package/dist/src/sync/sync-coordinator.d.ts.map +1 -1
- package/dist/src/sync/sync-coordinator.js +42 -2
- package/dist/src/sync/sync-coordinator.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/hooks/lib/update-active-increment.sh +2 -2
- package/plugins/specweave/hooks/lib/update-status-line.sh +2 -2
- package/plugins/specweave/hooks/stop-auto-v5.sh +28 -8
- package/plugins/specweave/hooks/stop-sync.sh +10 -5
- package/plugins/specweave/hooks/universal/fail-fast-wrapper.sh +8 -4
- package/plugins/specweave/hooks/user-prompt-submit.sh +130 -112
- package/plugins/specweave/hooks/v2/handlers/github-sync-handler.sh +6 -3
- package/plugins/specweave/hooks/v2/handlers/project-bridge-handler.sh +4 -3
- package/plugins/specweave/skills/auto/SKILL.md +5 -3
- package/plugins/specweave/skills/done/SKILL.md +9 -3
- package/plugins/specweave/skills/import/SKILL.md +186 -0
- package/plugins/specweave/skills/increment/SKILL.md +30 -16
- package/plugins/specweave/skills/pm/SKILL.md +29 -2
- package/plugins/specweave/skills/pm/phases/00-deep-interview.md +12 -0
- package/plugins/specweave/skills/team-lead/SKILL.md +4 -2
- package/plugins/specweave/skills/team-merge/SKILL.md +2 -2
- package/plugins/specweave-github/lib/github-ac-comment-poster.js +31 -19
- package/plugins/specweave-github/lib/github-ac-comment-poster.ts +44 -27
- package/plugins/specweave-github/lib/github-feature-sync-cli.js +5 -0
- package/plugins/specweave-github/lib/github-feature-sync-cli.ts +7 -1
- package/plugins/specweave-github/lib/github-feature-sync.js +274 -6
- package/plugins/specweave-github/lib/github-feature-sync.ts +353 -5
- package/plugins/specweave-github/lib/user-story-content-builder.js +6 -4
- package/plugins/specweave-github/lib/user-story-content-builder.ts +6 -4
- package/plugins/specweave-github/lib/user-story-issue-builder.js +26 -11
- 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.
|
|
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.
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
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
|
|
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
|
|
93
|
-
|
|
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 -
|
|
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
|
-
|
|
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("@
|
|
278
|
+
(.key | test("-lsp@"))
|
|
281
279
|
)
|
|
282
280
|
| .key
|
|
283
281
|
' "$USER_SETTINGS" 2>/dev/null)
|
|
284
282
|
|
|
285
|
-
if [[ -n "$
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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
|
-
#
|
|
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 "$
|
|
295
|
-
|
|
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 "$
|
|
305
|
-
echo "[$(date -Iseconds)] scope-guard |
|
|
306
|
+
if [[ -n "$MIGRATED" ]]; then
|
|
307
|
+
echo "[$(date -Iseconds)] scope-guard | migrated user→project: $MIGRATED" >> "$SW_PROJECT_ROOT/.specweave/state/hook.log" 2>/dev/null || true
|
|
306
308
|
fi
|
|
307
309
|
|
|
308
|
-
# Restore sw@specweave
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
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
|
-
|
|
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.
|
|
487
|
-
# Uses
|
|
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
|
|
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
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
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
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
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
|
-
#
|
|
511
|
-
local
|
|
512
|
-
if [[ -f "$
|
|
513
|
-
|
|
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
|
-
|
|
518
|
-
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
1259
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
|
|
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
|
-
#
|
|
1281
|
-
|
|
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=$(
|
|
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=$(
|
|
1991
|
-
inc_type=$(
|
|
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=$(
|
|
2262
|
-
COMPLETED_TASKS=$(
|
|
2263
|
-
TOTAL_ACS=$(
|
|
2264
|
-
COMPLETED_ACS=$(
|
|
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" "$@"
|
|
154
|
+
timeout "$timeout_secs" "$@" || true
|
|
152
155
|
elif command -v gtimeout >/dev/null 2>&1; then
|
|
153
|
-
gtimeout "$timeout_secs" "$@"
|
|
156
|
+
gtimeout "$timeout_secs" "$@" || true
|
|
154
157
|
else
|
|
155
|
-
"$@"
|
|
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" "$@"
|
|
87
|
+
timeout "$timeout_secs" "$@" || true
|
|
87
88
|
elif command -v gtimeout >/dev/null 2>&1; then
|
|
88
|
-
gtimeout "$timeout_secs" "$@"
|
|
89
|
+
gtimeout "$timeout_secs" "$@" || true
|
|
89
90
|
else
|
|
90
|
-
"$@"
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
|