@koda-sl/baker-cli 0.449.0-dev.bd86e5817 → 0.450.0-dev.b454c3dd2

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 (443) hide show
  1. package/README.md +11 -6
  2. package/dist/{account-AL2ZDSR7.js → account-XQXC7BR6.js} +5 -4
  3. package/dist/{account-AL2ZDSR7.js.map → account-XQXC7BR6.js.map} +1 -1
  4. package/dist/{accounts-HAFCLSR5.js → accounts-722UY53A.js} +4 -3
  5. package/dist/{accounts-HAFCLSR5.js.map → accounts-722UY53A.js.map} +1 -1
  6. package/dist/{accounts-O5MFO3QQ.js → accounts-E67BMK7T.js} +6 -5
  7. package/dist/{accounts-O5MFO3QQ.js.map → accounts-E67BMK7T.js.map} +1 -1
  8. package/dist/{actions-P35MEMGN.js → actions-6TQMSVWD.js} +18 -18
  9. package/dist/{add-5GAN6CVO.js → add-2BEGRHUX.js} +28 -5
  10. package/dist/add-2BEGRHUX.js.map +1 -0
  11. package/dist/{add-6DTC6X5G.js → add-LEMKEOPO.js} +3 -2
  12. package/dist/{add-6DTC6X5G.js.map → add-LEMKEOPO.js.map} +1 -1
  13. package/dist/{ads-73PGA4YC.js → ads-AGYCVD62.js} +4 -4
  14. package/dist/{advertisers-AE75CGVE.js → advertisers-2VQKAYKG.js} +4 -3
  15. package/dist/{advertisers-AE75CGVE.js.map → advertisers-2VQKAYKG.js.map} +1 -1
  16. package/dist/{analytics-FKCXIMPO.js → analytics-IFELDWLL.js} +24 -20
  17. package/dist/analytics-IFELDWLL.js.map +1 -0
  18. package/dist/{analytics-FPWQQGRM.js → analytics-OH5QEH7F.js} +4 -3
  19. package/dist/{analytics-FPWQQGRM.js.map → analytics-OH5QEH7F.js.map} +1 -1
  20. package/dist/{assign-ABN2AQ4J.js → assign-PTUJUCEL.js} +4 -3
  21. package/dist/{assign-ABN2AQ4J.js.map → assign-PTUJUCEL.js.map} +1 -1
  22. package/dist/{audience-size-GNBJY35X.js → audience-size-LRI6GJRT.js} +4 -3
  23. package/dist/{audience-size-GNBJY35X.js.map → audience-size-LRI6GJRT.js.map} +1 -1
  24. package/dist/{audit-3VS63TBW.js → audit-HWP7OPB7.js} +4 -3
  25. package/dist/{audit-3VS63TBW.js.map → audit-HWP7OPB7.js.map} +1 -1
  26. package/dist/{autocomplete-VS3XG3B7.js → autocomplete-J6DHU6MR.js} +4 -3
  27. package/dist/{autocomplete-VS3XG3B7.js.map → autocomplete-J6DHU6MR.js.map} +1 -1
  28. package/dist/{avatars-EKCKHCC3.js → avatars-467OSBD6.js} +4 -4
  29. package/dist/{bid-pricing-Q72B65AY.js → bid-pricing-EO5WLHGV.js} +4 -3
  30. package/dist/{bid-pricing-Q72B65AY.js.map → bid-pricing-EO5WLHGV.js.map} +1 -1
  31. package/dist/{brand-C6PFGGQN.js → brand-YRTEPGBK.js} +2 -2
  32. package/dist/{brief-YFJHQ5VQ.js → brief-OSFJ2V7F.js} +8 -7
  33. package/dist/{brief-YFJHQ5VQ.js.map → brief-OSFJ2V7F.js.map} +1 -1
  34. package/dist/{campaign-groups-KFFYQPU3.js → campaign-groups-PQ6KSQJR.js} +9 -8
  35. package/dist/{campaign-groups-KFFYQPU3.js.map → campaign-groups-PQ6KSQJR.js.map} +1 -1
  36. package/dist/{campaign-writes-FHOS5XZY.js → campaign-writes-5OVLUD5E.js} +4 -3
  37. package/dist/{campaign-writes-FHOS5XZY.js.map → campaign-writes-5OVLUD5E.js.map} +1 -1
  38. package/dist/{campaigns-2NHWBF5C.js → campaigns-6T3NSUT2.js} +12 -11
  39. package/dist/{campaigns-2NHWBF5C.js.map → campaigns-6T3NSUT2.js.map} +1 -1
  40. package/dist/{campaigns-KZYZTXDS.js → campaigns-OYMXDGWX.js} +5 -5
  41. package/dist/{canvas-UJNSHD3B.js → canvas-YQFG52IG.js} +13 -13
  42. package/dist/{capabilities-DJFTRJKS.js → capabilities-PXBKUN2G.js} +4 -3
  43. package/dist/{capabilities-DJFTRJKS.js.map → capabilities-PXBKUN2G.js.map} +1 -1
  44. package/dist/{catalog-ZQX6BGXS.js → catalog-XLXIM7IW.js} +4 -4
  45. package/dist/{chats-D2CSDX5Q.js → chats-UK47UE7C.js} +4 -3
  46. package/dist/{chats-D2CSDX5Q.js.map → chats-UK47UE7C.js.map} +1 -1
  47. package/dist/{chunk-7YCRFMXF.js → chunk-24EB7EDR.js} +3 -3
  48. package/dist/{chunk-5ZDLTE5T.js → chunk-2AOE2MZQ.js} +3 -3
  49. package/dist/{chunk-4SG4RW2P.js → chunk-2VPBIT65.js} +8 -8
  50. package/dist/chunk-4PDHHHUJ.js +537 -0
  51. package/dist/chunk-4PDHHHUJ.js.map +1 -0
  52. package/dist/{chunk-NPY4QUMQ.js → chunk-54C6YDGJ.js} +2 -2
  53. package/dist/{chunk-LZ73CZGP.js → chunk-5WCSKQ7Z.js} +6 -6
  54. package/dist/{chunk-3G3ZDLMI.js → chunk-5ZNTADVR.js} +2 -2
  55. package/dist/{chunk-AEOSAVVL.js → chunk-6F7DVPOS.js} +3 -3
  56. package/dist/{chunk-CJCVIEJ5.js → chunk-6NY2GPR4.js} +3 -3
  57. package/dist/{chunk-CXWFX2AM.js → chunk-6Y7ZBENQ.js} +6 -6
  58. package/dist/{chunk-M242LHLX.js → chunk-7CTMH5AK.js} +3 -3
  59. package/dist/{chunk-XF4JUKVF.js → chunk-7EPXVICM.js} +38 -5
  60. package/dist/chunk-7EPXVICM.js.map +1 -0
  61. package/dist/{chunk-T2PC5AVH.js → chunk-ASI4P6X2.js} +6 -6
  62. package/dist/chunk-ASI4P6X2.js.map +1 -0
  63. package/dist/{chunk-QD7ESRLN.js → chunk-C46GUI2S.js} +2 -2
  64. package/dist/{chunk-6N6WKAJM.js → chunk-CWYAELVG.js} +2 -2
  65. package/dist/{chunk-MXYBTMKB.js → chunk-DCRPXOJJ.js} +2 -2
  66. package/dist/{chunk-GKZ2WU75.js → chunk-FPOGPFAG.js} +3 -14
  67. package/dist/chunk-FPOGPFAG.js.map +1 -0
  68. package/dist/{chunk-JQJDXPCO.js → chunk-FUHN4MFY.js} +2 -2
  69. package/dist/{chunk-S77PZVYM.js → chunk-FYGR3I2A.js} +3 -3
  70. package/dist/{chunk-OZRUJVIQ.js → chunk-H3427GPU.js} +2 -2
  71. package/dist/{chunk-RPUSTYHL.js → chunk-HDLYPC6K.js} +5 -3
  72. package/dist/{chunk-RPUSTYHL.js.map → chunk-HDLYPC6K.js.map} +1 -1
  73. package/dist/{chunk-SSJK7FEV.js → chunk-HR6IWNKE.js} +1196 -1140
  74. package/dist/chunk-HR6IWNKE.js.map +1 -0
  75. package/dist/{chunk-YRQYA2LR.js → chunk-HROZYQ5H.js} +63 -5
  76. package/dist/chunk-HROZYQ5H.js.map +1 -0
  77. package/dist/{chunk-IR6D7K4H.js → chunk-I3ZR655O.js} +2 -2
  78. package/dist/{chunk-YK32GUBN.js → chunk-KMKEYI37.js} +3 -3
  79. package/dist/{chunk-W3ZHJJVT.js → chunk-KS2QY6MK.js} +4 -4
  80. package/dist/{chunk-WNRV4QH7.js → chunk-LYQJ4PZW.js} +5 -5
  81. package/dist/{chunk-B5SCU7MJ.js → chunk-MACCF4JZ.js} +16 -22
  82. package/dist/{chunk-B5SCU7MJ.js.map → chunk-MACCF4JZ.js.map} +1 -1
  83. package/dist/{chunk-CSYSX4D2.js → chunk-N4LAYIIN.js} +2 -2
  84. package/dist/{chunk-4AUMTNVB.js → chunk-NA63BH7V.js} +3 -3
  85. package/dist/{chunk-4BQXAE7Z.js → chunk-NDEE6G2J.js} +2 -2
  86. package/dist/{chunk-EDLZGTGN.js → chunk-NYIGXDUG.js} +1 -39
  87. package/dist/chunk-NYIGXDUG.js.map +1 -0
  88. package/dist/{chunk-DWHIOO7E.js → chunk-QE7W555R.js} +163 -12
  89. package/dist/chunk-QE7W555R.js.map +1 -0
  90. package/dist/{chunk-MELOSESI.js → chunk-R25YLW6H.js} +2 -2
  91. package/dist/{chunk-Y6O7EWYY.js → chunk-RL5CP7N6.js} +5 -5
  92. package/dist/{chunk-DGUNI37S.js → chunk-RX2DKU3W.js} +2 -2
  93. package/dist/{chunk-3HJLHTWP.js → chunk-SJYEY5MV.js} +12 -3
  94. package/dist/{chunk-3HJLHTWP.js.map → chunk-SJYEY5MV.js.map} +1 -1
  95. package/dist/{chunk-VTDMKARH.js → chunk-ULG4QRTV.js} +2 -2
  96. package/dist/{chunk-QRP3PXWN.js → chunk-VL43TNIP.js} +2 -2
  97. package/dist/{chunk-SHL7LOC3.js → chunk-VLMBTPXU.js} +3 -3
  98. package/dist/{chunk-KHRXPQID.js → chunk-VYQ3QJ3C.js} +2 -2
  99. package/dist/{chunk-A4LOJ2VD.js → chunk-WGUQHAJY.js} +2 -2
  100. package/dist/{chunk-ZEYEWPK6.js → chunk-WKQG6TER.js} +2 -2
  101. package/dist/{chunk-3IBYKLXR.js → chunk-ZDMTXQ2Q.js} +2 -2
  102. package/dist/{claim-FZ5OQLMU.js → claim-W6G6VEG5.js} +4 -3
  103. package/dist/{claim-FZ5OQLMU.js.map → claim-W6G6VEG5.js.map} +1 -1
  104. package/dist/cli.js +30 -30
  105. package/dist/{companies-DNI634RC.js → companies-TS6KBATJ.js} +4 -3
  106. package/dist/{companies-DNI634RC.js.map → companies-TS6KBATJ.js.map} +1 -1
  107. package/dist/{complete-2FZMGJV5.js → complete-LYR2HMQU.js} +4 -3
  108. package/dist/{complete-2FZMGJV5.js.map → complete-LYR2HMQU.js.map} +1 -1
  109. package/dist/{connect-QCOGEPP4.js → connect-FCXNVTXG.js} +13 -6
  110. package/dist/{conversation-6IOGV7B7.js → conversation-6ZJGPCXM.js} +4 -3
  111. package/dist/{conversation-6IOGV7B7.js.map → conversation-6ZJGPCXM.js.map} +1 -1
  112. package/dist/{conversions-4SRZPBBX.js → conversions-UHB55MMQ.js} +8 -7
  113. package/dist/{conversions-4SRZPBBX.js.map → conversions-UHB55MMQ.js.map} +1 -1
  114. package/dist/{create-BJNMO6HT.js → create-EX6OWLNM.js} +3 -2
  115. package/dist/{create-BJNMO6HT.js.map → create-EX6OWLNM.js.map} +1 -1
  116. package/dist/{create-RM7HV77Y.js → create-JCA7JPLP.js} +4 -3
  117. package/dist/{create-RM7HV77Y.js.map → create-JCA7JPLP.js.map} +1 -1
  118. package/dist/{create-FX4OJ2XF.js → create-JFSK4BOP.js} +4 -3
  119. package/dist/{create-FX4OJ2XF.js.map → create-JFSK4BOP.js.map} +1 -1
  120. package/dist/{create-VXM34ZWH.js → create-WU22YYU2.js} +4 -3
  121. package/dist/{create-VXM34ZWH.js.map → create-WU22YYU2.js.map} +1 -1
  122. package/dist/{creatives-NJF2U763.js → creatives-FXUQ5WSD.js} +10 -10
  123. package/dist/{creatives-JSWBFQ5R.js → creatives-KGXUOYPE.js} +9 -8
  124. package/dist/{creatives-JSWBFQ5R.js.map → creatives-KGXUOYPE.js.map} +1 -1
  125. package/dist/{credentials-C33K6XCJ.js → credentials-MJC7PGKR.js} +4 -3
  126. package/dist/{credentials-C33K6XCJ.js.map → credentials-MJC7PGKR.js.map} +1 -1
  127. package/dist/{critique-YDKPYZLD.js → critique-GS5VV5ZC.js} +7 -6
  128. package/dist/{critique-YDKPYZLD.js.map → critique-GS5VV5ZC.js.map} +1 -1
  129. package/dist/{critique-ZS4ON3SU.js → critique-TPHR27KH.js} +4 -3
  130. package/dist/{critique-ZS4ON3SU.js.map → critique-TPHR27KH.js.map} +1 -1
  131. package/dist/{crm-R5IXIFIV.js → crm-AVCM5D4G.js} +5 -4
  132. package/dist/{crm-R5IXIFIV.js.map → crm-AVCM5D4G.js.map} +1 -1
  133. package/dist/{crm-52ROSWH5.js → crm-VK44O3ED.js} +5 -4
  134. package/dist/{crm-52ROSWH5.js.map → crm-VK44O3ED.js.map} +1 -1
  135. package/dist/{customers-A36LOZOB.js → customers-XH2DMTFH.js} +6 -5
  136. package/dist/{delete-M2GDLPYN.js → delete-E3R3TKIL.js} +3 -2
  137. package/dist/{delete-M2GDLPYN.js.map → delete-E3R3TKIL.js.map} +1 -1
  138. package/dist/{delete-HGHXY24R.js → delete-KRH2YMSZ.js} +4 -3
  139. package/dist/{delete-HGHXY24R.js.map → delete-KRH2YMSZ.js.map} +1 -1
  140. package/dist/{delete-AIGE4Y4H.js → delete-WI5E3DR3.js} +4 -3
  141. package/dist/{delete-AIGE4Y4H.js.map → delete-WI5E3DR3.js.map} +1 -1
  142. package/dist/{demographics-NTWB2IMG.js → demographics-XV5PBA77.js} +4 -3
  143. package/dist/{demographics-NTWB2IMG.js.map → demographics-XV5PBA77.js.map} +1 -1
  144. package/dist/{discard-2WWQG6OU.js → discard-HTQUUHJR.js} +4 -3
  145. package/dist/{discard-2WWQG6OU.js.map → discard-HTQUUHJR.js.map} +1 -1
  146. package/dist/{domain-Y2LT6JLT.js → domain-RECGZXJB.js} +4 -3
  147. package/dist/{domain-Y2LT6JLT.js.map → domain-RECGZXJB.js.map} +1 -1
  148. package/dist/{draft-SLHAKJ2A.js → draft-2IBSJEKC.js} +4 -3
  149. package/dist/{draft-SLHAKJ2A.js.map → draft-2IBSJEKC.js.map} +1 -1
  150. package/dist/{draft-FJ7WHIXW.js → draft-PVTX6QT6.js} +4 -3
  151. package/dist/{draft-FJ7WHIXW.js.map → draft-PVTX6QT6.js.map} +1 -1
  152. package/dist/{draft-EJXNNJ3Y.js → draft-Q546QPPU.js} +5 -4
  153. package/dist/{draft-EJXNNJ3Y.js.map → draft-Q546QPPU.js.map} +1 -1
  154. package/dist/engine/index.js +3 -3
  155. package/dist/{facets-U7AQC4H6.js → facets-7EVPJMKS.js} +4 -3
  156. package/dist/{facets-U7AQC4H6.js.map → facets-7EVPJMKS.js.map} +1 -1
  157. package/dist/{feedback-PPQMOQ46.js → feedback-EIZKS4JU.js} +2 -2
  158. package/dist/{feedback-record-V66HWVRR.js → feedback-record-TKO54BOE.js} +9 -8
  159. package/dist/{feedback-record-V66HWVRR.js.map → feedback-record-TKO54BOE.js.map} +1 -1
  160. package/dist/{fetch-W7NULDEO.js → fetch-4BY6HYUM.js} +4 -3
  161. package/dist/{fetch-W7NULDEO.js.map → fetch-4BY6HYUM.js.map} +1 -1
  162. package/dist/{find-OTDIX6V4.js → find-FRRHAPWX.js} +4 -4
  163. package/dist/{flows-KABCBS3S.js → flows-KTFAML22.js} +21 -17
  164. package/dist/flows-KTFAML22.js.map +1 -0
  165. package/dist/{fonts-EMMX3KII.js → fonts-MXR3ZKDX.js} +6 -5
  166. package/dist/{forecast-GNODEIIC.js → forecast-3QTJYVND.js} +4 -3
  167. package/dist/{forecast-GNODEIIC.js.map → forecast-3QTJYVND.js.map} +1 -1
  168. package/dist/{funnel-AAX27NH4.js → funnel-I6XIAEHG.js} +11 -455
  169. package/dist/funnel-I6XIAEHG.js.map +1 -0
  170. package/dist/{ga4-UDQ2HA2J.js → ga4-DV2AXCSL.js} +1 -1
  171. package/dist/{get-QEYJRLV3.js → get-5PKNKJ5S.js} +7 -4
  172. package/dist/get-5PKNKJ5S.js.map +1 -0
  173. package/dist/{get-RTVUZM6E.js → get-72YPHJGV.js} +4 -3
  174. package/dist/{get-RTVUZM6E.js.map → get-72YPHJGV.js.map} +1 -1
  175. package/dist/{google-M7KEXVK5.js → google-6OGZX47I.js} +2 -2
  176. package/dist/{google-KTO3PLEU.js → google-QYYYSSXI.js} +5 -5
  177. package/dist/{google-ads-OK6IG3UV.js → google-ads-QGMQKZQD.js} +4 -3
  178. package/dist/{google-ads-OK6IG3UV.js.map → google-ads-QGMQKZQD.js.map} +1 -1
  179. package/dist/{gsc-P3QYGDV2.js → gsc-TAKOF7J5.js} +1 -1
  180. package/dist/{history-PQUJKK26.js → history-6AVQX2OQ.js} +4 -3
  181. package/dist/{history-PQUJKK26.js.map → history-6AVQX2OQ.js.map} +1 -1
  182. package/dist/{hubspot-Y77VLY6Y.js → hubspot-SVEMFK5S.js} +9 -8
  183. package/dist/{hubspot-Y77VLY6Y.js.map → hubspot-SVEMFK5S.js.map} +1 -1
  184. package/dist/{icon-I43F77FV.js → icon-L4RSS6PZ.js} +4 -4
  185. package/dist/{ideas-MIDU7YOA.js → ideas-NFOW3HKJ.js} +3 -2
  186. package/dist/{images-S254MS6O.js → images-2EFFUNNV.js} +9 -9
  187. package/dist/{ingest-YV2NLDBE.js → ingest-2EIKN4QC.js} +4 -3
  188. package/dist/{ingest-J4I3HKM3.js → ingest-2SO62RRI.js} +3 -2
  189. package/dist/{ingest-J4I3HKM3.js.map → ingest-2SO62RRI.js.map} +1 -1
  190. package/dist/{inspect-Q5NHBBHX.js → inspect-4OOS4APT.js} +4 -3
  191. package/dist/{inspect-Q5NHBBHX.js.map → inspect-4OOS4APT.js.map} +1 -1
  192. package/dist/{inspiration-P265QJ2H.js → inspiration-S3DU4CMQ.js} +1 -1
  193. package/dist/{keyword-metrics-PDY4ZXSP.js → keyword-metrics-SF4CSNZ2.js} +4 -3
  194. package/dist/{keyword-metrics-PDY4ZXSP.js.map → keyword-metrics-SF4CSNZ2.js.map} +1 -1
  195. package/dist/{keywords-for-site-GALSCV77.js → keywords-for-site-WDAOPNKC.js} +4 -3
  196. package/dist/{keywords-for-site-GALSCV77.js.map → keywords-for-site-WDAOPNKC.js.map} +1 -1
  197. package/dist/{landing-CJYGWCK4.js → landing-2ZB46LXH.js} +3 -3
  198. package/dist/{leads-PHKG6CP3.js → leads-A4W5KTWB.js} +4 -3
  199. package/dist/{leads-PHKG6CP3.js.map → leads-A4W5KTWB.js.map} +1 -1
  200. package/dist/{learn-FUQSY7DN.js → learn-IPULBCOD.js} +5 -4
  201. package/dist/{learn-FUQSY7DN.js.map → learn-IPULBCOD.js.map} +1 -1
  202. package/dist/{line-item-writes-E6MZPIZZ.js → line-item-writes-EMYSOJKM.js} +4 -3
  203. package/dist/{line-item-writes-E6MZPIZZ.js.map → line-item-writes-EMYSOJKM.js.map} +1 -1
  204. package/dist/{line-items-7ZGIKEF2.js → line-items-5NECXUZT.js} +5 -5
  205. package/dist/{link-QYAW6A2W.js → link-CI45HWFN.js} +4 -3
  206. package/dist/{link-QYAW6A2W.js.map → link-CI45HWFN.js.map} +1 -1
  207. package/dist/{linkedin-FFSDSGGS.js → linkedin-B7SYR75X.js} +27 -26
  208. package/dist/{linkedin-FFSDSGGS.js.map → linkedin-B7SYR75X.js.map} +1 -1
  209. package/dist/{list-NVQC5SNY.js → list-2BARXOT5.js} +3 -2
  210. package/dist/{list-NVQC5SNY.js.map → list-2BARXOT5.js.map} +1 -1
  211. package/dist/{list-SAV3LQHY.js → list-BIEVLEHS.js} +4 -3
  212. package/dist/{list-SAV3LQHY.js.map → list-BIEVLEHS.js.map} +1 -1
  213. package/dist/{list-5IC6KIKO.js → list-ZBT3EBVZ.js} +4 -3
  214. package/dist/{list-5IC6KIKO.js.map → list-ZBT3EBVZ.js.map} +1 -1
  215. package/dist/{log-XZPVOALD.js → log-C23OOAJZ.js} +4 -3
  216. package/dist/{log-XZPVOALD.js.map → log-C23OOAJZ.js.map} +1 -1
  217. package/dist/{logo-2IP663QO.js → logo-Q5D7PZY6.js} +3 -3
  218. package/dist/{lookup-XK45W2SH.js → lookup-ETWY47F7.js} +6 -5
  219. package/dist/{make-J3WBO62B.js → make-TPKKJXGL.js} +18 -17
  220. package/dist/{make-J3WBO62B.js.map → make-TPKKJXGL.js.map} +1 -1
  221. package/dist/{map-4J5WIWIG.js → map-SYZMPHLL.js} +5 -4
  222. package/dist/{map-4J5WIWIG.js.map → map-SYZMPHLL.js.map} +1 -1
  223. package/dist/{mcp-XXD7ZQCP.js → mcp-6FQBVJ6F.js} +3 -2
  224. package/dist/{mcp-XXD7ZQCP.js.map → mcp-6FQBVJ6F.js.map} +1 -1
  225. package/dist/{media-sources-O6ZRUA3N.js → media-sources-ZXHEEP6T.js} +2 -2
  226. package/dist/{members-D5ZYLS4Y.js → members-UDY4OOJW.js} +4 -3
  227. package/dist/{members-D5ZYLS4Y.js.map → members-UDY4OOJW.js.map} +1 -1
  228. package/dist/{normalize-PCNC6E2N.js → normalize-DAKHYS3V.js} +7 -3
  229. package/dist/{normalize-PCNC6E2N.js.map → normalize-DAKHYS3V.js.map} +1 -1
  230. package/dist/{options-MQ65VEVD.js → options-QL3ULED5.js} +7 -6
  231. package/dist/{options-MQ65VEVD.js.map → options-QL3ULED5.js.map} +1 -1
  232. package/dist/{performance-6QW2KEEQ.js → performance-UF5VTY2U.js} +5 -4
  233. package/dist/plan-FT632COT.js +51 -0
  234. package/dist/plan-FT632COT.js.map +1 -0
  235. package/dist/{promoted-tweet-writes-JPLHY3GM.js → promoted-tweet-writes-7HGESJ46.js} +4 -3
  236. package/dist/{promoted-tweet-writes-JPLHY3GM.js.map → promoted-tweet-writes-7HGESJ46.js.map} +1 -1
  237. package/dist/{promoted-tweets-SURKMHFI.js → promoted-tweets-LZKS5JIF.js} +3 -3
  238. package/dist/{publish-HCQ6MXLB.js → publish-NPD3SMZL.js} +4 -3
  239. package/dist/{publish-HCQ6MXLB.js.map → publish-NPD3SMZL.js.map} +1 -1
  240. package/dist/questionnaire-JNGYJTAY.js +37 -0
  241. package/dist/questionnaire-JNGYJTAY.js.map +1 -0
  242. package/dist/{reddit-GIP3ADMS.js → reddit-NU2N3LZD.js} +5 -4
  243. package/dist/{refresh-UXQSLCR3.js → refresh-EBVJ2C6L.js} +3 -2
  244. package/dist/{refresh-UXQSLCR3.js.map → refresh-EBVJ2C6L.js.map} +1 -1
  245. package/dist/{release-5KVLXNP6.js → release-V43YB2PY.js} +4 -3
  246. package/dist/{release-5KVLXNP6.js.map → release-V43YB2PY.js.map} +1 -1
  247. package/dist/{remove-6FIVKCJI.js → remove-QPSWLFI4.js} +3 -2
  248. package/dist/{remove-6FIVKCJI.js.map → remove-QPSWLFI4.js.map} +1 -1
  249. package/dist/{reopen-YM5LNOLB.js → reopen-GQ66NMWF.js} +4 -3
  250. package/dist/{reopen-YM5LNOLB.js.map → reopen-GQ66NMWF.js.map} +1 -1
  251. package/dist/{rerun-WYDRHIUJ.js → rerun-PZK275DY.js} +18 -17
  252. package/dist/{rerun-WYDRHIUJ.js.map → rerun-PZK275DY.js.map} +1 -1
  253. package/dist/{research-2BLEISBG.js → research-FMM6AWZC.js} +10 -10
  254. package/dist/{research-YOGE7GT2.js → research-GEOCUBXB.js} +3 -2
  255. package/dist/{research-YOGE7GT2.js.map → research-GEOCUBXB.js.map} +1 -1
  256. package/dist/{reset-C4UHQ3EU.js → reset-REXJ6AUK.js} +3 -2
  257. package/dist/{reset-C4UHQ3EU.js.map → reset-REXJ6AUK.js.map} +1 -1
  258. package/dist/{reset-OLVB6AE6.js → reset-Y72IVESB.js} +3 -2
  259. package/dist/{reset-OLVB6AE6.js.map → reset-Y72IVESB.js.map} +1 -1
  260. package/dist/{resolve-XYH2GDAE.js → resolve-OGX7C4TV.js} +4 -3
  261. package/dist/{resolve-XYH2GDAE.js.map → resolve-OGX7C4TV.js.map} +1 -1
  262. package/dist/{retry-7EELDEQP.js → retry-CD6JAQ3F.js} +3 -2
  263. package/dist/{retry-7EELDEQP.js.map → retry-CD6JAQ3F.js.map} +1 -1
  264. package/dist/{retry-726GKI6V.js → retry-TCUBBFR5.js} +3 -2
  265. package/dist/{retry-726GKI6V.js.map → retry-TCUBBFR5.js.map} +1 -1
  266. package/dist/{run-P4KR2MXC.js → run-A5ZDXTOI.js} +4 -3
  267. package/dist/{run-P4KR2MXC.js.map → run-A5ZDXTOI.js.map} +1 -1
  268. package/dist/{run-MODGUNGT.js → run-EUO34T2J.js} +18 -17
  269. package/dist/{scaffold-ad-5ZE7KE62.js → scaffold-ad-SW2HEWM3.js} +13 -12
  270. package/dist/{scaffold-ad-5ZE7KE62.js.map → scaffold-ad-SW2HEWM3.js.map} +1 -1
  271. package/dist/{scaffold-static-ad-HJY5HFDL.js → scaffold-static-ad-ECTJL54Y.js} +37 -36
  272. package/dist/scaffold-static-ad-ECTJL54Y.js.map +1 -0
  273. package/dist/{scaffold-video-P2PYPWG2.js → scaffold-video-EI7U7RBK.js} +12 -11
  274. package/dist/{scaffold-video-P2PYPWG2.js.map → scaffold-video-EI7U7RBK.js.map} +1 -1
  275. package/dist/{schedule-RDK4GEPI.js → schedule-S5YZJZ5U.js} +3 -2
  276. package/dist/{schedule-RDK4GEPI.js.map → schedule-S5YZJZ5U.js.map} +1 -1
  277. package/dist/{scheduled-agents-6U44QE76.js → scheduled-agents-N4LJRM4C.js} +11 -11
  278. package/dist/{schema-CHJDC7GQ.js → schema-R7JWWOF4.js} +8 -4
  279. package/dist/{schema-CHJDC7GQ.js.map → schema-R7JWWOF4.js.map} +1 -1
  280. package/dist/{search-PMJRU3C4.js → search-KHMQH3AT.js} +3 -2
  281. package/dist/{search-PMJRU3C4.js.map → search-KHMQH3AT.js.map} +1 -1
  282. package/dist/{select-AB2L4GAA.js → select-O2FN2JEQ.js} +9 -8
  283. package/dist/{select-AB2L4GAA.js.map → select-O2FN2JEQ.js.map} +1 -1
  284. package/dist/{sends-WGJVQUMF.js → sends-BQZM5PLS.js} +5 -4
  285. package/dist/{sends-WGJVQUMF.js.map → sends-BQZM5PLS.js.map} +1 -1
  286. package/dist/{set-prompt-DU2G2WTB.js → set-prompt-2HASHGWC.js} +9 -8
  287. package/dist/{set-prompt-DU2G2WTB.js.map → set-prompt-2HASHGWC.js.map} +1 -1
  288. package/dist/{setup-links-REPREN3C.js → setup-links-GYSE56GX.js} +4 -3
  289. package/dist/{setup-links-REPREN3C.js.map → setup-links-GYSE56GX.js.map} +1 -1
  290. package/dist/{site-WFSWIA3S.js → site-4SKM7RKG.js} +5 -4
  291. package/dist/{site-WFSWIA3S.js.map → site-4SKM7RKG.js.map} +1 -1
  292. package/dist/{sources-YBQ6KPFM.js → sources-FQ2UZTHL.js} +6 -6
  293. package/dist/{sources-AMI2AWKZ.js → sources-R2NKNC6J.js} +10 -9
  294. package/dist/{sources-AMI2AWKZ.js.map → sources-R2NKNC6J.js.map} +1 -1
  295. package/dist/{stale-6MJHVEG4.js → stale-W756ACKC.js} +8 -7
  296. package/dist/{stale-6MJHVEG4.js.map → stale-W756ACKC.js.map} +1 -1
  297. package/dist/{status-7F2KHFGA.js → status-SE2VZJJB.js} +4 -3
  298. package/dist/{status-7F2KHFGA.js.map → status-SE2VZJJB.js.map} +1 -1
  299. package/dist/{stock-2YCDN3N6.js → stock-KXJ26BY4.js} +5 -5
  300. package/dist/{studio-RA7QQH4O.js → studio-SYKOSNDB.js} +1 -1
  301. package/dist/{sync-GWTLKZTU.js → sync-LJGSODK3.js} +3 -2
  302. package/dist/{sync-GWTLKZTU.js.map → sync-LJGSODK3.js.map} +1 -1
  303. package/dist/{sync-definition-IPUFS5XS.js → sync-definition-QR2N233R.js} +12 -11
  304. package/dist/{tags-KFYLZLB3.js → tags-4BAVFH4S.js} +3 -2
  305. package/dist/{tags-KFYLZLB3.js.map → tags-4BAVFH4S.js.map} +1 -1
  306. package/dist/{tags-ABHSX6M5.js → tags-5SBMRC2A.js} +4 -3
  307. package/dist/{tags-ABHSX6M5.js.map → tags-5SBMRC2A.js.map} +1 -1
  308. package/dist/{tags-3WPW6PTV.js → tags-PYWFSBTR.js} +4 -4
  309. package/dist/{tags-6342FQEB.js → tags-QQU3OKMZ.js} +4 -3
  310. package/dist/{tags-6342FQEB.js.map → tags-QQU3OKMZ.js.map} +1 -1
  311. package/dist/{tags-FJIBBBRG.js → tags-YYLNF3PK.js} +4 -3
  312. package/dist/{tags-FJIBBBRG.js.map → tags-YYLNF3PK.js.map} +1 -1
  313. package/dist/{targeting-criteria-NR47AF5C.js → targeting-criteria-RJFLFICN.js} +3 -3
  314. package/dist/{targets-L56KOVQE.js → targets-S2MT2PNB.js} +4 -3
  315. package/dist/{targets-L56KOVQE.js.map → targets-S2MT2PNB.js.map} +1 -1
  316. package/dist/{templates-B6XGDYUF.js → templates-ZE5TOGRT.js} +4 -3
  317. package/dist/{templates-B6XGDYUF.js.map → templates-ZE5TOGRT.js.map} +1 -1
  318. package/dist/{testimonials-CVC4YIXO.js → testimonials-DII5DYLR.js} +6 -6
  319. package/dist/{top-companies-45X3DT7Z.js → top-companies-PGIAEHDF.js} +4 -3
  320. package/dist/{top-companies-45X3DT7Z.js.map → top-companies-PGIAEHDF.js.map} +1 -1
  321. package/dist/{translate-Z66FDB4K.js → translate-GXTS633J.js} +12 -11
  322. package/dist/{translate-Z66FDB4K.js.map → translate-GXTS633J.js.map} +1 -1
  323. package/dist/{triggers-22EMIVFD.js → triggers-2PTONXRU.js} +4 -3
  324. package/dist/{triggers-22EMIVFD.js.map → triggers-2PTONXRU.js.map} +1 -1
  325. package/dist/{unlink-65KUN6ID.js → unlink-XRMYJ6DB.js} +4 -3
  326. package/dist/{unlink-65KUN6ID.js.map → unlink-XRMYJ6DB.js.map} +1 -1
  327. package/dist/{unstage-2E3I5SWF.js → unstage-FY7A3YFF.js} +4 -3
  328. package/dist/{unstage-2E3I5SWF.js.map → unstage-FY7A3YFF.js.map} +1 -1
  329. package/dist/{unstage-4ZEULXEQ.js → unstage-RM2RLXKD.js} +5 -4
  330. package/dist/{unstage-4ZEULXEQ.js.map → unstage-RM2RLXKD.js.map} +1 -1
  331. package/dist/{update-KREBPGBH.js → update-E5SRBXQR.js} +4 -3
  332. package/dist/{update-KREBPGBH.js.map → update-E5SRBXQR.js.map} +1 -1
  333. package/dist/{update-D6DJC6T7.js → update-PJ67D2OG.js} +3 -2
  334. package/dist/{update-D6DJC6T7.js.map → update-PJ67D2OG.js.map} +1 -1
  335. package/dist/{update-2S7CSEAW.js → update-S4562V3O.js} +4 -3
  336. package/dist/{update-2S7CSEAW.js.map → update-S4562V3O.js.map} +1 -1
  337. package/dist/{update-7NCOTAQZ.js → update-V6YVEUI2.js} +4 -3
  338. package/dist/{update-7NCOTAQZ.js.map → update-V6YVEUI2.js.map} +1 -1
  339. package/dist/{upload-O6NHRPS7.js → upload-R6CQVLKF.js} +4 -3
  340. package/dist/{upload-O6NHRPS7.js.map → upload-R6CQVLKF.js.map} +1 -1
  341. package/dist/{url-options-GGXAL3J4.js → url-options-JOKU46F2.js} +4 -3
  342. package/dist/{url-options-GGXAL3J4.js.map → url-options-JOKU46F2.js.map} +1 -1
  343. package/dist/{url-params-3EFGVTZZ.js → url-params-7U2XMOWF.js} +4 -3
  344. package/dist/{url-params-3EFGVTZZ.js.map → url-params-7U2XMOWF.js.map} +1 -1
  345. package/dist/{validate-UMHHNTVU.js → validate-7YPOUKPB.js} +10 -9
  346. package/dist/{validate-UMHHNTVU.js.map → validate-7YPOUKPB.js.map} +1 -1
  347. package/dist/{videos-YSXYGTBM.js → videos-LICG6ACJ.js} +5 -5
  348. package/dist/{web-IGIGVEKS.js → web-BA2PGTWU.js} +4 -3
  349. package/dist/{web-IGIGVEKS.js.map → web-BA2PGTWU.js.map} +1 -1
  350. package/dist/{winning-ads-2WS7FI4E.js → winning-ads-C6S2C5VP.js} +2 -2
  351. package/dist/{write-commands-5C7FUOVN.js → write-commands-7SJ3BOW5.js} +5 -4
  352. package/dist/{write-commands-5C7FUOVN.js.map → write-commands-7SJ3BOW5.js.map} +1 -1
  353. package/dist/{x-BFSKFCZD.js → x-CZHRC6U7.js} +6 -6
  354. package/package.json +1 -1
  355. package/dist/add-5GAN6CVO.js.map +0 -1
  356. package/dist/analytics-FKCXIMPO.js.map +0 -1
  357. package/dist/chunk-DWHIOO7E.js.map +0 -1
  358. package/dist/chunk-EDLZGTGN.js.map +0 -1
  359. package/dist/chunk-GKZ2WU75.js.map +0 -1
  360. package/dist/chunk-SSJK7FEV.js.map +0 -1
  361. package/dist/chunk-T2PC5AVH.js.map +0 -1
  362. package/dist/chunk-XF4JUKVF.js.map +0 -1
  363. package/dist/chunk-YRQYA2LR.js.map +0 -1
  364. package/dist/flows-KABCBS3S.js.map +0 -1
  365. package/dist/funnel-AAX27NH4.js.map +0 -1
  366. package/dist/get-QEYJRLV3.js.map +0 -1
  367. package/dist/scaffold-static-ad-HJY5HFDL.js.map +0 -1
  368. /package/dist/{actions-P35MEMGN.js.map → actions-6TQMSVWD.js.map} +0 -0
  369. /package/dist/{ads-73PGA4YC.js.map → ads-AGYCVD62.js.map} +0 -0
  370. /package/dist/{avatars-EKCKHCC3.js.map → avatars-467OSBD6.js.map} +0 -0
  371. /package/dist/{brand-C6PFGGQN.js.map → brand-YRTEPGBK.js.map} +0 -0
  372. /package/dist/{campaigns-KZYZTXDS.js.map → campaigns-OYMXDGWX.js.map} +0 -0
  373. /package/dist/{canvas-UJNSHD3B.js.map → canvas-YQFG52IG.js.map} +0 -0
  374. /package/dist/{catalog-ZQX6BGXS.js.map → catalog-XLXIM7IW.js.map} +0 -0
  375. /package/dist/{chunk-7YCRFMXF.js.map → chunk-24EB7EDR.js.map} +0 -0
  376. /package/dist/{chunk-5ZDLTE5T.js.map → chunk-2AOE2MZQ.js.map} +0 -0
  377. /package/dist/{chunk-4SG4RW2P.js.map → chunk-2VPBIT65.js.map} +0 -0
  378. /package/dist/{chunk-NPY4QUMQ.js.map → chunk-54C6YDGJ.js.map} +0 -0
  379. /package/dist/{chunk-LZ73CZGP.js.map → chunk-5WCSKQ7Z.js.map} +0 -0
  380. /package/dist/{chunk-3G3ZDLMI.js.map → chunk-5ZNTADVR.js.map} +0 -0
  381. /package/dist/{chunk-AEOSAVVL.js.map → chunk-6F7DVPOS.js.map} +0 -0
  382. /package/dist/{chunk-CJCVIEJ5.js.map → chunk-6NY2GPR4.js.map} +0 -0
  383. /package/dist/{chunk-CXWFX2AM.js.map → chunk-6Y7ZBENQ.js.map} +0 -0
  384. /package/dist/{chunk-M242LHLX.js.map → chunk-7CTMH5AK.js.map} +0 -0
  385. /package/dist/{chunk-QD7ESRLN.js.map → chunk-C46GUI2S.js.map} +0 -0
  386. /package/dist/{chunk-6N6WKAJM.js.map → chunk-CWYAELVG.js.map} +0 -0
  387. /package/dist/{chunk-MXYBTMKB.js.map → chunk-DCRPXOJJ.js.map} +0 -0
  388. /package/dist/{chunk-JQJDXPCO.js.map → chunk-FUHN4MFY.js.map} +0 -0
  389. /package/dist/{chunk-S77PZVYM.js.map → chunk-FYGR3I2A.js.map} +0 -0
  390. /package/dist/{chunk-OZRUJVIQ.js.map → chunk-H3427GPU.js.map} +0 -0
  391. /package/dist/{chunk-IR6D7K4H.js.map → chunk-I3ZR655O.js.map} +0 -0
  392. /package/dist/{chunk-YK32GUBN.js.map → chunk-KMKEYI37.js.map} +0 -0
  393. /package/dist/{chunk-W3ZHJJVT.js.map → chunk-KS2QY6MK.js.map} +0 -0
  394. /package/dist/{chunk-WNRV4QH7.js.map → chunk-LYQJ4PZW.js.map} +0 -0
  395. /package/dist/{chunk-CSYSX4D2.js.map → chunk-N4LAYIIN.js.map} +0 -0
  396. /package/dist/{chunk-4AUMTNVB.js.map → chunk-NA63BH7V.js.map} +0 -0
  397. /package/dist/{chunk-4BQXAE7Z.js.map → chunk-NDEE6G2J.js.map} +0 -0
  398. /package/dist/{chunk-MELOSESI.js.map → chunk-R25YLW6H.js.map} +0 -0
  399. /package/dist/{chunk-Y6O7EWYY.js.map → chunk-RL5CP7N6.js.map} +0 -0
  400. /package/dist/{chunk-DGUNI37S.js.map → chunk-RX2DKU3W.js.map} +0 -0
  401. /package/dist/{chunk-VTDMKARH.js.map → chunk-ULG4QRTV.js.map} +0 -0
  402. /package/dist/{chunk-QRP3PXWN.js.map → chunk-VL43TNIP.js.map} +0 -0
  403. /package/dist/{chunk-SHL7LOC3.js.map → chunk-VLMBTPXU.js.map} +0 -0
  404. /package/dist/{chunk-KHRXPQID.js.map → chunk-VYQ3QJ3C.js.map} +0 -0
  405. /package/dist/{chunk-A4LOJ2VD.js.map → chunk-WGUQHAJY.js.map} +0 -0
  406. /package/dist/{chunk-ZEYEWPK6.js.map → chunk-WKQG6TER.js.map} +0 -0
  407. /package/dist/{chunk-3IBYKLXR.js.map → chunk-ZDMTXQ2Q.js.map} +0 -0
  408. /package/dist/{connect-QCOGEPP4.js.map → connect-FCXNVTXG.js.map} +0 -0
  409. /package/dist/{creatives-NJF2U763.js.map → creatives-FXUQ5WSD.js.map} +0 -0
  410. /package/dist/{customers-A36LOZOB.js.map → customers-XH2DMTFH.js.map} +0 -0
  411. /package/dist/{feedback-PPQMOQ46.js.map → feedback-EIZKS4JU.js.map} +0 -0
  412. /package/dist/{find-OTDIX6V4.js.map → find-FRRHAPWX.js.map} +0 -0
  413. /package/dist/{fonts-EMMX3KII.js.map → fonts-MXR3ZKDX.js.map} +0 -0
  414. /package/dist/{ga4-UDQ2HA2J.js.map → ga4-DV2AXCSL.js.map} +0 -0
  415. /package/dist/{google-M7KEXVK5.js.map → google-6OGZX47I.js.map} +0 -0
  416. /package/dist/{google-KTO3PLEU.js.map → google-QYYYSSXI.js.map} +0 -0
  417. /package/dist/{gsc-P3QYGDV2.js.map → gsc-TAKOF7J5.js.map} +0 -0
  418. /package/dist/{icon-I43F77FV.js.map → icon-L4RSS6PZ.js.map} +0 -0
  419. /package/dist/{ideas-MIDU7YOA.js.map → ideas-NFOW3HKJ.js.map} +0 -0
  420. /package/dist/{images-S254MS6O.js.map → images-2EFFUNNV.js.map} +0 -0
  421. /package/dist/{ingest-YV2NLDBE.js.map → ingest-2EIKN4QC.js.map} +0 -0
  422. /package/dist/{inspiration-P265QJ2H.js.map → inspiration-S3DU4CMQ.js.map} +0 -0
  423. /package/dist/{landing-CJYGWCK4.js.map → landing-2ZB46LXH.js.map} +0 -0
  424. /package/dist/{line-items-7ZGIKEF2.js.map → line-items-5NECXUZT.js.map} +0 -0
  425. /package/dist/{logo-2IP663QO.js.map → logo-Q5D7PZY6.js.map} +0 -0
  426. /package/dist/{lookup-XK45W2SH.js.map → lookup-ETWY47F7.js.map} +0 -0
  427. /package/dist/{media-sources-O6ZRUA3N.js.map → media-sources-ZXHEEP6T.js.map} +0 -0
  428. /package/dist/{performance-6QW2KEEQ.js.map → performance-UF5VTY2U.js.map} +0 -0
  429. /package/dist/{promoted-tweets-SURKMHFI.js.map → promoted-tweets-LZKS5JIF.js.map} +0 -0
  430. /package/dist/{reddit-GIP3ADMS.js.map → reddit-NU2N3LZD.js.map} +0 -0
  431. /package/dist/{research-2BLEISBG.js.map → research-FMM6AWZC.js.map} +0 -0
  432. /package/dist/{run-MODGUNGT.js.map → run-EUO34T2J.js.map} +0 -0
  433. /package/dist/{scheduled-agents-6U44QE76.js.map → scheduled-agents-N4LJRM4C.js.map} +0 -0
  434. /package/dist/{sources-YBQ6KPFM.js.map → sources-FQ2UZTHL.js.map} +0 -0
  435. /package/dist/{stock-2YCDN3N6.js.map → stock-KXJ26BY4.js.map} +0 -0
  436. /package/dist/{studio-RA7QQH4O.js.map → studio-SYKOSNDB.js.map} +0 -0
  437. /package/dist/{sync-definition-IPUFS5XS.js.map → sync-definition-QR2N233R.js.map} +0 -0
  438. /package/dist/{tags-3WPW6PTV.js.map → tags-PYWFSBTR.js.map} +0 -0
  439. /package/dist/{targeting-criteria-NR47AF5C.js.map → targeting-criteria-RJFLFICN.js.map} +0 -0
  440. /package/dist/{testimonials-CVC4YIXO.js.map → testimonials-DII5DYLR.js.map} +0 -0
  441. /package/dist/{videos-YSXYGTBM.js.map → videos-LICG6ACJ.js.map} +0 -0
  442. /package/dist/{winning-ads-2WS7FI4E.js.map → winning-ads-C6S2C5VP.js.map} +0 -0
  443. /package/dist/{x-BFSKFCZD.js.map → x-CZHRC6U7.js.map} +0 -0
