@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
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/ads/linkedin/conversation.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { NO_CACHE_ARG } from \"../../../cache-flag.ts\";\nimport { apiPost } from \"../../../client.ts\";\nimport { writeAdsJson, writeAdsOutput } from \"../output.ts\";\nimport { csvOrJson, daysAgoIso, handleLinkedinError, todayIso } from \"./shared.ts\";\n\ninterface AnalyticsResponse {\n rows: Array<Record<string, unknown>>;\n fields: string[];\n warnings: Array<{ code: string; message: string }>;\n}\n\n/**\n * Conversation Ads (Sponsored Messaging) per-button analytics. Wraps\n * --pivot conversation-node-button on /api/ads/linkedin/analytics.\n *\n * Lets agents see which CTA button inside a multi-step Sponsored Message\n * actually drives clicks — no other ad platform exposes this granularity.\n */\nexport const conversationCommand = defineCommand({\n meta: {\n name: \"conversation\",\n description: `Per-button click rates inside Sponsored Messaging / Conversation Ads.\n\nReturns one row per CONVERSATION_NODE_BUTTON pivot, sorted by clicks desc.\nUse this to A/B test button copy and the cascade tree.\n\nExamples:\n baker ads linkedin conversation --campaign-id 1234\n baker ads linkedin conversation --campaign-id 1234 --last-days 30 --output csv`,\n },\n args: {\n \"campaign-id\": {\n type: \"string\",\n description: \"Comma-separated campaign IDs (Conversation Ad campaigns)\",\n required: true,\n },\n start: { type: \"string\", description: \"Start date YYYY-MM-DD\" },\n end: { type: \"string\", description: \"End date YYYY-MM-DD\" },\n \"last-days\": { type: \"string\", description: \"Window relative to today (default: 30)\" },\n \"no-cache\": NO_CACHE_ARG,\n output: { type: \"string\", description: \"json|csv|jsonl|md\", default: \"json\" },\n },\n run: async ({ args }) => {\n const campaignIdsRaw = args[\"campaign-id\"] as string | undefined;\n if (!campaignIdsRaw) {\n handleLinkedinError(new Error(\"--campaign-id is required\"));\n }\n const ids = campaignIdsRaw\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n const start = (args.start as string | undefined) ?? daysAgoIso(args[\"last-days\"] ? Number(args[\"last-days\"]) : 30);\n const end = (args.end as string | undefined) ?? todayIso();\n\n try {\n const data = await apiPost<AnalyticsResponse>(\"/api/ads/linkedin/analytics\", {\n request: {\n level: \"campaign\",\n ids,\n intent: \"inmail\",\n pivot: \"conversation-node-button\",\n start,\n end,\n granularity: \"ALL\",\n limit: 500,\n },\n skipCache: Boolean(args[\"no-cache\"]),\n });\n const sorted = [...data.rows].sort((a, b) => Number(b.clicks ?? 0) - Number(a.clicks ?? 0));\n const fmt = csvOrJson(args);\n if (fmt !== \"json\") {\n writeAdsOutput(sorted, fmt, data.fields);\n return;\n }\n writeAdsJson({\n ok: true,\n data: { query: { campaigns: ids, start, end }, rows: sorted, warnings: data.warnings },\n });\n } catch (err) {\n handleLinkedinError(err);\n }\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,qBAAqB;AAmBvB,IAAM,sBAAsB,cAAc;AAAA,EAC/C,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQf;AAAA,EACA,MAAM;AAAA,IACJ,eAAe;AAAA,MACb,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,IACZ;AAAA,IACA,OAAO,EAAE,MAAM,UAAU,aAAa,wBAAwB;AAAA,IAC9D,KAAK,EAAE,MAAM,UAAU,aAAa,sBAAsB;AAAA,IAC1D,aAAa,EAAE,MAAM,UAAU,aAAa,yCAAyC;AAAA,IACrF,YAAY;AAAA,IACZ,QAAQ,EAAE,MAAM,UAAU,aAAa,qBAAqB,SAAS,OAAO;AAAA,EAC9E;AAAA,EACA,KAAK,OAAO,EAAE,KAAK,MAAM;AACvB,UAAM,iBAAiB,KAAK,aAAa;AACzC,QAAI,CAAC,gBAAgB;AACnB,0BAAoB,IAAI,MAAM,2BAA2B,CAAC;AAAA,IAC5D;AACA,UAAM,MAAM,eACT,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,OAAO;AACjB,UAAM,QAAS,KAAK,SAAgC,WAAW,KAAK,WAAW,IAAI,OAAO,KAAK,WAAW,CAAC,IAAI,EAAE;AACjH,UAAM,MAAO,KAAK,OAA8B,SAAS;AAEzD,QAAI;AACF,YAAM,OAAO,MAAM,QAA2B,+BAA+B;AAAA,QAC3E,SAAS;AAAA,UACP,OAAO;AAAA,UACP;AAAA,UACA,QAAQ;AAAA,UACR,OAAO;AAAA,UACP;AAAA,UACA;AAAA,UACA,aAAa;AAAA,UACb,OAAO;AAAA,QACT;AAAA,QACA,WAAW,QAAQ,KAAK,UAAU,CAAC;AAAA,MACrC,CAAC;AACD,YAAM,SAAS,CAAC,GAAG,KAAK,IAAI,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,EAAE,UAAU,CAAC,IAAI,OAAO,EAAE,UAAU,CAAC,CAAC;AAC1F,YAAM,MAAM,UAAU,IAAI;AAC1B,UAAI,QAAQ,QAAQ;AAClB,uBAAe,QAAQ,KAAK,KAAK,MAAM;AACvC;AAAA,MACF;AACA,mBAAa;AAAA,QACX,IAAI;AAAA,QACJ,MAAM,EAAE,OAAO,EAAE,WAAW,KAAK,OAAO,IAAI,GAAG,MAAM,QAAQ,UAAU,KAAK,SAAS;AAAA,MACvF,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,0BAAoB,GAAG;AAAA,IACzB;AAAA,EACF;AACF,CAAC;","names":[]}
1
+ {"version":3,"sources":["../src/commands/ads/linkedin/conversation.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { NO_CACHE_ARG } from \"../../../cache-flag.ts\";\nimport { apiPost } from \"../../../client.ts\";\nimport { writeAdsJson, writeAdsOutput } from \"../output.ts\";\nimport { csvOrJson, daysAgoIso, handleLinkedinError, todayIso } from \"./shared.ts\";\n\ninterface AnalyticsResponse {\n rows: Array<Record<string, unknown>>;\n fields: string[];\n warnings: Array<{ code: string; message: string }>;\n}\n\n/**\n * Conversation Ads (Sponsored Messaging) per-button analytics. Wraps\n * --pivot conversation-node-button on /api/ads/linkedin/analytics.\n *\n * Lets agents see which CTA button inside a multi-step Sponsored Message\n * actually drives clicks — no other ad platform exposes this granularity.\n */\nexport const conversationCommand = defineCommand({\n meta: {\n name: \"conversation\",\n description: `Per-button click rates inside Sponsored Messaging / Conversation Ads.\n\nReturns one row per CONVERSATION_NODE_BUTTON pivot, sorted by clicks desc.\nUse this to A/B test button copy and the cascade tree.\n\nExamples:\n baker ads linkedin conversation --campaign-id 1234\n baker ads linkedin conversation --campaign-id 1234 --last-days 30 --output csv`,\n },\n args: {\n \"campaign-id\": {\n type: \"string\",\n description: \"Comma-separated campaign IDs (Conversation Ad campaigns)\",\n required: true,\n },\n start: { type: \"string\", description: \"Start date YYYY-MM-DD\" },\n end: { type: \"string\", description: \"End date YYYY-MM-DD\" },\n \"last-days\": { type: \"string\", description: \"Window relative to today (default: 30)\" },\n \"no-cache\": NO_CACHE_ARG,\n output: { type: \"string\", description: \"json|csv|jsonl|md\", default: \"json\" },\n },\n run: async ({ args }) => {\n const campaignIdsRaw = args[\"campaign-id\"] as string | undefined;\n if (!campaignIdsRaw) {\n handleLinkedinError(new Error(\"--campaign-id is required\"));\n }\n const ids = campaignIdsRaw\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n const start = (args.start as string | undefined) ?? daysAgoIso(args[\"last-days\"] ? Number(args[\"last-days\"]) : 30);\n const end = (args.end as string | undefined) ?? todayIso();\n\n try {\n const data = await apiPost<AnalyticsResponse>(\"/api/ads/linkedin/analytics\", {\n request: {\n level: \"campaign\",\n ids,\n intent: \"inmail\",\n pivot: \"conversation-node-button\",\n start,\n end,\n granularity: \"ALL\",\n limit: 500,\n },\n skipCache: Boolean(args[\"no-cache\"]),\n });\n const sorted = [...data.rows].sort((a, b) => Number(b.clicks ?? 0) - Number(a.clicks ?? 0));\n const fmt = csvOrJson(args);\n if (fmt !== \"json\") {\n writeAdsOutput(sorted, fmt, data.fields);\n return;\n }\n writeAdsJson({\n ok: true,\n data: { query: { campaigns: ids, start, end }, rows: sorted, warnings: data.warnings },\n });\n } catch (err) {\n handleLinkedinError(err);\n }\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,qBAAqB;AAmBvB,IAAM,sBAAsB,cAAc;AAAA,EAC/C,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQf;AAAA,EACA,MAAM;AAAA,IACJ,eAAe;AAAA,MACb,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,IACZ;AAAA,IACA,OAAO,EAAE,MAAM,UAAU,aAAa,wBAAwB;AAAA,IAC9D,KAAK,EAAE,MAAM,UAAU,aAAa,sBAAsB;AAAA,IAC1D,aAAa,EAAE,MAAM,UAAU,aAAa,yCAAyC;AAAA,IACrF,YAAY;AAAA,IACZ,QAAQ,EAAE,MAAM,UAAU,aAAa,qBAAqB,SAAS,OAAO;AAAA,EAC9E;AAAA,EACA,KAAK,OAAO,EAAE,KAAK,MAAM;AACvB,UAAM,iBAAiB,KAAK,aAAa;AACzC,QAAI,CAAC,gBAAgB;AACnB,0BAAoB,IAAI,MAAM,2BAA2B,CAAC;AAAA,IAC5D;AACA,UAAM,MAAM,eACT,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,OAAO;AACjB,UAAM,QAAS,KAAK,SAAgC,WAAW,KAAK,WAAW,IAAI,OAAO,KAAK,WAAW,CAAC,IAAI,EAAE;AACjH,UAAM,MAAO,KAAK,OAA8B,SAAS;AAEzD,QAAI;AACF,YAAM,OAAO,MAAM,QAA2B,+BAA+B;AAAA,QAC3E,SAAS;AAAA,UACP,OAAO;AAAA,UACP;AAAA,UACA,QAAQ;AAAA,UACR,OAAO;AAAA,UACP;AAAA,UACA;AAAA,UACA,aAAa;AAAA,UACb,OAAO;AAAA,QACT;AAAA,QACA,WAAW,QAAQ,KAAK,UAAU,CAAC;AAAA,MACrC,CAAC;AACD,YAAM,SAAS,CAAC,GAAG,KAAK,IAAI,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,EAAE,UAAU,CAAC,IAAI,OAAO,EAAE,UAAU,CAAC,CAAC;AAC1F,YAAM,MAAM,UAAU,IAAI;AAC1B,UAAI,QAAQ,QAAQ;AAClB,uBAAe,QAAQ,KAAK,KAAK,MAAM;AACvC;AAAA,MACF;AACA,mBAAa;AAAA,QACX,IAAI;AAAA,QACJ,MAAM,EAAE,OAAO,EAAE,WAAW,KAAK,OAAO,IAAI,GAAG,MAAM,QAAQ,UAAU,KAAK,SAAS;AAAA,MACvF,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,0BAAoB,GAAG;AAAA,IACzB;AAAA,EACF;AACF,CAAC;","names":[]}
@@ -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
@@ -123,13 +124,13 @@ Subcommands:
123
124
  subCommands: {
124
125
  list: listCmd,
125
126
  health: healthCmd,
126
- create: () => import("./write-commands-5C7FUOVN.js").then((m) => m.conversionsCreateCommand),
127
- update: () => import("./write-commands-5C7FUOVN.js").then((m) => m.conversionsUpdateCommand),
128
- "associate-campaign": () => import("./write-commands-5C7FUOVN.js").then((m) => m.conversionsAssociateCommand),
129
- "dissociate-campaign": () => import("./write-commands-5C7FUOVN.js").then((m) => m.conversionsDissociateCommand)
127
+ create: () => import("./write-commands-7SJ3BOW5.js").then((m) => m.conversionsCreateCommand),
128
+ update: () => import("./write-commands-7SJ3BOW5.js").then((m) => m.conversionsUpdateCommand),
129
+ "associate-campaign": () => import("./write-commands-7SJ3BOW5.js").then((m) => m.conversionsAssociateCommand),
130
+ "dissociate-campaign": () => import("./write-commands-7SJ3BOW5.js").then((m) => m.conversionsDissociateCommand)
130
131
  }
131
132
  });
132
133
  export {
133
134
  conversionsCommand
134
135
  };
