specweave 0.26.14 → 0.27.0
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 +73 -1
- package/README.md +111 -466
- package/dist/plugins/specweave-jira/lib/setup-wizard.d.ts.map +1 -1
- package/dist/plugins/specweave-jira/lib/setup-wizard.js +57 -78
- package/dist/plugins/specweave-jira/lib/setup-wizard.js.map +1 -1
- package/dist/src/cli/commands/import-docs.d.ts.map +1 -1
- package/dist/src/cli/commands/import-docs.js +23 -31
- package/dist/src/cli/commands/import-docs.js.map +1 -1
- package/dist/src/cli/commands/import-external.d.ts.map +1 -1
- package/dist/src/cli/commands/import-external.js +6 -10
- package/dist/src/cli/commands/import-external.js.map +1 -1
- package/dist/src/cli/commands/init-multiproject.d.ts.map +1 -1
- package/dist/src/cli/commands/init-multiproject.js +58 -73
- package/dist/src/cli/commands/init-multiproject.js.map +1 -1
- package/dist/src/cli/commands/init.d.ts +17 -11
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +221 -1874
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/install.d.ts.map +1 -1
- package/dist/src/cli/commands/install.js +14 -22
- package/dist/src/cli/commands/install.js.map +1 -1
- package/dist/src/cli/commands/migrate-config.d.ts.map +1 -1
- package/dist/src/cli/commands/migrate-config.js +6 -10
- package/dist/src/cli/commands/migrate-config.js.map +1 -1
- package/dist/src/cli/commands/switch-project.d.ts.map +1 -1
- package/dist/src/cli/commands/switch-project.js.map +1 -1
- package/dist/src/cli/helpers/ado-area-path-mapper.d.ts.map +1 -1
- package/dist/src/cli/helpers/ado-area-path-mapper.js +36 -49
- package/dist/src/cli/helpers/ado-area-path-mapper.js.map +1 -1
- package/dist/src/cli/helpers/github/increment-profile-selector.d.ts.map +1 -1
- package/dist/src/cli/helpers/github/increment-profile-selector.js.map +1 -1
- package/dist/src/cli/helpers/github/profile-manager.d.ts.map +1 -1
- package/dist/src/cli/helpers/github/profile-manager.js +8 -11
- package/dist/src/cli/helpers/github/profile-manager.js.map +1 -1
- package/dist/src/cli/helpers/github-repo-selector.d.ts.map +1 -1
- package/dist/src/cli/helpers/github-repo-selector.js +26 -50
- package/dist/src/cli/helpers/github-repo-selector.js.map +1 -1
- package/dist/src/cli/helpers/import-strategy-prompter.d.ts.map +1 -1
- package/dist/src/cli/helpers/import-strategy-prompter.js +39 -52
- package/dist/src/cli/helpers/import-strategy-prompter.js.map +1 -1
- package/dist/src/cli/helpers/init/config-detection.d.ts +40 -0
- package/dist/src/cli/helpers/init/config-detection.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/config-detection.js +125 -0
- package/dist/src/cli/helpers/init/config-detection.js.map +1 -0
- package/dist/src/cli/helpers/init/directory-structure.d.ts +26 -0
- package/dist/src/cli/helpers/init/directory-structure.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/directory-structure.js +190 -0
- package/dist/src/cli/helpers/init/directory-structure.js.map +1 -0
- package/dist/src/cli/helpers/init/external-import.d.ts +15 -0
- package/dist/src/cli/helpers/init/external-import.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/external-import.js +251 -0
- package/dist/src/cli/helpers/init/external-import.js.map +1 -0
- package/dist/src/cli/helpers/init/index.d.ts +15 -0
- package/dist/src/cli/helpers/init/index.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/index.js +26 -0
- package/dist/src/cli/helpers/init/index.js.map +1 -0
- package/dist/src/cli/helpers/init/next-steps.d.ts +15 -0
- package/dist/src/cli/helpers/init/next-steps.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/next-steps.js +72 -0
- package/dist/src/cli/helpers/init/next-steps.js.map +1 -0
- package/dist/src/cli/helpers/init/path-utils.d.ts +41 -0
- package/dist/src/cli/helpers/init/path-utils.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/path-utils.js +146 -0
- package/dist/src/cli/helpers/init/path-utils.js.map +1 -0
- package/dist/src/cli/helpers/init/plugin-installer.d.ts +28 -0
- package/dist/src/cli/helpers/init/plugin-installer.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/plugin-installer.js +238 -0
- package/dist/src/cli/helpers/init/plugin-installer.js.map +1 -0
- package/dist/src/cli/helpers/init/repository-setup.d.ts +28 -0
- package/dist/src/cli/helpers/init/repository-setup.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/repository-setup.js +78 -0
- package/dist/src/cli/helpers/init/repository-setup.js.map +1 -0
- package/dist/src/cli/helpers/init/smart-reinit.d.ts +30 -0
- package/dist/src/cli/helpers/init/smart-reinit.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/smart-reinit.js +140 -0
- package/dist/src/cli/helpers/init/smart-reinit.js.map +1 -0
- package/dist/src/cli/helpers/init/testing-config.d.ts +27 -0
- package/dist/src/cli/helpers/init/testing-config.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/testing-config.js +131 -0
- package/dist/src/cli/helpers/init/testing-config.js.map +1 -0
- package/dist/src/cli/helpers/init/types.d.ts +86 -0
- package/dist/src/cli/helpers/init/types.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/types.js +5 -0
- package/dist/src/cli/helpers/init/types.js.map +1 -0
- package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.js +10 -12
- package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/ado.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/ado.js +43 -60
- package/dist/src/cli/helpers/issue-tracker/ado.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js +193 -230
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github.js +43 -54
- package/dist/src/cli/helpers/issue-tracker/github.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/index.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/index.js +27 -40
- package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/jira.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/jira.js +54 -70
- package/dist/src/cli/helpers/issue-tracker/jira.js.map +1 -1
- package/dist/src/cli/helpers/smart-filter.d.ts.map +1 -1
- package/dist/src/cli/helpers/smart-filter.js +62 -85
- package/dist/src/cli/helpers/smart-filter.js.map +1 -1
- package/dist/src/core/increment/auto-transition-manager.d.ts +12 -0
- package/dist/src/core/increment/auto-transition-manager.d.ts.map +1 -1
- package/dist/src/core/increment/auto-transition-manager.js +45 -0
- package/dist/src/core/increment/auto-transition-manager.js.map +1 -1
- package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
- package/dist/src/core/increment/metadata-manager.js +46 -0
- package/dist/src/core/increment/metadata-manager.js.map +1 -1
- package/dist/src/core/increment/status-change-sync-trigger.d.ts +12 -0
- package/dist/src/core/increment/status-change-sync-trigger.d.ts.map +1 -1
- package/dist/src/core/increment/status-change-sync-trigger.js +48 -2
- package/dist/src/core/increment/status-change-sync-trigger.js.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.d.ts +13 -0
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.js +40 -0
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/repo-structure/repo-bulk-discovery.d.ts.map +1 -1
- package/dist/src/core/repo-structure/repo-bulk-discovery.js +63 -83
- package/dist/src/core/repo-structure/repo-bulk-discovery.js.map +1 -1
- package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
- package/dist/src/core/repo-structure/repo-structure-manager.js +339 -424
- package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
- package/dist/src/core/sync/bidirectional-engine.d.ts.map +1 -1
- package/dist/src/core/sync/bidirectional-engine.js +21 -29
- package/dist/src/core/sync/bidirectional-engine.js.map +1 -1
- package/dist/src/init/InitFlow.js +15 -19
- package/dist/src/init/InitFlow.js.map +1 -1
- package/dist/src/init/repo/types.d.ts +1 -1
- package/dist/src/integrations/ado/area-path-mapper.d.ts.map +1 -1
- package/dist/src/integrations/ado/area-path-mapper.js +19 -23
- package/dist/src/integrations/ado/area-path-mapper.js.map +1 -1
- package/dist/src/utils/external-resource-validator.d.ts.map +1 -1
- package/dist/src/utils/external-resource-validator.js +41 -65
- package/dist/src/utils/external-resource-validator.js.map +1 -1
- package/dist/src/utils/project-detection.d.ts.map +1 -1
- package/dist/src/utils/project-detection.js +19 -21
- package/dist/src/utils/project-detection.js.map +1 -1
- package/dist/src/utils/project-validator.d.ts.map +1 -1
- package/dist/src/utils/project-validator.js +5 -7
- package/dist/src/utils/project-validator.js.map +1 -1
- package/package.json +2 -3
- package/plugins/specweave/agents/tech-lead/AGENT.md +9 -0
- package/plugins/specweave/hooks/docs-changed.sh.backup +79 -0
- package/plugins/specweave/hooks/human-input-required.sh.backup +75 -0
- package/plugins/specweave/hooks/post-first-increment.sh.backup +61 -0
- package/plugins/specweave/hooks/post-increment-change.sh.backup +98 -0
- package/plugins/specweave/hooks/post-increment-completion.sh.backup +231 -0
- package/plugins/specweave/hooks/post-increment-planning.sh.backup +1048 -0
- package/plugins/specweave/hooks/post-increment-status-change.sh.backup +147 -0
- package/plugins/specweave/hooks/post-spec-update.sh.backup +158 -0
- package/plugins/specweave/hooks/post-user-story-complete.sh.backup +179 -0
- package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +83 -0
- package/plugins/specweave/hooks/pre-implementation.sh.backup +67 -0
- package/plugins/specweave/hooks/pre-task-completion.sh.backup +194 -0
- package/plugins/specweave/hooks/pre-tool-use.sh.backup +133 -0
- package/plugins/specweave/hooks/user-prompt-submit.sh.backup +386 -0
- package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.d.ts +12 -0
- package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.js +45 -0
- package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.js.map +1 -1
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js +46 -0
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js.map +1 -1
- package/plugins/specweave/skills/increment-planner/SKILL.md +10 -5
- package/plugins/specweave/skills/specweave-framework/SKILL.md +6 -4
- package/plugins/specweave/templates/coding-standards.md.template +36 -0
- package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +353 -0
- package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +172 -0
- package/plugins/specweave-ado/lib/ado-multi-project-sync.js +1 -0
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
- package/plugins/specweave-ado/lib/project-selector.js +56 -67
- package/plugins/specweave-ado/lib/project-selector.ts +72 -85
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +1104 -0
- package/plugins/specweave-github/hooks/post-task-completion.sh.backup +258 -0
- package/plugins/specweave-github/lib/repo-selector.js +55 -66
- package/plugins/specweave-github/lib/repo-selector.ts +73 -84
- package/plugins/specweave-jira/commands/import-projects.js +3 -5
- package/plugins/specweave-jira/commands/import-projects.ts +3 -5
- package/plugins/specweave-jira/hooks/post-task-completion.sh.backup +172 -0
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
- package/plugins/specweave-jira/lib/project-selector.js +60 -71
- package/plugins/specweave-jira/lib/project-selector.ts +78 -91
- package/plugins/specweave-jira/lib/setup-wizard.js +51 -72
- package/plugins/specweave-jira/lib/setup-wizard.ts +56 -74
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +1017 -0
- package/plugins/specweave-release/hooks/post-task-completion.sh.backup +110 -0
- package/src/templates/CLAUDE.md.template +14 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# SpecWeave GitHub Sync Hook
|
|
4
|
+
# Runs after task completion to sync progress to GitHub Projects
|
|
5
|
+
#
|
|
6
|
+
# ARCHITECTURE (v0.19.0+): IMMUTABLE DESCRIPTIONS + PROGRESS COMMENTS
|
|
7
|
+
# - User Story files (.specweave/docs/internal/specs/) ↔ GitHub Issues
|
|
8
|
+
# - Issue descriptions created once (IMMUTABLE snapshot)
|
|
9
|
+
# - All updates via progress comments (audit trail)
|
|
10
|
+
#
|
|
11
|
+
# This hook is part of the specweave-github plugin and handles:
|
|
12
|
+
# - Finding which spec user stories the current work belongs to
|
|
13
|
+
# - Syncing progress via GitHub comments (NOT editing issue body)
|
|
14
|
+
# - Creating audit trail of all changes over time
|
|
15
|
+
# - Notifying stakeholders via GitHub notifications
|
|
16
|
+
#
|
|
17
|
+
# Dependencies:
|
|
18
|
+
# - Node.js and TypeScript CLI (dist/cli/commands/sync-spec-content.js)
|
|
19
|
+
# - GitHub CLI (gh) must be installed and authenticated
|
|
20
|
+
# - ProgressCommentBuilder (lib/progress-comment-builder.ts)
|
|
21
|
+
|
|
22
|
+
set -e
|
|
23
|
+
|
|
24
|
+
# ============================================================================
|
|
25
|
+
# PROJECT ROOT DETECTION
|
|
26
|
+
# ============================================================================
|
|
27
|
+
|
|
28
|
+
# Find project root by searching upward for .specweave/ directory
|
|
29
|
+
find_project_root() {
|
|
30
|
+
local dir="$1"
|
|
31
|
+
while [ "$dir" != "/" ]; do
|
|
32
|
+
if [ -d "$dir/.specweave" ]; then
|
|
33
|
+
echo "$dir"
|
|
34
|
+
return 0
|
|
35
|
+
fi
|
|
36
|
+
dir="$(dirname "$dir")"
|
|
37
|
+
done
|
|
38
|
+
# Fallback: try current directory
|
|
39
|
+
if [ -d "$(pwd)/.specweave" ]; then
|
|
40
|
+
pwd
|
|
41
|
+
else
|
|
42
|
+
echo "$(pwd)"
|
|
43
|
+
fi
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
PROJECT_ROOT="$(find_project_root "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")"
|
|
47
|
+
cd "$PROJECT_ROOT" 2>/dev/null || true
|
|
48
|
+
|
|
49
|
+
# ============================================================================
|
|
50
|
+
# CONFIGURATION
|
|
51
|
+
# ============================================================================
|
|
52
|
+
|
|
53
|
+
LOGS_DIR=".specweave/logs"
|
|
54
|
+
DEBUG_LOG="$LOGS_DIR/hooks-debug.log"
|
|
55
|
+
|
|
56
|
+
mkdir -p "$LOGS_DIR" 2>/dev/null || true
|
|
57
|
+
|
|
58
|
+
# ============================================================================
|
|
59
|
+
# PRECONDITIONS CHECK
|
|
60
|
+
# ============================================================================
|
|
61
|
+
|
|
62
|
+
echo "[$(date)] [GitHub] 🔗 GitHub sync hook fired" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
63
|
+
|
|
64
|
+
# Check if Node.js is available
|
|
65
|
+
if ! command -v node &> /dev/null; then
|
|
66
|
+
echo "[$(date)] [GitHub] ⚠️ Node.js not found, skipping GitHub sync" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
67
|
+
cat <<EOF
|
|
68
|
+
{
|
|
69
|
+
"continue": true
|
|
70
|
+
}
|
|
71
|
+
EOF
|
|
72
|
+
exit 0
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
# Check if github-spec-content-sync CLI exists
|
|
76
|
+
SYNC_CLI="$PROJECT_ROOT/dist/src/cli/commands/sync-spec-content.js"
|
|
77
|
+
if [ ! -f "$SYNC_CLI" ]; then
|
|
78
|
+
echo "[$(date)] [GitHub] ⚠️ sync-spec-content CLI not found at $SYNC_CLI, skipping sync" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
79
|
+
cat <<EOF
|
|
80
|
+
{
|
|
81
|
+
"continue": true
|
|
82
|
+
}
|
|
83
|
+
EOF
|
|
84
|
+
exit 0
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# Check for gh CLI
|
|
88
|
+
if ! command -v gh &> /dev/null; then
|
|
89
|
+
echo "[$(date)] [GitHub] ⚠️ GitHub CLI (gh) not found, skipping sync" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
90
|
+
cat <<EOF
|
|
91
|
+
{
|
|
92
|
+
"continue": true
|
|
93
|
+
}
|
|
94
|
+
EOF
|
|
95
|
+
exit 0
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
# ============================================================================
|
|
99
|
+
# DETECT ALL SPECS (Multi-Spec Support)
|
|
100
|
+
# ============================================================================
|
|
101
|
+
|
|
102
|
+
# Strategy: Use multi-spec detector to find ALL specs referenced in current increment
|
|
103
|
+
|
|
104
|
+
# 1. Detect current increment (temporary context)
|
|
105
|
+
CURRENT_INCREMENT=$(ls -td .specweave/increments/*/ 2>/dev/null | xargs -n1 basename | grep -v "_backlog" | grep -v "_archive" | grep -v "_working" | head -1)
|
|
106
|
+
|
|
107
|
+
if [ -z "$CURRENT_INCREMENT" ]; then
|
|
108
|
+
echo "[$(date)] [GitHub] ℹ️ No active increment, checking for spec changes..." >> "$DEBUG_LOG" 2>/dev/null || true
|
|
109
|
+
# Fall through to sync all changed specs
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
# 2. Use TypeScript CLI to detect all specs
|
|
113
|
+
DETECT_CLI="$PROJECT_ROOT/dist/src/cli/commands/detect-specs.js"
|
|
114
|
+
|
|
115
|
+
if [ -f "$DETECT_CLI" ]; then
|
|
116
|
+
echo "[$(date)] [GitHub] 🔍 Detecting all specs in increment $CURRENT_INCREMENT..." >> "$DEBUG_LOG" 2>/dev/null || true
|
|
117
|
+
|
|
118
|
+
# Call detect-specs CLI and capture JSON output
|
|
119
|
+
DETECTION_RESULT=$(node "$DETECT_CLI" 2>> "$DEBUG_LOG" || echo "{}")
|
|
120
|
+
|
|
121
|
+
# Extract spec count
|
|
122
|
+
SPEC_COUNT=$(echo "$DETECTION_RESULT" | node -e "const fs=require('fs'); const data=JSON.parse(fs.readFileSync(0,'utf-8')); console.log(data.specs?.length || 0)")
|
|
123
|
+
|
|
124
|
+
echo "[$(date)] [GitHub] 📋 Detected $SPEC_COUNT spec(s)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
125
|
+
|
|
126
|
+
# Store detection result for later use
|
|
127
|
+
echo "$DETECTION_RESULT" > /tmp/specweave-detected-specs.json
|
|
128
|
+
else
|
|
129
|
+
echo "[$(date)] [GitHub] ⚠️ detect-specs CLI not found at $DETECT_CLI, falling back to git diff" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
130
|
+
SPEC_COUNT=0
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
# ============================================================================
|
|
134
|
+
# SYNC ALL DETECTED SPECS TO GITHUB (Multi-Spec Support)
|
|
135
|
+
# ============================================================================
|
|
136
|
+
|
|
137
|
+
if [ -f /tmp/specweave-detected-specs.json ] && [ "$SPEC_COUNT" -gt 0 ]; then
|
|
138
|
+
# Multi-spec sync: Loop through all detected specs
|
|
139
|
+
echo "[$(date)] [GitHub] 🔄 Syncing $SPEC_COUNT spec(s) to GitHub..." >> "$DEBUG_LOG" 2>/dev/null || true
|
|
140
|
+
|
|
141
|
+
# Extract spec paths using Node.js
|
|
142
|
+
SPEC_PATHS=$(node -e "
|
|
143
|
+
const fs = require('fs');
|
|
144
|
+
const data = JSON.parse(fs.readFileSync('/tmp/specweave-detected-specs.json', 'utf-8'));
|
|
145
|
+
const syncable = data.specs.filter(s => s.syncEnabled && s.project !== '_parent');
|
|
146
|
+
syncable.forEach(s => console.log(s.path));
|
|
147
|
+
" 2>> "$DEBUG_LOG")
|
|
148
|
+
|
|
149
|
+
# Count syncable specs
|
|
150
|
+
SYNCABLE_COUNT=$(echo "$SPEC_PATHS" | grep -v '^$' | wc -l | tr -d ' ')
|
|
151
|
+
|
|
152
|
+
if [ "$SYNCABLE_COUNT" -gt 0 ]; then
|
|
153
|
+
echo "[$(date)] [GitHub] 📋 Syncing $SYNCABLE_COUNT syncable spec(s) (excluding _parent)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
154
|
+
|
|
155
|
+
# Sync each spec
|
|
156
|
+
echo "$SPEC_PATHS" | while read -r SPEC_FILE; do
|
|
157
|
+
if [ -n "$SPEC_FILE" ] && [ -f "$SPEC_FILE" ]; then
|
|
158
|
+
# Extract project and spec ID from path
|
|
159
|
+
SPEC_NAME=$(basename "$SPEC_FILE" .md)
|
|
160
|
+
PROJECT=$(basename "$(dirname "$SPEC_FILE")")
|
|
161
|
+
|
|
162
|
+
echo "[$(date)] [GitHub] 🔄 Syncing $PROJECT/$SPEC_NAME..." >> "$DEBUG_LOG" 2>/dev/null || true
|
|
163
|
+
|
|
164
|
+
(cd "$PROJECT_ROOT" && node "$SYNC_CLI" --spec "$SPEC_FILE" --provider github) 2>&1 | tee -a "$DEBUG_LOG" >/dev/null || {
|
|
165
|
+
echo "[$(date)] [GitHub] ⚠️ Spec sync failed for $PROJECT/$SPEC_NAME (non-blocking)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
echo "[$(date)] [GitHub] ✅ Synced $PROJECT/$SPEC_NAME" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
169
|
+
fi
|
|
170
|
+
done
|
|
171
|
+
|
|
172
|
+
echo "[$(date)] [GitHub] ✅ Multi-spec sync complete ($SYNCABLE_COUNT synced)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
173
|
+
else
|
|
174
|
+
echo "[$(date)] [GitHub] ℹ️ No syncable specs (all specs are _parent or syncEnabled=false)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
# Cleanup temp file
|
|
178
|
+
rm -f /tmp/specweave-detected-specs.json 2>/dev/null || true
|
|
179
|
+
else
|
|
180
|
+
# Fallback: Sync all modified specs (check git diff)
|
|
181
|
+
echo "[$(date)] [GitHub] 🔄 Checking for modified specs..." >> "$DEBUG_LOG" 2>/dev/null || true
|
|
182
|
+
|
|
183
|
+
MODIFIED_SPECS=$(git diff --name-only HEAD .specweave/docs/internal/specs/**/*.md 2>/dev/null || echo "")
|
|
184
|
+
|
|
185
|
+
if [ -n "$MODIFIED_SPECS" ]; then
|
|
186
|
+
echo "[$(date)] [GitHub] 📝 Found modified specs:" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
187
|
+
echo "$MODIFIED_SPECS" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
188
|
+
|
|
189
|
+
# Sync each modified spec
|
|
190
|
+
echo "$MODIFIED_SPECS" | while read -r SPEC_FILE; do
|
|
191
|
+
if [ -n "$SPEC_FILE" ] && [ -f "$SPEC_FILE" ]; then
|
|
192
|
+
echo "[$(date)] [GitHub] 🔄 Syncing $SPEC_FILE..." >> "$DEBUG_LOG" 2>/dev/null || true
|
|
193
|
+
(cd "$PROJECT_ROOT" && node "$SYNC_CLI" --spec "$SPEC_FILE" --provider github) 2>&1 | tee -a "$DEBUG_LOG" >/dev/null || true
|
|
194
|
+
fi
|
|
195
|
+
done
|
|
196
|
+
|
|
197
|
+
echo "[$(date)] [GitHub] ✅ Batch spec sync complete" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
198
|
+
else
|
|
199
|
+
echo "[$(date)] [GitHub] ℹ️ No modified specs found, skipping sync" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
200
|
+
fi
|
|
201
|
+
fi
|
|
202
|
+
|
|
203
|
+
# ============================================================================
|
|
204
|
+
# EPIC GITHUB ISSUE SYNC (DEPRECATED v0.24.0+)
|
|
205
|
+
# ============================================================================
|
|
206
|
+
#
|
|
207
|
+
# ⚠️ DEPRECATED: SpecWeave now syncs ONLY at User Story level.
|
|
208
|
+
#
|
|
209
|
+
# Feature/Epic-level issues are no longer updated.
|
|
210
|
+
# Use /specweave-github:sync instead to sync User Story issues.
|
|
211
|
+
#
|
|
212
|
+
# To re-enable (NOT recommended):
|
|
213
|
+
# export SPECWEAVE_ENABLE_EPIC_SYNC=true
|
|
214
|
+
#
|
|
215
|
+
# @see .specweave/increments/0047-us-task-linkage/reports/GITHUB-TITLE-FORMAT-FIX-PLAN.md
|
|
216
|
+
# ============================================================================
|
|
217
|
+
|
|
218
|
+
if [ "$SPECWEAVE_ENABLE_EPIC_SYNC" = "true" ]; then
|
|
219
|
+
echo "[$(date)] [GitHub] 🔄 Checking for Epic GitHub issue update (DEPRECATED)..." >> "$DEBUG_LOG" 2>/dev/null || true
|
|
220
|
+
|
|
221
|
+
# Find active increment ID
|
|
222
|
+
ACTIVE_INCREMENT=$(ls -t .specweave/increments/ | grep -v '^\.' | while read inc; do
|
|
223
|
+
if [ -f ".specweave/increments/$inc/metadata.json" ]; then
|
|
224
|
+
STATUS=$(grep -o '"status"[[:space:]]*:[[:space:]]*"[^"]*"' ".specweave/increments/$inc/metadata.json" 2>/dev/null | sed 's/.*"\([^"]*\)".*/\1/' || true)
|
|
225
|
+
if [ "$STATUS" = "active" ]; then
|
|
226
|
+
echo "$inc"
|
|
227
|
+
break
|
|
228
|
+
fi
|
|
229
|
+
fi
|
|
230
|
+
done | head -1)
|
|
231
|
+
|
|
232
|
+
if [ -n "$ACTIVE_INCREMENT" ]; then
|
|
233
|
+
echo "[$(date)] [GitHub] 🎯 Active increment: $ACTIVE_INCREMENT" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
234
|
+
|
|
235
|
+
# Run Epic sync script (silently, errors logged to debug log)
|
|
236
|
+
if [ -f "$PROJECT_ROOT/scripts/update-epic-github-issue.sh" ]; then
|
|
237
|
+
echo "[$(date)] [GitHub] 🚀 Updating Epic GitHub issue (DEPRECATED)..." >> "$DEBUG_LOG" 2>/dev/null || true
|
|
238
|
+
"$PROJECT_ROOT/scripts/update-epic-github-issue.sh" "$ACTIVE_INCREMENT" >> "$DEBUG_LOG" 2>&1 || true
|
|
239
|
+
echo "[$(date)] [GitHub] ⚠️ Epic sync is deprecated. Use /specweave-github:sync instead." >> "$DEBUG_LOG" 2>/dev/null || true
|
|
240
|
+
else
|
|
241
|
+
echo "[$(date)] [GitHub] ⚠️ Epic sync script not found, skipping" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
242
|
+
fi
|
|
243
|
+
else
|
|
244
|
+
echo "[$(date)] [GitHub] ℹ️ No active increment found, skipping Epic sync" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
245
|
+
fi
|
|
246
|
+
else
|
|
247
|
+
echo "[$(date)] [GitHub] ℹ️ Epic sync disabled (sync at User Story level only)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
248
|
+
fi
|
|
249
|
+
|
|
250
|
+
# ============================================================================
|
|
251
|
+
# OUTPUT TO CLAUDE
|
|
252
|
+
# ============================================================================
|
|
253
|
+
|
|
254
|
+
cat <<EOF
|
|
255
|
+
{
|
|
256
|
+
"continue": true
|
|
257
|
+
}
|
|
258
|
+
EOF
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { select, checkbox, input, Separator } from "@inquirer/prompts";
|
|
2
2
|
import { GitHubClient } from "./github-client.js";
|
|
3
3
|
async function fetchAllGitHubRepos(owner, limit = 100) {
|
|
4
4
|
console.log("\u{1F50D} Fetching GitHub repositories...");
|
|
@@ -34,29 +34,25 @@ async function selectGitHubRepos(options = {}) {
|
|
|
34
34
|
console.log("\u{1F4CB} Available GitHub Repositories:\n");
|
|
35
35
|
console.log(` Total: ${allRepos.length} repositories
|
|
36
36
|
`);
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
37
|
+
const selectionMethod = await select({
|
|
38
|
+
message: "How would you like to select repositories?",
|
|
39
|
+
choices: [
|
|
40
|
+
{
|
|
41
|
+
name: `\u{1F4CB} Interactive (browse and select from ${allRepos.length} repositories)`,
|
|
42
|
+
value: "interactive"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: "\u270F\uFE0F Manual entry (type repository names)",
|
|
46
|
+
value: "manual"
|
|
47
|
+
},
|
|
48
|
+
...allowSelectAll ? [
|
|
47
49
|
{
|
|
48
|
-
name:
|
|
49
|
-
value: "
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
value: "all"
|
|
55
|
-
}
|
|
56
|
-
] : []
|
|
57
|
-
]
|
|
58
|
-
}
|
|
59
|
-
]);
|
|
50
|
+
name: `\u2728 Select all (${allRepos.length} repositories)`,
|
|
51
|
+
value: "all"
|
|
52
|
+
}
|
|
53
|
+
] : []
|
|
54
|
+
]
|
|
55
|
+
});
|
|
60
56
|
if (selectionMethod === "all") {
|
|
61
57
|
return {
|
|
62
58
|
selectedRepos: allRepos.map((r) => r.fullName),
|
|
@@ -81,34 +77,31 @@ async function interactiveRepoSelection(allRepos, preSelected, minSelection, max
|
|
|
81
77
|
value: r.fullName,
|
|
82
78
|
checked: preSelected.includes(r.fullName)
|
|
83
79
|
}));
|
|
84
|
-
|
|
85
|
-
|
|
80
|
+
const allChoices = [
|
|
81
|
+
...choices,
|
|
82
|
+
new Separator(),
|
|
86
83
|
{
|
|
87
84
|
name: "\u270F\uFE0F Enter repository names manually instead",
|
|
88
85
|
value: "__MANUAL__",
|
|
89
86
|
checked: false
|
|
90
87
|
}
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
{
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
if (maxSelection && actualSelected.length > maxSelection) {
|
|
106
|
-
return `Please select at most ${maxSelection} repository(ies)`;
|
|
107
|
-
}
|
|
108
|
-
return true;
|
|
88
|
+
];
|
|
89
|
+
const selectedRepos = await checkbox({
|
|
90
|
+
message: `Select GitHub repositories (${minSelection}${maxSelection ? `-${maxSelection}` : "+"} required):`,
|
|
91
|
+
choices: allChoices,
|
|
92
|
+
pageSize,
|
|
93
|
+
loop: false,
|
|
94
|
+
validate: (selected) => {
|
|
95
|
+
const actualSelected = selected.filter((k) => k !== "__MANUAL__");
|
|
96
|
+
if (actualSelected.length < minSelection) {
|
|
97
|
+
return `Please select at least ${minSelection} repository(ies)`;
|
|
98
|
+
}
|
|
99
|
+
if (maxSelection && actualSelected.length > maxSelection) {
|
|
100
|
+
return `Please select at most ${maxSelection} repository(ies)`;
|
|
109
101
|
}
|
|
102
|
+
return true;
|
|
110
103
|
}
|
|
111
|
-
|
|
104
|
+
});
|
|
112
105
|
if (selectedRepos.includes("__MANUAL__")) {
|
|
113
106
|
return await manualRepoEntry(allRepos, minSelection, maxSelection);
|
|
114
107
|
}
|
|
@@ -130,30 +123,26 @@ async function manualRepoEntry(allRepos, minSelection, maxSelection) {
|
|
|
130
123
|
);
|
|
131
124
|
console.log("");
|
|
132
125
|
}
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
if (maxSelection && repos.length > maxSelection) {
|
|
147
|
-
return `Please enter at most ${maxSelection} repository name(s)`;
|
|
148
|
-
}
|
|
149
|
-
const invalidRepos = repos.filter((r) => !/^[a-zA-Z0-9_-]+\/[a-zA-Z0-9_.-]+$/.test(r));
|
|
150
|
-
if (invalidRepos.length > 0) {
|
|
151
|
-
return `Invalid repository format: ${invalidRepos.join(", ")}. Use owner/repo format (e.g., octocat/Hello-World).`;
|
|
152
|
-
}
|
|
153
|
-
return true;
|
|
126
|
+
const manualRepos = await input({
|
|
127
|
+
message: "Repository names:",
|
|
128
|
+
validate: (inputValue) => {
|
|
129
|
+
if (!inputValue.trim()) {
|
|
130
|
+
return "Please enter at least one repository name";
|
|
131
|
+
}
|
|
132
|
+
const repos = inputValue.split(",").map((r) => r.trim()).filter((r) => r.length > 0);
|
|
133
|
+
if (repos.length < minSelection) {
|
|
134
|
+
return `Please enter at least ${minSelection} repository name(s)`;
|
|
135
|
+
}
|
|
136
|
+
if (maxSelection && repos.length > maxSelection) {
|
|
137
|
+
return `Please enter at most ${maxSelection} repository name(s)`;
|
|
154
138
|
}
|
|
139
|
+
const invalidRepos = repos.filter((r) => !/^[a-zA-Z0-9_-]+\/[a-zA-Z0-9_.-]+$/.test(r));
|
|
140
|
+
if (invalidRepos.length > 0) {
|
|
141
|
+
return `Invalid repository format: ${invalidRepos.join(", ")}. Use owner/repo format (e.g., octocat/Hello-World).`;
|
|
142
|
+
}
|
|
143
|
+
return true;
|
|
155
144
|
}
|
|
156
|
-
|
|
145
|
+
});
|
|
157
146
|
const selectedRepos = manualRepos.split(",").map((r) => r.trim()).filter((r) => r.length > 0);
|
|
158
147
|
const knownRepos = allRepos.map((r) => r.fullName);
|
|
159
148
|
const unknownRepos = selectedRepos.filter((r) => !knownRepos.includes(r));
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* - Validates repo names
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import
|
|
12
|
+
import { select, checkbox, input, Separator } from '@inquirer/prompts';
|
|
13
13
|
import { GitHubClient } from './github-client.js';
|
|
14
14
|
|
|
15
15
|
// ============================================================================
|
|
@@ -109,31 +109,27 @@ export async function selectGitHubRepos(
|
|
|
109
109
|
console.log(` Total: ${allRepos.length} repositories\n`);
|
|
110
110
|
|
|
111
111
|
// Decide selection method
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
: []),
|
|
134
|
-
],
|
|
135
|
-
},
|
|
136
|
-
]);
|
|
112
|
+
const selectionMethod = await select({
|
|
113
|
+
message: 'How would you like to select repositories?',
|
|
114
|
+
choices: [
|
|
115
|
+
{
|
|
116
|
+
name: `📋 Interactive (browse and select from ${allRepos.length} repositories)`,
|
|
117
|
+
value: 'interactive',
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: '✏️ Manual entry (type repository names)',
|
|
121
|
+
value: 'manual',
|
|
122
|
+
},
|
|
123
|
+
...(allowSelectAll
|
|
124
|
+
? [
|
|
125
|
+
{
|
|
126
|
+
name: `✨ Select all (${allRepos.length} repositories)`,
|
|
127
|
+
value: 'all',
|
|
128
|
+
},
|
|
129
|
+
]
|
|
130
|
+
: []),
|
|
131
|
+
],
|
|
132
|
+
});
|
|
137
133
|
|
|
138
134
|
if (selectionMethod === 'all') {
|
|
139
135
|
return {
|
|
@@ -175,38 +171,35 @@ async function interactiveRepoSelection(
|
|
|
175
171
|
}));
|
|
176
172
|
|
|
177
173
|
// Add manual entry option at the end
|
|
178
|
-
|
|
179
|
-
|
|
174
|
+
const allChoices = [
|
|
175
|
+
...choices,
|
|
176
|
+
new Separator(),
|
|
180
177
|
{
|
|
181
178
|
name: '✏️ Enter repository names manually instead',
|
|
182
179
|
value: '__MANUAL__',
|
|
183
180
|
checked: false,
|
|
184
|
-
}
|
|
185
|
-
|
|
181
|
+
},
|
|
182
|
+
];
|
|
186
183
|
|
|
187
|
-
const
|
|
188
|
-
{
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
return true;
|
|
207
|
-
},
|
|
184
|
+
const selectedRepos = await checkbox({
|
|
185
|
+
message: `Select GitHub repositories (${minSelection}${maxSelection ? `-${maxSelection}` : '+'} required):`,
|
|
186
|
+
choices: allChoices,
|
|
187
|
+
pageSize,
|
|
188
|
+
loop: false,
|
|
189
|
+
validate: (selected: readonly string[]) => {
|
|
190
|
+
const actualSelected = selected.filter((k) => k !== '__MANUAL__');
|
|
191
|
+
|
|
192
|
+
if (actualSelected.length < minSelection) {
|
|
193
|
+
return `Please select at least ${minSelection} repository(ies)`;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (maxSelection && actualSelected.length > maxSelection) {
|
|
197
|
+
return `Please select at most ${maxSelection} repository(ies)`;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return true;
|
|
208
201
|
},
|
|
209
|
-
|
|
202
|
+
});
|
|
210
203
|
|
|
211
204
|
// Check if user chose manual entry
|
|
212
205
|
if (selectedRepos.includes('__MANUAL__')) {
|
|
@@ -243,39 +236,35 @@ async function manualRepoEntry(
|
|
|
243
236
|
console.log('');
|
|
244
237
|
}
|
|
245
238
|
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
return true;
|
|
276
|
-
},
|
|
239
|
+
const manualRepos = await input({
|
|
240
|
+
message: 'Repository names:',
|
|
241
|
+
validate: (inputValue: string) => {
|
|
242
|
+
if (!inputValue.trim()) {
|
|
243
|
+
return 'Please enter at least one repository name';
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const repos = inputValue
|
|
247
|
+
.split(',')
|
|
248
|
+
.map((r) => r.trim())
|
|
249
|
+
.filter((r) => r.length > 0);
|
|
250
|
+
|
|
251
|
+
if (repos.length < minSelection) {
|
|
252
|
+
return `Please enter at least ${minSelection} repository name(s)`;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (maxSelection && repos.length > maxSelection) {
|
|
256
|
+
return `Please enter at most ${maxSelection} repository name(s)`;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Validate format (owner/repo)
|
|
260
|
+
const invalidRepos = repos.filter((r) => !/^[a-zA-Z0-9_-]+\/[a-zA-Z0-9_.-]+$/.test(r));
|
|
261
|
+
if (invalidRepos.length > 0) {
|
|
262
|
+
return `Invalid repository format: ${invalidRepos.join(', ')}. Use owner/repo format (e.g., octocat/Hello-World).`;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return true;
|
|
277
266
|
},
|
|
278
|
-
|
|
267
|
+
});
|
|
279
268
|
|
|
280
269
|
const selectedRepos = manualRepos
|
|
281
270
|
.split(',')
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
-
import
|
|
2
|
+
import { confirm } from "@inquirer/prompts";
|
|
3
3
|
import { existsSync } from "fs";
|
|
4
4
|
import path from "path";
|
|
5
5
|
import { JiraClient } from "../../../src/integrations/jira/jira-client.js";
|
|
@@ -98,12 +98,10 @@ async function importProjects(options = {}) {
|
|
|
98
98
|
`));
|
|
99
99
|
return;
|
|
100
100
|
}
|
|
101
|
-
const
|
|
102
|
-
type: "confirm",
|
|
103
|
-
name: "confirmed",
|
|
101
|
+
const confirmed = await confirm({
|
|
104
102
|
message: `Import ${newProjects.length} new project(s)?`,
|
|
105
103
|
default: true
|
|
106
|
-
}
|
|
104
|
+
});
|
|
107
105
|
if (!confirmed) {
|
|
108
106
|
console.log(chalk.yellow("\n\u23ED\uFE0F Import canceled\n"));
|
|
109
107
|
return;
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import chalk from 'chalk';
|
|
21
|
-
import
|
|
21
|
+
import { confirm } from '@inquirer/prompts';
|
|
22
22
|
import { existsSync } from 'fs';
|
|
23
23
|
import path from 'path';
|
|
24
24
|
import { JiraClient } from '../../../src/integrations/jira/jira-client.js';
|
|
@@ -175,12 +175,10 @@ export async function importProjects(options: ImportProjectsOptions = {}): Promi
|
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
// Step 9: Confirm import
|
|
178
|
-
const
|
|
179
|
-
type: 'confirm',
|
|
180
|
-
name: 'confirmed',
|
|
178
|
+
const confirmed = await confirm({
|
|
181
179
|
message: `Import ${newProjects.length} new project(s)?`,
|
|
182
180
|
default: true
|
|
183
|
-
}
|
|
181
|
+
});
|
|
184
182
|
|
|
185
183
|
if (!confirmed) {
|
|
186
184
|
console.log(chalk.yellow('\n⏭️ Import canceled\n'));
|