jfl 0.4.3 → 0.5.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 (428) hide show
  1. package/README.md +15 -5
  2. package/dist/commands/context-hub.d.ts.map +1 -1
  3. package/dist/commands/context-hub.js +818 -39
  4. package/dist/commands/context-hub.js.map +1 -1
  5. package/dist/commands/eval.d.ts +1 -1
  6. package/dist/commands/eval.d.ts.map +1 -1
  7. package/dist/commands/eval.js +192 -1
  8. package/dist/commands/eval.js.map +1 -1
  9. package/dist/commands/findings.d.ts +6 -0
  10. package/dist/commands/findings.d.ts.map +1 -0
  11. package/dist/commands/findings.js +203 -0
  12. package/dist/commands/findings.js.map +1 -0
  13. package/dist/commands/hud.d.ts.map +1 -1
  14. package/dist/commands/hud.js +47 -9
  15. package/dist/commands/hud.js.map +1 -1
  16. package/dist/commands/ide.d.ts +27 -0
  17. package/dist/commands/ide.d.ts.map +1 -0
  18. package/dist/commands/ide.js +546 -0
  19. package/dist/commands/ide.js.map +1 -0
  20. package/dist/commands/onboard.d.ts.map +1 -1
  21. package/dist/commands/onboard.js +212 -2
  22. package/dist/commands/onboard.js.map +1 -1
  23. package/dist/commands/openclaw.d.ts +3 -0
  24. package/dist/commands/openclaw.d.ts.map +1 -1
  25. package/dist/commands/openclaw.js +76 -2
  26. package/dist/commands/openclaw.js.map +1 -1
  27. package/dist/commands/peter.d.ts +3 -0
  28. package/dist/commands/peter.d.ts.map +1 -1
  29. package/dist/commands/peter.js +1218 -2
  30. package/dist/commands/peter.js.map +1 -1
  31. package/dist/commands/pi-fleet.d.ts +18 -0
  32. package/dist/commands/pi-fleet.d.ts.map +1 -0
  33. package/dist/commands/pi-fleet.js +382 -0
  34. package/dist/commands/pi-fleet.js.map +1 -0
  35. package/dist/commands/pi.d.ts.map +1 -1
  36. package/dist/commands/pi.js +18 -3
  37. package/dist/commands/pi.js.map +1 -1
  38. package/dist/commands/scope.d.ts.map +1 -1
  39. package/dist/commands/scope.js +90 -1
  40. package/dist/commands/scope.js.map +1 -1
  41. package/dist/commands/services.d.ts.map +1 -1
  42. package/dist/commands/services.js +18 -0
  43. package/dist/commands/services.js.map +1 -1
  44. package/dist/commands/status.d.ts.map +1 -1
  45. package/dist/commands/status.js +22 -4
  46. package/dist/commands/status.js.map +1 -1
  47. package/dist/commands/viz.d.ts.map +1 -1
  48. package/dist/commands/viz.js +417 -0
  49. package/dist/commands/viz.js.map +1 -1
  50. package/dist/dashboard-static/assets/index-B6b867Pv.js +121 -0
  51. package/dist/dashboard-static/assets/index-Y4BrqxV-.css +1 -0
  52. package/dist/dashboard-static/index.html +2 -2
  53. package/dist/index.js +228 -62
  54. package/dist/index.js.map +1 -1
  55. package/dist/lib/agent-config.d.ts +52 -0
  56. package/dist/lib/agent-config.d.ts.map +1 -0
  57. package/dist/lib/agent-config.js +231 -0
  58. package/dist/lib/agent-config.js.map +1 -0
  59. package/dist/lib/agent-generator.d.ts +10 -0
  60. package/dist/lib/agent-generator.d.ts.map +1 -1
  61. package/dist/lib/agent-generator.js +64 -10
  62. package/dist/lib/agent-generator.js.map +1 -1
  63. package/dist/lib/agent-session.d.ts +104 -0
  64. package/dist/lib/agent-session.d.ts.map +1 -0
  65. package/dist/lib/agent-session.js +627 -0
  66. package/dist/lib/agent-session.js.map +1 -0
  67. package/dist/lib/eval-snapshot.d.ts +47 -0
  68. package/dist/lib/eval-snapshot.d.ts.map +1 -0
  69. package/dist/lib/eval-snapshot.js +315 -0
  70. package/dist/lib/eval-snapshot.js.map +1 -0
  71. package/dist/lib/eval-store.d.ts +5 -0
  72. package/dist/lib/eval-store.d.ts.map +1 -1
  73. package/dist/lib/eval-store.js +33 -3
  74. package/dist/lib/eval-store.js.map +1 -1
  75. package/dist/lib/findings-engine.d.ts +51 -0
  76. package/dist/lib/findings-engine.d.ts.map +1 -0
  77. package/dist/lib/findings-engine.js +338 -0
  78. package/dist/lib/findings-engine.js.map +1 -0
  79. package/dist/lib/flow-engine.d.ts +8 -0
  80. package/dist/lib/flow-engine.d.ts.map +1 -1
  81. package/dist/lib/flow-engine.js +84 -2
  82. package/dist/lib/flow-engine.js.map +1 -1
  83. package/dist/lib/hub-client.d.ts +1 -0
  84. package/dist/lib/hub-client.d.ts.map +1 -1
  85. package/dist/lib/hub-client.js +33 -6
  86. package/dist/lib/hub-client.js.map +1 -1
  87. package/dist/lib/ide-panes.d.ts +58 -0
  88. package/dist/lib/ide-panes.d.ts.map +1 -0
  89. package/dist/lib/ide-panes.js +508 -0
  90. package/dist/lib/ide-panes.js.map +1 -0
  91. package/dist/lib/memory-db.js +4 -4
  92. package/dist/lib/memory-db.js.map +1 -1
  93. package/dist/lib/memory-indexer.d.ts.map +1 -1
  94. package/dist/lib/memory-indexer.js +3 -0
  95. package/dist/lib/memory-indexer.js.map +1 -1
  96. package/dist/lib/memory-search.d.ts +148 -4
  97. package/dist/lib/memory-search.d.ts.map +1 -1
  98. package/dist/lib/memory-search.js +496 -58
  99. package/dist/lib/memory-search.js.map +1 -1
  100. package/dist/lib/meta-orchestrator.d.ts +104 -0
  101. package/dist/lib/meta-orchestrator.d.ts.map +1 -0
  102. package/dist/lib/meta-orchestrator.js +373 -0
  103. package/dist/lib/meta-orchestrator.js.map +1 -0
  104. package/dist/lib/peer-agent-generator.d.ts.map +1 -1
  105. package/dist/lib/peer-agent-generator.js +43 -19
  106. package/dist/lib/peer-agent-generator.js.map +1 -1
  107. package/dist/lib/policy-head.d.ts +25 -0
  108. package/dist/lib/policy-head.d.ts.map +1 -0
  109. package/dist/lib/policy-head.js +136 -0
  110. package/dist/lib/policy-head.js.map +1 -0
  111. package/dist/lib/replay-buffer.d.ts +93 -0
  112. package/dist/lib/replay-buffer.d.ts.map +1 -0
  113. package/dist/lib/replay-buffer.js +302 -0
  114. package/dist/lib/replay-buffer.js.map +1 -0
  115. package/dist/lib/sentinel-rl.d.ts +97 -0
  116. package/dist/lib/sentinel-rl.d.ts.map +1 -0
  117. package/dist/lib/sentinel-rl.js +430 -0
  118. package/dist/lib/sentinel-rl.js.map +1 -0
  119. package/dist/lib/session-lock.d.ts +61 -0
  120. package/dist/lib/session-lock.d.ts.map +1 -0
  121. package/dist/lib/session-lock.js +438 -0
  122. package/dist/lib/session-lock.js.map +1 -0
  123. package/dist/lib/stratus-client.d.ts +1 -0
  124. package/dist/lib/stratus-client.d.ts.map +1 -1
  125. package/dist/lib/stratus-client.js +24 -2
  126. package/dist/lib/stratus-client.js.map +1 -1
  127. package/dist/lib/telemetry-agent-v2.d.ts +128 -0
  128. package/dist/lib/telemetry-agent-v2.d.ts.map +1 -0
  129. package/dist/lib/telemetry-agent-v2.js +1042 -0
  130. package/dist/lib/telemetry-agent-v2.js.map +1 -0
  131. package/dist/lib/telemetry-agent.d.ts.map +1 -1
  132. package/dist/lib/telemetry-agent.js +27 -6
  133. package/dist/lib/telemetry-agent.js.map +1 -1
  134. package/dist/lib/telemetry-digest.d.ts.map +1 -1
  135. package/dist/lib/telemetry-digest.js +27 -5
  136. package/dist/lib/telemetry-digest.js.map +1 -1
  137. package/dist/lib/telemetry.d.ts.map +1 -1
  138. package/dist/lib/telemetry.js +29 -4
  139. package/dist/lib/telemetry.js.map +1 -1
  140. package/dist/lib/text-preprocessing.d.ts +83 -0
  141. package/dist/lib/text-preprocessing.d.ts.map +1 -0
  142. package/dist/lib/text-preprocessing.js +261 -0
  143. package/dist/lib/text-preprocessing.js.map +1 -0
  144. package/dist/lib/training-buffer.d.ts +86 -0
  145. package/dist/lib/training-buffer.d.ts.map +1 -0
  146. package/dist/lib/training-buffer.js +139 -0
  147. package/dist/lib/training-buffer.js.map +1 -0
  148. package/dist/lib/tuple-miner.d.ts +30 -0
  149. package/dist/lib/tuple-miner.d.ts.map +1 -0
  150. package/dist/lib/tuple-miner.js +427 -0
  151. package/dist/lib/tuple-miner.js.map +1 -0
  152. package/dist/lib/vm-backend.d.ts +72 -0
  153. package/dist/lib/vm-backend.d.ts.map +1 -0
  154. package/dist/lib/vm-backend.js +175 -0
  155. package/dist/lib/vm-backend.js.map +1 -0
  156. package/dist/lib/workspace/backend.d.ts +53 -0
  157. package/dist/lib/workspace/backend.d.ts.map +1 -0
  158. package/dist/lib/workspace/backend.js +37 -0
  159. package/dist/lib/workspace/backend.js.map +1 -0
  160. package/dist/lib/workspace/cmux-adapter.d.ts +46 -0
  161. package/dist/lib/workspace/cmux-adapter.d.ts.map +1 -0
  162. package/dist/lib/workspace/cmux-adapter.js +261 -0
  163. package/dist/lib/workspace/cmux-adapter.js.map +1 -0
  164. package/dist/lib/workspace/data-pipeline.d.ts +35 -0
  165. package/dist/lib/workspace/data-pipeline.d.ts.map +1 -0
  166. package/dist/lib/workspace/data-pipeline.js +463 -0
  167. package/dist/lib/workspace/data-pipeline.js.map +1 -0
  168. package/dist/lib/workspace/engine.d.ts +64 -0
  169. package/dist/lib/workspace/engine.d.ts.map +1 -0
  170. package/dist/lib/workspace/engine.js +397 -0
  171. package/dist/lib/workspace/engine.js.map +1 -0
  172. package/dist/lib/workspace/notifications.d.ts +14 -0
  173. package/dist/lib/workspace/notifications.d.ts.map +1 -0
  174. package/dist/lib/workspace/notifications.js +41 -0
  175. package/dist/lib/workspace/notifications.js.map +1 -0
  176. package/dist/lib/workspace/surface-registry.d.ts +49 -0
  177. package/dist/lib/workspace/surface-registry.d.ts.map +1 -0
  178. package/dist/lib/workspace/surface-registry.js +217 -0
  179. package/dist/lib/workspace/surface-registry.js.map +1 -0
  180. package/dist/lib/workspace/surface-type.d.ts +153 -0
  181. package/dist/lib/workspace/surface-type.d.ts.map +1 -0
  182. package/dist/lib/workspace/surface-type.js +9 -0
  183. package/dist/lib/workspace/surface-type.js.map +1 -0
  184. package/dist/lib/workspace/surfaces/agent-overview.d.ts +16 -0
  185. package/dist/lib/workspace/surfaces/agent-overview.d.ts.map +1 -0
  186. package/dist/lib/workspace/surfaces/agent-overview.js +116 -0
  187. package/dist/lib/workspace/surfaces/agent-overview.js.map +1 -0
  188. package/dist/lib/workspace/surfaces/agent.d.ts +16 -0
  189. package/dist/lib/workspace/surfaces/agent.d.ts.map +1 -0
  190. package/dist/lib/workspace/surfaces/agent.js +112 -0
  191. package/dist/lib/workspace/surfaces/agent.js.map +1 -0
  192. package/dist/lib/workspace/surfaces/claude.d.ts +15 -0
  193. package/dist/lib/workspace/surfaces/claude.d.ts.map +1 -0
  194. package/dist/lib/workspace/surfaces/claude.js +23 -0
  195. package/dist/lib/workspace/surfaces/claude.js.map +1 -0
  196. package/dist/lib/workspace/surfaces/dashboard.d.ts +21 -0
  197. package/dist/lib/workspace/surfaces/dashboard.d.ts.map +1 -0
  198. package/dist/lib/workspace/surfaces/dashboard.js +32 -0
  199. package/dist/lib/workspace/surfaces/dashboard.js.map +1 -0
  200. package/dist/lib/workspace/surfaces/eval.d.ts +15 -0
  201. package/dist/lib/workspace/surfaces/eval.d.ts.map +1 -0
  202. package/dist/lib/workspace/surfaces/eval.js +42 -0
  203. package/dist/lib/workspace/surfaces/eval.js.map +1 -0
  204. package/dist/lib/workspace/surfaces/event-stream.d.ts +16 -0
  205. package/dist/lib/workspace/surfaces/event-stream.d.ts.map +1 -0
  206. package/dist/lib/workspace/surfaces/event-stream.js +40 -0
  207. package/dist/lib/workspace/surfaces/event-stream.js.map +1 -0
  208. package/dist/lib/workspace/surfaces/flow.d.ts +16 -0
  209. package/dist/lib/workspace/surfaces/flow.d.ts.map +1 -0
  210. package/dist/lib/workspace/surfaces/flow.js +49 -0
  211. package/dist/lib/workspace/surfaces/flow.js.map +1 -0
  212. package/dist/lib/workspace/surfaces/index.d.ts +16 -0
  213. package/dist/lib/workspace/surfaces/index.d.ts.map +1 -0
  214. package/dist/lib/workspace/surfaces/index.js +16 -0
  215. package/dist/lib/workspace/surfaces/index.js.map +1 -0
  216. package/dist/lib/workspace/surfaces/portfolio.d.ts +16 -0
  217. package/dist/lib/workspace/surfaces/portfolio.d.ts.map +1 -0
  218. package/dist/lib/workspace/surfaces/portfolio.js +102 -0
  219. package/dist/lib/workspace/surfaces/portfolio.js.map +1 -0
  220. package/dist/lib/workspace/surfaces/service.d.ts +16 -0
  221. package/dist/lib/workspace/surfaces/service.d.ts.map +1 -0
  222. package/dist/lib/workspace/surfaces/service.js +45 -0
  223. package/dist/lib/workspace/surfaces/service.js.map +1 -0
  224. package/dist/lib/workspace/surfaces/shell.d.ts +15 -0
  225. package/dist/lib/workspace/surfaces/shell.d.ts.map +1 -0
  226. package/dist/lib/workspace/surfaces/shell.js +19 -0
  227. package/dist/lib/workspace/surfaces/shell.js.map +1 -0
  228. package/dist/lib/workspace/surfaces/telemetry.d.ts +16 -0
  229. package/dist/lib/workspace/surfaces/telemetry.d.ts.map +1 -0
  230. package/dist/lib/workspace/surfaces/telemetry.js +48 -0
  231. package/dist/lib/workspace/surfaces/telemetry.js.map +1 -0
  232. package/dist/lib/workspace/surfaces/topology.d.ts +15 -0
  233. package/dist/lib/workspace/surfaces/topology.d.ts.map +1 -0
  234. package/dist/lib/workspace/surfaces/topology.js +19 -0
  235. package/dist/lib/workspace/surfaces/topology.js.map +1 -0
  236. package/dist/lib/workspace/surfaces/training.d.ts +16 -0
  237. package/dist/lib/workspace/surfaces/training.d.ts.map +1 -0
  238. package/dist/lib/workspace/surfaces/training.js +22 -0
  239. package/dist/lib/workspace/surfaces/training.js.map +1 -0
  240. package/dist/lib/workspace/tmux-adapter.d.ts +27 -0
  241. package/dist/lib/workspace/tmux-adapter.d.ts.map +1 -0
  242. package/dist/lib/workspace/tmux-adapter.js +106 -0
  243. package/dist/lib/workspace/tmux-adapter.js.map +1 -0
  244. package/dist/mcp/context-hub-mcp.js +7 -24
  245. package/dist/mcp/context-hub-mcp.js.map +1 -1
  246. package/dist/types/flows.d.ts +2 -0
  247. package/dist/types/flows.d.ts.map +1 -1
  248. package/dist/types/ide.d.ts +49 -0
  249. package/dist/types/ide.d.ts.map +1 -0
  250. package/dist/types/ide.js +5 -0
  251. package/dist/types/ide.js.map +1 -0
  252. package/dist/types/platform-digest.d.ts +228 -0
  253. package/dist/types/platform-digest.d.ts.map +1 -0
  254. package/dist/types/platform-digest.js +5 -0
  255. package/dist/types/platform-digest.js.map +1 -0
  256. package/dist/types/telemetry-digest.d.ts +2 -0
  257. package/dist/types/telemetry-digest.d.ts.map +1 -1
  258. package/dist/utils/ensure-project.d.ts +1 -0
  259. package/dist/utils/ensure-project.d.ts.map +1 -1
  260. package/dist/utils/ensure-project.js +19 -7
  261. package/dist/utils/ensure-project.js.map +1 -1
  262. package/dist/utils/jfl-config.d.ts +1 -0
  263. package/dist/utils/jfl-config.d.ts.map +1 -1
  264. package/dist/utils/jfl-config.js +19 -1
  265. package/dist/utils/jfl-config.js.map +1 -1
  266. package/dist/utils/jfl-paths.d.ts +5 -0
  267. package/dist/utils/jfl-paths.d.ts.map +1 -1
  268. package/dist/utils/jfl-paths.js +25 -3
  269. package/dist/utils/jfl-paths.js.map +1 -1
  270. package/package.json +3 -2
  271. package/packages/pi/AGENTS.md +112 -0
  272. package/packages/pi/extensions/agent-grid.ts +191 -0
  273. package/packages/pi/extensions/agent-names.ts +178 -0
  274. package/packages/pi/extensions/autoresearch.ts +427 -0
  275. package/packages/pi/extensions/bookmarks.ts +85 -0
  276. package/packages/pi/extensions/context.ts +151 -0
  277. package/packages/pi/extensions/crm-tool.ts +61 -0
  278. package/packages/pi/extensions/eval-tool.ts +224 -0
  279. package/packages/pi/extensions/eval.ts +60 -0
  280. package/packages/pi/extensions/footer.ts +239 -0
  281. package/packages/pi/extensions/hud-tool.ts +145 -0
  282. package/packages/pi/extensions/index.ts +392 -0
  283. package/packages/pi/extensions/journal.ts +224 -0
  284. package/packages/pi/extensions/map-bridge.ts +178 -0
  285. package/packages/pi/extensions/memory-tool.ts +68 -0
  286. package/packages/pi/extensions/notifications.ts +73 -0
  287. package/packages/pi/extensions/peter-parker.ts +202 -0
  288. package/packages/pi/extensions/policy-head-tool.ts +276 -0
  289. package/packages/pi/extensions/portfolio-bridge.ts +90 -0
  290. package/packages/pi/extensions/session.ts +90 -0
  291. package/packages/pi/extensions/shortcuts.ts +259 -0
  292. package/packages/pi/extensions/stratus-bridge.ts +115 -0
  293. package/packages/pi/extensions/synopsis-tool.ts +83 -0
  294. package/packages/pi/extensions/tool-renderers.ts +352 -0
  295. package/packages/pi/extensions/training-buffer-tool.ts +368 -0
  296. package/packages/pi/extensions/types.ts +163 -0
  297. package/packages/pi/package-lock.json +346 -0
  298. package/packages/pi/package.json +44 -0
  299. package/packages/pi/skills/agent-browser/SKILL.md +116 -0
  300. package/packages/pi/skills/brand-architect/SKILL.md +240 -0
  301. package/packages/pi/skills/brand-architect/config.yaml +137 -0
  302. package/packages/pi/skills/campaign-hud/config.yaml +112 -0
  303. package/packages/pi/skills/content-creator/SKILL.md +294 -0
  304. package/packages/pi/skills/context/SKILL.md +65 -0
  305. package/packages/pi/skills/debug/MULTI_AGENT.md +360 -0
  306. package/packages/pi/skills/debug/SKILL.md +554 -0
  307. package/packages/pi/skills/end/SKILL.md +1782 -0
  308. package/packages/pi/skills/eval/SKILL.md +75 -0
  309. package/packages/pi/skills/fly-deploy/SKILL.md +676 -0
  310. package/packages/pi/skills/founder-video/SKILL.md +467 -0
  311. package/packages/pi/skills/hud/SKILL.md +160 -0
  312. package/packages/pi/skills/orchestrate/SKILL.md +74 -0
  313. package/packages/pi/skills/pi-agents/SKILL.md +78 -0
  314. package/packages/pi/skills/react-best-practices/AGENTS.md +2249 -0
  315. package/packages/pi/skills/react-best-practices/README.md +123 -0
  316. package/packages/pi/skills/react-best-practices/SKILL.md +125 -0
  317. package/packages/pi/skills/react-best-practices/metadata.json +15 -0
  318. package/packages/pi/skills/react-best-practices/rules/_sections.md +46 -0
  319. package/packages/pi/skills/react-best-practices/rules/_template.md +28 -0
  320. package/packages/pi/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  321. package/packages/pi/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
  322. package/packages/pi/skills/react-best-practices/rules/async-api-routes.md +38 -0
  323. package/packages/pi/skills/react-best-practices/rules/async-defer-await.md +80 -0
  324. package/packages/pi/skills/react-best-practices/rules/async-dependencies.md +36 -0
  325. package/packages/pi/skills/react-best-practices/rules/async-parallel.md +28 -0
  326. package/packages/pi/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
  327. package/packages/pi/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
  328. package/packages/pi/skills/react-best-practices/rules/bundle-conditional.md +31 -0
  329. package/packages/pi/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
  330. package/packages/pi/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  331. package/packages/pi/skills/react-best-practices/rules/bundle-preload.md +50 -0
  332. package/packages/pi/skills/react-best-practices/rules/client-event-listeners.md +74 -0
  333. package/packages/pi/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
  334. package/packages/pi/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
  335. package/packages/pi/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
  336. package/packages/pi/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
  337. package/packages/pi/skills/react-best-practices/rules/js-cache-storage.md +70 -0
  338. package/packages/pi/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
  339. package/packages/pi/skills/react-best-practices/rules/js-early-exit.md +50 -0
  340. package/packages/pi/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
  341. package/packages/pi/skills/react-best-practices/rules/js-index-maps.md +37 -0
  342. package/packages/pi/skills/react-best-practices/rules/js-length-check-first.md +49 -0
  343. package/packages/pi/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
  344. package/packages/pi/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
  345. package/packages/pi/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  346. package/packages/pi/skills/react-best-practices/rules/rendering-activity.md +26 -0
  347. package/packages/pi/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  348. package/packages/pi/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
  349. package/packages/pi/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
  350. package/packages/pi/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  351. package/packages/pi/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  352. package/packages/pi/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
  353. package/packages/pi/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
  354. package/packages/pi/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
  355. package/packages/pi/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
  356. package/packages/pi/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
  357. package/packages/pi/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  358. package/packages/pi/skills/react-best-practices/rules/rerender-memo.md +44 -0
  359. package/packages/pi/skills/react-best-practices/rules/rerender-transitions.md +40 -0
  360. package/packages/pi/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
  361. package/packages/pi/skills/react-best-practices/rules/server-cache-lru.md +41 -0
  362. package/packages/pi/skills/react-best-practices/rules/server-cache-react.md +26 -0
  363. package/packages/pi/skills/react-best-practices/rules/server-parallel-fetching.md +79 -0
  364. package/packages/pi/skills/react-best-practices/rules/server-serialization.md +38 -0
  365. package/packages/pi/skills/remotion-best-practices/SKILL.md +43 -0
  366. package/packages/pi/skills/remotion-best-practices/rules/3d.md +86 -0
  367. package/packages/pi/skills/remotion-best-practices/rules/animations.md +29 -0
  368. package/packages/pi/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx +173 -0
  369. package/packages/pi/skills/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +100 -0
  370. package/packages/pi/skills/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +108 -0
  371. package/packages/pi/skills/remotion-best-practices/rules/assets.md +78 -0
  372. package/packages/pi/skills/remotion-best-practices/rules/audio.md +172 -0
  373. package/packages/pi/skills/remotion-best-practices/rules/calculate-metadata.md +104 -0
  374. package/packages/pi/skills/remotion-best-practices/rules/can-decode.md +75 -0
  375. package/packages/pi/skills/remotion-best-practices/rules/charts.md +58 -0
  376. package/packages/pi/skills/remotion-best-practices/rules/compositions.md +146 -0
  377. package/packages/pi/skills/remotion-best-practices/rules/display-captions.md +126 -0
  378. package/packages/pi/skills/remotion-best-practices/rules/extract-frames.md +229 -0
  379. package/packages/pi/skills/remotion-best-practices/rules/fonts.md +152 -0
  380. package/packages/pi/skills/remotion-best-practices/rules/get-audio-duration.md +58 -0
  381. package/packages/pi/skills/remotion-best-practices/rules/get-video-dimensions.md +68 -0
  382. package/packages/pi/skills/remotion-best-practices/rules/get-video-duration.md +58 -0
  383. package/packages/pi/skills/remotion-best-practices/rules/gifs.md +138 -0
  384. package/packages/pi/skills/remotion-best-practices/rules/images.md +130 -0
  385. package/packages/pi/skills/remotion-best-practices/rules/import-srt-captions.md +67 -0
  386. package/packages/pi/skills/remotion-best-practices/rules/lottie.md +68 -0
  387. package/packages/pi/skills/remotion-best-practices/rules/measuring-dom-nodes.md +35 -0
  388. package/packages/pi/skills/remotion-best-practices/rules/measuring-text.md +143 -0
  389. package/packages/pi/skills/remotion-best-practices/rules/sequencing.md +106 -0
  390. package/packages/pi/skills/remotion-best-practices/rules/tailwind.md +11 -0
  391. package/packages/pi/skills/remotion-best-practices/rules/text-animations.md +20 -0
  392. package/packages/pi/skills/remotion-best-practices/rules/timing.md +179 -0
  393. package/packages/pi/skills/remotion-best-practices/rules/transcribe-captions.md +19 -0
  394. package/packages/pi/skills/remotion-best-practices/rules/transitions.md +122 -0
  395. package/packages/pi/skills/remotion-best-practices/rules/trimming.md +53 -0
  396. package/packages/pi/skills/remotion-best-practices/rules/videos.md +171 -0
  397. package/packages/pi/skills/search/SKILL.md +220 -0
  398. package/packages/pi/skills/spec/SKILL.md +377 -0
  399. package/packages/pi/skills/startup/SKILL.md +315 -0
  400. package/packages/pi/skills/web-architect/SKILL.md +309 -0
  401. package/packages/pi/skills/x-algorithm/SKILL.md +305 -0
  402. package/packages/pi/teams/dev-team.yaml +63 -0
  403. package/packages/pi/teams/gtm-team.yaml +79 -0
  404. package/packages/pi/themes/jfl.theme.json +76 -0
  405. package/packages/pi/tsconfig.json +21 -0
  406. package/scripts/collect-tuples.sh +124 -0
  407. package/scripts/destroy-fleet.sh +37 -0
  408. package/scripts/jfl-ide.sh +48 -0
  409. package/scripts/session/session-cleanup.sh +4 -11
  410. package/scripts/session/session-init.sh +6 -0
  411. package/scripts/session/session-sync.sh +25 -0
  412. package/scripts/setup-branch-protection.sh +106 -0
  413. package/scripts/spawn-fleet.sh +144 -0
  414. package/scripts/train-policy-head.py +434 -0
  415. package/scripts/vm-swarm/README.md +301 -0
  416. package/scripts/vm-swarm/collect-tuples.sh +331 -0
  417. package/scripts/vm-swarm/create-base-template.sh +339 -0
  418. package/scripts/vm-swarm/kill-fleet.sh +204 -0
  419. package/scripts/vm-swarm/monitor-fleet.sh +346 -0
  420. package/scripts/vm-swarm/spawn-fleet.sh +304 -0
  421. package/template/.github/workflows/jfl-eval.yml +105 -8
  422. package/template/.github/workflows/jfl-review.yml +4 -0
  423. package/template/scripts/session/session-end.sh +69 -6
  424. package/template/scripts/session/session-init.sh +55 -30
  425. package/template/scripts/session/session-lock.sh +464 -0
  426. package/template/templates/service-agent/workflows/jfl-eval.yml +19 -0
  427. package/dist/dashboard-static/assets/index-B6kRK9Rq.js +0 -116
  428. package/dist/dashboard-static/assets/index-BpdKJPLu.css +0 -1
