fraim-framework 2.0.30 → 2.0.34
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/bin/fraim.js +3 -18
- package/dist/src/cli/commands/init.js +29 -2
- package/dist/src/cli/commands/sync.js +82 -70
- package/dist/src/utils/script-sync-utils.js +216 -0
- package/dist/tests/debug-tools.js +6 -5
- package/dist/tests/test-chalk-regression.js +58 -8
- package/dist/tests/test-cli.js +70 -5
- package/dist/tests/test-end-to-end-hybrid-validation.js +328 -0
- package/dist/tests/test-first-run-journey.js +43 -3
- package/dist/tests/test-hybrid-script-execution.js +340 -0
- package/dist/tests/test-mcp-connection.js +2 -2
- package/dist/tests/test-mcp-issue-integration.js +12 -4
- package/dist/tests/test-mcp-lifecycle-methods.js +4 -4
- package/dist/tests/test-node-compatibility.js +24 -2
- package/dist/tests/test-prep-issue.js +4 -1
- package/dist/tests/test-script-location-independence.js +173 -0
- package/dist/tests/test-script-sync.js +557 -0
- package/dist/tests/test-session-rehydration.js +2 -2
- package/dist/tests/test-standalone.js +3 -3
- package/dist/tests/test-sync-version-update.js +1 -1
- package/dist/tests/test-telemetry.js +2 -2
- package/dist/tests/test-user-journey.js +8 -4
- package/dist/tests/test-utils.js +13 -0
- package/dist/tests/test-wizard.js +2 -2
- package/package.json +3 -3
- package/registry/rules/agent-testing-guidelines.md +502 -502
- package/registry/rules/ephemeral-execution.md +37 -27
- package/registry/rules/local-development.md +253 -251
- package/registry/rules/successful-debugging-patterns.md +491 -482
- package/registry/scripts/prep-issue.sh +468 -468
- package/registry/workflows/bootstrap/evaluate-code-quality.md +8 -2
- package/registry/workflows/bootstrap/verify-test-coverage.md +8 -2
- package/registry/workflows/customer-development/thank-customers.md +203 -193
- package/registry/workflows/customer-development/weekly-newsletter.md +366 -362
- package/registry/workflows/performance/analyze-performance.md +65 -63
- package/registry/workflows/product-building/implement.md +6 -2
- package/registry/workflows/product-building/prep-issue.md +11 -24
- package/registry/workflows/product-building/resolve.md +5 -1
- package/registry/workflows/replicate/replicate-discovery.md +336 -0
- package/registry/workflows/replicate/replicate-to-issues.md +319 -0
- package/registry/workflows/reviewer/review-implementation-vs-design-spec.md +632 -632
- package/.windsurf/rules/windsurf-rules.md +0 -7
- package/.windsurf/workflows/resolve-issue.md +0 -6
- package/.windsurf/workflows/retrospect.md +0 -6
- package/.windsurf/workflows/start-design.md +0 -6
- package/.windsurf/workflows/start-impl.md +0 -6
- package/.windsurf/workflows/start-spec.md +0 -6
- package/.windsurf/workflows/start-tests.md +0 -6
- package/registry/scripts/build-scripts-generator.ts +0 -216
- package/registry/scripts/cleanup-branch.ts +0 -303
- package/registry/scripts/fraim-config.ts +0 -63
- package/registry/scripts/generate-engagement-emails.ts +0 -744
- package/registry/scripts/generic-issues-api.ts +0 -110
- package/registry/scripts/newsletter-helpers.ts +0 -874
- package/registry/scripts/openapi-generator.ts +0 -695
- package/registry/scripts/performance/profile-server.ts +0 -370
- package/registry/scripts/run-thank-you-workflow.ts +0 -122
- package/registry/scripts/send-newsletter-simple.ts +0 -104
- package/registry/scripts/send-thank-you-emails.ts +0 -57
- package/registry/workflows/replicate/re-implementation-strategy.md +0 -226
- package/registry/workflows/replicate/use-case-extraction.md +0 -135
- package/registry/workflows/replicate/visual-analysis.md +0 -154
- package/registry/workflows/replicate/website-discovery-analysis.md +0 -231
- package/sample_package.json +0 -18
- /package/registry/scripts/{replicate/comprehensive-explorer.py → comprehensive-explorer.py} +0 -0
- /package/registry/scripts/{replicate/interactive-explorer.py → interactive-explorer.py} +0 -0
- /package/registry/scripts/{replicate/scrape-site.py → scrape-site.py} +0 -0
|
@@ -1,468 +1,468 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
set -e # Exit on any error
|
|
4
|
-
|
|
5
|
-
# Default flags (can be overridden by command line)
|
|
6
|
-
SKIP_INSTALL=false
|
|
7
|
-
SKIP_SERENA=true
|
|
8
|
-
SKIP_EDITOR=true
|
|
9
|
-
USE_DEFAULT_BRANCH=
|
|
10
|
-
|
|
11
|
-
# Function to display usage
|
|
12
|
-
usage() {
|
|
13
|
-
echo "Usage: $0 <issue_number> [editor] [flags]"
|
|
14
|
-
echo "Example: $0 123"
|
|
15
|
-
echo "Example: $0 123 windsurf"
|
|
16
|
-
echo "Example: $0 123 claude --skip-install"
|
|
17
|
-
echo "Example: $0 123 cursor --use-default --skip-serena"
|
|
18
|
-
echo ""
|
|
19
|
-
echo "Editor options: windsurf, claude, claudecode, cursor (default)"
|
|
20
|
-
echo "If no editor specified, will try to detect from GitHub issue labels"
|
|
21
|
-
echo ""
|
|
22
|
-
echo "Flags:"
|
|
23
|
-
echo " --skip-install Skip npm install step"
|
|
24
|
-
echo " --skip-serena Skip Serena indexing step"
|
|
25
|
-
echo " --skip-editor Skip opening editor"
|
|
26
|
-
echo " --use-default Force branch creation from default branch (ignore current branch)"
|
|
27
|
-
echo " --help Show this help message"
|
|
28
|
-
exit 1
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
# Function to get editor from GitHub issue labels
|
|
32
|
-
get_editor_from_issue() {
|
|
33
|
-
local issue_num=$1
|
|
34
|
-
|
|
35
|
-
# Try to get the issue labels using GitHub CLI or curl
|
|
36
|
-
if command -v gh &> /dev/null; then
|
|
37
|
-
# Use GitHub CLI if available
|
|
38
|
-
local labels=$(gh issue view $issue_num -R "$REPO_OWNER/$REPO_NAME" --json labels --jq '.labels[].name' 2>/dev/null)
|
|
39
|
-
else
|
|
40
|
-
# Fallback to curl (requires GitHub token in GITHUB_TOKEN env var)
|
|
41
|
-
if [ -n "$GITHUB_TOKEN" ]; then
|
|
42
|
-
local labels=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
|
43
|
-
"https://api.github.com/repos/$REPO_OWNER/$REPO_NAME/issues/$issue_num" \
|
|
44
|
-
| grep -o '"name":"ai-agent:[^"]*"' | sed 's/"name":"ai-agent://' | sed 's/"//' 2>/dev/null)
|
|
45
|
-
else
|
|
46
|
-
echo "Warning: No GitHub CLI or GITHUB_TOKEN found. Cannot auto-detect editor from issue labels." >&2
|
|
47
|
-
return 1
|
|
48
|
-
fi
|
|
49
|
-
fi
|
|
50
|
-
|
|
51
|
-
# Look for ai-agent labels
|
|
52
|
-
for label in $labels; do
|
|
53
|
-
if [[ $label == ai-agent:* ]]; then
|
|
54
|
-
local editor=${label#ai-agent:}
|
|
55
|
-
echo "Found ai-agent label: $label -> editor: $editor" >&2
|
|
56
|
-
echo "$editor"
|
|
57
|
-
return 0
|
|
58
|
-
fi
|
|
59
|
-
done
|
|
60
|
-
|
|
61
|
-
echo "No ai-agent label found in issue #$issue_num, will continue without editor" >&2
|
|
62
|
-
return 0
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
# Parse command line arguments
|
|
66
|
-
if [ $# -eq 0 ]; then
|
|
67
|
-
echo "Error: Issue number is required"
|
|
68
|
-
usage
|
|
69
|
-
fi
|
|
70
|
-
|
|
71
|
-
ISSUE_NUMBER=$1
|
|
72
|
-
EDITOR="" # Will be set later if not provided
|
|
73
|
-
|
|
74
|
-
# Parse remaining arguments (editor and flags)
|
|
75
|
-
shift 1 # Remove issue_number
|
|
76
|
-
while [[ $# -gt 0 ]]; do
|
|
77
|
-
case $1 in
|
|
78
|
-
--skip-install)
|
|
79
|
-
SKIP_INSTALL=true
|
|
80
|
-
shift
|
|
81
|
-
;;
|
|
82
|
-
--skip-serena)
|
|
83
|
-
SKIP_SERENA=true
|
|
84
|
-
shift
|
|
85
|
-
;;
|
|
86
|
-
--skip-editor)
|
|
87
|
-
SKIP_EDITOR=true
|
|
88
|
-
shift
|
|
89
|
-
;;
|
|
90
|
-
--use-default)
|
|
91
|
-
USE_DEFAULT_BRANCH=true
|
|
92
|
-
shift
|
|
93
|
-
;;
|
|
94
|
-
--help)
|
|
95
|
-
usage
|
|
96
|
-
;;
|
|
97
|
-
windsurf|claude|claudecode|cursor)
|
|
98
|
-
# Valid editor names
|
|
99
|
-
if [ -z "$EDITOR" ]; then
|
|
100
|
-
EDITOR="$1"
|
|
101
|
-
else
|
|
102
|
-
echo "Error: Multiple editors specified: $EDITOR and $1"
|
|
103
|
-
usage
|
|
104
|
-
fi
|
|
105
|
-
shift
|
|
106
|
-
;;
|
|
107
|
-
*)
|
|
108
|
-
echo "Unknown argument: $1"
|
|
109
|
-
echo "Valid editors: windsurf, claude, claudecode, cursor"
|
|
110
|
-
echo "Valid flags: --skip-install, --skip-serena, --skip-editor, --use-default"
|
|
111
|
-
usage
|
|
112
|
-
;;
|
|
113
|
-
esac
|
|
114
|
-
done
|
|
115
|
-
|
|
116
|
-
# Load repository config from config.json
|
|
117
|
-
CONFIG_FILE=".fraim/config.json"
|
|
118
|
-
if [ ! -f "$CONFIG_FILE" ]; then
|
|
119
|
-
echo "Error: Config file not found at $CONFIG_FILE" >&2
|
|
120
|
-
exit 1
|
|
121
|
-
fi
|
|
122
|
-
|
|
123
|
-
if ! command -v node &> /dev/null; then
|
|
124
|
-
echo "Error: node is required but not installed." >&2
|
|
125
|
-
exit 1
|
|
126
|
-
fi
|
|
127
|
-
|
|
128
|
-
# Extract values using node reading from stdin to avoid path issues
|
|
129
|
-
NODE_SCRIPT="
|
|
130
|
-
const fs = require('fs');
|
|
131
|
-
try {
|
|
132
|
-
const input = fs.readFileSync(0, 'utf-8');
|
|
133
|
-
const config = JSON.parse(input);
|
|
134
|
-
|
|
135
|
-
// Support both 'repository' (new) and 'git' (legacy/current) schemas
|
|
136
|
-
let repo = config.repository;
|
|
137
|
-
|
|
138
|
-
if (!repo) {
|
|
139
|
-
if (config.git) {
|
|
140
|
-
repo = {
|
|
141
|
-
owner: config.git.repoOwner,
|
|
142
|
-
name: config.git.repoName,
|
|
143
|
-
url: config.git.repoUrl || \`https://github.com/\${config.git.repoOwner}/\${config.git.repoName}.git\`
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (!repo || !repo.owner || !repo.name || !repo.url) {
|
|
149
|
-
process.exit(1);
|
|
150
|
-
}
|
|
151
|
-
console.log(\`\${repo.owner}:\${repo.name}:\${repo.url}\`);
|
|
152
|
-
} catch (e) {
|
|
153
|
-
process.exit(1);
|
|
154
|
-
}
|
|
155
|
-
"
|
|
156
|
-
|
|
157
|
-
REPO_INFO=$(cat "$CONFIG_FILE" | node -e "$NODE_SCRIPT")
|
|
158
|
-
if [ $? -ne 0 ]; then
|
|
159
|
-
echo "Error: Failed to parse repository config from $CONFIG_FILE" >&2
|
|
160
|
-
echo "Required: repository.owner, repository.name, repository.url" >&2
|
|
161
|
-
exit 1
|
|
162
|
-
fi
|
|
163
|
-
|
|
164
|
-
# Split the result into variables
|
|
165
|
-
IFS=':' read -r REPO_OWNER REPO_NAME REPO_URL <<< "$REPO_INFO"
|
|
166
|
-
|
|
167
|
-
echo "Repository Configuration:"
|
|
168
|
-
echo " Owner: $REPO_OWNER"
|
|
169
|
-
echo " Name: $REPO_NAME"
|
|
170
|
-
echo " URL: $REPO_URL"
|
|
171
|
-
echo
|
|
172
|
-
|
|
173
|
-
echo "=== $REPO_NAME - Issue Preparation ==="
|
|
174
|
-
echo "Preparing for Issue #$ISSUE_NUMBER"
|
|
175
|
-
echo
|
|
176
|
-
|
|
177
|
-
# Auto-detect editor from GitHub issue labels if not provided
|
|
178
|
-
if [ -z "$EDITOR" ]; then
|
|
179
|
-
echo "No editor specified, attempting to detect from GitHub issue labels..."
|
|
180
|
-
echo "Fetching issue #$ISSUE_NUMBER labels from GitHub..."
|
|
181
|
-
DETECTED_EDITOR=$(get_editor_from_issue $ISSUE_NUMBER)
|
|
182
|
-
if [ $? -eq 0 ] && [ -n "$DETECTED_EDITOR" ]; then
|
|
183
|
-
EDITOR="$DETECTED_EDITOR"
|
|
184
|
-
echo "Auto-detected editor: $EDITOR"
|
|
185
|
-
else
|
|
186
|
-
EDITOR="cursor" # Default fallback
|
|
187
|
-
echo "Using default editor: $EDITOR"
|
|
188
|
-
fi
|
|
189
|
-
else
|
|
190
|
-
echo "Using specified editor: $EDITOR"
|
|
191
|
-
fi
|
|
192
|
-
|
|
193
|
-
# Step 1: Capture current branch BEFORE cloning
|
|
194
|
-
echo "Step 1: Determining base branch from current repository..."
|
|
195
|
-
|
|
196
|
-
# Determine base branch from the ORIGINAL repository (before cloning)
|
|
197
|
-
if [ "$USE_DEFAULT_BRANCH" = true ]; then
|
|
198
|
-
# Detect the default branch
|
|
199
|
-
DEFAULT_BRANCH=""
|
|
200
|
-
for candidate in main master develop; do
|
|
201
|
-
if git ls-remote --exit-code --heads "$REPO_URL" "$candidate" >/dev/null 2>&1; then
|
|
202
|
-
DEFAULT_BRANCH="$candidate"
|
|
203
|
-
echo "✓ Detected default branch: $DEFAULT_BRANCH"
|
|
204
|
-
break
|
|
205
|
-
fi
|
|
206
|
-
done
|
|
207
|
-
|
|
208
|
-
# Fallback to master if nothing else worked
|
|
209
|
-
if [ -z "$DEFAULT_BRANCH" ]; then
|
|
210
|
-
DEFAULT_BRANCH="master"
|
|
211
|
-
echo "⚠️ Could not detect default branch, defaulting to: $DEFAULT_BRANCH"
|
|
212
|
-
fi
|
|
213
|
-
|
|
214
|
-
BASE_BRANCH="$DEFAULT_BRANCH"
|
|
215
|
-
echo "Using detected default branch as base: $BASE_BRANCH (--use-default flag)"
|
|
216
|
-
else
|
|
217
|
-
# Get current branch from the original repo
|
|
218
|
-
ORIGINAL_BRANCH=$(git branch --show-current 2>/dev/null || echo "")
|
|
219
|
-
|
|
220
|
-
if [ -z "$ORIGINAL_BRANCH" ]; then
|
|
221
|
-
echo "Warning: Detached HEAD detected in original repo, falling back to default branch detection"
|
|
222
|
-
|
|
223
|
-
# Detect the default branch
|
|
224
|
-
DEFAULT_BRANCH=""
|
|
225
|
-
for candidate in main master develop; do
|
|
226
|
-
if git ls-remote --exit-code --heads "$REPO_URL" "$candidate" >/dev/null 2>&1; then
|
|
227
|
-
DEFAULT_BRANCH="$candidate"
|
|
228
|
-
echo "✓ Detected default branch: $DEFAULT_BRANCH"
|
|
229
|
-
break
|
|
230
|
-
fi
|
|
231
|
-
done
|
|
232
|
-
|
|
233
|
-
# Fallback to master if nothing else worked
|
|
234
|
-
if [ -z "$DEFAULT_BRANCH" ]; then
|
|
235
|
-
DEFAULT_BRANCH="master"
|
|
236
|
-
echo "⚠️ Could not detect default branch, defaulting to: $DEFAULT_BRANCH"
|
|
237
|
-
fi
|
|
238
|
-
|
|
239
|
-
BASE_BRANCH="$DEFAULT_BRANCH"
|
|
240
|
-
else
|
|
241
|
-
BASE_BRANCH="$ORIGINAL_BRANCH"
|
|
242
|
-
echo "Using current branch from original repo as base: $BASE_BRANCH"
|
|
243
|
-
fi
|
|
244
|
-
fi
|
|
245
|
-
|
|
246
|
-
echo "Issue number = $ISSUE_NUMBER, Editor = $EDITOR, Base branch = $BASE_BRANCH"
|
|
247
|
-
echo
|
|
248
|
-
|
|
249
|
-
# Step 2: Clone the repo
|
|
250
|
-
echo "Step 2: Cloning repository..."
|
|
251
|
-
|
|
252
|
-
# Get current workspace path
|
|
253
|
-
CURRENT_WORKSPACE=$(pwd)
|
|
254
|
-
echo "Current workspace: $CURRENT_WORKSPACE"
|
|
255
|
-
|
|
256
|
-
# Change to parent directory
|
|
257
|
-
echo "Changing to parent directory..."
|
|
258
|
-
cd ..
|
|
259
|
-
PARENT_DIR=$(pwd)
|
|
260
|
-
echo "Parent directory: $PARENT_DIR"
|
|
261
|
-
|
|
262
|
-
# Define clone directory name
|
|
263
|
-
CLONE_DIR="$REPO_NAME - Issue $ISSUE_NUMBER"
|
|
264
|
-
CLONE_PATH="$PARENT_DIR/$CLONE_DIR"
|
|
265
|
-
|
|
266
|
-
# Check if directory already exists
|
|
267
|
-
if [ -d "$CLONE_PATH" ]; then
|
|
268
|
-
echo "Warning: Directory '$CLONE_PATH' already exists"
|
|
269
|
-
read -p "Do you want to remove it and re-clone? (y/N): " -n 1 -r
|
|
270
|
-
echo
|
|
271
|
-
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
272
|
-
echo "Removing existing directory..."
|
|
273
|
-
rm -rf "$CLONE_PATH"
|
|
274
|
-
else
|
|
275
|
-
echo "Aborting. Please remove the existing directory manually or choose a different issue number."
|
|
276
|
-
exit 1
|
|
277
|
-
fi
|
|
278
|
-
fi
|
|
279
|
-
|
|
280
|
-
# Clone the repository
|
|
281
|
-
echo "Cloning to: $CLONE_PATH"
|
|
282
|
-
git clone "$REPO_URL" "$CLONE_DIR"
|
|
283
|
-
|
|
284
|
-
# Change into the cloned repository
|
|
285
|
-
cd "$CLONE_DIR"
|
|
286
|
-
echo "Changed into cloned repository: $(pwd)"
|
|
287
|
-
|
|
288
|
-
echo
|
|
289
|
-
echo "Step 3: Safety Checklist Verification"
|
|
290
|
-
echo "====================================="
|
|
291
|
-
|
|
292
|
-
# Safety checklist verification
|
|
293
|
-
echo -n "✓ Confirmed current workspace path with pwd: "
|
|
294
|
-
pwd
|
|
295
|
-
|
|
296
|
-
echo -n "✓ Verified we are in the cloned repository: "
|
|
297
|
-
if [[ "$(pwd)" = "$CLONE_PATH" ]]; then
|
|
298
|
-
echo "YES"
|
|
299
|
-
else
|
|
300
|
-
echo "NO - ERROR!"
|
|
301
|
-
exit 1
|
|
302
|
-
fi
|
|
303
|
-
|
|
304
|
-
echo -n "✓ Successfully changed into cloned repository: "
|
|
305
|
-
if [ -d ".git" ]; then
|
|
306
|
-
echo "YES"
|
|
307
|
-
else
|
|
308
|
-
echo "NO - ERROR!"
|
|
309
|
-
exit 1
|
|
310
|
-
fi
|
|
311
|
-
|
|
312
|
-
echo
|
|
313
|
-
echo "🎉 Huzzah! Issue #$ISSUE_NUMBER preparation completed successfully!"
|
|
314
|
-
echo "Repository cloned to: $(pwd)"
|
|
315
|
-
echo
|
|
316
|
-
|
|
317
|
-
# Step 4: Create and checkout the feature branch
|
|
318
|
-
echo "Step 4: Creating and checking out feature branch..."
|
|
319
|
-
|
|
320
|
-
# Get issue title for branch naming
|
|
321
|
-
ISSUE_TITLE=$(gh issue view $ISSUE_NUMBER -R "$REPO_OWNER/$REPO_NAME" --json title --jq '.title' 2>/dev/null || echo "issue-$ISSUE_NUMBER")
|
|
322
|
-
BRANCH_NAME="feature/${ISSUE_NUMBER}-$(echo "$ISSUE_TITLE" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-\|-$//g')"
|
|
323
|
-
|
|
324
|
-
echo "Issue title: $ISSUE_TITLE"
|
|
325
|
-
echo "Branch name: $BRANCH_NAME"
|
|
326
|
-
echo "Base branch (from original repo): $BASE_BRANCH"
|
|
327
|
-
|
|
328
|
-
# Create and checkout the branch
|
|
329
|
-
if git show-ref --verify --quiet refs/heads/$BRANCH_NAME; then
|
|
330
|
-
echo "Branch $BRANCH_NAME already exists locally, checking it out..."
|
|
331
|
-
git checkout $BRANCH_NAME
|
|
332
|
-
git pull origin $BRANCH_NAME 2>/dev/null || echo "No remote branch to pull from"
|
|
333
|
-
else
|
|
334
|
-
echo "Creating new branch $BRANCH_NAME from $BASE_BRANCH..."
|
|
335
|
-
|
|
336
|
-
# Ensure we're on the base branch and it's up to date
|
|
337
|
-
git checkout $BASE_BRANCH
|
|
338
|
-
git pull origin $BASE_BRANCH 2>/dev/null || echo "Warning: Could not update $BASE_BRANCH from remote"
|
|
339
|
-
|
|
340
|
-
# Create the new branch
|
|
341
|
-
git checkout -b $BRANCH_NAME
|
|
342
|
-
|
|
343
|
-
# Push branch without any commits
|
|
344
|
-
# PR will be created by phase-change.yml when a phase label is applied
|
|
345
|
-
echo "Pushing empty branch to origin..."
|
|
346
|
-
git push -u origin $BRANCH_NAME
|
|
347
|
-
fi
|
|
348
|
-
|
|
349
|
-
echo "✓ Successfully on branch: $BRANCH_NAME (created from: $BASE_BRANCH)"
|
|
350
|
-
|
|
351
|
-
# Install dependencies (optional)
|
|
352
|
-
if [ "$SKIP_INSTALL" = false ]; then
|
|
353
|
-
echo "Installing npm dependencies..."
|
|
354
|
-
npm install
|
|
355
|
-
if [ $? -eq 0 ]; then
|
|
356
|
-
echo "✓ npm install completed successfully"
|
|
357
|
-
else
|
|
358
|
-
echo "⚠️ npm install failed - you may need to run it manually"
|
|
359
|
-
fi
|
|
360
|
-
else
|
|
361
|
-
echo "⏭️ Skipping npm install (--skip-install flag)"
|
|
362
|
-
fi
|
|
363
|
-
|
|
364
|
-
# Step 5: Branch Ready for Phase Workflow
|
|
365
|
-
echo "Step 5: Branch ready for phase workflow..."
|
|
366
|
-
echo "✓ Branch $BRANCH_NAME created and pushed (no commits yet)"
|
|
367
|
-
echo "✓ PR will be created when you apply a phase label to the issue"
|
|
368
|
-
echo " (phase:spec, phase:design, phase:tests, or phase:impl)"
|
|
369
|
-
|
|
370
|
-
# Step 6: Index the codebase with Serena (optional)
|
|
371
|
-
if [ "$SKIP_SERENA" = false ]; then
|
|
372
|
-
echo "Step 6: Indexing codebase with Serena..."
|
|
373
|
-
echo "Running: uvx --from git+https://github.com/oraios/serena serena project index"
|
|
374
|
-
|
|
375
|
-
if command -v uvx &> /dev/null; then
|
|
376
|
-
uvx --from git+https://github.com/oraios/serena serena project index
|
|
377
|
-
if [ $? -eq 0 ]; then
|
|
378
|
-
echo "✓ Serena indexing completed successfully"
|
|
379
|
-
else
|
|
380
|
-
echo "⚠️ Serena indexing failed, but continuing..."
|
|
381
|
-
fi
|
|
382
|
-
else
|
|
383
|
-
echo "⚠️ uvx command not found, skipping Serena indexing"
|
|
384
|
-
echo " You may want to install uvx or run the indexing manually"
|
|
385
|
-
fi
|
|
386
|
-
else
|
|
387
|
-
echo "⏭️ Skipping Serena indexing (--skip-serena flag)"
|
|
388
|
-
fi
|
|
389
|
-
|
|
390
|
-
# Step 7: Open the specified editor in the new directory (optional)
|
|
391
|
-
if [ "$SKIP_EDITOR" = false ]; then
|
|
392
|
-
echo "Step 7: Opening $EDITOR in the new workspace..."
|
|
393
|
-
echo "Opening: $(pwd)"
|
|
394
|
-
|
|
395
|
-
# Open the specified editor
|
|
396
|
-
case $EDITOR in
|
|
397
|
-
windsurf)
|
|
398
|
-
if command -v windsurf &> /dev/null; then
|
|
399
|
-
echo "Opening with 'windsurf' command..."
|
|
400
|
-
windsurf .
|
|
401
|
-
else
|
|
402
|
-
echo "Could not find 'windsurf' command."
|
|
403
|
-
echo "Please manually open Windsurf in: $(pwd)"
|
|
404
|
-
fi
|
|
405
|
-
;;
|
|
406
|
-
claude|claudecode)
|
|
407
|
-
if command -v claude &> /dev/null; then
|
|
408
|
-
echo "Opening with 'claude' command..."
|
|
409
|
-
claude --dangerously-skip-permissions .
|
|
410
|
-
else
|
|
411
|
-
echo "Could not find 'claude' command."
|
|
412
|
-
echo "Please manually open Claude in: $(pwd)"
|
|
413
|
-
fi
|
|
414
|
-
;;
|
|
415
|
-
cursor)
|
|
416
|
-
if command -v cursor &> /dev/null; then
|
|
417
|
-
echo "Opening with 'cursor' command..."
|
|
418
|
-
cursor .
|
|
419
|
-
elif command -v code &> /dev/null; then
|
|
420
|
-
echo "Opening with 'code' command (VS Code fallback)..."
|
|
421
|
-
code .
|
|
422
|
-
else
|
|
423
|
-
echo "Could not find 'cursor' or 'code' command."
|
|
424
|
-
echo "Please manually open Cursor in: $(pwd)"
|
|
425
|
-
fi
|
|
426
|
-
;;
|
|
427
|
-
*)
|
|
428
|
-
echo "Unknown editor: $EDITOR"
|
|
429
|
-
echo "Supported editors: windsurf, claude, claudecode, cursor"
|
|
430
|
-
echo "Please manually open your editor in: $(pwd)"
|
|
431
|
-
;;
|
|
432
|
-
esac
|
|
433
|
-
else
|
|
434
|
-
echo "⏭️ Skipping editor launch (--skip-editor flag)"
|
|
435
|
-
echo "Manually open your editor in: $(pwd)"
|
|
436
|
-
fi
|
|
437
|
-
|
|
438
|
-
echo
|
|
439
|
-
echo "🎉 Setup Complete! Ready for agent workflow."
|
|
440
|
-
echo
|
|
441
|
-
echo "What was prepared:"
|
|
442
|
-
echo "- ✅ Repository cloned and ready"
|
|
443
|
-
echo "- ✅ Branch created: $BRANCH_NAME (from: $BASE_BRANCH)"
|
|
444
|
-
echo "- ✅ Branch checked out and pushed"
|
|
445
|
-
if [ "$SKIP_INSTALL" = false ]; then
|
|
446
|
-
echo "- ✅ Dependencies installed"
|
|
447
|
-
else
|
|
448
|
-
echo "- ⏭️ Dependencies skipped"
|
|
449
|
-
fi
|
|
450
|
-
if [ "$SKIP_SERENA" = false ]; then
|
|
451
|
-
echo "- ✅ Codebase indexed with Serena"
|
|
452
|
-
else
|
|
453
|
-
echo "- ⏭️ Serena indexing skipped"
|
|
454
|
-
fi
|
|
455
|
-
if [ "$SKIP_EDITOR" = false ]; then
|
|
456
|
-
echo "- ✅ Editor opened: $EDITOR"
|
|
457
|
-
else
|
|
458
|
-
echo "- ⏭️ Editor launch skipped"
|
|
459
|
-
fi
|
|
460
|
-
echo
|
|
461
|
-
echo "Agent workflow:"
|
|
462
|
-
echo "1. Agent can start working immediately in this environment"
|
|
463
|
-
echo "2. No need to create branches - already done!"
|
|
464
|
-
echo "3. AGENT: Before starting work, you MUST read all documents in the retrospectives/ folder to learn from previous issues and avoid repeating mistakes."
|
|
465
|
-
echo "4. Agent labels the issue with the appropriate phase (e.g., phase:spec, phase:design)"
|
|
466
|
-
echo "5. GitHub Actions will automatically create the PR when phase label is applied"
|
|
467
|
-
echo "6. Agent can commit and push changes directly"
|
|
468
|
-
echo "7. GitHub Actions will update the PR when phase changes"
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -e # Exit on any error
|
|
4
|
+
|
|
5
|
+
# Default flags (can be overridden by command line)
|
|
6
|
+
SKIP_INSTALL=false
|
|
7
|
+
SKIP_SERENA=true
|
|
8
|
+
SKIP_EDITOR=true
|
|
9
|
+
USE_DEFAULT_BRANCH=true
|
|
10
|
+
|
|
11
|
+
# Function to display usage
|
|
12
|
+
usage() {
|
|
13
|
+
echo "Usage: $0 <issue_number> [editor] [flags]"
|
|
14
|
+
echo "Example: $0 123"
|
|
15
|
+
echo "Example: $0 123 windsurf"
|
|
16
|
+
echo "Example: $0 123 claude --skip-install"
|
|
17
|
+
echo "Example: $0 123 cursor --use-default --skip-serena"
|
|
18
|
+
echo ""
|
|
19
|
+
echo "Editor options: windsurf, claude, claudecode, cursor (default)"
|
|
20
|
+
echo "If no editor specified, will try to detect from GitHub issue labels"
|
|
21
|
+
echo ""
|
|
22
|
+
echo "Flags:"
|
|
23
|
+
echo " --skip-install Skip npm install step"
|
|
24
|
+
echo " --skip-serena Skip Serena indexing step"
|
|
25
|
+
echo " --skip-editor Skip opening editor"
|
|
26
|
+
echo " --use-default Force branch creation from default branch (ignore current branch)"
|
|
27
|
+
echo " --help Show this help message"
|
|
28
|
+
exit 1
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# Function to get editor from GitHub issue labels
|
|
32
|
+
get_editor_from_issue() {
|
|
33
|
+
local issue_num=$1
|
|
34
|
+
|
|
35
|
+
# Try to get the issue labels using GitHub CLI or curl
|
|
36
|
+
if command -v gh &> /dev/null; then
|
|
37
|
+
# Use GitHub CLI if available
|
|
38
|
+
local labels=$(gh issue view $issue_num -R "$REPO_OWNER/$REPO_NAME" --json labels --jq '.labels[].name' 2>/dev/null)
|
|
39
|
+
else
|
|
40
|
+
# Fallback to curl (requires GitHub token in GITHUB_TOKEN env var)
|
|
41
|
+
if [ -n "$GITHUB_TOKEN" ]; then
|
|
42
|
+
local labels=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
|
43
|
+
"https://api.github.com/repos/$REPO_OWNER/$REPO_NAME/issues/$issue_num" \
|
|
44
|
+
| grep -o '"name":"ai-agent:[^"]*"' | sed 's/"name":"ai-agent://' | sed 's/"//' 2>/dev/null)
|
|
45
|
+
else
|
|
46
|
+
echo "Warning: No GitHub CLI or GITHUB_TOKEN found. Cannot auto-detect editor from issue labels." >&2
|
|
47
|
+
return 1
|
|
48
|
+
fi
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# Look for ai-agent labels
|
|
52
|
+
for label in $labels; do
|
|
53
|
+
if [[ $label == ai-agent:* ]]; then
|
|
54
|
+
local editor=${label#ai-agent:}
|
|
55
|
+
echo "Found ai-agent label: $label -> editor: $editor" >&2
|
|
56
|
+
echo "$editor"
|
|
57
|
+
return 0
|
|
58
|
+
fi
|
|
59
|
+
done
|
|
60
|
+
|
|
61
|
+
echo "No ai-agent label found in issue #$issue_num, will continue without editor" >&2
|
|
62
|
+
return 0
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# Parse command line arguments
|
|
66
|
+
if [ $# -eq 0 ]; then
|
|
67
|
+
echo "Error: Issue number is required"
|
|
68
|
+
usage
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
ISSUE_NUMBER=$1
|
|
72
|
+
EDITOR="" # Will be set later if not provided
|
|
73
|
+
|
|
74
|
+
# Parse remaining arguments (editor and flags)
|
|
75
|
+
shift 1 # Remove issue_number
|
|
76
|
+
while [[ $# -gt 0 ]]; do
|
|
77
|
+
case $1 in
|
|
78
|
+
--skip-install)
|
|
79
|
+
SKIP_INSTALL=true
|
|
80
|
+
shift
|
|
81
|
+
;;
|
|
82
|
+
--skip-serena)
|
|
83
|
+
SKIP_SERENA=true
|
|
84
|
+
shift
|
|
85
|
+
;;
|
|
86
|
+
--skip-editor)
|
|
87
|
+
SKIP_EDITOR=true
|
|
88
|
+
shift
|
|
89
|
+
;;
|
|
90
|
+
--use-default)
|
|
91
|
+
USE_DEFAULT_BRANCH=true
|
|
92
|
+
shift
|
|
93
|
+
;;
|
|
94
|
+
--help)
|
|
95
|
+
usage
|
|
96
|
+
;;
|
|
97
|
+
windsurf|claude|claudecode|cursor)
|
|
98
|
+
# Valid editor names
|
|
99
|
+
if [ -z "$EDITOR" ]; then
|
|
100
|
+
EDITOR="$1"
|
|
101
|
+
else
|
|
102
|
+
echo "Error: Multiple editors specified: $EDITOR and $1"
|
|
103
|
+
usage
|
|
104
|
+
fi
|
|
105
|
+
shift
|
|
106
|
+
;;
|
|
107
|
+
*)
|
|
108
|
+
echo "Unknown argument: $1"
|
|
109
|
+
echo "Valid editors: windsurf, claude, claudecode, cursor"
|
|
110
|
+
echo "Valid flags: --skip-install, --skip-serena, --skip-editor, --use-default"
|
|
111
|
+
usage
|
|
112
|
+
;;
|
|
113
|
+
esac
|
|
114
|
+
done
|
|
115
|
+
|
|
116
|
+
# Load repository config from config.json
|
|
117
|
+
CONFIG_FILE=".fraim/config.json"
|
|
118
|
+
if [ ! -f "$CONFIG_FILE" ]; then
|
|
119
|
+
echo "Error: Config file not found at $CONFIG_FILE" >&2
|
|
120
|
+
exit 1
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
if ! command -v node &> /dev/null; then
|
|
124
|
+
echo "Error: node is required but not installed." >&2
|
|
125
|
+
exit 1
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
# Extract values using node reading from stdin to avoid path issues
|
|
129
|
+
NODE_SCRIPT="
|
|
130
|
+
const fs = require('fs');
|
|
131
|
+
try {
|
|
132
|
+
const input = fs.readFileSync(0, 'utf-8');
|
|
133
|
+
const config = JSON.parse(input);
|
|
134
|
+
|
|
135
|
+
// Support both 'repository' (new) and 'git' (legacy/current) schemas
|
|
136
|
+
let repo = config.repository;
|
|
137
|
+
|
|
138
|
+
if (!repo) {
|
|
139
|
+
if (config.git) {
|
|
140
|
+
repo = {
|
|
141
|
+
owner: config.git.repoOwner,
|
|
142
|
+
name: config.git.repoName,
|
|
143
|
+
url: config.git.repoUrl || \`https://github.com/\${config.git.repoOwner}/\${config.git.repoName}.git\`
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (!repo || !repo.owner || !repo.name || !repo.url) {
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
console.log(\`\${repo.owner}:\${repo.name}:\${repo.url}\`);
|
|
152
|
+
} catch (e) {
|
|
153
|
+
process.exit(1);
|
|
154
|
+
}
|
|
155
|
+
"
|
|
156
|
+
|
|
157
|
+
REPO_INFO=$(cat "$CONFIG_FILE" | node -e "$NODE_SCRIPT")
|
|
158
|
+
if [ $? -ne 0 ]; then
|
|
159
|
+
echo "Error: Failed to parse repository config from $CONFIG_FILE" >&2
|
|
160
|
+
echo "Required: repository.owner, repository.name, repository.url" >&2
|
|
161
|
+
exit 1
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
# Split the result into variables
|
|
165
|
+
IFS=':' read -r REPO_OWNER REPO_NAME REPO_URL <<< "$REPO_INFO"
|
|
166
|
+
|
|
167
|
+
echo "Repository Configuration:"
|
|
168
|
+
echo " Owner: $REPO_OWNER"
|
|
169
|
+
echo " Name: $REPO_NAME"
|
|
170
|
+
echo " URL: $REPO_URL"
|
|
171
|
+
echo
|
|
172
|
+
|
|
173
|
+
echo "=== $REPO_NAME - Issue Preparation ==="
|
|
174
|
+
echo "Preparing for Issue #$ISSUE_NUMBER"
|
|
175
|
+
echo
|
|
176
|
+
|
|
177
|
+
# Auto-detect editor from GitHub issue labels if not provided
|
|
178
|
+
if [ -z "$EDITOR" ]; then
|
|
179
|
+
echo "No editor specified, attempting to detect from GitHub issue labels..."
|
|
180
|
+
echo "Fetching issue #$ISSUE_NUMBER labels from GitHub..."
|
|
181
|
+
DETECTED_EDITOR=$(get_editor_from_issue $ISSUE_NUMBER)
|
|
182
|
+
if [ $? -eq 0 ] && [ -n "$DETECTED_EDITOR" ]; then
|
|
183
|
+
EDITOR="$DETECTED_EDITOR"
|
|
184
|
+
echo "Auto-detected editor: $EDITOR"
|
|
185
|
+
else
|
|
186
|
+
EDITOR="cursor" # Default fallback
|
|
187
|
+
echo "Using default editor: $EDITOR"
|
|
188
|
+
fi
|
|
189
|
+
else
|
|
190
|
+
echo "Using specified editor: $EDITOR"
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
# Step 1: Capture current branch BEFORE cloning
|
|
194
|
+
echo "Step 1: Determining base branch from current repository..."
|
|
195
|
+
|
|
196
|
+
# Determine base branch from the ORIGINAL repository (before cloning)
|
|
197
|
+
if [ "$USE_DEFAULT_BRANCH" = true ]; then
|
|
198
|
+
# Detect the default branch
|
|
199
|
+
DEFAULT_BRANCH=""
|
|
200
|
+
for candidate in main master develop; do
|
|
201
|
+
if git ls-remote --exit-code --heads "$REPO_URL" "$candidate" >/dev/null 2>&1; then
|
|
202
|
+
DEFAULT_BRANCH="$candidate"
|
|
203
|
+
echo "✓ Detected default branch: $DEFAULT_BRANCH"
|
|
204
|
+
break
|
|
205
|
+
fi
|
|
206
|
+
done
|
|
207
|
+
|
|
208
|
+
# Fallback to master if nothing else worked
|
|
209
|
+
if [ -z "$DEFAULT_BRANCH" ]; then
|
|
210
|
+
DEFAULT_BRANCH="master"
|
|
211
|
+
echo "⚠️ Could not detect default branch, defaulting to: $DEFAULT_BRANCH"
|
|
212
|
+
fi
|
|
213
|
+
|
|
214
|
+
BASE_BRANCH="$DEFAULT_BRANCH"
|
|
215
|
+
echo "Using detected default branch as base: $BASE_BRANCH (--use-default flag)"
|
|
216
|
+
else
|
|
217
|
+
# Get current branch from the original repo
|
|
218
|
+
ORIGINAL_BRANCH=$(git branch --show-current 2>/dev/null || echo "")
|
|
219
|
+
|
|
220
|
+
if [ -z "$ORIGINAL_BRANCH" ]; then
|
|
221
|
+
echo "Warning: Detached HEAD detected in original repo, falling back to default branch detection"
|
|
222
|
+
|
|
223
|
+
# Detect the default branch
|
|
224
|
+
DEFAULT_BRANCH=""
|
|
225
|
+
for candidate in main master develop; do
|
|
226
|
+
if git ls-remote --exit-code --heads "$REPO_URL" "$candidate" >/dev/null 2>&1; then
|
|
227
|
+
DEFAULT_BRANCH="$candidate"
|
|
228
|
+
echo "✓ Detected default branch: $DEFAULT_BRANCH"
|
|
229
|
+
break
|
|
230
|
+
fi
|
|
231
|
+
done
|
|
232
|
+
|
|
233
|
+
# Fallback to master if nothing else worked
|
|
234
|
+
if [ -z "$DEFAULT_BRANCH" ]; then
|
|
235
|
+
DEFAULT_BRANCH="master"
|
|
236
|
+
echo "⚠️ Could not detect default branch, defaulting to: $DEFAULT_BRANCH"
|
|
237
|
+
fi
|
|
238
|
+
|
|
239
|
+
BASE_BRANCH="$DEFAULT_BRANCH"
|
|
240
|
+
else
|
|
241
|
+
BASE_BRANCH="$ORIGINAL_BRANCH"
|
|
242
|
+
echo "Using current branch from original repo as base: $BASE_BRANCH"
|
|
243
|
+
fi
|
|
244
|
+
fi
|
|
245
|
+
|
|
246
|
+
echo "Issue number = $ISSUE_NUMBER, Editor = $EDITOR, Base branch = $BASE_BRANCH"
|
|
247
|
+
echo
|
|
248
|
+
|
|
249
|
+
# Step 2: Clone the repo
|
|
250
|
+
echo "Step 2: Cloning repository..."
|
|
251
|
+
|
|
252
|
+
# Get current workspace path
|
|
253
|
+
CURRENT_WORKSPACE=$(pwd)
|
|
254
|
+
echo "Current workspace: $CURRENT_WORKSPACE"
|
|
255
|
+
|
|
256
|
+
# Change to parent directory
|
|
257
|
+
echo "Changing to parent directory..."
|
|
258
|
+
cd ..
|
|
259
|
+
PARENT_DIR=$(pwd)
|
|
260
|
+
echo "Parent directory: $PARENT_DIR"
|
|
261
|
+
|
|
262
|
+
# Define clone directory name
|
|
263
|
+
CLONE_DIR="$REPO_NAME - Issue $ISSUE_NUMBER"
|
|
264
|
+
CLONE_PATH="$PARENT_DIR/$CLONE_DIR"
|
|
265
|
+
|
|
266
|
+
# Check if directory already exists
|
|
267
|
+
if [ -d "$CLONE_PATH" ]; then
|
|
268
|
+
echo "Warning: Directory '$CLONE_PATH' already exists"
|
|
269
|
+
read -p "Do you want to remove it and re-clone? (y/N): " -n 1 -r
|
|
270
|
+
echo
|
|
271
|
+
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
272
|
+
echo "Removing existing directory..."
|
|
273
|
+
rm -rf "$CLONE_PATH"
|
|
274
|
+
else
|
|
275
|
+
echo "Aborting. Please remove the existing directory manually or choose a different issue number."
|
|
276
|
+
exit 1
|
|
277
|
+
fi
|
|
278
|
+
fi
|
|
279
|
+
|
|
280
|
+
# Clone the repository
|
|
281
|
+
echo "Cloning to: $CLONE_PATH"
|
|
282
|
+
git clone "$REPO_URL" "$CLONE_DIR"
|
|
283
|
+
|
|
284
|
+
# Change into the cloned repository
|
|
285
|
+
cd "$CLONE_DIR"
|
|
286
|
+
echo "Changed into cloned repository: $(pwd)"
|
|
287
|
+
|
|
288
|
+
echo
|
|
289
|
+
echo "Step 3: Safety Checklist Verification"
|
|
290
|
+
echo "====================================="
|
|
291
|
+
|
|
292
|
+
# Safety checklist verification
|
|
293
|
+
echo -n "✓ Confirmed current workspace path with pwd: "
|
|
294
|
+
pwd
|
|
295
|
+
|
|
296
|
+
echo -n "✓ Verified we are in the cloned repository: "
|
|
297
|
+
if [[ "$(pwd)" = "$CLONE_PATH" ]]; then
|
|
298
|
+
echo "YES"
|
|
299
|
+
else
|
|
300
|
+
echo "NO - ERROR!"
|
|
301
|
+
exit 1
|
|
302
|
+
fi
|
|
303
|
+
|
|
304
|
+
echo -n "✓ Successfully changed into cloned repository: "
|
|
305
|
+
if [ -d ".git" ]; then
|
|
306
|
+
echo "YES"
|
|
307
|
+
else
|
|
308
|
+
echo "NO - ERROR!"
|
|
309
|
+
exit 1
|
|
310
|
+
fi
|
|
311
|
+
|
|
312
|
+
echo
|
|
313
|
+
echo "🎉 Huzzah! Issue #$ISSUE_NUMBER preparation completed successfully!"
|
|
314
|
+
echo "Repository cloned to: $(pwd)"
|
|
315
|
+
echo
|
|
316
|
+
|
|
317
|
+
# Step 4: Create and checkout the feature branch
|
|
318
|
+
echo "Step 4: Creating and checking out feature branch..."
|
|
319
|
+
|
|
320
|
+
# Get issue title for branch naming
|
|
321
|
+
ISSUE_TITLE=$(gh issue view $ISSUE_NUMBER -R "$REPO_OWNER/$REPO_NAME" --json title --jq '.title' 2>/dev/null || echo "issue-$ISSUE_NUMBER")
|
|
322
|
+
BRANCH_NAME="feature/${ISSUE_NUMBER}-$(echo "$ISSUE_TITLE" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-\|-$//g')"
|
|
323
|
+
|
|
324
|
+
echo "Issue title: $ISSUE_TITLE"
|
|
325
|
+
echo "Branch name: $BRANCH_NAME"
|
|
326
|
+
echo "Base branch (from original repo): $BASE_BRANCH"
|
|
327
|
+
|
|
328
|
+
# Create and checkout the branch
|
|
329
|
+
if git show-ref --verify --quiet refs/heads/$BRANCH_NAME; then
|
|
330
|
+
echo "Branch $BRANCH_NAME already exists locally, checking it out..."
|
|
331
|
+
git checkout $BRANCH_NAME
|
|
332
|
+
git pull origin $BRANCH_NAME 2>/dev/null || echo "No remote branch to pull from"
|
|
333
|
+
else
|
|
334
|
+
echo "Creating new branch $BRANCH_NAME from $BASE_BRANCH..."
|
|
335
|
+
|
|
336
|
+
# Ensure we're on the base branch and it's up to date
|
|
337
|
+
git checkout $BASE_BRANCH
|
|
338
|
+
git pull origin $BASE_BRANCH 2>/dev/null || echo "Warning: Could not update $BASE_BRANCH from remote"
|
|
339
|
+
|
|
340
|
+
# Create the new branch
|
|
341
|
+
git checkout -b $BRANCH_NAME
|
|
342
|
+
|
|
343
|
+
# Push branch without any commits
|
|
344
|
+
# PR will be created by phase-change.yml when a phase label is applied
|
|
345
|
+
echo "Pushing empty branch to origin..."
|
|
346
|
+
git push -u origin $BRANCH_NAME
|
|
347
|
+
fi
|
|
348
|
+
|
|
349
|
+
echo "✓ Successfully on branch: $BRANCH_NAME (created from: $BASE_BRANCH)"
|
|
350
|
+
|
|
351
|
+
# Install dependencies (optional)
|
|
352
|
+
if [ "$SKIP_INSTALL" = false ]; then
|
|
353
|
+
echo "Installing npm dependencies..."
|
|
354
|
+
npm install
|
|
355
|
+
if [ $? -eq 0 ]; then
|
|
356
|
+
echo "✓ npm install completed successfully"
|
|
357
|
+
else
|
|
358
|
+
echo "⚠️ npm install failed - you may need to run it manually"
|
|
359
|
+
fi
|
|
360
|
+
else
|
|
361
|
+
echo "⏭️ Skipping npm install (--skip-install flag)"
|
|
362
|
+
fi
|
|
363
|
+
|
|
364
|
+
# Step 5: Branch Ready for Phase Workflow
|
|
365
|
+
echo "Step 5: Branch ready for phase workflow..."
|
|
366
|
+
echo "✓ Branch $BRANCH_NAME created and pushed (no commits yet)"
|
|
367
|
+
echo "✓ PR will be created when you apply a phase label to the issue"
|
|
368
|
+
echo " (phase:spec, phase:design, phase:tests, or phase:impl)"
|
|
369
|
+
|
|
370
|
+
# Step 6: Index the codebase with Serena (optional)
|
|
371
|
+
if [ "$SKIP_SERENA" = false ]; then
|
|
372
|
+
echo "Step 6: Indexing codebase with Serena..."
|
|
373
|
+
echo "Running: uvx --from git+https://github.com/oraios/serena serena project index"
|
|
374
|
+
|
|
375
|
+
if command -v uvx &> /dev/null; then
|
|
376
|
+
uvx --from git+https://github.com/oraios/serena serena project index
|
|
377
|
+
if [ $? -eq 0 ]; then
|
|
378
|
+
echo "✓ Serena indexing completed successfully"
|
|
379
|
+
else
|
|
380
|
+
echo "⚠️ Serena indexing failed, but continuing..."
|
|
381
|
+
fi
|
|
382
|
+
else
|
|
383
|
+
echo "⚠️ uvx command not found, skipping Serena indexing"
|
|
384
|
+
echo " You may want to install uvx or run the indexing manually"
|
|
385
|
+
fi
|
|
386
|
+
else
|
|
387
|
+
echo "⏭️ Skipping Serena indexing (--skip-serena flag)"
|
|
388
|
+
fi
|
|
389
|
+
|
|
390
|
+
# Step 7: Open the specified editor in the new directory (optional)
|
|
391
|
+
if [ "$SKIP_EDITOR" = false ]; then
|
|
392
|
+
echo "Step 7: Opening $EDITOR in the new workspace..."
|
|
393
|
+
echo "Opening: $(pwd)"
|
|
394
|
+
|
|
395
|
+
# Open the specified editor
|
|
396
|
+
case $EDITOR in
|
|
397
|
+
windsurf)
|
|
398
|
+
if command -v windsurf &> /dev/null; then
|
|
399
|
+
echo "Opening with 'windsurf' command..."
|
|
400
|
+
windsurf .
|
|
401
|
+
else
|
|
402
|
+
echo "Could not find 'windsurf' command."
|
|
403
|
+
echo "Please manually open Windsurf in: $(pwd)"
|
|
404
|
+
fi
|
|
405
|
+
;;
|
|
406
|
+
claude|claudecode)
|
|
407
|
+
if command -v claude &> /dev/null; then
|
|
408
|
+
echo "Opening with 'claude' command..."
|
|
409
|
+
claude --dangerously-skip-permissions .
|
|
410
|
+
else
|
|
411
|
+
echo "Could not find 'claude' command."
|
|
412
|
+
echo "Please manually open Claude in: $(pwd)"
|
|
413
|
+
fi
|
|
414
|
+
;;
|
|
415
|
+
cursor)
|
|
416
|
+
if command -v cursor &> /dev/null; then
|
|
417
|
+
echo "Opening with 'cursor' command..."
|
|
418
|
+
cursor .
|
|
419
|
+
elif command -v code &> /dev/null; then
|
|
420
|
+
echo "Opening with 'code' command (VS Code fallback)..."
|
|
421
|
+
code .
|
|
422
|
+
else
|
|
423
|
+
echo "Could not find 'cursor' or 'code' command."
|
|
424
|
+
echo "Please manually open Cursor in: $(pwd)"
|
|
425
|
+
fi
|
|
426
|
+
;;
|
|
427
|
+
*)
|
|
428
|
+
echo "Unknown editor: $EDITOR"
|
|
429
|
+
echo "Supported editors: windsurf, claude, claudecode, cursor"
|
|
430
|
+
echo "Please manually open your editor in: $(pwd)"
|
|
431
|
+
;;
|
|
432
|
+
esac
|
|
433
|
+
else
|
|
434
|
+
echo "⏭️ Skipping editor launch (--skip-editor flag)"
|
|
435
|
+
echo "Manually open your editor in: $(pwd)"
|
|
436
|
+
fi
|
|
437
|
+
|
|
438
|
+
echo
|
|
439
|
+
echo "🎉 Setup Complete! Ready for agent workflow."
|
|
440
|
+
echo
|
|
441
|
+
echo "What was prepared:"
|
|
442
|
+
echo "- ✅ Repository cloned and ready"
|
|
443
|
+
echo "- ✅ Branch created: $BRANCH_NAME (from: $BASE_BRANCH)"
|
|
444
|
+
echo "- ✅ Branch checked out and pushed"
|
|
445
|
+
if [ "$SKIP_INSTALL" = false ]; then
|
|
446
|
+
echo "- ✅ Dependencies installed"
|
|
447
|
+
else
|
|
448
|
+
echo "- ⏭️ Dependencies skipped"
|
|
449
|
+
fi
|
|
450
|
+
if [ "$SKIP_SERENA" = false ]; then
|
|
451
|
+
echo "- ✅ Codebase indexed with Serena"
|
|
452
|
+
else
|
|
453
|
+
echo "- ⏭️ Serena indexing skipped"
|
|
454
|
+
fi
|
|
455
|
+
if [ "$SKIP_EDITOR" = false ]; then
|
|
456
|
+
echo "- ✅ Editor opened: $EDITOR"
|
|
457
|
+
else
|
|
458
|
+
echo "- ⏭️ Editor launch skipped"
|
|
459
|
+
fi
|
|
460
|
+
echo
|
|
461
|
+
echo "Agent workflow:"
|
|
462
|
+
echo "1. Agent can start working immediately in this environment"
|
|
463
|
+
echo "2. No need to create branches - already done!"
|
|
464
|
+
echo "3. AGENT: Before starting work, you MUST read all documents in the retrospectives/ folder to learn from previous issues and avoid repeating mistakes."
|
|
465
|
+
echo "4. Agent labels the issue with the appropriate phase (e.g., phase:spec, phase:design)"
|
|
466
|
+
echo "5. GitHub Actions will automatically create the PR when phase label is applied"
|
|
467
|
+
echo "6. Agent can commit and push changes directly"
|
|
468
|
+
echo "7. GitHub Actions will update the PR when phase changes"
|