jfl 0.1.0 → 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.
Files changed (262) hide show
  1. package/README.md +443 -145
  2. package/clawdbot-plugin/clawdbot.plugin.json +20 -0
  3. package/clawdbot-plugin/index.js +555 -0
  4. package/clawdbot-plugin/index.ts +582 -0
  5. package/clawdbot-skill/SKILL.md +33 -336
  6. package/clawdbot-skill/index.ts +491 -321
  7. package/clawdbot-skill/skill.json +4 -13
  8. package/dist/commands/clawdbot.d.ts +11 -0
  9. package/dist/commands/clawdbot.d.ts.map +1 -0
  10. package/dist/commands/clawdbot.js +215 -0
  11. package/dist/commands/clawdbot.js.map +1 -0
  12. package/dist/commands/context-hub.d.ts +5 -0
  13. package/dist/commands/context-hub.d.ts.map +1 -1
  14. package/dist/commands/context-hub.js +394 -28
  15. package/dist/commands/context-hub.js.map +1 -1
  16. package/dist/commands/gtm-process-update.d.ts +10 -0
  17. package/dist/commands/gtm-process-update.d.ts.map +1 -0
  18. package/dist/commands/gtm-process-update.js +101 -0
  19. package/dist/commands/gtm-process-update.js.map +1 -0
  20. package/dist/commands/init.d.ts.map +1 -1
  21. package/dist/commands/init.js +278 -4
  22. package/dist/commands/init.js.map +1 -1
  23. package/dist/commands/login.d.ts.map +1 -1
  24. package/dist/commands/login.js +32 -33
  25. package/dist/commands/login.js.map +1 -1
  26. package/dist/commands/memory.d.ts +38 -0
  27. package/dist/commands/memory.d.ts.map +1 -0
  28. package/dist/commands/memory.js +229 -0
  29. package/dist/commands/memory.js.map +1 -0
  30. package/dist/commands/migrate-services.d.ts +8 -0
  31. package/dist/commands/migrate-services.d.ts.map +1 -0
  32. package/dist/commands/migrate-services.js +182 -0
  33. package/dist/commands/migrate-services.js.map +1 -0
  34. package/dist/commands/onboard.d.ts +24 -0
  35. package/dist/commands/onboard.d.ts.map +1 -0
  36. package/dist/commands/onboard.js +663 -0
  37. package/dist/commands/onboard.js.map +1 -0
  38. package/dist/commands/openclaw.d.ts +56 -0
  39. package/dist/commands/openclaw.d.ts.map +1 -0
  40. package/dist/commands/openclaw.js +700 -0
  41. package/dist/commands/openclaw.js.map +1 -0
  42. package/dist/commands/orchestrate.d.ts +14 -0
  43. package/dist/commands/orchestrate.d.ts.map +1 -0
  44. package/dist/commands/orchestrate.js +270 -0
  45. package/dist/commands/orchestrate.js.map +1 -0
  46. package/dist/commands/profile.d.ts +46 -0
  47. package/dist/commands/profile.d.ts.map +1 -0
  48. package/dist/commands/profile.js +498 -0
  49. package/dist/commands/profile.js.map +1 -0
  50. package/dist/commands/repair.d.ts.map +1 -1
  51. package/dist/commands/repair.js +37 -0
  52. package/dist/commands/repair.js.map +1 -1
  53. package/dist/commands/service-agent.d.ts +16 -0
  54. package/dist/commands/service-agent.d.ts.map +1 -0
  55. package/dist/commands/service-agent.js +375 -0
  56. package/dist/commands/service-agent.js.map +1 -0
  57. package/dist/commands/service-manager.d.ts +12 -0
  58. package/dist/commands/service-manager.d.ts.map +1 -0
  59. package/dist/commands/service-manager.js +967 -0
  60. package/dist/commands/service-manager.js.map +1 -0
  61. package/dist/commands/service-validate.d.ts +12 -0
  62. package/dist/commands/service-validate.d.ts.map +1 -0
  63. package/dist/commands/service-validate.js +611 -0
  64. package/dist/commands/service-validate.js.map +1 -0
  65. package/dist/commands/services-create.d.ts +15 -0
  66. package/dist/commands/services-create.d.ts.map +1 -0
  67. package/dist/commands/services-create.js +1452 -0
  68. package/dist/commands/services-create.js.map +1 -0
  69. package/dist/commands/services-scan.d.ts +13 -0
  70. package/dist/commands/services-scan.d.ts.map +1 -0
  71. package/dist/commands/services-scan.js +251 -0
  72. package/dist/commands/services-scan.js.map +1 -0
  73. package/dist/commands/services-sync-agents.d.ts +23 -0
  74. package/dist/commands/services-sync-agents.d.ts.map +1 -0
  75. package/dist/commands/services-sync-agents.js +207 -0
  76. package/dist/commands/services-sync-agents.js.map +1 -0
  77. package/dist/commands/services.d.ts +19 -0
  78. package/dist/commands/services.d.ts.map +1 -0
  79. package/dist/commands/services.js +742 -0
  80. package/dist/commands/services.js.map +1 -0
  81. package/dist/commands/session.d.ts +5 -1
  82. package/dist/commands/session.d.ts.map +1 -1
  83. package/dist/commands/session.js +68 -586
  84. package/dist/commands/session.js.map +1 -1
  85. package/dist/commands/status.d.ts.map +1 -1
  86. package/dist/commands/status.js +17 -0
  87. package/dist/commands/status.js.map +1 -1
  88. package/dist/commands/update.d.ts.map +1 -1
  89. package/dist/commands/update.js +75 -21
  90. package/dist/commands/update.js.map +1 -1
  91. package/dist/commands/validate-settings.d.ts +37 -0
  92. package/dist/commands/validate-settings.d.ts.map +1 -0
  93. package/dist/commands/validate-settings.js +197 -0
  94. package/dist/commands/validate-settings.js.map +1 -0
  95. package/dist/commands/voice.d.ts +0 -1
  96. package/dist/commands/voice.d.ts.map +1 -1
  97. package/dist/commands/voice.js +16 -15
  98. package/dist/commands/voice.js.map +1 -1
  99. package/dist/index.js +395 -141
  100. package/dist/index.js.map +1 -1
  101. package/dist/lib/agent-generator.d.ts +26 -0
  102. package/dist/lib/agent-generator.d.ts.map +1 -0
  103. package/dist/lib/agent-generator.js +331 -0
  104. package/dist/lib/agent-generator.js.map +1 -0
  105. package/dist/lib/memory-db.d.ts +102 -0
  106. package/dist/lib/memory-db.d.ts.map +1 -0
  107. package/dist/lib/memory-db.js +313 -0
  108. package/dist/lib/memory-db.js.map +1 -0
  109. package/dist/lib/memory-indexer.d.ts +47 -0
  110. package/dist/lib/memory-indexer.d.ts.map +1 -0
  111. package/dist/lib/memory-indexer.js +215 -0
  112. package/dist/lib/memory-indexer.js.map +1 -0
  113. package/dist/lib/memory-search.d.ts +41 -0
  114. package/dist/lib/memory-search.d.ts.map +1 -0
  115. package/dist/lib/memory-search.js +246 -0
  116. package/dist/lib/memory-search.js.map +1 -0
  117. package/dist/lib/openclaw-registry.d.ts +48 -0
  118. package/dist/lib/openclaw-registry.d.ts.map +1 -0
  119. package/dist/lib/openclaw-registry.js +181 -0
  120. package/dist/lib/openclaw-registry.js.map +1 -0
  121. package/dist/lib/openclaw-sdk.d.ts +107 -0
  122. package/dist/lib/openclaw-sdk.d.ts.map +1 -0
  123. package/dist/lib/openclaw-sdk.js +208 -0
  124. package/dist/lib/openclaw-sdk.js.map +1 -0
  125. package/dist/lib/peer-agent-generator.d.ts +44 -0
  126. package/dist/lib/peer-agent-generator.d.ts.map +1 -0
  127. package/dist/lib/peer-agent-generator.js +286 -0
  128. package/dist/lib/peer-agent-generator.js.map +1 -0
  129. package/dist/lib/service-dependencies.d.ts +44 -0
  130. package/dist/lib/service-dependencies.d.ts.map +1 -0
  131. package/dist/lib/service-dependencies.js +314 -0
  132. package/dist/lib/service-dependencies.js.map +1 -0
  133. package/dist/lib/service-detector.d.ts +61 -0
  134. package/dist/lib/service-detector.d.ts.map +1 -0
  135. package/dist/lib/service-detector.js +521 -0
  136. package/dist/lib/service-detector.js.map +1 -0
  137. package/dist/lib/service-gtm.d.ts +157 -0
  138. package/dist/lib/service-gtm.d.ts.map +1 -0
  139. package/dist/lib/service-gtm.js +786 -0
  140. package/dist/lib/service-gtm.js.map +1 -0
  141. package/dist/lib/service-mcp-base.d.ts +103 -0
  142. package/dist/lib/service-mcp-base.d.ts.map +1 -0
  143. package/dist/lib/service-mcp-base.js +263 -0
  144. package/dist/lib/service-mcp-base.js.map +1 -0
  145. package/dist/lib/service-utils.d.ts +103 -0
  146. package/dist/lib/service-utils.d.ts.map +1 -0
  147. package/dist/lib/service-utils.js +368 -0
  148. package/dist/lib/service-utils.js.map +1 -0
  149. package/dist/lib/skill-generator.d.ts +21 -0
  150. package/dist/lib/skill-generator.d.ts.map +1 -0
  151. package/dist/lib/skill-generator.js +253 -0
  152. package/dist/lib/skill-generator.js.map +1 -0
  153. package/dist/lib/stratus-client.d.ts +100 -0
  154. package/dist/lib/stratus-client.d.ts.map +1 -0
  155. package/dist/lib/stratus-client.js +255 -0
  156. package/dist/lib/stratus-client.js.map +1 -0
  157. package/dist/mcp/context-hub-mcp.js +135 -53
  158. package/dist/mcp/context-hub-mcp.js.map +1 -1
  159. package/dist/mcp/service-mcp-server.d.ts +12 -0
  160. package/dist/mcp/service-mcp-server.d.ts.map +1 -0
  161. package/dist/mcp/service-mcp-server.js +434 -0
  162. package/dist/mcp/service-mcp-server.js.map +1 -0
  163. package/dist/mcp/service-peer-mcp.d.ts +36 -0
  164. package/dist/mcp/service-peer-mcp.d.ts.map +1 -0
  165. package/dist/mcp/service-peer-mcp.js +220 -0
  166. package/dist/mcp/service-peer-mcp.js.map +1 -0
  167. package/dist/mcp/service-registry-mcp.d.ts +13 -0
  168. package/dist/mcp/service-registry-mcp.d.ts.map +1 -0
  169. package/dist/mcp/service-registry-mcp.js +330 -0
  170. package/dist/mcp/service-registry-mcp.js.map +1 -0
  171. package/dist/ui/banner.js +1 -1
  172. package/dist/ui/banner.js.map +1 -1
  173. package/dist/ui/context-hub-logs.d.ts +10 -0
  174. package/dist/ui/context-hub-logs.d.ts.map +1 -0
  175. package/dist/ui/context-hub-logs.js +175 -0
  176. package/dist/ui/context-hub-logs.js.map +1 -0
  177. package/dist/ui/service-dashboard.d.ts +11 -0
  178. package/dist/ui/service-dashboard.d.ts.map +1 -0
  179. package/dist/ui/service-dashboard.js +357 -0
  180. package/dist/ui/service-dashboard.js.map +1 -0
  181. package/dist/ui/services-manager.d.ts +11 -0
  182. package/dist/ui/services-manager.d.ts.map +1 -0
  183. package/dist/ui/services-manager.js +507 -0
  184. package/dist/ui/services-manager.js.map +1 -0
  185. package/dist/utils/auth-guard.d.ts.map +1 -1
  186. package/dist/utils/auth-guard.js +8 -9
  187. package/dist/utils/auth-guard.js.map +1 -1
  188. package/dist/utils/claude-md-generator.d.ts +10 -0
  189. package/dist/utils/claude-md-generator.d.ts.map +1 -0
  190. package/dist/utils/claude-md-generator.js +215 -0
  191. package/dist/utils/claude-md-generator.js.map +1 -0
  192. package/dist/utils/ensure-context-hub.d.ts +20 -0
  193. package/dist/utils/ensure-context-hub.d.ts.map +1 -0
  194. package/dist/utils/ensure-context-hub.js +65 -0
  195. package/dist/utils/ensure-context-hub.js.map +1 -0
  196. package/dist/utils/ensure-project.d.ts.map +1 -1
  197. package/dist/utils/ensure-project.js +3 -4
  198. package/dist/utils/ensure-project.js.map +1 -1
  199. package/dist/utils/jfl-config.d.ts +19 -0
  200. package/dist/utils/jfl-config.d.ts.map +1 -0
  201. package/dist/utils/jfl-config.js +112 -0
  202. package/dist/utils/jfl-config.js.map +1 -0
  203. package/dist/utils/jfl-migration.d.ts +29 -0
  204. package/dist/utils/jfl-migration.d.ts.map +1 -0
  205. package/dist/utils/jfl-migration.js +142 -0
  206. package/dist/utils/jfl-migration.js.map +1 -0
  207. package/dist/utils/jfl-paths.d.ts +55 -0
  208. package/dist/utils/jfl-paths.d.ts.map +1 -0
  209. package/dist/utils/jfl-paths.js +120 -0
  210. package/dist/utils/jfl-paths.js.map +1 -0
  211. package/dist/utils/settings-validator.d.ts +73 -0
  212. package/dist/utils/settings-validator.d.ts.map +1 -0
  213. package/dist/utils/settings-validator.js +222 -0
  214. package/dist/utils/settings-validator.js.map +1 -0
  215. package/package.json +19 -3
  216. package/scripts/commit-gtm.sh +56 -0
  217. package/scripts/commit-product.sh +68 -0
  218. package/scripts/context-query.sh +45 -0
  219. package/scripts/session/auto-commit.sh +297 -0
  220. package/scripts/session/jfl-doctor.sh +707 -0
  221. package/scripts/session/session-cleanup.sh +268 -0
  222. package/scripts/session/session-end.sh +198 -0
  223. package/scripts/session/session-init.sh +350 -0
  224. package/scripts/session/session-init.sh.backup +292 -0
  225. package/scripts/session/session-sync.sh +167 -0
  226. package/scripts/session/test-context-preservation.sh +160 -0
  227. package/scripts/session/test-critical-infrastructure.sh +293 -0
  228. package/scripts/session/test-experience-level.sh +336 -0
  229. package/scripts/session/test-session-cleanup.sh +268 -0
  230. package/scripts/session/test-session-sync.sh +320 -0
  231. package/scripts/voice-start.sh +36 -8
  232. package/scripts/where-am-i.sh +78 -0
  233. package/template/.claude/service-settings.json +32 -0
  234. package/template/.claude/settings.json +14 -1
  235. package/template/.claude/skills/end/SKILL.md +1780 -0
  236. package/template/.jfl/config.json +2 -1
  237. package/template/CLAUDE.md +1039 -134
  238. package/template/CLAUDE.md.bak +1187 -0
  239. package/template/scripts/commit-gtm.sh +56 -0
  240. package/template/scripts/commit-product.sh +68 -0
  241. package/template/scripts/migrate-to-branch-sessions.sh +201 -0
  242. package/template/scripts/session/auto-commit.sh +58 -6
  243. package/template/scripts/session/jfl-doctor.sh +137 -17
  244. package/template/scripts/session/session-cleanup.sh +268 -0
  245. package/template/scripts/session/session-end.sh +4 -0
  246. package/template/scripts/session/session-init.sh +253 -66
  247. package/template/scripts/session/test-critical-infrastructure.sh +293 -0
  248. package/template/scripts/session/test-experience-level.sh +336 -0
  249. package/template/scripts/session/test-session-cleanup.sh +268 -0
  250. package/template/scripts/session/test-session-sync.sh +320 -0
  251. package/template/scripts/where-am-i.sh +78 -0
  252. package/template/templates/service-agent/.claude/settings.json +32 -0
  253. package/template/templates/service-agent/CLAUDE.md +334 -0
  254. package/template/templates/service-agent/knowledge/ARCHITECTURE.md +115 -0
  255. package/template/templates/service-agent/knowledge/DEPLOYMENT.md +199 -0
  256. package/template/templates/service-agent/knowledge/RUNBOOK.md +412 -0
  257. package/template/templates/service-agent/knowledge/SERVICE_SPEC.md +77 -0
  258. package/dist/commands/session-mgmt.d.ts +0 -33
  259. package/dist/commands/session-mgmt.d.ts.map +0 -1
  260. package/dist/commands/session-mgmt.js +0 -404
  261. package/dist/commands/session-mgmt.js.map +0 -1
  262. package/template/scripts/session/auto-merge.sh +0 -325
