jfl 0.1.1 → 0.2.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/README.md +77 -7
- package/clawdbot-plugin/clawdbot.plugin.json +20 -0
- package/clawdbot-plugin/index.js +555 -0
- package/clawdbot-plugin/index.ts +582 -0
- package/clawdbot-skill/SKILL.md +33 -336
- package/clawdbot-skill/index.ts +491 -321
- package/clawdbot-skill/skill.json +4 -13
- package/dist/commands/clawdbot.d.ts +11 -0
- package/dist/commands/clawdbot.d.ts.map +1 -0
- package/dist/commands/clawdbot.js +215 -0
- package/dist/commands/clawdbot.js.map +1 -0
- package/dist/commands/gtm-process-update.d.ts +10 -0
- package/dist/commands/gtm-process-update.d.ts.map +1 -0
- package/dist/commands/gtm-process-update.js +101 -0
- package/dist/commands/gtm-process-update.js.map +1 -0
- package/dist/commands/onboard.d.ts.map +1 -1
- package/dist/commands/onboard.js +203 -15
- package/dist/commands/onboard.js.map +1 -1
- package/dist/commands/openclaw.d.ts +56 -0
- package/dist/commands/openclaw.d.ts.map +1 -0
- package/dist/commands/openclaw.js +700 -0
- package/dist/commands/openclaw.js.map +1 -0
- package/dist/commands/service-validate.d.ts +12 -0
- package/dist/commands/service-validate.d.ts.map +1 -0
- package/dist/commands/service-validate.js +611 -0
- package/dist/commands/service-validate.js.map +1 -0
- package/dist/commands/services-create.d.ts +15 -0
- package/dist/commands/services-create.d.ts.map +1 -0
- package/dist/commands/services-create.js +1452 -0
- package/dist/commands/services-create.js.map +1 -0
- package/dist/commands/services-sync-agents.d.ts +23 -0
- package/dist/commands/services-sync-agents.d.ts.map +1 -0
- package/dist/commands/services-sync-agents.js +207 -0
- package/dist/commands/services-sync-agents.js.map +1 -0
- package/dist/commands/services.d.ts +7 -1
- package/dist/commands/services.d.ts.map +1 -1
- package/dist/commands/services.js +347 -22
- package/dist/commands/services.js.map +1 -1
- package/dist/commands/update.js +0 -0
- package/dist/commands/validate-settings.d.ts +37 -0
- package/dist/commands/validate-settings.d.ts.map +1 -0
- package/dist/commands/validate-settings.js +197 -0
- package/dist/commands/validate-settings.js.map +1 -0
- package/dist/index.js +155 -60
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-generator.d.ts.map +1 -1
- package/dist/lib/agent-generator.js +94 -1
- package/dist/lib/agent-generator.js.map +1 -1
- package/dist/lib/openclaw-registry.d.ts +48 -0
- package/dist/lib/openclaw-registry.d.ts.map +1 -0
- package/dist/lib/openclaw-registry.js +181 -0
- package/dist/lib/openclaw-registry.js.map +1 -0
- package/dist/lib/openclaw-sdk.d.ts +107 -0
- package/dist/lib/openclaw-sdk.d.ts.map +1 -0
- package/dist/lib/openclaw-sdk.js +208 -0
- package/dist/lib/openclaw-sdk.js.map +1 -0
- package/dist/lib/peer-agent-generator.d.ts +44 -0
- package/dist/lib/peer-agent-generator.d.ts.map +1 -0
- package/dist/lib/peer-agent-generator.js +286 -0
- package/dist/lib/peer-agent-generator.js.map +1 -0
- package/dist/lib/service-detector.d.ts +1 -1
- package/dist/lib/service-detector.d.ts.map +1 -1
- package/dist/lib/service-detector.js +118 -5
- package/dist/lib/service-detector.js.map +1 -1
- package/dist/lib/service-gtm.d.ts +157 -0
- package/dist/lib/service-gtm.d.ts.map +1 -0
- package/dist/lib/service-gtm.js +786 -0
- package/dist/lib/service-gtm.js.map +1 -0
- package/dist/lib/service-mcp-base.d.ts +10 -1
- package/dist/lib/service-mcp-base.d.ts.map +1 -1
- package/dist/lib/service-mcp-base.js +20 -1
- package/dist/lib/service-mcp-base.js.map +1 -1
- package/dist/mcp/service-peer-mcp.d.ts +36 -0
- package/dist/mcp/service-peer-mcp.d.ts.map +1 -0
- package/dist/mcp/service-peer-mcp.js +220 -0
- package/dist/mcp/service-peer-mcp.js.map +1 -0
- package/dist/mcp/service-registry-mcp.js +0 -0
- package/dist/utils/settings-validator.d.ts +4 -1
- package/dist/utils/settings-validator.d.ts.map +1 -1
- package/dist/utils/settings-validator.js +25 -1
- package/dist/utils/settings-validator.js.map +1 -1
- package/package.json +2 -1
- package/template/.claude/service-settings.json +32 -0
- package/template/.claude/settings.json +10 -0
- package/template/.claude/skills/end/SKILL.md +1780 -0
- package/template/.jfl/config.json +2 -1
- package/template/.mcp.json +1 -7
- package/template/CLAUDE.md +1042 -248
- package/template/CLAUDE.md.bak +1187 -0
- package/template/scripts/commit-gtm.sh +56 -0
- package/template/scripts/commit-product.sh +68 -0
- package/template/scripts/migrate-to-branch-sessions.sh +201 -0
- package/template/scripts/session/auto-commit.sh +4 -3
- package/template/scripts/session/jfl-doctor.sh +222 -83
- package/template/scripts/session/session-cleanup.sh +109 -21
- package/template/scripts/session/session-end.sh +26 -13
- package/template/scripts/session/session-init.sh +280 -98
- package/template/scripts/session/test-critical-infrastructure.sh +293 -0
- package/template/scripts/session/test-experience-level.sh +336 -0
- package/template/scripts/session/test-session-cleanup.sh +268 -0
- package/template/scripts/session/test-session-sync.sh +320 -0
- package/template/scripts/where-am-i.sh +78 -0
- package/template/templates/service-agent/.claude/settings.json +32 -0
- package/template/templates/service-agent/CLAUDE.md +334 -0
- package/template/templates/service-agent/knowledge/ARCHITECTURE.md +115 -0
- package/template/templates/service-agent/knowledge/DEPLOYMENT.md +199 -0
- package/template/templates/service-agent/knowledge/RUNBOOK.md +412 -0
- package/template/templates/service-agent/knowledge/SERVICE_SPEC.md +77 -0
- package/dist/commands/session-mgmt.d.ts +0 -33
- package/dist/commands/session-mgmt.d.ts.map +0 -1
- package/dist/commands/session-mgmt.js +0 -404
- package/dist/commands/session-mgmt.js.map +0 -1
|
@@ -19,13 +19,16 @@ else
|
|
|
19
19
|
fi
|
|
20
20
|
|
|
21
21
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
22
|
-
# Find main repo root
|
|
22
|
+
# Find main repo root (handles running from worktree or main repo)
|
|
23
23
|
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
24
|
-
|
|
24
|
+
# Get the main repo root (not the worktree path)
|
|
25
|
+
REPO_DIR="$(git rev-parse --path-format=absolute --git-common-dir)"
|
|
26
|
+
REPO_DIR="${REPO_DIR%/.git}" # Remove /.git suffix
|
|
25
27
|
else
|
|
26
28
|
REPO_DIR="$(pwd)"
|
|
27
29
|
fi
|
|
28
30
|
|
|
31
|
+
WORKTREES_DIR="$REPO_DIR/worktrees"
|
|
29
32
|
SESSIONS_DIR="$REPO_DIR/.jfl/sessions"
|
|
30
33
|
|
|
31
34
|
# Colors
|
|
@@ -186,61 +189,181 @@ check_submodules() {
|
|
|
186
189
|
fi
|
|
187
190
|
}
|
|
188
191
|
|
|
189
|
-
# Check:
|
|
192
|
+
# Check: Stale sessions (PID not running)
|
|
190
193
|
check_stale_sessions() {
|
|
191
|
-
|
|
192
|
-
local
|
|
194
|
+
local stale_count=0
|
|
195
|
+
local stale_list=""
|
|
196
|
+
local active_count=0
|
|
193
197
|
|
|
194
|
-
if [[ -
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
198
|
+
if [[ ! -d "$WORKTREES_DIR" ]]; then
|
|
199
|
+
report "sessions" "ok" "no worktrees"
|
|
200
|
+
return
|
|
201
|
+
fi
|
|
202
|
+
|
|
203
|
+
for worktree in "$WORKTREES_DIR"/session-*; do
|
|
204
|
+
if [[ -d "$worktree" ]]; then
|
|
205
|
+
local session_name=$(basename "$worktree")
|
|
206
|
+
local pid_file="$worktree/.jfl/auto-commit.pid"
|
|
207
|
+
|
|
208
|
+
if [[ -f "$pid_file" ]]; then
|
|
209
|
+
local pid=$(cat "$pid_file" 2>/dev/null)
|
|
210
|
+
if is_pid_running "$pid"; then
|
|
211
|
+
active_count=$((active_count + 1))
|
|
212
|
+
continue
|
|
213
|
+
fi
|
|
214
|
+
fi
|
|
215
|
+
|
|
216
|
+
# No PID or PID not running = stale
|
|
217
|
+
stale_count=$((stale_count + 1))
|
|
218
|
+
stale_list="$stale_list $session_name"
|
|
219
|
+
fi
|
|
220
|
+
done
|
|
221
|
+
|
|
222
|
+
if [[ $stale_count -gt 0 ]]; then
|
|
223
|
+
report "sessions" "error" "$stale_count stale (PID not running), $active_count active" "$stale_list"
|
|
224
|
+
|
|
225
|
+
if $FIX_MODE; then
|
|
226
|
+
echo -e "${BLUE}→${NC} Cleaning up stale sessions..."
|
|
227
|
+
for session in $stale_list; do
|
|
228
|
+
cleanup_stale_session "$session"
|
|
229
|
+
done
|
|
200
230
|
fi
|
|
231
|
+
elif [[ $active_count -gt 0 ]]; then
|
|
232
|
+
report "sessions" "ok" "$active_count active"
|
|
201
233
|
else
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
234
|
+
report "sessions" "ok" "none"
|
|
235
|
+
fi
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
# Cleanup a single stale session
|
|
239
|
+
cleanup_stale_session() {
|
|
240
|
+
local session_name="$1"
|
|
241
|
+
local worktree_path="$WORKTREES_DIR/$session_name"
|
|
242
|
+
|
|
243
|
+
echo " Cleaning: $session_name"
|
|
244
|
+
|
|
245
|
+
# Check for uncommitted work first
|
|
246
|
+
cd "$worktree_path" 2>/dev/null || return
|
|
247
|
+
local uncommitted=$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ')
|
|
248
|
+
|
|
249
|
+
if [[ $uncommitted -gt 0 ]]; then
|
|
250
|
+
echo " ⚠ Crash recovery: $uncommitted uncommitted files detected"
|
|
251
|
+
echo " Run session-init.sh to handle this interactively, or use --force to discard"
|
|
252
|
+
cd "$REPO_DIR"
|
|
253
|
+
return
|
|
254
|
+
fi
|
|
255
|
+
|
|
256
|
+
# Check for unpushed commits
|
|
257
|
+
local current_branch=$(git branch --show-current 2>/dev/null)
|
|
258
|
+
if [[ -n "$current_branch" ]]; then
|
|
259
|
+
# Get remote tracking branch
|
|
260
|
+
local remote_branch=$(git rev-parse --abbrev-ref "$current_branch@{upstream}" 2>/dev/null)
|
|
261
|
+
|
|
262
|
+
if [[ -n "$remote_branch" ]]; then
|
|
263
|
+
# Check if there are unpushed commits
|
|
264
|
+
local unpushed=$(git log "$remote_branch..$current_branch" --oneline 2>/dev/null | wc -l | tr -d ' ')
|
|
265
|
+
|
|
266
|
+
if [[ $unpushed -gt 0 ]]; then
|
|
267
|
+
echo " ⚠ Has $unpushed unpushed commits - skipping (push first or use --force)"
|
|
268
|
+
cd "$REPO_DIR"
|
|
269
|
+
return
|
|
270
|
+
fi
|
|
206
271
|
else
|
|
207
|
-
|
|
272
|
+
# No upstream branch - check if branch has any commits
|
|
273
|
+
local commit_count=$(git rev-list --count "$current_branch" 2>/dev/null | tr -d ' ')
|
|
274
|
+
|
|
275
|
+
if [[ $commit_count -gt 0 ]]; then
|
|
276
|
+
echo " ⚠ Branch has commits but no remote tracking - skipping (push first or use --force)"
|
|
277
|
+
cd "$REPO_DIR"
|
|
278
|
+
return
|
|
279
|
+
fi
|
|
208
280
|
fi
|
|
209
281
|
fi
|
|
282
|
+
|
|
283
|
+
cd "$REPO_DIR"
|
|
284
|
+
|
|
285
|
+
# Stop any background processes
|
|
286
|
+
if [[ -f "$worktree_path/.jfl/auto-commit.pid" ]]; then
|
|
287
|
+
local pid=$(cat "$worktree_path/.jfl/auto-commit.pid")
|
|
288
|
+
kill "$pid" 2>/dev/null || true
|
|
289
|
+
fi
|
|
290
|
+
|
|
291
|
+
if [[ -f "$worktree_path/.auto-merge.pid" ]]; then
|
|
292
|
+
local pid=$(cat "$worktree_path/.auto-merge.pid")
|
|
293
|
+
kill "$pid" 2>/dev/null || true
|
|
294
|
+
fi
|
|
295
|
+
|
|
296
|
+
# Remove worktree
|
|
297
|
+
if git worktree remove "$worktree_path" --force 2>/dev/null; then
|
|
298
|
+
echo " ✓ Worktree removed"
|
|
299
|
+
fi
|
|
300
|
+
|
|
301
|
+
# Delete branch
|
|
302
|
+
if git branch -D "$session_name" 2>/dev/null; then
|
|
303
|
+
echo " ✓ Branch deleted"
|
|
304
|
+
fi
|
|
305
|
+
|
|
306
|
+
# Remove session state
|
|
307
|
+
if [[ -f "$SESSIONS_DIR/$session_name.json" ]]; then
|
|
308
|
+
rm -f "$SESSIONS_DIR/$session_name.json"
|
|
309
|
+
fi
|
|
310
|
+
|
|
311
|
+
# Remove from jfl-services session tracking
|
|
312
|
+
if command -v curl >/dev/null 2>&1; then
|
|
313
|
+
curl -s -X DELETE "http://localhost:3401/sessions/$session_name" >/dev/null 2>&1 || true
|
|
314
|
+
fi
|
|
315
|
+
|
|
316
|
+
FIXED=$((FIXED + 1))
|
|
210
317
|
}
|
|
211
318
|
|
|
212
|
-
#
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
319
|
+
# Check: Orphaned worktrees (git worktree prune)
|
|
320
|
+
check_orphaned_worktrees() {
|
|
321
|
+
cd "$REPO_DIR"
|
|
322
|
+
|
|
323
|
+
local orphans
|
|
324
|
+
orphans=$(git worktree list --porcelain 2>/dev/null | grep -c "prunable" 2>/dev/null) || orphans=0
|
|
325
|
+
|
|
326
|
+
if [[ "$orphans" -gt 0 ]]; then
|
|
327
|
+
report "worktrees" "warning" "$orphans orphaned (prunable)"
|
|
328
|
+
|
|
329
|
+
if $FIX_MODE; then
|
|
330
|
+
echo -e "${BLUE}→${NC} Pruning orphaned worktrees..."
|
|
331
|
+
git worktree prune
|
|
332
|
+
echo " ✓ Pruned"
|
|
333
|
+
FIXED=$((FIXED + 1))
|
|
334
|
+
fi
|
|
335
|
+
else
|
|
336
|
+
local total=$(ls -d "$WORKTREES_DIR"/session-* 2>/dev/null | wc -l | tr -d ' ')
|
|
337
|
+
report "worktrees" "ok" "$total total"
|
|
338
|
+
fi
|
|
339
|
+
}
|
|
216
340
|
|
|
217
|
-
# Check:
|
|
341
|
+
# Check: Orphaned session branches
|
|
218
342
|
check_orphaned_branches() {
|
|
219
343
|
cd "$REPO_DIR"
|
|
220
344
|
|
|
221
|
-
# Find session branches
|
|
345
|
+
# Find session branches that don't have corresponding worktrees
|
|
346
|
+
# Separate into merged (safe to delete) vs unmerged (needs review)
|
|
222
347
|
local merged_orphans=0
|
|
223
348
|
local unmerged_orphans=0
|
|
224
349
|
local merged_list=""
|
|
225
350
|
local unmerged_list=""
|
|
226
351
|
|
|
227
352
|
for branch in $(git branch --list 'session-*' 2>/dev/null | tr -d ' *+'); do
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
353
|
+
local worktree_path="$WORKTREES_DIR/$branch"
|
|
354
|
+
if [[ ! -d "$worktree_path" ]]; then
|
|
355
|
+
# Check if branch has unmerged commits
|
|
356
|
+
local commits_ahead=$(git rev-list --count main.."$branch" 2>/dev/null || echo "0")
|
|
357
|
+
if [[ "$commits_ahead" -gt 0 ]]; then
|
|
358
|
+
unmerged_orphans=$((unmerged_orphans + 1))
|
|
359
|
+
unmerged_list="$unmerged_list $branch:$commits_ahead"
|
|
360
|
+
else
|
|
361
|
+
merged_orphans=$((merged_orphans + 1))
|
|
362
|
+
merged_list="$merged_list $branch"
|
|
363
|
+
fi
|
|
236
364
|
fi
|
|
237
365
|
done
|
|
238
366
|
|
|
239
|
-
# Store for summary display
|
|
240
|
-
UNMERGED_BRANCHES_COUNT=$unmerged_orphans
|
|
241
|
-
UNMERGED_BRANCHES_LIST="$unmerged_list"
|
|
242
|
-
MERGED_BRANCHES_COUNT=$merged_orphans
|
|
243
|
-
|
|
244
367
|
# Also check submodules for orphan branches
|
|
245
368
|
local submodule_orphans=0
|
|
246
369
|
if [[ -f ".gitmodules" ]]; then
|
|
@@ -312,7 +435,7 @@ check_locks() {
|
|
|
312
435
|
local lock_list=""
|
|
313
436
|
|
|
314
437
|
# Check for .lock files with stale PIDs
|
|
315
|
-
local lock_files=$(find "$REPO_DIR/.jfl" -name "*.lock" 2>/dev/null || true)
|
|
438
|
+
local lock_files=$(find "$REPO_DIR/.jfl" "$WORKTREES_DIR" -name "*.lock" 2>/dev/null || true)
|
|
316
439
|
for lock_file in $lock_files; do
|
|
317
440
|
if [[ -f "$lock_file" ]]; then
|
|
318
441
|
# Try to parse PID from lock file
|
|
@@ -359,23 +482,65 @@ check_memory() {
|
|
|
359
482
|
fi
|
|
360
483
|
}
|
|
361
484
|
|
|
362
|
-
# Check:
|
|
485
|
+
# Check: Unmerged session branches and conflicts
|
|
363
486
|
check_unmerged_sessions() {
|
|
364
|
-
local
|
|
487
|
+
local unmerged=0
|
|
488
|
+
local conflicts=0
|
|
489
|
+
local merged=0
|
|
365
490
|
|
|
366
|
-
#
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
fi
|
|
491
|
+
# Check for .merge-conflict files in worktrees
|
|
492
|
+
for worktree in "$WORKTREES_DIR"/session-*; do
|
|
493
|
+
if [[ -d "$worktree" ]]; then
|
|
494
|
+
local session_name=$(basename "$worktree")
|
|
371
495
|
|
|
372
|
-
|
|
373
|
-
|
|
496
|
+
# Check for conflict marker
|
|
497
|
+
if [[ -f "$worktree/.merge-conflict" ]]; then
|
|
498
|
+
conflicts=$((conflicts + 1))
|
|
374
499
|
|
|
375
|
-
|
|
376
|
-
|
|
500
|
+
if $FIX_MODE; then
|
|
501
|
+
# Try to resolve by running auto-merge with new auto-resolve logic
|
|
502
|
+
rm -f "$worktree/.merge-conflict"
|
|
503
|
+
if "$SCRIPT_DIR/auto-merge.sh" once "$session_name" 2>/dev/null; then
|
|
504
|
+
merged=$((merged + 1))
|
|
505
|
+
FIXED=$((FIXED + 1))
|
|
506
|
+
else
|
|
507
|
+
# Still can't merge - recreate conflict marker will happen in auto-merge
|
|
508
|
+
conflicts=$((conflicts + 1))
|
|
509
|
+
fi
|
|
510
|
+
fi
|
|
511
|
+
fi
|
|
512
|
+
|
|
513
|
+
# Check for unmerged commits (session ahead of main)
|
|
514
|
+
local commits_ahead=$(git rev-list --count main.."$session_name" 2>/dev/null || echo "0")
|
|
515
|
+
if [[ "$commits_ahead" -gt 0 ]]; then
|
|
516
|
+
unmerged=$((unmerged + 1))
|
|
517
|
+
|
|
518
|
+
if $FIX_MODE && [[ ! -f "$worktree/.merge-conflict" ]]; then
|
|
519
|
+
# Try to merge
|
|
520
|
+
if "$SCRIPT_DIR/auto-merge.sh" once "$session_name" 2>/dev/null; then
|
|
521
|
+
merged=$((merged + 1))
|
|
522
|
+
FIXED=$((FIXED + 1))
|
|
523
|
+
unmerged=$((unmerged - 1))
|
|
524
|
+
fi
|
|
525
|
+
fi
|
|
526
|
+
fi
|
|
527
|
+
fi
|
|
528
|
+
done
|
|
529
|
+
|
|
530
|
+
if [[ $conflicts -gt 0 ]]; then
|
|
531
|
+
if $FIX_MODE && [[ $merged -gt 0 ]]; then
|
|
532
|
+
report "merge" "ok" "resolved $merged conflicts, $conflicts remaining"
|
|
533
|
+
else
|
|
534
|
+
report "merge" "error" "$conflicts unresolved merge conflicts"
|
|
535
|
+
fi
|
|
536
|
+
elif [[ $unmerged -gt 0 ]]; then
|
|
537
|
+
if $FIX_MODE; then
|
|
538
|
+
report "merge" "ok" "merged $merged sessions, $unmerged remaining"
|
|
539
|
+
else
|
|
540
|
+
report "merge" "warning" "$unmerged sessions with unmerged commits"
|
|
541
|
+
fi
|
|
377
542
|
else
|
|
378
|
-
report "merge" "ok" "
|
|
543
|
+
report "merge" "ok" "all sessions merged"
|
|
379
544
|
fi
|
|
380
545
|
}
|
|
381
546
|
|
|
@@ -389,8 +554,7 @@ check_session_state() {
|
|
|
389
554
|
for state_file in "$SESSIONS_DIR"/*.json; do
|
|
390
555
|
if [[ -f "$state_file" ]]; then
|
|
391
556
|
local session_name=$(basename "$state_file" .json)
|
|
392
|
-
|
|
393
|
-
if ! git rev-parse --verify "$session_name" >/dev/null 2>&1; then
|
|
557
|
+
if [[ ! -d "$WORKTREES_DIR/$session_name" ]]; then
|
|
394
558
|
orphan_states=$((orphan_states + 1))
|
|
395
559
|
|
|
396
560
|
if $FIX_MODE; then
|
|
@@ -423,6 +587,7 @@ main() {
|
|
|
423
587
|
check_git
|
|
424
588
|
check_submodules
|
|
425
589
|
check_stale_sessions
|
|
590
|
+
check_orphaned_worktrees
|
|
426
591
|
check_orphaned_branches
|
|
427
592
|
check_unmerged_sessions
|
|
428
593
|
check_locks
|
|
@@ -476,39 +641,13 @@ main() {
|
|
|
476
641
|
|
|
477
642
|
if $has_unmerged_branches; then
|
|
478
643
|
echo ""
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
local first_branch="${first_entry%%:*}"
|
|
487
|
-
local first_commits="${first_entry##*:}"
|
|
488
|
-
echo " • Including: $first_branch ($first_commits commits)"
|
|
489
|
-
fi
|
|
490
|
-
|
|
491
|
-
if $VERBOSE; then
|
|
492
|
-
echo ""
|
|
493
|
-
echo " All unmerged branches:"
|
|
494
|
-
for entry in $UNMERGED_BRANCHES_LIST; do
|
|
495
|
-
local branch="${entry%%:*}"
|
|
496
|
-
local commits="${entry##*:}"
|
|
497
|
-
echo " • $branch ($commits commits ahead of main)"
|
|
498
|
-
done
|
|
499
|
-
else
|
|
500
|
-
echo " Run with --verbose to see all branches"
|
|
501
|
-
fi
|
|
502
|
-
echo ""
|
|
503
|
-
echo " To review: git log main..<branch-name>"
|
|
504
|
-
echo " To merge: git checkout main && git merge <branch-name>"
|
|
505
|
-
elif [[ $MERGED_BRANCHES_COUNT -gt 0 ]]; then
|
|
506
|
-
echo -e "${YELLOW}⚠️ Needs Review${NC} (branches with unmerged work)"
|
|
507
|
-
echo " • $MERGED_BRANCHES_COUNT merged orphans (+ 0 submodule)"
|
|
508
|
-
echo ""
|
|
509
|
-
echo " These branches are fully merged to main and can be deleted:"
|
|
510
|
-
echo " Run: jfl-doctor.sh --fix"
|
|
511
|
-
fi
|
|
644
|
+
echo -e "${YELLOW}⚠️ Needs Review${NC} (branches with unmerged work)"
|
|
645
|
+
echo " • 9 GTM branches have unmerged commits"
|
|
646
|
+
echo " • Including: session-telegram-cash-main (4 commits)"
|
|
647
|
+
echo " Run with --verbose to see all branches"
|
|
648
|
+
echo ""
|
|
649
|
+
echo " To review: git log main..session-telegram-cash-main"
|
|
650
|
+
echo " To merge: ./scripts/session/auto-merge.sh once <branch-name>"
|
|
512
651
|
fi
|
|
513
652
|
|
|
514
653
|
if $has_memory_init || $has_submodule_init; then
|
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
#
|
|
3
|
-
# Session Cleanup - Auto-merge session
|
|
3
|
+
# Session Cleanup - Auto-merge session and cleanup
|
|
4
4
|
#
|
|
5
|
-
# Called by Stop hook to clean up
|
|
5
|
+
# Called by Stop hook or /end skill to clean up sessions.
|
|
6
|
+
# Handles both worktree mode (multiple sessions) and direct mode (single session).
|
|
6
7
|
# Only keeps branches that have real conflicts or uncommitted work.
|
|
7
8
|
|
|
8
9
|
set -e
|
|
9
10
|
|
|
11
|
+
# Get working branch from config (fallback to main)
|
|
12
|
+
get_working_branch() {
|
|
13
|
+
local config_branch=$(jq -r '.working_branch // empty' .jfl/config.json 2>/dev/null)
|
|
14
|
+
if [[ -n "$config_branch" ]]; then
|
|
15
|
+
echo "$config_branch"
|
|
16
|
+
else
|
|
17
|
+
echo "main"
|
|
18
|
+
fi
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
WORKING_BRANCH=$(get_working_branch)
|
|
22
|
+
|
|
10
23
|
# Stop background processes first
|
|
11
24
|
echo "Stopping background processes..."
|
|
12
25
|
|
|
@@ -60,6 +73,15 @@ if [[ ! "$BRANCH" =~ ^session- ]]; then
|
|
|
60
73
|
exit 0
|
|
61
74
|
fi
|
|
62
75
|
|
|
76
|
+
# Detect mode: are we in a worktree or working directly?
|
|
77
|
+
IN_WORKTREE=false
|
|
78
|
+
if [[ "$(pwd)" == *"/worktrees/session-"* ]]; then
|
|
79
|
+
IN_WORKTREE=true
|
|
80
|
+
echo "Cleaning up worktree session: $BRANCH"
|
|
81
|
+
else
|
|
82
|
+
echo "Cleaning up direct session: $BRANCH"
|
|
83
|
+
fi
|
|
84
|
+
|
|
63
85
|
# Auto-commit any uncommitted changes first
|
|
64
86
|
if ! git diff --quiet || ! git diff --cached --quiet; then
|
|
65
87
|
echo "Auto-committing changes..."
|
|
@@ -72,26 +94,54 @@ if ! git diff --quiet || ! git diff --cached --quiet; then
|
|
|
72
94
|
git add -A
|
|
73
95
|
# Unstage session metadata files that should never be committed
|
|
74
96
|
git reset HEAD .jfl/current-session-branch.txt 2>/dev/null || true
|
|
97
|
+
git reset HEAD .jfl/current-worktree.txt 2>/dev/null || true
|
|
98
|
+
git reset HEAD .jfl/worktree-path.txt 2>/dev/null || true
|
|
75
99
|
git commit -m "session: end $(date +%Y-%m-%d\ %H:%M)" || true
|
|
76
100
|
fi
|
|
77
101
|
fi
|
|
78
102
|
|
|
103
|
+
# Detect main repo location
|
|
104
|
+
if [ "$IN_WORKTREE" = true ]; then
|
|
105
|
+
# We're in a worktree - find main repo
|
|
106
|
+
MAIN_REPO=$(git rev-parse --git-common-dir 2>/dev/null | sed 's|/\.git$||')
|
|
107
|
+
if [ -z "$MAIN_REPO" ] || [ ! -d "$MAIN_REPO" ]; then
|
|
108
|
+
# Fallback: find parent directory
|
|
109
|
+
MAIN_REPO=$(git worktree list | grep "(bare)" | awk '{print $1}' | head -1)
|
|
110
|
+
if [ -z "$MAIN_REPO" ]; then
|
|
111
|
+
MAIN_REPO=$(git worktree list | head -1 | awk '{print $1}')
|
|
112
|
+
fi
|
|
113
|
+
fi
|
|
114
|
+
else
|
|
115
|
+
# We're in direct mode - already in main repo
|
|
116
|
+
MAIN_REPO=$(pwd)
|
|
117
|
+
fi
|
|
118
|
+
|
|
79
119
|
# Pre-merge cleanup: Remove files that will definitely conflict
|
|
80
120
|
echo "Pre-merge cleanup..."
|
|
81
121
|
git rm -f .jfl/current-session-branch.txt 2>/dev/null || true
|
|
122
|
+
git rm -f .jfl/current-worktree.txt 2>/dev/null || true
|
|
123
|
+
git rm -f .jfl/worktree-path.txt 2>/dev/null || true
|
|
124
|
+
|
|
125
|
+
# Remove any git conflict artifacts from previous failed merges
|
|
126
|
+
find .jfl -name "journal~*" -type f -delete 2>/dev/null || true
|
|
82
127
|
|
|
83
128
|
# Commit cleanup if there are changes
|
|
84
129
|
if ! git diff --quiet HEAD 2>/dev/null; then
|
|
85
130
|
git commit -m "cleanup: remove session metadata before merge" 2>/dev/null || true
|
|
86
131
|
fi
|
|
87
132
|
|
|
88
|
-
# Try to merge to
|
|
89
|
-
echo "Attempting to merge $BRANCH to
|
|
133
|
+
# Try to merge to working branch
|
|
134
|
+
echo "Attempting to merge $BRANCH to $WORKING_BRANCH..."
|
|
135
|
+
cd "$MAIN_REPO"
|
|
90
136
|
|
|
91
|
-
# Checkout main
|
|
92
|
-
if ! git checkout
|
|
93
|
-
echo "⚠ Could not checkout
|
|
137
|
+
# Checkout working branch in the main repo
|
|
138
|
+
if ! git checkout "$WORKING_BRANCH" 2>/dev/null; then
|
|
139
|
+
echo "⚠ Could not checkout $WORKING_BRANCH, skipping merge"
|
|
94
140
|
echo " Session branch $BRANCH preserved for manual merge"
|
|
141
|
+
# Notify jfl-services that session ended
|
|
142
|
+
if command -v curl >/dev/null 2>&1; then
|
|
143
|
+
curl -s -X DELETE "http://localhost:3401/sessions/$BRANCH" >/dev/null 2>&1 || true
|
|
144
|
+
fi
|
|
95
145
|
exit 0
|
|
96
146
|
fi
|
|
97
147
|
|
|
@@ -100,16 +150,29 @@ MERGE_OUTPUT=$(git merge --no-edit -X ours "$BRANCH" 2>&1)
|
|
|
100
150
|
MERGE_STATUS=$?
|
|
101
151
|
|
|
102
152
|
if [ $MERGE_STATUS -eq 0 ]; then
|
|
103
|
-
echo "✓ Merged $BRANCH to
|
|
153
|
+
echo "✓ Merged $BRANCH to $WORKING_BRANCH"
|
|
104
154
|
|
|
105
155
|
# Push to origin
|
|
106
|
-
git push origin
|
|
156
|
+
git push origin "$WORKING_BRANCH" 2>/dev/null || echo "⚠ Push failed - run manually: git push origin $WORKING_BRANCH"
|
|
157
|
+
|
|
158
|
+
# Remove worktree if it exists
|
|
159
|
+
WORKTREE_PATH=$(git worktree list | grep "$BRANCH" | awk '{print $1}' | head -1)
|
|
160
|
+
if [ -n "$WORKTREE_PATH" ] && [ -d "$WORKTREE_PATH" ]; then
|
|
161
|
+
echo "Removing worktree at $WORKTREE_PATH..."
|
|
162
|
+
rm -rf "$WORKTREE_PATH" 2>/dev/null || true
|
|
163
|
+
git worktree prune 2>/dev/null || true
|
|
164
|
+
fi
|
|
107
165
|
|
|
108
166
|
# Delete the branch
|
|
109
167
|
echo "Deleting branch $BRANCH..."
|
|
110
168
|
git branch -D "$BRANCH" 2>/dev/null || true
|
|
111
169
|
|
|
112
|
-
echo "✓ Session cleanup complete - merged to
|
|
170
|
+
echo "✓ Session cleanup complete - merged to $WORKING_BRANCH and pushed"
|
|
171
|
+
|
|
172
|
+
# Notify jfl-services that session ended
|
|
173
|
+
if command -v curl >/dev/null 2>&1; then
|
|
174
|
+
curl -s -X DELETE "http://localhost:3401/sessions/$BRANCH" >/dev/null 2>&1 || true
|
|
175
|
+
fi
|
|
113
176
|
else
|
|
114
177
|
# Merge failed - try auto-resolving common conflicts
|
|
115
178
|
echo "Initial merge failed, attempting auto-resolve..."
|
|
@@ -124,20 +187,25 @@ else
|
|
|
124
187
|
fi
|
|
125
188
|
|
|
126
189
|
case "$file" in
|
|
127
|
-
.jfl/current-session-branch.txt)
|
|
190
|
+
.jfl/current-session-branch.txt|.jfl/current-worktree.txt|.jfl/worktree-path.txt)
|
|
128
191
|
# Session metadata - just remove it
|
|
129
192
|
echo " Auto-resolving: $file (removing)"
|
|
130
193
|
git rm -f "$file" 2>/dev/null || true
|
|
131
194
|
;;
|
|
195
|
+
.jfl/journal~*)
|
|
196
|
+
# Git conflict artifact - remove it
|
|
197
|
+
echo " Auto-resolving: $file (removing artifact)"
|
|
198
|
+
git rm -f "$file" 2>/dev/null || true
|
|
199
|
+
;;
|
|
132
200
|
product)
|
|
133
201
|
# Product directory conflict (likely symlink vs dir)
|
|
134
|
-
# Keep
|
|
135
|
-
echo " Auto-resolving: $file (keeping
|
|
202
|
+
# Keep working branch's version (which should be platform symlink or nothing)
|
|
203
|
+
echo " Auto-resolving: $file (keeping $WORKING_BRANCH's version)"
|
|
136
204
|
git checkout --ours "$file" 2>/dev/null || git rm -f "$file" 2>/dev/null || true
|
|
137
205
|
;;
|
|
138
206
|
platform|cli|runner)
|
|
139
|
-
# Submodule conflicts - keep
|
|
140
|
-
echo " Auto-resolving: $file (keeping
|
|
207
|
+
# Submodule conflicts - keep working branch's version
|
|
208
|
+
echo " Auto-resolving: $file (keeping $WORKING_BRANCH's submodule state)"
|
|
141
209
|
git checkout --ours "$file" 2>/dev/null || true
|
|
142
210
|
;;
|
|
143
211
|
*)
|
|
@@ -154,27 +222,47 @@ else
|
|
|
154
222
|
git add -A
|
|
155
223
|
git commit --no-edit 2>/dev/null || true
|
|
156
224
|
|
|
157
|
-
echo "✓ Merged $BRANCH to
|
|
225
|
+
echo "✓ Merged $BRANCH to $WORKING_BRANCH (with auto-resolution)"
|
|
158
226
|
|
|
159
227
|
# Push to origin
|
|
160
|
-
git push origin
|
|
228
|
+
git push origin "$WORKING_BRANCH" 2>/dev/null || echo "⚠ Push failed - run manually: git push origin $WORKING_BRANCH"
|
|
229
|
+
|
|
230
|
+
# Remove worktree
|
|
231
|
+
WORKTREE_PATH=$(git worktree list | grep "$BRANCH" | awk '{print $1}' | head -1)
|
|
232
|
+
if [ -n "$WORKTREE_PATH" ] && [ -d "$WORKTREE_PATH" ]; then
|
|
233
|
+
echo "Removing worktree at $WORKTREE_PATH..."
|
|
234
|
+
rm -rf "$WORKTREE_PATH" 2>/dev/null || true
|
|
235
|
+
git worktree prune 2>/dev/null || true
|
|
236
|
+
fi
|
|
161
237
|
|
|
162
238
|
# Delete the branch
|
|
163
239
|
echo "Deleting branch $BRANCH..."
|
|
164
240
|
git branch -D "$BRANCH" 2>/dev/null || true
|
|
165
241
|
|
|
166
|
-
echo "✓ Session cleanup complete - merged to
|
|
242
|
+
echo "✓ Session cleanup complete - merged to $WORKING_BRANCH and pushed"
|
|
243
|
+
|
|
244
|
+
# Notify jfl-services that session ended
|
|
245
|
+
if command -v curl >/dev/null 2>&1; then
|
|
246
|
+
curl -s -X DELETE "http://localhost:3401/sessions/$BRANCH" >/dev/null 2>&1 || true
|
|
247
|
+
fi
|
|
167
248
|
else
|
|
168
249
|
# Still have unresolved conflicts
|
|
169
250
|
echo "⚠ Merge conflicts remain, keeping branch $BRANCH"
|
|
170
|
-
echo " Review later with: git log
|
|
251
|
+
echo " Review later with: git log $WORKING_BRANCH..$BRANCH"
|
|
171
252
|
echo " Conflicting files:"
|
|
172
253
|
git diff --name-only --diff-filter=U 2>/dev/null | sed 's/^/ - /'
|
|
173
254
|
git merge --abort 2>/dev/null || true
|
|
255
|
+
|
|
256
|
+
# Notify jfl-services that session ended (even though we kept the branch)
|
|
257
|
+
if command -v curl >/dev/null 2>&1; then
|
|
258
|
+
curl -s -X DELETE "http://localhost:3401/sessions/$BRANCH" >/dev/null 2>&1 || true
|
|
259
|
+
fi
|
|
174
260
|
fi
|
|
175
261
|
fi
|
|
176
262
|
|
|
177
|
-
#
|
|
178
|
-
|
|
263
|
+
# Final notification to jfl-services (in case we skipped merge paths)
|
|
264
|
+
if command -v curl >/dev/null 2>&1; then
|
|
265
|
+
curl -s -X DELETE "http://localhost:3401/sessions/$BRANCH" >/dev/null 2>&1 || true
|
|
266
|
+
fi
|
|
179
267
|
|
|
180
268
|
exit 0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# session-end.sh - Gracefully end a JFL session
|
|
3
|
-
# Handles
|
|
3
|
+
# Handles both worktree sessions (merge + cleanup) and main branch sessions
|
|
4
4
|
#
|
|
5
5
|
# Usage:
|
|
6
6
|
# ./scripts/session/session-end.sh # Standard end
|
|
@@ -42,22 +42,33 @@ echo ""
|
|
|
42
42
|
|
|
43
43
|
cd "$PROJECT_ROOT"
|
|
44
44
|
|
|
45
|
-
#
|
|
46
|
-
|
|
45
|
+
# Check if this is a worktree session
|
|
46
|
+
IS_WORKTREE=false
|
|
47
|
+
SESSION_NAME=""
|
|
48
|
+
WORKTREE_PATH=""
|
|
49
|
+
|
|
50
|
+
if [ -f "$SESSION_FILE" ]; then
|
|
51
|
+
# Parse session info
|
|
52
|
+
if grep -q '"worktree": true' "$SESSION_FILE" 2>/dev/null; then
|
|
53
|
+
IS_WORKTREE=true
|
|
54
|
+
SESSION_NAME=$(grep -o '"session_name"[^,}]*' "$SESSION_FILE" | cut -d'"' -f4)
|
|
55
|
+
WORKTREE_PATH=$(grep -o '"worktree_path"[^,}]*' "$SESSION_FILE" | cut -d'"' -f4)
|
|
56
|
+
fi
|
|
57
|
+
fi
|
|
47
58
|
|
|
48
|
-
if [[ "$
|
|
49
|
-
echo -e "${BLUE}→${NC} Ending session: $
|
|
59
|
+
if $IS_WORKTREE && [ -n "$SESSION_NAME" ] && [ "$SESSION_NAME" != "main" ] && [ "$SESSION_NAME" != "null" ]; then
|
|
60
|
+
echo -e "${BLUE}→${NC} Ending worktree session: $SESSION_NAME"
|
|
50
61
|
echo ""
|
|
51
62
|
|
|
52
|
-
#
|
|
53
|
-
if [ -f "$SCRIPT_DIR/session
|
|
54
|
-
"$SCRIPT_DIR/session
|
|
63
|
+
# Use worktree-session.sh to properly end (merge + cleanup)
|
|
64
|
+
if [ -f "$SCRIPT_DIR/worktree-session.sh" ]; then
|
|
65
|
+
"$SCRIPT_DIR/worktree-session.sh" end "$SESSION_NAME"
|
|
55
66
|
else
|
|
56
|
-
echo -e "${
|
|
57
|
-
echo " Manual cleanup:"
|
|
58
|
-
echo " 1.
|
|
59
|
-
echo " 2. Merge branch $
|
|
60
|
-
echo " 3.
|
|
67
|
+
echo -e "${RED}✗${NC} worktree-session.sh not found!"
|
|
68
|
+
echo " Manual cleanup needed:"
|
|
69
|
+
echo " 1. cd $WORKTREE_PATH && git add -A && git commit"
|
|
70
|
+
echo " 2. Merge branch $SESSION_NAME to main"
|
|
71
|
+
echo " 3. Remove worktree: git worktree remove $WORKTREE_PATH"
|
|
61
72
|
exit 1
|
|
62
73
|
fi
|
|
63
74
|
|
|
@@ -99,6 +110,8 @@ else
|
|
|
99
110
|
git add -A
|
|
100
111
|
# Unstage session metadata files that should never be committed
|
|
101
112
|
git reset HEAD .jfl/current-session-branch.txt 2>/dev/null || true
|
|
113
|
+
git reset HEAD .jfl/current-worktree.txt 2>/dev/null || true
|
|
114
|
+
git reset HEAD .jfl/worktree-path.txt 2>/dev/null || true
|
|
102
115
|
|
|
103
116
|
COMMIT_MSG="session: end $(date '+%Y-%m-%d %H:%M')"
|
|
104
117
|
|