135
- //# sourceMappingURL=conversions-4SRZPBBX.js.map
136
+ //# sourceMappingURL=conversions-UHB55MMQ.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/ads/linkedin/conversions.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 ConversionRule {\n id: string;\n urn: string;\n account: string;\n name?: string;\n type?: string;\n enabled?: boolean;\n conversionMethod?: string;\n attributionType?: string;\n postClickAttributionWindowSize?: number;\n viewThroughAttributionWindowSize?: number;\n associatedCampaigns?: string[];\n countingMethod?: string;\n lastConversionReportedAt?: number;\n}\n\nconst DAY_MS = 86_400_000;\n\nfunction healthOf(rules: ConversionRule[]): {\n totalRules: number;\n enabledRules: number;\n capiRules: number;\n pixelRules: number;\n hasLeadEvent: boolean;\n hasPurchaseEvent: boolean;\n staleCapiRules: ConversionRule[];\n longViewWindow: ConversionRule[];\n wrongLeadDedup: ConversionRule[];\n} {\n const enabled = rules.filter((r) => r.enabled !== false);\n const capi = enabled.filter((r) => r.conversionMethod === \"CONVERSIONS_API\");\n const pixel = enabled.filter((r) => r.conversionMethod === \"PIXEL\");\n const staleCapi = capi.filter(\n (r) => !r.lastConversionReportedAt || Date.now() - r.lastConversionReportedAt > 7 * DAY_MS,\n );\n const longView = enabled.filter(\n (r) => r.viewThroughAttributionWindowSize !== undefined && r.viewThroughAttributionWindowSize > 7,\n );\n const leads = enabled.filter((r) => r.type === \"LEAD\");\n const wrongDedup = leads.filter((r) => r.countingMethod && r.countingMethod !== \"ONE_TIME_EACH_MEMBER\");\n return {\n totalRules: rules.length,\n enabledRules: enabled.length,\n capiRules: capi.length,\n pixelRules: pixel.length,\n hasLeadEvent: leads.length > 0,\n hasPurchaseEvent: enabled.some((r) => r.type === \"PURCHASE\"),\n staleCapiRules: staleCapi,\n longViewWindow: longView,\n wrongLeadDedup: wrongDedup,\n };\n}\n\nconst listCmd = defineCommand({\n meta: {\n name: \"list\",\n description: `List conversion rules on the account.`,\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 \"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[\"no-cache\"]) params[\"skip-cache\"] = \"true\";\n const data = await apiGet<ConversionRule[]>(\"/api/ads/linkedin/conversions\", params);\n const fmt = csvOrJson(args);\n if (fmt !== \"json\") {\n writeAdsOutput(data 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\nconst healthCmd = defineCommand({\n meta: {\n name: \"health\",\n description: `5-point Insight Tag / CAPI health check (playbook §07).\n\nSurfaces:\n - Are rules enabled?\n - Do we have at least one LEAD or PURCHASE event?\n - Do CAPI rules show recent activity (≤7 days)?\n - Is the view-through window ≤7 days?\n - Do LEAD rules use ONE_TIME_EACH_MEMBER de-dup?`,\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 \"no-cache\": NO_CACHE_ARG,\n output: { type: \"string\", description: \"json\", 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[\"no-cache\"]) params[\"skip-cache\"] = \"true\";\n const data = await apiGet<ConversionRule[]>(\"/api/ads/linkedin/conversions\", params);\n writeAdsJson({ ok: true, data: healthOf(data) });\n } catch (err) {\n handleLinkedinError(err);\n }\n },\n});\n\nexport const conversionsCommand = defineCommand({\n meta: {\n name: \"conversions\",\n description: `Conversion rules — Insight Tag and Conversions API.\n\nSubcommands:\n list — every rule on the account\n health — playbook §07 5-point health check\n create / update — stage a conversion-rule write (applies on chat publish)\n associate-campaign / dissociate-campaign\n — which ad sets a rule counts for (its own LinkedIn record, not a field on the rule)`,\n },\n subCommands: {\n list: listCmd,\n health: healthCmd,\n create: () => import(\"./write-commands.ts\").then((m) => m.conversionsCreateCommand),\n update: () => import(\"./write-commands.ts\").then((m) => m.conversionsUpdateCommand),\n \"associate-campaign\": () => import(\"./write-commands.ts\").then((m) => m.conversionsAssociateCommand),\n \"dissociate-campaign\": () => import(\"./write-commands.ts\").then((m) => m.conversionsDissociateCommand),\n },\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/commands/ads/linkedin/conversions.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 ConversionRule {\n id: string;\n urn: string;\n account: string;\n name?: string;\n type?: string;\n enabled?: boolean;\n conversionMethod?: string;\n attributionType?: string;\n postClickAttributionWindowSize?: number;\n viewThroughAttributionWindowSize?: number;\n associatedCampaigns?: string[];\n countingMethod?: string;\n lastConversionReportedAt?: number;\n}\n\nconst DAY_MS = 86_400_000;\n\nfunction healthOf(rules: ConversionRule[]): {\n totalRules: number;\n enabledRules: number;\n capiRules: number;\n pixelRules: number;\n hasLeadEvent: boolean;\n hasPurchaseEvent: boolean;\n staleCapiRules: ConversionRule[];\n longViewWindow: ConversionRule[];\n wrongLeadDedup: ConversionRule[];\n} {\n const enabled = rules.filter((r) => r.enabled !== false);\n const capi = enabled.filter((r) => r.conversionMethod === \"CONVERSIONS_API\");\n const pixel = enabled.filter((r) => r.conversionMethod === \"PIXEL\");\n const staleCapi = capi.filter(\n (r) => !r.lastConversionReportedAt || Date.now() - r.lastConversionReportedAt > 7 * DAY_MS,\n );\n const longView = enabled.filter(\n (r) => r.viewThroughAttributionWindowSize !== undefined && r.viewThroughAttributionWindowSize > 7,\n );\n const leads = enabled.filter((r) => r.type === \"LEAD\");\n const wrongDedup = leads.filter((r) => r.countingMethod && r.countingMethod !== \"ONE_TIME_EACH_MEMBER\");\n return {\n totalRules: rules.length,\n enabledRules: enabled.length,\n capiRules: capi.length,\n pixelRules: pixel.length,\n hasLeadEvent: leads.length > 0,\n hasPurchaseEvent: enabled.some((r) => r.type === \"PURCHASE\"),\n staleCapiRules: staleCapi,\n longViewWindow: longView,\n wrongLeadDedup: wrongDedup,\n };\n}\n\nconst listCmd = defineCommand({\n meta: {\n name: \"list\",\n description: `List conversion rules on the account.`,\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 \"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[\"no-cache\"]) params[\"skip-cache\"] = \"true\";\n const data = await apiGet<ConversionRule[]>(\"/api/ads/linkedin/conversions\", params);\n const fmt = csvOrJson(args);\n if (fmt !== \"json\") {\n writeAdsOutput(data 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\nconst healthCmd = defineCommand({\n meta: {\n name: \"health\",\n description: `5-point Insight Tag / CAPI health check (playbook §07).\n\nSurfaces:\n - Are rules enabled?\n - Do we have at least one LEAD or PURCHASE event?\n - Do CAPI rules show recent activity (≤7 days)?\n - Is the view-through window ≤7 days?\n - Do LEAD rules use ONE_TIME_EACH_MEMBER de-dup?`,\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 \"no-cache\": NO_CACHE_ARG,\n output: { type: \"string\", description: \"json\", 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[\"no-cache\"]) params[\"skip-cache\"] = \"true\";\n const data = await apiGet<ConversionRule[]>(\"/api/ads/linkedin/conversions\", params);\n writeAdsJson({ ok: true, data: healthOf(data) });\n } catch (err) {\n handleLinkedinError(err);\n }\n },\n});\n\nexport const conversionsCommand = defineCommand({\n meta: {\n name: \"conversions\",\n description: `Conversion rules — Insight Tag and Conversions API.\n\nSubcommands:\n list — every rule on the account\n health — playbook §07 5-point health check\n create / update — stage a conversion-rule write (applies on chat publish)\n associate-campaign / dissociate-campaign\n — which ad sets a rule counts for (its own LinkedIn record, not a field on the rule)`,\n },\n subCommands: {\n list: listCmd,\n health: healthCmd,\n create: () => import(\"./write-commands.ts\").then((m) => m.conversionsCreateCommand),\n update: () => import(\"./write-commands.ts\").then((m) => m.conversionsUpdateCommand),\n \"associate-campaign\": () => import(\"./write-commands.ts\").then((m) => m.conversionsAssociateCommand),\n \"dissociate-campaign\": () => import(\"./write-commands.ts\").then((m) => m.conversionsDissociateCommand),\n },\n});\n"],"mappings":"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","names":[]}
@@ -13,10 +13,11 @@ import {
13
13
  } from "./chunk-PWGWMIIJ.js";
14
14
  import {
15
15
  AVATAR_HANDLE_PATTERN
16
- } from "./chunk-XF4JUKVF.js";
16
+ } from "./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 "./chunk-XBOK23HI.js";
22
23
  import "./chunk-IFWP3ZDO.js";