@@ -0,0 +1,268 @@
1
+ #!/bin/bash
2
+ #
3
+ # Session Cleanup - Auto-merge session and cleanup
4
+ #
5
+ # Called by Stop hook or /end skill to clean up sessions.
6
+ # Handles both worktree mode (multiple sessions) and direct mode (single session).
7
+ # Only keeps branches that have real conflicts or uncommitted work.
8
+
9
+ set -e
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
+
23
+ # Stop background processes first
24
+ echo "Stopping background processes..."
25
+
26
+ # Stop auto-commit if running
27
+ if [ -f ".jfl/auto-commit.pid" ]; then
28
+ PID=$(cat ".jfl/auto-commit.pid")
29
+ if kill -0 "$PID" 2>/dev/null; then
30
+ echo " Stopping auto-commit (PID: $PID)..."
31
+ kill -TERM "$PID" 2>/dev/null || true
32
+ sleep 1
33
+ # Force kill if still running
34
+ kill -0 "$PID" 2>/dev/null && kill -9 "$PID" 2>/dev/null || true
35
+ fi
36
+ rm -f ".jfl/auto-commit.pid"
37
+ fi
38
+
39
+ # Stop auto-merge if running
40
+ if [ -f ".auto-merge.pid" ]; then
41
+ PID=$(cat ".auto-merge.pid")
42
+ if kill -0 "$PID" 2>/dev/null; then
43
+ echo " Stopping auto-merge (PID: $PID)..."
44
+ kill -TERM "$PID" 2>/dev/null || true
45
+ sleep 1
46
+ kill -0 "$PID" 2>/dev/null && kill -9 "$PID" 2>/dev/null || true
47
+ fi
48
+ rm -f ".auto-merge.pid"
49
+ fi
50
+
51
+ # Stop context-hub if running (already handled by Stop hook, but be defensive)
52
+ if [ -f ".jfl/context-hub.pid" ]; then
53
+ PID=$(cat ".jfl/context-hub.pid")
54
+ if kill -0 "$PID" 2>/dev/null; then
55
+ echo " Stopping context-hub (PID: $PID)..."
56
+ kill -TERM "$PID" 2>/dev/null || true
57
+ sleep 1
58
+ kill -0 "$PID" 2>/dev/null && kill -9 "$PID" 2>/dev/null || true
59
+ fi
60
+ rm -f ".jfl/context-hub.pid"
61
+ fi
62
+
63
+ # Get current session info
64
+ BRANCH=$(git branch --show-current 2>/dev/null || echo "")
65
+ if [ -z "$BRANCH" ]; then
66
+ echo "Not on a branch, skipping cleanup"
67
+ exit 0
68
+ fi
69
+
70
+ # Skip if not a session branch
71
+ if [[ ! "$BRANCH" =~ ^session- ]]; then
72
+ echo "Not a session branch, skipping cleanup"
73
+ exit 0
74
+ fi
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
+
85
+ # Auto-commit any uncommitted changes first
86
+ if ! git diff --quiet || ! git diff --cached --quiet; then
87
+ echo "Auto-committing changes..."
88
+
89
+ # Check if last commit is already "session: end" (make idempotent)
90
+ LAST_MSG=$(git log -1 --pretty=%s 2>/dev/null || echo "")
91
+ if [[ "$LAST_MSG" =~ ^session:\ end ]]; then
92
+ echo "Last commit already is 'session: end', skipping duplicate commit"
93
+ else
94
+ git add -A
95
+ # Unstage session metadata files that should never be committed
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
99
+ git commit -m "session: end $(date +%Y-%m-%d\ %H:%M)" || true
100
+ fi
101
+ fi
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
+
119
+ # Pre-merge cleanup: Remove files that will definitely conflict
120
+ echo "Pre-merge cleanup..."
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
127
+
128
+ # Commit cleanup if there are changes
129
+ if ! git diff --quiet HEAD 2>/dev/null; then
130
+ git commit -m "cleanup: remove session metadata before merge" 2>/dev/null || true
131
+ fi
132
+
133
+ # Try to merge to working branch
134
+ echo "Attempting to merge $BRANCH to $WORKING_BRANCH..."
135
+ cd "$MAIN_REPO"
136
+
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"
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
145
+ exit 0
146
+ fi
147
+
148
+ # Attempt merge with auto-resolve for .jfl/ conflicts
149
+ MERGE_OUTPUT=$(git merge --no-edit -X ours "$BRANCH" 2>&1)
150
+ MERGE_STATUS=$?
151
+
152
+ if [ $MERGE_STATUS -eq 0 ]; then
153
+ echo "✓ Merged $BRANCH to $WORKING_BRANCH"
154
+
155
+ # Push to 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
165
+
166
+ # Delete the branch
167
+ echo "Deleting branch $BRANCH..."
168
+ git branch -D "$BRANCH" 2>/dev/null || true
169
+
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
176
+ else
177
+ # Merge failed - try auto-resolving common conflicts
178
+ echo "Initial merge failed, attempting auto-resolve..."
179
+
180
+ # Check what conflicts we have
181
+ CONFLICTS=$(git diff --name-only --diff-filter=U 2>/dev/null)
182
+
183
+ AUTO_RESOLVED=true
184
+ while IFS= read -r file; do
185
+ if [[ -z "$file" ]]; then
186
+ continue
187
+ fi
188
+
189
+ case "$file" in
190
+ .jfl/current-session-branch.txt|.jfl/current-worktree.txt|.jfl/worktree-path.txt)
191
+ # Session metadata - just remove it
192
+ echo " Auto-resolving: $file (removing)"
193
+ git rm -f "$file" 2>/dev/null || true
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
+ ;;
200
+ product)
201
+ # Product directory conflict (likely symlink vs dir)
202
+ # Keep working branch's version (which should be platform symlink or nothing)
203
+ echo " Auto-resolving: $file (keeping $WORKING_BRANCH's version)"
204
+ git checkout --ours "$file" 2>/dev/null || git rm -f "$file" 2>/dev/null || true
205
+ ;;
206
+ platform|cli|runner)
207
+ # Submodule conflicts - keep working branch's version
208
+ echo " Auto-resolving: $file (keeping $WORKING_BRANCH's submodule state)"
209
+ git checkout --ours "$file" 2>/dev/null || true
210
+ ;;
211
+ *)
212
+ # Unknown conflict - can't auto-resolve
213
+ echo " ⚠ Cannot auto-resolve: $file"
214
+ AUTO_RESOLVED=false
215
+ ;;
216
+ esac
217
+ done <<< "$CONFLICTS"
218
+
219
+ if [ "$AUTO_RESOLVED" = true ]; then
220
+ # All conflicts resolved, complete the merge
221
+ echo "All conflicts auto-resolved, completing merge..."
222
+ git add -A
223
+ git commit --no-edit 2>/dev/null || true
224
+
225
+ echo "✓ Merged $BRANCH to $WORKING_BRANCH (with auto-resolution)"
226
+
227
+ # Push to 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
237
+
238
+ # Delete the branch
239
+ echo "Deleting branch $BRANCH..."
240
+ git branch -D "$BRANCH" 2>/dev/null || true
241
+
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
248
+ else
249
+ # Still have unresolved conflicts
250
+ echo "⚠ Merge conflicts remain, keeping branch $BRANCH"
251
+ echo " Review later with: git log $WORKING_BRANCH..$BRANCH"
252
+ echo " Conflicting files:"
253
+ git diff --name-only --diff-filter=U 2>/dev/null | sed 's/^/ - /'
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
260
+ fi
261
+ fi
262
+
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
267
+
268
+ exit 0
@@ -108,6 +108,10 @@ else
108
108
  echo ""
