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
@@ -38,6 +38,38 @@ jobs:
38
38
  - name: Build
39
39
  run: npx tsc --build --noEmit
40
40
 
41
+ - name: Predict eval delta (Stratus, optional)
42
+ id: predict
43
+ if: env.STRATUS_API_KEY != ''
44
+ continue-on-error: true
45
+ env:
46
+ STRATUS_API_KEY: ${{ secrets.STRATUS_API_KEY }}
47
+ PR_TITLE: ${{ github.event.pull_request.title }}
48
+ run: |
49
+ DIFF_SUMMARY=$(git diff origin/main...HEAD --stat | tail -5)
50
+ CURRENT_SCORE=$(cat .jfl/eval.jsonl 2>/dev/null | tail -1 | node -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{console.log(JSON.parse(d).composite||0)}catch{console.log(0)}})" 2>/dev/null || echo "0")
51
+
52
+ RESULT=$(node -e "
53
+ const { Predictor } = require('./dist/lib/predictor.js');
54
+ const p = new Predictor();
55
+ p.predict({
56
+ proposal: { description: '$PR_TITLE — $DIFF_SUMMARY', change_type: 'fix', scope: 'medium' },
57
+ current_score: $CURRENT_SCORE,
58
+ goal: 'test_pass_rate >= 1.0',
59
+ recent_trajectory: [],
60
+ }).then(r => {
61
+ console.log(JSON.stringify({id: r.prediction_id, delta: r.predicted_delta, confidence: r.confidence, recommendation: r.recommendation}));
62
+ }).catch(e => {
63
+ console.error('Prediction failed:', e.message);
64
+ console.log(JSON.stringify({id: '', delta: 0, confidence: 0, recommendation: 'revise'}));
65
+ });
66
+ " 2>/dev/null || echo '{"id":"","delta":0,"confidence":0,"recommendation":"revise"}')
67
+
68
+ echo "prediction_id=$(echo "$RESULT" | node -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{console.log(JSON.parse(d).id)}catch{console.log('')}})")" >> $GITHUB_OUTPUT
69
+ echo "predicted_delta=$(echo "$RESULT" | node -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{console.log(JSON.parse(d).delta)}catch{console.log(0)}})")" >> $GITHUB_OUTPUT
70
+ echo "confidence=$(echo "$RESULT" | node -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{console.log(JSON.parse(d).confidence)}catch{console.log(0)}})")" >> $GITHUB_OUTPUT
71
+ echo "recommendation=$(echo "$RESULT" | node -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{console.log(JSON.parse(d).recommendation)}catch{console.log('revise')}})")" >> $GITHUB_OUTPUT
72
+
41
73
  - name: Run tests (baseline from main)
42
74
  id: baseline
43
75
  run: |
@@ -129,6 +161,24 @@ jobs:
129
161
  echo "tests_passing_added=$TESTS_PASSING_ADDED" >> $GITHUB_OUTPUT
130
162
  echo "Delta: $DELTA, tests_added=$TESTS_ADDED (improved=$IMPROVED)"
131
163
 
164
+ - name: Resolve prediction (Stratus, optional)
165
+ if: steps.predict.outputs.prediction_id != ''
166
+ continue-on-error: true
167
+ env:
168
+ STRATUS_API_KEY: ${{ secrets.STRATUS_API_KEY }}
169
+ run: |
170
+ PRED_ID="${{ steps.predict.outputs.prediction_id }}"
171
+ DELTA=${{ steps.delta.outputs.delta }}
172
+ PR_SCORE=${{ steps.pr_eval.outputs.score }}
173
+
174
+ node -e "
175
+ const { Predictor } = require('./dist/lib/predictor.js');
176
+ const p = new Predictor();
177
+ p.resolve('$PRED_ID', $DELTA, $PR_SCORE, '${{ github.run_id }}')
178
+ .then(() => console.log('Prediction resolved: $PRED_ID'))
179
+ .catch(e => console.error('Resolve failed:', e.message));
180
+ " 2>/dev/null || echo "Warning: could not resolve prediction"
181
+
132
182
  - name: AI quality assessment
133
183
  id: ai_eval
134
184
  env:
@@ -263,6 +313,23 @@ jobs:
263
313
  }
264
314
  " >> $GITHUB_OUTPUT
265
315
 
316
+ - name: Detect agent from branch
317
+ id: agent
318
+ run: |
319
+ BRANCH="${{ github.head_ref }}"
320
+ # Extract agent from branch prefix: pp/* → peter-parker, bot/* → bot, etc.
321
+ if [[ "$BRANCH" == pp/* ]]; then
322
+ echo "name=peter-parker" >> $GITHUB_OUTPUT
323
+ elif [[ "$BRANCH" == bot/* ]]; then
324
+ echo "name=bot" >> $GITHUB_OUTPUT
325
+ elif [[ "$BRANCH" == agent/* ]]; then
326
+ # agent/agent-name/description → agent-name
327
+ AGENT_NAME=$(echo "$BRANCH" | cut -d'/' -f2)
328
+ echo "name=$AGENT_NAME" >> $GITHUB_OUTPUT
329
+ else
330
+ echo "name=${{ github.event.pull_request.user.login }}" >> $GITHUB_OUTPUT
331
+ fi
332
+
266
333
  - name: Commit eval entry to PR branch
267
334
  run: |
268
335
  git config user.name "github-actions[bot]"
@@ -271,18 +338,27 @@ jobs:
271
338
  # Checkout the actual PR branch (not detached HEAD)
272
339
  git checkout ${{ github.head_ref }}
273
340
 
274
- # Write eval entry
275
- mkdir -p .jfl/eval
276
- cat >> .jfl/eval/eval.jsonl << EOF
277
- {"v":1,"ts":"$(date -u +%Y-%m-%dT%H:%M:%SZ)","agent":"peter-parker","dataset":"ci-eval","metrics":{"test_pass_rate":${{ steps.pr_eval.outputs.score }},"tests_passed":${{ steps.pr_eval.outputs.passing }},"tests_total":${{ steps.pr_eval.outputs.total }}},"composite":${{ steps.pr_eval.outputs.score }},"delta":{"composite":${{ steps.delta.outputs.delta }}},"model_version":"pp-run","improved":${{ steps.delta.outputs.improved }},"pr_number":${{ github.event.pull_request.number }},"branch":"${{ github.head_ref }}"}
341
+ AGENT="${{ steps.agent.outputs.name }}"
342
+ PRED_ID="${{ steps.predict.outputs.prediction_id }}"
343
+
344
+ # Write eval entry (matches readEvals path: .jfl/eval.jsonl)
345
+ mkdir -p .jfl
346
+ cat >> .jfl/eval.jsonl << EOF
347
+ {"v":1,"ts":"$(date -u +%Y-%m-%dT%H:%M:%SZ)","agent":"$AGENT","dataset":"ci-eval","metrics":{"test_pass_rate":${{ steps.pr_eval.outputs.score }},"tests_passed":${{ steps.pr_eval.outputs.passing }},"tests_total":${{ steps.pr_eval.outputs.total }}},"composite":${{ steps.pr_eval.outputs.score }},"delta":{"composite":${{ steps.delta.outputs.delta }}},"model_version":"$AGENT-run","improved":${{ steps.delta.outputs.improved }},"pr_number":${{ github.event.pull_request.number }},"branch":"${{ github.head_ref }}","quality_score":${{ steps.ai_eval.outputs.quality_score }},"dim_correctness":${{ steps.ai_eval.outputs.dim_correctness }},"dim_coverage":${{ steps.ai_eval.outputs.dim_coverage }},"dim_architecture":${{ steps.ai_eval.outputs.dim_architecture }},"dim_value":${{ steps.ai_eval.outputs.dim_value }},"prediction_id":"$PRED_ID"}
278
348
  EOF
279
349
 
280
350
  # Write eval:scored event for hub file watcher
281
351
  cat >> .jfl/service-events.jsonl << EOF
282
- {"ts":"$(date -u +%Y-%m-%dT%H:%M:%S.000Z)","type":"eval:scored","source":"ci","data":{"agent":"peter-parker","composite":${{ steps.pr_eval.outputs.score }},"baseline":${{ steps.baseline.outputs.score }},"delta":${{ steps.delta.outputs.delta }},"improved":"${{ steps.delta.outputs.improved }}","pr_number":${{ github.event.pull_request.number }},"branch":"${{ github.head_ref }}","run_url":"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}","quality_score":${{ steps.ai_eval.outputs.quality_score }},"dim_correctness":${{ steps.ai_eval.outputs.dim_correctness }},"dim_coverage":${{ steps.ai_eval.outputs.dim_coverage }},"dim_architecture":${{ steps.ai_eval.outputs.dim_architecture }},"dim_value":${{ steps.ai_eval.outputs.dim_value }}}}
352
+ {"ts":"$(date -u +%Y-%m-%dT%H:%M:%S.000Z)","type":"eval:scored","source":"ci","data":{"agent":"$AGENT","composite":${{ steps.pr_eval.outputs.score }},"baseline":${{ steps.baseline.outputs.score }},"delta":${{ steps.delta.outputs.delta }},"improved":"${{ steps.delta.outputs.improved }}","pr_number":${{ github.event.pull_request.number }},"branch":"${{ github.head_ref }}","run_url":"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}","quality_score":${{ steps.ai_eval.outputs.quality_score }},"dim_correctness":${{ steps.ai_eval.outputs.dim_correctness }},"dim_coverage":${{ steps.ai_eval.outputs.dim_coverage }},"dim_architecture":${{ steps.ai_eval.outputs.dim_architecture }},"dim_value":${{ steps.ai_eval.outputs.dim_value }}}}
353
+ EOF
354
+
355
+ # Write training tuple for policy head
356
+ cat >> .jfl/training-buffer.jsonl << EOF
357
+ {"id":"tb_ci_${{ github.run_id }}","v":1,"ts":"$(date -u +%Y-%m-%dT%H:%M:%SZ)","agent":"$AGENT","state":{"composite_score":${{ steps.baseline.outputs.score }},"dimension_scores":{},"tests_passing":${{ steps.baseline.outputs.passing }},"tests_total":${{ steps.baseline.outputs.total }},"trajectory_length":0,"recent_deltas":[],"agent":"$AGENT"},"action":{"type":"experiment","description":"${{ github.event.pull_request.title }}","files_affected":[],"scope":"medium","branch":"${{ github.head_ref }}"},"reward":{"composite_delta":${{ steps.delta.outputs.delta }},"dimension_deltas":{},"tests_added":${{ steps.delta.outputs.tests_added }},"quality_score":${{ steps.ai_eval.outputs.quality_score }},"improved":${{ steps.delta.outputs.improved }},"prediction_error":0},"metadata":{"pr_number":${{ github.event.pull_request.number }},"branch":"${{ github.head_ref }}","eval_run_id":"${{ github.run_id }}","prediction_id":"$PRED_ID","source":"ci"}}
283
358
  EOF
284
359
 
285
- git add .jfl/eval/eval.jsonl .jfl/service-events.jsonl
360
+ git add .jfl/eval.jsonl .jfl/service-events.jsonl .jfl/training-buffer.jsonl
361
+ git add .jfl/predictions/ 2>/dev/null || true
286
362
  git commit -m "eval: scored PR #${{ github.event.pull_request.number }} (composite=${{ steps.pr_eval.outputs.score }}, delta=${{ steps.delta.outputs.delta }})"
287
363
  git push origin ${{ github.head_ref }}
288
364
 
@@ -301,7 +377,7 @@ jobs:
301
377
  "pr_url": "${{ github.event.pull_request.html_url }}",
302
378
  "branch": "${{ github.head_ref }}",
303
379
  "commit_sha": "${{ github.sha }}",
304
- "agent": "peter-parker",
380
+ "agent": "${{ steps.agent.outputs.name }}",
305
381
  "metrics": {
306
382
  "test_pass_rate": ${{ steps.pr_eval.outputs.score }},
307
383
  "test_count": ${{ steps.pr_eval.outputs.total }},
@@ -350,6 +426,27 @@ jobs:
350
426
  const dimArchitecture = '${{ steps.ai_eval.outputs.dim_architecture }}' || '—';
351
427
  const dimValue = '${{ steps.ai_eval.outputs.dim_value }}' || '—';
352
428
 
429
+ // Prediction data (optional)
430
+ const predId = '${{ steps.predict.outputs.prediction_id }}' || '';
431
+ const predDelta = parseFloat('${{ steps.predict.outputs.predicted_delta }}') || 0;
432
+ const predConf = parseFloat('${{ steps.predict.outputs.confidence }}') || 0;
433
+ const predRec = '${{ steps.predict.outputs.recommendation }}' || '';
434
+
435
+ const predictionSection = predId ? [
436
+ '',
437
+ `### Stratus Prediction`,
438
+ '',
439
+ `| Metric | Value |`,
440
+ `|--------|-------|`,
441
+ `| Predicted delta | ${predDelta >= 0 ? '+' : ''}${predDelta.toFixed(4)} |`,
442
+ `| Actual delta | ${delta >= 0 ? '+' : ''}${delta.toFixed(4)} |`,
443
+ `| Prediction error | ${Math.abs(predDelta - delta).toFixed(4)} |`,
444
+ `| Confidence | ${Math.round(predConf * 100)}% |`,
445
+ `| Recommendation | ${predRec} |`,
446
+ `| Direction correct | ${(predDelta >= 0) === (delta >= 0) ? ':white_check_mark:' : ':x:'} |`,
447
+ '',
448
+ ] : [];
449
+
353
450
  const body = [
354
451
  `## JFL Eval Results ${emoji}`,
355
452
  '',
@@ -369,7 +466,7 @@ jobs:
369
466
  `| Value | ${dimValue} |`,
370
467
  '',
371
468
  `> ${qualityReason}`,
372
- '',
469
+ ...predictionSection,
373
470
  `**Verdict: ${verdict}**`,
374
471
  '',
375
472
  improved
@@ -327,6 +327,10 @@ jobs:
327
327
  echo "Red findings detected — requesting changes"
328
328
  gh pr review ${{ github.event.pull_request.number }} --request-changes \
329
329
  --body "JFL AI Review: ${{ steps.findings.outputs.red_count }} blocker(s) found. Address red findings before merge."
330
+ else
331
+ echo "No blockers — approving (dismisses any previous CHANGES_REQUESTED)"
332
+ gh pr review ${{ github.event.pull_request.number }} --approve \
333
+ --body "JFL AI Review: Clean. No blockers found."
330
334
  fi
331
335
 
332
336
  - name: Post review:findings event to hub
@@ -12,6 +12,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
12
  PROJECT_ROOT="$(pwd)"
13
13
  LOG_DIR="$PROJECT_ROOT/.jfl/logs"
14
14
  SESSION_FILE="$PROJECT_ROOT/.jfl/current-session.json"
15
+ LOCK_SCRIPT="$SCRIPT_DIR/session-lock.sh"
15
16
 
16
17
  # Colors
17
18
  RED='\033[0;31m'
@@ -56,10 +57,32 @@ if [ -f "$SESSION_FILE" ]; then
56
57
  fi
57
58
  fi
58
59
 
60
+ SESSION_ID=""
61
+ if [ -f "$PROJECT_ROOT/.jfl/current-session-branch.txt" ]; then
62
+ SESSION_ID=$(cat "$PROJECT_ROOT/.jfl/current-session-branch.txt" 2>/dev/null || echo "")
63
+ fi
64
+
65
+ # Stop heartbeat daemon
66
+ stop_heartbeat() {
67
+ local pid_file="$1"
68
+ if [ -f "$pid_file" ]; then
69
+ local hb_pid
70
+ hb_pid=$(cat "$pid_file" 2>/dev/null || echo "")
71
+ if [ -n "$hb_pid" ]; then
72
+ kill "$hb_pid" 2>/dev/null || true
73
+ fi
74
+ rm -f "$pid_file"
75
+ fi
76
+ }
77
+
59
78
  if $IS_WORKTREE && [ -n "$SESSION_NAME" ] && [ "$SESSION_NAME" != "main" ] && [ "$SESSION_NAME" != "null" ]; then
60
79
  echo -e "${BLUE}→${NC} Ending worktree session: $SESSION_NAME"
61
80
  echo ""
62
81
 
82
+ # Stop heartbeat
83
+ stop_heartbeat "$WORKTREE_PATH/.jfl/heartbeat.pid"
84
+ stop_heartbeat "$PROJECT_ROOT/.jfl/heartbeat.pid"
85
+
63
86
  # Use worktree-session.sh to properly end (merge + cleanup)
64
87
  if [ -f "$SCRIPT_DIR/worktree-session.sh" ]; then
65
88
  "$SCRIPT_DIR/worktree-session.sh" end "$SESSION_NAME"
@@ -72,13 +95,22 @@ if $IS_WORKTREE && [ -n "$SESSION_NAME" ] && [ "$SESSION_NAME" != "main" ] && [
72
95
  exit 1
73
96
  fi
74
97
 
98
+ # Unregister from lock registry
99
+ if [ -x "$LOCK_SCRIPT" ] && [ -n "$SESSION_ID" ]; then
100
+ "$LOCK_SCRIPT" unregister "$SESSION_ID" >/dev/null 2>&1 || true
101
+ echo -e "${GREEN}✓${NC} Session unregistered from lock registry"
102
+ fi
103
+
75
104
  # Clean up session file
76
105
  rm -f "$SESSION_FILE"
77
106
 
78
107
  else
79
- # Main branch session - just commit and push
108
+ # Main branch session - commit, merge, push
80
109
  echo -e "${BLUE}→${NC} Ending main branch session..."
81
110
 
111
+ # Step 0: Stop heartbeat
112
+ stop_heartbeat "$PROJECT_ROOT/.jfl/heartbeat.pid"
113
+
82
114
  # Step 1: Stop auto-commit
83
115
  echo -e "${BLUE}→${NC} Stopping auto-commit..."
84
116
  "$SCRIPT_DIR/auto-commit.sh" stop 2>/dev/null || true
@@ -124,13 +156,38 @@ else
124
156
  echo -e "${GREEN}✓${NC} No uncommitted changes"
125
157
  fi
126
158
 
127
- # Step 4: Push to remote
128
- echo -e "${BLUE}→${NC} Pushing to remote..."
159
+ # Step 4: Merge session branch to working branch (sequenced)
129
160
  CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
130
- if git push origin "$CURRENT_BRANCH" 2>/dev/null; then
131
- echo -e "${GREEN}✓${NC} Pushed to origin/$CURRENT_BRANCH"
161
+ WORKING_BRANCH=$(jq -r '.working_branch // empty' .jfl/config.json 2>/dev/null)
162
+ if [ -z "$WORKING_BRANCH" ]; then WORKING_BRANCH="main"; fi
163
+
164
+ if [ "$CURRENT_BRANCH" != "$WORKING_BRANCH" ] && [[ "$CURRENT_BRANCH" == session-* ]]; then
165
+ echo -e "${BLUE}→${NC} Merging $CURRENT_BRANCH → $WORKING_BRANCH (sequenced)..."
166
+
167
+ if [ -x "$LOCK_SCRIPT" ] && [ -n "$SESSION_ID" ]; then
168
+ if "$LOCK_SCRIPT" merge "$CURRENT_BRANCH" "$WORKING_BRANCH" "$SESSION_ID" "$PROJECT_ROOT" 2>&1; then
169
+ echo -e "${GREEN}✓${NC} Merged and pushed via sequencer"
170
+ else
171
+ echo -e "${YELLOW}⚠${NC} Sequenced merge failed — pushing branch for manual merge"
172
+ git push origin "$CURRENT_BRANCH" 2>/dev/null || true
173
+ fi
174
+ else
175
+ # Fallback: direct push
176
+ echo -e "${BLUE}→${NC} Pushing to remote..."
177
+ if git push origin "$CURRENT_BRANCH" 2>/dev/null; then
178
+ echo -e "${GREEN}✓${NC} Pushed to origin/$CURRENT_BRANCH"
179
+ else
180
+ echo -e "${YELLOW}⚠${NC} Push failed (will retry on next session)"
181
+ fi
182
+ fi
132
183
  else
133
- echo -e "${YELLOW}⚠${NC} Push failed (will retry on next session)"
184
+ # Already on working branch just push
185
+ echo -e "${BLUE}→${NC} Pushing to remote..."
186
+ if git push origin "$CURRENT_BRANCH" 2>/dev/null; then
187
+ echo -e "${GREEN}✓${NC} Pushed to origin/$CURRENT_BRANCH"
188
+ else
189
+ echo -e "${YELLOW}⚠${NC} Push failed (will retry on next session)"
190
+ fi
134
191
  fi
135
192
 
136
193
  # Step 5: Sync product repo if symlink/submodule
@@ -188,6 +245,12 @@ else
188
245
  # Clean up session file
189
246
  rm -f "$SESSION_FILE"
190
247
 
248
+ # Unregister from lock registry
249
+ if [ -x "$LOCK_SCRIPT" ] && [ -n "$SESSION_ID" ]; then
250
+ "$LOCK_SCRIPT" unregister "$SESSION_ID" >/dev/null 2>&1 || true
251
+ echo -e "${GREEN}✓${NC} Session unregistered from lock registry"
252
+ fi
253
+
191
254
  echo ""
192
255
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
193
256
  echo -e " ${GREEN}Session ended successfully!${NC}"
@@ -200,9 +200,11 @@ if [[ -d "$WORKTREES_DIR" ]]; then
200
200
  fi
201
201
 
202
202
  # ==============================================================================
203
- # Step 2.9: Check for concurrent sessions via jfl-services
203
+ # Step 2.9: Check for concurrent sessions via lock registry
204
204
  # ==============================================================================
205
205
 
206
+ LOCK_SCRIPT="$SCRIPT_DIR/session-lock.sh"
207
+
206
208
  # Generate session details first
207
209
  user=$(git config user.name 2>/dev/null | tr ' ' '-' | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9-' || echo "user")
208
210
  user="${user:0:30}"
@@ -217,41 +219,41 @@ if [[ -z "$working_branch" ]]; then
217
219
  working_branch=$(git branch --show-current)
218
220
  fi
219
221
 
220
- # Check for concurrent sessions via jfl-services API
221
- use_worktree=false
222
- api_response=""
223
- if command -v curl >/dev/null 2>&1; then
224
- api_response=$(curl -s -X GET "http://localhost:3401/sessions/active?projectPath=$(pwd)" 2>/dev/null || echo "")
225
-
226
- if [[ -n "$api_response" ]] && echo "$api_response" | jq -e '.count' >/dev/null 2>&1; then
227
- session_count=$(echo "$api_response" | jq -r '.count // 0')
222
+ # Clean stale sessions first
223
+ if [[ -x "$LOCK_SCRIPT" ]]; then
224
+ cleaned=$("$LOCK_SCRIPT" clean 2>/dev/null | grep -o '[0-9]*' || echo "0")
225
+ if [[ "$cleaned" -gt 0 ]]; then
226
+ echo -e "${YELLOW}→${NC} Cleaned $cleaned stale session lock(s)"
227
+ fi
228
+ fi
228
229
 
229
- if [[ $session_count -gt 0 ]]; then
230
- use_worktree=true
231
- echo -e "${YELLOW}→${NC} Multiple sessions detected ($session_count active) - using worktree for isolation"
232
- else
233
- echo -e "${GREEN}→${NC} Single session - working directly on branch $working_branch"
234
- fi
230
+ # Check for concurrent sessions via lock registry (no external service needed)
231
+ use_worktree=false
232
+ if [[ -x "$LOCK_SCRIPT" ]]; then
233
+ session_count=$("$LOCK_SCRIPT" count 2>/dev/null || echo "0")
234
+
235
+ if [[ $session_count -gt 0 ]]; then
236
+ use_worktree=true
237
+ echo -e "${YELLOW}→${NC} $session_count active session(s) detected — using worktree for isolation"
238
+ # Show who's active
239
+ "$LOCK_SCRIPT" active 2>/dev/null | python3 -c "
240
+ import sys, json
241
+ try:
242
+ sessions = json.load(sys.stdin)
243
+ for s in sessions:
244
+ print(f' • {s[\"id\"]} (branch: {s[\"branch\"]}, pid: {s[\"pid\"]})')
245
+ except: pass
246
+ " 2>/dev/null || true
235
247
  else
236
- # API unavailable - fall back to local detection
237
- echo -e "${YELLOW}→${NC} jfl-services unavailable - checking locally..."
238
- local_sessions=$(ps aux | grep -c "claude.*$(pwd)" 2>/dev/null || echo "1")
239
- if [[ $local_sessions -gt 2 ]]; then
240
- use_worktree=true
241
- echo -e "${YELLOW}→${NC} Multiple processes detected - using worktree for isolation"
242
- fi
248
+ echo -e "${GREEN}→${NC} Single session working directly on branch $working_branch"
243
249
  fi
244
250
  else
245
- # No curl - assume single session
246
- echo -e "${GREEN}→${NC} Working directly on branch $working_branch"
251
+ echo -e "${YELLOW}→${NC} session-lock.sh not found — assuming single session"
247
252
  fi
248
253
 
249
- # Register this session with jfl-services
250
- if command -v curl >/dev/null 2>&1; then
251
- curl -s -X POST "http://localhost:3401/sessions/start" \
252
- -H "Content-Type: application/json" \
253
- -d "{\"id\":\"$session_name\",\"projectPath\":\"$(pwd)\",\"branch\":\"$working_branch\",\"user\":\"$user\",\"pid\":$$,\"worktree\":\"$use_worktree\"}" \
254
- >/dev/null 2>&1 || true
254
+ # Register this session in the lock registry
255
+ if [[ -x "$LOCK_SCRIPT" ]]; then
256
+ "$LOCK_SCRIPT" register "$session_name" "$working_branch" >/dev/null 2>&1 || true
255
257
  fi
256
258
 
257
259
  # ==============================================================================
@@ -305,6 +307,20 @@ if [[ "$use_worktree" == "true" ]]; then
305
307
  echo "$session_name" > "$REPO_DIR/.jfl/current-session-branch.txt"
306
308
  echo "$session_name" > "$worktree_path/.jfl/current-session-branch.txt"
307
309
 
310
+ # Update lock registry with worktree path
311
+ if [[ -x "$LOCK_SCRIPT" ]]; then
312
+ "$LOCK_SCRIPT" register "$session_name" "$session_name" "$worktree_path" >/dev/null 2>&1 || true
313
+ fi
314
+
315
+ # Start heartbeat in background (touch lock file every 30s)
316
+ if [[ -x "$LOCK_SCRIPT" ]]; then
317
+ (while true; do "$LOCK_SCRIPT" heartbeat "$session_name" >/dev/null 2>&1 || break; sleep 30; done) &
318
+ HEARTBEAT_PID=$!
319
+ echo "$HEARTBEAT_PID" > "$worktree_path/.jfl/heartbeat.pid"
320
+ disown "$HEARTBEAT_PID" 2>/dev/null || true
321
+ echo -e "${GREEN}✓${NC} Heartbeat started (PID $HEARTBEAT_PID)"
322
+ fi
323
+
308
324
  echo ""
309
325
  echo -e "${GREEN}✓${NC} Session ready in worktree: $worktree_path"
310
326
  echo ""
@@ -344,6 +360,15 @@ if [[ "$use_worktree" != "true" ]]; then
344
360
  echo "direct" > "$REPO_DIR/.jfl/current-worktree.txt"
345
361
  echo "$session_name" > "$REPO_DIR/.jfl/current-session-branch.txt"
346
362
 
363
+ # Start heartbeat in background (touch lock file every 30s)
364
+ if [[ -x "$LOCK_SCRIPT" ]]; then
365
+ (while true; do "$LOCK_SCRIPT" heartbeat "$session_name" >/dev/null 2>&1 || break; sleep 30; done) &
366
+ HEARTBEAT_PID=$!
367
+ echo "$HEARTBEAT_PID" > "$REPO_DIR/.jfl/heartbeat.pid"
368
+ disown "$HEARTBEAT_PID" 2>/dev/null || true
369
+ echo -e "${GREEN}✓${NC} Heartbeat started (PID $HEARTBEAT_PID)"
370
+ fi
371
+
347
372
  echo ""
348
373
  echo -e "${GREEN}✓${NC} Session ready on branch: $session_name"
349
374
  echo ""