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,350 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # session-init.sh - Initialize a JFL session properly
4
+ #
5
+ # Called by SessionStart hook. Does:
6
+ # 1. Quick doctor check (warn only, don't block)
7
+ # 2. Clean up stale sessions if > 5
8
+ # 3. Create new worktree for this session
9
+ # 4. Output path for Claude to cd into
10
+ #
11
+ # @purpose Session initialization with worktree creation
12
+
13
+ set -e
14
+
15
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16
+ REPO_DIR="${JFL_REPO_DIR:-$(pwd)}"
17
+ WORKTREES_DIR="$REPO_DIR/worktrees"
18
+
19
+ cd "$REPO_DIR" || exit 1
20
+
21
+ # Colors
22
+ RED='\033[0;31m'
23
+ GREEN='\033[0;32m'
24
+ YELLOW='\033[1;33m'
25
+ CYAN='\033[0;36m'
26
+ NC='\033[0m'
27
+
28
+ # ==============================================================================
29
+ # Step 0: Sync repos to latest (prevent context loss)
30
+ # ==============================================================================
31
+
32
+ echo ""
33
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
34
+ echo " JFL Session Init"
35
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
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
+
49
+ # Count stale sessions (no PID or PID not running)
50
+ stale_count=0
51
+ active_count=0
52
+
53
+ if [[ -d "$WORKTREES_DIR" ]]; then
54
+ for worktree in "$WORKTREES_DIR"/session-*; do
55
+ if [[ -d "$worktree" ]]; then
56
+ pid_file="$worktree/.jfl/auto-commit.pid"
57
+ if [[ -f "$pid_file" ]]; then
58
+ pid=$(cat "$pid_file" 2>/dev/null)
59
+ if [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null; then
60
+ active_count=$((active_count + 1))
61
+ continue
62
+ fi
63
+ fi
64
+ stale_count=$((stale_count + 1))
65
+ fi
66
+ done
67
+ fi
68
+
69
+ # Report status
70
+ if [[ $stale_count -gt 0 ]]; then
71
+ echo -e "${YELLOW}⚠${NC} $stale_count stale sessions, $active_count active"
72
+ else
73
+ echo -e "${GREEN}✓${NC} $active_count active sessions"
74
+ fi
75
+
76
+ # ==============================================================================
77
+ # Step 2: Auto-cleanup if too many stale sessions
78
+ # ==============================================================================
79
+
80
+ if [[ $stale_count -gt 5 ]]; then
81
+ echo -e "${YELLOW}→${NC} Cleaning up stale sessions (> 5)..."
82
+ "$SCRIPT_DIR/jfl-doctor.sh" --fix 2>/dev/null | grep -E "^ (Cleaning|✓)" || true
83
+ fi
84
+
85
+ # ==============================================================================
86
+ # Step 2.5: Crash Reconciliation - Check for uncommitted work in stale sessions
87
+ # ==============================================================================
88
+
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
207
+ user=$(git config user.name 2>/dev/null | tr ' ' '-' | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9-' || echo "user")
208
+ user="${user:0:30}"
209
+ date_str=$(date +%Y%m%d)
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 "")
225
+
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
235
+ else
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
243
+ fi
244
+ else
245
+ # No curl - assume single session
246
+ echo -e "${GREEN}→${NC} Working directly on branch $working_branch"
247
+ fi
248
+
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
255
+ fi
256
+
257
+ # ==============================================================================
258
+ # Step 3: Create worktree (if needed) or work directly
259
+ # ==============================================================================
260
+
261
+ if [[ "$use_worktree" == "true" ]]; then
262
+ # WORKTREE MODE: Multiple sessions detected
263
+ echo ""
264
+ echo "Creating worktree session: $session_name"
265
+
266
+ worktree_path="$WORKTREES_DIR/$session_name"
267
+
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
275
+ fi
276
+
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
289
+
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
300
+
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
312
+ fi
313
+
314
+ if [[ "$use_worktree" != "true" ]]; then
315
+ # DIRECT MODE: Single session, work on current branch
316
+ echo ""
317
+ echo "Direct session mode: $session_name"
318
+
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
333
+
334
+ # Create session directories
335
+ mkdir -p .jfl/logs
336
+
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
342
+
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
@@ -0,0 +1,292 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # session-init.sh - Initialize a JFL session properly
4
+ #
5
+ # Called by SessionStart hook. Does:
6
+ # 1. Quick doctor check (warn only, don't block)
7
+ # 2. Clean up stale sessions if > 5
8
+ # 3. Create new worktree for this session
9
+ # 4. Output path for Claude to cd into
10
+ #
11
+ # @purpose Session initialization with worktree creation
12
+
13
+ set -e
14
+
15
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16
+ REPO_DIR="${JFL_REPO_DIR:-$(pwd)}"
17
+ WORKTREES_DIR="$REPO_DIR/worktrees"
18
+
19
+ cd "$REPO_DIR" || exit 1
20
+
21
+ # Colors
22
+ RED='\033[0;31m'
23
+ GREEN='\033[0;32m'
24
+ YELLOW='\033[1;33m'
25
+ CYAN='\033[0;36m'
26
+ NC='\033[0m'
27
+
28
+ # ==============================================================================
29
+ # Step 0: Sync repos to latest (prevent context loss)
30
+ # ==============================================================================
31
+
32
+ echo ""
33
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
34
+ echo " JFL Session Init"
35
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
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
+
49
+ # Count stale sessions (no PID or PID not running)
50
+ stale_count=0
51
+ active_count=0
52
+
53
+ if [[ -d "$WORKTREES_DIR" ]]; then
54
+ for worktree in "$WORKTREES_DIR"/session-*; do
55
+ if [[ -d "$worktree" ]]; then
56
+ pid_file="$worktree/.jfl/auto-commit.pid"
57
+ if [[ -f "$pid_file" ]]; then
58
+ pid=$(cat "$pid_file" 2>/dev/null)
59
+ if [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null; then
60
+ active_count=$((active_count + 1))
61
+ continue
62
+ fi
63
+ fi
64
+ stale_count=$((stale_count + 1))
65
+ fi
66
+ done
67
+ fi
68
+
69
+ # Report status
70
+ if [[ $stale_count -gt 0 ]]; then
71
+ echo -e "${YELLOW}⚠${NC} $stale_count stale sessions, $active_count active"
72
+ else
73
+ echo -e "${GREEN}✓${NC} $active_count active sessions"
74
+ fi
75
+
76
+ # ==============================================================================
77
+ # Step 2: Auto-cleanup if too many stale sessions
78
+ # ==============================================================================
79
+
80
+ if [[ $stale_count -gt 5 ]]; then
81
+ echo -e "${YELLOW}→${NC} Cleaning up stale sessions (> 5)..."
82
+ "$SCRIPT_DIR/jfl-doctor.sh" --fix 2>/dev/null | grep -E "^ (Cleaning|✓)" || true
83
+ fi
84
+
85
+ # ==============================================================================
86
+ # Step 2.5: Crash Reconciliation - Check for uncommitted work in stale sessions
87
+ # ==============================================================================
88
+
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 3: Create new worktree
204
+ # ==============================================================================
205
+
206
+ # Generate session name with collision protection
207
+ user=$(git config user.name 2>/dev/null | tr ' ' '-' | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9-' || echo "user")
208
+ # Truncate long usernames to prevent path issues
209
+ user="${user:0:30}"
210
+ date_str=$(date +%Y%m%d)
211
+ time_str=$(date +%H%M)
212
+
213
+ # Generate unique session name, retry if collision detected
214
+ max_attempts=5
215
+ attempt=0
216
+ while [[ $attempt -lt $max_attempts ]]; do
217
+ random_id=$(openssl rand -hex 3 2>/dev/null || printf "%06x" $RANDOM$RANDOM)
218
+ session_name="session-${user}-${date_str}-${time_str}-${random_id}"
219
+
220
+ # Check for collision: journal file or worktree already exists
221
+ if [[ -f "$REPO_DIR/.jfl/journal/${session_name}.jsonl" ]] || [[ -d "$WORKTREES_DIR/$session_name" ]]; then
222
+ echo -e "${YELLOW}⚠${NC} Session name collision, regenerating..."
223
+ attempt=$((attempt + 1))
224
+ sleep 0.1 # Brief pause before retry
225
+ else
226
+ break
227
+ fi
228
+ done
229
+
230
+ if [[ $attempt -ge $max_attempts ]]; then
231
+ echo -e "${RED}✗${NC} Failed to generate unique session name after $max_attempts attempts"
232
+ exit 1
233
+ fi
234
+
235
+ worktree_path="$WORKTREES_DIR/$session_name"
236
+
237
+ echo ""
238
+ echo "Creating session: $session_name"
239
+
240
+ # Create worktree
241
+ if git worktree add "$worktree_path" -b "$session_name" 2>&1 | head -3; then
242
+ echo -e "${GREEN}✓${NC} Worktree created"
243
+ else
244
+ echo -e "${RED}✗${NC} Failed to create worktree"
245
+ # Fall back to main branch
246
+ echo "main" > "$REPO_DIR/.jfl/current-worktree.txt"
247
+ echo "main" > "$REPO_DIR/.jfl/current-session-branch.txt"
248
+ exit 0
249
+ fi
250
+
251
+ # Initialize submodules in worktree (quick, no network)
252
+ cd "$worktree_path"
253
+ if [[ -f ".gitmodules" ]]; then
254
+ if [[ ! -d "product/.git" ]] && [[ ! -f "product/.git" ]]; then
255
+ echo "→ Initializing submodules..."
256
+ git submodule update --init --depth 1 product 2>/dev/null || true
257
+ fi
258
+ fi
259
+
260
+ # Create session directories
261
+ mkdir -p .jfl/logs
262
+
263
+ # CRITICAL: Symlink journal to main repo so entries persist after worktree cleanup
264
+ # Without this, journal entries written in worktree are lost when worktree is removed!
265
+ rm -rf .jfl/journal 2>/dev/null || true
266
+ ln -sf "$REPO_DIR/.jfl/journal" .jfl/journal
267
+ echo -e "${GREEN}✓${NC} Journal symlinked to main repo"
268
+
269
+ # Start auto-commit in background
270
+ if [[ -x "$SCRIPT_DIR/auto-commit.sh" ]]; then
271
+ "$SCRIPT_DIR/auto-commit.sh" start >> .jfl/logs/auto-commit.log 2>&1 &
272
+ echo -e "${GREEN}✓${NC} Auto-commit started"
273
+ fi
274
+
275
+ cd "$REPO_DIR"
276
+
277
+ # ==============================================================================
278
+ # Step 4: Save state and output instructions
279
+ # ==============================================================================
280
+
281
+ # Save paths
282
+ echo "$worktree_path" > "$REPO_DIR/.jfl/current-worktree.txt"
283
+ echo "$session_name" > "$REPO_DIR/.jfl/current-session-branch.txt"
284
+
285
+ # Also save in worktree
286
+ echo "$session_name" > "$worktree_path/.jfl/current-session-branch.txt"
287
+
288
+ echo ""
289
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
290
+ echo -e " ${CYAN}CLAUDE: You MUST run:${NC} cd $worktree_path"
291
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
292
+ echo ""