@@ -57,22 +57,22 @@ Full guide: __tooling__/docs/tools/baker/images.md`
57
57
  get: () => import("./get-XN5ZGDIK.js").then((m) => m.getCommand),
58
58
  group: () => import("./group-GKWCCX66.js").then((m) => m.groupCommand),
59
59
  library: () => import("./library-ARKRLCNJ.js").then((m) => m.libraryCommand),
60
- find: () => import("./find-OTDIX6V4.js").then((m) => m.findCommand),
61
- stock: () => import("./stock-2YCDN3N6.js").then((m) => m.stockCommand),
62
- google: () => import("./google-KTO3PLEU.js").then((m) => m.googleCommand),
60
+ find: () => import("./find-FRRHAPWX.js").then((m) => m.findCommand),
61
+ stock: () => import("./stock-KXJ26BY4.js").then((m) => m.stockCommand),
62
+ google: () => import("./google-QYYYSSXI.js").then((m) => m.googleCommand),
63
63
  pinterest: () => import("./pinterest-AUH7WBA7.js").then((m) => m.pinterestCommand),
64
- logo: () => import("./logo-2IP663QO.js").then((m) => m.logoCommand),
65
- icon: () => import("./icon-I43F77FV.js").then((m) => m.iconCommand),
64
+ logo: () => import("./logo-Q5D7PZY6.js").then((m) => m.logoCommand),
65
+ icon: () => import("./icon-L4RSS6PZ.js").then((m) => m.iconCommand),
66
66
  gif: () => import("./gif-53ULFVLR.js").then((m) => m.gifCommand),
67
67
  sticker: () => import("./sticker-4KMBSMP5.js").then((m) => m.stickerCommand),
68
68
  extract: () => import("./extract-7QKLME7Z.js").then((m) => m.extractCommand),
69
69
  screenshot: () => import("./screenshot-YCQF25ZB.js").then((m) => m.screenshotCommand),
70
- ingest: () => import("./ingest-J4I3HKM3.js").then((m) => m.ingestCommand),
70
+ ingest: () => import("./ingest-2SO62RRI.js").then((m) => m.ingestCommand),
71
71
  use: () => import("./use-UT2DIZOG.js").then((m) => m.useCommand),
72
72
  search: () => import("./search-MEEM4D3W.js").then((m) => m.searchCommand),
73
73
  upload: () => import("./upload-L5SYZB3X.js").then((m) => m.uploadCommand),
74
74
  delete: () => import("./delete-3AV3ARMX.js").then((m) => m.deleteCommand),
75
- retry: () => import("./retry-7EELDEQP.js").then((m) => m.retryCommand),
75
+ retry: () => import("./retry-CD6JAQ3F.js").then((m) => m.retryCommand),
76
76
  describe: () => import("./describe-P3PPIQME.js").then((m) => m.describeCommand),
77
77
  download: () => import("./download-7T6HIJKD.js").then((m) => m.downloadCommand),
78
78
  normalize: () => import("./normalize-ICQF2AST.js").then((m) => m.normalizeCommand),
@@ -81,10 +81,10 @@ Full guide: __tooling__/docs/tools/baker/images.md`
81
81
  layerize: () => import("./layerize-RPD6SNP6.js").then((m) => m.layerizeCommand),