109
109
  echo -e "${BLUE}→${NC} Committing all changes..."
110
110
  git add -A
111
+ # Unstage session metadata files that should never be committed
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
111
115
 
112
116
  COMMIT_MSG="session: end $(date '+%Y-%m-%d %H:%M')"
113
117
 
@@ -26,7 +26,7 @@ CYAN='\033[0;36m'
26
26
  NC='\033[0m'
27
27
 
28
28
  # ==============================================================================
29
- # Step 1: Quick health check (warn only)
29
+ # Step 0: Sync repos to latest (prevent context loss)
30
30
  # ==============================================================================
31
31
 
32
32
  echo ""
@@ -34,6 +34,18 @@ echo "━━━━━━━━━━━━━━━━━━━━━━━━
34
34
  echo " JFL Session Init"
35
35
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
36
36
 
37
+ # Sync repos before creating worktree (ensures worktree is from latest main)
38
+ if [[ -x "$SCRIPT_DIR/session-sync.sh" ]]; then
39
+ echo ""
40
+ "$SCRIPT_DIR/session-sync.sh" || {
41
+ echo -e "${YELLOW}⚠${NC} Session sync failed, continuing with local state"
42
+ }
43
+ fi
44
+
45
+ # ==============================================================================
46
+ # Step 1: Quick health check (warn only)
47
+ # ==============================================================================
48
+
37
49
  # Count stale sessions (no PID or PID not running)