@@ -0,0 +1,1782 @@
1
+ ---
2
+ name: end
3
+ description: End the current JFL session gracefully with automatic merge and cleanup
4
+ triggers:
5
+ - done
6
+ - that's it
7
+ - I'm finished
8
+ - end session
9
+ - /end
10
+ - let's wrap up
11
+ - all set for today
12
+ ---
13
+
14
+ # /end - Session Reconciliation
15
+
16
+ End the current JFL session gracefully with work preservation, conflict resolution, and handoff visibility.
17
+
18
+ ---
19
+
20
+ ## Core Principle
21
+
22
+ **Session ending is a critical handoff point.** Poor UX here creates uncertainty ("Did my work get saved?"), risks lost work if errors aren't handled clearly, and loses context if journal entries aren't captured.
23
+
24
+ JFL's session architecture guarantees work preservation through multiple safety layers:
25
+
26
+ 1. **Continuous auto-commit** - Background process commits every 2 minutes (managed by `session.ts` extension in Pi)
27
+ 2. **session_shutdown hook** - Pi's `session_shutdown` extension handler runs cleanup when session ends
28
+ 3. **This skill** - User-initiated clean ending with full visibility
29
+
30
+ **Note for Pi sessions:** Hook enforcement is handled by the `session_shutdown` extension (`extensions/session.ts`), not `.claude/settings.json` Stop hooks. The cleanup script and journal checks run via the Pi extension lifecycle.
31
+
32
+ When you invoke `/end`, the user wants to:
33
+ - **Know what happened** - What commits merged? What changed?
34
+ - **Trust their work is saved** - No uncertainty about state
35
+ - **Understand next steps** - What should they or others do next?
36
+ - **Get handoff context** - Synopsis of work accomplished
37
+
38
+ This skill provides **comprehensive UX orchestration** around the solid `session-cleanup.sh` infrastructure. The script handles all git operations correctly - we wrap it with clear communication, pre-flight checks, and error guidance.
39
+
40
+ ### What "Clean Ending" Means
41
+
42
+ A clean session end has these properties:
43
+
44
+ 1. **All work committed** - No uncommitted changes left behind
45
+ 2. **Merged to working branch** - Session branch integrated, not stranded
46
+ 3. **Journal entry exists** - Future sessions understand what happened
47
+ 4. **Conflicts resolved** - No manual cleanup required later
48
+ 5. **Remote updated** - Team can see the work
49
+ 6. **Synopsis shown** - Clear summary of accomplishments
50
+
51
+ This skill ensures all six properties are met, or guides the user to resolve issues that prevent them.
52
+
53
+ ### Relationship to Other Safety Mechanisms
54
+
55
+ ```
56
+ User working...
57
+
58
+ ├─ Auto-commit (every 2 minutes)
59
+ │ └─ Prevents data loss during crashes
60
+
61
+ ├─ Stop hook (terminal close)
62
+ │ └─ Automatic fallback if /end not called
63
+
64
+ └─ /end skill (user-initiated) ← YOU ARE HERE
65
+ └─ Best UX: visibility + control
66
+ ```
67
+
68
+ **When to use each:**
69
+ - **Auto-commit**: Runs automatically, you don't invoke it
70
+ - **Stop hook**: Triggered automatically on terminal close
71
+ - **This skill**: User explicitly says "done" → invoke this for best experience
72
+
73
+ ---
74
+
75
+ ## When to Use This Skill
76
+
77
+ ### Explicit Triggers (HIGH CONFIDENCE)
78
+
79
+ User says any of these phrases → **immediately invoke this skill**:
80
+
81
+ | Phrase | Confidence | Action |
82
+ |--------|-----------|--------|
83
+ | "done" | 100% | Invoke immediately |
84
+ | "that's it" | 100% | Invoke immediately |
85
+ | "I'm finished" | 100% | Invoke immediately |
86
+ | "end session" | 100% | Invoke immediately |
87
+ | "/end" | 100% | Invoke immediately |
88
+ | "let's wrap up" | 95% | Invoke immediately |
89
+ | "all set for today" | 95% | Invoke immediately |
90
+ | "I'm out" | 90% | Invoke immediately |
91
+ | "good for now" | 85% | Invoke immediately |
92
+ | "ship it" | 80% | Check context - might mean commit, not end |
93
+
94
+ ### Implicit Triggers (CONTEXT-DEPENDENT)
95
+
96
+ User says these in a concluding context → **consider invoking**:
97
+
98
+ | Phrase | When to Invoke | When NOT to Invoke |
99
+ |--------|---------------|-------------------|
100
+ | "looks good" | After reviewing final work | After reviewing one piece of ongoing work |
101
+ | "perfect" | At end of conversation | In middle of iteration |
102
+ | "thanks" | With no pending questions | After getting help mid-session |
103
+ | "bye" | Clear goodbye | Just casual acknowledgment |
104
+
105
+ **Test: Is this the end of the session or just the end of a task?**
106
+
107
+ ```
108
+ User: "Great, the auth flow works. Thanks!"
109
+
110
+ → NOT an ending (still building, just finished one feature)
111
+ → Don't invoke /end
112
+
113
+ User: "Auth flow is done. That's all I needed today."
114
+
115
+ → IS an ending (explicit scope closure)
116
+ → Invoke /end
117
+ ```
118
+
119
+ ### When NOT to Use
120
+
121
+ **Do NOT invoke this skill if:**
122
+
123
+ 1. **User is continuing work** - "That's done, let's do X next"
124
+ 2. **In middle of iteration** - "Okay that works, but change the color to blue"
125
+ 3. **Just answered a question** - "Got it, thanks" (not ending, just acknowledging)
126
+ 4. **Unclear intent** - If unsure, ask: "Ready to end the session, or keep going?"
127
+
128
+ ---
129
+
130
+ ## Pre-Flight Check
131
+
132
+ Before executing cleanup, gather complete session state. This informs what to show the user and what prompts are needed.
133
+
134
+ ### Step 1: Detect Session Mode
135
+
136
+ ```bash
137
+ # Read worktree state
138
+ WORKTREE_PATH=$(cat .jfl/current-worktree.txt 2>/dev/null || echo "")
139
+
140
+ if [[ "$WORKTREE_PATH" == "direct" ]]; then
141
+ MODE="direct"
142
+ LOCATION=$(pwd)
143
+ elif [[ -n "$WORKTREE_PATH" ]]; then
144
+ MODE="worktree"
145
+ LOCATION="$WORKTREE_PATH"
146
+ else
147
+ # Not in a session
148
+ MODE="none"
149
+ fi
150
+ ```
151
+
152
+ **What this tells you:**
153
+ - `direct` → Single session, working on branch directly
154
+ - `worktree` → Multiple concurrent sessions, isolated worktree
155
+ - `none` → Not in a JFL session (shouldn't happen, but handle gracefully)
156
+
157
+ ### Step 1.5: Detect Service Context
158
+
159
+ After detecting session mode, check if running in a service:
160
+
161
+ ```bash
162
+ # Read config to detect environment
163
+ CONFIG_TYPE=$(jq -r '.type // "unknown"' .jfl/config.json 2>/dev/null)
164
+
165
+ if [[ "$CONFIG_TYPE" == "service" ]]; then
166
+ # Running in a service
167
+ GTM_PARENT=$(jq -r '.gtm_parent // empty' .jfl/config.json)
168
+
169
+ if [[ -z "$GTM_PARENT" ]]; then
170
+ echo "⚠️ Service not linked to GTM workspace"
171
+ echo ""
172
+ echo "This service can still be cleaned up, but changes won't sync to a GTM."
173
+ echo "To link: cd <gtm> && jfl services register $(pwd)"
174
+ echo ""
175
+ fi
176
+
177
+ SERVICE_NAME=$(jq -r '.name' .jfl/config.json)
178
+ SYNC_TO_GTM=true
179
+ echo "📡 Service context detected: $SERVICE_NAME"
180
+ echo " GTM parent: $GTM_PARENT"
181
+ else
182
+ # Running in GTM or standalone
183
+ SYNC_TO_GTM=false
184
+ fi
185
+ ```
186
+
187
+ **What this tells you:**
188
+ - If `SYNC_TO_GTM=true`: This is a service session, sync after cleanup
189
+ - If `GTM_PARENT` is empty: Service exists but not linked
190
+ - Otherwise: Regular GTM or standalone session
191
+
192
+ ### Step 1.6: Validate Service Configuration (Services Only)
193
+
194
+ If running in a service (`SYNC_TO_GTM=true`), validate configuration before ending:
195
+
196
+ ```bash
197
+ if [[ "$SYNC_TO_GTM" == "true" ]]; then
198
+ echo ""
199
+ echo "🔍 Validating service configuration..."
200
+
201
+ # Run validation (non-blocking, just show warnings)
202
+ if jfl services validate --json > /tmp/validation-result.json 2>/dev/null; then
203
+ # Parse results
204
+ ERRORS=$(jq -r '.summary.errors' /tmp/validation-result.json)
205
+ WARNINGS=$(jq -r '.summary.warnings' /tmp/validation-result.json)
206
+
207
+ if [[ "$ERRORS" -gt 0 ]]; then
208
+ echo "⚠️ Service validation found $ERRORS error(s)"
209
+ echo ""
210
+ echo "Run 'jfl services validate' to see details"
211
+ echo "Run 'jfl services validate --fix' to auto-repair"
212
+ echo ""
213
+
214
+ # Ask if they want to fix before ending
215
+ read -p "Auto-fix issues now? (y/N) " -n 1 -r
216
+ echo
217
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
218
+ jfl services validate --fix
219
+ fi
220
+ elif [[ "$WARNINGS" -gt 0 ]]; then
221
+ echo "✓ Validation passed ($WARNINGS warning(s))"
222
+ else
223
+ echo "✓ Service configuration valid"
224
+ fi
225
+ fi
226
+
227
+ rm -f /tmp/validation-result.json
228
+ fi
229
+ ```
230
+
231
+ **What this does:**
232
+ - Validates service configuration before ending session
233
+ - Non-blocking: Shows warnings but doesn't prevent session end
234
+ - Offers to auto-fix issues if errors found
235
+ - Only runs for services, not GTM workspaces
236
+
237
+ **Why this matters:**
238
+ - Catches configuration issues before they cause problems
239
+ - Prevents services from ending in an invalid state
240
+ - Ensures hooks, journal, and GTM integration are correct
241
+
242
+ ### Step 2: Get Branch Information
243
+
244
+ ```bash
245
+ # Current session branch
246
+ BRANCH=$(cat .jfl/current-session-branch.txt 2>/dev/null || git branch --show-current 2>/dev/null || echo "")
247
+
248
+ # Working branch (where session merges to)
249
+ WORKING_BRANCH=$(jq -r '.working_branch // "main"' .jfl/config.json 2>/dev/null || echo "main")
250
+
251
+ # Verify session branch format
252
+ if [[ ! "$BRANCH" =~ ^session- ]]; then
253
+ echo "⚠ Not on a session branch (current: $BRANCH)"
254
+ echo "Session branches start with 'session-'"
255
+ echo ""
256
+ echo "You might already be on $WORKING_BRANCH."
257
+ echo "No cleanup needed."
258
+ exit 0
259
+ fi
260
+ ```
261
+
262
+ **What this tells you:**
263
+ - `BRANCH` → Current session being worked on
264
+ - `WORKING_BRANCH` → Where work will merge (usually `main` or `develop`)
265
+
266
+ ### Step 3: Check for Uncommitted Changes
267
+
268
+ ```bash
269
+ # Check working directory and staging area
270
+ if ! git diff --quiet || ! git diff --cached --quiet; then
271
+ UNCOMMITTED=true
272
+ UNCOMMITTED_COUNT=$(git status --porcelain | wc -l | tr -d ' ')
273
+ else
274
+ UNCOMMITTED=false
275
+ UNCOMMITTED_COUNT=0
276
+ fi
277
+ ```
278
+
279
+ **What this tells you:**
280
+ - `true` → User has uncommitted changes, need to prompt
281
+ - `false` → Clean working directory, can proceed
282
+
283
+ ### Step 4: Check for Journal Entry
284
+
285
+ ```bash
286
+ # Session journal file
287
+ JOURNAL_FILE=".jfl/journal/${BRANCH}.jsonl"
288
+
289
+ if [[ -s "$JOURNAL_FILE" ]]; then
290
+ JOURNAL_EXISTS=true
291
+ JOURNAL_ENTRY_COUNT=$(wc -l < "$JOURNAL_FILE" | tr -d ' ')
292
+ else
293
+ JOURNAL_EXISTS=false
294
+ JOURNAL_ENTRY_COUNT=0
295
+ fi
296
+ ```
297
+
298
+ **What this tells you:**
299
+ - `true` → Session is documented, good handoff
300
+ - `false` → No journal entry, should warn user
301
+
302
+ ### Step 5: Count Session Work
303
+
304
+ ```bash
305
+ # Commits in this session (since branching from working branch)
306
+ COMMIT_COUNT=$(git rev-list --count $WORKING_BRANCH..HEAD 2>/dev/null || echo "0")
307
+
308
+ # Files changed in this session
309
+ FILES_CHANGED=$(git diff --name-only $WORKING_BRANCH..HEAD 2>/dev/null | wc -l | tr -d ' ')
310
+
311
+ # Lines changed (rough metric)
312
+ LINES_ADDED=$(git diff --numstat $WORKING_BRANCH..HEAD 2>/dev/null | awk '{sum+=$1} END {print sum+0}')
313
+ LINES_REMOVED=$(git diff --numstat $WORKING_BRANCH..HEAD 2>/dev/null | awk '{sum+=$2} END {print sum+0}')
314
+ ```
315
+
316
+ **What this tells you:**
317
+ - How much work will be merged
318
+ - Whether session had any meaningful work
319
+ - Context for journal warning (lots of work, no journal = bad)
320
+
321
+ ### Step 6: Calculate Session Duration
322
+
323
+ ```bash
324
+ # First commit in session (timestamp)
325
+ SESSION_START=$(git log --format=%ct --reverse $WORKING_BRANCH..HEAD 2>/dev/null | head -1)
326
+
327
+ if [[ -n "$SESSION_START" ]]; then
328
+ NOW=$(date +%s)
329
+ DURATION_SECONDS=$((NOW - SESSION_START))
330
+ DURATION_HOURS=$((DURATION_SECONDS / 3600))
331
+ DURATION_MINUTES=$(((DURATION_SECONDS % 3600) / 60))
332
+ else
333
+ # No commits yet
334
+ DURATION_HOURS=0
335
+ DURATION_MINUTES=0
336
+ fi
337
+ ```
338
+
339
+ **What this tells you:**
340
+ - How long user has been working
341
+ - Used for synopsis timeframe (show last N hours)
342
+
343
+ ### Complete Pre-Flight Check Script
344
+
345
+ Here's the full pattern to gather all session state:
346
+
347
+ ```bash
348
+ #!/bin/bash
349
+
350
+ # Pre-flight check - gather complete session state
351
+
352
+ echo "Gathering session state..."
353
+
354
+ # 1. Detect mode
355
+ WORKTREE_PATH=$(cat .jfl/current-worktree.txt 2>/dev/null || echo "")
356
+ if [[ "$WORKTREE_PATH" == "direct" ]]; then
357
+ MODE="direct"
358
+ elif [[ -n "$WORKTREE_PATH" ]]; then
359
+ MODE="worktree"
360
+ else
361
+ MODE="none"
362
+ fi
363
+
364
+ # 2. Get branches
365
+ BRANCH=$(cat .jfl/current-session-branch.txt 2>/dev/null || git branch --show-current 2>/dev/null || echo "")
366
+ WORKING_BRANCH=$(jq -r '.working_branch // "main"' .jfl/config.json 2>/dev/null || echo "main")
367
+
368
+ # Verify this is a session
369
+ if [[ ! "$BRANCH" =~ ^session- ]]; then
370
+ echo "⚠ Not in a JFL session"
371
+ exit 1
372
+ fi
373
+
374
+ # 3. Check uncommitted changes
375
+ if ! git diff --quiet || ! git diff --cached --quiet; then
376
+ UNCOMMITTED=true
377
+ UNCOMMITTED_COUNT=$(git status --porcelain | wc -l | tr -d ' ')
378
+ else
379
+ UNCOMMITTED=false
380
+ UNCOMMITTED_COUNT=0
381
+ fi
382
+
383
+ # 4. Check journal
384
+ JOURNAL_FILE=".jfl/journal/${BRANCH}.jsonl"
385
+ if [[ -s "$JOURNAL_FILE" ]]; then
386
+ JOURNAL_EXISTS=true
387
+ JOURNAL_ENTRY_COUNT=$(wc -l < "$JOURNAL_FILE" | tr -d ' ')
388
+ else
389
+ JOURNAL_EXISTS=false
390
+ JOURNAL_ENTRY_COUNT=0
391
+ fi
392
+
393
+ # 5. Count work
394
+ COMMIT_COUNT=$(git rev-list --count $WORKING_BRANCH..HEAD 2>/dev/null || echo "0")
395
+ FILES_CHANGED=$(git diff --name-only $WORKING_BRANCH..HEAD 2>/dev/null | wc -l | tr -d ' ')
396
+ LINES_ADDED=$(git diff --numstat $WORKING_BRANCH..HEAD 2>/dev/null | awk '{sum+=$1} END {print sum+0}')
397
+ LINES_REMOVED=$(git diff --numstat $WORKING_BRANCH..HEAD 2>/dev/null | awk '{sum+=$2} END {print sum+0}')
398
+
399
+ # 6. Calculate duration
400
+ SESSION_START=$(git log --format=%ct --reverse $WORKING_BRANCH..HEAD 2>/dev/null | head -1)
401
+ if [[ -n "$SESSION_START" ]]; then
402
+ NOW=$(date +%s)
403
+ DURATION_SECONDS=$((NOW - SESSION_START))
404
+ DURATION_HOURS=$((DURATION_SECONDS / 3600))
405
+ DURATION_MINUTES=$(((DURATION_SECONDS % 3600) / 60))
406
+ else
407
+ DURATION_HOURS=0
408
+ DURATION_MINUTES=0
409
+ fi
410
+
411
+ # Export for use by skill
412
+ echo "MODE=$MODE"
413
+ echo "BRANCH=$BRANCH"
414
+ echo "WORKING_BRANCH=$WORKING_BRANCH"
415
+ echo "UNCOMMITTED=$UNCOMMITTED"
416
+ echo "UNCOMMITTED_COUNT=$UNCOMMITTED_COUNT"
417
+ echo "JOURNAL_EXISTS=$JOURNAL_EXISTS"
418
+ echo "JOURNAL_ENTRY_COUNT=$JOURNAL_ENTRY_COUNT"
419
+ echo "COMMIT_COUNT=$COMMIT_COUNT"
420
+ echo "FILES_CHANGED=$FILES_CHANGED"
421
+ echo "LINES_ADDED=$LINES_ADDED"
422
+ echo "LINES_REMOVED=$LINES_REMOVED"
423
+ echo "DURATION_HOURS=$DURATION_HOURS"
424
+ echo "DURATION_MINUTES=$DURATION_MINUTES"
425
+ ```
426
+
427
+ You can run this and parse the output, or inline the checks directly in your skill logic.
428
+
429
+ ---
430
+
431
+ ## User Experience Flows
432
+
433
+ ### Scenario 1: Clean State (Happy Path)
434
+
435
+ **State:** No uncommitted changes, journal exists, clean merge expected
436
+
437
+ **What user sees:**
438
+
439
+ ```
440
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
441
+ Ending Session
442
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
443
+ Session: session-goose-20260210-1430-a1b2c3
444
+ Mode: worktree
445
+ Merging to: main
446
+
447
+ Changes:
448
+ • 8 commits
449
+ • 12 files modified
450
+ • +234 / -67 lines
451
+
452
+ ✓ Journal entry exists (3 entries)
453
+ ✓ No uncommitted changes
454
+
455
+ Executing cleanup...
456
+ ✓ Merged to main
457
+ ✓ Pushed to origin
458
+ ✓ Removed worktree
459
+ ✓ Deleted session branch
460
+
461
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
462
+ Work Summary (2h 15m session)
463
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
464
+
465
+ [Synopsis output here...]
466
+
467
+ ✓ Session ended successfully
468
+ ```
469
+
470
+ **Implementation:**
471
+
472
+ ```bash
473
+ # After pre-flight check shows clean state
474
+
475
+ echo ""
476
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
477
+ echo " Ending Session"
478
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
479
+ echo "Session: $BRANCH"
480
+ echo "Mode: $MODE"
481
+ echo "Merging to: $WORKING_BRANCH"
482
+ echo ""
483
+ echo "Changes:"
484
+ echo " • $COMMIT_COUNT commits"
485
+ echo " • $FILES_CHANGED files modified"
486
+ echo " • +$LINES_ADDED / -$LINES_REMOVED lines"
487
+ echo ""
488
+ echo "✓ Journal entry exists ($JOURNAL_ENTRY_COUNT entries)"
489
+ echo "✓ No uncommitted changes"
490
+ echo ""
491
+ echo "Executing cleanup..."
492
+
493
+ # Call session-cleanup.sh
494
+ ./scripts/session/session-cleanup.sh 2>&1 | while IFS= read -r line; do
495
+ # Filter output to show only key steps
496
+ if [[ "$line" =~ ^✓ ]] || [[ "$line" =~ ^⚠ ]] || [[ "$line" =~ "Merged" ]] || [[ "$line" =~ "Pushed" ]]; then
497
+ echo " $line"
498
+ fi
499
+ done
500
+
501
+ EXIT_CODE=${PIPESTATUS[0]}
502
+
503
+ if [[ $EXIT_CODE -eq 0 ]]; then
504
+ # Show synopsis
505
+ echo ""
506
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
507
+ echo " Work Summary (${DURATION_HOURS}h ${DURATION_MINUTES}m session)"
508
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
509
+ jfl synopsis $((DURATION_HOURS + 1)) # Round up to next hour
510
+ echo ""
511
+ echo "✓ Session ended successfully"
512
+ else
513
+ echo ""
514
+ echo "⚠ Session cleanup encountered issues"
515
+ echo "See log: .jfl/logs/session-cleanup.log"
516
+ fi
517
+ ```
518
+
519
+ ### Scenario 2: Uncommitted Changes
520
+
521
+ **State:** User has uncommitted changes (forgot to commit before ending)
522
+
523
+ **What user sees:**
524
+
525
+ ```
526
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
527
+ Uncommitted Changes Detected
528
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
529
+
530
+ You have 5 uncommitted changes:
531
+
532
+ M src/lib/auth.ts
533
+ M src/components/LoginForm.tsx
534
+ A src/lib/session-manager.ts
535
+ ?? src/lib/types.ts
536
+ M README.md
537
+
538
+ Options:
539
+ 1. Auto-commit these changes (recommended)
540
+ 2. Show me the diff first
541
+ 3. Discard these changes (⚠ cannot be undone)
542
+ 4. Cancel (stay in session)
543
+
544
+ What would you like to do? [1-4]:
545
+ ```
546
+
547
+ **Implementation:**
548
+
549
+ ```bash
550
+ # After detecting UNCOMMITTED=true
551
+
552
+ echo ""
553
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
554
+ echo " Uncommitted Changes Detected"
555
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
556
+ echo ""
557
+ echo "You have $UNCOMMITTED_COUNT uncommitted changes:"
558
+ echo ""
559
+ git status --porcelain | head -10 | sed 's/^/ /'
560
+ if [[ $UNCOMMITTED_COUNT -gt 10 ]]; then
561
+ echo " ... and $((UNCOMMITTED_COUNT - 10)) more"
562
+ fi
563
+ echo ""
564
+ ```
565
+
566
+ **Then present options to the user via AskUserQuestion tool:**
567
+
568
+ ```json
569
+ {
570
+ "questions": [
571
+ {
572
+ "question": "What would you like to do with uncommitted changes?",
573
+ "header": "Uncommitted",
574
+ "multiSelect": false,
575
+ "options": [
576
+ {
577
+ "label": "Auto-commit (Recommended)",
578
+ "description": "Automatically commit all changes with message 'session: end'. Safe and fast."
579
+ },
580
+ {
581
+ "label": "Show diff first",
582
+ "description": "Review changes before deciding. Lets you see exactly what will be committed."
583
+ },
584
+ {
585
+ "label": "Discard changes",
586
+ "description": "⚠ Permanently delete uncommitted changes. Cannot be undone. Only use if you're sure."
587
+ },
588
+ {
589
+ "label": "Cancel",
590
+ "description": "Stay in the session. Commit changes manually, then run /end again."
591
+ }
592
+ ]
593
+ }
594
+ ]
595
+ }
596
+ ```
597
+
598
+ **Handle each choice:**
599
+
600
+ **Choice 1: Auto-commit**
601
+ ```bash
602
+ echo "Auto-committing changes..."
603
+ git add -A
604
+ git commit -m "session: end $(date +%Y-%m-%d\ %H:%M)"
605
+ echo "✓ Changes committed"
606
+ echo ""
607
+ # Continue to cleanup
608
+ ```
609
+
610
+ **Choice 2: Show diff**
611
+ ```bash
612
+ echo "Changes to be committed:"
613
+ echo ""
614
+ git diff HEAD
615
+ echo ""
616
+ echo "What now?"
617
+ echo " 1. Commit these changes"
618
+ echo " 2. Discard these changes"
619
+ echo " 3. Cancel"
620
+ # Prompt again
621
+ ```
622
+
623
+ **Choice 3: Discard**
624
+ ```bash
625
+ echo "⚠ WARNING: This will permanently delete all uncommitted changes."
626
+ echo ""
627
+ echo "Type 'discard' to confirm: "
628
+ # Wait for user confirmation
629
+ # If confirmed:
630
+ git reset --hard HEAD
631
+ git clean -fd
632
+ echo "✓ Changes discarded"
633
+ # Continue to cleanup
634
+ ```
635
+
636
+ **Choice 4: Cancel**
637
+ ```bash
638
+ echo "Session still active."
639
+ echo "Commit your changes, then run /end again."
640
+ exit 0
641
+ ```
642
+
643
+ ### Scenario 3: No Journal Entry
644
+
645
+ **State:** Session has substantial work but no journal entry
646
+
647
+ **What user sees:**
648
+
649
+ ```
650
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
651
+ Missing Journal Entry
652
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
653
+
654
+ This session has work, but no journal entry:
655
+ • 8 commits
656
+ • 12 files changed
657
+ • 2h 15m duration
658
+
659
+ Journal entries help you (and others) understand what
660
+ happened when resuming work later.
661
+
662
+ Would you like to:
663
+ 1. Write a quick journal entry now (30 seconds)
664
+ 2. Skip (not recommended, but allowed)
665
+
666
+ Choice [1-2]:
667
+ ```
668
+
669
+ **Implementation:**
670
+
671
+ ```bash
672
+ # After detecting JOURNAL_EXISTS=false and COMMIT_COUNT > 0
673
+
674
+ echo ""
675
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
676
+ echo " Missing Journal Entry"
677
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
678
+ echo ""
679
+ echo "This session has work, but no journal entry:"
680
+ echo " • $COMMIT_COUNT commits"
681
+ echo " • $FILES_CHANGED files changed"
682
+ echo " • ${DURATION_HOURS}h ${DURATION_MINUTES}m duration"
683
+ echo ""
684
+ echo "Journal entries help you (and others) understand what"
685
+ echo "happened when resuming work later."
686
+ echo ""
687
+ ```
688
+
689
+ **Present options:**
690
+
691
+ ```json
692
+ {
693
+ "questions": [
694
+ {
695
+ "question": "Would you like to write a journal entry?",
696
+ "header": "Journal",
697
+ "multiSelect": false,
698
+ "options": [
699
+ {
700
+ "label": "Write entry (Recommended)",
701
+ "description": "Quick 30-second entry. Just a title and summary of what you did."
702
+ },
703
+ {
704
+ "label": "Skip",
705
+ "description": "Not recommended. Future sessions won't have context for this work."
706
+ }
707
+ ]
708
+ }
709
+ ]
710
+ }
711
+ ```
712
+
713
+ **If write entry:**
714
+
715
+ Prompt for minimal info:
716
+
717
+ ```
718
+ What did you work on? (one sentence):
719
+ ```
720
+
721
+ Wait for user input, then write basic journal entry:
722
+
723
+ ```bash
724
+ TITLE="$USER_INPUT"
725
+ SUMMARY="Session work (auto-generated)"
726
+ TS=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
727
+
728
+ # Get files changed
729
+ FILES=$(git diff --name-only $WORKING_BRANCH..HEAD | jq -R -s -c 'split("\n") | map(select(length > 0))')
730
+
731
+ # Write entry
732
+ cat >> "$JOURNAL_FILE" << EOF
733
+ {"v":1,"ts":"$TS","session":"$BRANCH","type":"session-end","status":"complete","title":"$TITLE","summary":"$SUMMARY","files":$FILES}
734
+ EOF
735
+
736
+ echo "✓ Journal entry created"
737
+ ```
738
+
739
+ **If skip:**
740
+
741
+ ```bash
742
+ echo "⚠ Proceeding without journal entry"
743
+ echo "Note: This makes handoffs harder for future sessions"
744
+ echo ""
745
+ # Continue to cleanup
746
+ ```
747
+
748
+ ### Scenario 4: Merge Conflicts
749
+
750
+ **State:** Cleanup script detects conflicts that can't be auto-resolved
751
+
752
+ **What user sees:**
753
+
754
+ ```
755
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
756
+ Merge Conflicts Detected
757
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
758
+
759
+ Conflicts in:
760
+ • src/lib/auth.ts
761
+ • src/components/LoginForm.tsx
762
+
763
+ Your session branch has been preserved: session-goose-20260210-1430-a1b2c3
764
+
765
+ To resolve manually:
766
+
767
+ 1. Review changes:
768
+ git log main..session-goose-20260210-1430-a1b2c3
769
+
770
+ 2. Merge manually:
771
+ git checkout main
772
+ git merge session-goose-20260210-1430-a1b2c3
773
+
774
+ 3. Resolve conflicts in your editor
775
+
776
+ 4. Complete merge:
777
+ git add .
778
+ git commit
779
+ git push origin main
780
+
781
+ 5. Delete session branch:
782
+ git branch -D session-goose-20260210-1430-a1b2c3
783
+
784
+ Need help? Ask Claude to guide you through conflict resolution.
785
+ ```
786
+
787
+ **Implementation:**
788
+
789
+ ```bash
790
+ # session-cleanup.sh handles conflict detection
791
+ # If it exits with conflicts, parse output and guide user
792
+
793
+ EXIT_CODE=${PIPESTATUS[0]}
794
+
795
+ if [[ $EXIT_CODE -ne 0 ]]; then
796
+ # Check if conflicts were the issue
797
+ if grep -q "Merge conflicts remain" .jfl/logs/session-cleanup.log; then
798
+ echo ""
799
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
800
+ echo " Merge Conflicts Detected"
801
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
802
+ echo ""
803
+ echo "Conflicts in:"
804
+ grep "Cannot auto-resolve:" .jfl/logs/session-cleanup.log | sed 's/^.*: / • /'
805
+ echo ""
806
+ echo "Your session branch has been preserved: $BRANCH"
807
+ echo ""
808
+ echo "To resolve manually:"
809
+ echo ""
810
+ echo "1. Review changes:"
811
+ echo " git log $WORKING_BRANCH..$BRANCH"
812
+ echo ""
813
+ echo "2. Merge manually:"
814
+ echo " git checkout $WORKING_BRANCH"
815
+ echo " git merge $BRANCH"
816
+ echo ""
817
+ echo "3. Resolve conflicts in your editor"
818
+ echo ""
819
+ echo "4. Complete merge:"
820
+ echo " git add ."
821
+ echo " git commit"
822
+ echo " git push origin $WORKING_BRANCH"
823
+ echo ""
824
+ echo "5. Delete session branch:"
825
+ echo " git branch -D $BRANCH"
826
+ echo ""
827
+ echo "Need help? Ask Claude to guide you through conflict resolution."
828
+ fi
829
+ fi
830
+ ```
831
+
832
+ ---
833
+
834
+ ## Implementation Steps
835
+
836
+ ### Complete Execution Flow
837
+
838
+ Here's the full implementation pattern for the `/end` skill:
839
+
840
+ ```bash
841
+ #!/bin/bash
842
+
843
+ # /end skill implementation
844
+
845
+ set -e
846
+
847
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
848
+ echo " Preparing to End Session"
849
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
850
+ echo ""
851
+
852
+ # ============================================================
853
+ # STEP 1: Pre-Flight Check
854
+ # ============================================================
855
+
856
+ echo "Running pre-flight checks..."
857
+ echo ""
858
+
859
+ # Detect mode
860
+ WORKTREE_PATH=$(cat .jfl/current-worktree.txt 2>/dev/null || echo "")
861
+ if [[ "$WORKTREE_PATH" == "direct" ]]; then
862
+ MODE="direct"
863
+ elif [[ -n "$WORKTREE_PATH" ]]; then
864
+ MODE="worktree"
865
+ else
866
+ MODE="none"
867
+ fi
868
+
869
+ # Get branches
870
+ BRANCH=$(cat .jfl/current-session-branch.txt 2>/dev/null || git branch --show-current 2>/dev/null || echo "")
871
+ WORKING_BRANCH=$(jq -r '.working_branch // "main"' .jfl/config.json 2>/dev/null || echo "main")
872
+
873
+ # Verify session
874
+ if [[ ! "$BRANCH" =~ ^session- ]]; then
875
+ echo "⚠ Not in a JFL session (current branch: ${BRANCH:-none})"
876
+ echo ""
877
+ echo "You might already be on $WORKING_BRANCH."
878
+ echo "Session branches start with 'session-'."
879
+ echo ""
880
+ echo "No cleanup needed."
881
+ exit 0
882
+ fi
883
+
884
+ # Check uncommitted
885
+ if ! git diff --quiet || ! git diff --cached --quiet; then
886
+ UNCOMMITTED=true
887
+ UNCOMMITTED_COUNT=$(git status --porcelain | wc -l | tr -d ' ')
888
+ else
889
+ UNCOMMITTED=false
890
+ UNCOMMITTED_COUNT=0
891
+ fi
892
+
893
+ # Check journal
894
+ JOURNAL_FILE=".jfl/journal/${BRANCH}.jsonl"
895
+ if [[ -s "$JOURNAL_FILE" ]]; then
896
+ JOURNAL_EXISTS=true
897
+ JOURNAL_ENTRY_COUNT=$(wc -l < "$JOURNAL_FILE" | tr -d ' ')
898
+ else
899
+ JOURNAL_EXISTS=false
900
+ JOURNAL_ENTRY_COUNT=0
901
+ fi
902
+
903
+ # Count work
904
+ COMMIT_COUNT=$(git rev-list --count $WORKING_BRANCH..HEAD 2>/dev/null || echo "0")
905
+ FILES_CHANGED=$(git diff --name-only $WORKING_BRANCH..HEAD 2>/dev/null | wc -l | tr -d ' ')
906
+ LINES_ADDED=$(git diff --numstat $WORKING_BRANCH..HEAD 2>/dev/null | awk '{sum+=$1} END {print sum+0}')
907
+ LINES_REMOVED=$(git diff --numstat $WORKING_BRANCH..HEAD 2>/dev/null | awk '{sum+=$2} END {print sum+0}')
908
+
909
+ # Calculate duration
910
+ SESSION_START=$(git log --format=%ct --reverse $WORKING_BRANCH..HEAD 2>/dev/null | head -1)
911
+ if [[ -n "$SESSION_START" ]]; then
912
+ NOW=$(date +%s)
913
+ DURATION_SECONDS=$((NOW - SESSION_START))
914
+ DURATION_HOURS=$((DURATION_SECONDS / 3600))
915
+ DURATION_MINUTES=$(((DURATION_SECONDS % 3600) / 60))
916
+ else
917
+ DURATION_HOURS=0
918
+ DURATION_MINUTES=0
919
+ fi
920
+
921
+ # ============================================================
922
+ # STEP 2: Display Session Summary
923
+ # ============================================================
924
+
925
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
926
+ echo " Session Summary"
927
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
928
+ echo "Session: $BRANCH"
929
+ echo "Mode: $MODE"
930
+ echo "Merging to: $WORKING_BRANCH"
931
+ echo "Duration: ${DURATION_HOURS}h ${DURATION_MINUTES}m"
932
+ echo ""
933
+ echo "Changes:"
934
+ echo " • $COMMIT_COUNT commits"
935
+ echo " • $FILES_CHANGED files modified"
936
+ echo " • +$LINES_ADDED / -$LINES_REMOVED lines"
937
+ echo ""
938
+
939
+ # ============================================================
940
+ # STEP 3: Handle Uncommitted Changes
941
+ # ============================================================
942
+
943
+ if [[ "$UNCOMMITTED" == "true" ]]; then
944
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
945
+ echo " Uncommitted Changes Detected"
946
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
947
+ echo ""
948
+ echo "You have $UNCOMMITTED_COUNT uncommitted changes:"
949
+ echo ""
950
+ git status --porcelain | head -10 | sed 's/^/ /'
951
+ if [[ $UNCOMMITTED_COUNT -gt 10 ]]; then
952
+ echo " ... and $((UNCOMMITTED_COUNT - 10)) more"
953
+ fi
954
+ echo ""
955
+
956
+ # Use AskUserQuestion tool here in actual implementation
957
+ # For script, prompt directly:
958
+ echo "Options:"
959
+ echo " 1. Auto-commit (recommended)"
960
+ echo " 2. Show diff first"
961
+ echo " 3. Discard changes (⚠ cannot undo)"
962
+ echo " 4. Cancel"
963
+ echo ""
964
+ read -p "Choice [1-4]: " CHOICE
965
+
966
+ case $CHOICE in
967
+ 1)
968
+ echo "Auto-committing changes..."
969
+ git add -A
970
+ git commit -m "session: end $(date +%Y-%m-%d\ %H:%M)"
971
+ echo "✓ Changes committed"
972
+ echo ""
973
+ ;;
974
+ 2)
975
+ git diff HEAD
976
+ echo ""
977
+ echo "Commit these changes? [y/n]"
978
+ read -p "> " CONFIRM
979
+ if [[ "$CONFIRM" =~ ^[Yy] ]]; then
980
+ git add -A
981
+ git commit -m "session: end $(date +%Y-%m-%d\ %H:%M)"
982
+ echo "✓ Changes committed"
983
+ else
984
+ echo "Cancelled."
985
+ exit 0
986
+ fi
987
+ ;;
988
+ 3)
989
+ echo "⚠ WARNING: Permanently delete uncommitted changes?"
990
+ read -p "Type 'discard' to confirm: " CONFIRM
991
+ if [[ "$CONFIRM" == "discard" ]]; then
992
+ git reset --hard HEAD
993
+ git clean -fd
994
+ echo "✓ Changes discarded"
995
+ else
996
+ echo "Cancelled."
997
+ exit 0
998
+ fi
999
+ ;;
1000
+ 4)
1001
+ echo "Session still active."
1002
+ echo "Commit your changes, then run /end again."
1003
+ exit 0
1004
+ ;;
1005
+ esac
1006
+ fi
1007
+
1008
+ # ============================================================
1009
+ # STEP 4: Handle Missing Journal
1010
+ # ============================================================
1011
+
1012
+ if [[ "$JOURNAL_EXISTS" == "false" ]] && [[ $COMMIT_COUNT -gt 0 ]]; then
1013
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
1014
+ echo " Missing Journal Entry"
1015
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
1016
+ echo ""
1017
+ echo "This session has work, but no journal entry:"
1018
+ echo " • $COMMIT_COUNT commits"
1019
+ echo " • $FILES_CHANGED files changed"
1020
+ echo " • ${DURATION_HOURS}h ${DURATION_MINUTES}m duration"
1021
+ echo ""
1022
+ echo "Journal entries help future sessions understand this work."
1023
+ echo ""
1024
+ echo "Options:"
1025
+ echo " 1. Write quick entry (30 seconds)"
1026
+ echo " 2. Skip (not recommended)"
1027
+ echo ""
1028
+ read -p "Choice [1-2]: " CHOICE
1029
+
1030
+ if [[ "$CHOICE" == "1" ]]; then
1031
+ echo ""
1032
+ read -p "What did you work on? (one sentence): " TITLE
1033
+ SUMMARY="Session work"
1034
+ TS=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
1035
+ FILES=$(git diff --name-only $WORKING_BRANCH..HEAD | jq -R -s -c 'split("\n") | map(select(length > 0))')
1036
+
1037
+ mkdir -p .jfl/journal
1038
+ cat >> "$JOURNAL_FILE" << EOF
1039
+ {"v":1,"ts":"$TS","session":"$BRANCH","type":"session-end","status":"complete","title":"$TITLE","summary":"$SUMMARY","files":$FILES}
1040
+ EOF
1041
+
1042
+ echo "✓ Journal entry created"
1043
+ echo ""
1044
+ else
1045
+ echo "⚠ Proceeding without journal entry"
1046
+ echo ""
1047
+ fi
1048
+ else
1049
+ echo "✓ Journal entry exists ($JOURNAL_ENTRY_COUNT entries)"
1050
+ fi
1051
+
1052
+ if [[ "$UNCOMMITTED" == "false" ]]; then
1053
+ echo "✓ No uncommitted changes"
1054
+ fi
1055
+
1056
+ # ============================================================
1057
+ # STEP 5: Execute Cleanup
1058
+ # ============================================================
1059
+
1060
+ echo ""
1061
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
1062
+ echo " Executing Cleanup"
1063
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
1064
+ echo ""
1065
+
1066
+ # Create logs directory
1067
+ mkdir -p .jfl/logs
1068
+
1069
+ # Run session-cleanup.sh and capture output
1070
+ ./scripts/session/session-cleanup.sh 2>&1 | tee .jfl/logs/session-cleanup.log | while IFS= read -r line; do
1071
+ # Filter to show only key steps
1072
+ if [[ "$line" =~ ^✓ ]] || [[ "$line" =~ ^⚠ ]] || [[ "$line" =~ "Merged" ]] || [[ "$line" =~ "Pushed" ]] || [[ "$line" =~ "Removing" ]] || [[ "$line" =~ "Deleting" ]]; then
1073
+ echo " $line"
1074
+ fi
1075
+ done
1076
+
1077
+ EXIT_CODE=${PIPESTATUS[0]}
1078
+
1079
+ # ============================================================
1080
+ # STEP 5.5: Sync to GTM (if in service)
1081
+ # ============================================================
1082
+
1083
+ if [[ "$SYNC_TO_GTM" == "true" && -n "$GTM_PARENT" ]]; then
1084
+ echo ""
1085
+ echo "📡 Syncing to GTM workspace..."
1086
+
1087
+ # Validate GTM parent exists
1088
+ if [[ ! -d "$GTM_PARENT" ]]; then
1089
+ echo "⚠️ GTM parent not found: $GTM_PARENT"
1090
+ echo "Skipping sync. Session cleaned up locally."
1091
+ else
1092
+ # Validate it's actually a GTM
1093
+ GTM_TYPE=$(jq -r '.type // empty' "$GTM_PARENT/.jfl/config.json" 2>/dev/null)
1094
+ if [[ "$GTM_TYPE" != "gtm" ]]; then
1095
+ echo "⚠️ Parent is not a GTM workspace (type: $GTM_TYPE)"
1096
+ echo "Skipping sync. Session cleaned up locally."
1097
+ else
1098
+ # 1. Sync journal entries
1099
+ mkdir -p "$GTM_PARENT/.jfl/journal"
1100
+
1101
+ SYNCED_COUNT=0
1102
+ for journal in .jfl/journal/*.jsonl; do
1103
+ if [[ -f "$journal" ]]; then
1104
+ BASENAME=$(basename "$journal")
1105
+ TARGET="$GTM_PARENT/.jfl/journal/service-${SERVICE_NAME}-${BASENAME}"
1106
+
1107
+ # Copy journal with preserved permissions
1108
+ cp "$journal" "$TARGET"
1109
+ ((SYNCED_COUNT++))
1110
+ echo " ✓ Synced: $BASENAME"
1111
+ fi
1112
+ done
1113
+
1114
+ # 2. Update GTM's last_sync timestamp
1115
+ cd "$GTM_PARENT"
1116
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
1117
+
1118
+ # Use jq to update the timestamp (create registered_services if needed)
1119
+ jq --arg name "$SERVICE_NAME" \
1120
+ --arg ts "$TIMESTAMP" \
1121
+ '(.registered_services // []) |= (
1122
+ if any(.name == $name) then
1123
+ map(if .name == $name then .last_sync = $ts else . end)
1124
+ else
1125
+ . + [{"name": $name, "last_sync": $ts}]
1126
+ end
1127
+ )' \
1128
+ .jfl/config.json > .jfl/config.json.tmp && \
1129
+ mv .jfl/config.json.tmp .jfl/config.json
1130
+
1131
+ # 3. Create sync entry in GTM journal
1132
+ GTM_SESSION=$(git branch --show-current 2>/dev/null || echo "main")
1133
+ GTM_JOURNAL=".jfl/journal/${GTM_SESSION}.jsonl"
1134
+
1135
+ cat >> "$GTM_JOURNAL" << EOF
1136
+ {"v":1,"ts":"$TIMESTAMP","session":"$GTM_SESSION","type":"sync","title":"Service sync: $SERVICE_NAME","summary":"Synced $SYNCED_COUNT journal file(s) from $SERVICE_NAME","service":"$SERVICE_NAME","files_synced":$SYNCED_COUNT}
1137
+ EOF
1138
+
1139
+ echo " ✓ Updated GTM registry"
1140
+ echo ""
1141
+ echo "✅ Sync complete ($SYNCED_COUNT journal file(s) → GTM)"
1142
+ fi
1143
+ fi
1144
+ fi
1145
+
1146
+ # ============================================================
1147
+ # STEP 6: Report Results
1148
+ # ============================================================
1149
+
1150
+ echo ""
1151
+
1152
+ if [[ $EXIT_CODE -eq 0 ]]; then
1153
+ # Check if merge happened or if conflicts remained
1154
+ if grep -q "Merge conflicts remain" .jfl/logs/session-cleanup.log; then
1155
+ # Conflicts - branch preserved
1156
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
1157
+ echo " Merge Conflicts Detected"
1158
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
1159
+ echo ""
1160
+ echo "Conflicts in:"
1161
+ grep "Cannot auto-resolve:" .jfl/logs/session-cleanup.log | sed 's/^.*: / • /'
1162
+ echo ""
1163
+ echo "Your session branch has been preserved: $BRANCH"
1164
+ echo ""
1165
+ echo "To resolve manually:"
1166
+ echo ""
1167
+ echo "1. Review changes:"
1168
+ echo " git log $WORKING_BRANCH..$BRANCH"
1169
+ echo ""
1170
+ echo "2. Merge manually:"
1171
+ echo " git checkout $WORKING_BRANCH"
1172
+ echo " git merge $BRANCH"
1173
+ echo ""
1174
+ echo "3. Resolve conflicts in your editor"
1175
+ echo ""
1176
+ echo "4. Complete merge:"
1177
+ echo " git add ."
1178
+ echo " git commit"
1179
+ echo " git push origin $WORKING_BRANCH"
1180
+ echo ""
1181
+ echo "5. Delete session branch:"
1182
+ echo " git branch -D $BRANCH"
1183
+ echo ""
1184
+ echo "Need help? Ask Claude to guide you through conflict resolution."
1185
+ else
1186
+ # Success - show synopsis
1187
+ echo "✓ Session ended successfully"
1188
+
1189
+ # ============================================================
1190
+ # STEP 7: Show Synopsis
1191
+ # ============================================================
1192
+
1193
+ echo ""
1194
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
1195
+ echo " Work Summary (${DURATION_HOURS}h ${DURATION_MINUTES}m session)"
1196
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
1197
+ echo ""
1198
+
1199
+ # Round up duration for synopsis
1200
+ SYNOPSIS_HOURS=$((DURATION_HOURS + 1))
1201
+ if [[ $SYNOPSIS_HOURS -lt 1 ]]; then
1202
+ SYNOPSIS_HOURS=1
1203
+ fi
1204
+
1205
+ # Run synopsis command
1206
+ if command -v jfl >/dev/null 2>&1; then
1207
+ jfl synopsis $SYNOPSIS_HOURS 2>/dev/null || echo "Synopsis not available (jfl command not found or synopsis failed)"
1208
+ else
1209
+ echo "Synopsis not available (jfl command not in PATH)"
1210
+ fi
1211
+
1212
+ echo ""
1213
+ echo "✓ All changes merged to $WORKING_BRANCH and pushed to origin"
1214
+ fi
1215
+ else
1216
+ # Generic failure
1217
+ echo "⚠ Session cleanup encountered issues"
1218
+ echo ""
1219
+ echo "Check the log for details:"
1220
+ echo " cat .jfl/logs/session-cleanup.log"
1221
+ echo ""
1222
+ echo "Your session branch is preserved: $BRANCH"
1223
+ echo "No work has been lost."
1224
+ echo ""
1225
+ echo "Common issues:"
1226
+ echo " • Push failed → retry: git push origin $WORKING_BRANCH"
1227
+ echo " • Merge conflicts → see conflict resolution steps above"
1228
+ echo " • Other errors → check log and ask for help"
1229
+ fi
1230
+
1231
+ echo ""
1232
+ ```
1233
+
1234
+ ---
1235
+
1236
+ ## Error Handling
1237
+
1238
+ ### Error Pattern 1: Not in a Session
1239
+
1240
+ **Detection:**
1241
+ ```bash
1242
+ if [[ ! "$BRANCH" =~ ^session- ]]; then
1243
+ # Not in a session
1244
+ fi
1245
+ ```
1246
+
1247
+ **Message:**
1248
+ ```
1249
+ ⚠ Not in a JFL session
1250
+
1251
+ Current branch: main
1252
+
1253
+ You're already on your working branch.
1254
+ Session branches start with 'session-'.
1255
+
1256
+ No cleanup needed.
1257
+ ```
1258
+
1259
+ **Recovery:** None needed, gracefully exit.
1260
+
1261
+ ### Error Pattern 2: Cleanup Script Fails
1262
+
1263
+ **Detection:**
1264
+ ```bash
1265
+ EXIT_CODE=${PIPESTATUS[0]}
1266
+ if [[ $EXIT_CODE -ne 0 ]]; then
1267
+ # Cleanup failed
1268
+ fi
1269
+ ```
1270
+
1271
+ **Message:**
1272
+ ```
1273
+ ⚠ Session cleanup encountered issues
1274
+
1275
+ Check the log for details:
1276
+ cat .jfl/logs/session-cleanup.log
1277
+
1278
+ Your session branch is preserved: session-goose-20260210-1430-a1b2c3
1279
+ No work has been lost.
1280
+
1281
+ Common issues:
1282
+ • Push failed → retry: git push origin main
1283
+ • Merge conflicts → see conflict resolution guide
1284
+ • Other errors → share log with Claude for help
1285
+ ```
1286
+
1287
+ **Recovery:** Guide user to check log, provide common solutions.
1288
+
1289
+ ### Error Pattern 3: Push Fails
1290
+
1291
+ **Detection:**
1292
+ ```bash
1293
+ if grep -q "Push failed" .jfl/logs/session-cleanup.log; then
1294
+ # Push to remote failed
1295
+ fi
1296
+ ```
1297
+
1298
+ **Message:**
1299
+ ```
1300
+ ✓ Merged to main locally
1301
+ ⚠ Push to origin failed
1302
+
1303
+ Your work is merged locally but not on GitHub yet.
1304
+
1305
+ To retry push:
1306
+ git push origin main
1307
+
1308
+ Common causes:
1309
+ • No network connection
1310
+ • Remote has new commits → fetch and merge first
1311
+ • Authentication issue → check git credentials
1312
+ ```
1313
+
1314
+ **Recovery:** Provide retry command, list common causes.
1315
+
1316
+ ### Error Pattern 4: Synopsis Command Fails
1317
+
1318
+ **Detection:**
1319
+ ```bash
1320
+ if ! jfl synopsis $HOURS 2>/dev/null; then
1321
+ # Synopsis failed
1322
+ fi
1323
+ ```
1324
+
1325
+ **Handling:**
1326
+ ```bash
1327
+ # Don't fail the entire skill if synopsis fails
1328
+ jfl synopsis $HOURS 2>/dev/null || echo "Synopsis not available"
1329
+ ```
1330
+
1331
+ **Message:**
1332
+ ```
1333
+ Synopsis not available (jfl command failed)
1334
+
1335
+ But your session ended successfully:
1336
+ ✓ Merged to main
1337
+ ✓ Pushed to origin
1338
+ ```
1339
+
1340
+ **Recovery:** Session end still successful, synopsis is nice-to-have.
1341
+
1342
+ ### Error Pattern 5: Journal Write Fails
1343
+
1344
+ **Detection:**
1345
+ ```bash
1346
+ if ! cat >> "$JOURNAL_FILE" << EOF ...; then
1347
+ # Journal write failed
1348
+ fi
1349
+ ```
1350
+
1351
+ **Handling:**
1352
+ ```bash
1353
+ # Try to write journal, but don't block session end if it fails
1354
+ if ! cat >> "$JOURNAL_FILE" << EOF
1355
+ ...
1356
+ EOF
1357
+ then
1358
+ echo "⚠ Failed to write journal entry (file permissions?)"
1359
+ echo "Continuing with session end anyway..."
1360
+ fi
1361
+ ```
1362
+
1363
+ **Message:**
1364
+ ```
1365
+ ⚠ Failed to write journal entry
1366
+
1367
+ Possible causes:
1368
+ • .jfl/journal/ directory doesn't exist
1369
+ • Permission issue
1370
+
1371
+ Session ending anyway (journal is recommended but not required).
1372
+ ```
1373
+
1374
+ **Recovery:** Session ends, user can manually add journal later.
1375
+
1376
+ ---
1377
+
1378
+ ## Synopsis Integration
1379
+
1380
+ **Always run synopsis after successful session end.** This provides handoff context for future sessions.
1381
+
1382
+ ### Calculating Duration
1383
+
1384
+ ```bash
1385
+ # Get first commit timestamp in session
1386
+ SESSION_START=$(git log --format=%ct --reverse $WORKING_BRANCH..HEAD 2>/dev/null | head -1)
1387
+
1388
+ if [[ -n "$SESSION_START" ]]; then
1389
+ NOW=$(date +%s)
1390
+ DURATION_SECONDS=$((NOW - SESSION_START))
1391
+ DURATION_HOURS=$((DURATION_SECONDS / 3600))
1392
+ DURATION_MINUTES=$(((DURATION_SECONDS % 3600) / 60))
1393
+ else
1394
+ # No commits yet (shouldn't happen at session end, but handle gracefully)
1395
+ DURATION_HOURS=0
1396
+ DURATION_MINUTES=0
1397
+ fi
1398
+
1399
+ # Round up for synopsis (show at least last hour)
1400
+ SYNOPSIS_HOURS=$((DURATION_HOURS + 1))
1401
+ if [[ $SYNOPSIS_HOURS -lt 1 ]]; then
1402
+ SYNOPSIS_HOURS=1
1403
+ fi
1404
+ ```
1405
+
1406
+ ### Calling Synopsis
1407
+
1408
+ ```bash
1409
+ echo ""
1410
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
1411
+ echo " Work Summary (${DURATION_HOURS}h ${DURATION_MINUTES}m session)"
1412
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
1413
+ echo ""
1414
+
1415
+ # Call jfl synopsis command
1416
+ if command -v jfl >/dev/null 2>&1; then
1417
+ jfl synopsis $SYNOPSIS_HOURS 2>/dev/null || {
1418
+ echo "Synopsis command failed"
1419
+ echo ""
1420
+ echo "Manual summary:"
1421
+ echo " Commits: $COMMIT_COUNT"
1422
+ echo " Files: $FILES_CHANGED"
1423
+ echo " Lines: +$LINES_ADDED / -$LINES_REMOVED"
1424
+ echo ""
1425
+ git log --oneline $WORKING_BRANCH..HEAD~10 2>/dev/null | head -10
1426
+ }
1427
+ else
1428
+ echo "Synopsis not available (jfl not in PATH)"
1429
+ echo ""
1430
+ echo "Manual summary:"
1431
+ echo " Commits: $COMMIT_COUNT"
1432
+ echo " Files: $FILES_CHANGED"
1433
+ echo " Lines: +$LINES_ADDED / -$LINES_REMOVED"
1434
+ echo ""
1435
+ echo "Recent commits:"
1436
+ git log --oneline $WORKING_BRANCH..HEAD~10 2>/dev/null | head -10
1437
+ fi
1438
+ ```
1439
+
1440
+ ### Fallback if Synopsis Unavailable
1441
+
1442
+ If `jfl synopsis` fails, show manual summary:
1443
+
1444
+ ```
1445
+ Manual summary:
1446
+ Commits: 8
1447
+ Files: 12
1448
+ Lines: +234 / -67
1449
+
1450
+ Recent commits:
1451
+ a1b2c3d feat: add session manager
1452
+ e4f5g6h fix: auth token refresh
1453
+ i7j8k9l docs: update README
1454
+ m1n2o3p style: format code
1455
+ ...
1456
+ ```
1457
+
1458
+ ---
1459
+
1460
+ ## Integration Points
1461
+
1462
+ ### 1. session-cleanup.sh
1463
+
1464
+ **Location:** `scripts/session/session-cleanup.sh`
1465
+
1466
+ **What it does:**
1467
+ - Stops background processes (auto-commit, context-hub)
1468
+ - Auto-commits uncommitted changes
1469
+ - Detects worktree vs direct mode
1470
+ - Pre-merge cleanup (removes session metadata)
1471
+ - Merges session branch to working branch with `-X ours`
1472
+ - Auto-resolves common conflicts (.jfl files, submodules)
1473
+ - Pushes to remote
1474
+ - Removes worktrees and deletes session branches
1475
+ - Notifies jfl-services API
1476
+
1477
+ **How skill uses it:**
1478
+ - Calls it after pre-flight checks and user prompts
1479
+ - Captures output to show key steps
1480
+ - Parses exit code and output for error handling
1481
+ - Logs full output to `.jfl/logs/session-cleanup.log`
1482
+
1483
+ ### 2. Journal System
1484
+
1485
+ **Location:** `.jfl/journal/*.jsonl`
1486
+
1487
+ **Format:** One JSON object per line (JSONL)
1488
+
1489
+ **Example entry:**
1490
+ ```json
1491
+ {
1492
+ "v": 1,
1493
+ "ts": "2026-02-10T14:30:00.000Z",
1494
+ "session": "session-goose-20260210-1430-a1b2c3",
1495
+ "type": "session-end",
1496
+ "status": "complete",
1497
+ "title": "Session management enhancements",
1498
+ "summary": "Enhanced /end skill with comprehensive UX",
1499
+ "files": ["SKILL.md", "session-cleanup.sh"]
1500
+ }
1501
+ ```
1502
+
1503
+ **How skill uses it:**
1504
+ - Checks if file exists: `[[ -s ".jfl/journal/${BRANCH}.jsonl" ]]`
1505
+ - Counts entries: `wc -l < "$JOURNAL_FILE"`
1506
+ - Warns if missing and offers to create
1507
+ - Creates minimal entry if user agrees
1508
+
1509
+ ### 3. Synopsis Command
1510
+
1511
+ **Location:** `src/commands/synopsis.ts` (TypeScript)
1512
+
1513
+ **Usage:** `jfl synopsis [hours] [author]`
1514
+
1515
+ **What it returns:**
1516
+ - Journal entries from all sessions/worktrees
1517
+ - Git commits from all branches
1518
+ - File headers (@purpose, @spec tags)
1519
+ - Time audit with category breakdown
1520
+ - Health checks and next steps
1521
+
1522
+ **How skill uses it:**
1523
+ - Called after successful cleanup
1524
+ - Duration calculated from session start time
1525
+ - Rounds up to next hour (e.g., 2h 15m → 3 hours)
1526
+ - Fallback to manual summary if command fails
1527
+
1528
+ ### 4. Session State Files
1529
+
1530
+ **Location:** `.jfl/`
1531
+
1532
+ | File | Purpose |
1533
+ |------|---------|
1534
+ | `current-session-branch.txt` | Current session branch name |
1535
+ | `current-worktree.txt` | Worktree path or "direct" |
1536
+ | `config.json` | Project config (working_branch, etc.) |
1537
+ | `logs/session-cleanup.log` | Last cleanup output |
1538
+
1539
+ **How skill uses it:**
1540
+ - Reads to detect mode and branch info
1541
+ - Used by pre-flight check
1542
+ - cleanup.sh removes metadata files before merge
1543
+
1544
+ ### 5. Working Branch Config
1545
+
1546
+ **Location:** `.jfl/config.json`
1547
+
1548
+ **Format:**
1549
+ ```json
1550
+ {
1551
+ "name": "project-name",
1552
+ "working_branch": "develop"
1553
+ }
1554
+ ```
1555
+
1556
+ **How skill uses it:**
1557
+ - Reads working_branch (defaults to "main")
1558
+ - Shows in summary: "Merging to: develop"
1559
+ - Passed to session-cleanup.sh
1560
+
1561
+ ---
1562
+
1563
+ ## Dependencies & Testing
1564
+
1565
+ ### Required Commands
1566
+
1567
+ The skill requires these commands to be available:
1568
+
1569
+ | Command | Purpose | Fallback if Missing |
1570
+ |---------|---------|-------------------|
1571
+ | `git` | Version control | **REQUIRED** - skill cannot run |
1572
+ | `jq` | JSON parsing | Use sed/awk for simple parsing |
1573
+ | `jfl` | Synopsis command | Show manual summary |
1574
+ | `bash` | Shell execution | **REQUIRED** - skill runs in bash |
1575
+
1576
+ **Checking dependencies:**
1577
+
1578
+ ```bash
1579
+ # Check git
1580
+ if ! command -v git >/dev/null 2>&1; then
1581
+ echo "Error: git is required"
1582
+ exit 1
1583
+ fi
1584
+
1585
+ # Check jq (optional but recommended)
1586
+ if ! command -v jq >/dev/null 2>&1; then
1587
+ echo "Warning: jq not found, using basic parsing"
1588
+ USE_JQ=false
1589
+ else
1590
+ USE_JQ=true
1591
+ fi
1592
+
1593
+ # Check jfl (optional)
1594
+ if ! command -v jfl >/dev/null 2>&1; then
1595
+ echo "Warning: jfl not found, synopsis unavailable"
1596
+ USE_SYNOPSIS=false
1597
+ else
1598
+ USE_SYNOPSIS=true
1599
+ fi
1600
+ ```
1601
+
1602
+ ### Required Files
1603
+
1604
+ | File | Purpose | What if Missing |
1605
+ |------|---------|----------------|
1606
+ | `scripts/session/session-cleanup.sh` | Core cleanup | **CRITICAL** - skill fails |
1607
+ | `.jfl/config.json` | Working branch | Use "main" as default |
1608
+ | `.jfl/current-session-branch.txt` | Session info | Read from git |
1609
+
1610
+ ### Testing Checklist
1611
+
1612
+ Test these scenarios to verify the skill works correctly:
1613
+
1614
+ #### 1. Happy Path (Clean State)
1615
+ - [ ] No uncommitted changes
1616
+ - [ ] Journal entry exists
1617
+ - [ ] Merges cleanly to working branch
1618
+ - [ ] Pushes to origin successfully
1619
+ - [ ] Shows synopsis
1620
+ - [ ] Success message displayed
1621
+
1622
+ #### 2. Uncommitted Changes → Auto-commit
1623
+ - [ ] Make changes without committing
1624
+ - [ ] Choose "auto-commit" option
1625
+ - [ ] Changes committed automatically
1626
+ - [ ] Merge succeeds
1627
+ - [ ] Synopsis shows all work
1628
+
1629
+ #### 3. Uncommitted Changes → Show Diff
1630
+ - [ ] Make changes without committing
1631
+ - [ ] Choose "show diff" option
1632
+ - [ ] Diff displayed correctly
1633
+ - [ ] Prompted for next action
1634
+ - [ ] Can commit or cancel
1635
+
1636
+ #### 4. Uncommitted Changes → Discard
1637
+ - [ ] Make changes without committing
1638
+ - [ ] Choose "discard" option
1639
+ - [ ] Warning shown
1640
+ - [ ] Confirmation required
1641
+ - [ ] Changes discarded (verified)
1642
+ - [ ] Merge proceeds
1643
+
1644
+ #### 5. Uncommitted Changes → Cancel
1645
+ - [ ] Make changes without committing
1646
+ - [ ] Choose "cancel" option
1647
+ - [ ] Session stays active
1648
+ - [ ] No cleanup performed
1649
+ - [ ] Can continue working
1650
+
1651
+ #### 6. No Journal → Write Entry
1652
+ - [ ] End session without journal
1653
+ - [ ] Prompted to write entry
1654
+ - [ ] Choose "write entry"
1655
+ - [ ] Provide title
1656
+ - [ ] Entry created (verified in .jfl/journal/)
1657
+ - [ ] Merge proceeds
1658
+
1659
+ #### 7. No Journal → Skip
1660
+ - [ ] End session without journal
1661
+ - [ ] Prompted to write entry
1662
+ - [ ] Choose "skip"
1663
+ - [ ] Warning shown
1664
+ - [ ] Merge proceeds anyway
1665
+
1666
+ #### 8. Worktree Mode
1667
+ - [ ] Start second concurrent session (creates worktree)
1668
+ - [ ] Make commits in worktree
1669
+ - [ ] End worktree session
1670
+ - [ ] Worktree removed (verified)
1671
+ - [ ] Branch deleted
1672
+ - [ ] Main repo untouched
1673
+
1674
+ #### 9. Direct Mode
1675
+ - [ ] Start single session (no worktree)
1676
+ - [ ] Make commits
1677
+ - [ ] End session
1678
+ - [ ] Merges on same branch
1679
+ - [ ] No worktree cleanup needed
1680
+
1681
+ #### 10. Merge Conflicts
1682
+ - [ ] Create intentional conflict (modify same line in session and working branch)
1683
+ - [ ] End session
1684
+ - [ ] Conflicts detected
1685
+ - [ ] Branch preserved (not deleted)
1686
+ - [ ] Clear resolution guidance shown
1687
+ - [ ] Can resolve manually
1688
+
1689
+ #### 11. Synopsis Display
1690
+ - [ ] Work for 10+ minutes
1691
+ - [ ] Make several commits
1692
+ - [ ] Write journal entries
1693
+ - [ ] End session
1694
+ - [ ] Synopsis shows commits, files, journal entries
1695
+ - [ ] Time breakdown displayed
1696
+
1697
+ #### 12. Not in Session
1698
+ - [ ] Checkout main branch manually
1699
+ - [ ] Try to invoke /end
1700
+ - [ ] Graceful message shown
1701
+ - [ ] Explains not in session
1702
+ - [ ] No errors thrown
1703
+
1704
+ ### Success Criteria
1705
+
1706
+ The skill is working correctly if:
1707
+
1708
+ - ✅ All 12 test scenarios pass
1709
+ - ✅ User always knows what's happening at each step
1710
+ - ✅ No work is lost in any scenario
1711
+ - ✅ Error messages provide clear recovery steps
1712
+ - ✅ Synopsis integrates cleanly after successful cleanup
1713
+ - ✅ Session ends in < 30 seconds (without conflicts)
1714
+ - ✅ Journal compliance encouraged without being blocking
1715
+
1716
+ ---
1717
+
1718
+ ## Notes for Claude
1719
+
1720
+ ### When to Invoke This Skill
1721
+
1722
+ **Immediate invocation (HIGH CONFIDENCE):**
1723
+ - User says "done", "that's it", "I'm finished", "end session", "/end"
1724
+ - User says "wrap up", "all set", "good for now" in concluding context
1725
+
1726
+ **Check context first:**
1727
+ - User says "thanks", "looks good", "perfect" → Is this end of session or just task?
1728
+ - If unclear, ask: "Ready to end the session, or keep working?"
1729
+
1730
+ ### What You Should Do
1731
+
1732
+ When you invoke this skill:
1733
+
1734
+ 1. **Don't run commands yourself** - The skill script handles everything
1735
+ 2. **Present prompts to user** - Use AskUserQuestion for uncommitted/journal decisions
1736
+ 3. **Parse script output** - Show key steps, not full git output
1737
+ 4. **Guide on errors** - If conflicts, walk user through resolution
1738
+ 5. **Always show synopsis** - User chose "always show" preference
1739
+
1740
+ ### What You Should NOT Do
1741
+
1742
+ - ❌ Don't manually run `git commit`, `git merge`, etc. - Let the script do it
1743
+ - ❌ Don't skip uncommitted change check - User must decide what to do
1744
+ - ❌ Don't force journal entries - Encourage but allow skip
1745
+ - ❌ Don't hide errors - Parse and explain clearly
1746
+
1747
+ ### User Preferences (From Plan)
1748
+
1749
+ | Setting | User Choice | How to Handle |
1750
+ |---------|-------------|---------------|
1751
+ | Synopsis | Always show | Run synopsis after every session end |
1752
+ | Journal | Warn if missing | Prompt to write or skip, don't block |
1753
+ | Verbosity | Balanced | Show summary + key steps, not full output |
1754
+ | Auto-commit | Prompt | Ask what to do with uncommitted changes |
1755
+
1756
+ ### Common User Questions
1757
+
1758
+ **"Did my work get saved?"**
1759
+ → Yes! Show what merged: "✓ 8 commits, 12 files merged to main and pushed"
1760
+
1761
+ **"What if I made a mistake?"**
1762
+ → On main, you can: `git revert <commit>` or `git reset --hard HEAD~1` (before push)
1763
+
1764
+ **"Can I undo the session end?"**
1765
+ → If merge happened: No, but commits are on main, can revert. If conflicts: Yes, branch preserved.
1766
+
1767
+ **"Where did my session branch go?"**
1768
+ → Deleted after successful merge (work is on main now). If conflicts: Preserved for manual resolution.
1769
+
1770
+ ---
1771
+
1772
+ ## Summary
1773
+
1774
+ This skill provides comprehensive UX orchestration for session ending:
1775
+
1776
+ 1. ✅ **Pre-flight checks** - Gather complete state (mode, branches, uncommitted, journal, work stats)
1777
+ 2. ✅ **User prompts** - Handle uncommitted changes and missing journal gracefully
1778
+ 3. ✅ **Execute cleanup** - Call session-cleanup.sh with clear progress display
1779
+ 4. ✅ **Error handling** - Guide user through conflicts and failures
1780
+ 5. ✅ **Synopsis** - Always show work summary for handoff context
1781
+
1782
+ **Key principle:** Wrap solid infrastructure (session-cleanup.sh) with excellent UX.