jfl 0.4.4 → 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 (427) hide show
  1. package/dist/commands/context-hub.d.ts.map +1 -1
  2. package/dist/commands/context-hub.js +818 -39
  3. package/dist/commands/context-hub.js.map +1 -1
  4. package/dist/commands/eval.d.ts +1 -1
  5. package/dist/commands/eval.d.ts.map +1 -1
  6. package/dist/commands/eval.js +192 -1
  7. package/dist/commands/eval.js.map +1 -1
  8. package/dist/commands/findings.d.ts +6 -0
  9. package/dist/commands/findings.d.ts.map +1 -0
  10. package/dist/commands/findings.js +203 -0
  11. package/dist/commands/findings.js.map +1 -0
  12. package/dist/commands/hud.d.ts.map +1 -1
  13. package/dist/commands/hud.js +47 -9
  14. package/dist/commands/hud.js.map +1 -1
  15. package/dist/commands/ide.d.ts +27 -0
  16. package/dist/commands/ide.d.ts.map +1 -0
  17. package/dist/commands/ide.js +546 -0
  18. package/dist/commands/ide.js.map +1 -0
  19. package/dist/commands/onboard.d.ts.map +1 -1
  20. package/dist/commands/onboard.js +212 -2
  21. package/dist/commands/onboard.js.map +1 -1
  22. package/dist/commands/openclaw.d.ts +3 -0
  23. package/dist/commands/openclaw.d.ts.map +1 -1
  24. package/dist/commands/openclaw.js +76 -2
  25. package/dist/commands/openclaw.js.map +1 -1
  26. package/dist/commands/peter.d.ts +1 -0
  27. package/dist/commands/peter.d.ts.map +1 -1
  28. package/dist/commands/peter.js +935 -15
  29. package/dist/commands/peter.js.map +1 -1
  30. package/dist/commands/pi-fleet.d.ts +18 -0
  31. package/dist/commands/pi-fleet.d.ts.map +1 -0
  32. package/dist/commands/pi-fleet.js +382 -0
  33. package/dist/commands/pi-fleet.js.map +1 -0
  34. package/dist/commands/pi.d.ts.map +1 -1
  35. package/dist/commands/pi.js +18 -3
  36. package/dist/commands/pi.js.map +1 -1
  37. package/dist/commands/scope.d.ts.map +1 -1
  38. package/dist/commands/scope.js +90 -1
  39. package/dist/commands/scope.js.map +1 -1
  40. package/dist/commands/services.d.ts.map +1 -1
  41. package/dist/commands/services.js +18 -0
  42. package/dist/commands/services.js.map +1 -1
  43. package/dist/commands/status.d.ts.map +1 -1
  44. package/dist/commands/status.js +22 -4
  45. package/dist/commands/status.js.map +1 -1
  46. package/dist/commands/viz.d.ts.map +1 -1
  47. package/dist/commands/viz.js +417 -0
  48. package/dist/commands/viz.js.map +1 -1
  49. package/dist/dashboard-static/assets/index-B6b867Pv.js +121 -0
  50. package/dist/dashboard-static/assets/index-Y4BrqxV-.css +1 -0
  51. package/dist/dashboard-static/index.html +2 -2
  52. package/dist/index.js +225 -61
  53. package/dist/index.js.map +1 -1
  54. package/dist/lib/agent-config.d.ts +52 -0
  55. package/dist/lib/agent-config.d.ts.map +1 -0
  56. package/dist/lib/agent-config.js +231 -0
  57. package/dist/lib/agent-config.js.map +1 -0
  58. package/dist/lib/agent-generator.d.ts +10 -0
  59. package/dist/lib/agent-generator.d.ts.map +1 -1
  60. package/dist/lib/agent-generator.js +64 -10
  61. package/dist/lib/agent-generator.js.map +1 -1
  62. package/dist/lib/agent-session.d.ts +104 -0
  63. package/dist/lib/agent-session.d.ts.map +1 -0
  64. package/dist/lib/agent-session.js +627 -0
  65. package/dist/lib/agent-session.js.map +1 -0
  66. package/dist/lib/eval-snapshot.d.ts +47 -0
  67. package/dist/lib/eval-snapshot.d.ts.map +1 -0
  68. package/dist/lib/eval-snapshot.js +315 -0
  69. package/dist/lib/eval-snapshot.js.map +1 -0
  70. package/dist/lib/eval-store.d.ts +5 -0
  71. package/dist/lib/eval-store.d.ts.map +1 -1
  72. package/dist/lib/eval-store.js +33 -3
  73. package/dist/lib/eval-store.js.map +1 -1
  74. package/dist/lib/findings-engine.d.ts +51 -0
  75. package/dist/lib/findings-engine.d.ts.map +1 -0
  76. package/dist/lib/findings-engine.js +338 -0
  77. package/dist/lib/findings-engine.js.map +1 -0
  78. package/dist/lib/flow-engine.d.ts +8 -0
  79. package/dist/lib/flow-engine.d.ts.map +1 -1
  80. package/dist/lib/flow-engine.js +84 -2
  81. package/dist/lib/flow-engine.js.map +1 -1
  82. package/dist/lib/hub-client.d.ts +1 -0
  83. package/dist/lib/hub-client.d.ts.map +1 -1
  84. package/dist/lib/hub-client.js +33 -6
  85. package/dist/lib/hub-client.js.map +1 -1
  86. package/dist/lib/ide-panes.d.ts +58 -0
  87. package/dist/lib/ide-panes.d.ts.map +1 -0
  88. package/dist/lib/ide-panes.js +508 -0
  89. package/dist/lib/ide-panes.js.map +1 -0
  90. package/dist/lib/memory-db.js +4 -4
  91. package/dist/lib/memory-db.js.map +1 -1
  92. package/dist/lib/memory-indexer.d.ts.map +1 -1
  93. package/dist/lib/memory-indexer.js +3 -0
  94. package/dist/lib/memory-indexer.js.map +1 -1
  95. package/dist/lib/memory-search.d.ts +148 -4
  96. package/dist/lib/memory-search.d.ts.map +1 -1
  97. package/dist/lib/memory-search.js +496 -58
  98. package/dist/lib/memory-search.js.map +1 -1
  99. package/dist/lib/meta-orchestrator.d.ts +104 -0
  100. package/dist/lib/meta-orchestrator.d.ts.map +1 -0
  101. package/dist/lib/meta-orchestrator.js +373 -0
  102. package/dist/lib/meta-orchestrator.js.map +1 -0
  103. package/dist/lib/peer-agent-generator.d.ts.map +1 -1
  104. package/dist/lib/peer-agent-generator.js +43 -19
  105. package/dist/lib/peer-agent-generator.js.map +1 -1
  106. package/dist/lib/policy-head.d.ts +25 -0
  107. package/dist/lib/policy-head.d.ts.map +1 -0
  108. package/dist/lib/policy-head.js +136 -0
  109. package/dist/lib/policy-head.js.map +1 -0
  110. package/dist/lib/replay-buffer.d.ts +93 -0
  111. package/dist/lib/replay-buffer.d.ts.map +1 -0
  112. package/dist/lib/replay-buffer.js +302 -0
  113. package/dist/lib/replay-buffer.js.map +1 -0
  114. package/dist/lib/sentinel-rl.d.ts +97 -0
  115. package/dist/lib/sentinel-rl.d.ts.map +1 -0
  116. package/dist/lib/sentinel-rl.js +430 -0
  117. package/dist/lib/sentinel-rl.js.map +1 -0
  118. package/dist/lib/session-lock.d.ts +61 -0
  119. package/dist/lib/session-lock.d.ts.map +1 -0
  120. package/dist/lib/session-lock.js +438 -0
  121. package/dist/lib/session-lock.js.map +1 -0
  122. package/dist/lib/stratus-client.d.ts +1 -0
  123. package/dist/lib/stratus-client.d.ts.map +1 -1
  124. package/dist/lib/stratus-client.js +24 -2
  125. package/dist/lib/stratus-client.js.map +1 -1
  126. package/dist/lib/telemetry-agent-v2.d.ts +128 -0
  127. package/dist/lib/telemetry-agent-v2.d.ts.map +1 -0
  128. package/dist/lib/telemetry-agent-v2.js +1042 -0
  129. package/dist/lib/telemetry-agent-v2.js.map +1 -0
  130. package/dist/lib/telemetry-agent.d.ts.map +1 -1
  131. package/dist/lib/telemetry-agent.js +27 -6
  132. package/dist/lib/telemetry-agent.js.map +1 -1
  133. package/dist/lib/telemetry-digest.d.ts.map +1 -1
  134. package/dist/lib/telemetry-digest.js +27 -5
  135. package/dist/lib/telemetry-digest.js.map +1 -1
  136. package/dist/lib/telemetry.d.ts.map +1 -1
  137. package/dist/lib/telemetry.js +29 -4
  138. package/dist/lib/telemetry.js.map +1 -1
  139. package/dist/lib/text-preprocessing.d.ts +83 -0
  140. package/dist/lib/text-preprocessing.d.ts.map +1 -0
  141. package/dist/lib/text-preprocessing.js +261 -0
  142. package/dist/lib/text-preprocessing.js.map +1 -0
  143. package/dist/lib/training-buffer.d.ts +86 -0
  144. package/dist/lib/training-buffer.d.ts.map +1 -0
  145. package/dist/lib/training-buffer.js +139 -0
  146. package/dist/lib/training-buffer.js.map +1 -0
  147. package/dist/lib/tuple-miner.d.ts +30 -0
  148. package/dist/lib/tuple-miner.d.ts.map +1 -0
  149. package/dist/lib/tuple-miner.js +427 -0
  150. package/dist/lib/tuple-miner.js.map +1 -0
  151. package/dist/lib/vm-backend.d.ts +72 -0
  152. package/dist/lib/vm-backend.d.ts.map +1 -0
  153. package/dist/lib/vm-backend.js +175 -0
  154. package/dist/lib/vm-backend.js.map +1 -0
  155. package/dist/lib/workspace/backend.d.ts +53 -0
  156. package/dist/lib/workspace/backend.d.ts.map +1 -0
  157. package/dist/lib/workspace/backend.js +37 -0
  158. package/dist/lib/workspace/backend.js.map +1 -0
  159. package/dist/lib/workspace/cmux-adapter.d.ts +46 -0
  160. package/dist/lib/workspace/cmux-adapter.d.ts.map +1 -0
  161. package/dist/lib/workspace/cmux-adapter.js +261 -0
  162. package/dist/lib/workspace/cmux-adapter.js.map +1 -0
  163. package/dist/lib/workspace/data-pipeline.d.ts +35 -0
  164. package/dist/lib/workspace/data-pipeline.d.ts.map +1 -0
  165. package/dist/lib/workspace/data-pipeline.js +463 -0
  166. package/dist/lib/workspace/data-pipeline.js.map +1 -0
  167. package/dist/lib/workspace/engine.d.ts +64 -0
  168. package/dist/lib/workspace/engine.d.ts.map +1 -0
  169. package/dist/lib/workspace/engine.js +397 -0
  170. package/dist/lib/workspace/engine.js.map +1 -0
  171. package/dist/lib/workspace/notifications.d.ts +14 -0
  172. package/dist/lib/workspace/notifications.d.ts.map +1 -0
  173. package/dist/lib/workspace/notifications.js +41 -0
  174. package/dist/lib/workspace/notifications.js.map +1 -0
  175. package/dist/lib/workspace/surface-registry.d.ts +49 -0
  176. package/dist/lib/workspace/surface-registry.d.ts.map +1 -0
  177. package/dist/lib/workspace/surface-registry.js +217 -0
  178. package/dist/lib/workspace/surface-registry.js.map +1 -0
  179. package/dist/lib/workspace/surface-type.d.ts +153 -0
  180. package/dist/lib/workspace/surface-type.d.ts.map +1 -0
  181. package/dist/lib/workspace/surface-type.js +9 -0
  182. package/dist/lib/workspace/surface-type.js.map +1 -0
  183. package/dist/lib/workspace/surfaces/agent-overview.d.ts +16 -0
  184. package/dist/lib/workspace/surfaces/agent-overview.d.ts.map +1 -0
  185. package/dist/lib/workspace/surfaces/agent-overview.js +116 -0
  186. package/dist/lib/workspace/surfaces/agent-overview.js.map +1 -0
  187. package/dist/lib/workspace/surfaces/agent.d.ts +16 -0
  188. package/dist/lib/workspace/surfaces/agent.d.ts.map +1 -0
  189. package/dist/lib/workspace/surfaces/agent.js +112 -0
  190. package/dist/lib/workspace/surfaces/agent.js.map +1 -0
  191. package/dist/lib/workspace/surfaces/claude.d.ts +15 -0
  192. package/dist/lib/workspace/surfaces/claude.d.ts.map +1 -0
  193. package/dist/lib/workspace/surfaces/claude.js +23 -0
  194. package/dist/lib/workspace/surfaces/claude.js.map +1 -0
  195. package/dist/lib/workspace/surfaces/dashboard.d.ts +21 -0
  196. package/dist/lib/workspace/surfaces/dashboard.d.ts.map +1 -0
  197. package/dist/lib/workspace/surfaces/dashboard.js +32 -0
  198. package/dist/lib/workspace/surfaces/dashboard.js.map +1 -0
  199. package/dist/lib/workspace/surfaces/eval.d.ts +15 -0
  200. package/dist/lib/workspace/surfaces/eval.d.ts.map +1 -0
  201. package/dist/lib/workspace/surfaces/eval.js +42 -0
  202. package/dist/lib/workspace/surfaces/eval.js.map +1 -0
  203. package/dist/lib/workspace/surfaces/event-stream.d.ts +16 -0
  204. package/dist/lib/workspace/surfaces/event-stream.d.ts.map +1 -0
  205. package/dist/lib/workspace/surfaces/event-stream.js +40 -0
  206. package/dist/lib/workspace/surfaces/event-stream.js.map +1 -0
  207. package/dist/lib/workspace/surfaces/flow.d.ts +16 -0
  208. package/dist/lib/workspace/surfaces/flow.d.ts.map +1 -0
  209. package/dist/lib/workspace/surfaces/flow.js +49 -0
  210. package/dist/lib/workspace/surfaces/flow.js.map +1 -0
  211. package/dist/lib/workspace/surfaces/index.d.ts +16 -0
  212. package/dist/lib/workspace/surfaces/index.d.ts.map +1 -0
  213. package/dist/lib/workspace/surfaces/index.js +16 -0
  214. package/dist/lib/workspace/surfaces/index.js.map +1 -0
  215. package/dist/lib/workspace/surfaces/portfolio.d.ts +16 -0
  216. package/dist/lib/workspace/surfaces/portfolio.d.ts.map +1 -0
  217. package/dist/lib/workspace/surfaces/portfolio.js +102 -0
  218. package/dist/lib/workspace/surfaces/portfolio.js.map +1 -0
  219. package/dist/lib/workspace/surfaces/service.d.ts +16 -0
  220. package/dist/lib/workspace/surfaces/service.d.ts.map +1 -0
  221. package/dist/lib/workspace/surfaces/service.js +45 -0
  222. package/dist/lib/workspace/surfaces/service.js.map +1 -0
  223. package/dist/lib/workspace/surfaces/shell.d.ts +15 -0
  224. package/dist/lib/workspace/surfaces/shell.d.ts.map +1 -0
  225. package/dist/lib/workspace/surfaces/shell.js +19 -0
  226. package/dist/lib/workspace/surfaces/shell.js.map +1 -0
  227. package/dist/lib/workspace/surfaces/telemetry.d.ts +16 -0
  228. package/dist/lib/workspace/surfaces/telemetry.d.ts.map +1 -0
  229. package/dist/lib/workspace/surfaces/telemetry.js +48 -0
  230. package/dist/lib/workspace/surfaces/telemetry.js.map +1 -0
  231. package/dist/lib/workspace/surfaces/topology.d.ts +15 -0
  232. package/dist/lib/workspace/surfaces/topology.d.ts.map +1 -0
  233. package/dist/lib/workspace/surfaces/topology.js +19 -0
  234. package/dist/lib/workspace/surfaces/topology.js.map +1 -0
  235. package/dist/lib/workspace/surfaces/training.d.ts +16 -0
  236. package/dist/lib/workspace/surfaces/training.d.ts.map +1 -0
  237. package/dist/lib/workspace/surfaces/training.js +22 -0
  238. package/dist/lib/workspace/surfaces/training.js.map +1 -0
  239. package/dist/lib/workspace/tmux-adapter.d.ts +27 -0
  240. package/dist/lib/workspace/tmux-adapter.d.ts.map +1 -0
  241. package/dist/lib/workspace/tmux-adapter.js +106 -0
  242. package/dist/lib/workspace/tmux-adapter.js.map +1 -0
  243. package/dist/mcp/context-hub-mcp.js +7 -24
  244. package/dist/mcp/context-hub-mcp.js.map +1 -1
  245. package/dist/types/flows.d.ts +2 -0
  246. package/dist/types/flows.d.ts.map +1 -1
  247. package/dist/types/ide.d.ts +49 -0
  248. package/dist/types/ide.d.ts.map +1 -0
  249. package/dist/types/ide.js +5 -0
  250. package/dist/types/ide.js.map +1 -0
  251. package/dist/types/platform-digest.d.ts +228 -0
  252. package/dist/types/platform-digest.d.ts.map +1 -0
  253. package/dist/types/platform-digest.js +5 -0
  254. package/dist/types/platform-digest.js.map +1 -0
  255. package/dist/types/telemetry-digest.d.ts +2 -0
  256. package/dist/types/telemetry-digest.d.ts.map +1 -1
  257. package/dist/utils/ensure-project.d.ts +1 -0
  258. package/dist/utils/ensure-project.d.ts.map +1 -1
  259. package/dist/utils/ensure-project.js +19 -7
  260. package/dist/utils/ensure-project.js.map +1 -1
  261. package/dist/utils/jfl-config.d.ts +1 -0
  262. package/dist/utils/jfl-config.d.ts.map +1 -1
  263. package/dist/utils/jfl-config.js +19 -1
  264. package/dist/utils/jfl-config.js.map +1 -1
  265. package/dist/utils/jfl-paths.d.ts +5 -0
  266. package/dist/utils/jfl-paths.d.ts.map +1 -1
  267. package/dist/utils/jfl-paths.js +25 -3
  268. package/dist/utils/jfl-paths.js.map +1 -1
  269. package/package.json +3 -2
  270. package/packages/pi/AGENTS.md +112 -0
  271. package/packages/pi/extensions/agent-grid.ts +191 -0
  272. package/packages/pi/extensions/agent-names.ts +178 -0
  273. package/packages/pi/extensions/autoresearch.ts +427 -0
  274. package/packages/pi/extensions/bookmarks.ts +85 -0
  275. package/packages/pi/extensions/context.ts +151 -0
  276. package/packages/pi/extensions/crm-tool.ts +61 -0
  277. package/packages/pi/extensions/eval-tool.ts +224 -0
  278. package/packages/pi/extensions/eval.ts +60 -0
  279. package/packages/pi/extensions/footer.ts +239 -0
  280. package/packages/pi/extensions/hud-tool.ts +145 -0
  281. package/packages/pi/extensions/index.ts +392 -0
  282. package/packages/pi/extensions/journal.ts +224 -0
  283. package/packages/pi/extensions/map-bridge.ts +178 -0
  284. package/packages/pi/extensions/memory-tool.ts +68 -0
  285. package/packages/pi/extensions/notifications.ts +73 -0
  286. package/packages/pi/extensions/peter-parker.ts +202 -0
  287. package/packages/pi/extensions/policy-head-tool.ts +276 -0
  288. package/packages/pi/extensions/portfolio-bridge.ts +90 -0
  289. package/packages/pi/extensions/session.ts +90 -0
  290. package/packages/pi/extensions/shortcuts.ts +259 -0
  291. package/packages/pi/extensions/stratus-bridge.ts +115 -0
  292. package/packages/pi/extensions/synopsis-tool.ts +83 -0
  293. package/packages/pi/extensions/tool-renderers.ts +352 -0
  294. package/packages/pi/extensions/training-buffer-tool.ts +368 -0
  295. package/packages/pi/extensions/types.ts +163 -0
  296. package/packages/pi/package-lock.json +346 -0
  297. package/packages/pi/package.json +44 -0
  298. package/packages/pi/skills/agent-browser/SKILL.md +116 -0
  299. package/packages/pi/skills/brand-architect/SKILL.md +240 -0
  300. package/packages/pi/skills/brand-architect/config.yaml +137 -0
  301. package/packages/pi/skills/campaign-hud/config.yaml +112 -0
  302. package/packages/pi/skills/content-creator/SKILL.md +294 -0
  303. package/packages/pi/skills/context/SKILL.md +65 -0
  304. package/packages/pi/skills/debug/MULTI_AGENT.md +360 -0
  305. package/packages/pi/skills/debug/SKILL.md +554 -0
  306. package/packages/pi/skills/end/SKILL.md +1782 -0
  307. package/packages/pi/skills/eval/SKILL.md +75 -0
  308. package/packages/pi/skills/fly-deploy/SKILL.md +676 -0
  309. package/packages/pi/skills/founder-video/SKILL.md +467 -0
  310. package/packages/pi/skills/hud/SKILL.md +160 -0
  311. package/packages/pi/skills/orchestrate/SKILL.md +74 -0
  312. package/packages/pi/skills/pi-agents/SKILL.md +78 -0
  313. package/packages/pi/skills/react-best-practices/AGENTS.md +2249 -0
  314. package/packages/pi/skills/react-best-practices/README.md +123 -0
  315. package/packages/pi/skills/react-best-practices/SKILL.md +125 -0
  316. package/packages/pi/skills/react-best-practices/metadata.json +15 -0
  317. package/packages/pi/skills/react-best-practices/rules/_sections.md +46 -0
  318. package/packages/pi/skills/react-best-practices/rules/_template.md +28 -0
  319. package/packages/pi/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  320. package/packages/pi/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
  321. package/packages/pi/skills/react-best-practices/rules/async-api-routes.md +38 -0
  322. package/packages/pi/skills/react-best-practices/rules/async-defer-await.md +80 -0
  323. package/packages/pi/skills/react-best-practices/rules/async-dependencies.md +36 -0
  324. package/packages/pi/skills/react-best-practices/rules/async-parallel.md +28 -0
  325. package/packages/pi/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
  326. package/packages/pi/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
  327. package/packages/pi/skills/react-best-practices/rules/bundle-conditional.md +31 -0
  328. package/packages/pi/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
  329. package/packages/pi/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  330. package/packages/pi/skills/react-best-practices/rules/bundle-preload.md +50 -0
  331. package/packages/pi/skills/react-best-practices/rules/client-event-listeners.md +74 -0
  332. package/packages/pi/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
  333. package/packages/pi/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
  334. package/packages/pi/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
  335. package/packages/pi/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
  336. package/packages/pi/skills/react-best-practices/rules/js-cache-storage.md +70 -0
  337. package/packages/pi/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
  338. package/packages/pi/skills/react-best-practices/rules/js-early-exit.md +50 -0
  339. package/packages/pi/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
  340. package/packages/pi/skills/react-best-practices/rules/js-index-maps.md +37 -0
  341. package/packages/pi/skills/react-best-practices/rules/js-length-check-first.md +49 -0
  342. package/packages/pi/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
  343. package/packages/pi/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
  344. package/packages/pi/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  345. package/packages/pi/skills/react-best-practices/rules/rendering-activity.md +26 -0
  346. package/packages/pi/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  347. package/packages/pi/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
  348. package/packages/pi/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
  349. package/packages/pi/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  350. package/packages/pi/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  351. package/packages/pi/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
  352. package/packages/pi/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
  353. package/packages/pi/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
  354. package/packages/pi/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
  355. package/packages/pi/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
  356. package/packages/pi/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  357. package/packages/pi/skills/react-best-practices/rules/rerender-memo.md +44 -0
  358. package/packages/pi/skills/react-best-practices/rules/rerender-transitions.md +40 -0
  359. package/packages/pi/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
  360. package/packages/pi/skills/react-best-practices/rules/server-cache-lru.md +41 -0
  361. package/packages/pi/skills/react-best-practices/rules/server-cache-react.md +26 -0
  362. package/packages/pi/skills/react-best-practices/rules/server-parallel-fetching.md +79 -0
  363. package/packages/pi/skills/react-best-practices/rules/server-serialization.md +38 -0
  364. package/packages/pi/skills/remotion-best-practices/SKILL.md +43 -0
  365. package/packages/pi/skills/remotion-best-practices/rules/3d.md +86 -0
  366. package/packages/pi/skills/remotion-best-practices/rules/animations.md +29 -0
  367. package/packages/pi/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx +173 -0
  368. package/packages/pi/skills/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +100 -0
  369. package/packages/pi/skills/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +108 -0
  370. package/packages/pi/skills/remotion-best-practices/rules/assets.md +78 -0
  371. package/packages/pi/skills/remotion-best-practices/rules/audio.md +172 -0
  372. package/packages/pi/skills/remotion-best-practices/rules/calculate-metadata.md +104 -0
  373. package/packages/pi/skills/remotion-best-practices/rules/can-decode.md +75 -0
  374. package/packages/pi/skills/remotion-best-practices/rules/charts.md +58 -0
  375. package/packages/pi/skills/remotion-best-practices/rules/compositions.md +146 -0
  376. package/packages/pi/skills/remotion-best-practices/rules/display-captions.md +126 -0
  377. package/packages/pi/skills/remotion-best-practices/rules/extract-frames.md +229 -0
  378. package/packages/pi/skills/remotion-best-practices/rules/fonts.md +152 -0
  379. package/packages/pi/skills/remotion-best-practices/rules/get-audio-duration.md +58 -0
  380. package/packages/pi/skills/remotion-best-practices/rules/get-video-dimensions.md +68 -0
  381. package/packages/pi/skills/remotion-best-practices/rules/get-video-duration.md +58 -0
  382. package/packages/pi/skills/remotion-best-practices/rules/gifs.md +138 -0
  383. package/packages/pi/skills/remotion-best-practices/rules/images.md +130 -0
  384. package/packages/pi/skills/remotion-best-practices/rules/import-srt-captions.md +67 -0
  385. package/packages/pi/skills/remotion-best-practices/rules/lottie.md +68 -0
  386. package/packages/pi/skills/remotion-best-practices/rules/measuring-dom-nodes.md +35 -0
  387. package/packages/pi/skills/remotion-best-practices/rules/measuring-text.md +143 -0
  388. package/packages/pi/skills/remotion-best-practices/rules/sequencing.md +106 -0
  389. package/packages/pi/skills/remotion-best-practices/rules/tailwind.md +11 -0
  390. package/packages/pi/skills/remotion-best-practices/rules/text-animations.md +20 -0
  391. package/packages/pi/skills/remotion-best-practices/rules/timing.md +179 -0
  392. package/packages/pi/skills/remotion-best-practices/rules/transcribe-captions.md +19 -0
  393. package/packages/pi/skills/remotion-best-practices/rules/transitions.md +122 -0
  394. package/packages/pi/skills/remotion-best-practices/rules/trimming.md +53 -0
  395. package/packages/pi/skills/remotion-best-practices/rules/videos.md +171 -0
  396. package/packages/pi/skills/search/SKILL.md +220 -0
  397. package/packages/pi/skills/spec/SKILL.md +377 -0
  398. package/packages/pi/skills/startup/SKILL.md +315 -0
  399. package/packages/pi/skills/web-architect/SKILL.md +309 -0
  400. package/packages/pi/skills/x-algorithm/SKILL.md +305 -0
  401. package/packages/pi/teams/dev-team.yaml +63 -0
  402. package/packages/pi/teams/gtm-team.yaml +79 -0
  403. package/packages/pi/themes/jfl.theme.json +76 -0
  404. package/packages/pi/tsconfig.json +21 -0
  405. package/scripts/collect-tuples.sh +124 -0
  406. package/scripts/destroy-fleet.sh +37 -0
  407. package/scripts/jfl-ide.sh +48 -0
  408. package/scripts/session/session-cleanup.sh +4 -11
  409. package/scripts/session/session-init.sh +6 -0
  410. package/scripts/session/session-sync.sh +25 -0
  411. package/scripts/setup-branch-protection.sh +106 -0
  412. package/scripts/spawn-fleet.sh +144 -0
  413. package/scripts/train-policy-head.py +434 -0
  414. package/scripts/vm-swarm/README.md +301 -0
  415. package/scripts/vm-swarm/collect-tuples.sh +331 -0
  416. package/scripts/vm-swarm/create-base-template.sh +339 -0
  417. package/scripts/vm-swarm/kill-fleet.sh +204 -0
  418. package/scripts/vm-swarm/monitor-fleet.sh +346 -0
  419. package/scripts/vm-swarm/spawn-fleet.sh +304 -0
  420. package/template/.github/workflows/jfl-eval.yml +6 -1
  421. package/template/.github/workflows/jfl-review.yml +4 -0
  422. package/template/scripts/session/session-end.sh +69 -6
  423. package/template/scripts/session/session-init.sh +55 -30
  424. package/template/scripts/session/session-lock.sh +464 -0
  425. package/template/templates/service-agent/workflows/jfl-eval.yml +19 -0
  426. package/dist/dashboard-static/assets/index-B6kRK9Rq.js +0 -116
  427. package/dist/dashboard-static/assets/index-BpdKJPLu.css +0 -1
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Peter Parker Extension — Full Orchestrator
3
+ *
4
+ * Replaces the WebSocket bridge with a proper Pi extension orchestrator.
5
+ * Subscribes to MAP events, queries Stratus predictor for optimal action,
6
+ * spawns Pi RPC subprocesses, and runs the review loop (max 5 iterations).
7
+ *
8
+ * @purpose Full Peter Parker orchestrator — review loop with Stratus dispatch via Pi RPC
9
+ */
10
+
11
+ import { spawn } from "child_process"
12
+ import { existsSync, readFileSync } from "fs"
13
+ import { join } from "path"
14
+ import type { PiContext, JflConfig } from "./types.js"
15
+ import { emitCustomEvent, hubUrl, authToken } from "./map-bridge.js"
16
+
17
+ interface ReviewTask {
18
+ id: string
19
+ prompt: string
20
+ source: string
21
+ priority?: number
22
+ }
23
+
24
+ interface PeterIteration {
25
+ taskId: string
26
+ iteration: number
27
+ agentPid?: number
28
+ startTime: Date
29
+ prediction?: { delta: number; recommendation: string }
30
+ result?: "success" | "failed" | "max_iterations"
31
+ }
32
+
33
+ const MAX_ITERATIONS = 5
34
+ let projectRoot = ""
35
+ let maxIterations = MAX_ITERATIONS
36
+ let activeIterations = new Map<string, PeterIteration>()
37
+
38
+ async function getPredictor(root: string) {
39
+ try {
40
+ // @ts-ignore — resolved from jfl package at runtime
41
+ const { Predictor } = await import("../../src/lib/predictor.js")
42
+ return new Predictor(root)
43
+ } catch {
44
+ return null
45
+ }
46
+ }
47
+
48
+ async function spawnPiAgent(
49
+ ctx: PiContext,
50
+ task: ReviewTask,
51
+ extensionPath: string
52
+ ): Promise<{ exitCode: number | null }> {
53
+ return new Promise((resolve) => {
54
+ const args = [
55
+ "--mode", "rpc",
56
+ "--extension", extensionPath,
57
+ "--task", task.prompt,
58
+ "--yolo",
59
+ ]
60
+
61
+ ctx.log(`PP: spawning agent for task ${task.id}`, "debug")
62
+
63
+ const proc = spawn("pi", args, {
64
+ cwd: projectRoot,
65
+ stdio: ["ignore", "pipe", "pipe"],
66
+ env: {
67
+ ...process.env,
68
+ JFL_SESSION_ID: ctx.session.id,
69
+ JFL_TASK_ID: task.id,
70
+ },
71
+ })
72
+
73
+ proc.stdout?.on("data", (d: Buffer) => ctx.log(`PP agent: ${d.toString().trim()}`, "debug"))
74
+ proc.stderr?.on("data", (d: Buffer) => ctx.log(`PP agent err: ${d.toString().trim()}`, "debug"))
75
+
76
+ proc.on("close", (code) => resolve({ exitCode: code }))
77
+ proc.on("error", () => resolve({ exitCode: -1 }))
78
+
79
+ setTimeout(() => {
80
+ proc.kill()
81
+ resolve({ exitCode: -1 })
82
+ }, 5 * 60 * 1000)
83
+ })
84
+ }
85
+
86
+ async function runReviewLoop(ctx: PiContext, task: ReviewTask): Promise<void> {
87
+ const current = activeIterations.get(task.id)
88
+ const iteration = current ? current.iteration + 1 : 1
89
+
90
+ if (iteration > maxIterations) {
91
+ ctx.log(`PP: max iterations (${maxIterations}) reached for task ${task.id}`, "warn")
92
+ await emitCustomEvent(ctx, "peter:max-iterations", { taskId: task.id, iterations: iteration - 1 })
93
+ activeIterations.delete(task.id)
94
+ return
95
+ }
96
+
97
+ const iterRecord: PeterIteration = {
98
+ taskId: task.id,
99
+ iteration,
100
+ startTime: new Date(),
101
+ }
102
+
103
+ const predictor = await getPredictor(projectRoot)
104
+ if (predictor) {
105
+ try {
106
+ const prediction = await predictor.predict({
107
+ proposal: {
108
+ description: task.prompt,
109
+ change_type: "fix",
110
+ scope: "small",
111
+ },
112
+ current_score: 0,
113
+ goal: "resolve review findings",
114
+ recent_trajectory: [],
115
+ })
116
+ iterRecord.prediction = { delta: prediction.predicted_delta, recommendation: prediction.recommendation }
117
+
118
+ if (prediction.recommendation === "abandon") {
119
+ ctx.log(`PP: predictor recommends abandon for task ${task.id}`, "info")
120
+ activeIterations.delete(task.id)
121
+ return
122
+ }
123
+ } catch {}
124
+ }
125
+
126
+ activeIterations.set(task.id, iterRecord)
127
+ await emitCustomEvent(ctx, "peter:dispatched", { taskId: task.id, iteration, prediction: iterRecord.prediction })
128
+
129
+ const extensionPath = join(projectRoot, "node_modules", "@jfl", "pi", "dist", "extensions", "index.js")
130
+ const result = await spawnPiAgent(ctx, task, extensionPath)
131
+
132
+ iterRecord.result = result.exitCode === 0 ? "success" : "failed"
133
+ activeIterations.set(task.id, iterRecord)
134
+
135
+ if (result.exitCode !== 0) {
136
+ ctx.log(`PP: agent failed (iteration ${iteration}), will retry`, "info")
137
+ await runReviewLoop(ctx, task)
138
+ } else {
139
+ await emitCustomEvent(ctx, "peter:completed", { taskId: task.id, iterations: iteration })
140
+ activeIterations.delete(task.id)
141
+ }
142
+ }
143
+
144
+ export async function setupPeterParker(ctx: PiContext, config: JflConfig): Promise<void> {
145
+ projectRoot = ctx.session.projectRoot
146
+ maxIterations = config.pi?.max_peter_iterations ?? MAX_ITERATIONS
147
+
148
+ ctx.on("map:eval:scored", async (data) => {
149
+ const event = data as { taskId?: string; score?: number; findings?: string[] }
150
+ if (!event.taskId || !event.findings?.length) return
151
+
152
+ const task: ReviewTask = {
153
+ id: event.taskId,
154
+ prompt: `Review findings to address:\n${event.findings.join("\n")}`,
155
+ source: "eval:scored",
156
+ }
157
+ await runReviewLoop(ctx, task)
158
+ })
159
+
160
+ ctx.on("map:review:findings", async (data) => {
161
+ const event = data as { id?: string; findings?: string; priority?: number }
162
+ if (!event.findings) return
163
+
164
+ const task: ReviewTask = {
165
+ id: event.id ?? `review-${Date.now()}`,
166
+ prompt: event.findings,
167
+ source: "review:findings",
168
+ priority: event.priority,
169
+ }
170
+ await runReviewLoop(ctx, task)
171
+ })
172
+
173
+ ctx.on("map:task:requested", async (data) => {
174
+ const event = data as { id?: string; prompt?: string }
175
+ if (!event.prompt) return
176
+
177
+ const task: ReviewTask = {
178
+ id: event.id ?? `task-${Date.now()}`,
179
+ prompt: event.prompt,
180
+ source: "task:requested",
181
+ }
182
+ await runReviewLoop(ctx, task)
183
+ })
184
+
185
+ ctx.registerCommand({
186
+ name: "peter",
187
+ description: "Peter Parker orchestrator — run a task through the review loop",
188
+ async handler(args, ctx) {
189
+ if (!args.trim()) {
190
+ ctx.ui.notify("Usage: /peter <task description>", { level: "info" })
191
+ return
192
+ }
193
+ const task: ReviewTask = {
194
+ id: `peter-${Date.now()}`,
195
+ prompt: args.trim(),
196
+ source: "manual",
197
+ }
198
+ ctx.ui.notify(`Starting Peter Parker loop for: ${args.trim().slice(0, 60)}`, { level: "info" })
199
+ await runReviewLoop(ctx, task)
200
+ },
201
+ })
202
+ }
@@ -0,0 +1,276 @@
1
+ /**
2
+ * Policy Head Tool
3
+ *
4
+ * Exposes the RL policy head to the agent as a tool. The agent can score
5
+ * candidate actions before executing them — "should I fix this test or
6
+ * refactor that module?" — and get a predicted reward delta.
7
+ *
8
+ * Also registers /policy command to show policy head stats and rank
9
+ * ad-hoc proposals interactively.
10
+ *
11
+ * @purpose Pi tool for RL policy head — score candidate actions, rank proposals
12
+ */
13
+
14
+ import { existsSync, readFileSync } from "fs"
15
+ import { join } from "path"
16
+ import type { PiContext, JflConfig } from "./types.js"
17
+ import { emitCustomEvent } from "./map-bridge.js"
18
+
19
+ let projectRoot = ""
20
+
21
+ interface PolicyWeights {
22
+ version: number
23
+ trained_on: number
24
+ direction_accuracy: number
25
+ rank_correlation: number
26
+ target_mean: number
27
+ target_std: number
28
+ }
29
+
30
+ function getWeightsInfo(): PolicyWeights | null {
31
+ const weightsPath = join(projectRoot, ".jfl", "policy-weights.json")
32
+ if (!existsSync(weightsPath)) return null
33
+ try {
34
+ return JSON.parse(readFileSync(weightsPath, "utf-8")) as PolicyWeights
35
+ } catch {
36
+ return null
37
+ }
38
+ }
39
+
40
+ async function getPolicyHead(): Promise<any> {
41
+ try {
42
+ // @ts-ignore — resolved from jfl package at runtime
43
+ const { PolicyHeadInference } = await import("../../src/lib/policy-head.js")
44
+ return new PolicyHeadInference(projectRoot)
45
+ } catch {
46
+ return null
47
+ }
48
+ }
49
+
50
+ async function getTrainingBuffer(): Promise<any> {
51
+ try {
52
+ // @ts-ignore — resolved from jfl package at runtime
53
+ const { TrainingBuffer } = await import("../../src/lib/training-buffer.js")
54
+ return new TrainingBuffer(projectRoot)
55
+ } catch {
56
+ return null
57
+ }
58
+ }
59
+
60
+ export async function setupPolicyHeadTool(ctx: PiContext, _config: JflConfig): Promise<void> {
61
+ projectRoot = ctx.session.projectRoot
62
+
63
+ ctx.registerTool({
64
+ name: "jfl_policy_score",
65
+ description: "Score a candidate action using the RL policy head. Returns predicted reward delta to help decide which action to take next. Requires trained policy weights (.jfl/policy-weights.json).",
66
+ inputSchema: {
67
+ type: "object",
68
+ properties: {
69
+ action_type: {
70
+ type: "string",
71
+ description: "Type of action",
72
+ enum: ["fix", "refactor", "feature", "test", "config", "experiment"],
73
+ },
74
+ description: {
75
+ type: "string",
76
+ description: "What the action does (1-2 sentences)",
77
+ },
78
+ files: {
79
+ type: "string",
80
+ description: "Comma-separated list of files affected",
81
+ },
82
+ scope: {
83
+ type: "string",
84
+ description: "Scope of change",
85
+ enum: ["small", "medium", "large"],
86
+ },
87
+ },
88
+ required: ["action_type", "description"],
89
+ },
90
+ async handler(input) {
91
+ const {
92
+ action_type,
93
+ description,
94
+ files,
95
+ scope,
96
+ } = input as {
97
+ action_type: string
98
+ description: string
99
+ files?: string
100
+ scope?: string
101
+ }
102
+
103
+ const policyHead = await getPolicyHead()
104
+ if (!policyHead || !policyHead.isLoaded) {
105
+ return "Policy head not available. No trained weights found at .jfl/policy-weights.json. Run `jfl eval train` to train the policy head from existing training tuples."
106
+ }
107
+
108
+ const tb = await getTrainingBuffer()
109
+ const entries: any[] = tb ? tb.read() : []
110
+ const recentDeltas = entries.slice(-10).map((e: any) => e.reward.composite_delta)
111
+
112
+ const state = {
113
+ composite_score: entries.length > 0
114
+ ? entries[entries.length - 1].reward.composite_delta + entries[entries.length - 1].state.composite_score
115
+ : 0,
116
+ dimension_scores: {} as Record<string, number>,
117
+ tests_passing: 0,
118
+ tests_total: 0,
119
+ trajectory_length: entries.length,
120
+ recent_deltas: recentDeltas,
121
+ agent: "pi-agent",
122
+ }
123
+
124
+ const action = {
125
+ type: action_type as "fix" | "refactor" | "feature" | "test" | "config" | "experiment",
126
+ description,
127
+ files_affected: files ? files.split(",").map(f => f.trim()) : [],
128
+ scope: (scope || "medium") as "small" | "medium" | "large",
129
+ branch: ctx.session.branch,
130
+ }
131
+
132
+ try {
133
+ const predicted = await policyHead.predictReward(state, action)
134
+ const stats = policyHead.stats
135
+
136
+ await emitCustomEvent(ctx, "policy:scored", {
137
+ action_type,
138
+ description: description.slice(0, 80),
139
+ predicted_reward: predicted,
140
+ })
141
+
142
+ const lines = [
143
+ `Predicted reward delta: ${predicted >= 0 ? "+" : ""}${predicted.toFixed(4)}`,
144
+ `Recommendation: ${predicted > 0.01 ? "PROCEED — positive expected outcome" : predicted > -0.005 ? "NEUTRAL — marginal expected impact" : "SKIP — negative expected outcome"}`,
145
+ "",
146
+ `Policy head stats:`,
147
+ ` Trained on: ${stats?.trained_on ?? "?"} tuples`,
148
+ ` Direction accuracy: ${stats?.direction_accuracy ? (stats.direction_accuracy * 100).toFixed(1) + "%" : "?"}`,
149
+ ` Rank correlation: ${stats?.rank_correlation?.toFixed(3) ?? "?"}`,
150
+ ]
151
+
152
+ return lines.join("\n")
153
+ } catch (err) {
154
+ return `Policy head inference failed: ${err}. Ensure STRATUS_API_KEY is set for embedding generation.`
155
+ }
156
+ },
157
+ })
158
+
159
+ ctx.registerTool({
160
+ name: "jfl_policy_rank",
161
+ description: "Rank multiple candidate actions by predicted reward. Pass 2-5 actions as JSON array. Returns ranked list with predicted deltas.",
162
+ inputSchema: {
163
+ type: "object",
164
+ properties: {
165
+ actions: {
166
+ type: "string",
167
+ description: 'JSON array of actions, each with: {"type": "fix|refactor|feature|test|config|experiment", "description": "what it does", "files": ["file1.ts"], "scope": "small|medium|large"}',
168
+ },
169
+ },
170
+ required: ["actions"],
171
+ },
172
+ async handler(input) {
173
+ const { actions: actionsStr } = input as { actions: string }
174
+
175
+ const policyHead = await getPolicyHead()
176
+ if (!policyHead || !policyHead.isLoaded) {
177
+ return "Policy head not available. No trained weights at .jfl/policy-weights.json."
178
+ }
179
+
180
+ let candidates: Array<{
181
+ type: string
182
+ description: string
183
+ files?: string[]
184
+ scope?: string
185
+ }>
186
+ try {
187
+ candidates = JSON.parse(actionsStr)
188
+ if (!Array.isArray(candidates) || candidates.length < 2) {
189
+ return "Provide at least 2 actions as a JSON array."
190
+ }
191
+ } catch {
192
+ return "Invalid JSON. Provide a JSON array of action objects."
193
+ }
194
+
195
+ const tb = await getTrainingBuffer()
196
+ const entries: any[] = tb ? tb.read() : []
197
+
198
+ const state = {
199
+ composite_score: entries.length > 0
200
+ ? entries[entries.length - 1].reward.composite_delta + entries[entries.length - 1].state.composite_score
201
+ : 0,
202
+ dimension_scores: {} as Record<string, number>,
203
+ tests_passing: 0,
204
+ tests_total: 0,
205
+ trajectory_length: entries.length,
206
+ recent_deltas: entries.slice(-10).map((e: any) => e.reward.composite_delta),
207
+ agent: "pi-agent",
208
+ }
209
+
210
+ const rlActions = candidates.map(c => ({
211
+ type: (c.type || "feature") as "fix" | "refactor" | "feature" | "test" | "config" | "experiment",
212
+ description: c.description,
213
+ files_affected: c.files || [],
214
+ scope: (c.scope || "medium") as "small" | "medium" | "large",
215
+ branch: ctx.session.branch,
216
+ }))
217
+
218
+ try {
219
+ const ranked = await policyHead.rankActions(state, rlActions)
220
+
221
+ await emitCustomEvent(ctx, "policy:ranked", {
222
+ count: ranked.length,
223
+ top: ranked[0]?.action.description.slice(0, 60),
224
+ })
225
+
226
+ const lines = ["Ranked actions (best first):", ""]
227
+ for (const r of ranked) {
228
+ const sign = r.predictedReward >= 0 ? "+" : ""
229
+ lines.push(` #${r.rank} [${sign}${r.predictedReward.toFixed(4)}] ${r.action.type}: ${r.action.description.slice(0, 80)}`)
230
+ }
231
+
232
+ return lines.join("\n")
233
+ } catch (err) {
234
+ return `Ranking failed: ${err}`
235
+ }
236
+ },
237
+ })
238
+
239
+ ctx.registerCommand({
240
+ name: "policy",
241
+ description: "Show policy head status and training buffer stats",
242
+ async handler(_args, ctx) {
243
+ const weights = getWeightsInfo()
244
+ const tb = await getTrainingBuffer()
245
+ const stats = tb ? tb.stats() : null
246
+
247
+ const lines: string[] = []
248
+
249
+ if (weights) {
250
+ lines.push(
251
+ "Policy Head: LOADED",
252
+ ` Trained on: ${weights.trained_on} tuples`,
253
+ ` Direction accuracy: ${(weights.direction_accuracy * 100).toFixed(1)}%`,
254
+ ` Rank correlation: ${weights.rank_correlation.toFixed(3)}`,
255
+ "",
256
+ )
257
+ } else {
258
+ lines.push("Policy Head: NOT LOADED (no .jfl/policy-weights.json)", "")
259
+ }
260
+
261
+ if (stats) {
262
+ lines.push(
263
+ `Training Buffer: ${stats.total} tuples`,
264
+ ` Avg reward: ${stats.avgReward.toFixed(4)}`,
265
+ ` Improvement rate: ${(stats.improvedRate * 100).toFixed(1)}%`,
266
+ ` By agent: ${Object.entries(stats.byAgent).map(([k, v]) => `${k}=${v}`).join(", ") || "none"}`,
267
+ ` By source: ${Object.entries(stats.bySource).map(([k, v]) => `${k}=${v}`).join(", ") || "none"}`,
268
+ )
269
+ } else {
270
+ lines.push("Training Buffer: empty or unavailable")
271
+ }
272
+
273
+ ctx.ui.notify(lines.join("\n"), { level: "info" })
274
+ },
275
+ })
276
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Portfolio Bridge Extension
3
+ *
4
+ * Handles cross-GTM coordination: phoneHome on session end, journal sync to parent,
5
+ * and eval scores propagated to portfolio hub for cross-GTM RL training.
6
+ *
7
+ * @purpose Portfolio-GTM coordination — phoneHome, journal sync, eval propagation
8
+ */
9
+
10
+ import { existsSync, readFileSync } from "fs"
11
+ import { join } from "path"
12
+ import type { PiContext, JflConfig } from "./types.js"
13
+ import { emitCustomEvent } from "./map-bridge.js"
14
+
15
+ let projectRoot = ""
16
+ let portfolioParent: string | null = null
17
+
18
+ async function phoneHome(ctx: PiContext): Promise<void> {
19
+ if (!portfolioParent || !existsSync(portfolioParent)) return
20
+
21
+ try {
22
+ // @ts-ignore — resolved from jfl package at runtime
23
+ const { phoneHomeToPortfolio } = await import("../../src/lib/service-gtm.js")
24
+ await phoneHomeToPortfolio(projectRoot)
25
+ ctx.log("Portfolio phoneHome complete", "debug")
26
+ } catch (err) {
27
+ ctx.log(`Portfolio phoneHome failed: ${err}`, "debug")
28
+ }
29
+ }
30
+
31
+ async function syncJournalEntry(ctx: PiContext, entry: unknown): Promise<void> {
32
+ if (!portfolioParent || !existsSync(portfolioParent)) return
33
+
34
+ try {
35
+ // @ts-ignore — resolved from jfl package at runtime
36
+ const { writeSyncToParent } = await import("../../src/lib/service-gtm.js")
37
+ await (writeSyncToParent as (root: string, entry: unknown) => Promise<void>)(projectRoot, entry)
38
+ } catch (err) {
39
+ ctx.log(`Journal sync to parent failed: ${err}`, "debug")
40
+ }
41
+ }
42
+
43
+ async function propagateEvalToPortfolio(ctx: PiContext, evalData: unknown): Promise<void> {
44
+ if (!portfolioParent) return
45
+
46
+ const portfolioConfigPath = join(portfolioParent, ".jfl", "context-hub.port")
47
+ if (!existsSync(portfolioConfigPath)) return
48
+
49
+ try {
50
+ const port = readFileSync(portfolioConfigPath, "utf-8").trim()
51
+ const portfolioHub = `http://localhost:${port}`
52
+ const tokenPath = join(portfolioParent, ".jfl", "context-hub.token")
53
+ const token = existsSync(tokenPath) ? readFileSync(tokenPath, "utf-8").trim() : null
54
+
55
+ await fetch(`${portfolioHub}/api/events`, {
56
+ method: "POST",
57
+ headers: {
58
+ "Content-Type": "application/json",
59
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
60
+ },
61
+ body: JSON.stringify({
62
+ type: "eval:scored",
63
+ source: projectRoot,
64
+ data: evalData,
65
+ ts: new Date().toISOString(),
66
+ }),
67
+ })
68
+ } catch {}
69
+ }
70
+
71
+ export async function setupPortfolioBridge(ctx: PiContext, config: JflConfig): Promise<void> {
72
+ projectRoot = ctx.session.projectRoot
73
+ portfolioParent = config.portfolio_parent ?? null
74
+
75
+ if (!portfolioParent) return
76
+
77
+ ctx.on("map:journal:entry", (data) => syncJournalEntry(ctx, data))
78
+
79
+ ctx.on("map:eval:scored", (data) => propagateEvalToPortfolio(ctx, data))
80
+
81
+ ctx.on("map:portfolio:directive", async (data) => {
82
+ const directive = data as { action?: string; payload?: unknown }
83
+ ctx.log(`Portfolio directive received: ${directive.action}`, "info")
84
+ await emitCustomEvent(ctx, "portfolio:directive:received", directive)
85
+ })
86
+ }
87
+
88
+ export async function onPortfolioShutdown(ctx: PiContext): Promise<void> {
89
+ await phoneHome(ctx)
90
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * JFL Session Extension
3
+ *
4
+ * Handles auto-commit and session cleanup within a Pi session.
5
+ * Does NOT run session-init.sh — that script is a Claude Code pre-hook that
6
+ * launches the AI CLI, which would cause a double-launch inside Pi.
7
+ * Pi IS the AI runtime; we only handle the persistent background tasks here.
8
+ *
9
+ * @purpose Pi session lifecycle — auto-commit daemon + cleanup script delegation
10
+ */
11
+
12
+ import { execSync, spawn } from "child_process"
13
+ import { existsSync, readFileSync } from "fs"
14
+ import { join } from "path"
15
+ import type { PiContext, JflConfig } from "./types.js"
16
+
17
+ let autoCommitProcess: ReturnType<typeof spawn> | null = null
18
+
19
+ function findScript(root: string, scriptName: string): string | null {
20
+ const candidates = [
21
+ join(root, "scripts", "session", scriptName),
22
+ join(root, "scripts", scriptName),
23
+ ]
24
+ for (const candidate of candidates) {
25
+ if (existsSync(candidate)) return candidate
26
+ }
27
+ return null
28
+ }
29
+
30
+ export async function setupSession(ctx: PiContext, _config: JflConfig): Promise<void> {
31
+ const root = ctx.session.projectRoot
32
+
33
+ // Start auto-commit daemon — detached so it outlives this call
34
+ const autoCommitScript = findScript(root, "auto-commit.sh")
35
+ if (autoCommitScript) {
36
+ autoCommitProcess = spawn("bash", [autoCommitScript, "start", "120"], {
37
+ cwd: root,
38
+ detached: true,
39
+ stdio: "ignore",
40
+ })
41
+ autoCommitProcess.unref()
42
+ ctx.log("Auto-commit daemon started (120s interval)", "debug")
43
+ }
44
+
45
+ ctx.emit("hook:session-start", {
46
+ session: ctx.session.id,
47
+ branch: ctx.session.branch,
48
+ projectRoot: root,
49
+ ts: new Date().toISOString(),
50
+ })
51
+ }
52
+
53
+ export async function onShutdown(ctx: PiContext): Promise<void> {
54
+ const root = ctx.session.projectRoot
55
+
56
+ if (autoCommitProcess) {
57
+ try {
58
+ autoCommitProcess.kill()
59
+ } catch {}
60
+ autoCommitProcess = null
61
+ }
62
+
63
+ const cleanupScript = findScript(root, "session-cleanup.sh")
64
+ if (cleanupScript) {
65
+ try {
66
+ execSync(`bash "${cleanupScript}"`, { cwd: root, stdio: "inherit" })
67
+ } catch (err) {
68
+ ctx.log(`session-cleanup.sh failed: ${err}`, "warn")
69
+ }
70
+ }
71
+
72
+ ctx.emit("hook:session-end", {
73
+ session: ctx.session.id,
74
+ branch: ctx.session.branch,
75
+ ts: new Date().toISOString(),
76
+ })
77
+ }
78
+
79
+ export function getCurrentBranch(root: string): string {
80
+ try {
81
+ return execSync("git branch --show-current", { cwd: root }).toString().trim()
82
+ } catch {
83
+ try {
84
+ const saved = readFileSync(join(root, ".jfl", "current-session-branch.txt"), "utf-8").trim()
85
+ return saved
86
+ } catch {
87
+ return "main"
88
+ }
89
+ }
90
+ }