38
50
  stale_count=0
39
51
  active_count=0
@@ -71,93 +83,268 @@ if [[ $stale_count -gt 5 ]]; then
71
83
  fi
72
84
 
73
85
  # ==============================================================================
74
- # Step 3: Create new worktree
86
+ # Step 2.5: Crash Reconciliation - Check for uncommitted work in stale sessions
75
87
  # ==============================================================================
76
88
 
77
- # Generate session name with collision protection
89
+ if [[ -d "$WORKTREES_DIR" ]]; then
90
+ worktrees_with_changes=""
91
+ change_count=0
92
+
93
+ for worktree in "$WORKTREES_DIR"/session-*; do
94
+ if [[ -d "$worktree" ]]; then
95
+ # Check if worktree has uncommitted changes
96
+ cd "$worktree"
97
+ if [[ -n $(git status --porcelain 2>/dev/null) ]]; then
98
+ session_name=$(basename "$worktree")
99
+ worktrees_with_changes="$worktrees_with_changes $session_name"
100
+ change_count=$((change_count + 1))
101
+ fi
102
+ cd "$REPO_DIR"
103
+ fi
104
+ done
105
+
106
+ if [[ $change_count -gt 0 ]]; then
107
+ echo ""
108
+ echo -e "${RED}⚠${NC} Found $change_count session(s) with uncommitted work"
109
+ echo ""
110
+
111
+ for session in $worktrees_with_changes; do
112
+ worktree_path="$WORKTREES_DIR/$session"
113
+ cd "$worktree_path"
114
+ files=$(git status --porcelain | wc -l | tr -d ' ')
115
+ echo " • $session ($files files)"
116
+ cd "$REPO_DIR"
117
+ done
118
+
119
+ echo ""
120
+ echo -e "${YELLOW}This work needs to be saved before continuing.${NC}"
121
+ echo ""
122
+
123
+ # Check if running non-interactively (hook context)
124
+ if [[ ! -t 0 ]]; then
125
+ # Non-interactive - auto-commit (safest)
126
+ echo "Running non-interactively - auto-committing all changes..."
127
+ choice="1"
128
+ else
129
+ # Interactive - ask user
130
+ echo "Options:"
131
+ echo " 1) Auto-commit all and continue (safest - no work lost)"
132
+ echo " 2) Show me the changes (for review)"
133
+ echo " 3) Skip for now (manual cleanup)"
134
+ echo ""
135
+ read -p "Choose [1-3]: " choice
136
+ fi
137
+
138
+ case "$choice" in
139
+ 1)
140
+ echo ""
141
+ echo -e "${CYAN}→${NC} Auto-committing all changes..."
142
+ for session in $worktrees_with_changes; do
143
+ worktree_path="$WORKTREES_DIR/$session"
144
+ cd "$worktree_path"
145
+
146
+ if [[ -n $(git status --porcelain 2>/dev/null) ]]; then
147
+ # Critical paths
148
+ git add knowledge/ previews/ content/ suggestions/ CLAUDE.md .jfl/ 2>/dev/null || true
149
+
150
+ if git commit -m "crash recovery: auto-save uncommitted work from $session" 2>/dev/null; then
151
+ echo -e " ${GREEN}✓${NC} $session - committed and saved"
152
+ git push origin "$(git branch --show-current)" 2>/dev/null || true
153
+ fi
154
+ fi
155
+
156
+ cd "$REPO_DIR"
157
+ done
158
+ echo ""
159
+ echo -e "${GREEN}✓${NC} All changes saved. Continuing..."
160
+ ;;
161
+ 2)
162
+ echo ""
163
+ for session in $worktrees_with_changes; do
164
+ worktree_path="$WORKTREES_DIR/$session"
165
+ echo "─────────────────────────────────────"
166
+ echo "$session:"
167
+ echo ""
168
+ cd "$worktree_path"
169
+ git status --short
170
+ cd "$REPO_DIR"
171
+ echo ""
172
+ done
173
+ echo "─────────────────────────────────────"
174
+ echo ""
175
+ read -p "Commit these changes? [y/N]: " commit_choice
176
+ if [[ "$commit_choice" =~ ^[Yy]$ ]]; then
177
+ for session in $worktrees_with_changes; do
178
+ worktree_path="$WORKTREES_DIR/$session"
179
+ cd "$worktree_path"
180
+ git add knowledge/ previews/ content/ suggestions/ CLAUDE.md .jfl/ 2>/dev/null || true
181
+ git commit -m "crash recovery: manual save from $session" 2>/dev/null || true
182
+ git push origin "$(git branch --show-current)" 2>/dev/null || true
183
+ cd "$REPO_DIR"
184
+ done
185
+ echo -e "${GREEN}✓${NC} Changes committed"
186
+ fi
187
+ ;;
188
+ 3)
189
+ echo ""
190
+ echo -e "${YELLOW}Skipping crash recovery.${NC}"
191
+ echo "You can manually handle these sessions later."
192
+ echo ""
193
+ ;;
194
+ *)
195
+ echo ""
196
+ echo -e "${RED}Invalid choice. Skipping.${NC}"
197
+ ;;
198
+ esac
199
+ fi
200
+ fi
201
+
202
+ # ==============================================================================
203
+ # Step 2.9: Check for concurrent sessions via jfl-services
204
+ # ==============================================================================
205
+
206
+ # Generate session details first
78
207
  user=$(git config user.name 2>/dev/null | tr ' ' '-' | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9-' || echo "user")
79
- # Truncate long usernames to prevent path issues
80
208
  user="${user:0:30}"
81
209
  date_str=$(date +%Y%m%d)
82
210
  time_str=$(date +%H%M)
211
+ random_id=$(openssl rand -hex 3 2>/dev/null || printf "%06x" $RANDOM$RANDOM)
212
+ session_name="session-${user}-${date_str}-${time_str}-${random_id}"
213
+
214
+ # Get working branch (from config or current branch)
215
+ working_branch=$(jq -r '.working_branch // empty' .jfl/config.json 2>/dev/null)
216
+ if [[ -z "$working_branch" ]]; then
217
+ working_branch=$(git branch --show-current)
218
+ fi
219
+
220
+ # Check for concurrent sessions via jfl-services API
221
+ use_worktree=false
222
+ api_response=""
223
+ if command -v curl >/dev/null 2>&1; then
224
+ api_response=$(curl -s -X GET "http://localhost:3401/sessions/active?projectPath=$(pwd)" 2>/dev/null || echo "")
83
225
 
84
- # Generate unique session name, retry if collision detected
85
- max_attempts=5
86
- attempt=0
87
- while [[ $attempt -lt $max_attempts ]]; do
88
- random_id=$(openssl rand -hex 3 2>/dev/null || printf "%06x" $RANDOM$RANDOM)
89
- session_name="session-${user}-${date_str}-${time_str}-${random_id}"
90
-
91
- # Check for collision: journal file or worktree already exists
92
- if [[ -f "$REPO_DIR/.jfl/journal/${session_name}.jsonl" ]] || [[ -d "$WORKTREES_DIR/$session_name" ]]; then
93
- echo -e "${YELLOW}⚠${NC} Session name collision, regenerating..."
94
- attempt=$((attempt + 1))
95
- sleep 0.1 # Brief pause before retry
226
+ if [[ -n "$api_response" ]] && echo "$api_response" | jq -e '.count' >/dev/null 2>&1; then
227
+ session_count=$(echo "$api_response" | jq -r '.count // 0')
228
+
229
+ if [[ $session_count -gt 0 ]]; then
230
+ use_worktree=true
231
+ echo -e "${YELLOW}→${NC} Multiple sessions detected ($session_count active) - using worktree for isolation"
232
+ else
233
+ echo -e "${GREEN}→${NC} Single session - working directly on branch $working_branch"
234
+ fi
96
235
  else
97
- break
236
+ # API unavailable - fall back to local detection
237
+ echo -e "${YELLOW}→${NC} jfl-services unavailable - checking locally..."
238
+ local_sessions=$(ps aux | grep -c "claude.*$(pwd)" 2>/dev/null || echo "1")
239
+ if [[ $local_sessions -gt 2 ]]; then
240
+ use_worktree=true
241
+ echo -e "${YELLOW}→${NC} Multiple processes detected - using worktree for isolation"
242
+ fi
98
243
  fi
99
- done
244
+ else
245
+ # No curl - assume single session
246
+ echo -e "${GREEN}→${NC} Working directly on branch $working_branch"
247
+ fi
100
248
 
101
- if [[ $attempt -ge $max_attempts ]]; then
102
- echo -e "${RED}✗${NC} Failed to generate unique session name after $max_attempts attempts"
103
- exit 1
249
+ # Register this session with jfl-services
250
+ if command -v curl >/dev/null 2>&1; then
251
+ curl -s -X POST "http://localhost:3401/sessions/start" \
252
+ -H "Content-Type: application/json" \
253
+ -d "{\"id\":\"$session_name\",\"projectPath\":\"$(pwd)\",\"branch\":\"$working_branch\",\"user\":\"$user\",\"pid\":$$,\"worktree\":\"$use_worktree\"}" \
254
+ >/dev/null 2>&1 || true
104
255
  fi
105
256
 
106
- worktree_path="$WORKTREES_DIR/$session_name"
257
+ # ==============================================================================
258
+ # Step 3: Create worktree (if needed) or work directly
259
+ # ==============================================================================
107
260
 
108
- echo ""
109
- echo "Creating session: $session_name"
261
+ if [[ "$use_worktree" == "true" ]]; then
262
+ # WORKTREE MODE: Multiple sessions detected
263
+ echo ""
264
+ echo "Creating worktree session: $session_name"
110
265
 
111
- # Create worktree
112
- if git worktree add "$worktree_path" -b "$session_name" 2>&1 | head -3; then
113
- echo -e "${GREEN}✓${NC} Worktree created"
114
- else
115
- echo -e "${RED}✗${NC} Failed to create worktree"
116
- # Fall back to main branch
117
- echo "main" > "$REPO_DIR/.jfl/current-worktree.txt"
118
- echo "main" > "$REPO_DIR/.jfl/current-session-branch.txt"
119
- exit 0
120
- fi
266
+ worktree_path="$WORKTREES_DIR/$session_name"
121
267
 
122
- # Initialize submodules in worktree (quick, no network)
123
- cd "$worktree_path"
124
- if [[ -f ".gitmodules" ]]; then
125
- if [[ ! -d "product/.git" ]] && [[ ! -f "product/.git" ]]; then
126
- echo " Initializing submodules..."
127
- git submodule update --init --depth 1 product 2>/dev/null || true
268
+ # Create worktree
269
+ if git worktree add "$worktree_path" -b "$session_name" 2>&1 | head -3; then
270
+ echo -e "${GREEN}✓${NC} Worktree created"
271
+ else
272
+ echo -e "${RED}✗${NC} Failed to create worktree"
273
+ # Fall back to direct branch mode
274
+ use_worktree=false
128
275
  fi
129
- fi
130
276
 
131
- # Create session directories
132
- mkdir -p .jfl/logs
277
+ if [[ "$use_worktree" == "true" ]]; then
278
+ # Initialize submodules in worktree (quick, no network)
279
+ cd "$worktree_path"
280
+ if [[ -f ".gitmodules" ]]; then
281
+ if [[ ! -d "product/.git" ]] && [[ ! -f "product/.git" ]]; then
282
+ echo "→ Initializing submodules..."
283
+ git submodule update --init --depth 1 product 2>/dev/null || true
284
+ fi
285
+ fi
286
+
287
+ # Create session directories
288
+ mkdir -p .jfl/logs
133
289
 
134
- # CRITICAL: Symlink journal to main repo so entries persist after worktree cleanup
135
- # Without this, journal entries written in worktree are lost when worktree is removed!
136
- rm -rf .jfl/journal 2>/dev/null || true
137
- ln -sf "$REPO_DIR/.jfl/journal" .jfl/journal
138
- echo -e "${GREEN}✓${NC} Journal symlinked to main repo"
290
+ # CRITICAL: Symlink journal to main repo so entries persist after worktree cleanup
291
+ rm -rf .jfl/journal 2>/dev/null || true
292
+ ln -sf "$REPO_DIR/.jfl/journal" .jfl/journal
293
+ echo -e "${GREEN}✓${NC} Journal symlinked to main repo"
294
+
295
+ # Start auto-commit in background
296
+ if [[ -x "$SCRIPT_DIR/auto-commit.sh" ]]; then
297
+ "$SCRIPT_DIR/auto-commit.sh" start >> .jfl/logs/auto-commit.log 2>&1 &
298
+ echo -e "${GREEN}✓${NC} Auto-commit started"
299
+ fi
139
300
 
140
- # Start auto-commit in background
141
- if [[ -x "$SCRIPT_DIR/auto-commit.sh" ]]; then
142
- "$SCRIPT_DIR/auto-commit.sh" start >> .jfl/logs/auto-commit.log 2>&1 &
143
- echo -e "${GREEN}✓${NC} Auto-commit started"
301
+ cd "$REPO_DIR"
302
+
303
+ # Save paths
304
+ echo "$worktree_path" > "$REPO_DIR/.jfl/current-worktree.txt"
305
+ echo "$session_name" > "$REPO_DIR/.jfl/current-session-branch.txt"
306
+ echo "$session_name" > "$worktree_path/.jfl/current-session-branch.txt"
307
+
308
+ echo ""
309
+ echo -e "${GREEN}✓${NC} Session ready in worktree: $worktree_path"
310
+ echo ""
311
+ fi
144
312
  fi
145
313
 
146
- cd "$REPO_DIR"
314
+ if [[ "$use_worktree" != "true" ]]; then
315
+ # DIRECT MODE: Single session, work on current branch
316
+ echo ""
317
+ echo "Direct session mode: $session_name"
147
318
 
148
- # ==============================================================================
149
- # Step 4: Save state and output instructions
150
- # ==============================================================================
319
+ # Ensure we're on working branch
320
+ current_branch=$(git branch --show-current)
321
+ if [[ "$current_branch" != "$working_branch" ]]; then
322
+ echo "→ Switching to working branch: $working_branch"
323
+ git checkout "$working_branch" 2>&1 | head -3
324
+ fi
325
+
326
+ # Create session branch from working branch
327
+ if git checkout -b "$session_name" 2>&1 | head -3; then
328
+ echo -e "${GREEN}✓${NC} Session branch created: $session_name"
329
+ else
330
+ echo -e "${YELLOW}⚠${NC} Continuing on branch: $current_branch"
331
+ session_name="$current_branch"
332
+ fi
151
333
 
152
- # Save paths
153
- echo "$worktree_path" > "$REPO_DIR/.jfl/current-worktree.txt"
154
- echo "$session_name" > "$REPO_DIR/.jfl/current-session-branch.txt"
334
+ # Create session directories
335
+ mkdir -p .jfl/logs
155
336
 
156
- # Also save in worktree
157
- echo "$session_name" > "$worktree_path/.jfl/current-session-branch.txt"
337
+ # Start auto-commit in background
338
+ if [[ -x "$SCRIPT_DIR/auto-commit.sh" ]]; then
339
+ "$SCRIPT_DIR/auto-commit.sh" start >> .jfl/logs/auto-commit.log 2>&1 &
340
+ echo -e "${GREEN}✓${NC} Auto-commit started"
341
+ fi
158
342
 
159
- echo ""
160
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
161
- echo -e " ${CYAN}CLAUDE: You MUST run:${NC} cd $worktree_path"
162
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
163
- echo ""
343
+ # Save session info (no worktree path in direct mode)
344
+ echo "direct" > "$REPO_DIR/.jfl/current-worktree.txt"
345
+ echo "$session_name" > "$REPO_DIR/.jfl/current-session-branch.txt"
346
+
347
+ echo ""
348
+ echo -e "${GREEN}✓${NC} Session ready on branch: $session_name"
349
+ echo ""
350
+ fi