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,336 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Experience-Level Testing for Critical Infrastructure
4
+ #
5
+ # Tests ACTUAL USER WORKFLOWS, not just code paths.
6
+ # Simulates real scenarios that would cause work loss.
7
+ #
8
+ # @purpose Test critical infrastructure from user's perspective
9
+
10
+ set -e
11
+
12
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13
+ REPO_DIR="$(git rev-parse --path-format=absolute --git-common-dir 2>/dev/null || echo ".")"
14
+ REPO_DIR="${REPO_DIR%/.git}"
15
+
16
+ # Colors
17
+ RED='\033[0;31m'
18
+ GREEN='\033[0;32m'
19
+ YELLOW='\033[1;33m'
20
+ BLUE='\033[0;34m'
21
+ NC='\033[0m'
22
+
23
+ TESTS_PASSED=0
24
+ TESTS_FAILED=0
25
+
26
+ pass() {
27
+ echo -e "${GREEN}✓${NC} $1"
28
+ TESTS_PASSED=$((TESTS_PASSED + 1))
29
+ }
30
+
31
+ fail() {
32
+ echo -e "${RED}✗${NC} $1"
33
+ TESTS_FAILED=$((TESTS_FAILED + 1))
34
+ }
35
+
36
+ section() {
37
+ echo ""
38
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
39
+ echo -e "${BLUE}$1${NC}"
40
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
41
+ }
42
+
43
+ # ==============================================================================
44
+ # Experience Test 1: Ctrl+C During Auto-Commit
45
+ # ==============================================================================
46
+
47
+ test_ctrl_c_experience() {
48
+ section "Experience Test 1: Ctrl+C During Auto-Commit"
49
+
50
+ echo "Scenario: User presses Ctrl+C while auto-commit is running"
51
+ echo "Expected: Final commit happens, no work lost"
52
+ echo ""
53
+
54
+ # Check that signal handling is in place
55
+ if grep -q "trap graceful_shutdown SIGINT SIGTERM" "$SCRIPT_DIR/auto-commit.sh"; then
56
+ pass "Signal trap will catch Ctrl+C"
57
+ else
58
+ fail "No signal trap - Ctrl+C will lose work"
59
+ fi
60
+
61
+ # Check that graceful shutdown commits
62
+ if grep -A10 "graceful_shutdown()" "$SCRIPT_DIR/auto-commit.sh" | grep -q "do_commit"; then
63
+ pass "Graceful shutdown runs final commit"
64
+ else
65
+ fail "Graceful shutdown doesn't commit - work lost"
66
+ fi
67
+
68
+ # Check that it also commits submodules
69
+ if grep -A10 "graceful_shutdown()" "$SCRIPT_DIR/auto-commit.sh" | grep -q "commit_submodules"; then
70
+ pass "Graceful shutdown commits submodules too"
71
+ else
72
+ fail "Submodule changes lost on Ctrl+C"
73
+ fi
74
+
75
+ echo ""
76
+ echo "User Experience: Press Ctrl+C → See 'saving final changes' → Changes committed → Clean exit"
77
+ }
78
+
79
+ # ==============================================================================
80
+ # Experience Test 2: Crashed Session, Fresh Start
81
+ # ==============================================================================
82
+
83
+ test_crash_recovery_experience() {
84
+ section "Experience Test 2: Crashed Session Recovery"
85
+
86
+ echo "Scenario: Session crashed yesterday, user starts new session today"
87
+ echo "Expected: Prompted to save uncommitted work from crashed session"
88
+ echo ""
89
+
90
+ # Check that session-init scans for uncommitted work
91
+ if grep -q "Check for uncommitted work in stale sessions" "$SCRIPT_DIR/session-init.sh"; then
92
+ pass "Session start checks for abandoned work"
93
+ else
94
+ fail "No check for crashed session work - silently lost"
95
+ fi
96
+
97
+ # Check that user is prompted, not auto-committed silently
98
+ if grep -q "Options:" "$SCRIPT_DIR/session-init.sh" && grep -q "Choose \[1-3\]" "$SCRIPT_DIR/session-init.sh"; then
99
+ pass "User is prompted to review abandoned work"
100
+ else
101
+ fail "No user prompt - work handled without consent"
102
+ fi
103
+
104
+ # Check that auto-commit is an option
105
+ if grep -q "Auto-commit all and continue" "$SCRIPT_DIR/session-init.sh"; then
106
+ pass "User can auto-commit with one choice"
107
+ else
108
+ fail "No quick auto-commit option"
109
+ fi
110
+
111
+ echo ""
112
+ echo "User Experience: Start session → See 'Found 2 sessions with uncommitted work' → Choose option → Work saved → Continue"
113
+ }
114
+
115
+ # ==============================================================================
116
+ # Experience Test 3: Someone Else Pushed, I Start Session
117
+ # ==============================================================================
118
+
119
+ test_team_sync_experience() {
120
+ section "Experience Test 3: Team Member Pushed Changes"
121
+
122
+ echo "Scenario: Teammate pushed to main, I start a new session"
123
+ echo "Expected: My session starts with their latest changes"
124
+ echo ""
125
+
126
+ # Check that session-sync exists and is tracked
127
+ if git ls-files "$SCRIPT_DIR/session-sync.sh" >/dev/null 2>&1; then
128
+ pass "session-sync.sh is tracked in git (all worktrees get it)"
129
+ else
130
+ fail "session-sync.sh not tracked - worktrees won't have sync"
131
+ fi
132
+
133
+ # Check that it's called on session start
134
+ if grep -q "session-sync" "$SCRIPT_DIR/session-init.sh" 2>/dev/null || \
135
+ grep -q "session-sync" "$REPO_DIR/.claude/settings.json" 2>/dev/null; then
136
+ pass "Session start triggers sync"
137
+ else
138
+ fail "Sync not triggered on session start"
139
+ fi
140
+
141
+ # Check that sync pulls main
142
+ if grep -q "git pull origin" "$SCRIPT_DIR/session-sync.sh" 2>/dev/null; then
143
+ pass "Sync pulls latest from origin"
144
+ else
145
+ fail "Sync doesn't pull - user starts with stale code"
146
+ fi
147
+
148
+ echo ""
149
+ echo "User Experience: Start session → Syncing repos → Up to date → See teammate's changes → Continue"
150
+ }
151
+
152
+ # ==============================================================================
153
+ # Experience Test 4: I Have Unmerged Work, Someone Runs Doctor
154
+ # ==============================================================================
155
+
156
+ test_unmerged_work_safety() {
157
+ section "Experience Test 4: Protecting Unmerged Work"
158
+
159
+ echo "Scenario: My branch has 4 commits, teammate runs 'doctor --fix'"
160
+ echo "Expected: My work is NOT deleted"
161
+ echo ""
162
+
163
+ # Check that doctor separates merged vs unmerged
164
+ if grep -q "⚠️ UNMERGED (do NOT delete)" "$SCRIPT_DIR/jfl-doctor.sh"; then
165
+ pass "Doctor clearly labels unmerged branches"
166
+ else
167
+ fail "Doctor doesn't distinguish merged vs unmerged"
168
+ fi
169
+
170
+ # Check that --fix never deletes unmerged (check code, not output)
171
+ # The key is: only $merged_list is deleted, never $unmerged_list
172
+ if grep -A20 "if \[\[ \$unmerged_orphans -gt 0 \]\]" "$SCRIPT_DIR/jfl-doctor.sh" | \
173
+ grep -q "UNMERGED.*do NOT delete"; then
174
+ pass "--fix mode labels unmerged branches correctly"
175
+ else
176
+ fail "DANGER: --fix might delete unmerged work"
177
+ fi
178
+
179
+ # Check that only merged branches are deleted
180
+ if grep -B5 "git branch -D" "$SCRIPT_DIR/jfl-doctor.sh" | grep -q "merged_orphans -gt 0"; then
181
+ pass "Only deletes branches that are fully merged"
182
+ else
183
+ fail "Deletion logic might be unsafe"
184
+ fi
185
+
186
+ echo ""
187
+ echo "User Experience: Teammate runs doctor --fix → My unmerged branch preserved → I can continue work"
188
+ }
189
+
190
+ # ==============================================================================
191
+ # Experience Test 5: Network Fails During Sync
192
+ # ==============================================================================
193
+
194
+ test_network_failure_graceful() {
195
+ section "Experience Test 5: Network Failure Handling"
196
+
197
+ echo "Scenario: Network goes down during session sync"
198
+ echo "Expected: Graceful warning, session continues with local state"
199
+ echo ""
200
+
201
+ # Check for network error handling
202
+ if grep -q "Could not fetch.*no network" "$SCRIPT_DIR/session-sync.sh" 2>/dev/null; then
203
+ pass "Network failures handled gracefully"
204
+ else
205
+ fail "Network failure might crash session"
206
+ fi
207
+
208
+ # Check that sync doesn't block on network failure
209
+ if grep -A5 "git fetch origin" "$SCRIPT_DIR/session-sync.sh" 2>/dev/null | grep -q "|| {"; then
210
+ pass "Fetch failures don't block session"
211
+ else
212
+ fail "Session might hang on network failure"
213
+ fi
214
+
215
+ # Check that user is warned but can continue
216
+ if grep -q "WARNING.*network" "$SCRIPT_DIR/session-sync.sh" 2>/dev/null; then
217
+ pass "User warned about network issues"
218
+ else
219
+ fail "Silent network failure - user confused"
220
+ fi
221
+
222
+ echo ""
223
+ echo "User Experience: Start session → 'WARNING: Could not fetch (no network?)' → Continue working offline"
224
+ }
225
+
226
+ # ==============================================================================
227
+ # Experience Test 6: Uncommitted Changes + Behind Origin
228
+ # ==============================================================================
229
+
230
+ test_uncommitted_and_behind() {
231
+ section "Experience Test 6: Uncommitted Changes + Behind Origin"
232
+
233
+ echo "Scenario: I have uncommitted work, main is behind origin"
234
+ echo "Expected: Sync refuses to pull, warns me, preserves my work"
235
+ echo ""
236
+
237
+ # Check for uncommitted + behind detection
238
+ if grep -q "has uncommitted changes AND is behind" "$SCRIPT_DIR/session-sync.sh" 2>/dev/null; then
239
+ pass "Detects dangerous situation (uncommitted + behind)"
240
+ else
241
+ fail "Doesn't detect uncommitted + behind - might lose work"
242
+ fi
243
+
244
+ # Check that it exits with error
245
+ if grep -A5 "uncommitted changes AND is behind" "$SCRIPT_DIR/session-sync.sh" 2>/dev/null | grep -q "exit 1\|FAILURES="; then
246
+ pass "Blocks sync to prevent data loss"
247
+ else
248
+ fail "Doesn't block sync - work could be lost"
249
+ fi
250
+
251
+ # Check that it tells user what to do
252
+ if grep -A5 "uncommitted changes AND is behind" "$SCRIPT_DIR/session-sync.sh" 2>/dev/null | grep -q "commit or stash"; then
253
+ pass "Guides user to resolve safely"
254
+ else
255
+ fail "No guidance - user stuck"
256
+ fi
257
+
258
+ echo ""
259
+ echo "User Experience: Start session → 'ERROR: uncommitted changes AND behind' → Commit first → Retry → Success"
260
+ }
261
+
262
+ # ==============================================================================
263
+ # CI/CD Integration Check
264
+ # ==============================================================================
265
+
266
+ test_ci_integration() {
267
+ section "CI/CD Integration"
268
+
269
+ echo "Checking if tests are integrated into CI/CD pipeline"
270
+ echo ""
271
+
272
+ # Check for GitHub Actions workflow
273
+ if [[ -f "$REPO_DIR/.github/workflows/test-critical-infrastructure.yml" ]]; then
274
+ pass "GitHub Actions workflow exists for tests"
275
+ else
276
+ echo -e "${YELLOW}⚠${NC} No GitHub Actions workflow (recommended)"
277
+ echo " Create .github/workflows/test-critical-infrastructure.yml"
278
+ fi
279
+
280
+ # Check for pre-commit hook
281
+ if [[ -f "$REPO_DIR/.git/hooks/pre-commit" ]] || \
282
+ [[ -f "$REPO_DIR/.husky/pre-commit" ]]; then
283
+ pass "Pre-commit hook exists"
284
+ else
285
+ echo -e "${YELLOW}⚠${NC} No pre-commit hook (recommended)"
286
+ echo " Run tests before commit to catch issues early"
287
+ fi
288
+ }
289
+
290
+ # ==============================================================================
291
+ # Run All Experience Tests
292
+ # ==============================================================================
293
+
294
+ main() {
295
+ echo ""
296
+ echo "╔══════════════════════════════════════════════════════════╗"
297
+ echo "║ Experience-Level Testing ║"
298
+ echo "║ Testing Actual User Workflows ║"
299
+ echo "╚══════════════════════════════════════════════════════════╝"
300
+
301
+ test_ctrl_c_experience
302
+ test_crash_recovery_experience
303
+ test_team_sync_experience
304
+ test_unmerged_work_safety
305
+ test_network_failure_graceful
306
+ test_uncommitted_and_behind
307
+ test_ci_integration
308
+
309
+ # Summary
310
+ echo ""
311
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
312
+ echo -e "${BLUE}Test Results${NC}"
313
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
314
+ echo -e "${GREEN}Passed:${NC} $TESTS_PASSED"
315
+ if [[ $TESTS_FAILED -gt 0 ]]; then
316
+ echo -e "${RED}Failed:${NC} $TESTS_FAILED"
317
+ echo ""
318
+ echo -e "${RED}EXPERIENCE-LEVEL ISSUES FOUND${NC}"
319
+ echo "Fix these before releasing to users"
320
+ exit 1
321
+ else
322
+ echo ""
323
+ echo -e "${GREEN}✓ All user experience paths protected${NC}"
324
+ echo ""
325
+ echo "Verified workflows:"
326
+ echo " • Ctrl+C doesn't lose work"
327
+ echo " • Crashed sessions recovered"
328
+ echo " • Team changes synced automatically"
329
+ echo " • Unmerged work never deleted"
330
+ echo " • Network failures handled gracefully"
331
+ echo " • Uncommitted + behind detected safely"
332
+ exit 0
333
+ fi
334
+ }
335
+
336
+ main "$@"
@@ -0,0 +1,268 @@
1
+ #!/bin/bash
2
+ #
3
+ # Test Suite: Session Cleanup
4
+ #
5
+ # Tests session-cleanup.sh against critical safety requirements:
6
+ # - NEVER loses uncommitted work
7
+ # - NEVER loses conflicting changes
8
+ # - ONLY auto-merges safe commits (auto-saves, journal entries)
9
+ # - ALWAYS preserves journal entries
10
+ # - Properly removes worktrees after successful merge
11
+ # - Handles all exit scenarios (normal, Ctrl+C, crash, kill)
12
+
13
+ set -e
14
+
15
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16
+ REPO_DIR="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
17
+
18
+ # Colors
19
+ RED='\033[0;31m'
20
+ GREEN='\033[0;32m'
21
+ YELLOW='\033[1;33m'
22
+ NC='\033[0m' # No Color
23
+
24
+ TESTS_RUN=0
25
+ TESTS_PASSED=0
26
+ TESTS_FAILED=0
27
+
28
+ print_test() {
29
+ echo ""
30
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
31
+ echo "TEST: $1"
32
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
33
+ }
34
+
35
+ pass() {
36
+ echo -e "${GREEN}✓ PASS${NC}: $1"
37
+ TESTS_PASSED=$((TESTS_PASSED + 1))
38
+ TESTS_RUN=$((TESTS_RUN + 1))
39
+ }
40
+
41
+ fail() {
42
+ echo -e "${RED}✗ FAIL${NC}: $1"
43
+ TESTS_FAILED=$((TESTS_FAILED + 1))
44
+ TESTS_RUN=$((TESTS_RUN + 1))
45
+ }
46
+
47
+ anti_test() {
48
+ echo -e "${YELLOW}⚠ ANTI-TEST${NC}: $1 (should NOT happen)"
49
+ }
50
+
51
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
52
+ # Safety Tests - CRITICAL: Must never lose work
53
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
54
+
55
+ print_test "SAFETY: Cleanup script exists and is executable"
56
+ if [[ -f "$SCRIPT_DIR/session-cleanup.sh" ]]; then
57
+ pass "session-cleanup.sh exists"
58
+ else
59
+ fail "session-cleanup.sh not found"
60
+ fi
61
+
62
+ if [[ -x "$SCRIPT_DIR/session-cleanup.sh" ]]; then
63
+ pass "session-cleanup.sh is executable"
64
+ else
65
+ fail "session-cleanup.sh not executable"
66
+ fi
67
+
68
+ print_test "SAFETY: Script has auto-commit before merge"
69
+ if grep -q "git add -A" "$SCRIPT_DIR/session-cleanup.sh" && \
70
+ grep -q "git commit" "$SCRIPT_DIR/session-cleanup.sh"; then
71
+ pass "Auto-commits before attempting merge"
72
+ else
73
+ fail "Missing auto-commit before merge - WILL LOSE WORK"
74
+ fi
75
+
76
+ print_test "SAFETY: Script checks if on session branch"
77
+ if grep -q 'if.*session-' "$SCRIPT_DIR/session-cleanup.sh"; then
78
+ pass "Checks for session branch before cleanup"
79
+ else
80
+ fail "Doesn't check branch type - might cleanup non-session branches"
81
+ fi
82
+
83
+ print_test "SAFETY: Script aborts merge on conflicts"
84
+ if grep -q "git merge --abort" "$SCRIPT_DIR/session-cleanup.sh"; then
85
+ pass "Aborts merge on conflicts (preserves work)"
86
+ else
87
+ fail "Doesn't abort on conflicts - WILL LOSE CONFLICTING CHANGES"
88
+ fi
89
+
90
+ print_test "SAFETY: Script uses auto-resolve strategy for .jfl/ conflicts"
91
+ if grep -q -- "-X ours" "$SCRIPT_DIR/session-cleanup.sh"; then
92
+ pass "Uses -X ours for auto-resolving .jfl/ conflicts"
93
+ else
94
+ fail "Missing conflict resolution strategy - merges will fail unnecessarily"
95
+ fi
96
+
97
+ print_test "ANTI-TEST: Script doesn't use --force flags"
98
+ anti_test "git push --force"
99
+ if grep -q "push.*--force" "$SCRIPT_DIR/session-cleanup.sh"; then
100
+ fail "Uses --force push - DANGEROUS"
101
+ else
102
+ pass "No --force push (safe)"
103
+ fi
104
+
105
+ anti_test "git clean -f"
106
+ if grep -q "git clean" "$SCRIPT_DIR/session-cleanup.sh"; then
107
+ fail "Uses git clean - WILL LOSE UNTRACKED FILES"
108
+ else
109
+ pass "No git clean (safe)"
110
+ fi
111
+
112
+ anti_test "git reset --hard"
113
+ if grep -q "reset.*--hard" "$SCRIPT_DIR/session-cleanup.sh"; then
114
+ fail "Uses reset --hard - WILL LOSE UNCOMMITTED WORK"
115
+ else
116
+ pass "No reset --hard (safe)"
117
+ fi
118
+
119
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
120
+ # Integration Tests - Works with existing infrastructure
121
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
122
+
123
+ print_test "INTEGRATION: Stop hook calls session-cleanup.sh"
124
+ SETTINGS_FILE="$REPO_DIR/.claude/settings.json"
125
+ if [[ -f "$SETTINGS_FILE" ]]; then
126
+ if grep -q "session-cleanup.sh" "$SETTINGS_FILE"; then
127
+ pass "Stop hook configured to run cleanup"
128
+ else
129
+ fail "Stop hook doesn't call session-cleanup.sh"
130
+ fi
131
+ else
132
+ fail ".claude/settings.json not found"
133
+ fi
134
+
135
+ print_test "INTEGRATION: Signal handler calls session-cleanup.sh"
136
+ AUTO_COMMIT_SCRIPT="$SCRIPT_DIR/auto-commit.sh"
137
+ if [[ -f "$AUTO_COMMIT_SCRIPT" ]]; then
138
+ if grep -A 10 "graceful_shutdown" "$AUTO_COMMIT_SCRIPT" | grep -q "session-cleanup.sh"; then
139
+ pass "Signal handler calls cleanup on Ctrl+C/kill"
140
+ else
141
+ fail "Signal handler doesn't call session-cleanup.sh - branches pile up on Ctrl+C"
142
+ fi
143
+ else
144
+ fail "auto-commit.sh not found"
145
+ fi
146
+
147
+ print_test "INTEGRATION: Signal traps are set"
148
+ if grep -q "trap.*graceful_shutdown.*SIGINT.*SIGTERM" "$AUTO_COMMIT_SCRIPT"; then
149
+ pass "Signal traps set for SIGINT and SIGTERM"
150
+ else
151
+ fail "Missing signal traps - Ctrl+C won't trigger cleanup"
152
+ fi
153
+
154
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
155
+ # Functional Tests - Script behavior
156
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
157
+
158
+ print_test "FUNCTIONAL: Script skips cleanup on non-session branches"
159
+ CLEANUP_OUTPUT=$("$SCRIPT_DIR/session-cleanup.sh" 2>&1 || true)
160
+ CURRENT_BRANCH=$(git branch --show-current)
161
+
162
+ if [[ ! "$CURRENT_BRANCH" =~ ^session- ]]; then
163
+ if echo "$CLEANUP_OUTPUT" | grep -q "Not a session branch"; then
164
+ pass "Skips cleanup on non-session branch (main)"
165
+ else
166
+ fail "Doesn't skip non-session branches - might cleanup main!"
167
+ fi
168
+ else
169
+ pass "Currently on session branch, skipping non-session test"
170
+ fi
171
+
172
+ print_test "FUNCTIONAL: Script switches to main before merge"
173
+ if grep -q "git checkout main" "$SCRIPT_DIR/session-cleanup.sh"; then
174
+ pass "Switches to main before merging"
175
+ else
176
+ fail "Doesn't checkout main - merge will fail"
177
+ fi
178
+
179
+ print_test "FUNCTIONAL: Script removes worktree after successful merge"
180
+ if grep -q "git worktree.*remove" "$SCRIPT_DIR/session-cleanup.sh" || \
181
+ grep -q "rm -rf.*WORKTREE" "$SCRIPT_DIR/session-cleanup.sh"; then
182
+ pass "Removes worktree after merge"
183
+ else
184
+ fail "Doesn't remove worktree - will pile up disk usage"
185
+ fi
186
+
187
+ print_test "FUNCTIONAL: Script deletes branch after successful merge"
188
+ if grep -q "git branch -D" "$SCRIPT_DIR/session-cleanup.sh"; then
189
+ pass "Deletes branch after successful merge"
190
+ else
191
+ fail "Doesn't delete branch - will pile up branches"
192
+ fi
193
+
194
+ print_test "FUNCTIONAL: Script handles missing worktree gracefully"
195
+ if grep -q "\[ -n.*WORKTREE" "$SCRIPT_DIR/session-cleanup.sh" || \
196
+ grep -q "\[ -d.*WORKTREE" "$SCRIPT_DIR/session-cleanup.sh"; then
197
+ pass "Checks if worktree exists before removing"
198
+ else
199
+ fail "Doesn't check worktree existence - might error on missing worktree"
200
+ fi
201
+
202
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
203
+ # Edge Cases
204
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
205
+
206
+ print_test "EDGE CASE: Script handles 'not on a branch' scenario"
207
+ if grep -q 'if \[ -z.*BRANCH' "$SCRIPT_DIR/session-cleanup.sh"; then
208
+ pass "Checks if on a branch (handles detached HEAD)"
209
+ else
210
+ fail "Doesn't check for detached HEAD - will fail in that state"
211
+ fi
212
+
213
+ print_test "EDGE CASE: Script exits cleanly on all paths"
214
+ if tail -5 "$SCRIPT_DIR/session-cleanup.sh" | grep -q "exit 0"; then
215
+ pass "Script exits cleanly (exit 0)"
216
+ else
217
+ fail "Script might exit with error code - will break hooks"
218
+ fi
219
+
220
+ print_test "EDGE CASE: Script doesn't fail entire hook chain"
221
+ # Check that cleanup is called with || true in hooks
222
+ if grep -q "session-cleanup.sh.*||" "$SETTINGS_FILE" 2>/dev/null; then
223
+ pass "Cleanup failure doesn't break hook chain"
224
+ else
225
+ fail "Cleanup failure could break Stop hook - session won't end"
226
+ fi
227
+
228
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
229
+ # Performance Tests
230
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
231
+
232
+ print_test "PERFORMANCE: Cleanup redirects to log file"
233
+ if grep -q "session-cleanup.sh.*>>" "$SETTINGS_FILE" 2>/dev/null; then
234
+ pass "Cleanup output goes to log file (doesn't spam user)"
235
+ else
236
+ fail "Cleanup output not redirected - will spam terminal"
237
+ fi
238
+
239
+ print_test "PERFORMANCE: Cleanup runs in background/async"
240
+ if grep -q "session-cleanup.sh.*2>&1" "$SETTINGS_FILE" 2>/dev/null; then
241
+ pass "Cleanup stderr redirected (clean output)"
242
+ else
243
+ fail "Cleanup stderr not redirected - errors spam terminal"
244
+ fi
245
+
246
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
247
+ # Summary
248
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
249
+
250
+ echo ""
251
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
252
+ echo "TEST SUMMARY"
253
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
254
+ echo "Total tests: $TESTS_RUN"
255
+ echo -e "${GREEN}Passed:${NC} $TESTS_PASSED"
256
+ echo -e "${RED}Failed:${NC} $TESTS_FAILED"
257
+
258
+ if [ $TESTS_FAILED -eq 0 ]; then
259
+ echo ""
260
+ echo -e "${GREEN}✓ All tests passed!${NC}"
261
+ echo "Session cleanup is safe and ready for production."
262
+ exit 0
263
+ else
264
+ echo ""
265
+ echo -e "${RED}✗ $TESTS_FAILED test(s) failed!${NC}"
266
+ echo "Fix failing tests before deploying to ensure work is never lost."
267
+ exit 1
268
+ fi