@@ -204,4 +205,4 @@ var createCommand = defineCommand({
204
205
  export {
205
206
  createCommand
206
207
  };
207
- //# sourceMappingURL=create-BJNMO6HT.js.map
208
+ //# sourceMappingURL=create-EX6OWLNM.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/avatars/create.ts"],"sourcesContent":["import { AVATAR_HANDLE_PATTERN, type AvatarsCreateRequest, type AvatarsCreateResponse } from \"@baker/api\";\nimport { defineCommand } from \"citty\";\nimport { writeJson } from \"../../output.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport { chatIdFromEnv, creationHints, parseFaceChoice } from \"./casting.ts\";\nimport { failAvatarApi, failValidation } from \"./failures.ts\";\nimport { buildProfilePatch } from \"./profile.ts\";\nimport { writeAvatars } from \"./transport.ts\";\n\nfunction parseImageIds(value: unknown): string[] | undefined {\n if (typeof value !== \"string\") return undefined;\n const ids = value\n .split(\",\")\n .map((id) => id.trim())\n .filter((id) => id.length > 0);\n return ids.length > 0 ? [...new Set(ids)] : undefined;\n}\n\nregisterSchema({\n command: \"avatars.create\",\n description:\n 'Cast a new avatar — a reusable AI presenter this company can put in images and video. Start here: `baker avatars create --name \"Marta\" --subject \"woman in her early 40s, shoulder-length dark hair, warm brown eyes, light olive skin\"`. --subject is the identity: describe ONE person plainly (age, build, hair, skin, face) with no scene, no lighting and no wardrobe, because it is copied word for word into every prompt that renders them. Two kinds: invented from your description (default), or built from photographs of a real person (--source-image with --likeness-confirmed, which is the company stating it may use that person\\'s image in advertising). For a real person the copy NAMES — a testimonial author, the founder, a team member — use `baker avatars research \"<name>, <role> at <company>\" --create` instead: it finds their photos and builds the avatar itself. Returns immediately with status `generating` — the identity sheet is a ~30s render that settles in the background.',\n args: {\n name: { type: \"string\", description: 'Display name, e.g. \"Marta\"', required: true },\n handle: {\n type: \"string\",\n description: 'Mention handle (lowercase, dashes), e.g. \"marta\". Derived from the name when omitted.',\n required: false,\n },\n subject: {\n type: \"string\",\n description:\n \"The identity, reused verbatim in every render: one person, plainly described (age, build, hair, skin, face). No scene, no lighting, no camera, no wardrobe — those belong in the render prompt or in --wardrobe/--setting.\",\n required: true,\n },\n persona: { type: \"string\", description: \"Who they are on camera — role, attitude, energy\", required: false },\n speech: { type: \"string\", description: \"How they speak — pace, register, verbal habits\", required: false },\n accent: {\n type: \"string\",\n description:\n \"Where their VOICE is from, as a place: 'Spanish from Spain, Madrid accent', 'Mexican Spanish', 'British English, London'. Name the region — an adjective like 'clear Spanish accent' is read by the video model as NO accent, and the clip comes out sounding like nowhere. Default to the language the USER is writing to you in, always: they are describing an ad for their own market, and an avatar that answers them in another language is unusable however good it looks. Never take this from how the person LOOKS — 'aspecto europeo', 'Nordic', 'Mediterranean' describe a face and belong in --subject. Read literally, that mistake shipped an ad for a Spanish client with --accent \\\"German\\\", and the clip came back spoken in German.\",\n required: false,\n },\n motion: { type: \"string\", description: \"Body language and gesture in video\", required: false },\n wardrobe: { type: \"string\", description: \"Default outfit when the brief does not name one\", required: false },\n setting: {\n type: \"string\",\n description:\n 'Where they are in their own life (\"her small kitchen in Madrid on a weekday morning\") — their casting photo is taken there, and renders use it when the brief leaves the surroundings open. Always fill it: a face with no world comes back looking like a studio headshot.',\n required: false,\n },\n guardrails: {\n type: \"string\",\n description: 'Comma-separated things this avatar must never do, e.g. \"no competitor logos, no medical claims\"',\n required: false,\n },\n \"source-image\": {\n type: \"string\",\n description:\n \"Comma-separated library image ids (up to 6) of photographs of a REAL person to build the likeness from. Requires --likeness-confirmed. Source them with `baker images upload`/`library` first.\",\n required: false,\n },\n \"likeness-confirmed\": {\n type: \"boolean\",\n description:\n \"The company's statement that it may use this real person's image in advertising. Required with --source-image. Pass it when the user gave you the photos, or the person is someone the company features in its own marketing (its founder, its team, a customer quoted by name) — that request is the statement; there is no separate question to ask.\",\n required: false,\n },\n face: {\n type: \"string\",\n description:\n \"Who picks the face, for an invented avatar: 'ask' (default) blocks on the user through `request_avatar_casting`, 'auto' keeps the one this build casts and asks nobody. Use 'auto' only when there is no one to answer — a Schedule, a batch, an explicit \\\"do it yourself\\\" — because a person who is there almost always wants this choice.\",\n required: false,\n },\n output: {\n type: \"string\",\n description:\n \"Output format. Only `json`, which is what this returns anyway — accepted because `avatars list` and `avatars get` take it, so reaching for it here is the obvious guess.\",\n required: false,\n default: \"json\",\n },\n },\n});\n\nexport const createCommand = defineCommand({\n meta: {\n name: \"create\",\n description:\n 'Cast a new avatar (reusable AI presenter). Example: baker avatars create --name \"Marta\" --subject \"woman in her early 40s, shoulder-length dark hair, light olive skin, warm open face\" --persona \"friendly product expert\". Returns while the identity sheet is still building.',\n },\n args: {\n name: { type: \"string\", description: \"Display name\", required: false },\n handle: { type: \"string\", description: \"Mention handle (derived from the name when omitted)\", required: false },\n subject: { type: \"string\", description: \"The person, plainly described — reused verbatim\", required: false },\n persona: { type: \"string\", description: \"Who they are on camera\", required: false },\n speech: { type: \"string\", description: \"How they speak\", required: false },\n accent: {\n type: \"string\",\n description: \"Where their voice is FROM — name the region, e.g. 'Spanish from Spain, Madrid accent'\",\n required: false,\n },\n motion: { type: \"string\", description: \"Body language in video\", required: false },\n wardrobe: { type: \"string\", description: \"Default outfit\", required: false },\n setting: { type: \"string\", description: \"Default surroundings\", required: false },\n guardrails: { type: \"string\", description: \"Comma-separated things they must never do\", required: false },\n \"source-image\": {\n type: \"string\",\n description: \"Comma-separated library image ids of a real person (needs --likeness-confirmed)\",\n required: false,\n },\n \"likeness-confirmed\": {\n type: \"boolean\",\n description: \"The company may use this real person's image in advertising\",\n required: false,\n default: false,\n },\n face: {\n type: \"string\",\n description:\n \"Who picks the face of an invented avatar: 'ask' (default, blocks on the user) or 'auto' (asks nobody)\",\n required: false,\n },\n output: {\n type: \"string\",\n description: \"Output format — `json` only, which is what this returns anyway\",\n required: false,\n default: \"json\",\n },\n },\n run: async ({ args }) => {\n const name = (args.name as string | undefined)?.trim();\n if (!name) {\n failValidation('--name is required, e.g. `baker avatars create --name \"Marta\" --subject \"…\"`.');\n }\n\n const profile = buildProfilePatch(args);\n const subjectDescription = profile.subjectDescription;\n if (!subjectDescription) {\n failValidation(\n \"--subject is required: it is the identity every render of this avatar is built from, and it is copied into each prompt word for word.\",\n {\n action: \"describe_the_person\",\n explanation:\n 'Write one person, plainly: age range, build, hair, skin, face, anything distinctive. No scene, no lighting, no camera, no wardrobe. Good: \"woman in her early 40s, shoulder-length dark brown hair, light olive skin, warm open face, slight smile lines\". Bad: \"confident businesswoman in a sunlit office\". If the user described a real person and you have their photos, pass --source-image with --likeness-confirmed instead of inventing the description; if they are named but you have no photos, run `baker avatars research \"<name>, <role> at <company>\" --create`.',\n },\n );\n }\n\n const handle = (args.handle as string | undefined)?.trim().toLowerCase();\n if (handle && !AVATAR_HANDLE_PATTERN.test(handle)) {\n failValidation(\n `--handle \"${handle}\" is not usable. Use lowercase letters, numbers and dashes, starting with a letter — \"maria-founder\", not \"Maria Founder\". Leave it off to have one derived from the name.`,\n );\n }\n\n // Accepted rather than refused, because refusing it cost a whole create: the command\n // was rejected for this flag alone, the agent retried without it, and the retry landed\n // while the casting for the first attempt was still pending — so the avatar that DID\n // get made never got a face picker. `create` has one shape of output; saying so is\n // cheaper than being right about it.\n const output = (args.output as string | undefined)?.trim().toLowerCase();\n if (output && output !== \"json\") {\n failValidation(\n `\\`--output ${output}\\` is not a format \\`baker avatars create\\` produces — it returns JSON and nothing else. Drop the flag, or pass \\`--output json\\`. \\`baker avatars list\\` and \\`baker avatars get\\` are the ones that also render \\`files\\` and \\`md\\`.`,\n );\n }\n\n const faceChoice = parseFaceChoice(args.face as string | undefined);\n if (faceChoice === null) {\n failValidation(\n `--face \"${String(args.face)}\" is not a mode. Use --face ask to let the user pick the face, or --face auto to keep the one this build casts.`,\n {\n action: \"pick_a_mode\",\n explanation:\n \"Drop the flag entirely if a person is in the conversation — that is --face ask, and it is what they almost always want. Pass --face auto only when nobody is there to answer: a Schedule, a batch run, or the user telling you to do it without them.\",\n },\n );\n }\n\n const sourceImageIds = parseImageIds(args[\"source-image\"]);\n const likenessConfirmed = Boolean(args[\"likeness-confirmed\"]);\n if (sourceImageIds && !likenessConfirmed) {\n failValidation(\n \"Building an avatar from photographs of a real person needs --likeness-confirmed: the company has to state that it may use that person's image in its advertising.\",\n {\n action: \"confirm_the_likeness\",\n explanation:\n 'Photos the user handed you, or of someone the company features in its own marketing (its founder, its team, a customer it quotes by name), come with that statement: re-run the same command with --likeness-confirmed. If the person is named in the copy and you have no photos, use `baker avatars research \"<name>, <role> at <company>\" --create` instead. Only if the user said they may NOT use this person\\'s image, drop --source-image and cast an invented presenter from --subject — do not abandon the wider job over it.',\n },\n );\n }\n\n try {\n const body: AvatarsCreateRequest = {\n name,\n ...(handle ? { handle } : {}),\n profile: { ...profile, subjectDescription },\n ...(sourceImageIds ? { sourceImageIds, likenessConfirmed: true } : {}),\n ...(chatIdFromEnv() ? { chatId: chatIdFromEnv() } : {}),\n // Sent so the backend can hold the sheet until the chosen portrait exists —\n // otherwise it fuses one from a face nobody picked and pays for it twice.\n faceChoice,\n };\n\n const data = await writeAvatars<AvatarsCreateResponse>(\"/api/avatars\", body);\n writeJson({ ok: true, data, hints: creationHints({ ...data, faceChoice }, body.profile) });\n } catch (err) {\n failAvatarApi(err, handle);\n }\n },\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/commands/avatars/create.ts"],"sourcesContent":["import { AVATAR_HANDLE_PATTERN, type AvatarsCreateRequest, type AvatarsCreateResponse } from \"@baker/api\";\nimport { defineCommand } from \"citty\";\nimport { writeJson } from \"../../output.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport { chatIdFromEnv, creationHints, parseFaceChoice } from \"./casting.ts\";\nimport { failAvatarApi, failValidation } from \"./failures.ts\";\nimport { buildProfilePatch } from \"./profile.ts\";\nimport { writeAvatars } from \"./transport.ts\";\n\nfunction parseImageIds(value: unknown): string[] | undefined {\n if (typeof value !== \"string\") return undefined;\n const ids = value\n .split(\",\")\n .map((id) => id.trim())\n .filter((id) => id.length > 0);\n return ids.length > 0 ? [...new Set(ids)] : undefined;\n}\n\nregisterSchema({\n command: \"avatars.create\",\n description:\n 'Cast a new avatar — a reusable AI presenter this company can put in images and video. Start here: `baker avatars create --name \"Marta\" --subject \"woman in her early 40s, shoulder-length dark hair, warm brown eyes, light olive skin\"`. --subject is the identity: describe ONE person plainly (age, build, hair, skin, face) with no scene, no lighting and no wardrobe, because it is copied word for word into every prompt that renders them. Two kinds: invented from your description (default), or built from photographs of a real person (--source-image with --likeness-confirmed, which is the company stating it may use that person\\'s image in advertising). For a real person the copy NAMES — a testimonial author, the founder, a team member — use `baker avatars research \"<name>, <role> at <company>\" --create` instead: it finds their photos and builds the avatar itself. Returns immediately with status `generating` — the identity sheet is a ~30s render that settles in the background.',\n args: {\n name: { type: \"string\", description: 'Display name, e.g. \"Marta\"', required: true },\n handle: {\n type: \"string\",\n description: 'Mention handle (lowercase, dashes), e.g. \"marta\". Derived from the name when omitted.',\n required: false,\n },\n subject: {\n type: \"string\",\n description:\n \"The identity, reused verbatim in every render: one person, plainly described (age, build, hair, skin, face). No scene, no lighting, no camera, no wardrobe — those belong in the render prompt or in --wardrobe/--setting.\",\n required: true,\n },\n persona: { type: \"string\", description: \"Who they are on camera — role, attitude, energy\", required: false },\n speech: { type: \"string\", description: \"How they speak — pace, register, verbal habits\", required: false },\n accent: {\n type: \"string\",\n description:\n \"Where their VOICE is from, as a place: 'Spanish from Spain, Madrid accent', 'Mexican Spanish', 'British English, London'. Name the region — an adjective like 'clear Spanish accent' is read by the video model as NO accent, and the clip comes out sounding like nowhere. Default to the language the USER is writing to you in, always: they are describing an ad for their own market, and an avatar that answers them in another language is unusable however good it looks. Never take this from how the person LOOKS — 'aspecto europeo', 'Nordic', 'Mediterranean' describe a face and belong in --subject. Read literally, that mistake shipped an ad for a Spanish client with --accent \\\"German\\\", and the clip came back spoken in German.\",\n required: false,\n },\n motion: { type: \"string\", description: \"Body language and gesture in video\", required: false },\n wardrobe: { type: \"string\", description: \"Default outfit when the brief does not name one\", required: false },\n setting: {\n type: \"string\",\n description:\n 'Where they are in their own life (\"her small kitchen in Madrid on a weekday morning\") — their casting photo is taken there, and renders use it when the brief leaves the surroundings open. Always fill it: a face with no world comes back looking like a studio headshot.',\n required: false,\n },\n guardrails: {\n type: \"string\",\n description: 'Comma-separated things this avatar must never do, e.g. \"no competitor logos, no medical claims\"',\n required: false,\n },\n \"source-image\": {\n type: \"string\",\n description:\n \"Comma-separated library image ids (up to 6) of photographs of a REAL person to build the likeness from. Requires --likeness-confirmed. Source them with `baker images upload`/`library` first.\",\n required: false,\n },\n \"likeness-confirmed\": {\n type: \"boolean\",\n description:\n \"The company's statement that it may use this real person's image in advertising. Required with --source-image. Pass it when the user gave you the photos, or the person is someone the company features in its own marketing (its founder, its team, a customer quoted by name) — that request is the statement; there is no separate question to ask.\",\n required: false,\n },\n face: {\n type: \"string\",\n description:\n \"Who picks the face, for an invented avatar: 'ask' (default) blocks on the user through `request_avatar_casting`, 'auto' keeps the one this build casts and asks nobody. Use 'auto' only when there is no one to answer — a Schedule, a batch, an explicit \\\"do it yourself\\\" — because a person who is there almost always wants this choice.\",\n required: false,\n },\n output: {\n type: \"string\",\n description:\n \"Output format. Only `json`, which is what this returns anyway — accepted because `avatars list` and `avatars get` take it, so reaching for it here is the obvious guess.\",\n required: false,\n default: \"json\",\n },\n },\n});\n\nexport const createCommand = defineCommand({\n meta: {\n name: \"create\",\n description:\n 'Cast a new avatar (reusable AI presenter). Example: baker avatars create --name \"Marta\" --subject \"woman in her early 40s, shoulder-length dark hair, light olive skin, warm open face\" --persona \"friendly product expert\". Returns while the identity sheet is still building.',\n },\n args: {\n name: { type: \"string\", description: \"Display name\", required: false },\n handle: { type: \"string\", description: \"Mention handle (derived from the name when omitted)\", required: false },\n subject: { type: \"string\", description: \"The person, plainly described — reused verbatim\", required: false },\n persona: { type: \"string\", description: \"Who they are on camera\", required: false },\n speech: { type: \"string\", description: \"How they speak\", required: false },\n accent: {\n type: \"string\",\n description: \"Where their voice is FROM — name the region, e.g. 'Spanish from Spain, Madrid accent'\",\n required: false,\n },\n motion: { type: \"string\", description: \"Body language in video\", required: false },\n wardrobe: { type: \"string\", description: \"Default outfit\", required: false },\n setting: { type: \"string\", description: \"Default surroundings\", required: false },\n guardrails: { type: \"string\", description: \"Comma-separated things they must never do\", required: false },\n \"source-image\": {\n type: \"string\",\n description: \"Comma-separated library image ids of a real person (needs --likeness-confirmed)\",\n required: false,\n },\n \"likeness-confirmed\": {\n type: \"boolean\",\n description: \"The company may use this real person's image in advertising\",\n required: false,\n default: false,\n },\n face: {\n type: \"string\",\n description:\n \"Who picks the face of an invented avatar: 'ask' (default, blocks on the user) or 'auto' (asks nobody)\",\n required: false,\n },\n output: {\n type: \"string\",\n description: \"Output format — `json` only, which is what this returns anyway\",\n required: false,\n default: \"json\",\n },\n },\n run: async ({ args }) => {\n const name = (args.name as string | undefined)?.trim();\n if (!name) {\n failValidation('--name is required, e.g. `baker avatars create --name \"Marta\" --subject \"…\"`.');\n }\n\n const profile = buildProfilePatch(args);\n const subjectDescription = profile.subjectDescription;\n if (!subjectDescription) {\n failValidation(\n \"--subject is required: it is the identity every render of this avatar is built from, and it is copied into each prompt word for word.\",\n {\n action: \"describe_the_person\",\n explanation:\n 'Write one person, plainly: age range, build, hair, skin, face, anything distinctive. No scene, no lighting, no camera, no wardrobe. Good: \"woman in her early 40s, shoulder-length dark brown hair, light olive skin, warm open face, slight smile lines\". Bad: \"confident businesswoman in a sunlit office\". If the user described a real person and you have their photos, pass --source-image with --likeness-confirmed instead of inventing the description; if they are named but you have no photos, run `baker avatars research \"<name>, <role> at <company>\" --create`.',\n },\n );\n }\n\n const handle = (args.handle as string | undefined)?.trim().toLowerCase();\n if (handle && !AVATAR_HANDLE_PATTERN.test(handle)) {\n failValidation(\n `--handle \"${handle}\" is not usable. Use lowercase letters, numbers and dashes, starting with a letter — \"maria-founder\", not \"Maria Founder\". Leave it off to have one derived from the name.`,\n );\n }\n\n // Accepted rather than refused, because refusing it cost a whole create: the command\n // was rejected for this flag alone, the agent retried without it, and the retry landed\n // while the casting for the first attempt was still pending — so the avatar that DID\n // get made never got a face picker. `create` has one shape of output; saying so is\n // cheaper than being right about it.\n const output = (args.output as string | undefined)?.trim().toLowerCase();\n if (output && output !== \"json\") {\n failValidation(\n `\\`--output ${output}\\` is not a format \\`baker avatars create\\` produces — it returns JSON and nothing else. Drop the flag, or pass \\`--output json\\`. \\`baker avatars list\\` and \\`baker avatars get\\` are the ones that also render \\`files\\` and \\`md\\`.`,\n );\n }\n\n const faceChoice = parseFaceChoice(args.face as string | undefined);\n if (faceChoice === null) {\n failValidation(\n `--face \"${String(args.face)}\" is not a mode. Use --face ask to let the user pick the face, or --face auto to keep the one this build casts.`,\n {\n action: \"pick_a_mode\",\n explanation:\n \"Drop the flag entirely if a person is in the conversation — that is --face ask, and it is what they almost always want. Pass --face auto only when nobody is there to answer: a Schedule, a batch run, or the user telling you to do it without them.\",\n },\n );\n }\n\n const sourceImageIds = parseImageIds(args[\"source-image\"]);\n const likenessConfirmed = Boolean(args[\"likeness-confirmed\"]);\n if (sourceImageIds && !likenessConfirmed) {\n failValidation(\n \"Building an avatar from photographs of a real person needs --likeness-confirmed: the company has to state that it may use that person's image in its advertising.\",\n {\n action: \"confirm_the_likeness\",\n explanation:\n 'Photos the user handed you, or of someone the company features in its own marketing (its founder, its team, a customer it quotes by name), come with that statement: re-run the same command with --likeness-confirmed. If the person is named in the copy and you have no photos, use `baker avatars research \"<name>, <role> at <company>\" --create` instead. Only if the user said they may NOT use this person\\'s image, drop --source-image and cast an invented presenter from --subject — do not abandon the wider job over it.',\n },\n );\n }\n\n try {\n const body: AvatarsCreateRequest = {\n name,\n ...(handle ? { handle } : {}),\n profile: { ...profile, subjectDescription },\n ...(sourceImageIds ? { sourceImageIds, likenessConfirmed: true } : {}),\n ...(chatIdFromEnv() ? { chatId: chatIdFromEnv() } : {}),\n // Sent so the backend can hold the sheet until the chosen portrait exists —\n // otherwise it fuses one from a face nobody picked and pays for it twice.\n faceChoice,\n };\n\n const data = await writeAvatars<AvatarsCreateResponse>(\"/api/avatars\", body);\n writeJson({ ok: true, data, hints: creationHints({ ...data, faceChoice }, body.profile) });\n } catch (err) {\n failAvatarApi(err, handle);\n }\n },\n});\n"],"mappings":"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","names":[]}
@@ -11,11 +11,12 @@ import {
11
11
  reactionBody,
12
12
  refuseAutoPublish,
13
13
  slackBody
14
- } from "./chunk-IR6D7K4H.js";
15
- import "./chunk-XF4JUKVF.js";
14
+ } from "./chunk-I3ZR655O.js";
15
+ import "./chunk-7EPXVICM.js";
16
16
  import "./chunk-GXDLWBOY.js";
17
17
  import "./chunk-TEINLN64.js";
18
18
  import "./chunk-ZJWUBJYQ.js";
19
+ import "./chunk-HR6IWNKE.js";
19
20
  import "./chunk-NE4F3FHN.js";
20
21
  import {
21
22
  apiPost
@@ -127,4 +128,4 @@ var createCommand = defineCommand({
127
128
  export {
128
129
  createCommand
129
130
  };
130
- //# sourceMappingURL=create-RM7HV77Y.js.map
131
+ //# sourceMappingURL=create-JCA7JPLP.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/scheduled-agents/create.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { apiPost } from \"../../client.ts\";\nimport { requireChatId } from \"../../env.ts\";\nimport { writeJson } from \"../../output.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport {\n AUTO_PUBLISH_ARG,\n buildTriggerBody,\n failApi,\n failValidation,\n NARROWING_ARGS,\n REACTION_ARGS,\n reactionBody,\n refuseAutoPublish,\n SLACK_ARG,\n slackBody,\n TRIGGER_ARG_DESCRIPTION,\n TRIGGER_KIND_LIST,\n} from \"./shared.ts\";\n\nregisterSchema({\n command: \"scheduled-agents.create\",\n description:\n \"Stage a scheduled agent: a trigger and a prompt. Applies when the chat is published and returns a temp_agent_* ID. Start here: `baker scheduled-agents triggers` lists everything that can start one.\",\n args: {\n name: { type: \"string\", description: \"What a person will call it in the list\", required: true },\n description: { type: \"string\", description: \"One line under the name. Not read by the run.\", required: true },\n prompt: {\n type: \"string\",\n description:\n \"What the run does, in full. This IS the job — nothing else is resolved when it fires. Write it as you would write a message to an agent.\",\n required: true,\n },\n cron: { type: \"string\", description: \"5-field cron expression; implies --trigger time.cron\", required: false },\n \"run-at\": {\n type: \"string\",\n description:\n \"Run once at this ISO UTC timestamp ending in Z; implies --trigger time.once. Must still be in the future — a time that has passed is refused.\",\n required: false,\n },\n trigger: { type: \"string\", description: TRIGGER_ARG_DESCRIPTION, required: false, enum: TRIGGER_KIND_LIST },\n ...NARROWING_ARGS,\n occurrences: {\n type: \"string\",\n description:\n \"Run only on these firings of the trigger, 1-based and comma-separated. `1` is only the first time it ever happens. Omit it to run every time.\",\n required: false,\n },\n ...REACTION_ARGS,\n ...SLACK_ARG,\n timezone: { type: \"string\", description: \"IANA timezone override; defaults to Company Timezone\", required: false },\n disabled: { type: \"boolean\", description: \"Create it switched off\", required: false, default: false },\n template: {\n type: \"string\",\n description:\n \"Start from one of Baker's recipes, by its id from `baker scheduled-agents templates --list`. The recipe's brief is **copied** onto the item, so the person who owns it can read and edit exactly what it will do; anything you pass in --prompt is appended after it. Editing the recipe later does not change an item already built from it.\",\n required: false,\n },\n },\n});\n\nexport const createCommand = defineCommand({\n meta: {\n name: \"create\",\n description:\n 'Stage a scheduled agent. Examples: baker scheduled-agents create --name \"Weekly report\" --description \"...\" --prompt \"...\" --cron \"0 9 * * MON\" | baker scheduled-agents create --name \"Chase a new lead\" --description \"...\" --prompt \"Research {{payload.answers.company}} and draft a reply\" --trigger form.submitted --form quote | baker scheduled-agents create --name \"Big deals\" --description \"...\" --prompt \"...\" --trigger webhook.received --when \"deal.stage = won AND deal.amount > 10000\" --times 3',\n },\n args: {\n name: { type: \"string\", description: \"What a person will call it\", required: false },\n description: { type: \"string\", description: \"One line under the name\", required: false },\n prompt: { type: \"string\", description: \"What the run does, in full\", required: false },\n cron: { type: \"string\", description: \"5-field cron expression\", required: false },\n \"run-at\": { type: \"string\", description: \"ISO UTC timestamp ending in Z, still in the future\", required: false },\n trigger: { type: \"string\", description: `One of: ${TRIGGER_KIND_LIST.join(\", \")}`, required: false },\n ...NARROWING_ARGS,\n occurrences: { type: \"string\", description: \"Only these firings, e.g. 1 or 1,3\", required: false },\n ...REACTION_ARGS,\n ...SLACK_ARG,\n timezone: { type: \"string\", description: \"IANA timezone override\", required: false },\n disabled: { type: \"boolean\", description: \"Create it switched off\", required: false, default: false },\n template: { type: \"string\", description: \"Recipe id to start from\", required: false },\n\n ...AUTO_PUBLISH_ARG,\n },\n run: async ({ args }) => {\n try {\n refuseAutoPublish(args);\n const name = args.name as string | undefined;\n const description = args.description as string | undefined;\n const prompt = args.prompt as string | undefined;\n const template = typeof args.template === \"string\" ? args.template.trim() : \"\";\n if (!name || name.trim().length === 0) {\n failValidation(\"--name is required.\");\n }\n if (!description || description.trim().length === 0) {\n failValidation(\"--description is required.\");\n }\n // A recipe brings its own brief, so `--prompt` is what this company adds to\n // it rather than the whole job. Without one there is nothing to run.\n if (template.length === 0 && (!prompt || prompt.trim().length === 0)) {\n failValidation(\"--prompt is required: it is the whole of what a run does. Or pass --template to copy a brief.\");\n }\n const trigger = buildTriggerBody(args, { required: true });\n const reaction = reactionBody(args);\n const body: Record<string, unknown> = {\n chatId: requireChatId(),\n name,\n description,\n enabled: !args.disabled,\n ...trigger,\n ...(prompt ? { prompt } : {}),\n ...reaction,\n ...slackBody(args),\n ...(template.length > 0 ? { templateId: template } : {}),\n };\n const response = await apiPost<{ ok: true; data: { tempId: string } }>(\"/api/scheduled-agents/create\", body);\n writeJson(response);\n } catch (err) {\n failApi(err);\n }\n },\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/commands/scheduled-agents/create.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { apiPost } from \"../../client.ts\";\nimport { requireChatId } from \"../../env.ts\";\nimport { writeJson } from \"../../output.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport {\n AUTO_PUBLISH_ARG,\n buildTriggerBody,\n failApi,\n failValidation,\n NARROWING_ARGS,\n REACTION_ARGS,\n reactionBody,\n refuseAutoPublish,\n SLACK_ARG,\n slackBody,\n TRIGGER_ARG_DESCRIPTION,\n TRIGGER_KIND_LIST,\n} from \"./shared.ts\";\n\nregisterSchema({\n command: \"scheduled-agents.create\",\n description:\n \"Stage a scheduled agent: a trigger and a prompt. Applies when the chat is published and returns a temp_agent_* ID. Start here: `baker scheduled-agents triggers` lists everything that can start one.\",\n args: {\n name: { type: \"string\", description: \"What a person will call it in the list\", required: true },\n description: { type: \"string\", description: \"One line under the name. Not read by the run.\", required: true },\n prompt: {\n type: \"string\",\n description:\n \"What the run does, in full. This IS the job — nothing else is resolved when it fires. Write it as you would write a message to an agent.\",\n required: true,\n },\n cron: { type: \"string\", description: \"5-field cron expression; implies --trigger time.cron\", required: false },\n \"run-at\": {\n type: \"string\",\n description:\n \"Run once at this ISO UTC timestamp ending in Z; implies --trigger time.once. Must still be in the future — a time that has passed is refused.\",\n required: false,\n },\n trigger: { type: \"string\", description: TRIGGER_ARG_DESCRIPTION, required: false, enum: TRIGGER_KIND_LIST },\n ...NARROWING_ARGS,\n occurrences: {\n type: \"string\",\n description:\n \"Run only on these firings of the trigger, 1-based and comma-separated. `1` is only the first time it ever happens. Omit it to run every time.\",\n required: false,\n },\n ...REACTION_ARGS,\n ...SLACK_ARG,\n timezone: { type: \"string\", description: \"IANA timezone override; defaults to Company Timezone\", required: false },\n disabled: { type: \"boolean\", description: \"Create it switched off\", required: false, default: false },\n template: {\n type: \"string\",\n description:\n \"Start from one of Baker's recipes, by its id from `baker scheduled-agents templates --list`. The recipe's brief is **copied** onto the item, so the person who owns it can read and edit exactly what it will do; anything you pass in --prompt is appended after it. Editing the recipe later does not change an item already built from it.\",\n required: false,\n },\n },\n});\n\nexport const createCommand = defineCommand({\n meta: {\n name: \"create\",\n description:\n 'Stage a scheduled agent. Examples: baker scheduled-agents create --name \"Weekly report\" --description \"...\" --prompt \"...\" --cron \"0 9 * * MON\" | baker scheduled-agents create --name \"Chase a new lead\" --description \"...\" --prompt \"Research {{payload.answers.company}} and draft a reply\" --trigger form.submitted --form quote | baker scheduled-agents create --name \"Big deals\" --description \"...\" --prompt \"...\" --trigger webhook.received --when \"deal.stage = won AND deal.amount > 10000\" --times 3',\n },\n args: {\n name: { type: \"string\", description: \"What a person will call it\", required: false },\n description: { type: \"string\", description: \"One line under the name\", required: false },\n prompt: { type: \"string\", description: \"What the run does, in full\", required: false },\n cron: { type: \"string\", description: \"5-field cron expression\", required: false },\n \"run-at\": { type: \"string\", description: \"ISO UTC timestamp ending in Z, still in the future\", required: false },\n trigger: { type: \"string\", description: `One of: ${TRIGGER_KIND_LIST.join(\", \")}`, required: false },\n ...NARROWING_ARGS,\n occurrences: { type: \"string\", description: \"Only these firings, e.g. 1 or 1,3\", required: false },\n ...REACTION_ARGS,\n ...SLACK_ARG,\n timezone: { type: \"string\", description: \"IANA timezone override\", required: false },\n disabled: { type: \"boolean\", description: \"Create it switched off\", required: false, default: false },\n template: { type: \"string\", description: \"Recipe id to start from\", required: false },\n\n ...AUTO_PUBLISH_ARG,\n },\n run: async ({ args }) => {\n try {\n refuseAutoPublish(args);\n const name = args.name as string | undefined;\n const description = args.description as string | undefined;\n const prompt = args.prompt as string | undefined;\n const template = typeof args.template === \"string\" ? args.template.trim() : \"\";\n if (!name || name.trim().length === 0) {\n failValidation(\"--name is required.\");\n }\n if (!description || description.trim().length === 0) {\n failValidation(\"--description is required.\");\n }\n // A recipe brings its own brief, so `--prompt` is what this company adds to\n // it rather than the whole job. Without one there is nothing to run.\n if (template.length === 0 && (!prompt || prompt.trim().length === 0)) {\n failValidation(\"--prompt is required: it is the whole of what a run does. Or pass --template to copy a brief.\");\n }\n const trigger = buildTriggerBody(args, { required: true });\n const reaction = reactionBody(args);\n const body: Record<string, unknown> = {\n chatId: requireChatId(),\n name,\n description,\n enabled: !args.disabled,\n ...trigger,\n ...(prompt ? { prompt } : {}),\n ...reaction,\n ...slackBody(args),\n ...(template.length > 0 ? { templateId: template } : {}),\n };\n const response = await apiPost<{ ok: true; data: { tempId: string } }>(\"/api/scheduled-agents/create\", body);\n writeJson(response);\n } catch (err) {\n failApi(err);\n }\n },\n});\n"],"mappings":"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","names":[]}
@@ -2,11 +2,12 @@ import {
2
2
  failApi,
3
3
  failValidation,
4
4
  writeOk
5
- } from "./chunk-3HJLHTWP.js";
6
- import "./chunk-XF4JUKVF.js";
5
+ } from "./chunk-SJYEY5MV.js";
6
+ import "./chunk-7EPXVICM.js";
7
7
  import "./chunk-GXDLWBOY.js";
8
8
  import "./chunk-TEINLN64.js";
9
9
  import "./chunk-ZJWUBJYQ.js";
10
+ import "./chunk-HR6IWNKE.js";
10
11
  import "./chunk-NE4F3FHN.js";
11
12
  import {
12
13
  apiPost
@@ -56,4 +57,4 @@ var tagsCreateCommand = defineCommand({
56
57
  export {
57
58
  tagsCreateCommand
58
59
  };
59
- //# sourceMappingURL=create-FX4OJ2XF.js.map
60
+ //# sourceMappingURL=create-JFSK4BOP.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/actions/tags/create.ts"],"sourcesContent":["import type { ActionsTagsCreateResponse } from \"@baker/api\";\nimport { defineCommand } from \"citty\";\nimport { apiPost } from \"../../../client.ts\";\nimport { registerSchema } from \"../../../schemas.ts\";\nimport { failApi, failValidation, writeOk } from \"../shared.ts\";\n\nregisterSchema({\n command: \"actions.tags.create\",\n description:\n \"Create a company custom action tag, minting a new slug usable with --tags. The name is slugified (lowercased, spaces→hyphens). Use when no existing tag fits the work.\",\n args: {\n slug: { type: \"string\", description: \"Tag name/slug (e.g. pmax, retargeting)\", required: true },\n description: { type: \"string\", description: \"What this tag means\", required: false },\n },\n});\n\nexport const tagsCreateCommand = defineCommand({\n meta: {\n name: \"create\",\n description:\n 'Create a custom action tag. Example: baker actions tags create --slug pmax --description \"Performance Max work\"',\n },\n args: {\n slug: { type: \"string\", description: \"Tag name/slug\", required: false },\n description: { type: \"string\", description: \"Description\", required: false },\n },\n run: async ({ args }) => {\n try {\n const slug = args.slug as string | undefined;\n if (!slug || slug.trim().length === 0) {\n failValidation(\"--slug is required.\");\n }\n const response = await apiPost<ActionsTagsCreateResponse>(\"/api/actions/tags/create\", {\n name: slug,\n description: args.description,\n });\n writeOk(response.data);\n } catch (err) {\n failApi(err);\n }\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AACA,SAAS,qBAAqB;AAK9B,eAAe;AAAA,EACb,SAAS;AAAA,EACT,aACE;AAAA,EACF,MAAM;AAAA,IACJ,MAAM,EAAE,MAAM,UAAU,aAAa,0CAA0C,UAAU,KAAK;AAAA,IAC9F,aAAa,EAAE,MAAM,UAAU,aAAa,uBAAuB,UAAU,MAAM;AAAA,EACrF;AACF,CAAC;AAEM,IAAM,oBAAoB,cAAc;AAAA,EAC7C,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aACE;AAAA,EACJ;AAAA,EACA,MAAM;AAAA,IACJ,MAAM,EAAE,MAAM,UAAU,aAAa,iBAAiB,UAAU,MAAM;AAAA,IACtE,aAAa,EAAE,MAAM,UAAU,aAAa,eAAe,UAAU,MAAM;AAAA,EAC7E;AAAA,EACA,KAAK,OAAO,EAAE,KAAK,MAAM;AACvB,QAAI;AACF,YAAM,OAAO,KAAK;AAClB,UAAI,CAAC,QAAQ,KAAK,KAAK,EAAE,WAAW,GAAG;AACrC,uBAAe,qBAAqB;AAAA,MACtC;AACA,YAAM,WAAW,MAAM,QAAmC,4BAA4B;AAAA,QACpF,MAAM;AAAA,QACN,aAAa,KAAK;AAAA,MACpB,CAAC;AACD,cAAQ,SAAS,IAAI;AAAA,IACvB,SAAS,KAAK;AACZ,cAAQ,GAAG;AAAA,IACb;AAAA,EACF;AACF,CAAC;","names":[]}
1
+ {"version":3,"sources":["../src/commands/actions/tags/create.ts"],"sourcesContent":["import type { ActionsTagsCreateResponse } from \"@baker/api\";\nimport { defineCommand } from \"citty\";\nimport { apiPost } from \"../../../client.ts\";\nimport { registerSchema } from \"../../../schemas.ts\";\nimport { failApi, failValidation, writeOk } from \"../shared.ts\";\n\nregisterSchema({\n command: \"actions.tags.create\",\n description:\n \"Create a company custom action tag, minting a new slug usable with --tags. The name is slugified (lowercased, spaces→hyphens). Use when no existing tag fits the work.\",\n args: {\n slug: { type: \"string\", description: \"Tag name/slug (e.g. pmax, retargeting)\", required: true },\n description: { type: \"string\", description: \"What this tag means\", required: false },\n },\n});\n\nexport const tagsCreateCommand = defineCommand({\n meta: {\n name: \"create\",\n description:\n 'Create a custom action tag. Example: baker actions tags create --slug pmax --description \"Performance Max work\"',\n },\n args: {\n slug: { type: \"string\", description: \"Tag name/slug\", required: false },\n description: { type: \"string\", description: \"Description\", required: false },\n },\n run: async ({ args }) => {\n try {\n const slug = args.slug as string | undefined;\n if (!slug || slug.trim().length === 0) {\n failValidation(\"--slug is required.\");\n }\n const response = await apiPost<ActionsTagsCreateResponse>(\"/api/actions/tags/create\", {\n name: slug,\n description: args.description,\n });\n writeOk(response.data);\n } catch (err) {\n failApi(err);\n }\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AACA,SAAS,qBAAqB;AAK9B,eAAe;AAAA,EACb,SAAS;AAAA,EACT,aACE;AAAA,EACF,MAAM;AAAA,IACJ,MAAM,EAAE,MAAM,UAAU,aAAa,0CAA0C,UAAU,KAAK;AAAA,IAC9F,aAAa,EAAE,MAAM,UAAU,aAAa,uBAAuB,UAAU,MAAM;AAAA,EACrF;AACF,CAAC;AAEM,IAAM,oBAAoB,cAAc;AAAA,EAC7C,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aACE;AAAA,EACJ;AAAA,EACA,MAAM;AAAA,IACJ,MAAM,EAAE,MAAM,UAAU,aAAa,iBAAiB,UAAU,MAAM;AAAA,IACtE,aAAa,EAAE,MAAM,UAAU,aAAa,eAAe,UAAU,MAAM;AAAA,EAC7E;AAAA,EACA,KAAK,OAAO,EAAE,KAAK,MAAM;AACvB,QAAI;AACF,YAAM,OAAO,KAAK;AAClB,UAAI,CAAC,QAAQ,KAAK,KAAK,EAAE,WAAW,GAAG;AACrC,uBAAe,qBAAqB;AAAA,MACtC;AACA,YAAM,WAAW,MAAM,QAAmC,4BAA4B;AAAA,QACpF,MAAM;AAAA,QACN,aAAa,KAAK;AAAA,MACpB,CAAC;AACD,cAAQ,SAAS,IAAI;AAAA,IACvB,SAAS,KAAK;AACZ,cAAQ,GAAG;AAAA,IACb;AAAA,EACF;AACF,CAAC;","names":[]}
@@ -16,13 +16,14 @@ import {
16
16
  generateTempId,
17
17
  parsePriority,
18
18
  parseTagList
19
- } from "./chunk-3HJLHTWP.js";
19
+ } from "./chunk-SJYEY5MV.js";
20
20
  import {
21
21
  actionTempIdSchema
22
- } from "./chunk-XF4JUKVF.js";
22
+ } from "./chunk-7EPXVICM.js";
23
23
  import "./chunk-GXDLWBOY.js";
24
24
  import "./chunk-TEINLN64.js";
25
25
  import "./chunk-ZJWUBJYQ.js";
26
+ import "./chunk-HR6IWNKE.js";
26
27
  import "./chunk-NE4F3FHN.js";
27
28
  import {
28
29
  apiPost
@@ -232,4 +233,4 @@ var createCommand = defineCommand({
232
233
  export {
233
234
  createCommand
234
235
  };
235
- //# sourceMappingURL=create-VXM34ZWH.js.map
236
+ //# sourceMappingURL=create-WU22YYU2.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/actions/create.ts","../src/commands/actions/advisory.ts"],"sourcesContent":["import { type ActionsCreateResponse, actionTempIdSchema } from \"@baker/api\";\nimport { defineCommand } from \"citty\";\nimport { apiPost } from \"../../client.ts\";\nimport { requireChatId } from \"../../env.ts\";\nimport { writeJson } from \"../../output.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport { advisoryHint, jevTaskJudge } from \"./advisory.ts\";\nimport {\n ACTION_PRIORITIES,\n buildCreateHints,\n failApi,\n failValidation,\n generateTempId,\n parsePriority,\n parseTagList,\n} from \"./shared.ts\";\n\nregisterSchema({\n command: \"actions.create\",\n description:\n \"Stage creation of a new action (applies when the chat is published). Returns a tempId you can use to link in the same draft. Pass --tags (REQUIRED — run `baker actions tags list` for the taxonomy) and --priority (one of urgent|high|medium|low — drives the dependency-aware 'Do first' ordering). After creating, check if this action blocks or is blocked by other actions and wire dependencies with `baker actions link`.\",\n args: {\n name: { type: \"string\", description: \"Action name (short, action-verb, ≤6 words)\", required: true },\n description: {\n type: \"string\",\n description:\n \"Context-complete description in markdown: what / why / where / done-when. Use `##` headings for those sections, `-` bullets for lists of items, and `**bold**` for the figures that drive the decision. Anything longer than a couple of sentences needs headings — it is read in a narrow panel.\",\n required: false,\n },\n tags: {\n type: \"string\",\n description:\n \"Comma-separated tag slugs (e.g. google-ads,audit-finding). Must be known — see `baker actions tags list`.\",\n required: false,\n },\n priority: {\n type: \"string\",\n description: `User priority for the do-first ordering. One of: ${ACTION_PRIORITIES.join(\", \")}.`,\n required: false,\n },\n \"temp-id\": {\n type: \"string\",\n description:\n \"Custom tempId — must start with `temp_` (e.g. temp_hero_copy). Auto-generated if omitted; omitting it is fine.\",\n required: false,\n },\n },\n});\n\nexport const createCommand = defineCommand({\n meta: {\n name: \"create\",\n description:\n 'Stage a new action. Applies when the chat is published. Example: baker actions create --name \"Build hero\"',\n },\n args: {\n name: { type: \"string\", description: \"Action name\", required: false },\n description: { type: \"string\", description: \"Description\", required: false, default: \"\" },\n tags: { type: \"string\", description: \"Comma-separated tag slugs (see `baker actions tags list`)\", required: false },\n priority: { type: \"string\", description: `User priority: ${ACTION_PRIORITIES.join(\"|\")}`, required: false },\n \"temp-id\": { type: \"string\", description: \"Optional custom tempId (must start with `temp_`)\", required: false },\n },\n run: async ({ args }) => {\n try {\n const name = args.name as string | undefined;\n if (!name || name.trim().length === 0) {\n failValidation(\"--name is required.\");\n }\n // Check the args the agent typed before anything about the environment:\n // a bad --temp-id must report itself, not hide behind a missing chat id.\n // Refusing here rather than at publish is the point — `temp_` is what\n // tells a staged Task apart from a published action id in every later\n // command, and by publish time the draft is already written.\n const customTempId = args[\"temp-id\"] as string | undefined;\n if (customTempId) {\n const parsed = actionTempIdSchema.safeParse(customTempId);\n if (!parsed.success) {\n failValidation(parsed.error.issues[0]?.message ?? \"Invalid --temp-id.\");\n }\n }\n const chatId = requireChatId();\n const tempId = customTempId || generateTempId();\n const tags = parseTagList(args.tags);\n // Create doesn't support clearing — there's nothing to clear yet. Reject\n // \"none\"/empty so the agent doesn't think it just unset something.\n const priority = parsePriority(args.priority, { allowClear: false });\n const description = (args.description as string) ?? \"\";\n const [response, advisory] = await Promise.all([\n apiPost<ActionsCreateResponse>(\"/api/actions/create\", {\n chatId,\n tempId,\n name,\n description,\n ...(tags ? { tags } : {}),\n ...(priority !== undefined && priority !== null ? { priority } : {}),\n }),\n advisoryHint(name, description, jevTaskJudge),\n ]);\n\n writeJson({\n ...response,\n hints: buildCreateHints({\n advisory,\n description,\n tempId,\n tags,\n prioritySet: priority !== undefined,\n draftCreateCount: response.data.draftCreateCount ?? 0,\n }),\n });\n } catch (err) {\n failApi(err);\n }\n },\n});\n","/**\n * The one advisory hint `baker actions create` returns about the Task itself: it reads as\n * recurring work (a Scheduled agent), or as work a surface of this chat executes now. A Task is\n * the exception, not the default. The agent names Tasks in the marketer's language, so the\n * decision model reads the name and description in whatever language they are in\n * (docs/decision-model.md). Advisory only: a wrong hint costs one line, a missing one costs a\n * Task that should not exist.\n */\nimport { askJev } from \"../../engine/nodes/local/lib/jev.ts\";\nimport type { ReviewUsage } from \"../../engine/nodes/local/lib/render-review.ts\";\nimport { holdWorkspaceSpend } from \"../canvas/unbilled-spend.ts\";\n\nexport const EXECUTABLE_SURFACES = [\n \"ask-user\",\n \"analysis\",\n \"ads-write\",\n \"tag-manager\",\n \"site-tags\",\n \"landing\",\n \"flow\",\n] as const;\nexport type ExecutableSurface = (typeof EXECUTABLE_SURFACES)[number];\n\nexport const SCHEDULED_HINT =\n 'This reads as recurring/scheduled work. If it should run on a cadence or a future date, create a Scheduled agent instead — baker scheduled-agents create --cron \"0 9 * * MON\" (or --run-at, or --trigger for a reaction rather than a clock; guide: `__tooling__/docs/tools/baker/scheduled-agents.md`). Do not capture \"set up a schedule\" as a Work Action.';\n\n// A surface is asked as one or more questions, the highest kept: one judgment per question reads\n// better than one long question listing everything a surface covers.\ntype Surface = { questions: readonly string[]; hint: string };\n\nconst SURFACES: Readonly<Record<ExecutableSurface, Surface>> = {\n \"ask-user\": {\n questions: [\n \"Does `task` say the work cannot go ahead until the client or user gives or confirms one specific value, such as a production domain, an account ID or credentials? Work that is blocked for any other reason is not.\",\n ],\n hint: \"This is a missing input, not blocked work. Ask for it with AskUserQuestion (one question), then do the work in the same turn — filing the Task AND asking the question is the same request twice.\",\n },\n analysis: {\n questions: [\n \"Is the work `task` names itself an investigation: to audit, review, analyse, verify, check, document or research something, where the result is a finding rather than a change?\",\n ],\n hint: \"This names the analysis itself — investigating, auditing and documenting are work you do now, not work you file. Run it in this chat and deliver the finding; a Task is for a fix something genuinely blocks (bar: `__tooling__/docs/tools/baker/actions.md`).\",\n },\n \"ads-write\": {\n // The platform often goes unnamed (\"6 new WhatsApp campaigns\" are Google Ads campaigns).\n questions: [\n \"Is `task` a change to the settings of paid ad campaigns or ad sets: location targeting, ad schedule, audiences or audience signals, bids, tracking URL templates or final URLs?\",\n \"Is `task` setting, applying, raising, lowering or capping the budget of paid ad campaigns or ad sets? Approving a budget is not.\",\n \"Is `task` a change to what paid ads say or show: ad copy, search ad (RSA) headlines or descriptions, display paths, claims in the ads, callouts, sitelinks, structured snippets or other ad extensions?\",\n \"Is `task` a change to the keywords of paid search campaigns: adding keywords, match types or negative keywords? Work that needs another company's permission first is not.\",\n \"Is `task` pausing, launching, enabling, duplicating, pruning, reweighting or restructuring paid ad campaigns, ad sets or ads, or labelling them? Getting a decision or an approval is not.\",\n ],\n hint: \"This is an ad-platform change the write surface covers — stage it now with `baker ads google|meta|linkedin` and it applies at publish (guides: `__tooling__/docs/tools/baker/ads-google.md`, `__tooling__/docs/tools/baker/ads-meta.md`, `__tooling__/docs/tools/baker/ads-linkedin.md`). Staging is not going live.\",\n },\n \"tag-manager\": {\n questions: [\n \"Is `task` a change inside the Google Tag Manager container: its tags, triggers, variables, data layer events, consent settings, GA4 events or conversion measurement? Server-side tagging, or hosting, is not.\",\n ],\n hint: \"This is a change inside the GTM container — `baker tag-manager` stages it now and it applies at publish (guide: `__tooling__/docs/tools/baker/tag-manager.md`). Stage it instead of filing it, and if several container fixes really are blocked, they belong in ONE Task, not one per finding.\",\n },\n \"site-tags\": {\n questions: [\n \"Is `task` installing, configuring or removing a tracking script, pixel or tag on the website pages (a Meta pixel and its Conversions API events, Clarity, Hotjar, a HubSpot tracking code, a LinkedIn Insight tag)? A server-side setup on the company's own domain is not.\",\n ],\n hint: \"This is a tag or script on the site — it goes through the `request_tag_input` approval form in this chat, which also collects any secret values (guide: `__tooling__/docs/tools/baker/tags.md`). Show the form instead of filing a Task.\",\n },\n landing: {\n questions: [\n \"Is `task` building or editing a page of the website or a landing page: its copy, hero, headline, sections or layout? A headline of an ad, or a page only mentioned as the cause of another problem, is not.\",\n ],\n hint: \"This is a page change — build it in this chat with the `/landing` skill. Only file it if something outside the page blocks the work.\",\n },\n flow: {\n questions: [\"Is `task` changing how a form behaves: its steps, branching logic, or the redirect after it is sent?\"],\n hint: \"This is form behaviour — change it in this chat with the `/flow-builder` skill. Only file it if something outside the form blocks the work.\",\n },\n};\n\n// Two shapes of the same answer, the higher kept.\nconst SCHEDULED_QUESTIONS = [\n \"Does `task` ask for work to be done again and again on a schedule (every day, every week, each Monday, monthly)? A month or period that only says what the work is about is not.\",\n \"Does `task` ask to be reminded, or for work to be done, at a later date or moment (before a launch, on a given day)? A month or date that only names the period the work is about is not.\",\n];\n\n/**\n * The bands, measured 2026-10-07 on 74 Task names and descriptions, verbatim from production chats\n * and in five languages (scripts/task-routing-evals, 74/74 on three runs). Recurring or reminder\n * work scored 0.66 or more and one-off work 0.38 or less; the surface that executes a Task 0.59 or\n * more, and Tasks no surface executes (an approval, server-side hosting, a CRM integration) 0.40\n * or less on every surface.\n */\nexport const ROUTING_BANDS = { scheduled: 0.5, surface: 0.5 } as const;\n\n/** The decision model's reading of one Task: the probability it is recurring, and that each surface executes it. */\nexport type TaskReading = { scheduled: number; surfaces: Readonly<Record<ExecutableSurface, number>> };\n\n/** Reads a Task; null when no judgment came back. */\nexport type TaskJudge = (task: string) => Promise<TaskReading | null>;\n\n/** The decision model as the judge: one Noul per question, all in one request. */\nexport const jevTaskJudge: TaskJudge = async (task) => {\n const groups: ReadonlyArray<readonly string[]> = [\n SCHEDULED_QUESTIONS,\n ...EXECUTABLE_SURFACES.map((s) => SURFACES[s].questions),\n ];\n const spent: ReviewUsage[] = [];\n const answers = await askJev(\n groups.flat().map((question) => ({ instructions: { task, question } })),\n (usage) => spent.push(usage),\n );\n await holdWorkspaceSpend(spent);\n if (answers === null) return null;\n let next = 0;\n const [scheduled = 0, ...surfaces] = groups.map((group) => Math.max(...group.map(() => answers[next++] ?? 0)));\n return {\n scheduled,\n surfaces: Object.fromEntries(EXECUTABLE_SURFACES.map((s, i) => [s, surfaces[i] ?? 0])) as Record<\n ExecutableSurface,\n number\n >,\n };\n};\n\nexport type AdvisoryHint =\n | { kind: \"scheduled\"; hint: string }\n | { kind: \"executable\"; surface: ExecutableSurface; hint: string };\n\n/**\n * One advisory hint, never two. A recurring GTM review is both; the scheduled redirect is the more\n * specific instruction, and two hints would tell the agent to do different things with one Task.\n * Pure.\n */\nexport function hintFor(reading: TaskReading): AdvisoryHint | null {\n if (reading.scheduled >= ROUTING_BANDS.scheduled) return { kind: \"scheduled\", hint: SCHEDULED_HINT };\n // A missing input beats the surface next to it: asking and then doing is one turn.\n if (reading.surfaces[\"ask-user\"] >= ROUTING_BANDS.surface) {\n return { kind: \"executable\", surface: \"ask-user\", hint: SURFACES[\"ask-user\"].hint };\n }\n let best: { surface: ExecutableSurface; p: number } | null = null;\n for (const surface of EXECUTABLE_SURFACES) {\n const p = reading.surfaces[surface];\n if (p >= ROUTING_BANDS.surface && (best === null || p > best.p)) best = { surface, p };\n }\n return best ? { kind: \"executable\", surface: best.surface, hint: SURFACES[best.surface].hint } : null;\n}\n\n/** The Task as the decision model reads it: its name, then its description. */\nexport function taskText(name: string, description: string): string {\n return description.trim() ? `${name.trim()}\\n\\n${description.trim()}` : name.trim();\n}\n\n/** The advisory hint for a staged Task; none when the decision model gives no judgment. */\nexport async function advisoryHint(name: string, description: string, judge: TaskJudge): Promise<AdvisoryHint | null> {\n const reading = await judge(taskText(name, description)).catch(() => null);\n return reading === null ? null : hintFor(reading);\n}\n\n/** Every hint above points the agent somewhere; a test asserts each referenced doc still exists. */\nexport function executableSurfaceHints(): string[] {\n return EXECUTABLE_SURFACES.map((s) => SURFACES[s].hint);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/commands/actions/create.ts","../src/commands/actions/advisory.ts"],"sourcesContent":["import { type ActionsCreateResponse, actionTempIdSchema } from \"@baker/api\";\nimport { defineCommand } from \"citty\";\nimport { apiPost } from \"../../client.ts\";\nimport { requireChatId } from \"../../env.ts\";\nimport { writeJson } from \"../../output.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport { advisoryHint, jevTaskJudge } from \"./advisory.ts\";\nimport {\n ACTION_PRIORITIES,\n buildCreateHints,\n failApi,\n failValidation,\n generateTempId,\n parsePriority,\n parseTagList,\n} from \"./shared.ts\";\n\nregisterSchema({\n command: \"actions.create\",\n description:\n \"Stage creation of a new action (applies when the chat is published). Returns a tempId you can use to link in the same draft. Pass --tags (REQUIRED — run `baker actions tags list` for the taxonomy) and --priority (one of urgent|high|medium|low — drives the dependency-aware 'Do first' ordering). After creating, check if this action blocks or is blocked by other actions and wire dependencies with `baker actions link`.\",\n args: {\n name: { type: \"string\", description: \"Action name (short, action-verb, ≤6 words)\", required: true },\n description: {\n type: \"string\",\n description:\n \"Context-complete description in markdown: what / why / where / done-when. Use `##` headings for those sections, `-` bullets for lists of items, and `**bold**` for the figures that drive the decision. Anything longer than a couple of sentences needs headings — it is read in a narrow panel.\",\n required: false,\n },\n tags: {\n type: \"string\",\n description:\n \"Comma-separated tag slugs (e.g. google-ads,audit-finding). Must be known — see `baker actions tags list`.\",\n required: false,\n },\n priority: {\n type: \"string\",\n description: `User priority for the do-first ordering. One of: ${ACTION_PRIORITIES.join(\", \")}.`,\n required: false,\n },\n \"temp-id\": {\n type: \"string\",\n description:\n \"Custom tempId — must start with `temp_` (e.g. temp_hero_copy). Auto-generated if omitted; omitting it is fine.\",\n required: false,\n },\n },\n});\n\nexport const createCommand = defineCommand({\n meta: {\n name: \"create\",\n description:\n 'Stage a new action. Applies when the chat is published. Example: baker actions create --name \"Build hero\"',\n },\n args: {\n name: { type: \"string\", description: \"Action name\", required: false },\n description: { type: \"string\", description: \"Description\", required: false, default: \"\" },\n tags: { type: \"string\", description: \"Comma-separated tag slugs (see `baker actions tags list`)\", required: false },\n priority: { type: \"string\", description: `User priority: ${ACTION_PRIORITIES.join(\"|\")}`, required: false },\n \"temp-id\": { type: \"string\", description: \"Optional custom tempId (must start with `temp_`)\", required: false },\n },\n run: async ({ args }) => {\n try {\n const name = args.name as string | undefined;\n if (!name || name.trim().length === 0) {\n failValidation(\"--name is required.\");\n }\n // Check the args the agent typed before anything about the environment:\n // a bad --temp-id must report itself, not hide behind a missing chat id.\n // Refusing here rather than at publish is the point — `temp_` is what\n // tells a staged Task apart from a published action id in every later\n // command, and by publish time the draft is already written.\n const customTempId = args[\"temp-id\"] as string | undefined;\n if (customTempId) {\n const parsed = actionTempIdSchema.safeParse(customTempId);\n if (!parsed.success) {\n failValidation(parsed.error.issues[0]?.message ?? \"Invalid --temp-id.\");\n }\n }\n const chatId = requireChatId();\n const tempId = customTempId || generateTempId();\n const tags = parseTagList(args.tags);\n // Create doesn't support clearing — there's nothing to clear yet. Reject\n // \"none\"/empty so the agent doesn't think it just unset something.\n const priority = parsePriority(args.priority, { allowClear: false });\n const description = (args.description as string) ?? \"\";\n const [response, advisory] = await Promise.all([\n apiPost<ActionsCreateResponse>(\"/api/actions/create\", {\n chatId,\n tempId,\n name,\n description,\n ...(tags ? { tags } : {}),\n ...(priority !== undefined && priority !== null ? { priority } : {}),\n }),\n advisoryHint(name, description, jevTaskJudge),\n ]);\n\n writeJson({\n ...response,\n hints: buildCreateHints({\n advisory,\n description,\n tempId,\n tags,\n prioritySet: priority !== undefined,\n draftCreateCount: response.data.draftCreateCount ?? 0,\n }),\n });\n } catch (err) {\n failApi(err);\n }\n },\n});\n","/**\n * The one advisory hint `baker actions create` returns about the Task itself: it reads as\n * recurring work (a Scheduled agent), or as work a surface of this chat executes now. A Task is\n * the exception, not the default. The agent names Tasks in the marketer's language, so the\n * decision model reads the name and description in whatever language they are in\n * (docs/decision-model.md). Advisory only: a wrong hint costs one line, a missing one costs a\n * Task that should not exist.\n */\nimport { askJev } from \"../../engine/nodes/local/lib/jev.ts\";\nimport type { ReviewUsage } from \"../../engine/nodes/local/lib/render-review.ts\";\nimport { holdWorkspaceSpend } from \"../canvas/unbilled-spend.ts\";\n\nexport const EXECUTABLE_SURFACES = [\n \"ask-user\",\n \"analysis\",\n \"ads-write\",\n \"tag-manager\",\n \"site-tags\",\n \"landing\",\n \"flow\",\n] as const;\nexport type ExecutableSurface = (typeof EXECUTABLE_SURFACES)[number];\n\nexport const SCHEDULED_HINT =\n 'This reads as recurring/scheduled work. If it should run on a cadence or a future date, create a Scheduled agent instead — baker scheduled-agents create --cron \"0 9 * * MON\" (or --run-at, or --trigger for a reaction rather than a clock; guide: `__tooling__/docs/tools/baker/scheduled-agents.md`). Do not capture \"set up a schedule\" as a Work Action.';\n\n// A surface is asked as one or more questions, the highest kept: one judgment per question reads\n// better than one long question listing everything a surface covers.\ntype Surface = { questions: readonly string[]; hint: string };\n\nconst SURFACES: Readonly<Record<ExecutableSurface, Surface>> = {\n \"ask-user\": {\n questions: [\n \"Does `task` say the work cannot go ahead until the client or user gives or confirms one specific value, such as a production domain, an account ID or credentials? Work that is blocked for any other reason is not.\",\n ],\n hint: \"This is a missing input, not blocked work. Ask for it with AskUserQuestion (one question), then do the work in the same turn — filing the Task AND asking the question is the same request twice.\",\n },\n analysis: {\n questions: [\n \"Is the work `task` names itself an investigation: to audit, review, analyse, verify, check, document or research something, where the result is a finding rather than a change?\",\n ],\n hint: \"This names the analysis itself — investigating, auditing and documenting are work you do now, not work you file. Run it in this chat and deliver the finding; a Task is for a fix something genuinely blocks (bar: `__tooling__/docs/tools/baker/actions.md`).\",\n },\n \"ads-write\": {\n // The platform often goes unnamed (\"6 new WhatsApp campaigns\" are Google Ads campaigns).\n questions: [\n \"Is `task` a change to the settings of paid ad campaigns or ad sets: location targeting, ad schedule, audiences or audience signals, bids, tracking URL templates or final URLs?\",\n \"Is `task` setting, applying, raising, lowering or capping the budget of paid ad campaigns or ad sets? Approving a budget is not.\",\n \"Is `task` a change to what paid ads say or show: ad copy, search ad (RSA) headlines or descriptions, display paths, claims in the ads, callouts, sitelinks, structured snippets or other ad extensions?\",\n \"Is `task` a change to the keywords of paid search campaigns: adding keywords, match types or negative keywords? Work that needs another company's permission first is not.\",\n \"Is `task` pausing, launching, enabling, duplicating, pruning, reweighting or restructuring paid ad campaigns, ad sets or ads, or labelling them? Getting a decision or an approval is not.\",\n ],\n hint: \"This is an ad-platform change the write surface covers — stage it now with `baker ads google|meta|linkedin` and it applies at publish (guides: `__tooling__/docs/tools/baker/ads-google.md`, `__tooling__/docs/tools/baker/ads-meta.md`, `__tooling__/docs/tools/baker/ads-linkedin.md`). Staging is not going live.\",\n },\n \"tag-manager\": {\n questions: [\n \"Is `task` a change inside the Google Tag Manager container: its tags, triggers, variables, data layer events, consent settings, GA4 events or conversion measurement? Server-side tagging, or hosting, is not.\",\n ],\n hint: \"This is a change inside the GTM container — `baker tag-manager` stages it now and it applies at publish (guide: `__tooling__/docs/tools/baker/tag-manager.md`). Stage it instead of filing it, and if several container fixes really are blocked, they belong in ONE Task, not one per finding.\",\n },\n \"site-tags\": {\n questions: [\n \"Is `task` installing, configuring or removing a tracking script, pixel or tag on the website pages (a Meta pixel and its Conversions API events, Clarity, Hotjar, a HubSpot tracking code, a LinkedIn Insight tag)? A server-side setup on the company's own domain is not.\",\n ],\n hint: \"This is a tag or script on the site — it goes through the `request_tag_input` approval form in this chat, which also collects any secret values (guide: `__tooling__/docs/tools/baker/tags.md`). Show the form instead of filing a Task.\",\n },\n landing: {\n questions: [\n \"Is `task` building or editing a page of the website or a landing page: its copy, hero, headline, sections or layout? A headline of an ad, or a page only mentioned as the cause of another problem, is not.\",\n ],\n hint: \"This is a page change — build it in this chat with the `/landing` skill. Only file it if something outside the page blocks the work.\",\n },\n flow: {\n questions: [\"Is `task` changing how a form behaves: its steps, branching logic, or the redirect after it is sent?\"],\n hint: \"This is form behaviour — change it in this chat with the `/flow-builder` skill. Only file it if something outside the form blocks the work.\",\n },\n};\n\n// Two shapes of the same answer, the higher kept.\nconst SCHEDULED_QUESTIONS = [\n \"Does `task` ask for work to be done again and again on a schedule (every day, every week, each Monday, monthly)? A month or period that only says what the work is about is not.\",\n \"Does `task` ask to be reminded, or for work to be done, at a later date or moment (before a launch, on a given day)? A month or date that only names the period the work is about is not.\",\n];\n\n/**\n * The bands, measured 2026-10-07 on 74 Task names and descriptions, verbatim from production chats\n * and in five languages (scripts/task-routing-evals, 74/74 on three runs). Recurring or reminder\n * work scored 0.66 or more and one-off work 0.38 or less; the surface that executes a Task 0.59 or\n * more, and Tasks no surface executes (an approval, server-side hosting, a CRM integration) 0.40\n * or less on every surface.\n */\nexport const ROUTING_BANDS = { scheduled: 0.5, surface: 0.5 } as const;\n\n/** The decision model's reading of one Task: the probability it is recurring, and that each surface executes it. */\nexport type TaskReading = { scheduled: number; surfaces: Readonly<Record<ExecutableSurface, number>> };\n\n/** Reads a Task; null when no judgment came back. */\nexport type TaskJudge = (task: string) => Promise<TaskReading | null>;\n\n/** The decision model as the judge: one Noul per question, all in one request. */\nexport const jevTaskJudge: TaskJudge = async (task) => {\n const groups: ReadonlyArray<readonly string[]> = [\n SCHEDULED_QUESTIONS,\n ...EXECUTABLE_SURFACES.map((s) => SURFACES[s].questions),\n ];\n const spent: ReviewUsage[] = [];\n const answers = await askJev(\n groups.flat().map((question) => ({ instructions: { task, question } })),\n (usage) => spent.push(usage),\n );\n await holdWorkspaceSpend(spent);\n if (answers === null) return null;\n let next = 0;\n const [scheduled = 0, ...surfaces] = groups.map((group) => Math.max(...group.map(() => answers[next++] ?? 0)));\n return {\n scheduled,\n surfaces: Object.fromEntries(EXECUTABLE_SURFACES.map((s, i) => [s, surfaces[i] ?? 0])) as Record<\n ExecutableSurface,\n number\n >,\n };\n};\n\nexport type AdvisoryHint =\n | { kind: \"scheduled\"; hint: string }\n | { kind: \"executable\"; surface: ExecutableSurface; hint: string };\n\n/**\n * One advisory hint, never two. A recurring GTM review is both; the scheduled redirect is the more\n * specific instruction, and two hints would tell the agent to do different things with one Task.\n * Pure.\n */\nexport function hintFor(reading: TaskReading): AdvisoryHint | null {\n if (reading.scheduled >= ROUTING_BANDS.scheduled) return { kind: \"scheduled\", hint: SCHEDULED_HINT };\n // A missing input beats the surface next to it: asking and then doing is one turn.\n if (reading.surfaces[\"ask-user\"] >= ROUTING_BANDS.surface) {\n return { kind: \"executable\", surface: \"ask-user\", hint: SURFACES[\"ask-user\"].hint };\n }\n let best: { surface: ExecutableSurface; p: number } | null = null;\n for (const surface of EXECUTABLE_SURFACES) {\n const p = reading.surfaces[surface];\n if (p >= ROUTING_BANDS.surface && (best === null || p > best.p)) best = { surface, p };\n }\n return best ? { kind: \"executable\", surface: best.surface, hint: SURFACES[best.surface].hint } : null;\n}\n\n/** The Task as the decision model reads it: its name, then its description. */\nexport function taskText(name: string, description: string): string {\n return description.trim() ? `${name.trim()}\\n\\n${description.trim()}` : name.trim();\n}\n\n/** The advisory hint for a staged Task; none when the decision model gives no judgment. */\nexport async function advisoryHint(name: string, description: string, judge: TaskJudge): Promise<AdvisoryHint | null> {\n const reading = await judge(taskText(name, description)).catch(() => null);\n return reading === null ? null : hintFor(reading);\n}\n\n/** Every hint above points the agent somewhere; a test asserts each referenced doc still exists. */\nexport function executableSurfaceHints(): string[] {\n return EXECUTABLE_SURFACES.map((s) => SURFACES[s].hint);\n}\n"],"mappings":"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","names":[]}
@@ -34,18 +34,18 @@ How published creatives are doing in live Meta ads (results, fatigue, angle; hoo
34
34
  Full guide: __tooling__/docs/tools/baker/creatives.md`
35
35
  },
36
36
  subCommands: {
37
- brief: () => import("./brief-YFJHQ5VQ.js").then((m) => m.briefCommand),
38
- ideas: () => import("./ideas-MIDU7YOA.js").then((m) => m.ideasCommand),
39
- make: () => import("./make-J3WBO62B.js").then((m) => m.makeCommand),
40
- translate: () => import("./translate-Z66FDB4K.js").then((m) => m.translateCommand),
41
- learn: () => import("./learn-FUQSY7DN.js").then((m) => m.learnCommand),
42
- feedback: () => import("./feedback-PPQMOQ46.js").then((m) => m.feedbackCommand),
43
- select: () => import("./select-AB2L4GAA.js").then((m) => m.selectCommand),
44
- publish: () => import("./publish-HCQ6MXLB.js").then((m) => m.publishCommand),
45
- performance: () => import("./performance-6QW2KEEQ.js").then((m) => m.performanceCommand)
37
+ brief: () => import("./brief-OSFJ2V7F.js").then((m) => m.briefCommand),
38
+ ideas: () => import("./ideas-NFOW3HKJ.js").then((m) => m.ideasCommand),
39
+ make: () => import("./make-TPKKJXGL.js").then((m) => m.makeCommand),
40
+ translate: () => import("./translate-GXTS633J.js").then((m) => m.translateCommand),
41
+ learn: () => import("./learn-IPULBCOD.js").then((m) => m.learnCommand),
42
+ feedback: () => import("./feedback-EIZKS4JU.js").then((m) => m.feedbackCommand),
43
+ select: () => import("./select-O2FN2JEQ.js").then((m) => m.selectCommand),
44
+ publish: () => import("./publish-NPD3SMZL.js").then((m) => m.publishCommand),
45
+ performance: () => import("./performance-UF5VTY2U.js").then((m) => m.performanceCommand)
46
46
  }
47
47
  });
48
48
  export {
49
49
  creativesCommand
50
50
  };
51
- //# sourceMappingURL=creatives-NJF2U763.js.map
51
+ //# sourceMappingURL=creatives-FXUQ5WSD.js.map
@@ -4,7 +4,7 @@ import {
4
4
  resolveAccountIdArg,
5
5
  resolveStatusFilter,
6
6
  statusesArgDescription
7
- } from "./chunk-CSYSX4D2.js";
7
+ } from "./chunk-N4LAYIIN.js";
8
8
  import {
9
9
  writeAdsOutput,
10
10
  writeJsonEnvelope
@@ -15,10 +15,11 @@ import {
15
15
  import {
16
16
  shapeListRows
17
17
  } from "./chunk-KIGGMKAE.js";
18
- import "./chunk-XF4JUKVF.js";
18
+ import "./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
  apiGet
@@ -162,11 +163,11 @@ Examples:
162
163
  },
163
164
  subCommands: {
164
165
  list: creativesListCommand,
165
- create: () => import("./write-commands-5C7FUOVN.js").then((m) => m.creativesCreateCommand),
166
- update: () => import("./write-commands-5C7FUOVN.js").then((m) => m.creativesUpdateCommand),
167
- pause: () => import("./write-commands-5C7FUOVN.js").then((m) => m.creativesPauseCommand),
168
- resume: () => import("./write-commands-5C7FUOVN.js").then((m) => m.creativesResumeCommand),
169
- duplicate: () => import("./write-commands-5C7FUOVN.js").then((m) => m.creativesDuplicateCommand)
166
+ create: () => import("./write-commands-7SJ3BOW5.js").then((m) => m.creativesCreateCommand),
167
+ update: () => import("./write-commands-7SJ3BOW5.js").then((m) => m.creativesUpdateCommand),
168
+ pause: () => import("./write-commands-7SJ3BOW5.js").then((m) => m.creativesPauseCommand),
169
+ resume: () => import("./write-commands-7SJ3BOW5.js").then((m) => m.creativesResumeCommand),
170
+ duplicate: () => import("./write-commands-7SJ3BOW5.js").then((m) => m.creativesDuplicateCommand)
170
171
  },
171
172
  // A parent must never declare `run`: citty falls through to it *after* running
172
173
  // the matched subcommand, so every write would also trigger a full live list.
@@ -179,4 +180,4 @@ export {
179
180
  creativesCommand,
180
181
  unmappedShapeWarnings
181
182
  };
182
- //# sourceMappingURL=creatives-JSWBFQ5R.js.map
183
+ //# sourceMappingURL=creatives-KGXUOYPE.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/ads/linkedin/creatives.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { NO_CACHE_ARG } from \"../../../cache-flag.ts\";\nimport { apiGet } from \"../../../client.ts\";\nimport { shapeListRows } from \"../list-rows.ts\";\nimport { writeAdsOutput, writeJsonEnvelope } from \"../output.ts\";\nimport type { AdsWarning } from \"../types.ts\";\nimport {\n csvOrJson,\n handleLinkedinError,\n resolveAccountIdArg,\n resolveStatusFilter,\n statusesArgDescription,\n} from \"./shared.ts\";\n\ninterface LinkedinCreativeRow {\n id: string;\n urn: string;\n account: string;\n campaign?: string;\n intendedStatus?: string;\n isServing?: boolean;\n reviewStatus?: string;\n type?: string;\n content?: Record<string, unknown>;\n createdAt?: number;\n}\n\n/**\n * The shape of a creative's `content` depends on its format, and LinkedIn wraps\n * each one differently. Callers overwhelmingly want one thing from it — where\n * the ad sends people — so resolve that here instead of making every reader\n * re-learn the union.\n *\n * Post-based ads (image, video, carousel, document, article, event, TLA) only\n * carry a post reference: their destination lives inside the post and is not\n * readable — or writable — through the ads API.\n */\nexport interface CreativeDestination {\n format: string;\n landingUrl?: string;\n postUrn?: string;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nexport function creativeDestination(content: Record<string, unknown> | undefined): CreativeDestination {\n if (!content) return { format: \"unknown\" };\n\n const reference = asString(content.reference);\n if (reference) return { format: \"post\", postUrn: reference };\n\n const textAd = asRecord(content.textAd);\n if (textAd) return { format: \"text\", landingUrl: asString(textAd.landingPage) };\n\n const spotlight = asRecord(content.spotlight);\n if (spotlight) return { format: \"spotlight\", landingUrl: asString(spotlight.landingPage) };\n\n if (asRecord(content.follower)) return { format: \"follower\" };\n if (asRecord(content.jobs)) return { format: \"jobs\" };\n\n return { format: \"unknown\" };\n}\n\n/**\n * Every column a compact row can carry, in order. `compactRow` omits the destination\n * keys it has no value for, so the tabular writers cannot infer the header from a row:\n * a first row that is post-based would drop `landingUrl` from every later row.\n */\nconst COMPACT_COLUMNS = [\n \"id\",\n \"urn\",\n \"campaign\",\n \"intendedStatus\",\n \"isServing\",\n \"reviewStatus\",\n \"format\",\n \"landingUrl\",\n \"postUrn\",\n] as const;\n\n/** The fields worth spending context on by default — everything else needs --fields or --full. */\nfunction compactRow(row: LinkedinCreativeRow): Record<string, unknown> {\n const destination = creativeDestination(row.content);\n return {\n id: row.id,\n urn: row.urn,\n campaign: row.campaign,\n intendedStatus: row.intendedStatus,\n isServing: row.isServing,\n reviewStatus: row.reviewStatus,\n format: destination.format,\n ...(destination.landingUrl ? { landingUrl: destination.landingUrl } : {}),\n ...(destination.postUrn ? { postUrn: destination.postUrn } : {}),\n };\n}\n\n/**\n * `content` crosses the wire as an unvalidated bag, so if LinkedIn renames a\n * wrapper key nothing else in the stack would notice — the destination would\n * just quietly stop resolving. Counting the shapes this mapper couldn't read is\n * the cheapest signal that the contract moved.\n */\nexport function unmappedShapeWarnings(rows: LinkedinCreativeRow[], rawContentReturned: boolean): AdsWarning[] {\n const unmapped = rows.filter((row) => row.content && creativeDestination(row.content).format === \"unknown\");\n if (unmapped.length === 0) return [];\n // Under --full the caller already holds the raw `content`, so \"re-read with\n // --full\" is a dead end — point them at what they are already holding.\n const remedy = rawContentReturned\n ? \"Their raw content is in this response — read it directly; this command cannot resolve a destination for them.\"\n : \"Re-read those with --full before drawing any conclusion about where they point.\";\n return [\n {\n code: \"UNMAPPED_CREATIVE_CONTENT\",\n message: `${unmapped.length} of ${rows.length} creatives have a content shape this command can't read, so their destination is missing (ids: ${unmapped\n .slice(0, 5)\n .map((row) => row.id)\n .join(\", \")}). ${remedy}`,\n },\n ];\n}\n\nconst listArgs = {\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 \"campaign-id\": { type: \"string\", description: \"Filter by campaign ID\" },\n \"all-statuses\": { type: \"boolean\", description: \"Drop the default ACTIVE filter\" },\n statuses: { type: \"string\", description: statusesArgDescription(\"creatives\") },\n fields: {\n type: \"string\",\n description: \"CSV of dotted paths to return instead of the compact row, e.g. id,content.textAd.landingPage\",\n },\n full: { type: \"boolean\", description: \"Return the complete raw records, including the opaque 'content' block\" },\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} as const;\n\nconst creativesListCommand = defineCommand({\n meta: {\n name: \"list\",\n description: \"List LinkedIn creatives (ads). Runs by default when no subcommand is given.\",\n },\n args: listArgs,\n run: async ({ args }) => {\n const accountId = resolveAccountIdArg(args);\n try {\n const params: Record<string, string> = { \"account-id\": accountId };\n const statuses = resolveStatusFilter(args, \"creatives\");\n if (statuses) params.statuses = statuses.join(\",\");\n if (args[\"campaign-id\"]) params[\"campaign-id\"] = String(args[\"campaign-id\"]);\n if (args.limit) params.limit = String(args.limit);\n if (args[\"no-cache\"]) params[\"skip-cache\"] = \"true\";\n\n const data = await apiGet<LinkedinCreativeRow[]>(\"/api/ads/linkedin/creatives\", params);\n const shaped = shapeListRows(data, args as Record<string, unknown>, {\n row: compactRow,\n columns: COMPACT_COLUMNS,\n });\n const fmt = csvOrJson(args);\n if (fmt !== \"json\") {\n writeAdsOutput(shaped.rows, fmt, shaped.fields, shaped.hints);\n return;\n }\n const warnings = unmappedShapeWarnings(data, args.full === true);\n writeJsonEnvelope({\n ok: true,\n data: shaped.rows,\n ...(warnings.length > 0 ? { warnings } : {}),\n ...(shaped.hints ? { hints: shaped.hints } : {}),\n });\n } catch (err) {\n handleLinkedinError(err);\n }\n },\n});\n\nexport const creativesCommand = defineCommand({\n meta: {\n name: \"creatives\",\n description: `List LinkedIn creatives (ads), or stage writes (create/update/pause/resume/duplicate).\n\nDefaults to ACTIVE intended-status. Pass --all-statuses or --statuses ACTIVE,PAUSED to widen.\n\nRows are compact by default: id, urn, campaign, status, review status, format, and\nthe resolved destination (landingUrl, or postUrn for post-based ads). Use --fields\nfor specific dotted paths, or --full for the complete raw records.\n\nPost-based ads (image, video, carousel, document, article, event, TLA) report a\npostUrn, not a landingUrl — their destination lives in the post itself.\nUse 'reviewStatus' to spot rejected/pending creatives during an audit.\n\nWrite subcommands stage ops on this chat's draft — media comes from the Baker\nlibrary and is uploaded to LinkedIn only at publish.\n\nExamples:\n baker ads linkedin creatives --account-id 503001492\n baker ads linkedin creatives --account-id 503001492 --fields id,intendedStatus,content.textAd.landingPage\n baker ads linkedin creatives create --campaign 1234 --format image --image-id <bakerImageId> --intro \"…\" --headline \"Book a demo\" --landing-url https://example.com --cta REQUEST_DEMO\n baker ads linkedin creatives pause urn:li:sponsoredCreative:789`,\n },\n subCommands: {\n list: creativesListCommand,\n create: () => import(\"./write-commands.ts\").then((m) => m.creativesCreateCommand),\n update: () => import(\"./write-commands.ts\").then((m) => m.creativesUpdateCommand),\n pause: () => import(\"./write-commands.ts\").then((m) => m.creativesPauseCommand),\n resume: () => import(\"./write-commands.ts\").then((m) => m.creativesResumeCommand),\n duplicate: () => import(\"./write-commands.ts\").then((m) => m.creativesDuplicateCommand),\n },\n // A parent must never declare `run`: citty falls through to it *after* running\n // the matched subcommand, so every write would also trigger a full live list.\n // `args` stays here so citty's subcommand scan knows which flags take a value.\n args: listArgs,\n default: \"list\",\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,qBAAqB;AA2C9B,SAAS,SAAS,OAAqD;AACrE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK,IACrE,QACD;AACN;AAEA,SAAS,SAAS,OAAoC;AACpD,SAAO,OAAO,UAAU,YAAY,MAAM,SAAS,IAAI,QAAQ;AACjE;AAEO,SAAS,oBAAoB,SAAmE;AACrG,MAAI,CAAC,QAAS,QAAO,EAAE,QAAQ,UAAU;AAEzC,QAAM,YAAY,SAAS,QAAQ,SAAS;AAC5C,MAAI,UAAW,QAAO,EAAE,QAAQ,QAAQ,SAAS,UAAU;AAE3D,QAAM,SAAS,SAAS,QAAQ,MAAM;AACtC,MAAI,OAAQ,QAAO,EAAE,QAAQ,QAAQ,YAAY,SAAS,OAAO,WAAW,EAAE;AAE9E,QAAM,YAAY,SAAS,QAAQ,SAAS;AAC5C,MAAI,UAAW,QAAO,EAAE,QAAQ,aAAa,YAAY,SAAS,UAAU,WAAW,EAAE;AAEzF,MAAI,SAAS,QAAQ,QAAQ,EAAG,QAAO,EAAE,QAAQ,WAAW;AAC5D,MAAI,SAAS,QAAQ,IAAI,EAAG,QAAO,EAAE,QAAQ,OAAO;AAEpD,SAAO,EAAE,QAAQ,UAAU;AAC7B;AAOA,IAAM,kBAAkB;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,SAAS,WAAW,KAAmD;AACrE,QAAM,cAAc,oBAAoB,IAAI,OAAO;AACnD,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,KAAK,IAAI;AAAA,IACT,UAAU,IAAI;AAAA,IACd,gBAAgB,IAAI;AAAA,IACpB,WAAW,IAAI;AAAA,IACf,cAAc,IAAI;AAAA,IAClB,QAAQ,YAAY;AAAA,IACpB,GAAI,YAAY,aAAa,EAAE,YAAY,YAAY,WAAW,IAAI,CAAC;AAAA,IACvE,GAAI,YAAY,UAAU,EAAE,SAAS,YAAY,QAAQ,IAAI,CAAC;AAAA,EAChE;AACF;AAQO,SAAS,sBAAsB,MAA6B,oBAA2C;AAC5G,QAAM,WAAW,KAAK,OAAO,CAAC,QAAQ,IAAI,WAAW,oBAAoB,IAAI,OAAO,EAAE,WAAW,SAAS;AAC1G,MAAI,SAAS,WAAW,EAAG,QAAO,CAAC;AAGnC,QAAM,SAAS,qBACX,uHACA;AACJ,SAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,SAAS,GAAG,SAAS,MAAM,OAAO,KAAK,MAAM,kGAAkG,SAC5I,MAAM,GAAG,CAAC,EACV,IAAI,CAAC,QAAQ,IAAI,EAAE,EACnB,KAAK,IAAI,CAAC,MAAM,MAAM;AAAA,IAC3B;AAAA,EACF;AACF;AAEA,IAAM,WAAW;AAAA,EACf,cAAc,EAAE,MAAM,UAAU,aAAa,kDAAkD;AAAA,EAC/F,eAAe,EAAE,MAAM,UAAU,aAAa,yBAAyB;AAAA,EACvE,eAAe,EAAE,MAAM,UAAU,aAAa,wBAAwB;AAAA,EACtE,gBAAgB,EAAE,MAAM,WAAW,aAAa,iCAAiC;AAAA,EACjF,UAAU,EAAE,MAAM,UAAU,aAAa,uBAAuB,WAAW,EAAE;AAAA,EAC7E,QAAQ;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,MAAM,EAAE,MAAM,WAAW,aAAa,wEAAwE;AAAA,EAC9G,OAAO,EAAE,MAAM,UAAU,aAAa,0BAA0B;AAAA,EAChE,YAAY;AAAA,EACZ,QAAQ,EAAE,MAAM,UAAU,aAAa,qBAAqB,SAAS,OAAO;AAC9E;AAEA,IAAM,uBAAuB,cAAc;AAAA,EACzC,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,EACN,KAAK,OAAO,EAAE,KAAK,MAAM;AACvB,UAAM,YAAY,oBAAoB,IAAI;AAC1C,QAAI;AACF,YAAM,SAAiC,EAAE,cAAc,UAAU;AACjE,YAAM,WAAW,oBAAoB,MAAM,WAAW;AACtD,UAAI,SAAU,QAAO,WAAW,SAAS,KAAK,GAAG;AACjD,UAAI,KAAK,aAAa,EAAG,QAAO,aAAa,IAAI,OAAO,KAAK,aAAa,CAAC;AAC3E,UAAI,KAAK,MAAO,QAAO,QAAQ,OAAO,KAAK,KAAK;AAChD,UAAI,KAAK,UAAU,EAAG,QAAO,YAAY,IAAI;AAE7C,YAAM,OAAO,MAAM,OAA8B,+BAA+B,MAAM;AACtF,YAAM,SAAS,cAAc,MAAM,MAAiC;AAAA,QAClE,KAAK;AAAA,QACL,SAAS;AAAA,MACX,CAAC;AACD,YAAM,MAAM,UAAU,IAAI;AAC1B,UAAI,QAAQ,QAAQ;AAClB,uBAAe,OAAO,MAAM,KAAK,OAAO,QAAQ,OAAO,KAAK;AAC5D;AAAA,MACF;AACA,YAAM,WAAW,sBAAsB,MAAM,KAAK,SAAS,IAAI;AAC/D,wBAAkB;AAAA,QAChB,IAAI;AAAA,QACJ,MAAM,OAAO;AAAA,QACb,GAAI,SAAS,SAAS,IAAI,EAAE,SAAS,IAAI,CAAC;AAAA,QAC1C,GAAI,OAAO,QAAQ,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,MAChD,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,0BAAoB,GAAG;AAAA,IACzB;AAAA,EACF;AACF,CAAC;AAEM,IAAM,mBAAmB,cAAc;AAAA,EAC5C,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBf;AAAA,EACA,aAAa;AAAA,IACX,MAAM;AAAA,IACN,QAAQ,MAAM,OAAO,8BAAqB,EAAE,KAAK,CAAC,MAAM,EAAE,sBAAsB;AAAA,IAChF,QAAQ,MAAM,OAAO,8BAAqB,EAAE,KAAK,CAAC,MAAM,EAAE,sBAAsB;AAAA,IAChF,OAAO,MAAM,OAAO,8BAAqB,EAAE,KAAK,CAAC,MAAM,EAAE,qBAAqB;AAAA,IAC9E,QAAQ,MAAM,OAAO,8BAAqB,EAAE,KAAK,CAAC,MAAM,EAAE,sBAAsB;AAAA,IAChF,WAAW,MAAM,OAAO,8BAAqB,EAAE,KAAK,CAAC,MAAM,EAAE,yBAAyB;AAAA,EACxF;AAAA;AAAA;AAAA;AAAA,EAIA,MAAM;AAAA,EACN,SAAS;AACX,CAAC;","names":[]}
1
+ {"version":3,"sources":["../src/commands/ads/linkedin/creatives.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { NO_CACHE_ARG } from \"../../../cache-flag.ts\";\nimport { apiGet } from \"../../../client.ts\";\nimport { shapeListRows } from \"../list-rows.ts\";\nimport { writeAdsOutput, writeJsonEnvelope } from \"../output.ts\";\nimport type { AdsWarning } from \"../types.ts\";\nimport {\n csvOrJson,\n handleLinkedinError,\n resolveAccountIdArg,\n resolveStatusFilter,\n statusesArgDescription,\n} from \"./shared.ts\";\n\ninterface LinkedinCreativeRow {\n id: string;\n urn: string;\n account: string;\n campaign?: string;\n intendedStatus?: string;\n isServing?: boolean;\n reviewStatus?: string;\n type?: string;\n content?: Record<string, unknown>;\n createdAt?: number;\n}\n\n/**\n * The shape of a creative's `content` depends on its format, and LinkedIn wraps\n * each one differently. Callers overwhelmingly want one thing from it — where\n * the ad sends people — so resolve that here instead of making every reader\n * re-learn the union.\n *\n * Post-based ads (image, video, carousel, document, article, event, TLA) only\n * carry a post reference: their destination lives inside the post and is not\n * readable — or writable — through the ads API.\n */\nexport interface CreativeDestination {\n format: string;\n landingUrl?: string;\n postUrn?: string;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nexport function creativeDestination(content: Record<string, unknown> | undefined): CreativeDestination {\n if (!content) return { format: \"unknown\" };\n\n const reference = asString(content.reference);\n if (reference) return { format: \"post\", postUrn: reference };\n\n const textAd = asRecord(content.textAd);\n if (textAd) return { format: \"text\", landingUrl: asString(textAd.landingPage) };\n\n const spotlight = asRecord(content.spotlight);\n if (spotlight) return { format: \"spotlight\", landingUrl: asString(spotlight.landingPage) };\n\n if (asRecord(content.follower)) return { format: \"follower\" };\n if (asRecord(content.jobs)) return { format: \"jobs\" };\n\n return { format: \"unknown\" };\n}\n\n/**\n * Every column a compact row can carry, in order. `compactRow` omits the destination\n * keys it has no value for, so the tabular writers cannot infer the header from a row:\n * a first row that is post-based would drop `landingUrl` from every later row.\n */\nconst COMPACT_COLUMNS = [\n \"id\",\n \"urn\",\n \"campaign\",\n \"intendedStatus\",\n \"isServing\",\n \"reviewStatus\",\n \"format\",\n \"landingUrl\",\n \"postUrn\",\n] as const;\n\n/** The fields worth spending context on by default — everything else needs --fields or --full. */\nfunction compactRow(row: LinkedinCreativeRow): Record<string, unknown> {\n const destination = creativeDestination(row.content);\n return {\n id: row.id,\n urn: row.urn,\n campaign: row.campaign,\n intendedStatus: row.intendedStatus,\n isServing: row.isServing,\n reviewStatus: row.reviewStatus,\n format: destination.format,\n ...(destination.landingUrl ? { landingUrl: destination.landingUrl } : {}),\n ...(destination.postUrn ? { postUrn: destination.postUrn } : {}),\n };\n}\n\n/**\n * `content` crosses the wire as an unvalidated bag, so if LinkedIn renames a\n * wrapper key nothing else in the stack would notice — the destination would\n * just quietly stop resolving. Counting the shapes this mapper couldn't read is\n * the cheapest signal that the contract moved.\n */\nexport function unmappedShapeWarnings(rows: LinkedinCreativeRow[], rawContentReturned: boolean): AdsWarning[] {\n const unmapped = rows.filter((row) => row.content && creativeDestination(row.content).format === \"unknown\");\n if (unmapped.length === 0) return [];\n // Under --full the caller already holds the raw `content`, so \"re-read with\n // --full\" is a dead end — point them at what they are already holding.\n const remedy = rawContentReturned\n ? \"Their raw content is in this response — read it directly; this command cannot resolve a destination for them.\"\n : \"Re-read those with --full before drawing any conclusion about where they point.\";\n return [\n {\n code: \"UNMAPPED_CREATIVE_CONTENT\",\n message: `${unmapped.length} of ${rows.length} creatives have a content shape this command can't read, so their destination is missing (ids: ${unmapped\n .slice(0, 5)\n .map((row) => row.id)\n .join(\", \")}). ${remedy}`,\n },\n ];\n}\n\nconst listArgs = {\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 \"campaign-id\": { type: \"string\", description: \"Filter by campaign ID\" },\n \"all-statuses\": { type: \"boolean\", description: \"Drop the default ACTIVE filter\" },\n statuses: { type: \"string\", description: statusesArgDescription(\"creatives\") },\n fields: {\n type: \"string\",\n description: \"CSV of dotted paths to return instead of the compact row, e.g. id,content.textAd.landingPage\",\n },\n full: { type: \"boolean\", description: \"Return the complete raw records, including the opaque 'content' block\" },\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} as const;\n\nconst creativesListCommand = defineCommand({\n meta: {\n name: \"list\",\n description: \"List LinkedIn creatives (ads). Runs by default when no subcommand is given.\",\n },\n args: listArgs,\n run: async ({ args }) => {\n const accountId = resolveAccountIdArg(args);\n try {\n const params: Record<string, string> = { \"account-id\": accountId };\n const statuses = resolveStatusFilter(args, \"creatives\");\n if (statuses) params.statuses = statuses.join(\",\");\n if (args[\"campaign-id\"]) params[\"campaign-id\"] = String(args[\"campaign-id\"]);\n if (args.limit) params.limit = String(args.limit);\n if (args[\"no-cache\"]) params[\"skip-cache\"] = \"true\";\n\n const data = await apiGet<LinkedinCreativeRow[]>(\"/api/ads/linkedin/creatives\", params);\n const shaped = shapeListRows(data, args as Record<string, unknown>, {\n row: compactRow,\n columns: COMPACT_COLUMNS,\n });\n const fmt = csvOrJson(args);\n if (fmt !== \"json\") {\n writeAdsOutput(shaped.rows, fmt, shaped.fields, shaped.hints);\n return;\n }\n const warnings = unmappedShapeWarnings(data, args.full === true);\n writeJsonEnvelope({\n ok: true,\n data: shaped.rows,\n ...(warnings.length > 0 ? { warnings } : {}),\n ...(shaped.hints ? { hints: shaped.hints } : {}),\n });\n } catch (err) {\n handleLinkedinError(err);\n }\n },\n});\n\nexport const creativesCommand = defineCommand({\n meta: {\n name: \"creatives\",\n description: `List LinkedIn creatives (ads), or stage writes (create/update/pause/resume/duplicate).\n\nDefaults to ACTIVE intended-status. Pass --all-statuses or --statuses ACTIVE,PAUSED to widen.\n\nRows are compact by default: id, urn, campaign, status, review status, format, and\nthe resolved destination (landingUrl, or postUrn for post-based ads). Use --fields\nfor specific dotted paths, or --full for the complete raw records.\n\nPost-based ads (image, video, carousel, document, article, event, TLA) report a\npostUrn, not a landingUrl — their destination lives in the post itself.\nUse 'reviewStatus' to spot rejected/pending creatives during an audit.\n\nWrite subcommands stage ops on this chat's draft — media comes from the Baker\nlibrary and is uploaded to LinkedIn only at publish.\n\nExamples:\n baker ads linkedin creatives --account-id 503001492\n baker ads linkedin creatives --account-id 503001492 --fields id,intendedStatus,content.textAd.landingPage\n baker ads linkedin creatives create --campaign 1234 --format image --image-id <bakerImageId> --intro \"…\" --headline \"Book a demo\" --landing-url https://example.com --cta REQUEST_DEMO\n baker ads linkedin creatives pause urn:li:sponsoredCreative:789`,\n },\n subCommands: {\n list: creativesListCommand,\n create: () => import(\"./write-commands.ts\").then((m) => m.creativesCreateCommand),\n update: () => import(\"./write-commands.ts\").then((m) => m.creativesUpdateCommand),\n pause: () => import(\"./write-commands.ts\").then((m) => m.creativesPauseCommand),\n resume: () => import(\"./write-commands.ts\").then((m) => m.creativesResumeCommand),\n duplicate: () => import(\"./write-commands.ts\").then((m) => m.creativesDuplicateCommand),\n },\n // A parent must never declare `run`: citty falls through to it *after* running\n // the matched subcommand, so every write would also trigger a full live list.\n // `args` stays here so citty's subcommand scan knows which flags take a value.\n args: listArgs,\n default: \"list\",\n});\n"],"mappings":"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","names":[]}