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
+ # 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
@@ -0,0 +1,320 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Rigorous tests for session-sync.sh
4
+ # Tests both positive cases AND anti-tests (what should NOT happen)
5
+ #
6
+ # @purpose Test session-sync.sh before committing (work-loss prevention)
7
+
8
+ set -e
9
+
10
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
+ TEST_DIR="/tmp/jfl-session-sync-test-$$"
12
+ REPO_DIR="$(git rev-parse --path-format=absolute --git-common-dir 2>/dev/null || echo ".")"
13
+ REPO_DIR="${REPO_DIR%/.git}"
14
+
15
+ # Colors
16
+ RED='\033[0;31m'
17
+ GREEN='\033[0;32m'
18
+ YELLOW='\033[1;33m'
19
+ BLUE='\033[0;34m'
20
+ NC='\033[0m'
21
+
22
+ TESTS_PASSED=0
23
+ TESTS_FAILED=0
24
+
25
+ pass() {
26
+ echo -e "${GREEN}✓${NC} $1"
27
+ TESTS_PASSED=$((TESTS_PASSED + 1))
28
+ }
29
+
30
+ fail() {
31
+ echo -e "${RED}✗${NC} $1"
32
+ TESTS_FAILED=$((TESTS_FAILED + 1))
33
+ }
34
+
35
+ section() {
36
+ echo ""
37
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
38
+ echo -e "${BLUE}$1${NC}"
39
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
40
+ }
41
+
42
+ cleanup() {
43
+ rm -rf "$TEST_DIR" 2>/dev/null || true
44
+ }
45
+
46
+ trap cleanup EXIT
47
+
48
+ # ==============================================================================
49
+ # Test 1: Script Safety Checks
50
+ # ==============================================================================
51
+
52
+ test_safety_checks() {
53
+ section "Test 1: Safety Checks (prevent data loss)"
54
+
55
+ # Check for uncommitted changes protection
56
+ if grep -q "has uncommitted changes AND is behind" "$SCRIPT_DIR/session-sync.sh"; then
57
+ pass "Protects against pulling over uncommitted changes"
58
+ else
59
+ fail "No protection for uncommitted changes + pull"
60
+ fi
61
+
62
+ # Check that it uses 'set -e' for failure propagation
63
+ if head -10 "$SCRIPT_DIR/session-sync.sh" | grep -q "set -e"; then
64
+ pass "Uses 'set -e' for error propagation"
65
+ else
66
+ fail "Doesn't use 'set -e' - errors may be silent"
67
+ fi
68
+
69
+ # Check that it exits with error code on failure
70
+ if grep -q "exit 1" "$SCRIPT_DIR/session-sync.sh"; then
71
+ pass "Exits with error code on failure"
72
+ else
73
+ fail "Doesn't exit with error - CI/CD won't catch failures"
74
+ fi
75
+
76
+ # Anti-test: Verify it doesn't use --force flags
77
+ if grep -E "git pull.*--force|git reset --hard" "$SCRIPT_DIR/session-sync.sh" >/dev/null; then
78
+ fail "DANGER: Uses destructive git commands (--force, --hard)"
79
+ else
80
+ pass "Doesn't use destructive git commands"
81
+ fi
82
+
83
+ # Check for graceful network failure handling
84
+ if grep -q "Could not fetch.*no network" "$SCRIPT_DIR/session-sync.sh"; then
85
+ pass "Handles network failures gracefully"
86
+ else
87
+ fail "No graceful handling of network failures"
88
+ fi
89
+ }
90
+
91
+ # ==============================================================================
92
+ # Test 2: Detached HEAD Handling
93
+ # ==============================================================================
94
+
95
+ test_detached_head() {
96
+ section "Test 2: Detached HEAD Handling (submodules)"
97
+
98
+ # Check if script detects detached HEAD
99
+ if grep -q "detached HEAD state" "$SCRIPT_DIR/session-sync.sh"; then
100
+ pass "Detects detached HEAD state"
101
+ else
102
+ fail "Doesn't detect detached HEAD"
103
+ fi
104
+
105
+ # Check if it attempts to fix detached HEAD
106
+ if grep -A5 "detached HEAD" "$SCRIPT_DIR/session-sync.sh" | grep -q "checkout main"; then
107
+ pass "Attempts to fix detached HEAD automatically"
108
+ else
109
+ fail "Doesn't auto-fix detached HEAD"
110
+ fi
111
+
112
+ # Anti-test: Verify it doesn't force checkout (would lose work)
113
+ if grep -E "git checkout.*-f|git checkout.*--force" "$SCRIPT_DIR/session-sync.sh" >/dev/null; then
114
+ fail "DANGER: Uses force checkout (loses uncommitted work)"
115
+ else
116
+ pass "Doesn't use force checkout"
117
+ fi
118
+ }
119
+
120
+ # ==============================================================================
121
+ # Test 3: Submodule vs Symlink Detection
122
+ # ==============================================================================
123
+
124
+ test_product_detection() {
125
+ section "Test 3: Product Detection (submodule vs symlink)"
126
+
127
+ # Check for submodule detection (has .git FILE)
128
+ if grep -q "It's a submodule" "$SCRIPT_DIR/session-sync.sh"; then
129
+ pass "Detects submodules correctly (.git as file)"
130
+ else
131
+ fail "Doesn't detect submodules"
132
+ fi
133
+
134
+ # Check for symlink detection
135
+ if grep -q "\[ -L \"\$PRODUCT_PATH\" \]" "$SCRIPT_DIR/session-sync.sh"; then
136
+ pass "Detects symlinks correctly"
137
+ else
138
+ fail "Doesn't detect symlinks"
139
+ fi
140
+
141
+ # Check for missing product handling
142
+ if grep -q "Initializing product submodule" "$SCRIPT_DIR/session-sync.sh"; then
143
+ pass "Handles missing product gracefully"
144
+ else
145
+ fail "Doesn't handle missing product"
146
+ fi
147
+
148
+ # Check for symlink deprecation warning
149
+ if grep -q "product/ is a symlink, not a submodule" "$SCRIPT_DIR/session-sync.sh"; then
150
+ pass "Warns about legacy symlink usage"
151
+ else
152
+ fail "Doesn't warn about symlinks (legacy pattern)"
153
+ fi
154
+ }
155
+
156
+ # ==============================================================================
157
+ # Test 4: Failure Tracking
158
+ # ==============================================================================
159
+
160
+ test_failure_tracking() {
161
+ section "Test 4: Failure Tracking (exit codes)"
162
+
163
+ # Check that failures are tracked
164
+ if grep -q "FAILURES=0" "$SCRIPT_DIR/session-sync.sh"; then
165
+ pass "Initializes failure counter"
166
+ else
167
+ fail "Doesn't track failures"
168
+ fi
169
+
170
+ # Check that failures increment counter
171
+ if grep -q "FAILURES=\$((FAILURES + 1))" "$SCRIPT_DIR/session-sync.sh"; then
172
+ pass "Increments failure counter on errors"
173
+ else
174
+ fail "Doesn't increment failure counter"
175
+ fi
176
+
177
+ # Check that exit code reflects failures
178
+ if grep -A5 "if.*FAILURES.*-gt 0" "$SCRIPT_DIR/session-sync.sh" | grep -q "exit 1"; then
179
+ pass "Exits with code 1 when failures occur"
180
+ else
181
+ fail "Doesn't exit with error code on failures"
182
+ fi
183
+ }
184
+
185
+ # ==============================================================================
186
+ # Test 5: Integration with Current Repo
187
+ # ==============================================================================
188
+
189
+ test_current_repo_integration() {
190
+ section "Test 5: Integration with Current Repo"
191
+
192
+ cd "$REPO_DIR"
193
+
194
+ # Test that script runs without crashing
195
+ if "$SCRIPT_DIR/session-sync.sh" >/dev/null 2>&1; then
196
+ pass "Script runs successfully on current repo"
197
+ else
198
+ exit_code=$?
199
+ if [[ $exit_code -eq 1 ]]; then
200
+ # Check if failure was due to uncommitted changes (safe failure)
201
+ output=$("$SCRIPT_DIR/session-sync.sh" 2>&1 || true)
202
+ if echo "$output" | grep -q "uncommitted changes"; then
203
+ pass "Script correctly fails on uncommitted changes"
204
+ else
205
+ fail "Script failed for unknown reason (exit code 1)"
206
+ fi
207
+ else
208
+ fail "Script crashed with exit code $exit_code"
209
+ fi
210
+ fi
211
+
212
+ # Test that it doesn't modify uncommitted changes
213
+ before_status=$(git status --porcelain)
214
+ "$SCRIPT_DIR/session-sync.sh" >/dev/null 2>&1 || true
215
+ after_status=$(git status --porcelain)
216
+
217
+ if [[ "$before_status" == "$after_status" ]]; then
218
+ pass "Doesn't modify uncommitted changes"
219
+ else
220
+ fail "DANGER: Modified uncommitted changes!"
221
+ fi
222
+ }
223
+
224
+ # ==============================================================================
225
+ # Test 6: Behind/Ahead Detection
226
+ # ==============================================================================
227
+
228
+ test_behind_ahead_detection() {
229
+ section "Test 6: Behind/Ahead Detection"
230
+
231
+ # Check for behind detection
232
+ if grep -q "commits behind origin" "$SCRIPT_DIR/session-sync.sh"; then
233
+ pass "Detects when repo is behind origin"
234
+ else
235
+ fail "Doesn't detect behind status"
236
+ fi
237
+
238
+ # Check for ahead detection
239
+ if grep -q "commits ahead" "$SCRIPT_DIR/session-sync.sh"; then
240
+ pass "Detects when repo is ahead (unpushed)"
241
+ else
242
+ fail "Doesn't detect ahead status"
243
+ fi
244
+
245
+ # Check for up-to-date message
246
+ if grep -q "is up to date" "$SCRIPT_DIR/session-sync.sh"; then
247
+ pass "Reports when repo is up to date"
248
+ else
249
+ fail "Doesn't report up-to-date status"
250
+ fi
251
+ }
252
+
253
+ # ==============================================================================
254
+ # Test 7: Recursive Submodule Update
255
+ # ==============================================================================
256
+
257
+ test_recursive_submodules() {
258
+ section "Test 7: Recursive Submodule Handling"
259
+
260
+ # Check for recursive submodule update
261
+ if grep -q "submodule update.*--recursive" "$SCRIPT_DIR/session-sync.sh"; then
262
+ pass "Updates submodules recursively"
263
+ else
264
+ fail "Doesn't update nested submodules"
265
+ fi
266
+
267
+ # Check for --init flag (initializes new submodules)
268
+ if grep -q "submodule update --init" "$SCRIPT_DIR/session-sync.sh"; then
269
+ pass "Initializes new submodules automatically"
270
+ else
271
+ fail "Doesn't initialize new submodules"
272
+ fi
273
+ }
274
+
275
+ # ==============================================================================
276
+ # Run All Tests
277
+ # ==============================================================================
278
+
279
+ main() {
280
+ echo ""
281
+ echo "╔══════════════════════════════════════════════════════════╗"
282
+ echo "║ session-sync.sh Rigorous Testing ║"
283
+ echo "║ Before Commit Verification ║"
284
+ echo "╚══════════════════════════════════════════════════════════╝"
285
+
286
+ test_safety_checks
287
+ test_detached_head
288
+ test_product_detection
289
+ test_failure_tracking
290
+ test_current_repo_integration
291
+ test_behind_ahead_detection
292
+ test_recursive_submodules
293
+
294
+ # Summary
295
+ echo ""
296
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
297
+ echo -e "${BLUE}Test Results${NC}"
298
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
299
+ echo -e "${GREEN}Passed:${NC} $TESTS_PASSED"
300
+ if [[ $TESTS_FAILED -gt 0 ]]; then
301
+ echo -e "${RED}Failed:${NC} $TESTS_FAILED"
302
+ echo ""
303
+ echo -e "${RED}session-sync.sh NOT READY TO COMMIT${NC}"
304
+ exit 1
305
+ else
306
+ echo ""
307
+ echo -e "${GREEN}✓ session-sync.sh ready to commit${NC}"
308
+ echo ""
309
+ echo "Safety verified:"
310
+ echo " • Won't pull over uncommitted changes"
311
+ echo " • Exits with error on failure"
312
+ echo " • Handles network failures gracefully"
313
+ echo " • No destructive operations"
314
+ echo " • Detached HEAD auto-fix"
315
+ echo " • Recursive submodule updates"
316
+ exit 0
317
+ fi
318
+ }
319
+
320
+ main "$@"
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # where-am-i.sh - Quick context check for git operations
4
+ #
5
+ # Shows:
6
+ # - Current directory
7
+ # - Which repo you're in (GTM or product submodule)
8
+ # - Current branch
9
+ # - Uncommitted changes
10
+ #
11
+ # Usage:
12
+ # ./scripts/where-am-i.sh
13
+
14
+ set -e
15
+
16
+ CWD=$(pwd)
17
+
18
+ # Colors
19
+ BLUE='\033[0;34m'
20
+ GREEN='\033[0;32m'
21
+ YELLOW='\033[1;33m'
22
+ NC='\033[0m'
23
+
24
+ echo ""
25
+ echo -e "${BLUE}📍 Current Location${NC}"
26
+ echo "─────────────────────────────────────"
27
+ echo ""
28
+
29
+ # Show current directory
30
+ echo -e "Directory: ${GREEN}$CWD${NC}"
31
+
32
+ # Detect which repo context (check for submodules first, then GTM)
33
+ REMOTE_URL=$(git remote get-url origin 2>/dev/null || echo "")
34
+
35
+ if [[ "$CWD" == *"/product"* ]] || [[ "$REMOTE_URL" == *"jfl-platform"* ]]; then
36
+ echo -e "Context: ${YELLOW}product submodule${NC} (jfl-platform)"
37
+ echo ""
38
+ echo "To commit here: ./scripts/commit-product.sh \"message\""
39
+ elif [[ "$CWD" == *"/runner"* ]] || [[ "$REMOTE_URL" == *"jfl-runner"* ]]; then
40
+ echo -e "Context: ${YELLOW}runner submodule${NC} (jfl-runner)"
41
+ echo ""
42
+ echo "To commit here: cd ../; git add runner && git commit -m \"Update runner submodule\""
43
+ elif [[ "$REMOTE_URL" == *"JFL-GTM"* ]] || [[ -f ".jfl/config.json" ]]; then
44
+ echo -e "Context: ${GREEN}GTM repo${NC} (main project)"
45
+ echo ""
46
+ echo "To commit here: ./scripts/commit-gtm.sh \"message\""
47
+ else
48
+ # Check if we're in any submodule
49
+ if git rev-parse --show-superproject-working-tree &>/dev/null; then
50
+ SUBMODULE_NAME=$(basename "$CWD")
51
+ echo -e "Context: ${YELLOW}${SUBMODULE_NAME} submodule${NC}"
52
+ else
53
+ echo -e "Context: ${YELLOW}unknown${NC}"
54
+ fi
55
+ fi
56
+
57
+ echo ""
58
+
59
+ # Show current branch
60
+ BRANCH=$(git branch --show-current 2>/dev/null || echo "detached HEAD")
61
+ if [[ "$BRANCH" == "detached HEAD" ]]; then
62
+ echo -e "Branch: ${YELLOW}⚠️ detached HEAD${NC}"
63
+ echo " (run: git checkout main)"
64
+ else
65
+ echo -e "Branch: ${GREEN}$BRANCH${NC}"
66
+ fi
67
+
68
+ # Show uncommitted changes
69
+ CHANGES=$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ')
70
+ if [[ "$CHANGES" -gt 0 ]]; then
71
+ echo -e "Changes: ${YELLOW}$CHANGES uncommitted${NC}"
72
+ echo ""
73
+ git status --short
74
+ else
75
+ echo -e "Changes: ${GREEN}none (clean)${NC}"
76
+ fi
77
+
78
+ echo ""