82
82
  layers: () => import("./layerize-RPD6SNP6.js").then((m) => m.layersCommand),
83
83
  upscale: () => import("./upscale-YWRLFU22.js").then((m) => m.upscaleCommand),
84
- tags: () => import("./tags-6342FQEB.js").then((m) => m.tagsCommand)
84
+ tags: () => import("./tags-QQU3OKMZ.js").then((m) => m.tagsCommand)
85
85
  }
86
86
  });
87
87
  export {
88
88
  imagesCommand
89
89
  };
90
- //# sourceMappingURL=images-S254MS6O.js.map
90
+ //# sourceMappingURL=images-2EFFUNNV.js.map
@@ -2,13 +2,14 @@ import {
2
2
  ingestCommand,
3
3
  ingestHints,
4
4
  runVideoIngest
5
- } from "./chunk-MXYBTMKB.js";
5
+ } from "./chunk-DCRPXOJJ.js";
6
6
  import "./chunk-FKOECEVC.js";
7
7
  import "./chunk-VVZBBKRC.js";
8
- import "./chunk-XF4JUKVF.js";
8
+ import "./chunk-7EPXVICM.js";
9
9
  import "./chunk-GXDLWBOY.js";
10
10
  import "./chunk-TEINLN64.js";
11
11
  import "./chunk-ZJWUBJYQ.js";
12
+ import "./chunk-HR6IWNKE.js";
12
13
  import "./chunk-NE4F3FHN.js";
13
14
  import "./chunk-XBOK23HI.js";
14
15
  import "./chunk-IFWP3ZDO.js";
@@ -20,4 +21,4 @@ export {
20
21
  ingestHints,
21
22
  runVideoIngest
22
23
  };
23
- //# sourceMappingURL=ingest-YV2NLDBE.js.map
24
+ //# sourceMappingURL=ingest-2EIKN4QC.js.map
@@ -1,9 +1,10 @@
1
1
  import {
2
2
  imageSourceSchema
3
- } from "./chunk-XF4JUKVF.js";
3
+ } from "./chunk-7EPXVICM.js";
4
4
  import "./chunk-GXDLWBOY.js";
5
5
  import "./chunk-TEINLN64.js";
6
6
  import "./chunk-ZJWUBJYQ.js";
7
+ import "./chunk-HR6IWNKE.js";
7
8
  import "./chunk-NE4F3FHN.js";
