jfl 0.0.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 (381) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +313 -0
  3. package/clawdbot-skill/README.md +328 -0
  4. package/clawdbot-skill/SKILL.md +362 -0
  5. package/clawdbot-skill/index.ts +486 -0
  6. package/clawdbot-skill/package.json +28 -0
  7. package/clawdbot-skill/skill.json +28 -0
  8. package/dist/commands/agents.d.ts +5 -0
  9. package/dist/commands/agents.d.ts.map +1 -0
  10. package/dist/commands/agents.js +399 -0
  11. package/dist/commands/agents.js.map +1 -0
  12. package/dist/commands/context-hub.d.ts +12 -0
  13. package/dist/commands/context-hub.d.ts.map +1 -0
  14. package/dist/commands/context-hub.js +642 -0
  15. package/dist/commands/context-hub.js.map +1 -0
  16. package/dist/commands/deploy.d.ts +5 -0
  17. package/dist/commands/deploy.d.ts.map +1 -0
  18. package/dist/commands/deploy.js +370 -0
  19. package/dist/commands/deploy.js.map +1 -0
  20. package/dist/commands/feedback.d.ts +2 -0
  21. package/dist/commands/feedback.d.ts.map +1 -0
  22. package/dist/commands/feedback.js +178 -0
  23. package/dist/commands/feedback.js.map +1 -0
  24. package/dist/commands/hud.d.ts +4 -0
  25. package/dist/commands/hud.d.ts.map +1 -0
  26. package/dist/commands/hud.js +262 -0
  27. package/dist/commands/hud.js.map +1 -0
  28. package/dist/commands/init.d.ts +4 -0
  29. package/dist/commands/init.d.ts.map +1 -0
  30. package/dist/commands/init.js +553 -0
  31. package/dist/commands/init.js.map +1 -0
  32. package/dist/commands/login.d.ts +23 -0
  33. package/dist/commands/login.d.ts.map +1 -0
  34. package/dist/commands/login.js +818 -0
  35. package/dist/commands/login.js.map +1 -0
  36. package/dist/commands/ralph.d.ts +9 -0
  37. package/dist/commands/ralph.d.ts.map +1 -0
  38. package/dist/commands/ralph.js +67 -0
  39. package/dist/commands/ralph.js.map +1 -0
  40. package/dist/commands/repair.d.ts +7 -0
  41. package/dist/commands/repair.d.ts.map +1 -0
  42. package/dist/commands/repair.js +283 -0
  43. package/dist/commands/repair.js.map +1 -0
  44. package/dist/commands/session-mgmt.d.ts +33 -0
  45. package/dist/commands/session-mgmt.d.ts.map +1 -0
  46. package/dist/commands/session-mgmt.js +404 -0
  47. package/dist/commands/session-mgmt.js.map +1 -0
  48. package/dist/commands/session.d.ts +2 -0
  49. package/dist/commands/session.d.ts.map +1 -0
  50. package/dist/commands/session.js +639 -0
  51. package/dist/commands/session.js.map +1 -0
  52. package/dist/commands/skills.d.ts +31 -0
  53. package/dist/commands/skills.d.ts.map +1 -0
  54. package/dist/commands/skills.js +314 -0
  55. package/dist/commands/skills.js.map +1 -0
  56. package/dist/commands/status.d.ts +2 -0
  57. package/dist/commands/status.d.ts.map +1 -0
  58. package/dist/commands/status.js +127 -0
  59. package/dist/commands/status.js.map +1 -0
  60. package/dist/commands/synopsis.d.ts +10 -0
  61. package/dist/commands/synopsis.d.ts.map +1 -0
  62. package/dist/commands/synopsis.js +277 -0
  63. package/dist/commands/synopsis.js.map +1 -0
  64. package/dist/commands/update.d.ts +10 -0
  65. package/dist/commands/update.d.ts.map +1 -0
  66. package/dist/commands/update.js +165 -0
  67. package/dist/commands/update.js.map +1 -0
  68. package/dist/commands/voice.d.ts +410 -0
  69. package/dist/commands/voice.d.ts.map +1 -0
  70. package/dist/commands/voice.js +4763 -0
  71. package/dist/commands/voice.js.map +1 -0
  72. package/dist/index.d.ts +9 -0
  73. package/dist/index.d.ts.map +1 -0
  74. package/dist/index.js +512 -0
  75. package/dist/index.js.map +1 -0
  76. package/dist/mcp/context-hub-mcp.d.ts +11 -0
  77. package/dist/mcp/context-hub-mcp.d.ts.map +1 -0
  78. package/dist/mcp/context-hub-mcp.js +548 -0
  79. package/dist/mcp/context-hub-mcp.js.map +1 -0
  80. package/dist/telegram/voice.d.ts +146 -0
  81. package/dist/telegram/voice.d.ts.map +1 -0
  82. package/dist/telegram/voice.js +351 -0
  83. package/dist/telegram/voice.js.map +1 -0
  84. package/dist/types/skills.d.ts +44 -0
  85. package/dist/types/skills.d.ts.map +1 -0
  86. package/dist/types/skills.js +5 -0
  87. package/dist/types/skills.js.map +1 -0
  88. package/dist/ui/banner.d.ts +18 -0
  89. package/dist/ui/banner.d.ts.map +1 -0
  90. package/dist/ui/banner.js +323 -0
  91. package/dist/ui/banner.js.map +1 -0
  92. package/dist/ui/index.d.ts +8 -0
  93. package/dist/ui/index.d.ts.map +1 -0
  94. package/dist/ui/index.js +8 -0
  95. package/dist/ui/index.js.map +1 -0
  96. package/dist/ui/prompts.d.ts +52 -0
  97. package/dist/ui/prompts.d.ts.map +1 -0
  98. package/dist/ui/prompts.js +72 -0
  99. package/dist/ui/prompts.js.map +1 -0
  100. package/dist/ui/theme.d.ts +82 -0
  101. package/dist/ui/theme.d.ts.map +1 -0
  102. package/dist/ui/theme.js +142 -0
  103. package/dist/ui/theme.js.map +1 -0
  104. package/dist/utils/auth-guard.d.ts +66 -0
  105. package/dist/utils/auth-guard.d.ts.map +1 -0
  106. package/dist/utils/auth-guard.js +348 -0
  107. package/dist/utils/auth-guard.js.map +1 -0
  108. package/dist/utils/ensure-project.d.ts +11 -0
  109. package/dist/utils/ensure-project.d.ts.map +1 -0
  110. package/dist/utils/ensure-project.js +70 -0
  111. package/dist/utils/ensure-project.js.map +1 -0
  112. package/dist/utils/git.d.ts +73 -0
  113. package/dist/utils/git.d.ts.map +1 -0
  114. package/dist/utils/git.js +219 -0
  115. package/dist/utils/git.js.map +1 -0
  116. package/dist/utils/github-auth.d.ts +54 -0
  117. package/dist/utils/github-auth.d.ts.map +1 -0
  118. package/dist/utils/github-auth.js +375 -0
  119. package/dist/utils/github-auth.js.map +1 -0
  120. package/dist/utils/github-repo.d.ts +30 -0
  121. package/dist/utils/github-repo.d.ts.map +1 -0
  122. package/dist/utils/github-repo.js +219 -0
  123. package/dist/utils/github-repo.js.map +1 -0
  124. package/dist/utils/platform-auth.d.ts +81 -0
  125. package/dist/utils/platform-auth.d.ts.map +1 -0
  126. package/dist/utils/platform-auth.js +191 -0
  127. package/dist/utils/platform-auth.js.map +1 -0
  128. package/dist/utils/project-config.d.ts +43 -0
  129. package/dist/utils/project-config.d.ts.map +1 -0
  130. package/dist/utils/project-config.js +97 -0
  131. package/dist/utils/project-config.js.map +1 -0
  132. package/dist/utils/skill-registry.d.ts +49 -0
  133. package/dist/utils/skill-registry.d.ts.map +1 -0
  134. package/dist/utils/skill-registry.js +192 -0
  135. package/dist/utils/skill-registry.js.map +1 -0
  136. package/dist/utils/wallet.d.ts +62 -0
  137. package/dist/utils/wallet.d.ts.map +1 -0
  138. package/dist/utils/wallet.js +252 -0
  139. package/dist/utils/wallet.js.map +1 -0
  140. package/dist/utils/x402-client.d.ts +86 -0
  141. package/dist/utils/x402-client.d.ts.map +1 -0
  142. package/dist/utils/x402-client.js +265 -0
  143. package/dist/utils/x402-client.js.map +1 -0
  144. package/package.json +76 -0
  145. package/scripts/postinstall.js +116 -0
  146. package/scripts/test-onboarding.sh +121 -0
  147. package/scripts/voice-start.sh +128 -0
  148. package/scripts/voice-stop.sh +33 -0
  149. package/template/.claude/settings.json +92 -0
  150. package/template/.claude/skills/agent-browser/SKILL.md +116 -0
  151. package/template/.claude/skills/brand-architect/SKILL.md +240 -0
  152. package/template/.claude/skills/brand-architect/config.yaml +137 -0
  153. package/template/.claude/skills/campaign-hud/config.yaml +112 -0
  154. package/template/.claude/skills/content-creator/SKILL.md +294 -0
  155. package/template/.claude/skills/debug/MULTI_AGENT.md +360 -0
  156. package/template/.claude/skills/debug/SKILL.md +549 -0
  157. package/template/.claude/skills/fly-deploy/SKILL.md +676 -0
  158. package/template/.claude/skills/founder-video/SKILL.md +467 -0
  159. package/template/.claude/skills/hud/SKILL.md +157 -0
  160. package/template/.claude/skills/ralph-tui/SKILL.md +210 -0
  161. package/template/.claude/skills/react-best-practices/AGENTS.md +2249 -0
  162. package/template/.claude/skills/react-best-practices/README.md +123 -0
  163. package/template/.claude/skills/react-best-practices/SKILL.md +125 -0
  164. package/template/.claude/skills/react-best-practices/metadata.json +15 -0
  165. package/template/.claude/skills/react-best-practices/rules/_sections.md +46 -0
  166. package/template/.claude/skills/react-best-practices/rules/_template.md +28 -0
  167. package/template/.claude/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  168. package/template/.claude/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
  169. package/template/.claude/skills/react-best-practices/rules/async-api-routes.md +38 -0
  170. package/template/.claude/skills/react-best-practices/rules/async-defer-await.md +80 -0
  171. package/template/.claude/skills/react-best-practices/rules/async-dependencies.md +36 -0
  172. package/template/.claude/skills/react-best-practices/rules/async-parallel.md +28 -0
  173. package/template/.claude/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
  174. package/template/.claude/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
  175. package/template/.claude/skills/react-best-practices/rules/bundle-conditional.md +31 -0
  176. package/template/.claude/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
  177. package/template/.claude/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  178. package/template/.claude/skills/react-best-practices/rules/bundle-preload.md +50 -0
  179. package/template/.claude/skills/react-best-practices/rules/client-event-listeners.md +74 -0
  180. package/template/.claude/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
  181. package/template/.claude/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
  182. package/template/.claude/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
  183. package/template/.claude/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
  184. package/template/.claude/skills/react-best-practices/rules/js-cache-storage.md +70 -0
  185. package/template/.claude/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
  186. package/template/.claude/skills/react-best-practices/rules/js-early-exit.md +50 -0
  187. package/template/.claude/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
  188. package/template/.claude/skills/react-best-practices/rules/js-index-maps.md +37 -0
  189. package/template/.claude/skills/react-best-practices/rules/js-length-check-first.md +49 -0
  190. package/template/.claude/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
  191. package/template/.claude/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
  192. package/template/.claude/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  193. package/template/.claude/skills/react-best-practices/rules/rendering-activity.md +26 -0
  194. package/template/.claude/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  195. package/template/.claude/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
  196. package/template/.claude/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
  197. package/template/.claude/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  198. package/template/.claude/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  199. package/template/.claude/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
  200. package/template/.claude/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
  201. package/template/.claude/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
  202. package/template/.claude/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
  203. package/template/.claude/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
  204. package/template/.claude/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  205. package/template/.claude/skills/react-best-practices/rules/rerender-memo.md +44 -0
  206. package/template/.claude/skills/react-best-practices/rules/rerender-transitions.md +40 -0
  207. package/template/.claude/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
  208. package/template/.claude/skills/react-best-practices/rules/server-cache-lru.md +41 -0
  209. package/template/.claude/skills/react-best-practices/rules/server-cache-react.md +26 -0
  210. package/template/.claude/skills/react-best-practices/rules/server-parallel-fetching.md +79 -0
  211. package/template/.claude/skills/react-best-practices/rules/server-serialization.md +38 -0
  212. package/template/.claude/skills/remotion-best-practices/SKILL.md +43 -0
  213. package/template/.claude/skills/remotion-best-practices/rules/3d.md +86 -0
  214. package/template/.claude/skills/remotion-best-practices/rules/animations.md +29 -0
  215. package/template/.claude/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx +173 -0
  216. package/template/.claude/skills/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +100 -0
  217. package/template/.claude/skills/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +108 -0
  218. package/template/.claude/skills/remotion-best-practices/rules/assets.md +78 -0
  219. package/template/.claude/skills/remotion-best-practices/rules/audio.md +172 -0
  220. package/template/.claude/skills/remotion-best-practices/rules/calculate-metadata.md +104 -0
  221. package/template/.claude/skills/remotion-best-practices/rules/can-decode.md +75 -0
  222. package/template/.claude/skills/remotion-best-practices/rules/charts.md +58 -0
  223. package/template/.claude/skills/remotion-best-practices/rules/compositions.md +146 -0
  224. package/template/.claude/skills/remotion-best-practices/rules/display-captions.md +126 -0
  225. package/template/.claude/skills/remotion-best-practices/rules/extract-frames.md +229 -0
  226. package/template/.claude/skills/remotion-best-practices/rules/fonts.md +152 -0
  227. package/template/.claude/skills/remotion-best-practices/rules/get-audio-duration.md +58 -0
  228. package/template/.claude/skills/remotion-best-practices/rules/get-video-dimensions.md +68 -0
  229. package/template/.claude/skills/remotion-best-practices/rules/get-video-duration.md +58 -0
  230. package/template/.claude/skills/remotion-best-practices/rules/gifs.md +138 -0
  231. package/template/.claude/skills/remotion-best-practices/rules/images.md +130 -0
  232. package/template/.claude/skills/remotion-best-practices/rules/import-srt-captions.md +67 -0
  233. package/template/.claude/skills/remotion-best-practices/rules/lottie.md +68 -0
  234. package/template/.claude/skills/remotion-best-practices/rules/measuring-dom-nodes.md +35 -0
  235. package/template/.claude/skills/remotion-best-practices/rules/measuring-text.md +143 -0
  236. package/template/.claude/skills/remotion-best-practices/rules/sequencing.md +106 -0
  237. package/template/.claude/skills/remotion-best-practices/rules/tailwind.md +11 -0
  238. package/template/.claude/skills/remotion-best-practices/rules/text-animations.md +20 -0
  239. package/template/.claude/skills/remotion-best-practices/rules/timing.md +179 -0
  240. package/template/.claude/skills/remotion-best-practices/rules/transcribe-captions.md +19 -0
  241. package/template/.claude/skills/remotion-best-practices/rules/transitions.md +122 -0
  242. package/template/.claude/skills/remotion-best-practices/rules/trimming.md +53 -0
  243. package/template/.claude/skills/remotion-best-practices/rules/videos.md +171 -0
  244. package/template/.claude/skills/search/SKILL.md +220 -0
  245. package/template/.claude/skills/spec/SKILL.md +377 -0
  246. package/template/.claude/skills/startup/SKILL.md +310 -0
  247. package/template/.claude/skills/web-architect/SKILL.md +309 -0
  248. package/template/.claude/skills/x-algorithm/SKILL.md +305 -0
  249. package/template/.jfl/config.json +8 -0
  250. package/template/.mcp.json +11 -0
  251. package/template/CLAUDE.md +960 -0
  252. package/template/content/.gitkeep +0 -0
  253. package/template/context-hub +3 -0
  254. package/template/knowledge/BRAND_BRIEF.md +124 -0
  255. package/template/knowledge/BRAND_DECISIONS.md +168 -0
  256. package/template/knowledge/NARRATIVE.md +114 -0
  257. package/template/knowledge/ROADMAP.md +128 -0
  258. package/template/knowledge/THESIS.md +108 -0
  259. package/template/knowledge/VISION.md +74 -0
  260. package/template/knowledge/VOICE_AND_TONE.md +146 -0
  261. package/template/previews/.gitkeep +0 -0
  262. package/template/scripts/session/auto-commit.sh +245 -0
  263. package/template/scripts/session/auto-merge.sh +325 -0
  264. package/template/scripts/session/jfl-doctor.sh +587 -0
  265. package/template/scripts/session/session-end.sh +194 -0
  266. package/template/scripts/session/session-init.sh +163 -0
  267. package/template/scripts/session/session-sync.sh +167 -0
  268. package/template/scripts/session/test-context-preservation.sh +160 -0
  269. package/template/skills/agent-browser/SKILL.md +116 -0
  270. package/template/skills/brand-architect/SKILL.md +240 -0
  271. package/template/skills/brand-architect/config.yaml +137 -0
  272. package/template/skills/campaign-hud/config.yaml +112 -0
  273. package/template/skills/content-creator/SKILL.md +294 -0
  274. package/template/skills/debug/MULTI_AGENT.md +360 -0
  275. package/template/skills/debug/SKILL.md +549 -0
  276. package/template/skills/fly-deploy/SKILL.md +676 -0
  277. package/template/skills/founder-video/SKILL.md +467 -0
  278. package/template/skills/hud/SKILL.md +204 -0
  279. package/template/skills/ralph-tui/SKILL.md +210 -0
  280. package/template/skills/react-best-practices/AGENTS.md +2249 -0
  281. package/template/skills/react-best-practices/README.md +123 -0
  282. package/template/skills/react-best-practices/SKILL.md +125 -0
  283. package/template/skills/react-best-practices/metadata.json +15 -0
  284. package/template/skills/react-best-practices/rules/_sections.md +46 -0
  285. package/template/skills/react-best-practices/rules/_template.md +28 -0
  286. package/template/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  287. package/template/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
  288. package/template/skills/react-best-practices/rules/async-api-routes.md +38 -0
  289. package/template/skills/react-best-practices/rules/async-defer-await.md +80 -0
  290. package/template/skills/react-best-practices/rules/async-dependencies.md +36 -0
  291. package/template/skills/react-best-practices/rules/async-parallel.md +28 -0
  292. package/template/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
  293. package/template/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
  294. package/template/skills/react-best-practices/rules/bundle-conditional.md +31 -0
  295. package/template/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
  296. package/template/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  297. package/template/skills/react-best-practices/rules/bundle-preload.md +50 -0
  298. package/template/skills/react-best-practices/rules/client-event-listeners.md +74 -0
  299. package/template/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
  300. package/template/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
  301. package/template/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
  302. package/template/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
  303. package/template/skills/react-best-practices/rules/js-cache-storage.md +70 -0
  304. package/template/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
  305. package/template/skills/react-best-practices/rules/js-early-exit.md +50 -0
  306. package/template/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
  307. package/template/skills/react-best-practices/rules/js-index-maps.md +37 -0
  308. package/template/skills/react-best-practices/rules/js-length-check-first.md +49 -0
  309. package/template/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
  310. package/template/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
  311. package/template/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  312. package/template/skills/react-best-practices/rules/rendering-activity.md +26 -0
  313. package/template/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  314. package/template/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
  315. package/template/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
  316. package/template/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  317. package/template/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  318. package/template/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
  319. package/template/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
  320. package/template/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
  321. package/template/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
  322. package/template/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
  323. package/template/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  324. package/template/skills/react-best-practices/rules/rerender-memo.md +44 -0
  325. package/template/skills/react-best-practices/rules/rerender-transitions.md +40 -0
  326. package/template/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
  327. package/template/skills/react-best-practices/rules/server-cache-lru.md +41 -0
  328. package/template/skills/react-best-practices/rules/server-cache-react.md +26 -0
  329. package/template/skills/react-best-practices/rules/server-parallel-fetching.md +79 -0
  330. package/template/skills/react-best-practices/rules/server-serialization.md +38 -0
  331. package/template/skills/remotion-best-practices/SKILL.md +43 -0
  332. package/template/skills/remotion-best-practices/rules/3d.md +86 -0
  333. package/template/skills/remotion-best-practices/rules/animations.md +29 -0
  334. package/template/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx +173 -0
  335. package/template/skills/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +100 -0
  336. package/template/skills/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +108 -0
  337. package/template/skills/remotion-best-practices/rules/assets.md +78 -0
  338. package/template/skills/remotion-best-practices/rules/audio.md +172 -0
  339. package/template/skills/remotion-best-practices/rules/calculate-metadata.md +104 -0
  340. package/template/skills/remotion-best-practices/rules/can-decode.md +75 -0
  341. package/template/skills/remotion-best-practices/rules/charts.md +58 -0
  342. package/template/skills/remotion-best-practices/rules/compositions.md +146 -0
  343. package/template/skills/remotion-best-practices/rules/display-captions.md +126 -0
  344. package/template/skills/remotion-best-practices/rules/extract-frames.md +229 -0
  345. package/template/skills/remotion-best-practices/rules/fonts.md +152 -0
  346. package/template/skills/remotion-best-practices/rules/get-audio-duration.md +58 -0
  347. package/template/skills/remotion-best-practices/rules/get-video-dimensions.md +68 -0
  348. package/template/skills/remotion-best-practices/rules/get-video-duration.md +58 -0
  349. package/template/skills/remotion-best-practices/rules/gifs.md +138 -0
  350. package/template/skills/remotion-best-practices/rules/images.md +130 -0
  351. package/template/skills/remotion-best-practices/rules/import-srt-captions.md +67 -0
  352. package/template/skills/remotion-best-practices/rules/lottie.md +68 -0
  353. package/template/skills/remotion-best-practices/rules/measuring-dom-nodes.md +35 -0
  354. package/template/skills/remotion-best-practices/rules/measuring-text.md +143 -0
  355. package/template/skills/remotion-best-practices/rules/sequencing.md +106 -0
  356. package/template/skills/remotion-best-practices/rules/tailwind.md +11 -0
  357. package/template/skills/remotion-best-practices/rules/text-animations.md +20 -0
  358. package/template/skills/remotion-best-practices/rules/timing.md +179 -0
  359. package/template/skills/remotion-best-practices/rules/transcribe-captions.md +19 -0
  360. package/template/skills/remotion-best-practices/rules/transitions.md +122 -0
  361. package/template/skills/remotion-best-practices/rules/trimming.md +53 -0
  362. package/template/skills/remotion-best-practices/rules/videos.md +171 -0
  363. package/template/skills/search/SKILL.md +220 -0
  364. package/template/skills/spec/SKILL.md +377 -0
  365. package/template/skills/startup/SKILL.md +310 -0
  366. package/template/skills/web-architect/SKILL.md +309 -0
  367. package/template/skills/x-algorithm/SKILL.md +305 -0
  368. package/template/suggestions/.gitkeep +0 -0
  369. package/template/templates/QUICKSTART_SKILL_TO_PRODUCT.md +242 -0
  370. package/template/templates/brand/BRAND_BRIEF.md +124 -0
  371. package/template/templates/brand/BRAND_DECISIONS.md +168 -0
  372. package/template/templates/brand/BRAND_GUIDELINES.md +251 -0
  373. package/template/templates/brand/VOICE_AND_TONE.md +146 -0
  374. package/template/templates/brand/global.css +240 -0
  375. package/template/templates/collaboration/CONTRIBUTOR.md +74 -0
  376. package/template/templates/collaboration/CRM.md +97 -0
  377. package/template/templates/collaboration/TASKS.md +83 -0
  378. package/template/templates/strategic/NARRATIVE.md +114 -0
  379. package/template/templates/strategic/ROADMAP.md +128 -0
  380. package/template/templates/strategic/THESIS.md +108 -0
  381. package/template/templates/strategic/VISION.md +74 -0