8
9
  import {
9
10
  ApiError,
@@ -104,4 +105,4 @@ var ingestCommand = defineCommand({
104
105
  export {
105
106
  ingestCommand
106
107
  };
107
- //# sourceMappingURL=ingest-J4I3HKM3.js.map
108
+ //# sourceMappingURL=ingest-2SO62RRI.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/images/ingest.ts"],"sourcesContent":["import { type ImagesIngestRequest, type ImagesIngestResponse, imageSourceSchema } from \"@baker/api\";\nimport { defineCommand } from \"citty\";\nimport { ApiError, apiPost } from \"../../client.ts\";\nimport { type OutputFormat, writeJson, writeOutput } from \"../../output.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\n\n// The enum lives in @baker/api. Spelling it out here rather than describing it\n// as \"enum\" is the difference between one call and two: the value set was only\n// discoverable by sending a wrong one and reading the server's rejection.\nconst SOURCE_VALUES = imageSourceSchema.options.join(\" | \");\n\nregisterSchema({\n command: \"images.ingest\",\n description: \"Ingest a remote image URL into the library (full describe + embed).\",\n args: {\n url: { type: \"string\", description: \"Image URL to ingest\", required: true },\n source: { type: \"string\", description: `Where the image came from. One of: ${SOURCE_VALUES}`, required: true },\n \"external-id\": { type: \"string\", description: \"Provider asset id\", required: false },\n \"external-url\": { type: \"string\", description: \"Canonical page URL\", required: false },\n context: { type: \"string\", description: \"Description context hint\", required: false },\n output: { type: \"string\", description: \"Output format: json|files|md\", required: false, default: \"json\" },\n fields: { type: \"string\", description: \"Comma-separated field names to include\", required: false },\n },\n});\n\nexport const ingestCommand = defineCommand({\n meta: {\n name: \"ingest\",\n description:\n \"Download a remote URL and store it in the library. Hash-deduped on bytes + externalId.\\n\\nExample: baker images ingest https://images.pexels.com/photos/13219418/pexels-photo-13219418.jpeg --source pexels --external-id 13219418\",\n },\n args: {\n url: { type: \"positional\", description: \"Image URL\", required: false },\n source: { type: \"string\", description: `Where the image came from. One of: ${SOURCE_VALUES}`, required: false },\n \"external-id\": { type: \"string\", description: \"Provider asset id\", required: false },\n \"external-url\": { type: \"string\", description: \"Canonical page URL\", required: false },\n context: { type: \"string\", description: \"Description context\", required: false },\n output: { type: \"string\", description: \"Output format: json|files|md\", required: false, default: \"json\" },\n fields: { type: \"string\", description: \"Comma-separated field names to include\", required: false },\n },\n run: async ({ args }) => {\n try {\n const url = args.url as string | undefined;\n const source = args.source as string | undefined;\n if (!url) {\n writeJson({ ok: false, error: { code: \"VALIDATION_ERROR\", message: \"URL is required\" } });\n process.exit(1);\n }\n if (!source) {\n writeJson({\n ok: false,\n error: {\n code: \"VALIDATION_ERROR\",\n message: \"--source is required\",\n fix: `Pass one of: ${SOURCE_VALUES}. Use \"website\" for an asset pulled off a company's own site.`,\n },\n });\n process.exit(1);\n }\n // Parse here, not just at the HTTP boundary. A blind cast turned every\n // wrong value into a network round-trip before the agent learned the\n // valid set — which is exactly the boundary this repo says to parse at.\n const parsedSource = imageSourceSchema.safeParse(source);\n if (!parsedSource.success) {\n writeJson({\n ok: false,\n error: {\n code: \"VALIDATION_ERROR\",\n message: `--source \"${source}\" is not a known image source`,\n fix: `Pass one of: ${SOURCE_VALUES}. Use \"website\" for an asset pulled off a company's own site.`,\n },\n });\n process.exit(1);\n }\n const body: ImagesIngestRequest = { url, source: parsedSource.data };\n if (args[\"external-id\"]) body.externalId = args[\"external-id\"] as string;\n if (args[\"external-url\"]) body.externalUrl = args[\"external-url\"] as string;\n if (args.context) body.descriptionContext = args.context as string;\n\n const data = await apiPost<ImagesIngestResponse>(\"/api/images/ingest\", body);\n // The response is three scalars, not a library row — project it as-is\n // rather than through the image normalizer, which would blank it.\n writeOutput(\n { ok: true, data },\n (args.output as OutputFormat) || \"json\",\n args.fields ? (args.fields as string).split(\",\") : undefined,\n false,\n (record) => record,\n );\n } catch (err) {\n if (err instanceof ApiError) {\n writeJson({ ok: false, error: { code: err.code, message: err.message } });\n process.exit(1);\n }\n writeJson({ ok: false, error: { code: \"INTERNAL_ERROR\", message: \"Unexpected error\" } });\n process.exit(1);\n }\n },\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/commands/images/ingest.ts"],"sourcesContent":["import { type ImagesIngestRequest, type ImagesIngestResponse, imageSourceSchema } from \"@baker/api\";\nimport { defineCommand } from \"citty\";\nimport { ApiError, apiPost } from \"../../client.ts\";\nimport { type OutputFormat, writeJson, writeOutput } from \"../../output.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\n\n// The enum lives in @baker/api. Spelling it out here rather than describing it\n// as \"enum\" is the difference between one call and two: the value set was only\n// discoverable by sending a wrong one and reading the server's rejection.\nconst SOURCE_VALUES = imageSourceSchema.options.join(\" | \");\n\nregisterSchema({\n command: \"images.ingest\",\n description: \"Ingest a remote image URL into the library (full describe + embed).\",\n args: {\n url: { type: \"string\", description: \"Image URL to ingest\", required: true },\n source: { type: \"string\", description: `Where the image came from. One of: ${SOURCE_VALUES}`, required: true },\n \"external-id\": { type: \"string\", description: \"Provider asset id\", required: false },\n \"external-url\": { type: \"string\", description: \"Canonical page URL\", required: false },\n context: { type: \"string\", description: \"Description context hint\", required: false },\n output: { type: \"string\", description: \"Output format: json|files|md\", required: false, default: \"json\" },\n fields: { type: \"string\", description: \"Comma-separated field names to include\", required: false },\n },\n});\n\nexport const ingestCommand = defineCommand({\n meta: {\n name: \"ingest\",\n description:\n \"Download a remote URL and store it in the library. Hash-deduped on bytes + externalId.\\n\\nExample: baker images ingest https://images.pexels.com/photos/13219418/pexels-photo-13219418.jpeg --source pexels --external-id 13219418\",\n },\n args: {\n url: { type: \"positional\", description: \"Image URL\", required: false },\n source: { type: \"string\", description: `Where the image came from. One of: ${SOURCE_VALUES}`, required: false },\n \"external-id\": { type: \"string\", description: \"Provider asset id\", required: false },\n \"external-url\": { type: \"string\", description: \"Canonical page URL\", required: false },\n context: { type: \"string\", description: \"Description context\", required: false },\n output: { type: \"string\", description: \"Output format: json|files|md\", required: false, default: \"json\" },\n fields: { type: \"string\", description: \"Comma-separated field names to include\", required: false },\n },\n run: async ({ args }) => {\n try {\n const url = args.url as string | undefined;\n const source = args.source as string | undefined;\n if (!url) {\n writeJson({ ok: false, error: { code: \"VALIDATION_ERROR\", message: \"URL is required\" } });\n process.exit(1);\n }\n if (!source) {\n writeJson({\n ok: false,\n error: {\n code: \"VALIDATION_ERROR\",\n message: \"--source is required\",\n fix: `Pass one of: ${SOURCE_VALUES}. Use \"website\" for an asset pulled off a company's own site.`,\n },\n });\n process.exit(1);\n }\n // Parse here, not just at the HTTP boundary. A blind cast turned every\n // wrong value into a network round-trip before the agent learned the\n // valid set — which is exactly the boundary this repo says to parse at.\n const parsedSource = imageSourceSchema.safeParse(source);\n if (!parsedSource.success) {\n writeJson({\n ok: false,\n error: {\n code: \"VALIDATION_ERROR\",\n message: `--source \"${source}\" is not a known image source`,\n fix: `Pass one of: ${SOURCE_VALUES}. Use \"website\" for an asset pulled off a company's own site.`,\n },\n });\n process.exit(1);\n }\n const body: ImagesIngestRequest = { url, source: parsedSource.data };\n if (args[\"external-id\"]) body.externalId = args[\"external-id\"] as string;\n if (args[\"external-url\"]) body.externalUrl = args[\"external-url\"] as string;\n if (args.context) body.descriptionContext = args.context as string;\n\n const data = await apiPost<ImagesIngestResponse>(\"/api/images/ingest\", body);\n // The response is three scalars, not a library row — project it as-is\n // rather than through the image normalizer, which would blank it.\n writeOutput(\n { ok: true, data },\n (args.output as OutputFormat) || \"json\",\n args.fields ? (args.fields as string).split(\",\") : undefined,\n false,\n (record) => record,\n );\n } catch (err) {\n if (err instanceof ApiError) {\n writeJson({ ok: false, error: { code: err.code, message: err.message } });\n process.exit(1);\n }\n writeJson({ ok: false, error: { code: \"INTERNAL_ERROR\", message: \"Unexpected error\" } });\n process.exit(1);\n }\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AACA,SAAS,qBAAqB;AAQ9B,IAAM,gBAAgB,kBAAkB,QAAQ,KAAK,KAAK;AAE1D,eAAe;AAAA,EACb,SAAS;AAAA,EACT,aAAa;AAAA,EACb,MAAM;AAAA,IACJ,KAAK,EAAE,MAAM,UAAU,aAAa,uBAAuB,UAAU,KAAK;AAAA,IAC1E,QAAQ,EAAE,MAAM,UAAU,aAAa,sCAAsC,aAAa,IAAI,UAAU,KAAK;AAAA,IAC7G,eAAe,EAAE,MAAM,UAAU,aAAa,qBAAqB,UAAU,MAAM;AAAA,IACnF,gBAAgB,EAAE,MAAM,UAAU,aAAa,sBAAsB,UAAU,MAAM;AAAA,IACrF,SAAS,EAAE,MAAM,UAAU,aAAa,4BAA4B,UAAU,MAAM;AAAA,IACpF,QAAQ,EAAE,MAAM,UAAU,aAAa,gCAAgC,UAAU,OAAO,SAAS,OAAO;AAAA,IACxG,QAAQ,EAAE,MAAM,UAAU,aAAa,0CAA0C,UAAU,MAAM;AAAA,EACnG;AACF,CAAC;AAEM,IAAM,gBAAgB,cAAc;AAAA,EACzC,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aACE;AAAA,EACJ;AAAA,EACA,MAAM;AAAA,IACJ,KAAK,EAAE,MAAM,cAAc,aAAa,aAAa,UAAU,MAAM;AAAA,IACrE,QAAQ,EAAE,MAAM,UAAU,aAAa,sCAAsC,aAAa,IAAI,UAAU,MAAM;AAAA,IAC9G,eAAe,EAAE,MAAM,UAAU,aAAa,qBAAqB,UAAU,MAAM;AAAA,IACnF,gBAAgB,EAAE,MAAM,UAAU,aAAa,sBAAsB,UAAU,MAAM;AAAA,IACrF,SAAS,EAAE,MAAM,UAAU,aAAa,uBAAuB,UAAU,MAAM;AAAA,IAC/E,QAAQ,EAAE,MAAM,UAAU,aAAa,gCAAgC,UAAU,OAAO,SAAS,OAAO;AAAA,IACxG,QAAQ,EAAE,MAAM,UAAU,aAAa,0CAA0C,UAAU,MAAM;AAAA,EACnG;AAAA,EACA,KAAK,OAAO,EAAE,KAAK,MAAM;AACvB,QAAI;AACF,YAAM,MAAM,KAAK;AACjB,YAAM,SAAS,KAAK;AACpB,UAAI,CAAC,KAAK;AACR,kBAAU,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,oBAAoB,SAAS,kBAAkB,EAAE,CAAC;AACxF,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,UAAI,CAAC,QAAQ;AACX,kBAAU;AAAA,UACR,IAAI;AAAA,UACJ,OAAO;AAAA,YACL,MAAM;AAAA,YACN,SAAS;AAAA,YACT,KAAK,gBAAgB,aAAa;AAAA,UACpC;AAAA,QACF,CAAC;AACD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAIA,YAAM,eAAe,kBAAkB,UAAU,MAAM;AACvD,UAAI,CAAC,aAAa,SAAS;AACzB,kBAAU;AAAA,UACR,IAAI;AAAA,UACJ,OAAO;AAAA,YACL,MAAM;AAAA,YACN,SAAS,aAAa,MAAM;AAAA,YAC5B,KAAK,gBAAgB,aAAa;AAAA,UACpC;AAAA,QACF,CAAC;AACD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,YAAM,OAA4B,EAAE,KAAK,QAAQ,aAAa,KAAK;AACnE,UAAI,KAAK,aAAa,EAAG,MAAK,aAAa,KAAK,aAAa;AAC7D,UAAI,KAAK,cAAc,EAAG,MAAK,cAAc,KAAK,cAAc;AAChE,UAAI,KAAK,QAAS,MAAK,qBAAqB,KAAK;AAEjD,YAAM,OAAO,MAAM,QAA8B,sBAAsB,IAAI;AAG3E;AAAA,QACE,EAAE,IAAI,MAAM,KAAK;AAAA,QAChB,KAAK,UAA2B;AAAA,QACjC,KAAK,SAAU,KAAK,OAAkB,MAAM,GAAG,IAAI;AAAA,QACnD;AAAA,QACA,CAAC,WAAW;AAAA,MACd;AAAA,IACF,SAAS,KAAK;AACZ,UAAI,eAAe,UAAU;AAC3B,kBAAU,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,IAAI,MAAM,SAAS,IAAI,QAAQ,EAAE,CAAC;AACxE,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,gBAAU,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,kBAAkB,SAAS,mBAAmB,EAAE,CAAC;AACvF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AACF,CAAC;","names":[]}
@@ -1,16 +1,17 @@
1
1
  import {
2
2
  fetchRunRecord
3
- } from "./chunk-A4LOJ2VD.js";
3
+ } from "./chunk-WGUQHAJY.js";
4
4
  import {
5
5
  findWorkspaceRoot
6
6
  } from "./chunk-DZSIUEGH.js";
7
7
  import "./chunk-HRYOZUSK.js";
8
8
  import "./chunk-VVZBBKRC.js";
9
9
  import "./chunk-YBMVHGY3.js";
10
- import "./chunk-XF4JUKVF.js";
10
+ import "./chunk-7EPXVICM.js";
11
11
  import "./chunk-GXDLWBOY.js";
12
12
  import "./chunk-TEINLN64.js";
13
13
  import "./chunk-ZJWUBJYQ.js";
14
+ import "./chunk-HR6IWNKE.js";
14
15
  import "./chunk-NE4F3FHN.js";
15
16
  import {
16
17
  ApiError
@@ -186,4 +187,4 @@ async function probeDuration(filePath) {
186
187
  export {
187
188
  inspectCommand
188
189
  };
189
- //# sourceMappingURL=inspect-Q5NHBBHX.js.map
190
+ //# sourceMappingURL=inspect-4OOS4APT.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/canvas/inspect.ts"],"sourcesContent":["import { execFile } from \"node:child_process\";\nimport { readdir, readFile, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { defineCommand } from \"citty\";\nimport { ApiError } from \"../../client.ts\";\nimport { findWorkspaceRoot } from \"./normalize-paths.ts\";\nimport { fetchRunRecord } from \"./run-history.ts\";\n\nconst execFileAsync = promisify(execFile);\n\ntype ManifestNodeRun = {\n node_id: string;\n node_type: string;\n cached: boolean;\n duration_ms: number;\n credits: number;\n};\n\ntype Manifest = {\n run_id: string;\n output?: unknown;\n stats?: { total_nodes: number; cached_nodes: number; total_credits: number; duration_ms: number };\n node_runs?: ManifestNodeRun[];\n};\n\nexport const inspectCommand = defineCommand({\n meta: {\n name: \"inspect\",\n description:\n \"Dump a one-page summary of a canvas run: per-node duration + cache status, the run's outputs, and optionally three thumbnail frames per video output. Pass a run_id (r_…) or an absolute run directory. A run whose folder is not in this workspace (an older version, or one rendered in another chat) is read from the company's run history instead: its status, stats, per-node results and the durable URL of every output.\",\n },\n args: {\n run: { type: \"positional\", required: true, description: \"Run id (e.g. r_01K...) or absolute run directory\" },\n \"outputs-dir\": { type: \"string\", description: \"Per-run outputs root (default <workspace root>/canvas, where `canvas run` writes)\" },\n thumbnails: {\n type: \"boolean\",\n description: \"Extract start/middle/end frames from every video output in the local run folder (requires ffmpeg)\",\n },\n },\n async run({ args }) {\n const cwd = process.cwd();\n const outputsDir = args[\"outputs-dir\"]\n ? path.resolve(String(args[\"outputs-dir\"]))\n : path.join(findWorkspaceRoot(cwd) ?? cwd, \"canvas\");\n const runArg = String(args.run);\n const runDir = await localRunDir(runArg, outputsDir);\n if (!runDir) {\n if (path.isAbsolute(runArg)) fail(\"not_found\", `${runArg} is not a run directory`);\n await inspectFromHistory(runArg, path.join(outputsDir, runArg));\n return;\n }\n\n const manifest = await loadManifest(runDir);\n const files = await listRunFiles(runDir);\n const videos = files.filter((f) => isVideoFile(f.path));\n let thumbnails: Array<{ video: string; frames: string[] }> = [];\n if (args.thumbnails) {\n thumbnails = await extractThumbnails(videos.map((v) => v.path));\n }\n\n const summary = {\n ok: true,\n source: \"local\",\n run_id: manifest.run_id ?? path.basename(runDir),\n run_dir: runDir,\n stats: manifest.stats ?? null,\n output: manifest.output ?? null,\n node_runs: manifest.node_runs ?? [],\n files: files.map((f) => ({ name: f.name, path: f.path, size_bytes: f.size })),\n thumbnails,\n };\n\n process.stdout.write(`${JSON.stringify(summary, null, 2)}\\n`);\n },\n});\n\n/** The run's local folder, or null when this workspace does not have it. */\nasync function localRunDir(run: string, outputsDir: string): Promise<string | null> {\n const candidate = path.isAbsolute(run) ? run : path.join(outputsDir, run);\n const s = await stat(candidate).catch(() => null);\n return s?.isDirectory() ? candidate : null;\n}\n\n/** The run as the company's run history keeps it: no local files, durable output URLs. */\nasync function inspectFromHistory(runId: string, expectedDir: string): Promise<void> {\n let run: Awaited<ReturnType<typeof fetchRunRecord>>;\n try {\n run = await fetchRunRecord(runId);\n } catch (e) {\n const reason = e instanceof ApiError ? e.message : e instanceof Error ? e.message : String(e);\n fail(\"unavailable\", `No run folder at ${expectedDir}, and the run history could not be read (${reason}).`);\n }\n if (!run) {\n fail(\n \"not_found\",\n `No run \"${runId}\": there is no folder at ${expectedDir} and the company's run history has no run by that id.`,\n );\n }\n const summary = {\n ok: true,\n source: \"run_history\",\n run_id: run.runId,\n creative: run.creativeSlug ?? null,\n status: run.status,\n ...(run.errorMessage ? { error: run.errorMessage } : {}),\n stats: {\n total_nodes: run.stats.totalNodes,\n cached_nodes: run.stats.cachedNodes,\n total_credits: run.stats.totalCredits,\n duration_ms: run.stats.durationMs,\n },\n outputs: run.finalOutputs,\n node_runs: run.nodes.map((node) => ({\n node_id: node.nodeId,\n node_type: node.nodeType,\n cached: node.cached,\n duration_ms: node.durationMs,\n credits: node.credits,\n ...(node.status ? { status: node.status } : {}),\n outputs: node.outputs,\n })),\n ...(run.review ? { review: run.review } : {}),\n hints: [\n \"This run's folder is not in this workspace, so there are no local files: every output above is a durable URL. To render it again here, run `baker canvas run --slug <creative>`.\",\n ],\n };\n process.stdout.write(`${JSON.stringify(summary, null, 2)}\\n`);\n}\n\nfunction fail(code: string, message: string): never {\n process.stderr.write(`${JSON.stringify({ ok: false, error: { code, message } }, null, 2)}\\n`);\n process.exit(2);\n}\n\nasync function loadManifest(runDir: string): Promise<Manifest> {\n const manifestPath = path.join(runDir, \"manifest.json\");\n try {\n const raw = await readFile(manifestPath, \"utf-8\");\n return JSON.parse(raw) as Manifest;\n } catch {\n return {} as Manifest;\n }\n}\n\ntype RunFile = { name: string; path: string; size: number };\nasync function listRunFiles(runDir: string): Promise<RunFile[]> {\n const out: RunFile[] = [];\n const names = await readdir(runDir);\n for (const name of names) {\n const abs = path.join(runDir, name);\n const s = await stat(abs).catch(() => null);\n if (!s?.isFile()) continue;\n out.push({ name, path: abs, size: s.size });\n }\n out.sort((a, b) => a.name.localeCompare(b.name));\n return out;\n}\n\nfunction isVideoFile(p: string): boolean {\n return /\\.(mp4|webm|mov)$/i.test(p);\n}\n\nasync function extractThumbnails(videoPaths: string[]): Promise<Array<{ video: string; frames: string[] }>> {\n const out: Array<{ video: string; frames: string[] }> = [];\n for (const v of videoPaths) {\n const duration = await probeDuration(v).catch(() => null);\n if (duration === null) {\n out.push({ video: v, frames: [] });\n continue;\n }\n const frames: string[] = [];\n const checkpoints = [0.05, 0.5, 0.95];\n const base = v.replace(/\\.[^.]+$/, \"\");\n for (const ratio of checkpoints) {\n const at = Math.max(0, Math.min(duration * ratio, duration - 0.01));\n const dest = `${base}__frame_${Math.round(ratio * 100)\n .toString()\n .padStart(2, \"0\")}.png`;\n try {\n await execFileAsync(\"ffmpeg\", [\"-ss\", at.toFixed(3), \"-i\", v, \"-frames:v\", \"1\", \"-y\", dest]);\n frames.push(dest);\n } catch {\n // skip — best-effort; thumbnail extraction is non-fatal.\n }\n }\n out.push({ video: v, frames });\n }\n return out;\n}\n\nasync function probeDuration(filePath: string): Promise<number> {\n const { stdout } = await execFileAsync(\n \"ffprobe\",\n [\"-v\", \"error\", \"-show_entries\", \"format=duration\", \"-of\", \"csv=p=0\", filePath],\n { encoding: \"utf-8\" },\n );\n return Number.parseFloat(stdout.trim());\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,gBAAgB;AACzB,SAAS,SAAS,UAAU,YAAY;AACxC,OAAO,UAAU;AACjB,SAAS,iBAAiB;AAC1B,SAAS,qBAAqB;AAK9B,IAAM,gBAAgB,UAAU,QAAQ;AAiBjC,IAAM,iBAAiB,cAAc;AAAA,EAC1C,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aACE;AAAA,EACJ;AAAA,EACA,MAAM;AAAA,IACJ,KAAK,EAAE,MAAM,cAAc,UAAU,MAAM,aAAa,mDAAmD;AAAA,IAC3G,eAAe,EAAE,MAAM,UAAU,aAAa,oFAAoF;AAAA,IAClI,YAAY;AAAA,MACV,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,EACF;AAAA,EACA,MAAM,IAAI,EAAE,KAAK,GAAG;AAClB,UAAM,MAAM,QAAQ,IAAI;AACxB,UAAM,aAAa,KAAK,aAAa,IACjC,KAAK,QAAQ,OAAO,KAAK,aAAa,CAAC,CAAC,IACxC,KAAK,KAAK,kBAAkB,GAAG,KAAK,KAAK,QAAQ;AACrD,UAAM,SAAS,OAAO,KAAK,GAAG;AAC9B,UAAM,SAAS,MAAM,YAAY,QAAQ,UAAU;AACnD,QAAI,CAAC,QAAQ;AACX,UAAI,KAAK,WAAW,MAAM,EAAG,MAAK,aAAa,GAAG,MAAM,yBAAyB;AACjF,YAAM,mBAAmB,QAAQ,KAAK,KAAK,YAAY,MAAM,CAAC;AAC9D;AAAA,IACF;AAEA,UAAM,WAAW,MAAM,aAAa,MAAM;AAC1C,UAAM,QAAQ,MAAM,aAAa,MAAM;AACvC,UAAM,SAAS,MAAM,OAAO,CAAC,MAAM,YAAY,EAAE,IAAI,CAAC;AACtD,QAAI,aAAyD,CAAC;AAC9D,QAAI,KAAK,YAAY;AACnB,mBAAa,MAAM,kBAAkB,OAAO,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AAAA,IAChE;AAEA,UAAM,UAAU;AAAA,MACd,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR,QAAQ,SAAS,UAAU,KAAK,SAAS,MAAM;AAAA,MAC/C,SAAS;AAAA,MACT,OAAO,SAAS,SAAS;AAAA,MACzB,QAAQ,SAAS,UAAU;AAAA,MAC3B,WAAW,SAAS,aAAa,CAAC;AAAA,MAClC,OAAO,MAAM,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,EAAE,MAAM,YAAY,EAAE,KAAK,EAAE;AAAA,MAC5E;AAAA,IACF;AAEA,YAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,SAAS,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,EAC9D;AACF,CAAC;AAGD,eAAe,YAAY,KAAa,YAA4C;AAClF,QAAM,YAAY,KAAK,WAAW,GAAG,IAAI,MAAM,KAAK,KAAK,YAAY,GAAG;AACxE,QAAM,IAAI,MAAM,KAAK,SAAS,EAAE,MAAM,MAAM,IAAI;AAChD,SAAO,GAAG,YAAY,IAAI,YAAY;AACxC;AAGA,eAAe,mBAAmB,OAAe,aAAoC;AACnF,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,eAAe,KAAK;AAAA,EAClC,SAAS,GAAG;AACV,UAAM,SAAS,aAAa,WAAW,EAAE,UAAU,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AAC5F,SAAK,eAAe,oBAAoB,WAAW,4CAA4C,MAAM,IAAI;AAAA,EAC3G;AACA,MAAI,CAAC,KAAK;AACR;AAAA,MACE;AAAA,MACA,WAAW,KAAK,4BAA4B,WAAW;AAAA,IACzD;AAAA,EACF;AACA,QAAM,UAAU;AAAA,IACd,IAAI;AAAA,IACJ,QAAQ;AAAA,IACR,QAAQ,IAAI;AAAA,IACZ,UAAU,IAAI,gBAAgB;AAAA,IAC9B,QAAQ,IAAI;AAAA,IACZ,GAAI,IAAI,eAAe,EAAE,OAAO,IAAI,aAAa,IAAI,CAAC;AAAA,IACtD,OAAO;AAAA,MACL,aAAa,IAAI,MAAM;AAAA,MACvB,cAAc,IAAI,MAAM;AAAA,MACxB,eAAe,IAAI,MAAM;AAAA,MACzB,aAAa,IAAI,MAAM;AAAA,IACzB;AAAA,IACA,SAAS,IAAI;AAAA,IACb,WAAW,IAAI,MAAM,IAAI,CAAC,UAAU;AAAA,MAClC,SAAS,KAAK;AAAA,MACd,WAAW,KAAK;AAAA,MAChB,QAAQ,KAAK;AAAA,MACb,aAAa,KAAK;AAAA,MAClB,SAAS,KAAK;AAAA,MACd,GAAI,KAAK,SAAS,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;AAAA,MAC7C,SAAS,KAAK;AAAA,IAChB,EAAE;AAAA,IACF,GAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;AAAA,IAC3C,OAAO;AAAA,MACL;AAAA,IACF;AAAA,EACF;AACA,UAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,SAAS,MAAM,CAAC,CAAC;AAAA,CAAI;AAC9D;AAEA,SAAS,KAAK,MAAc,SAAwB;AAClD,UAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,QAAQ,EAAE,GAAG,MAAM,CAAC,CAAC;AAAA,CAAI;AAC5F,UAAQ,KAAK,CAAC;AAChB;AAEA,eAAe,aAAa,QAAmC;AAC7D,QAAM,eAAe,KAAK,KAAK,QAAQ,eAAe;AACtD,MAAI;AACF,UAAM,MAAM,MAAM,SAAS,cAAc,OAAO;AAChD,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAGA,eAAe,aAAa,QAAoC;AAC9D,QAAM,MAAiB,CAAC;AACxB,QAAM,QAAQ,MAAM,QAAQ,MAAM;AAClC,aAAW,QAAQ,OAAO;AACxB,UAAM,MAAM,KAAK,KAAK,QAAQ,IAAI;AAClC,UAAM,IAAI,MAAM,KAAK,GAAG,EAAE,MAAM,MAAM,IAAI;AAC1C,QAAI,CAAC,GAAG,OAAO,EAAG;AAClB,QAAI,KAAK,EAAE,MAAM,MAAM,KAAK,MAAM,EAAE,KAAK,CAAC;AAAA,EAC5C;AACA,MAAI,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AAC/C,SAAO;AACT;AAEA,SAAS,YAAY,GAAoB;AACvC,SAAO,qBAAqB,KAAK,CAAC;AACpC;AAEA,eAAe,kBAAkB,YAA2E;AAC1G,QAAM,MAAkD,CAAC;AACzD,aAAW,KAAK,YAAY;AAC1B,UAAM,WAAW,MAAM,cAAc,CAAC,EAAE,MAAM,MAAM,IAAI;AACxD,QAAI,aAAa,MAAM;AACrB,UAAI,KAAK,EAAE,OAAO,GAAG,QAAQ,CAAC,EAAE,CAAC;AACjC;AAAA,IACF;AACA,UAAM,SAAmB,CAAC;AAC1B,UAAM,cAAc,CAAC,MAAM,KAAK,IAAI;AACpC,UAAM,OAAO,EAAE,QAAQ,YAAY,EAAE;AACrC,eAAW,SAAS,aAAa;AAC/B,YAAM,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI,WAAW,OAAO,WAAW,IAAI,CAAC;AAClE,YAAM,OAAO,GAAG,IAAI,WAAW,KAAK,MAAM,QAAQ,GAAG,EAClD,SAAS,EACT,SAAS,GAAG,GAAG,CAAC;AACnB,UAAI;AACF,cAAM,cAAc,UAAU,CAAC,OAAO,GAAG,QAAQ,CAAC,GAAG,MAAM,GAAG,aAAa,KAAK,MAAM,IAAI,CAAC;AAC3F,eAAO,KAAK,IAAI;AAAA,MAClB,QAAQ;AAAA,MAER;AAAA,IACF;AACA,QAAI,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;AAAA,EAC/B;AACA,SAAO;AACT;AAEA,eAAe,cAAc,UAAmC;AAC9D,QAAM,EAAE,OAAO,IAAI,MAAM;AAAA,IACvB;AAAA,IACA,CAAC,MAAM,SAAS,iBAAiB,mBAAmB,OAAO,WAAW,QAAQ;AAAA,IAC9E,EAAE,UAAU,QAAQ;AAAA,EACtB;AACA,SAAO,OAAO,WAAW,OAAO,KAAK,CAAC;AACxC;","names":[]}
1
+ {"version":3,"sources":["../src/commands/canvas/inspect.ts"],"sourcesContent":["import { execFile } from \"node:child_process\";\nimport { readdir, readFile, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { defineCommand } from \"citty\";\nimport { ApiError } from \"../../client.ts\";\nimport { findWorkspaceRoot } from \"./normalize-paths.ts\";\nimport { fetchRunRecord } from \"./run-history.ts\";\n\nconst execFileAsync = promisify(execFile);\n\ntype ManifestNodeRun = {\n node_id: string;\n node_type: string;\n cached: boolean;\n duration_ms: number;\n credits: number;\n};\n\ntype Manifest = {\n run_id: string;\n output?: unknown;\n stats?: { total_nodes: number; cached_nodes: number; total_credits: number; duration_ms: number };\n node_runs?: ManifestNodeRun[];\n};\n\nexport const inspectCommand = defineCommand({\n meta: {\n name: \"inspect\",\n description:\n \"Dump a one-page summary of a canvas run: per-node duration + cache status, the run's outputs, and optionally three thumbnail frames per video output. Pass a run_id (r_…) or an absolute run directory. A run whose folder is not in this workspace (an older version, or one rendered in another chat) is read from the company's run history instead: its status, stats, per-node results and the durable URL of every output.\",\n },\n args: {\n run: { type: \"positional\", required: true, description: \"Run id (e.g. r_01K...) or absolute run directory\" },\n \"outputs-dir\": { type: \"string\", description: \"Per-run outputs root (default <workspace root>/canvas, where `canvas run` writes)\" },\n thumbnails: {\n type: \"boolean\",\n description: \"Extract start/middle/end frames from every video output in the local run folder (requires ffmpeg)\",\n },\n },\n async run({ args }) {\n const cwd = process.cwd();\n const outputsDir = args[\"outputs-dir\"]\n ? path.resolve(String(args[\"outputs-dir\"]))\n : path.join(findWorkspaceRoot(cwd) ?? cwd, \"canvas\");\n const runArg = String(args.run);\n const runDir = await localRunDir(runArg, outputsDir);\n if (!runDir) {\n if (path.isAbsolute(runArg)) fail(\"not_found\", `${runArg} is not a run directory`);\n await inspectFromHistory(runArg, path.join(outputsDir, runArg));\n return;\n }\n\n const manifest = await loadManifest(runDir);\n const files = await listRunFiles(runDir);\n const videos = files.filter((f) => isVideoFile(f.path));\n let thumbnails: Array<{ video: string; frames: string[] }> = [];\n if (args.thumbnails) {\n thumbnails = await extractThumbnails(videos.map((v) => v.path));\n }\n\n const summary = {\n ok: true,\n source: \"local\",\n run_id: manifest.run_id ?? path.basename(runDir),\n run_dir: runDir,\n stats: manifest.stats ?? null,\n output: manifest.output ?? null,\n node_runs: manifest.node_runs ?? [],\n files: files.map((f) => ({ name: f.name, path: f.path, size_bytes: f.size })),\n thumbnails,\n };\n\n process.stdout.write(`${JSON.stringify(summary, null, 2)}\\n`);\n },\n});\n\n/** The run's local folder, or null when this workspace does not have it. */\nasync function localRunDir(run: string, outputsDir: string): Promise<string | null> {\n const candidate = path.isAbsolute(run) ? run : path.join(outputsDir, run);\n const s = await stat(candidate).catch(() => null);\n return s?.isDirectory() ? candidate : null;\n}\n\n/** The run as the company's run history keeps it: no local files, durable output URLs. */\nasync function inspectFromHistory(runId: string, expectedDir: string): Promise<void> {\n let run: Awaited<ReturnType<typeof fetchRunRecord>>;\n try {\n run = await fetchRunRecord(runId);\n } catch (e) {\n const reason = e instanceof ApiError ? e.message : e instanceof Error ? e.message : String(e);\n fail(\"unavailable\", `No run folder at ${expectedDir}, and the run history could not be read (${reason}).`);\n }\n if (!run) {\n fail(\n \"not_found\",\n `No run \"${runId}\": there is no folder at ${expectedDir} and the company's run history has no run by that id.`,\n );\n }\n const summary = {\n ok: true,\n source: \"run_history\",\n run_id: run.runId,\n creative: run.creativeSlug ?? null,\n status: run.status,\n ...(run.errorMessage ? { error: run.errorMessage } : {}),\n stats: {\n total_nodes: run.stats.totalNodes,\n cached_nodes: run.stats.cachedNodes,\n total_credits: run.stats.totalCredits,\n duration_ms: run.stats.durationMs,\n },\n outputs: run.finalOutputs,\n node_runs: run.nodes.map((node) => ({\n node_id: node.nodeId,\n node_type: node.nodeType,\n cached: node.cached,\n duration_ms: node.durationMs,\n credits: node.credits,\n ...(node.status ? { status: node.status } : {}),\n outputs: node.outputs,\n })),\n ...(run.review ? { review: run.review } : {}),\n hints: [\n \"This run's folder is not in this workspace, so there are no local files: every output above is a durable URL. To render it again here, run `baker canvas run --slug <creative>`.\",\n ],\n };\n process.stdout.write(`${JSON.stringify(summary, null, 2)}\\n`);\n}\n\nfunction fail(code: string, message: string): never {\n process.stderr.write(`${JSON.stringify({ ok: false, error: { code, message } }, null, 2)}\\n`);\n process.exit(2);\n}\n\nasync function loadManifest(runDir: string): Promise<Manifest> {\n const manifestPath = path.join(runDir, \"manifest.json\");\n try {\n const raw = await readFile(manifestPath, \"utf-8\");\n return JSON.parse(raw) as Manifest;\n } catch {\n return {} as Manifest;\n }\n}\n\ntype RunFile = { name: string; path: string; size: number };\nasync function listRunFiles(runDir: string): Promise<RunFile[]> {\n const out: RunFile[] = [];\n const names = await readdir(runDir);\n for (const name of names) {\n const abs = path.join(runDir, name);\n const s = await stat(abs).catch(() => null);\n if (!s?.isFile()) continue;\n out.push({ name, path: abs, size: s.size });\n }\n out.sort((a, b) => a.name.localeCompare(b.name));\n return out;\n}\n\nfunction isVideoFile(p: string): boolean {\n return /\\.(mp4|webm|mov)$/i.test(p);\n}\n\nasync function extractThumbnails(videoPaths: string[]): Promise<Array<{ video: string; frames: string[] }>> {\n const out: Array<{ video: string; frames: string[] }> = [];\n for (const v of videoPaths) {\n const duration = await probeDuration(v).catch(() => null);\n if (duration === null) {\n out.push({ video: v, frames: [] });\n continue;\n }\n const frames: string[] = [];\n const checkpoints = [0.05, 0.5, 0.95];\n const base = v.replace(/\\.[^.]+$/, \"\");\n for (const ratio of checkpoints) {\n const at = Math.max(0, Math.min(duration * ratio, duration - 0.01));\n const dest = `${base}__frame_${Math.round(ratio * 100)\n .toString()\n .padStart(2, \"0\")}.png`;\n try {\n await execFileAsync(\"ffmpeg\", [\"-ss\", at.toFixed(3), \"-i\", v, \"-frames:v\", \"1\", \"-y\", dest]);\n frames.push(dest);\n } catch {\n // skip — best-effort; thumbnail extraction is non-fatal.\n }\n }\n out.push({ video: v, frames });\n }\n return out;\n}\n\nasync function probeDuration(filePath: string): Promise<number> {\n const { stdout } = await execFileAsync(\n \"ffprobe\",\n [\"-v\", \"error\", \"-show_entries\", \"format=duration\", \"-of\", \"csv=p=0\", filePath],\n { encoding: \"utf-8\" },\n );\n return Number.parseFloat(stdout.trim());\n}\n"],"mappings":"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","names":[]}
@@ -50,4 +50,4 @@ Full guide: __tooling__/docs/tools/baker/landing.md`
50
50
  export {
51
51
  inspirationCommand
52
52
  };
53
- //# sourceMappingURL=inspiration-P265QJ2H.js.map
53
+ //# sourceMappingURL=inspiration-S3DU4CMQ.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  keywordMetricsHints
3
- } from "./chunk-OZRUJVIQ.js";
3
+ } from "./chunk-H3427GPU.js";
4
4
  import {
5
5
  RESEARCH_DATA_NOTE,
6
6
  handleResearchError,
@@ -15,10 +15,11 @@ import {
15
15
  import "./chunk-XCM6XWOB.js";
16
16
  import {
17
17
  RESEARCH_KEYWORD_METRICS_MAX_KEYWORDS
18
- } from "./chunk-XF4JUKVF.js";
18
+ } from "./chunk-7EPXVICM.js";
19
19
  import "./chunk-GXDLWBOY.js";
20
20
  import "./chunk-TEINLN64.js";
21
21
  import "./chunk-ZJWUBJYQ.js";
22
+ import "./chunk-HR6IWNKE.js";
22
23
  import "./chunk-NE4F3FHN.js";
23
24
  import {
24
25
  apiPost
@@ -194,4 +195,4 @@ Examples:
194
195
  export {
195
196
  keywordMetricsCommand
196
197
  };
197
- //# sourceMappingURL=keyword-metrics-PDY4ZXSP.js.map
198
+ //# sourceMappingURL=keyword-metrics-SF4CSNZ2.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/research/keyword-metrics.ts","../src/commands/research/keyword-metrics-rows.ts"],"sourcesContent":["import { RESEARCH_KEYWORD_METRICS_MAX_KEYWORDS, type ResearchKeywordMetricsRow } from \"@baker/api\";\nimport { defineCommand } from \"citty\";\nimport { apiPost } from \"../../client.ts\";\nimport { buildResearchQueryContext, warnDefaults } from \"../../geo-context.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport { keywordMetricsHints } from \"./hints.ts\";\nimport { keywordMetricsFields, toOutputRow } from \"./keyword-metrics-rows.ts\";\nimport {\n handleResearchError,\n RESEARCH_DATA_NOTE,\n writeResearchHints,\n writeResearchJson,\n writeResearchOutput,\n} from \"./output.ts\";\n\nregisterSchema({\n command: \"research.keyword-metrics\",\n description:\n \"Search volume, CPC, top-of-page bids and competition for a list of keywords you name — no domain needed. This is the command for sizing a market you have keywords for; the domain-bound ones (keywords-for-site, keyword-gap) answer a different question and should not be used as a workaround for this one. The volume is Google's Keyword Planner figure resold by DataForSEO, so it is not a second opinion on `baker ads google keywords metrics` — for that, pass --clickstream. If --location and --language are omitted, defaults to United States (us) and English (en). The response includes a query_context object showing which location/language were used.\",\n args: {\n keywords: {\n type: \"string\",\n description: `Comma-separated keywords (max ${RESEARCH_KEYWORD_METRICS_MAX_KEYWORDS}, 80 chars each)`,\n required: true,\n },\n location: {\n type: \"string\",\n description:\n \"Country code (us, mx, br, es...) or DataForSEO location code. Defaults to us (United States) if omitted — always set this for non-US markets\",\n required: false,\n },\n language: {\n type: \"string\",\n description:\n \"Language code or name. Defaults to en (English) if omitted — always set this for non-English markets\",\n required: false,\n },\n clickstream: {\n type: \"boolean\",\n description:\n \"Also return DataForSEO's own panel-derived volume (clickstream_search_volume), the only genuinely independent estimate of demand available here. Costs 2x.\",\n required: false,\n },\n full: {\n type: \"boolean\",\n description: \"Add keyword difficulty, search intent and the 12-month volume trend to each row\",\n required: false,\n },\n \"no-cache\": { type: \"boolean\", description: \"Skip server cache, hit API directly\", required: false },\n },\n});\n\nexport const keywordMetricsCommand = defineCommand({\n meta: {\n name: \"keyword-metrics\",\n description: `Volume, CPC and competition for keywords you name. No domain required.\n\nNumbers are Keyword Planner ESTIMATES of total market volume, resold by DataForSEO — every column carrying one is named planner_. Pass --clickstream for DataForSEO's own independent estimate alongside.\n\nExamples:\n baker research keyword-metrics \"chatbot whatsapp,agente whatsapp ecommerce\" --location mx --language es\n baker research keyword-metrics \"chatbot whatsapp\" --location br --language pt --clickstream\n baker research keyword-metrics \"crm software,best crm\" --full --output md`,\n },\n args: {\n keywords: { type: \"positional\", description: \"Comma-separated keywords\", required: true },\n location: { type: \"string\", description: \"Country code or location code (default: us)\", required: false },\n language: { type: \"string\", description: \"Language code or name (default: en)\", required: false },\n clickstream: { type: \"boolean\", description: \"Add DataForSEO's own volume estimate (costs 2x)\", required: false },\n full: { type: \"boolean\", description: \"Add difficulty, intent and the 12-month trend\", required: false },\n output: { type: \"string\", description: \"Format: json|csv|md|jsonl\", required: false, default: \"json\" },\n \"no-cache\": { type: \"boolean\", description: \"Skip server cache, hit API directly\", required: false },\n },\n run: async ({ args }) => {\n const keywords = (args.keywords as string)\n .split(\",\")\n .map((k) => k.trim())\n .filter(Boolean);\n\n if (keywords.length === 0) {\n writeResearchJson({\n ok: false,\n error: { code: \"VALIDATION_ERROR\", message: \"Provide at least one keyword\" },\n });\n process.exit(1);\n }\n if (keywords.length > RESEARCH_KEYWORD_METRICS_MAX_KEYWORDS) {\n writeResearchJson({\n ok: false,\n error: {\n code: \"VALIDATION_ERROR\",\n message: `Maximum ${RESEARCH_KEYWORD_METRICS_MAX_KEYWORDS} keywords per request`,\n fix: {\n action: \"retry_with_changes\",\n explanation: `You sent ${keywords.length}. Split the list into batches of ${RESEARCH_KEYWORD_METRICS_MAX_KEYWORDS} and run the command once per batch — each batch is a separate charge, so batch by priority.`,\n },\n },\n });\n process.exit(1);\n }\n\n const location = (args.location as string) || undefined;\n const language = (args.language as string) || undefined;\n const clickstream = Boolean(args.clickstream);\n const full = Boolean(args.full);\n const queryContext = buildResearchQueryContext(location, language);\n\n try {\n const result = await apiPost<{ data: ResearchKeywordMetricsRow[] }>(\"/api/research/keyword-metrics\", {\n keywords,\n location,\n language,\n includeClickstream: clickstream,\n skipCache: args[\"no-cache\"] ? true : undefined,\n });\n\n const columns = { clickstream, full };\n const rows = result.data.map((row) => toOutputRow(row, columns));\n const hints = keywordMetricsHints({ rows: result.data, asked: keywords, clickstream, queryContext });\n\n warnDefaults(queryContext);\n const format = (args.output as string) || \"json\";\n if (format !== \"json\") {\n writeResearchOutput(rows, format);\n writeResearchHints([...hints, RESEARCH_DATA_NOTE], format);\n return;\n }\n writeResearchJson({\n ok: true,\n data: rows,\n fields: keywordMetricsFields(columns),\n note: RESEARCH_DATA_NOTE,\n hints,\n query_context: queryContext,\n });\n } catch (err) {\n handleResearchError(err);\n }\n },\n});\n","/**\n * Naming the rows of `baker research keyword-metrics` after where each number\n * came from.\n *\n * DataForSEO does not measure Google's search volume — it resells the Keyword\n * Planner figure, so `search_volume` here and `planner_avg_monthly_searches`\n * from `baker ads google keywords metrics` are one number with two names. A run\n * that did not know that presented the two side by side as agreeing sources and\n * reported the agreement as validation; they matched to the digit in all seven\n * rows because they are the same row. The only defence that survives a CSV in\n * /tmp is the column name, which is the same conclusion `ads/google/keywords/\n * provenance.ts` reached for the other half of the pair — so the same prefix is\n * used deliberately.\n *\n * The exception is clickstream: `clickstream_search_volume` is DataForSEO's own\n * panel-derived estimate and genuinely is a second opinion. It keeps its own\n * prefix so it can never be read as Google's, or Google's as it.\n */\nimport type { ResearchKeywordMetricsRow } from \"@baker/api\";\n\nexport const KEYWORD_METRICS_SOURCE = \"keyword_planner_estimate_via_dataforseo\";\n\nexport type KeywordMetricsOutputRow = Record<string, unknown>;\n\nexport interface KeywordMetricsColumnOptions {\n /** The request asked for DataForSEO's panel volume alongside Google's. */\n clickstream: boolean;\n /** Add difficulty, intent and the 12-month trend. */\n full: boolean;\n}\n\nexport function toOutputRow(\n row: ResearchKeywordMetricsRow,\n options: KeywordMetricsColumnOptions,\n): KeywordMetricsOutputRow {\n const out: KeywordMetricsOutputRow = {\n source: KEYWORD_METRICS_SOURCE,\n keyword: row.keyword,\n planner_search_volume: row.search_volume,\n planner_cpc: row.cpc,\n planner_low_top_of_page_bid: row.low_top_of_page_bid,\n planner_high_top_of_page_bid: row.high_top_of_page_bid,\n planner_competition: row.competition,\n planner_competition_index: row.competition_index,\n };\n if (options.clickstream) {\n out.clickstream_search_volume = row.clickstream_search_volume;\n }\n if (options.full) {\n out.keyword_difficulty = row.keyword_difficulty;\n out.main_intent = row.main_intent;\n out.planner_monthly_searches = row.monthly_searches;\n }\n return out;\n}\n\nexport function keywordMetricsFields(options: KeywordMetricsColumnOptions): Record<string, string> {\n const fields: Record<string, string> = {\n source: `Always \"${KEYWORD_METRICS_SOURCE}\". Every planner_ column below is Google's Keyword Planner ESTIMATE of total market volume, resold by DataForSEO — the same number \\`baker ads google keywords metrics\\` returns, not an independent measurement of it. Columns without the planner_ prefix are DataForSEO's own.`,\n keyword:\n \"The keyword asked for. A row with every metric null means DataForSEO holds no data on it — not that nobody searches it.\",\n planner_search_volume: \"ESTIMATE: average monthly searches across the whole market, last 12 months\",\n planner_cpc: \"ESTIMATE: average cost per click in USD (a single blended figure, not a top-of-page range)\",\n planner_low_top_of_page_bid: \"ESTIMATE: low-range top-of-page bid in USD\",\n planner_high_top_of_page_bid: \"ESTIMATE: high-range top-of-page bid in USD\",\n planner_competition: \"ESTIMATE: competition level — LOW, MEDIUM or HIGH\",\n planner_competition_index: \"ESTIMATE: competition index 0-100 (higher = more advertisers)\",\n };\n if (options.clickstream) {\n fields.clickstream_search_volume =\n \"DataForSEO's OWN volume estimate, from clickstream panels — not Google's, and the only number here that is a genuine second opinion on demand. Expect it to differ from planner_search_volume; that is the point.\";\n }\n if (options.full) {\n fields.keyword_difficulty = \"DataForSEO's 0-100 estimate of how hard ranking in the organic top 10 would be\";\n fields.main_intent = \"DataForSEO's intent classification: informational, navigational, commercial or transactional\";\n fields.planner_monthly_searches = \"ESTIMATE: 12-month volume breakdown ({year, month, search_volume})\";\n }\n return fields;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/commands/research/keyword-metrics.ts","../src/commands/research/keyword-metrics-rows.ts"],"sourcesContent":["import { RESEARCH_KEYWORD_METRICS_MAX_KEYWORDS, type ResearchKeywordMetricsRow } from \"@baker/api\";\nimport { defineCommand } from \"citty\";\nimport { apiPost } from \"../../client.ts\";\nimport { buildResearchQueryContext, warnDefaults } from \"../../geo-context.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport { keywordMetricsHints } from \"./hints.ts\";\nimport { keywordMetricsFields, toOutputRow } from \"./keyword-metrics-rows.ts\";\nimport {\n handleResearchError,\n RESEARCH_DATA_NOTE,\n writeResearchHints,\n writeResearchJson,\n writeResearchOutput,\n} from \"./output.ts\";\n\nregisterSchema({\n command: \"research.keyword-metrics\",\n description:\n \"Search volume, CPC, top-of-page bids and competition for a list of keywords you name — no domain needed. This is the command for sizing a market you have keywords for; the domain-bound ones (keywords-for-site, keyword-gap) answer a different question and should not be used as a workaround for this one. The volume is Google's Keyword Planner figure resold by DataForSEO, so it is not a second opinion on `baker ads google keywords metrics` — for that, pass --clickstream. If --location and --language are omitted, defaults to United States (us) and English (en). The response includes a query_context object showing which location/language were used.\",\n args: {\n keywords: {\n type: \"string\",\n description: `Comma-separated keywords (max ${RESEARCH_KEYWORD_METRICS_MAX_KEYWORDS}, 80 chars each)`,\n required: true,\n },\n location: {\n type: \"string\",\n description:\n \"Country code (us, mx, br, es...) or DataForSEO location code. Defaults to us (United States) if omitted — always set this for non-US markets\",\n required: false,\n },\n language: {\n type: \"string\",\n description:\n \"Language code or name. Defaults to en (English) if omitted — always set this for non-English markets\",\n required: false,\n },\n clickstream: {\n type: \"boolean\",\n description:\n \"Also return DataForSEO's own panel-derived volume (clickstream_search_volume), the only genuinely independent estimate of demand available here. Costs 2x.\",\n required: false,\n },\n full: {\n type: \"boolean\",\n description: \"Add keyword difficulty, search intent and the 12-month volume trend to each row\",\n required: false,\n },\n \"no-cache\": { type: \"boolean\", description: \"Skip server cache, hit API directly\", required: false },\n },\n});\n\nexport const keywordMetricsCommand = defineCommand({\n meta: {\n name: \"keyword-metrics\",\n description: `Volume, CPC and competition for keywords you name. No domain required.\n\nNumbers are Keyword Planner ESTIMATES of total market volume, resold by DataForSEO — every column carrying one is named planner_. Pass --clickstream for DataForSEO's own independent estimate alongside.\n\nExamples:\n baker research keyword-metrics \"chatbot whatsapp,agente whatsapp ecommerce\" --location mx --language es\n baker research keyword-metrics \"chatbot whatsapp\" --location br --language pt --clickstream\n baker research keyword-metrics \"crm software,best crm\" --full --output md`,\n },\n args: {\n keywords: { type: \"positional\", description: \"Comma-separated keywords\", required: true },\n location: { type: \"string\", description: \"Country code or location code (default: us)\", required: false },\n language: { type: \"string\", description: \"Language code or name (default: en)\", required: false },\n clickstream: { type: \"boolean\", description: \"Add DataForSEO's own volume estimate (costs 2x)\", required: false },\n full: { type: \"boolean\", description: \"Add difficulty, intent and the 12-month trend\", required: false },\n output: { type: \"string\", description: \"Format: json|csv|md|jsonl\", required: false, default: \"json\" },\n \"no-cache\": { type: \"boolean\", description: \"Skip server cache, hit API directly\", required: false },\n },\n run: async ({ args }) => {\n const keywords = (args.keywords as string)\n .split(\",\")\n .map((k) => k.trim())\n .filter(Boolean);\n\n if (keywords.length === 0) {\n writeResearchJson({\n ok: false,\n error: { code: \"VALIDATION_ERROR\", message: \"Provide at least one keyword\" },\n });\n process.exit(1);\n }\n if (keywords.length > RESEARCH_KEYWORD_METRICS_MAX_KEYWORDS) {\n writeResearchJson({\n ok: false,\n error: {\n code: \"VALIDATION_ERROR\",\n message: `Maximum ${RESEARCH_KEYWORD_METRICS_MAX_KEYWORDS} keywords per request`,\n fix: {\n action: \"retry_with_changes\",\n explanation: `You sent ${keywords.length}. Split the list into batches of ${RESEARCH_KEYWORD_METRICS_MAX_KEYWORDS} and run the command once per batch — each batch is a separate charge, so batch by priority.`,\n },\n },\n });\n process.exit(1);\n }\n\n const location = (args.location as string) || undefined;\n const language = (args.language as string) || undefined;\n const clickstream = Boolean(args.clickstream);\n const full = Boolean(args.full);\n const queryContext = buildResearchQueryContext(location, language);\n\n try {\n const result = await apiPost<{ data: ResearchKeywordMetricsRow[] }>(\"/api/research/keyword-metrics\", {\n keywords,\n location,\n language,\n includeClickstream: clickstream,\n skipCache: args[\"no-cache\"] ? true : undefined,\n });\n\n const columns = { clickstream, full };\n const rows = result.data.map((row) => toOutputRow(row, columns));\n const hints = keywordMetricsHints({ rows: result.data, asked: keywords, clickstream, queryContext });\n\n warnDefaults(queryContext);\n const format = (args.output as string) || \"json\";\n if (format !== \"json\") {\n writeResearchOutput(rows, format);\n writeResearchHints([...hints, RESEARCH_DATA_NOTE], format);\n return;\n }\n writeResearchJson({\n ok: true,\n data: rows,\n fields: keywordMetricsFields(columns),\n note: RESEARCH_DATA_NOTE,\n hints,\n query_context: queryContext,\n });\n } catch (err) {\n handleResearchError(err);\n }\n },\n});\n","/**\n * Naming the rows of `baker research keyword-metrics` after where each number\n * came from.\n *\n * DataForSEO does not measure Google's search volume — it resells the Keyword\n * Planner figure, so `search_volume` here and `planner_avg_monthly_searches`\n * from `baker ads google keywords metrics` are one number with two names. A run\n * that did not know that presented the two side by side as agreeing sources and\n * reported the agreement as validation; they matched to the digit in all seven\n * rows because they are the same row. The only defence that survives a CSV in\n * /tmp is the column name, which is the same conclusion `ads/google/keywords/\n * provenance.ts` reached for the other half of the pair — so the same prefix is\n * used deliberately.\n *\n * The exception is clickstream: `clickstream_search_volume` is DataForSEO's own\n * panel-derived estimate and genuinely is a second opinion. It keeps its own\n * prefix so it can never be read as Google's, or Google's as it.\n */\nimport type { ResearchKeywordMetricsRow } from \"@baker/api\";\n\nexport const KEYWORD_METRICS_SOURCE = \"keyword_planner_estimate_via_dataforseo\";\n\nexport type KeywordMetricsOutputRow = Record<string, unknown>;\n\nexport interface KeywordMetricsColumnOptions {\n /** The request asked for DataForSEO's panel volume alongside Google's. */\n clickstream: boolean;\n /** Add difficulty, intent and the 12-month trend. */\n full: boolean;\n}\n\nexport function toOutputRow(\n row: ResearchKeywordMetricsRow,\n options: KeywordMetricsColumnOptions,\n): KeywordMetricsOutputRow {\n const out: KeywordMetricsOutputRow = {\n source: KEYWORD_METRICS_SOURCE,\n keyword: row.keyword,\n planner_search_volume: row.search_volume,\n planner_cpc: row.cpc,\n planner_low_top_of_page_bid: row.low_top_of_page_bid,\n planner_high_top_of_page_bid: row.high_top_of_page_bid,\n planner_competition: row.competition,\n planner_competition_index: row.competition_index,\n };\n if (options.clickstream) {\n out.clickstream_search_volume = row.clickstream_search_volume;\n }\n if (options.full) {\n out.keyword_difficulty = row.keyword_difficulty;\n out.main_intent = row.main_intent;\n out.planner_monthly_searches = row.monthly_searches;\n }\n return out;\n}\n\nexport function keywordMetricsFields(options: KeywordMetricsColumnOptions): Record<string, string> {\n const fields: Record<string, string> = {\n source: `Always \"${KEYWORD_METRICS_SOURCE}\". Every planner_ column below is Google's Keyword Planner ESTIMATE of total market volume, resold by DataForSEO — the same number \\`baker ads google keywords metrics\\` returns, not an independent measurement of it. Columns without the planner_ prefix are DataForSEO's own.`,\n keyword:\n \"The keyword asked for. A row with every metric null means DataForSEO holds no data on it — not that nobody searches it.\",\n planner_search_volume: \"ESTIMATE: average monthly searches across the whole market, last 12 months\",\n planner_cpc: \"ESTIMATE: average cost per click in USD (a single blended figure, not a top-of-page range)\",\n planner_low_top_of_page_bid: \"ESTIMATE: low-range top-of-page bid in USD\",\n planner_high_top_of_page_bid: \"ESTIMATE: high-range top-of-page bid in USD\",\n planner_competition: \"ESTIMATE: competition level — LOW, MEDIUM or HIGH\",\n planner_competition_index: \"ESTIMATE: competition index 0-100 (higher = more advertisers)\",\n };\n if (options.clickstream) {\n fields.clickstream_search_volume =\n \"DataForSEO's OWN volume estimate, from clickstream panels — not Google's, and the only number here that is a genuine second opinion on demand. Expect it to differ from planner_search_volume; that is the point.\";\n }\n if (options.full) {\n fields.keyword_difficulty = \"DataForSEO's 0-100 estimate of how hard ranking in the organic top 10 would be\";\n fields.main_intent = \"DataForSEO's intent classification: informational, navigational, commercial or transactional\";\n fields.planner_monthly_searches = \"ESTIMATE: 12-month volume breakdown ({year, month, search_volume})\";\n }\n return fields;\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  keywordsForSiteHints
3
- } from "./chunk-OZRUJVIQ.js";
3
+ } from "./chunk-H3427GPU.js";
4
4
  import {
5
5
  RESEARCH_DATA_NOTE,
6
6
  handleResearchError,
@@ -13,10 +13,11 @@ import {
13
13
  warnDefaults
14
14
  } from "./chunk-LIQ4SQ2T.js";
15
15
  import "./chunk-XCM6XWOB.js";
16
- import "./chunk-XF4JUKVF.js";
16
+ import "./chunk-7EPXVICM.js";
17
17
  import "./chunk-GXDLWBOY.js";
18
18
  import "./chunk-TEINLN64.js";
19
19
  import "./chunk-ZJWUBJYQ.js";
20
+ import "./chunk-HR6IWNKE.js";
20
21
  import "./chunk-NE4F3FHN.js";
21
22
  import {
22
23
  apiPost
@@ -125,4 +126,4 @@ Examples:
125
126
  export {
126
127
  keywordsForSiteCommand
127
128
  };
128
- //# sourceMappingURL=keywords-for-site-GALSCV77.js.map
129
+ //# sourceMappingURL=keywords-for-site-WDAOPNKC.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/research/keywords-for-site.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { apiPost } from \"../../client.ts\";\nimport { buildResearchQueryContext, warnDefaults } from \"../../geo-context.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport { keywordsForSiteHints } from \"./hints.ts\";\nimport {\n handleResearchError,\n RESEARCH_DATA_NOTE,\n writeResearchHints,\n writeResearchJson,\n writeResearchOutput,\n} from \"./output.ts\";\n\nregisterSchema({\n command: \"research.keywords-for-site\",\n description:\n \"Get keywords a competitor targets in Google. Use --type paid to see only paid keywords, --type organic for organic only. If --location and --language are omitted, defaults to United States (us) and English (en). The response includes a query_context object showing which location/language were used.\",\n args: {\n target: { type: \"string\", description: \"Domain or URL to analyze (positional)\", required: true },\n location: {\n type: \"string\",\n description:\n \"Country code (us, uk, es, de...) or DataForSEO location code. Defaults to us (United States) if omitted — always set this for non-US markets\",\n required: false,\n },\n language: {\n type: \"string\",\n description:\n \"Language code or name. Defaults to en (English) if omitted — always set this for non-English markets\",\n required: false,\n },\n sort: {\n type: \"string\",\n description: \"Sort: search_volume, competition, cpc (default: search_volume)\",\n required: false,\n },\n type: { type: \"string\", description: \"Filter: paid, organic, all (default: all)\", required: false },\n limit: { type: \"string\", description: \"Max results (default: 50, max: 1000)\", required: false },\n \"no-cache\": { type: \"boolean\", description: \"Skip server cache, hit API directly\", required: false },\n },\n});\n\ninterface KeywordForSite {\n keyword: string;\n search_volume: number;\n cpc: number;\n competition: string;\n competition_index: number;\n}\n\nconst FIELDS: Record<string, string> = {\n keyword: \"Keyword the site targets\",\n search_volume: \"Monthly search volume\",\n cpc: \"Cost per click in USD\",\n competition: \"LOW, MEDIUM, or HIGH\",\n competition_index: \"Competition score 0-100\",\n};\n\nexport const keywordsForSiteCommand = defineCommand({\n meta: {\n name: \"keywords-for-site\",\n description: `Get keywords a competitor targets in Google. Use --type to filter paid/organic.\n\nExamples:\n baker research keywords-for-site \"competitor.com\"\n baker research keywords-for-site \"competitor.com\" --type paid --limit 20\n baker research keywords-for-site \"competitor.com\" --type organic --location uk`,\n },\n args: {\n target: { type: \"positional\", description: \"Domain or URL to analyze\", required: true },\n location: { type: \"string\", description: \"Country code or location code (default: us)\", required: false },\n language: { type: \"string\", description: \"Language code or name (default: en)\", required: false },\n sort: { type: \"string\", description: \"Sort: search_volume, competition, cpc\", required: false },\n type: { type: \"string\", description: \"Filter: paid, organic, all (default: all)\", required: false },\n limit: { type: \"string\", description: \"Max results (default: 50, max: 1000)\", required: false },\n output: { type: \"string\", description: \"Format: json|csv|md|jsonl\", required: false, default: \"json\" },\n \"no-cache\": { type: \"boolean\", description: \"Skip server cache, hit API directly\", required: false },\n },\n run: async ({ args }) => {\n const target = args.target as string;\n const location = (args.location as string) || undefined;\n const language = (args.language as string) || undefined;\n const sort = (args.sort as string) || undefined;\n const type = (args.type as string) || undefined;\n const limit = args.limit ? Number(args.limit) : undefined;\n const skipCache = args[\"no-cache\"] ? true : undefined;\n const queryContext = buildResearchQueryContext(location, language);\n\n try {\n const data = await apiPost<KeywordForSite[]>(\"/api/research/keywords-for-site\", {\n target,\n location,\n language,\n sort,\n type,\n limit,\n skipCache,\n });\n\n warnDefaults(queryContext);\n const format = (args.output as string) || \"json\";\n const hints = keywordsForSiteHints(data.length, queryContext, type);\n if (format !== \"json\") {\n writeResearchOutput(data as unknown as Array<Record<string, unknown>>, format);\n writeResearchHints(hints, format);\n return;\n }\n writeResearchJson({\n ok: true,\n data,\n fields: FIELDS,\n note: RESEARCH_DATA_NOTE,\n query_context: queryContext,\n hints,\n });\n } catch (err) {\n handleResearchError(err);\n }\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,qBAAqB;AAa9B,eAAe;AAAA,EACb,SAAS;AAAA,EACT,aACE;AAAA,EACF,MAAM;AAAA,IACJ,QAAQ,EAAE,MAAM,UAAU,aAAa,yCAAyC,UAAU,KAAK;AAAA,IAC/F,UAAU;AAAA,MACR,MAAM;AAAA,MACN,aACE;AAAA,MACF,UAAU;AAAA,IACZ;AAAA,IACA,UAAU;AAAA,MACR,MAAM;AAAA,MACN,aACE;AAAA,MACF,UAAU;AAAA,IACZ;AAAA,IACA,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,IACZ;AAAA,IACA,MAAM,EAAE,MAAM,UAAU,aAAa,6CAA6C,UAAU,MAAM;AAAA,IAClG,OAAO,EAAE,MAAM,UAAU,aAAa,wCAAwC,UAAU,MAAM;AAAA,IAC9F,YAAY,EAAE,MAAM,WAAW,aAAa,uCAAuC,UAAU,MAAM;AAAA,EACrG;AACF,CAAC;AAUD,IAAM,SAAiC;AAAA,EACrC,SAAS;AAAA,EACT,eAAe;AAAA,EACf,KAAK;AAAA,EACL,aAAa;AAAA,EACb,mBAAmB;AACrB;AAEO,IAAM,yBAAyB,cAAc;AAAA,EAClD,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMf;AAAA,EACA,MAAM;AAAA,IACJ,QAAQ,EAAE,MAAM,cAAc,aAAa,4BAA4B,UAAU,KAAK;AAAA,IACtF,UAAU,EAAE,MAAM,UAAU,aAAa,+CAA+C,UAAU,MAAM;AAAA,IACxG,UAAU,EAAE,MAAM,UAAU,aAAa,uCAAuC,UAAU,MAAM;AAAA,IAChG,MAAM,EAAE,MAAM,UAAU,aAAa,yCAAyC,UAAU,MAAM;AAAA,IAC9F,MAAM,EAAE,MAAM,UAAU,aAAa,6CAA6C,UAAU,MAAM;AAAA,IAClG,OAAO,EAAE,MAAM,UAAU,aAAa,wCAAwC,UAAU,MAAM;AAAA,IAC9F,QAAQ,EAAE,MAAM,UAAU,aAAa,6BAA6B,UAAU,OAAO,SAAS,OAAO;AAAA,IACrG,YAAY,EAAE,MAAM,WAAW,aAAa,uCAAuC,UAAU,MAAM;AAAA,EACrG;AAAA,EACA,KAAK,OAAO,EAAE,KAAK,MAAM;AACvB,UAAM,SAAS,KAAK;AACpB,UAAM,WAAY,KAAK,YAAuB;AAC9C,UAAM,WAAY,KAAK,YAAuB;AAC9C,UAAM,OAAQ,KAAK,QAAmB;AACtC,UAAM,OAAQ,KAAK,QAAmB;AACtC,UAAM,QAAQ,KAAK,QAAQ,OAAO,KAAK,KAAK,IAAI;AAChD,UAAM,YAAY,KAAK,UAAU,IAAI,OAAO;AAC5C,UAAM,eAAe,0BAA0B,UAAU,QAAQ;AAEjE,QAAI;AACF,YAAM,OAAO,MAAM,QAA0B,mCAAmC;AAAA,QAC9E;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAED,mBAAa,YAAY;AACzB,YAAM,SAAU,KAAK,UAAqB;AAC1C,YAAM,QAAQ,qBAAqB,KAAK,QAAQ,cAAc,IAAI;AAClE,UAAI,WAAW,QAAQ;AACrB,4BAAoB,MAAmD,MAAM;AAC7E,2BAAmB,OAAO,MAAM;AAChC;AAAA,MACF;AACA,wBAAkB;AAAA,QAChB,IAAI;AAAA,QACJ;AAAA,QACA,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,eAAe;AAAA,QACf;AAAA,MACF,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,0BAAoB,GAAG;AAAA,IACzB;AAAA,EACF;AACF,CAAC;","names":[]}
1
+ {"version":3,"sources":["../src/commands/research/keywords-for-site.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { apiPost } from \"../../client.ts\";\nimport { buildResearchQueryContext, warnDefaults } from \"../../geo-context.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport { keywordsForSiteHints } from \"./hints.ts\";\nimport {\n handleResearchError,\n RESEARCH_DATA_NOTE,\n writeResearchHints,\n writeResearchJson,\n writeResearchOutput,\n} from \"./output.ts\";\n\nregisterSchema({\n command: \"research.keywords-for-site\",\n description:\n \"Get keywords a competitor targets in Google. Use --type paid to see only paid keywords, --type organic for organic only. If --location and --language are omitted, defaults to United States (us) and English (en). The response includes a query_context object showing which location/language were used.\",\n args: {\n target: { type: \"string\", description: \"Domain or URL to analyze (positional)\", required: true },\n location: {\n type: \"string\",\n description:\n \"Country code (us, uk, es, de...) or DataForSEO location code. Defaults to us (United States) if omitted — always set this for non-US markets\",\n required: false,\n },\n language: {\n type: \"string\",\n description:\n \"Language code or name. Defaults to en (English) if omitted — always set this for non-English markets\",\n required: false,\n },\n sort: {\n type: \"string\",\n description: \"Sort: search_volume, competition, cpc (default: search_volume)\",\n required: false,\n },\n type: { type: \"string\", description: \"Filter: paid, organic, all (default: all)\", required: false },\n limit: { type: \"string\", description: \"Max results (default: 50, max: 1000)\", required: false },\n \"no-cache\": { type: \"boolean\", description: \"Skip server cache, hit API directly\", required: false },\n },\n});\n\ninterface KeywordForSite {\n keyword: string;\n search_volume: number;\n cpc: number;\n competition: string;\n competition_index: number;\n}\n\nconst FIELDS: Record<string, string> = {\n keyword: \"Keyword the site targets\",\n search_volume: \"Monthly search volume\",\n cpc: \"Cost per click in USD\",\n competition: \"LOW, MEDIUM, or HIGH\",\n competition_index: \"Competition score 0-100\",\n};\n\nexport const keywordsForSiteCommand = defineCommand({\n meta: {\n name: \"keywords-for-site\",\n description: `Get keywords a competitor targets in Google. Use --type to filter paid/organic.\n\nExamples:\n baker research keywords-for-site \"competitor.com\"\n baker research keywords-for-site \"competitor.com\" --type paid --limit 20\n baker research keywords-for-site \"competitor.com\" --type organic --location uk`,\n },\n args: {\n target: { type: \"positional\", description: \"Domain or URL to analyze\", required: true },\n location: { type: \"string\", description: \"Country code or location code (default: us)\", required: false },\n language: { type: \"string\", description: \"Language code or name (default: en)\", required: false },\n sort: { type: \"string\", description: \"Sort: search_volume, competition, cpc\", required: false },\n type: { type: \"string\", description: \"Filter: paid, organic, all (default: all)\", required: false },\n limit: { type: \"string\", description: \"Max results (default: 50, max: 1000)\", required: false },\n output: { type: \"string\", description: \"Format: json|csv|md|jsonl\", required: false, default: \"json\" },\n \"no-cache\": { type: \"boolean\", description: \"Skip server cache, hit API directly\", required: false },\n },\n run: async ({ args }) => {\n const target = args.target as string;\n const location = (args.location as string) || undefined;\n const language = (args.language as string) || undefined;\n const sort = (args.sort as string) || undefined;\n const type = (args.type as string) || undefined;\n const limit = args.limit ? Number(args.limit) : undefined;\n const skipCache = args[\"no-cache\"] ? true : undefined;\n const queryContext = buildResearchQueryContext(location, language);\n\n try {\n const data = await apiPost<KeywordForSite[]>(\"/api/research/keywords-for-site\", {\n target,\n location,\n language,\n sort,\n type,\n limit,\n skipCache,\n });\n\n warnDefaults(queryContext);\n const format = (args.output as string) || \"json\";\n const hints = keywordsForSiteHints(data.length, queryContext, type);\n if (format !== \"json\") {\n writeResearchOutput(data as unknown as Array<Record<string, unknown>>, format);\n writeResearchHints(hints, format);\n return;\n }\n writeResearchJson({\n ok: true,\n data,\n fields: FIELDS,\n note: RESEARCH_DATA_NOTE,\n query_context: queryContext,\n hints,\n });\n } catch (err) {\n handleResearchError(err);\n }\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,qBAAqB;AAa9B,eAAe;AAAA,EACb,SAAS;AAAA,EACT,aACE;AAAA,EACF,MAAM;AAAA,IACJ,QAAQ,EAAE,MAAM,UAAU,aAAa,yCAAyC,UAAU,KAAK;AAAA,IAC/F,UAAU;AAAA,MACR,MAAM;AAAA,MACN,aACE;AAAA,MACF,UAAU;AAAA,IACZ;AAAA,IACA,UAAU;AAAA,MACR,MAAM;AAAA,MACN,aACE;AAAA,MACF,UAAU;AAAA,IACZ;AAAA,IACA,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,IACZ;AAAA,IACA,MAAM,EAAE,MAAM,UAAU,aAAa,6CAA6C,UAAU,MAAM;AAAA,IAClG,OAAO,EAAE,MAAM,UAAU,aAAa,wCAAwC,UAAU,MAAM;AAAA,IAC9F,YAAY,EAAE,MAAM,WAAW,aAAa,uCAAuC,UAAU,MAAM;AAAA,EACrG;AACF,CAAC;AAUD,IAAM,SAAiC;AAAA,EACrC,SAAS;AAAA,EACT,eAAe;AAAA,EACf,KAAK;AAAA,EACL,aAAa;AAAA,EACb,mBAAmB;AACrB;AAEO,IAAM,yBAAyB,cAAc;AAAA,EAClD,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMf;AAAA,EACA,MAAM;AAAA,IACJ,QAAQ,EAAE,MAAM,cAAc,aAAa,4BAA4B,UAAU,KAAK;AAAA,IACtF,UAAU,EAAE,MAAM,UAAU,aAAa,+CAA+C,UAAU,MAAM;AAAA,IACxG,UAAU,EAAE,MAAM,UAAU,aAAa,uCAAuC,UAAU,MAAM;AAAA,IAChG,MAAM,EAAE,MAAM,UAAU,aAAa,yCAAyC,UAAU,MAAM;AAAA,IAC9F,MAAM,EAAE,MAAM,UAAU,aAAa,6CAA6C,UAAU,MAAM;AAAA,IAClG,OAAO,EAAE,MAAM,UAAU,aAAa,wCAAwC,UAAU,MAAM;AAAA,IAC9F,QAAQ,EAAE,MAAM,UAAU,aAAa,6BAA6B,UAAU,OAAO,SAAS,OAAO;AAAA,IACrG,YAAY,EAAE,MAAM,WAAW,aAAa,uCAAuC,UAAU,MAAM;AAAA,EACrG;AAAA,EACA,KAAK,OAAO,EAAE,KAAK,MAAM;AACvB,UAAM,SAAS,KAAK;AACpB,UAAM,WAAY,KAAK,YAAuB;AAC9C,UAAM,WAAY,KAAK,YAAuB;AAC9C,UAAM,OAAQ,KAAK,QAAmB;AACtC,UAAM,OAAQ,KAAK,QAAmB;AACtC,UAAM,QAAQ,KAAK,QAAQ,OAAO,KAAK,KAAK,IAAI;AAChD,UAAM,YAAY,KAAK,UAAU,IAAI,OAAO;AAC5C,UAAM,eAAe,0BAA0B,UAAU,QAAQ;AAEjE,QAAI;AACF,YAAM,OAAO,MAAM,QAA0B,mCAAmC;AAAA,QAC9E;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAED,mBAAa,YAAY;AACzB,YAAM,SAAU,KAAK,UAAqB;AAC1C,YAAM,QAAQ,qBAAqB,KAAK,QAAQ,cAAc,IAAI;AAClE,UAAI,WAAW,QAAQ;AACrB,4BAAoB,MAAmD,MAAM;AAC7E,2BAAmB,OAAO,MAAM;AAChC;AAAA,MACF;AACA,wBAAkB;AAAA,QAChB,IAAI;AAAA,QACJ;AAAA,QACA,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,eAAe;AAAA,QACf;AAAA,MACF,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,0BAAoB,GAAG;AAAA,IACzB;AAAA,EACF;AACF,CAAC;","names":[]}
@@ -16,8 +16,8 @@ Subcommands:
16
16
  baker landing export start \u2014 download the PUBLISHED landings as a ZIP of plain HTML ("download my landings", "send me the HTML"); \`baker landing export status <id>\` gives the link.`
17
17
  },
18
18
  subCommands: {
19
- inspiration: () => import("./inspiration-P265QJ2H.js").then((m) => m.inspirationCommand),
20
- critique: () => import("./critique-ZS4ON3SU.js").then((m) => m.critiqueCommand),
19
+ inspiration: () => import("./inspiration-S3DU4CMQ.js").then((m) => m.inspirationCommand),
20
+ critique: () => import("./critique-TPHR27KH.js").then((m) => m.critiqueCommand),
21
21
  variant: () => import("./variant-FLZJYGYL.js").then((m) => m.variantCommand),
22
22
  export: () => import("./export-JQRMBJ7D.js").then((m) => m.exportCommand)
23
23
  }
@@ -25,4 +25,4 @@ Subcommands:
25
25
  export {
26
26
  landingCommand
27
27
  };
28
- //# sourceMappingURL=landing-CJYGWCK4.js.map
28
+ //# sourceMappingURL=landing-2ZB46LXH.js.map
@@ -2,7 +2,7 @@ import {
2
2
  csvOrJson,
3
3
  handleLinkedinError,
4
4
  resolveAccountIdArg
5
- } from "./chunk-CSYSX4D2.js";
5
+ } from "./chunk-N4LAYIIN.js";
6
6
  import {
7
7
  writeAdsJson,
8
8
  writeAdsOutput
@@ -10,10 +10,11 @@ import {
10
10
  import {
11
11
  NO_CACHE_ARG
12
12
  } from "./chunk-X7ZODEXJ.js";
13
- import "./chunk-XF4JUKVF.js";
13
+ import "./chunk-7EPXVICM.js";
14
14
  import "./chunk-GXDLWBOY.js";
15
15
  import "./chunk-TEINLN64.js";
16
16
  import "./chunk-ZJWUBJYQ.js";
17
+ import "./chunk-HR6IWNKE.js";
17
18
  import "./chunk-NE4F3FHN.js";
18
19
  import {
19
20
  apiGet
@@ -87,4 +88,4 @@ Examples:
87
88
  export {
88
89
  leadsCommand
89
90
  };
90
- //# sourceMappingURL=leads-PHKG6CP3.js.map
91
+ //# sourceMappingURL=leads-A4W5KTWB.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/ads/linkedin/leads.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { NO_CACHE_ARG } from \"../../../cache-flag.ts\";\nimport { apiGet } from \"../../../client.ts\";\nimport { writeAdsJson, writeAdsOutput } from \"../output.ts\";\nimport { csvOrJson, handleLinkedinError, resolveAccountIdArg } from \"./shared.ts\";\n\ninterface LeadResponseRow {\n id: string;\n formId: string;\n formUrn: string;\n campaignUrn?: string;\n submittedAt?: number;\n answers?: Array<{ questionId: string; question: string; answer: string }>;\n consentResponses?: Array<{ consentId: string; consentText?: string; agreed?: boolean }>;\n}\n\nconst DAY_MS = 86_400_000;\n\nexport const leadsCommand = defineCommand({\n meta: {\n name: \"leads\",\n description: `List Lead Gen Form responses (playbook §07).\n\nLinkedIn retains LGF responses for 90 days only — sync to your CRM via this\nendpoint or you'll lose them.\n\nExamples:\n baker ads linkedin leads --account-id 503001492\n baker ads linkedin leads --account-id 503001492 --campaign-id 1234\n baker ads linkedin leads --account-id 503001492 --form-id 5678 --since-days 7\n baker ads linkedin leads --account-id 503001492 --output csv`,\n },\n args: {\n \"account-id\": { type: \"string\", description: \"Numeric account ID or urn:li:sponsoredAccount:N\" },\n \"account-urn\": { type: \"string\", description: \"Alias for --account-id\" },\n \"form-id\": { type: \"string\", description: \"Filter by Lead Gen Form ID\" },\n \"campaign-id\": { type: \"string\", description: \"Filter by campaign ID\" },\n \"since-days\": { type: \"string\", description: \"Only responses submitted in the last N days\" },\n \"since-ms\": {\n type: \"string\",\n description: \"Only responses submitted at or after this epoch ms (alternative to --since-days)\",\n },\n limit: { type: \"string\", description: \"Max rows (default: 500)\" },\n \"no-cache\": NO_CACHE_ARG,\n output: { type: \"string\", description: \"json|csv|jsonl|md\", default: \"json\" },\n },\n run: async ({ args }) => {\n const accountId = resolveAccountIdArg(args);\n try {\n const params: Record<string, string> = { \"account-id\": accountId };\n if (args[\"form-id\"]) params[\"form-id\"] = String(args[\"form-id\"]);\n if (args[\"campaign-id\"]) params[\"campaign-id\"] = String(args[\"campaign-id\"]);\n const sinceDays = args[\"since-days\"] ? Number(args[\"since-days\"]) : undefined;\n const sinceMs = args[\"since-ms\"]\n ? Number(args[\"since-ms\"])\n : sinceDays\n ? Date.now() - sinceDays * DAY_MS\n : undefined;\n if (sinceMs) params[\"since-ms\"] = String(sinceMs);\n if (args.limit) params.limit = String(args.limit);\n if (args[\"no-cache\"]) params[\"skip-cache\"] = \"true\";\n\n const data = await apiGet<LeadResponseRow[]>(\"/api/ads/linkedin/leads\", params);\n const fmt = csvOrJson(args);\n if (fmt !== \"json\") {\n // Flatten the answers array for CSV/MD output.\n const flat = data.map((r) => ({\n id: r.id,\n formId: r.formId,\n campaignUrn: r.campaignUrn,\n submittedAt: r.submittedAt ? new Date(r.submittedAt).toISOString() : \"\",\n answers: (r.answers ?? []).map((a) => `${a.question}: ${a.answer}`).join(\" | \"),\n }));\n writeAdsOutput(flat as unknown as Array<Record<string, unknown>>, fmt);\n return;\n }\n writeAdsJson({ ok: true, data });\n } catch (err) {\n handleLinkedinError(err);\n }\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,qBAAqB;AAgB9B,IAAM,SAAS;AAER,IAAM,eAAe,cAAc;AAAA,EACxC,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUf;AAAA,EACA,MAAM;AAAA,IACJ,cAAc,EAAE,MAAM,UAAU,aAAa,kDAAkD;AAAA,IAC/F,eAAe,EAAE,MAAM,UAAU,aAAa,yBAAyB;AAAA,IACvE,WAAW,EAAE,MAAM,UAAU,aAAa,6BAA6B;AAAA,IACvE,eAAe,EAAE,MAAM,UAAU,aAAa,wBAAwB;AAAA,IACtE,cAAc,EAAE,MAAM,UAAU,aAAa,8CAA8C;AAAA,IAC3F,YAAY;AAAA,MACV,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,IACA,OAAO,EAAE,MAAM,UAAU,aAAa,0BAA0B;AAAA,IAChE,YAAY;AAAA,IACZ,QAAQ,EAAE,MAAM,UAAU,aAAa,qBAAqB,SAAS,OAAO;AAAA,EAC9E;AAAA,EACA,KAAK,OAAO,EAAE,KAAK,MAAM;AACvB,UAAM,YAAY,oBAAoB,IAAI;AAC1C,QAAI;AACF,YAAM,SAAiC,EAAE,cAAc,UAAU;AACjE,UAAI,KAAK,SAAS,EAAG,QAAO,SAAS,IAAI,OAAO,KAAK,SAAS,CAAC;AAC/D,UAAI,KAAK,aAAa,EAAG,QAAO,aAAa,IAAI,OAAO,KAAK,aAAa,CAAC;AAC3E,YAAM,YAAY,KAAK,YAAY,IAAI,OAAO,KAAK,YAAY,CAAC,IAAI;AACpE,YAAM,UAAU,KAAK,UAAU,IAC3B,OAAO,KAAK,UAAU,CAAC,IACvB,YACE,KAAK,IAAI,IAAI,YAAY,SACzB;AACN,UAAI,QAAS,QAAO,UAAU,IAAI,OAAO,OAAO;AAChD,UAAI,KAAK,MAAO,QAAO,QAAQ,OAAO,KAAK,KAAK;AAChD,UAAI,KAAK,UAAU,EAAG,QAAO,YAAY,IAAI;AAE7C,YAAM,OAAO,MAAM,OAA0B,2BAA2B,MAAM;AAC9E,YAAM,MAAM,UAAU,IAAI;AAC1B,UAAI,QAAQ,QAAQ;AAElB,cAAM,OAAO,KAAK,IAAI,CAAC,OAAO;AAAA,UAC5B,IAAI,EAAE;AAAA,UACN,QAAQ,EAAE;AAAA,UACV,aAAa,EAAE;AAAA,UACf,aAAa,EAAE,cAAc,IAAI,KAAK,EAAE,WAAW,EAAE,YAAY,IAAI;AAAA,UACrE,UAAU,EAAE,WAAW,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,EAAE,QAAQ,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,KAAK;AAAA,QAChF,EAAE;AACF,uBAAe,MAAmD,GAAG;AACrE;AAAA,MACF;AACA,mBAAa,EAAE,IAAI,MAAM,KAAK,CAAC;AAAA,IACjC,SAAS,KAAK;AACZ,0BAAoB,GAAG;AAAA,IACzB;AAAA,EACF;AACF,CAAC;","names":[]}
1
+ {"version":3,"sources":["../src/commands/ads/linkedin/leads.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { NO_CACHE_ARG } from \"../../../cache-flag.ts\";\nimport { apiGet } from \"../../../client.ts\";\nimport { writeAdsJson, writeAdsOutput } from \"../output.ts\";\nimport { csvOrJson, handleLinkedinError, resolveAccountIdArg } from \"./shared.ts\";\n\ninterface LeadResponseRow {\n id: string;\n formId: string;\n formUrn: string;\n campaignUrn?: string;\n submittedAt?: number;\n answers?: Array<{ questionId: string; question: string; answer: string }>;\n consentResponses?: Array<{ consentId: string; consentText?: string; agreed?: boolean }>;\n}\n\nconst DAY_MS = 86_400_000;\n\nexport const leadsCommand = defineCommand({\n meta: {\n name: \"leads\",\n description: `List Lead Gen Form responses (playbook §07).\n\nLinkedIn retains LGF responses for 90 days only — sync to your CRM via this\nendpoint or you'll lose them.\n\nExamples:\n baker ads linkedin leads --account-id 503001492\n baker ads linkedin leads --account-id 503001492 --campaign-id 1234\n baker ads linkedin leads --account-id 503001492 --form-id 5678 --since-days 7\n baker ads linkedin leads --account-id 503001492 --output csv`,\n },\n args: {\n \"account-id\": { type: \"string\", description: \"Numeric account ID or urn:li:sponsoredAccount:N\" },\n \"account-urn\": { type: \"string\", description: \"Alias for --account-id\" },\n \"form-id\": { type: \"string\", description: \"Filter by Lead Gen Form ID\" },\n \"campaign-id\": { type: \"string\", description: \"Filter by campaign ID\" },\n \"since-days\": { type: \"string\", description: \"Only responses submitted in the last N days\" },\n \"since-ms\": {\n type: \"string\",\n description: \"Only responses submitted at or after this epoch ms (alternative to --since-days)\",\n },\n limit: { type: \"string\", description: \"Max rows (default: 500)\" },\n \"no-cache\": NO_CACHE_ARG,\n output: { type: \"string\", description: \"json|csv|jsonl|md\", default: \"json\" },\n },\n run: async ({ args }) => {\n const accountId = resolveAccountIdArg(args);\n try {\n const params: Record<string, string> = { \"account-id\": accountId };\n if (args[\"form-id\"]) params[\"form-id\"] = String(args[\"form-id\"]);\n if (args[\"campaign-id\"]) params[\"campaign-id\"] = String(args[\"campaign-id\"]);\n const sinceDays = args[\"since-days\"] ? Number(args[\"since-days\"]) : undefined;\n const sinceMs = args[\"since-ms\"]\n ? Number(args[\"since-ms\"])\n : sinceDays\n ? Date.now() - sinceDays * DAY_MS\n : undefined;\n if (sinceMs) params[\"since-ms\"] = String(sinceMs);\n if (args.limit) params.limit = String(args.limit);\n if (args[\"no-cache\"]) params[\"skip-cache\"] = \"true\";\n\n const data = await apiGet<LeadResponseRow[]>(\"/api/ads/linkedin/leads\", params);\n const fmt = csvOrJson(args);\n if (fmt !== \"json\") {\n // Flatten the answers array for CSV/MD output.\n const flat = data.map((r) => ({\n id: r.id,\n formId: r.formId,\n campaignUrn: r.campaignUrn,\n submittedAt: r.submittedAt ? new Date(r.submittedAt).toISOString() : \"\",\n answers: (r.answers ?? []).map((a) => `${a.question}: ${a.answer}`).join(\" | \"),\n }));\n writeAdsOutput(flat as unknown as Array<Record<string, unknown>>, fmt);\n return;\n }\n writeAdsJson({ ok: true, data });\n } catch (err) {\n handleLinkedinError(err);\n }\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,qBAAqB;AAgB9B,IAAM,SAAS;AAER,IAAM,eAAe,cAAc;AAAA,EACxC,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUf;AAAA,EACA,MAAM;AAAA,IACJ,cAAc,EAAE,MAAM,UAAU,aAAa,kDAAkD;AAAA,IAC/F,eAAe,EAAE,MAAM,UAAU,aAAa,yBAAyB;AAAA,IACvE,WAAW,EAAE,MAAM,UAAU,aAAa,6BAA6B;AAAA,IACvE,eAAe,EAAE,MAAM,UAAU,aAAa,wBAAwB;AAAA,IACtE,cAAc,EAAE,MAAM,UAAU,aAAa,8CAA8C;AAAA,IAC3F,YAAY;AAAA,MACV,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,IACA,OAAO,EAAE,MAAM,UAAU,aAAa,0BAA0B;AAAA,IAChE,YAAY;AAAA,IACZ,QAAQ,EAAE,MAAM,UAAU,aAAa,qBAAqB,SAAS,OAAO;AAAA,EAC9E;AAAA,EACA,KAAK,OAAO,EAAE,KAAK,MAAM;AACvB,UAAM,YAAY,oBAAoB,IAAI;AAC1C,QAAI;AACF,YAAM,SAAiC,EAAE,cAAc,UAAU;AACjE,UAAI,KAAK,SAAS,EAAG,QAAO,SAAS,IAAI,OAAO,KAAK,SAAS,CAAC;AAC/D,UAAI,KAAK,aAAa,EAAG,QAAO,aAAa,IAAI,OAAO,KAAK,aAAa,CAAC;AAC3E,YAAM,YAAY,KAAK,YAAY,IAAI,OAAO,KAAK,YAAY,CAAC,IAAI;AACpE,YAAM,UAAU,KAAK,UAAU,IAC3B,OAAO,KAAK,UAAU,CAAC,IACvB,YACE,KAAK,IAAI,IAAI,YAAY,SACzB;AACN,UAAI,QAAS,QAAO,UAAU,IAAI,OAAO,OAAO;AAChD,UAAI,KAAK,MAAO,QAAO,QAAQ,OAAO,KAAK,KAAK;AAChD,UAAI,KAAK,UAAU,EAAG,QAAO,YAAY,IAAI;AAE7C,YAAM,OAAO,MAAM,OAA0B,2BAA2B,MAAM;AAC9E,YAAM,MAAM,UAAU,IAAI;AAC1B,UAAI,QAAQ,QAAQ;AAElB,cAAM,OAAO,KAAK,IAAI,CAAC,OAAO;AAAA,UAC5B,IAAI,EAAE;AAAA,UACN,QAAQ,EAAE;AAAA,UACV,aAAa,EAAE;AAAA,UACf,aAAa,EAAE,cAAc,IAAI,KAAK,EAAE,WAAW,EAAE,YAAY,IAAI;AAAA,UACrE,UAAU,EAAE,WAAW,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,EAAE,QAAQ,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,KAAK;AAAA,QAChF,EAAE;AACF,uBAAe,MAAmD,GAAG;AACrE;AAAA,MACF;AACA,mBAAa,EAAE,IAAI,MAAM,KAAK,CAAC;AAAA,IACjC,SAAS,KAAK;AACZ,0BAAoB,GAAG;AAAA,IACzB;AAAA,EACF;AACF,CAAC;","names":[]}
@@ -8,7 +8,7 @@ import {
8
8
  import {
9
9
  parseDays,
10
10
  withDefinitions
11
- } from "./chunk-5ZDLTE5T.js";
11
+ } from "./chunk-2AOE2MZQ.js";
12
12
  import "./chunk-F2S5BLPE.js";
13
13
  import "./chunk-WTOYCUKH.js";
14
14
  import {
@@ -22,11 +22,12 @@ import "./chunk-VVZBBKRC.js";
22
22
  import "./chunk-YBMVHGY3.js";
23
23
  import {
24
24
  failApi
25
- } from "./chunk-3HJLHTWP.js";
26
- import "./chunk-XF4JUKVF.js";
25
+ } from "./chunk-SJYEY5MV.js";
26
+ import "./chunk-7EPXVICM.js";
27
27
  import "./chunk-GXDLWBOY.js";
28
28
  import "./chunk-TEINLN64.js";
29
29
  import "./chunk-ZJWUBJYQ.js";
30
+ import "./chunk-HR6IWNKE.js";
30
31
  import "./chunk-NE4F3FHN.js";
31
32
  import {
32
33
  apiPost
@@ -200,4 +201,4 @@ export {
200
201
  learnCommand,
201
202
  learnEnvelope
202
203
  };
203
- //# sourceMappingURL=learn-FUQSY7DN.js.map
204
+ //# sourceMappingURL=learn-IPULBCOD.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/creatives/learn.ts","../src/commands/creatives/learn-model.ts"],"sourcesContent":["/**\n * `baker creatives learn`: what the ads each idea became did in the live account, written back\n * onto the idea (its `status` and a frozen `result`), so the next chat builds on winners and\n * never repeats a message that lost.\n */\nimport { readFileSync } from \"node:fs\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { CreativesPerformanceResponse } from \"@baker/api\";\nimport { defineCommand } from \"citty\";\nimport { apiPost } from \"../../client.ts\";\nimport { writeJson } from \"../../output.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport { failApi } from \"../actions/shared.ts\";\nimport { findWorkspaceRoot } from \"../canvas/normalize-paths.ts\";\nimport { IDEAS_DIR, readIdeas } from \"./ideas-workspace.ts\";\nimport { type IdeaLearning, learnFromResults } from \"./learn-model.ts\";\nimport { setDefinitionFields } from \"./make-model.ts\";\nimport { parseDays, withDefinitions } from \"./performance.ts\";\n\nconst DESCRIPTION = `Write back what each built idea's ads did in the live Meta account: every creative of the idea pooled, judged against the rest of the account's cost per result, and the verdict (winner, failed, inconclusive, testing) and frozen numbers written onto src/creatives/_ideas/<idea>.md. Run it before writing new ideas, and weekly.\n\nStart here:\n baker creatives learn # last 30 days, written onto the ideas\n baker creatives learn --days 60\n baker creatives learn --dry-run # show the verdicts, write nothing\n\nA winner gets results at 0.8x the usual cost or less (3+ results); failed is 1.5x or more, or spend worth two usual results with none; under 1,000 impressions it is still testing.`;\n\nconst ARGS = {\n days: { type: \"string\", required: false, description: \"Reporting window in days (default 30)\" },\n \"dry-run\": { type: \"boolean\", required: false, default: false, description: \"Show the verdicts; write nothing\" },\n} as const;\n\nregisterSchema({ command: \"creatives.learn\", description: DESCRIPTION, args: ARGS });\n\n/** What the agent reads, and what to do with winners and losers. Pure. */\nexport function learnEnvelope(\n learnings: readonly IdeaLearning[],\n written: boolean,\n unreadable: readonly string[] = [],\n) {\n const winners = learnings.filter((l) => l.to === \"winner\").map((l) => l.idea);\n const failed = learnings.filter((l) => l.to === \"failed\").map((l) => l.idea);\n const hints: string[] = [];\n if (unreadable.length > 0) {\n hints.push(\n `Could not read ${unreadable.join(\", \")}, so their results were not written: fix what \\`baker creatives ideas\\` names, then run this again.`,\n );\n }\n if (learnings.length === 0) {\n hints.push(\n \"No built idea has ads delivering yet: nothing to learn. Ideas count once a published ad shows their creative.\",\n );\n }\n if (winners.length > 0) {\n hints.push(\n `Build on ${winners.join(\", \")}: keep the message and make it in a new format or for a new persona before any new idea.`,\n );\n }\n if (failed.length > 0) {\n hints.push(\n `${failed.join(\", \")} lost: never repeat their message; \\`baker creatives ideas\\` flags an idea that does.`,\n );\n }\n return {\n ok: true as const,\n data: {\n written,\n ideas: learnings.map((l) => ({\n idea: l.idea,\n status: l.from === l.to ? l.to : `${l.from} → ${l.to}`,\n ...l.result,\n })),\n },\n hints,\n };\n}\n\nasync function writeBack(root: string, learnings: readonly IdeaLearning[]): Promise<void> {\n for (const learning of learnings) {\n const file = path.join(root, IDEAS_DIR, `${learning.idea}.md`);\n const raw = await readFile(file, \"utf8\");\n await writeFile(file, setDefinitionFields(raw, { status: learning.to, result: learning.result }), \"utf8\");\n }\n}\n\nfunction readDefinition(root: string, slug: string): string | null {\n try {\n return readFileSync(path.join(root, \"src\", \"creatives\", slug, \"_definition.md\"), \"utf8\");\n } catch {\n return null;\n }\n}\n\nfunction today(): string {\n return new Date().toISOString().slice(0, 10);\n}\n\nexport const learnCommand = defineCommand({\n meta: { name: \"learn\", description: DESCRIPTION },\n args: ARGS,\n async run({ args }) {\n try {\n const root = findWorkspaceRoot(process.cwd()) ?? process.cwd();\n const days = parseDays(args.days as string | undefined);\n const performance = withDefinitions(\n await apiPost<CreativesPerformanceResponse>(\"/api/creatives/performance\", days ? { days } : {}),\n (slug) => readDefinition(root, slug),\n );\n const { ideas, unreadable } = await readIdeas(root);\n const learnings = learnFromResults(ideas, performance.data.creatives, today());\n const dryRun = args[\"dry-run\"] === true;\n if (!dryRun) await writeBack(root, learnings);\n writeJson(\n learnEnvelope(\n learnings,\n !dryRun && learnings.length > 0,\n unreadable.map((u) => u.id),\n ),\n );\n } catch (err) {\n failApi(err);\n }\n },\n});\n","/**\n * What the ads an idea became did, written back onto the idea: `baker creatives learn` turns\n * performance into a verdict per idea, so the next chat starts from what won and what lost\n * instead of from zero. Pure.\n */\nimport type { CreativePerformance } from \"@baker/api\";\nimport type { Idea, IdeaStatus } from \"./ideas-model.ts\";\n\n/** Below this many impressions an idea has not been seen enough to call. */\nconst MIN_IMPRESSIONS = 1000;\n/** Seen this much with no clear verdict, an idea is inconclusive rather than still testing. */\nconst SEEN_ENOUGH = 5000;\n/** At or under this share of the account's usual cost per result, with enough results: a winner. */\nconst WINNER_RATIO = 0.8;\nconst WINNER_MIN_RESULTS = 3;\n/** At or over this share of the usual cost per result: failed. */\nconst FAILED_RATIO = 1.5;\n/** Spending this many usual results' worth with none: failed. */\nconst SILENT_SPEND = 2;\n/** Verdicts a thin window never takes back: too little delivery says nothing new about them. */\nconst SETTLED: ReadonlySet<IdeaStatus> = new Set([\"winner\", \"failed\", \"inconclusive\"]);\n\nexport type IdeaResult = {\n asOf: string;\n creatives: number;\n currency?: string;\n spend: number;\n impressions: number;\n results: number;\n costPerResult: number | null;\n ctr: number | null;\n /** Cost per result over the rest of the account's: 0.5 is half the usual cost. */\n vsAccount: number | null;\n};\n\nexport type IdeaLearning = { idea: string; from: IdeaStatus; to: IdeaStatus; result: IdeaResult };\n\nconst round = (n: number) => Math.round(n * 100) / 100;\n\nfunction totals(creatives: readonly CreativePerformance[]) {\n const spend = creatives.reduce((sum, c) => sum + c.spend, 0);\n const impressions = creatives.reduce((sum, c) => sum + c.impressions, 0);\n const results = creatives.reduce((sum, c) => sum + (c.results ?? 0), 0);\n const clicks = creatives.reduce((sum, c) => sum + (c.ctr ?? 0) * c.impressions, 0);\n return { spend, impressions, results, ctr: impressions > 0 ? round(clicks / impressions) : null };\n}\n\nfunction verdict(result: IdeaResult, usual: number | null): IdeaStatus {\n if (result.impressions < MIN_IMPRESSIONS) return \"testing\";\n if (usual !== null) {\n if (result.results === 0 && result.spend >= SILENT_SPEND * usual) return \"failed\";\n const ratio = result.vsAccount;\n if (ratio !== null && result.results >= WINNER_MIN_RESULTS && ratio <= WINNER_RATIO) return \"winner\";\n if (ratio !== null && ratio >= FAILED_RATIO) return \"failed\";\n }\n return result.impressions >= SEEN_ENOUGH ? \"inconclusive\" : \"testing\";\n}\n\n/** One idea's ads pooled into the numbers frozen on it, against the account's usual cost per result. */\nfunction ideaResult(own: readonly CreativePerformance[], usual: number | null, asOf: string): IdeaResult {\n const mine = totals(own);\n const costPerResult = mine.results > 0 ? round(mine.spend / mine.results) : null;\n return {\n asOf,\n creatives: own.length,\n ...(own[0]?.currency ? { currency: own[0].currency } : {}),\n spend: round(mine.spend),\n impressions: mine.impressions,\n results: mine.results,\n costPerResult,\n ctr: mine.ctr,\n vsAccount: usual !== null && costPerResult !== null ? round(costPerResult / usual) : null,\n };\n}\n\n/**\n * Each built idea's ads, pooled and judged against the rest of the account: cheaper results than\n * usual win, far dearer ones (or spend with none) fail. Ideas still to build, retired, with no\n * ad delivering, or already judged and seen too little since, are left alone.\n */\nexport function learnFromResults(\n ideas: readonly Idea[],\n creatives: readonly CreativePerformance[],\n asOf: string,\n): IdeaLearning[] {\n const ideaOf = (c: CreativePerformance) => c.definition?.idea ?? null;\n return ideas.flatMap((idea): IdeaLearning[] => {\n if (idea.status === \"idea\" || idea.status === \"retired\") return [];\n const own = creatives.filter((c) => ideaOf(c) === idea.id);\n if (own.length === 0) return [];\n const rest = totals(creatives.filter((c) => ideaOf(c) !== idea.id));\n const usual = rest.results > 0 ? rest.spend / rest.results : null;\n const result = ideaResult(own, usual, asOf);\n const to = verdict(result, usual);\n if (to === \"testing\" && SETTLED.has(idea.status)) return [];\n return [{ idea: idea.id, from: idea.status, to, result }];\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKA,SAAS,oBAAoB;AAC7B,SAAS,UAAU,iBAAiB;AACpC,OAAO,UAAU;AAEjB,SAAS,qBAAqB;;;ACA9B,IAAM,kBAAkB;AAExB,IAAM,cAAc;AAEpB,IAAM,eAAe;AACrB,IAAM,qBAAqB;AAE3B,IAAM,eAAe;AAErB,IAAM,eAAe;AAErB,IAAM,UAAmC,oBAAI,IAAI,CAAC,UAAU,UAAU,cAAc,CAAC;AAiBrF,IAAM,QAAQ,CAAC,MAAc,KAAK,MAAM,IAAI,GAAG,IAAI;AAEnD,SAAS,OAAO,WAA2C;AACzD,QAAM,QAAQ,UAAU,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,OAAO,CAAC;AAC3D,QAAM,cAAc,UAAU,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,aAAa,CAAC;AACvE,QAAM,UAAU,UAAU,OAAO,CAAC,KAAK,MAAM,OAAO,EAAE,WAAW,IAAI,CAAC;AACtE,QAAM,SAAS,UAAU,OAAO,CAAC,KAAK,MAAM,OAAO,EAAE,OAAO,KAAK,EAAE,aAAa,CAAC;AACjF,SAAO,EAAE,OAAO,aAAa,SAAS,KAAK,cAAc,IAAI,MAAM,SAAS,WAAW,IAAI,KAAK;AAClG;AAEA,SAAS,QAAQ,QAAoB,OAAkC;AACrE,MAAI,OAAO,cAAc,gBAAiB,QAAO;AACjD,MAAI,UAAU,MAAM;AAClB,QAAI,OAAO,YAAY,KAAK,OAAO,SAAS,eAAe,MAAO,QAAO;AACzE,UAAM,QAAQ,OAAO;AACrB,QAAI,UAAU,QAAQ,OAAO,WAAW,sBAAsB,SAAS,aAAc,QAAO;AAC5F,QAAI,UAAU,QAAQ,SAAS,aAAc,QAAO;AAAA,EACtD;AACA,SAAO,OAAO,eAAe,cAAc,iBAAiB;AAC9D;AAGA,SAAS,WAAW,KAAqC,OAAsB,MAA0B;AACvG,QAAM,OAAO,OAAO,GAAG;AACvB,QAAM,gBAAgB,KAAK,UAAU,IAAI,MAAM,KAAK,QAAQ,KAAK,OAAO,IAAI;AAC5E,SAAO;AAAA,IACL;AAAA,IACA,WAAW,IAAI;AAAA,IACf,GAAI,IAAI,CAAC,GAAG,WAAW,EAAE,UAAU,IAAI,CAAC,EAAE,SAAS,IAAI,CAAC;AAAA,IACxD,OAAO,MAAM,KAAK,KAAK;AAAA,IACvB,aAAa,KAAK;AAAA,IAClB,SAAS,KAAK;AAAA,IACd;AAAA,IACA,KAAK,KAAK;AAAA,IACV,WAAW,UAAU,QAAQ,kBAAkB,OAAO,MAAM,gBAAgB,KAAK,IAAI;AAAA,EACvF;AACF;AAOO,SAAS,iBACd,OACA,WACA,MACgB;AAChB,QAAM,SAAS,CAAC,MAA2B,EAAE,YAAY,QAAQ;AACjE,SAAO,MAAM,QAAQ,CAAC,SAAyB;AAC7C,QAAI,KAAK,WAAW,UAAU,KAAK,WAAW,UAAW,QAAO,CAAC;AACjE,UAAM,MAAM,UAAU,OAAO,CAAC,MAAM,OAAO,CAAC,MAAM,KAAK,EAAE;AACzD,QAAI,IAAI,WAAW,EAAG,QAAO,CAAC;AAC9B,UAAM,OAAO,OAAO,UAAU,OAAO,CAAC,MAAM,OAAO,CAAC,MAAM,KAAK,EAAE,CAAC;AAClE,UAAM,QAAQ,KAAK,UAAU,IAAI,KAAK,QAAQ,KAAK,UAAU;AAC7D,UAAM,SAAS,WAAW,KAAK,OAAO,IAAI;AAC1C,UAAM,KAAK,QAAQ,QAAQ,KAAK;AAChC,QAAI,OAAO,aAAa,QAAQ,IAAI,KAAK,MAAM,EAAG,QAAO,CAAC;AAC1D,WAAO,CAAC,EAAE,MAAM,KAAK,IAAI,MAAM,KAAK,QAAQ,IAAI,OAAO,CAAC;AAAA,EAC1D,CAAC;AACH;;;AD7EA,IAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASpB,IAAM,OAAO;AAAA,EACX,MAAM,EAAE,MAAM,UAAU,UAAU,OAAO,aAAa,wCAAwC;AAAA,EAC9F,WAAW,EAAE,MAAM,WAAW,UAAU,OAAO,SAAS,OAAO,aAAa,mCAAmC;AACjH;AAEA,eAAe,EAAE,SAAS,mBAAmB,aAAa,aAAa,MAAM,KAAK,CAAC;AAG5E,SAAS,cACd,WACA,SACA,aAAgC,CAAC,GACjC;AACA,QAAM,UAAU,UAAU,OAAO,CAAC,MAAM,EAAE,OAAO,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI;AAC5E,QAAM,SAAS,UAAU,OAAO,CAAC,MAAM,EAAE,OAAO,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI;AAC3E,QAAM,QAAkB,CAAC;AACzB,MAAI,WAAW,SAAS,GAAG;AACzB,UAAM;AAAA,MACJ,kBAAkB,WAAW,KAAK,IAAI,CAAC;AAAA,IACzC;AAAA,EACF;AACA,MAAI,UAAU,WAAW,GAAG;AAC1B,UAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACA,MAAI,QAAQ,SAAS,GAAG;AACtB,UAAM;AAAA,MACJ,YAAY,QAAQ,KAAK,IAAI,CAAC;AAAA,IAChC;AAAA,EACF;AACA,MAAI,OAAO,SAAS,GAAG;AACrB,UAAM;AAAA,MACJ,GAAG,OAAO,KAAK,IAAI,CAAC;AAAA,IACtB;AAAA,EACF;AACA,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,MAAM;AAAA,MACJ;AAAA,MACA,OAAO,UAAU,IAAI,CAAC,OAAO;AAAA,QAC3B,MAAM,EAAE;AAAA,QACR,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,EAAE,IAAI,WAAM,EAAE,EAAE;AAAA,QACpD,GAAG,EAAE;AAAA,MACP,EAAE;AAAA,IACJ;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAe,UAAU,MAAc,WAAmD;AACxF,aAAW,YAAY,WAAW;AAChC,UAAM,OAAO,KAAK,KAAK,MAAM,WAAW,GAAG,SAAS,IAAI,KAAK;AAC7D,UAAM,MAAM,MAAM,SAAS,MAAM,MAAM;AACvC,UAAM,UAAU,MAAM,oBAAoB,KAAK,EAAE,QAAQ,SAAS,IAAI,QAAQ,SAAS,OAAO,CAAC,GAAG,MAAM;AAAA,EAC1G;AACF;AAEA,SAAS,eAAe,MAAc,MAA6B;AACjE,MAAI;AACF,WAAO,aAAa,KAAK,KAAK,MAAM,OAAO,aAAa,MAAM,gBAAgB,GAAG,MAAM;AAAA,EACzF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,QAAgB;AACvB,UAAO,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AAC7C;AAEO,IAAM,eAAe,cAAc;AAAA,EACxC,MAAM,EAAE,MAAM,SAAS,aAAa,YAAY;AAAA,EAChD,MAAM;AAAA,EACN,MAAM,IAAI,EAAE,KAAK,GAAG;AAClB,QAAI;AACF,YAAM,OAAO,kBAAkB,QAAQ,IAAI,CAAC,KAAK,QAAQ,IAAI;AAC7D,YAAM,OAAO,UAAU,KAAK,IAA0B;AACtD,YAAM,cAAc;AAAA,QAClB,MAAM,QAAsC,8BAA8B,OAAO,EAAE,KAAK,IAAI,CAAC,CAAC;AAAA,QAC9F,CAAC,SAAS,eAAe,MAAM,IAAI;AAAA,MACrC;AACA,YAAM,EAAE,OAAO,WAAW,IAAI,MAAM,UAAU,IAAI;AAClD,YAAM,YAAY,iBAAiB,OAAO,YAAY,KAAK,WAAW,MAAM,CAAC;AAC7E,YAAM,SAAS,KAAK,SAAS,MAAM;AACnC,UAAI,CAAC,OAAQ,OAAM,UAAU,MAAM,SAAS;AAC5C;AAAA,QACE;AAAA,UACE;AAAA,UACA,CAAC,UAAU,UAAU,SAAS;AAAA,UAC9B,WAAW,IAAI,CAAC,MAAM,EAAE,EAAE;AAAA,QAC5B;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,GAAG;AAAA,IACb;AAAA,EACF;AACF,CAAC;","names":[]}
1
+ {"version":3,"sources":["../src/commands/creatives/learn.ts","../src/commands/creatives/learn-model.ts"],"sourcesContent":["/**\n * `baker creatives learn`: what the ads each idea became did in the live account, written back\n * onto the idea (its `status` and a frozen `result`), so the next chat builds on winners and\n * never repeats a message that lost.\n */\nimport { readFileSync } from \"node:fs\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { CreativesPerformanceResponse } from \"@baker/api\";\nimport { defineCommand } from \"citty\";\nimport { apiPost } from \"../../client.ts\";\nimport { writeJson } from \"../../output.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport { failApi } from \"../actions/shared.ts\";\nimport { findWorkspaceRoot } from \"../canvas/normalize-paths.ts\";\nimport { IDEAS_DIR, readIdeas } from \"./ideas-workspace.ts\";\nimport { type IdeaLearning, learnFromResults } from \"./learn-model.ts\";\nimport { setDefinitionFields } from \"./make-model.ts\";\nimport { parseDays, withDefinitions } from \"./performance.ts\";\n\nconst DESCRIPTION = `Write back what each built idea's ads did in the live Meta account: every creative of the idea pooled, judged against the rest of the account's cost per result, and the verdict (winner, failed, inconclusive, testing) and frozen numbers written onto src/creatives/_ideas/<idea>.md. Run it before writing new ideas, and weekly.\n\nStart here:\n baker creatives learn # last 30 days, written onto the ideas\n baker creatives learn --days 60\n baker creatives learn --dry-run # show the verdicts, write nothing\n\nA winner gets results at 0.8x the usual cost or less (3+ results); failed is 1.5x or more, or spend worth two usual results with none; under 1,000 impressions it is still testing.`;\n\nconst ARGS = {\n days: { type: \"string\", required: false, description: \"Reporting window in days (default 30)\" },\n \"dry-run\": { type: \"boolean\", required: false, default: false, description: \"Show the verdicts; write nothing\" },\n} as const;\n\nregisterSchema({ command: \"creatives.learn\", description: DESCRIPTION, args: ARGS });\n\n/** What the agent reads, and what to do with winners and losers. Pure. */\nexport function learnEnvelope(\n learnings: readonly IdeaLearning[],\n written: boolean,\n unreadable: readonly string[] = [],\n) {\n const winners = learnings.filter((l) => l.to === \"winner\").map((l) => l.idea);\n const failed = learnings.filter((l) => l.to === \"failed\").map((l) => l.idea);\n const hints: string[] = [];\n if (unreadable.length > 0) {\n hints.push(\n `Could not read ${unreadable.join(\", \")}, so their results were not written: fix what \\`baker creatives ideas\\` names, then run this again.`,\n );\n }\n if (learnings.length === 0) {\n hints.push(\n \"No built idea has ads delivering yet: nothing to learn. Ideas count once a published ad shows their creative.\",\n );\n }\n if (winners.length > 0) {\n hints.push(\n `Build on ${winners.join(\", \")}: keep the message and make it in a new format or for a new persona before any new idea.`,\n );\n }\n if (failed.length > 0) {\n hints.push(\n `${failed.join(\", \")} lost: never repeat their message; \\`baker creatives ideas\\` flags an idea that does.`,\n );\n }\n return {\n ok: true as const,\n data: {\n written,\n ideas: learnings.map((l) => ({\n idea: l.idea,\n status: l.from === l.to ? l.to : `${l.from} → ${l.to}`,\n ...l.result,\n })),\n },\n hints,\n };\n}\n\nasync function writeBack(root: string, learnings: readonly IdeaLearning[]): Promise<void> {\n for (const learning of learnings) {\n const file = path.join(root, IDEAS_DIR, `${learning.idea}.md`);\n const raw = await readFile(file, \"utf8\");\n await writeFile(file, setDefinitionFields(raw, { status: learning.to, result: learning.result }), \"utf8\");\n }\n}\n\nfunction readDefinition(root: string, slug: string): string | null {\n try {\n return readFileSync(path.join(root, \"src\", \"creatives\", slug, \"_definition.md\"), \"utf8\");\n } catch {\n return null;\n }\n}\n\nfunction today(): string {\n return new Date().toISOString().slice(0, 10);\n}\n\nexport const learnCommand = defineCommand({\n meta: { name: \"learn\", description: DESCRIPTION },\n args: ARGS,\n async run({ args }) {\n try {\n const root = findWorkspaceRoot(process.cwd()) ?? process.cwd();\n const days = parseDays(args.days as string | undefined);\n const performance = withDefinitions(\n await apiPost<CreativesPerformanceResponse>(\"/api/creatives/performance\", days ? { days } : {}),\n (slug) => readDefinition(root, slug),\n );\n const { ideas, unreadable } = await readIdeas(root);\n const learnings = learnFromResults(ideas, performance.data.creatives, today());\n const dryRun = args[\"dry-run\"] === true;\n if (!dryRun) await writeBack(root, learnings);\n writeJson(\n learnEnvelope(\n learnings,\n !dryRun && learnings.length > 0,\n unreadable.map((u) => u.id),\n ),\n );\n } catch (err) {\n failApi(err);\n }\n },\n});\n","/**\n * What the ads an idea became did, written back onto the idea: `baker creatives learn` turns\n * performance into a verdict per idea, so the next chat starts from what won and what lost\n * instead of from zero. Pure.\n */\nimport type { CreativePerformance } from \"@baker/api\";\nimport type { Idea, IdeaStatus } from \"./ideas-model.ts\";\n\n/** Below this many impressions an idea has not been seen enough to call. */\nconst MIN_IMPRESSIONS = 1000;\n/** Seen this much with no clear verdict, an idea is inconclusive rather than still testing. */\nconst SEEN_ENOUGH = 5000;\n/** At or under this share of the account's usual cost per result, with enough results: a winner. */\nconst WINNER_RATIO = 0.8;\nconst WINNER_MIN_RESULTS = 3;\n/** At or over this share of the usual cost per result: failed. */\nconst FAILED_RATIO = 1.5;\n/** Spending this many usual results' worth with none: failed. */\nconst SILENT_SPEND = 2;\n/** Verdicts a thin window never takes back: too little delivery says nothing new about them. */\nconst SETTLED: ReadonlySet<IdeaStatus> = new Set([\"winner\", \"failed\", \"inconclusive\"]);\n\nexport type IdeaResult = {\n asOf: string;\n creatives: number;\n currency?: string;\n spend: number;\n impressions: number;\n results: number;\n costPerResult: number | null;\n ctr: number | null;\n /** Cost per result over the rest of the account's: 0.5 is half the usual cost. */\n vsAccount: number | null;\n};\n\nexport type IdeaLearning = { idea: string; from: IdeaStatus; to: IdeaStatus; result: IdeaResult };\n\nconst round = (n: number) => Math.round(n * 100) / 100;\n\nfunction totals(creatives: readonly CreativePerformance[]) {\n const spend = creatives.reduce((sum, c) => sum + c.spend, 0);\n const impressions = creatives.reduce((sum, c) => sum + c.impressions, 0);\n const results = creatives.reduce((sum, c) => sum + (c.results ?? 0), 0);\n const clicks = creatives.reduce((sum, c) => sum + (c.ctr ?? 0) * c.impressions, 0);\n return { spend, impressions, results, ctr: impressions > 0 ? round(clicks / impressions) : null };\n}\n\nfunction verdict(result: IdeaResult, usual: number | null): IdeaStatus {\n if (result.impressions < MIN_IMPRESSIONS) return \"testing\";\n if (usual !== null) {\n if (result.results === 0 && result.spend >= SILENT_SPEND * usual) return \"failed\";\n const ratio = result.vsAccount;\n if (ratio !== null && result.results >= WINNER_MIN_RESULTS && ratio <= WINNER_RATIO) return \"winner\";\n if (ratio !== null && ratio >= FAILED_RATIO) return \"failed\";\n }\n return result.impressions >= SEEN_ENOUGH ? \"inconclusive\" : \"testing\";\n}\n\n/** One idea's ads pooled into the numbers frozen on it, against the account's usual cost per result. */\nfunction ideaResult(own: readonly CreativePerformance[], usual: number | null, asOf: string): IdeaResult {\n const mine = totals(own);\n const costPerResult = mine.results > 0 ? round(mine.spend / mine.results) : null;\n return {\n asOf,\n creatives: own.length,\n ...(own[0]?.currency ? { currency: own[0].currency } : {}),\n spend: round(mine.spend),\n impressions: mine.impressions,\n results: mine.results,\n costPerResult,\n ctr: mine.ctr,\n vsAccount: usual !== null && costPerResult !== null ? round(costPerResult / usual) : null,\n };\n}\n\n/**\n * Each built idea's ads, pooled and judged against the rest of the account: cheaper results than\n * usual win, far dearer ones (or spend with none) fail. Ideas still to build, retired, with no\n * ad delivering, or already judged and seen too little since, are left alone.\n */\nexport function learnFromResults(\n ideas: readonly Idea[],\n creatives: readonly CreativePerformance[],\n asOf: string,\n): IdeaLearning[] {\n const ideaOf = (c: CreativePerformance) => c.definition?.idea ?? null;\n return ideas.flatMap((idea): IdeaLearning[] => {\n if (idea.status === \"idea\" || idea.status === \"retired\") return [];\n const own = creatives.filter((c) => ideaOf(c) === idea.id);\n if (own.length === 0) return [];\n const rest = totals(creatives.filter((c) => ideaOf(c) !== idea.id));\n const usual = rest.results > 0 ? rest.spend / rest.results : null;\n const result = ideaResult(own, usual, asOf);\n const to = verdict(result, usual);\n if (to === \"testing\" && SETTLED.has(idea.status)) return [];\n return [{ idea: idea.id, from: idea.status, to, result }];\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKA,SAAS,oBAAoB;AAC7B,SAAS,UAAU,iBAAiB;AACpC,OAAO,UAAU;AAEjB,SAAS,qBAAqB;;;ACA9B,IAAM,kBAAkB;AAExB,IAAM,cAAc;AAEpB,IAAM,eAAe;AACrB,IAAM,qBAAqB;AAE3B,IAAM,eAAe;AAErB,IAAM,eAAe;AAErB,IAAM,UAAmC,oBAAI,IAAI,CAAC,UAAU,UAAU,cAAc,CAAC;AAiBrF,IAAM,QAAQ,CAAC,MAAc,KAAK,MAAM,IAAI,GAAG,IAAI;AAEnD,SAAS,OAAO,WAA2C;AACzD,QAAM,QAAQ,UAAU,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,OAAO,CAAC;AAC3D,QAAM,cAAc,UAAU,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,aAAa,CAAC;AACvE,QAAM,UAAU,UAAU,OAAO,CAAC,KAAK,MAAM,OAAO,EAAE,WAAW,IAAI,CAAC;AACtE,QAAM,SAAS,UAAU,OAAO,CAAC,KAAK,MAAM,OAAO,EAAE,OAAO,KAAK,EAAE,aAAa,CAAC;AACjF,SAAO,EAAE,OAAO,aAAa,SAAS,KAAK,cAAc,IAAI,MAAM,SAAS,WAAW,IAAI,KAAK;AAClG;AAEA,SAAS,QAAQ,QAAoB,OAAkC;AACrE,MAAI,OAAO,cAAc,gBAAiB,QAAO;AACjD,MAAI,UAAU,MAAM;AAClB,QAAI,OAAO,YAAY,KAAK,OAAO,SAAS,eAAe,MAAO,QAAO;AACzE,UAAM,QAAQ,OAAO;AACrB,QAAI,UAAU,QAAQ,OAAO,WAAW,sBAAsB,SAAS,aAAc,QAAO;AAC5F,QAAI,UAAU,QAAQ,SAAS,aAAc,QAAO;AAAA,EACtD;AACA,SAAO,OAAO,eAAe,cAAc,iBAAiB;AAC9D;AAGA,SAAS,WAAW,KAAqC,OAAsB,MAA0B;AACvG,QAAM,OAAO,OAAO,GAAG;AACvB,QAAM,gBAAgB,KAAK,UAAU,IAAI,MAAM,KAAK,QAAQ,KAAK,OAAO,IAAI;AAC5E,SAAO;AAAA,IACL;AAAA,IACA,WAAW,IAAI;AAAA,IACf,GAAI,IAAI,CAAC,GAAG,WAAW,EAAE,UAAU,IAAI,CAAC,EAAE,SAAS,IAAI,CAAC;AAAA,IACxD,OAAO,MAAM,KAAK,KAAK;AAAA,IACvB,aAAa,KAAK;AAAA,IAClB,SAAS,KAAK;AAAA,IACd;AAAA,IACA,KAAK,KAAK;AAAA,IACV,WAAW,UAAU,QAAQ,kBAAkB,OAAO,MAAM,gBAAgB,KAAK,IAAI;AAAA,EACvF;AACF;AAOO,SAAS,iBACd,OACA,WACA,MACgB;AAChB,QAAM,SAAS,CAAC,MAA2B,EAAE,YAAY,QAAQ;AACjE,SAAO,MAAM,QAAQ,CAAC,SAAyB;AAC7C,QAAI,KAAK,WAAW,UAAU,KAAK,WAAW,UAAW,QAAO,CAAC;AACjE,UAAM,MAAM,UAAU,OAAO,CAAC,MAAM,OAAO,CAAC,MAAM,KAAK,EAAE;AACzD,QAAI,IAAI,WAAW,EAAG,QAAO,CAAC;AAC9B,UAAM,OAAO,OAAO,UAAU,OAAO,CAAC,MAAM,OAAO,CAAC,MAAM,KAAK,EAAE,CAAC;AAClE,UAAM,QAAQ,KAAK,UAAU,IAAI,KAAK,QAAQ,KAAK,UAAU;AAC7D,UAAM,SAAS,WAAW,KAAK,OAAO,IAAI;AAC1C,UAAM,KAAK,QAAQ,QAAQ,KAAK;AAChC,QAAI,OAAO,aAAa,QAAQ,IAAI,KAAK,MAAM,EAAG,QAAO,CAAC;AAC1D,WAAO,CAAC,EAAE,MAAM,KAAK,IAAI,MAAM,KAAK,QAAQ,IAAI,OAAO,CAAC;AAAA,EAC1D,CAAC;AACH;;;AD7EA,IAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASpB,IAAM,OAAO;AAAA,EACX,MAAM,EAAE,MAAM,UAAU,UAAU,OAAO,aAAa,wCAAwC;AAAA,EAC9F,WAAW,EAAE,MAAM,WAAW,UAAU,OAAO,SAAS,OAAO,aAAa,mCAAmC;AACjH;AAEA,eAAe,EAAE,SAAS,mBAAmB,aAAa,aAAa,MAAM,KAAK,CAAC;AAG5E,SAAS,cACd,WACA,SACA,aAAgC,CAAC,GACjC;AACA,QAAM,UAAU,UAAU,OAAO,CAAC,MAAM,EAAE,OAAO,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI;AAC5E,QAAM,SAAS,UAAU,OAAO,CAAC,MAAM,EAAE,OAAO,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI;AAC3E,QAAM,QAAkB,CAAC;AACzB,MAAI,WAAW,SAAS,GAAG;AACzB,UAAM;AAAA,MACJ,kBAAkB,WAAW,KAAK,IAAI,CAAC;AAAA,IACzC;AAAA,EACF;AACA,MAAI,UAAU,WAAW,GAAG;AAC1B,UAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACA,MAAI,QAAQ,SAAS,GAAG;AACtB,UAAM;AAAA,MACJ,YAAY,QAAQ,KAAK,IAAI,CAAC;AAAA,IAChC;AAAA,EACF;AACA,MAAI,OAAO,SAAS,GAAG;AACrB,UAAM;AAAA,MACJ,GAAG,OAAO,KAAK,IAAI,CAAC;AAAA,IACtB;AAAA,EACF;AACA,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,MAAM;AAAA,MACJ;AAAA,MACA,OAAO,UAAU,IAAI,CAAC,OAAO;AAAA,QAC3B,MAAM,EAAE;AAAA,QACR,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,EAAE,IAAI,WAAM,EAAE,EAAE;AAAA,QACpD,GAAG,EAAE;AAAA,MACP,EAAE;AAAA,IACJ;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAe,UAAU,MAAc,WAAmD;AACxF,aAAW,YAAY,WAAW;AAChC,UAAM,OAAO,KAAK,KAAK,MAAM,WAAW,GAAG,SAAS,IAAI,KAAK;AAC7D,UAAM,MAAM,MAAM,SAAS,MAAM,MAAM;AACvC,UAAM,UAAU,MAAM,oBAAoB,KAAK,EAAE,QAAQ,SAAS,IAAI,QAAQ,SAAS,OAAO,CAAC,GAAG,MAAM;AAAA,EAC1G;AACF;AAEA,SAAS,eAAe,MAAc,MAA6B;AACjE,MAAI;AACF,WAAO,aAAa,KAAK,KAAK,MAAM,OAAO,aAAa,MAAM,gBAAgB,GAAG,MAAM;AAAA,EACzF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,QAAgB;AACvB,UAAO,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AAC7C;AAEO,IAAM,eAAe,cAAc;AAAA,EACxC,MAAM,EAAE,MAAM,SAAS,aAAa,YAAY;AAAA,EAChD,MAAM;AAAA,EACN,MAAM,IAAI,EAAE,KAAK,GAAG;AAClB,QAAI;AACF,YAAM,OAAO,kBAAkB,QAAQ,IAAI,CAAC,KAAK,QAAQ,IAAI;AAC7D,YAAM,OAAO,UAAU,KAAK,IAA0B;AACtD,YAAM,cAAc;AAAA,QAClB,MAAM,QAAsC,8BAA8B,OAAO,EAAE,KAAK,IAAI,CAAC,CAAC;AAAA,QAC9F,CAAC,SAAS,eAAe,MAAM,IAAI;AAAA,MACrC;AACA,YAAM,EAAE,OAAO,WAAW,IAAI,MAAM,UAAU,IAAI;AAClD,YAAM,YAAY,iBAAiB,OAAO,YAAY,KAAK,WAAW,MAAM,CAAC;AAC7E,YAAM,SAAS,KAAK,SAAS,MAAM;AACnC,UAAI,CAAC,OAAQ,OAAM,UAAU,MAAM,SAAS;AAC5C;AAAA,QACE;AAAA,UACE;AAAA,UACA,CAAC,UAAU,UAAU,SAAS;AAAA,UAC9B,WAAW,IAAI,CAAC,MAAM,EAAE,EAAE;AAAA,QAC5B;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,GAAG;AAAA,IACb;AAAA,EACF;AACF,CAAC;","names":[]}
@@ -7,7 +7,7 @@ import {
7
7
  stageAccountId,
8
8
  stageXOp,
9
9
  stageXOps
10
- } from "./chunk-KHRXPQID.js";
10
+ } from "./chunk-VYQ3QJ3C.js";
11
11
  import "./chunk-M6UNISGO.js";
12
12
  import "./chunk-C6U6UDHJ.js";
13
13
  import "./chunk-VFIOJD5M.js";
@@ -15,10 +15,11 @@ import {
15
15
  OBJECTIVES,
16
16
  PLACEMENTS,
17
17
  PRODUCT_TYPES
18
- } from "./chunk-XF4JUKVF.js";
18
+ } from "./chunk-7EPXVICM.js";
19
19
  import "./chunk-GXDLWBOY.js";
20
20
  import "./chunk-TEINLN64.js";
21
21
  import "./chunk-ZJWUBJYQ.js";
22
+ import "./chunk-HR6IWNKE.js";
22
23
  import "./chunk-NE4F3FHN.js";
23
24
  import "./chunk-XBOK23HI.js";
24
25
  import "./chunk-IFWP3ZDO.js";
@@ -205,4 +206,4 @@ export {
205
206
  lineItemsResumeCommand,
206
207
  lineItemsUpdateCommand
207
208
  };
208
- //# sourceMappingURL=line-item-writes-E6MZPIZZ.js.map
209
+ //# sourceMappingURL=line-item-writes-EMYSOJKM.js.map