@@ -0,0 +1,642 @@
1
+ /**
2
+ * jfl context-hub - Unified context layer for AI agents
3
+ *
4
+ * Provides context from journal, knowledge docs, and code to any AI.
5
+ * Works locally (CLI) and hosted (platform).
6
+ *
7
+ * @purpose CLI command for Context Hub daemon management
8
+ */
9
+ import chalk from "chalk";
10
+ import ora from "ora";
11
+ import { spawn } from "child_process";
12
+ import * as fs from "fs";
13
+ import * as path from "path";
14
+ import * as http from "http";
15
+ const DEFAULT_PORT = 4242;
16
+ const PID_FILE = ".jfl/context-hub.pid";
17
+ const LOG_FILE = ".jfl/logs/context-hub.log";
18
+ const TOKEN_FILE = ".jfl/context-hub.token";
19
+ // ============================================================================
20
+ // Security
21
+ // ============================================================================
22
+ function generateToken() {
23
+ return Array.from({ length: 32 }, () => Math.floor(Math.random() * 16).toString(16)).join('');
24
+ }
25
+ function getTokenFile(projectRoot) {
26
+ return path.join(projectRoot, TOKEN_FILE);
27
+ }
28
+ function getOrCreateToken(projectRoot) {
29
+ const tokenFile = getTokenFile(projectRoot);
30
+ if (fs.existsSync(tokenFile)) {
31
+ return fs.readFileSync(tokenFile, 'utf-8').trim();
32
+ }
33
+ const token = generateToken();
34
+ fs.writeFileSync(tokenFile, token, { mode: 0o600 }); // Owner read/write only
35
+ return token;
36
+ }
37
+ function validateAuth(req, projectRoot) {
38
+ const tokenFile = getTokenFile(projectRoot);
39
+ // If no token file exists, allow access (backwards compatibility during migration)
40
+ if (!fs.existsSync(tokenFile)) {
41
+ return true;
42
+ }
43
+ const expectedToken = fs.readFileSync(tokenFile, 'utf-8').trim();
44
+ const authHeader = req.headers['authorization'];
45
+ if (!authHeader) {
46
+ return false;
47
+ }
48
+ // Support "Bearer <token>" format
49
+ const providedToken = authHeader.startsWith('Bearer ')
50
+ ? authHeader.slice(7)
51
+ : authHeader;
52
+ return providedToken === expectedToken;
53
+ }
54
+ function isPortInUse(port) {
55
+ return new Promise((resolve) => {
56
+ const server = http.createServer();
57
+ server.once('error', (err) => {
58
+ if (err.code === 'EADDRINUSE') {
59
+ resolve(true);
60
+ }
61
+ else {
62
+ resolve(false);
63
+ }
64
+ });
65
+ server.once('listening', () => {
66
+ server.close();
67
+ resolve(false);
68
+ });
69
+ server.listen(port);
70
+ });
71
+ }
72
+ // ============================================================================
73
+ // Journal Reader
74
+ // ============================================================================
75
+ function readJournalEntries(projectRoot, limit = 20) {
76
+ const journalDir = path.join(projectRoot, ".jfl", "journal");
77
+ const items = [];
78
+ if (!fs.existsSync(journalDir)) {
79
+ return items;
80
+ }
81
+ const files = fs.readdirSync(journalDir)
82
+ .filter(f => f.endsWith(".jsonl"))
83
+ .sort()
84
+ .reverse();
85
+ for (const file of files) {
86
+ if (items.length >= limit)
87
+ break;
88
+ const filePath = path.join(journalDir, file);
89
+ const content = fs.readFileSync(filePath, "utf-8");
90
+ const lines = content.trim().split("\n").filter(l => l.trim());
91
+ for (const line of lines.reverse()) {
92
+ if (items.length >= limit)
93
+ break;
94
+ try {
95
+ const entry = JSON.parse(line);
96
+ items.push({
97
+ source: "journal",
98
+ type: entry.type || "entry",
99
+ title: entry.title || "Untitled",
100
+ content: entry.summary || entry.detail || "",
101
+ timestamp: entry.ts,
102
+ path: filePath
103
+ });
104
+ }
105
+ catch {
106
+ // Skip malformed lines
107
+ }
108
+ }
109
+ }
110
+ return items;
111
+ }
112
+ // ============================================================================
113
+ // Knowledge Reader
114
+ // ============================================================================
115
+ function readKnowledgeDocs(projectRoot) {
116
+ const knowledgeDir = path.join(projectRoot, "knowledge");
117
+ const items = [];
118
+ if (!fs.existsSync(knowledgeDir)) {
119
+ return items;
120
+ }
121
+ const priorityFiles = [
122
+ "VISION.md",
123
+ "ROADMAP.md",
124
+ "NARRATIVE.md",
125
+ "THESIS.md",
126
+ "BRAND_DECISIONS.md",
127
+ "TASKS.md"
128
+ ];
129
+ for (const filename of priorityFiles) {
130
+ const filePath = path.join(knowledgeDir, filename);
131
+ if (fs.existsSync(filePath)) {
132
+ const content = fs.readFileSync(filePath, "utf-8");
133
+ const title = filename.replace(".md", "").replace(/_/g, " ");
134
+ items.push({
135
+ source: "knowledge",
136
+ type: "doc",
137
+ title,
138
+ content: content.slice(0, 2000), // Truncate for context
139
+ path: filePath
140
+ });
141
+ }
142
+ }
143
+ return items;
144
+ }
145
+ // ============================================================================
146
+ // Code Context Reader
147
+ // ============================================================================
148
+ function extractPurpose(content) {
149
+ const match = content.match(/@purpose\s+(.+?)(?:\n|\*)/i);
150
+ return match ? match[1].trim() : null;
151
+ }
152
+ function readCodeContext(projectRoot, limit = 30) {
153
+ const items = [];
154
+ // Look for files with @purpose in common locations
155
+ const searchDirs = [
156
+ path.join(projectRoot, "src"),
157
+ path.join(projectRoot, "app"),
158
+ path.join(projectRoot, "lib"),
159
+ path.join(projectRoot, "components"),
160
+ path.join(projectRoot, "product", "src"),
161
+ path.join(projectRoot, "product", "packages")
162
+ ];
163
+ const extensions = [".ts", ".tsx", ".js", ".jsx"];
164
+ function scanDir(dir, depth = 0) {
165
+ if (depth > 4 || items.length >= limit)
166
+ return;
167
+ if (!fs.existsSync(dir))
168
+ return;
169
+ try {
170
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
171
+ for (const entry of entries) {
172
+ if (items.length >= limit)
173
+ break;
174
+ if (entry.name.startsWith(".") || entry.name === "node_modules")
175
+ continue;
176
+ const fullPath = path.join(dir, entry.name);
177
+ if (entry.isDirectory()) {
178
+ scanDir(fullPath, depth + 1);
179
+ }
180
+ else if (extensions.some(ext => entry.name.endsWith(ext))) {
181
+ try {
182
+ const content = fs.readFileSync(fullPath, "utf-8");
183
+ const purpose = extractPurpose(content);
184
+ if (purpose) {
185
+ items.push({
186
+ source: "code",
187
+ type: "file",
188
+ title: entry.name,
189
+ content: purpose,
190
+ path: fullPath
191
+ });
192
+ }
193
+ }
194
+ catch {
195
+ // Skip unreadable files
196
+ }
197
+ }
198
+ }
199
+ }
200
+ catch {
201
+ // Skip unreadable directories
202
+ }
203
+ }
204
+ for (const dir of searchDirs) {
205
+ scanDir(dir);
206
+ }
207
+ return items;
208
+ }
209
+ // ============================================================================
210
+ // Search & Scoring (TF-IDF style)
211
+ // ============================================================================
212
+ function tokenize(text) {
213
+ return text
214
+ .toLowerCase()
215
+ .replace(/[^\w\s]/g, " ")
216
+ .split(/\s+/)
217
+ .filter(t => t.length > 2);
218
+ }
219
+ function computeTF(tokens) {
220
+ const tf = new Map();
221
+ for (const token of tokens) {
222
+ tf.set(token, (tf.get(token) || 0) + 1);
223
+ }
224
+ // Normalize by document length
225
+ for (const [term, count] of tf) {
226
+ tf.set(term, count / tokens.length);
227
+ }
228
+ return tf;
229
+ }
230
+ function computeIDF(documents) {
231
+ const idf = new Map();
232
+ const N = documents.length;
233
+ // Count documents containing each term
234
+ const docCount = new Map();
235
+ for (const doc of documents) {
236
+ const uniqueTerms = new Set(doc);
237
+ for (const term of uniqueTerms) {
238
+ docCount.set(term, (docCount.get(term) || 0) + 1);
239
+ }
240
+ }
241
+ // Compute IDF
242
+ for (const [term, count] of docCount) {
243
+ idf.set(term, Math.log((N + 1) / (count + 1)) + 1);
244
+ }
245
+ return idf;
246
+ }
247
+ function scoreItem(item, queryTokens, idf) {
248
+ const text = `${item.title} ${item.content}`;
249
+ const tokens = tokenize(text);
250
+ const tf = computeTF(tokens);
251
+ let score = 0;
252
+ for (const queryTerm of queryTokens) {
253
+ const termTF = tf.get(queryTerm) || 0;
254
+ const termIDF = idf.get(queryTerm) || 1;
255
+ score += termTF * termIDF;
256
+ }
257
+ // Boost title matches
258
+ const titleTokens = new Set(tokenize(item.title));
259
+ for (const queryTerm of queryTokens) {
260
+ if (titleTokens.has(queryTerm)) {
261
+ score *= 1.5;
262
+ }
263
+ }
264
+ // Boost recent items (journal)
265
+ if (item.source === "journal" && item.timestamp) {
266
+ const age = Date.now() - new Date(item.timestamp).getTime();
267
+ const daysSinceUpdate = age / (1000 * 60 * 60 * 24);
268
+ if (daysSinceUpdate < 7) {
269
+ score *= 1.3; // Boost recent entries
270
+ }
271
+ }
272
+ return score;
273
+ }
274
+ function semanticSearch(items, query) {
275
+ const queryTokens = tokenize(query);
276
+ if (queryTokens.length === 0)
277
+ return items;
278
+ // Build corpus for IDF
279
+ const documents = items.map(item => tokenize(`${item.title} ${item.content}`));
280
+ const idf = computeIDF(documents);
281
+ // Score and sort
282
+ for (const item of items) {
283
+ item.relevance = scoreItem(item, queryTokens, idf);
284
+ }
285
+ return items
286
+ .filter(item => (item.relevance || 0) > 0)
287
+ .sort((a, b) => (b.relevance || 0) - (a.relevance || 0));
288
+ }
289
+ // ============================================================================
290
+ // Orchestrator
291
+ // ============================================================================
292
+ function getUnifiedContext(projectRoot, query, taskType) {
293
+ const journalItems = readJournalEntries(projectRoot);
294
+ const knowledgeItems = readKnowledgeDocs(projectRoot);
295
+ const codeItems = readCodeContext(projectRoot);
296
+ let items = [...journalItems, ...knowledgeItems, ...codeItems];
297
+ // Apply semantic search if query provided
298
+ if (query) {
299
+ items = semanticSearch(items, query);
300
+ }
301
+ return {
302
+ items,
303
+ sources: {
304
+ journal: journalItems.length > 0,
305
+ knowledge: knowledgeItems.length > 0,
306
+ code: codeItems.length > 0,
307
+ memory: false
308
+ },
309
+ query,
310
+ taskType
311
+ };
312
+ }
313
+ // ============================================================================
314
+ // HTTP Server
315
+ // ============================================================================
316
+ function createServer(projectRoot, port) {
317
+ const server = http.createServer((req, res) => {
318
+ // CORS - include Authorization header
319
+ res.setHeader("Access-Control-Allow-Origin", "*");
320
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
321
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
322
+ if (req.method === "OPTIONS") {
323
+ res.writeHead(200);
324
+ res.end();
325
+ return;
326
+ }
327
+ const url = new URL(req.url || "/", `http://localhost:${port}`);
328
+ // Health check - no auth required (for monitoring)
329
+ if (url.pathname === "/health" && req.method === "GET") {
330
+ res.writeHead(200, { "Content-Type": "application/json" });
331
+ res.end(JSON.stringify({ status: "ok", port }));
332
+ return;
333
+ }
334
+ // All other endpoints require auth
335
+ if (!validateAuth(req, projectRoot)) {
336
+ res.writeHead(401, { "Content-Type": "application/json" });
337
+ res.end(JSON.stringify({
338
+ error: "Unauthorized",
339
+ message: "Provide token via Authorization header: Bearer <token>",
340
+ tokenFile: ".jfl/context-hub.token"
341
+ }));
342
+ return;
343
+ }
344
+ // Status
345
+ if (url.pathname === "/api/context/status" && req.method === "GET") {
346
+ const context = getUnifiedContext(projectRoot);
347
+ res.writeHead(200, { "Content-Type": "application/json" });
348
+ res.end(JSON.stringify({
349
+ status: "running",
350
+ port,
351
+ sources: context.sources,
352
+ itemCount: context.items.length
353
+ }));
354
+ return;
355
+ }
356
+ // Get context
357
+ if (url.pathname === "/api/context" && req.method === "POST") {
358
+ let body = "";
359
+ req.on("data", chunk => body += chunk);
360
+ req.on("end", () => {
361
+ try {
362
+ const { query, taskType, maxItems } = JSON.parse(body || "{}");
363
+ const context = getUnifiedContext(projectRoot, query, taskType);
364
+ if (maxItems && context.items.length > maxItems) {
365
+ context.items = context.items.slice(0, maxItems);
366
+ }
367
+ res.writeHead(200, { "Content-Type": "application/json" });
368
+ res.end(JSON.stringify(context));
369
+ }
370
+ catch (err) {
371
+ res.writeHead(400, { "Content-Type": "application/json" });
372
+ res.end(JSON.stringify({ error: err.message }));
373
+ }
374
+ });
375
+ return;
376
+ }
377
+ // Search
378
+ if (url.pathname === "/api/context/search" && req.method === "POST") {
379
+ let body = "";
380
+ req.on("data", chunk => body += chunk);
381
+ req.on("end", () => {
382
+ try {
383
+ const { query, maxItems = 20 } = JSON.parse(body || "{}");
384
+ if (!query) {
385
+ res.writeHead(400, { "Content-Type": "application/json" });
386
+ res.end(JSON.stringify({ error: "query required" }));
387
+ return;
388
+ }
389
+ const context = getUnifiedContext(projectRoot, query);
390
+ context.items = context.items
391
+ .filter(item => item.relevance && item.relevance > 0)
392
+ .slice(0, maxItems);
393
+ res.writeHead(200, { "Content-Type": "application/json" });
394
+ res.end(JSON.stringify(context));
395
+ }
396
+ catch (err) {
397
+ res.writeHead(400, { "Content-Type": "application/json" });
398
+ res.end(JSON.stringify({ error: err.message }));
399
+ }
400
+ });
401
+ return;
402
+ }
403
+ // 404
404
+ res.writeHead(404, { "Content-Type": "application/json" });
405
+ res.end(JSON.stringify({ error: "Not found" }));
406
+ });
407
+ return server;
408
+ }
409
+ // ============================================================================
410
+ // Daemon Management
411
+ // ============================================================================
412
+ function getPidFile(projectRoot) {
413
+ return path.join(projectRoot, PID_FILE);
414
+ }
415
+ function getLogFile(projectRoot) {
416
+ const logFile = path.join(projectRoot, LOG_FILE);
417
+ const logDir = path.dirname(logFile);
418
+ if (!fs.existsSync(logDir)) {
419
+ fs.mkdirSync(logDir, { recursive: true });
420
+ }
421
+ return logFile;
422
+ }
423
+ function isRunning(projectRoot) {
424
+ const pidFile = getPidFile(projectRoot);
425
+ if (!fs.existsSync(pidFile)) {
426
+ return { running: false };
427
+ }
428
+ const pid = parseInt(fs.readFileSync(pidFile, "utf-8").trim(), 10);
429
+ try {
430
+ process.kill(pid, 0); // Check if process exists
431
+ return { running: true, pid };
432
+ }
433
+ catch {
434
+ // Process doesn't exist, clean up stale PID file
435
+ fs.unlinkSync(pidFile);
436
+ return { running: false };
437
+ }
438
+ }
439
+ async function startDaemon(projectRoot, port) {
440
+ const status = isRunning(projectRoot);
441
+ if (status.running) {
442
+ return { success: true, message: `Context Hub already running (PID: ${status.pid})` };
443
+ }
444
+ // Check if port is in use by another process
445
+ const portInUse = await isPortInUse(port);
446
+ if (portInUse) {
447
+ return { success: false, message: `Port ${port} is already in use by another process` };
448
+ }
449
+ const logFile = getLogFile(projectRoot);
450
+ const pidFile = getPidFile(projectRoot);
451
+ // Generate auth token before starting
452
+ const token = getOrCreateToken(projectRoot);
453
+ // Start as detached process
454
+ const child = spawn(process.execPath, [process.argv[1], "context-hub", "serve", "--port", String(port)], {
455
+ cwd: projectRoot,
456
+ detached: true,
457
+ stdio: ["ignore", fs.openSync(logFile, "a"), fs.openSync(logFile, "a")]
458
+ });
459
+ child.unref();
460
+ // Write PID file
461
+ if (child.pid) {
462
+ fs.writeFileSync(pidFile, String(child.pid));
463
+ return { success: true, message: `Started (PID: ${child.pid}). Token: ${token.slice(0, 8)}...` };
464
+ }
465
+ return { success: false, message: "Failed to spawn daemon process" };
466
+ }
467
+ async function stopDaemon(projectRoot) {
468
+ const status = isRunning(projectRoot);
469
+ if (!status.running || !status.pid) {
470
+ return { success: true, message: "Context Hub is not running" };
471
+ }
472
+ const pidFile = getPidFile(projectRoot);
473
+ const tokenFile = getTokenFile(projectRoot);
474
+ try {
475
+ // Send SIGTERM first (graceful)
476
+ process.kill(status.pid, "SIGTERM");
477
+ // Wait up to 3 seconds for graceful shutdown
478
+ let attempts = 0;
479
+ while (attempts < 6) {
480
+ await new Promise(resolve => setTimeout(resolve, 500));
481
+ try {
482
+ process.kill(status.pid, 0); // Check if still running
483
+ attempts++;
484
+ }
485
+ catch {
486
+ // Process is gone
487
+ break;
488
+ }
489
+ }
490
+ // If still running after 3 seconds, force kill
491
+ try {
492
+ process.kill(status.pid, 0);
493
+ process.kill(status.pid, "SIGKILL");
494
+ await new Promise(resolve => setTimeout(resolve, 100));
495
+ }
496
+ catch {
497
+ // Process is gone, that's fine
498
+ }
499
+ // Clean up PID and token files
500
+ if (fs.existsSync(pidFile)) {
501
+ fs.unlinkSync(pidFile);
502
+ }
503
+ if (fs.existsSync(tokenFile)) {
504
+ fs.unlinkSync(tokenFile);
505
+ }
506
+ return { success: true, message: "Context Hub stopped" };
507
+ }
508
+ catch (err) {
509
+ return { success: false, message: `Failed to stop daemon: ${err}` };
510
+ }
511
+ }
512
+ // ============================================================================
513
+ // CLI Command
514
+ // ============================================================================
515
+ export async function contextHubCommand(action, options = {}) {
516
+ const projectRoot = process.cwd();
517
+ const port = options.port || DEFAULT_PORT;
518
+ // Ensure .jfl directory exists
519
+ const jflDir = path.join(projectRoot, ".jfl");
520
+ if (!fs.existsSync(jflDir)) {
521
+ fs.mkdirSync(jflDir, { recursive: true });
522
+ }
523
+ switch (action) {
524
+ case "start": {
525
+ const spinner = ora("Starting Context Hub...").start();
526
+ const result = await startDaemon(projectRoot, port);
527
+ if (result.success) {
528
+ // Check if it was already running
529
+ if (result.message.includes("already running")) {
530
+ spinner.info(result.message);
531
+ }
532
+ else {
533
+ // Wait for server to be ready
534
+ await new Promise(resolve => setTimeout(resolve, 500));
535
+ const status = isRunning(projectRoot);
536
+ spinner.succeed(`Context Hub started on port ${port} (PID: ${status.pid})`);
537
+ console.log(chalk.gray(` Token file: .jfl/context-hub.token`));
538
+ }
539
+ }
540
+ else {
541
+ spinner.fail(result.message);
542
+ }
543
+ break;
544
+ }
545
+ case "stop": {
546
+ const spinner = ora("Stopping Context Hub...").start();
547
+ const result = await stopDaemon(projectRoot);
548
+ if (result.success) {
549
+ spinner.succeed(result.message);
550
+ }
551
+ else {
552
+ spinner.fail(result.message);
553
+ }
554
+ break;
555
+ }
556
+ case "restart": {
557
+ await contextHubCommand("stop", options);
558
+ await new Promise(resolve => setTimeout(resolve, 500));
559
+ await contextHubCommand("start", options);
560
+ break;
561
+ }
562
+ case "status": {
563
+ const status = isRunning(projectRoot);
564
+ if (status.running) {
565
+ console.log(chalk.green(`\n Context Hub is running`));
566
+ console.log(chalk.gray(` PID: ${status.pid}`));
567
+ console.log(chalk.gray(` Port: ${port}`));
568
+ // Try to get more info from the API
569
+ try {
570
+ const response = await fetch(`http://localhost:${port}/api/context/status`);
571
+ const data = await response.json();
572
+ console.log(chalk.gray(` Sources: ${Object.entries(data.sources).filter(([, v]) => v).map(([k]) => k).join(", ")}`));
573
+ console.log(chalk.gray(` Items: ${data.itemCount}`));
574
+ }
575
+ catch {
576
+ // Server might not be responding yet
577
+ }
578
+ console.log();
579
+ }
580
+ else {
581
+ console.log(chalk.yellow("\n Context Hub is not running"));
582
+ console.log(chalk.gray(" Run: jfl context-hub start\n"));
583
+ }
584
+ break;
585
+ }
586
+ case "ensure": {
587
+ const status = isRunning(projectRoot);
588
+ if (status.running) {
589
+ // Already running, nothing to do
590
+ return;
591
+ }
592
+ // Start silently
593
+ await startDaemon(projectRoot, port);
594
+ break;
595
+ }
596
+ case "serve": {
597
+ // Run server in foreground (used by daemon)
598
+ const server = createServer(projectRoot, port);
599
+ server.listen(port, () => {
600
+ console.log(`Context Hub listening on port ${port}`);
601
+ });
602
+ // Handle shutdown
603
+ process.on("SIGTERM", () => {
604
+ server.close();
605
+ process.exit(0);
606
+ });
607
+ process.on("SIGINT", () => {
608
+ server.close();
609
+ process.exit(0);
610
+ });
611
+ break;
612
+ }
613
+ case "query": {
614
+ // Quick query for testing
615
+ const context = getUnifiedContext(projectRoot);
616
+ console.log(chalk.bold("\n Context Hub Query\n"));
617
+ console.log(chalk.gray(` Sources: ${Object.entries(context.sources).filter(([, v]) => v).map(([k]) => k).join(", ")}`));
618
+ console.log(chalk.gray(` Items: ${context.items.length}\n`));
619
+ for (const item of context.items.slice(0, 10)) {
620
+ console.log(chalk.cyan(` [${item.source}] ${item.title}`));
621
+ console.log(chalk.gray(` ${item.content.slice(0, 100)}${item.content.length > 100 ? "..." : ""}`));
622
+ }
623
+ console.log();
624
+ break;
625
+ }
626
+ default: {
627
+ console.log(chalk.bold("\n Context Hub - Unified context for AI agents\n"));
628
+ console.log(chalk.gray(" Commands:"));
629
+ console.log(" jfl context-hub start Start the daemon");
630
+ console.log(" jfl context-hub stop Stop the daemon");
631
+ console.log(" jfl context-hub restart Restart the daemon");
632
+ console.log(" jfl context-hub status Check if running");
633
+ console.log(" jfl context-hub ensure Start if not running (for hooks)");
634
+ console.log(" jfl context-hub query Quick context query");
635
+ console.log();
636
+ console.log(chalk.gray(" Options:"));
637
+ console.log(" --port <port> Port to run on (default: 4242)");
638
+ console.log();
639
+ }
640
+ }
641
+ }
642
+ //# sourceMappingURL=context-hub.js.map