@koda-sl/baker-cli 0.385.0-dev.ec7b0e42b → 0.385.0-dev.f7ef4c7e1

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 (963) hide show
  1. package/README.md +1082 -210
  2. package/canvas/tiktok-captions-composition/index.html +5 -6
  3. package/canvas/tiktok-captions-composition/meta.json +5 -0
  4. package/dist/account-4UEZAY5T.js +49 -0
  5. package/dist/account-4UEZAY5T.js.map +1 -0
  6. package/dist/account-G6QK2VXQ.js +79 -0
  7. package/dist/account-G6QK2VXQ.js.map +1 -0
  8. package/dist/account-OINZG6UP.js +80 -0
  9. package/dist/account-OINZG6UP.js.map +1 -0
  10. package/dist/account-reads-ZKKDYHK5.js +218 -0
  11. package/dist/account-reads-ZKKDYHK5.js.map +1 -0
  12. package/dist/account-writes-N4JDIDRB.js +66 -0
  13. package/dist/account-writes-N4JDIDRB.js.map +1 -0
  14. package/dist/accounts-7KRRRVLB.js +611 -0
  15. package/dist/accounts-7KRRRVLB.js.map +1 -0
  16. package/dist/accounts-AEBQFCNH.js +114 -0
  17. package/dist/accounts-AEBQFCNH.js.map +1 -0
  18. package/dist/accounts-CNTOHRQ2.js +77 -0
  19. package/dist/accounts-CNTOHRQ2.js.map +1 -0
  20. package/dist/accounts-HP4BLKK5.js +75 -0
  21. package/dist/accounts-HP4BLKK5.js.map +1 -0
  22. package/dist/accounts-Z4CLGQXJ.js +115 -0
  23. package/dist/accounts-Z4CLGQXJ.js.map +1 -0
  24. package/dist/actions-QO7VQ6UV.js +55 -0
  25. package/dist/actions-QO7VQ6UV.js.map +1 -0
  26. package/dist/active-entities-YB46ADQN.js +103 -0
  27. package/dist/active-entities-YB46ADQN.js.map +1 -0
  28. package/dist/activities-DUAIQJLN.js +74 -0
  29. package/dist/activities-DUAIQJLN.js.map +1 -0
  30. package/dist/ad-group-writes-HL3EZ3BT.js +170 -0
  31. package/dist/ad-group-writes-HL3EZ3BT.js.map +1 -0
  32. package/dist/ad-groups-FGS5JJGN.js +68 -0
  33. package/dist/ad-groups-FGS5JJGN.js.map +1 -0
  34. package/dist/ad-writes-LX4ACUHB.js +174 -0
  35. package/dist/ad-writes-LX4ACUHB.js.map +1 -0
  36. package/dist/add-5CUXNOUM.js +97 -0
  37. package/dist/add-5CUXNOUM.js.map +1 -0
  38. package/dist/add-5JBMJHNW.js +302 -0
  39. package/dist/add-5JBMJHNW.js.map +1 -0
  40. package/dist/add-E66HBIZV.js +105 -0
  41. package/dist/add-E66HBIZV.js.map +1 -0
  42. package/dist/add-O76R2SPE.js +104 -0
  43. package/dist/add-O76R2SPE.js.map +1 -0
  44. package/dist/add-accounts-YME5SCXD.js +91 -0
  45. package/dist/add-accounts-YME5SCXD.js.map +1 -0
  46. package/dist/ads-65R3WMDU.js +128 -0
  47. package/dist/ads-65R3WMDU.js.map +1 -0
  48. package/dist/ads-O63J7BDF.js +113 -0
  49. package/dist/ads-O63J7BDF.js.map +1 -0
  50. package/dist/ads-T5JWNFSA.js +40 -0
  51. package/dist/ads-T5JWNFSA.js.map +1 -0
  52. package/dist/ads-TFZ5PXKS.js +77 -0
  53. package/dist/ads-TFZ5PXKS.js.map +1 -0
  54. package/dist/adsets-Y62JOOTV.js +176 -0
  55. package/dist/adsets-Y62JOOTV.js.map +1 -0
  56. package/dist/advertisers-LJ2HKJ4W.js +125 -0
  57. package/dist/advertisers-LJ2HKJ4W.js.map +1 -0
  58. package/dist/advertisers-WJW5DK3Q.js +120 -0
  59. package/dist/advertisers-WJW5DK3Q.js.map +1 -0
  60. package/dist/analytics-HIOC3TUK.js +1976 -0
  61. package/dist/analytics-HIOC3TUK.js.map +1 -0
  62. package/dist/analytics-U2NLDV2V.js +433 -0
  63. package/dist/analytics-U2NLDV2V.js.map +1 -0
  64. package/dist/animate-E3SKQ6SI.js +480 -0
  65. package/dist/animate-E3SKQ6SI.js.map +1 -0
  66. package/dist/assign-V7EAR7VD.js +77 -0
  67. package/dist/assign-V7EAR7VD.js.map +1 -0
  68. package/dist/audience-size-GS7EDBDP.js +94 -0
  69. package/dist/audience-size-GS7EDBDP.js.map +1 -0
  70. package/dist/audiences-5A6BCWSA.js +268 -0
  71. package/dist/audiences-5A6BCWSA.js.map +1 -0
  72. package/dist/audiences-6QOCASVV.js +78 -0
  73. package/dist/audiences-6QOCASVV.js.map +1 -0
  74. package/dist/audiences-O67NGIP5.js +85 -0
  75. package/dist/audiences-O67NGIP5.js.map +1 -0
  76. package/dist/audit-HWK24VXI.js +88 -0
  77. package/dist/audit-HWK24VXI.js.map +1 -0
  78. package/dist/audit-WMZERUAA.js +151 -0
  79. package/dist/audit-WMZERUAA.js.map +1 -0
  80. package/dist/autocomplete-KQSTLQFS.js +111 -0
  81. package/dist/autocomplete-KQSTLQFS.js.map +1 -0
  82. package/dist/avatars-HAFQZD63.js +38 -0
  83. package/dist/avatars-HAFQZD63.js.map +1 -0
  84. package/dist/bid-pricing-5SORFAPE.js +99 -0
  85. package/dist/bid-pricing-5SORFAPE.js.map +1 -0
  86. package/dist/brand-EBG436YV.js +22 -0
  87. package/dist/brand-EBG436YV.js.map +1 -0
  88. package/dist/brief-AYXXPTHC.js +490 -0
  89. package/dist/brief-AYXXPTHC.js.map +1 -0
  90. package/dist/businesses-65EWTK5E.js +53 -0
  91. package/dist/businesses-65EWTK5E.js.map +1 -0
  92. package/dist/campaign-groups-U7723BBE.js +95 -0
  93. package/dist/campaign-groups-U7723BBE.js.map +1 -0
  94. package/dist/campaign-writes-CXS4KYB5.js +165 -0
  95. package/dist/campaign-writes-CXS4KYB5.js.map +1 -0
  96. package/dist/campaign-writes-M6JLF5AC.js +170 -0
  97. package/dist/campaign-writes-M6JLF5AC.js.map +1 -0
  98. package/dist/campaigns-6SM2ZSIH.js +76 -0
  99. package/dist/campaigns-6SM2ZSIH.js.map +1 -0
  100. package/dist/campaigns-7DWD2A5U.js +109 -0
  101. package/dist/campaigns-7DWD2A5U.js.map +1 -0
  102. package/dist/campaigns-F66OYA6N.js +107 -0
  103. package/dist/campaigns-F66OYA6N.js.map +1 -0
  104. package/dist/campaigns-TD7ZB5DG.js +110 -0
  105. package/dist/campaigns-TD7ZB5DG.js.map +1 -0
  106. package/dist/canvas-3NYM5Y7G.js +46 -0
  107. package/dist/canvas-3NYM5Y7G.js.map +1 -0
  108. package/dist/capabilities-JNFYSGRD.js +144 -0
  109. package/dist/capabilities-JNFYSGRD.js.map +1 -0
  110. package/dist/cards-7HRC4UQQ.js +85 -0
  111. package/dist/cards-7HRC4UQQ.js.map +1 -0
  112. package/dist/catalog-N6MDMIVL.js +64 -0
  113. package/dist/catalog-N6MDMIVL.js.map +1 -0
  114. package/dist/catalogs-PB46L7FH.js +128 -0
  115. package/dist/catalogs-PB46L7FH.js.map +1 -0
  116. package/dist/changes-SASUQK62.js +135 -0
  117. package/dist/changes-SASUQK62.js.map +1 -0
  118. package/dist/chatgpt-JKBSAG25.js +47 -0
  119. package/dist/chatgpt-JKBSAG25.js.map +1 -0
  120. package/dist/chats-TUZANLQH.js +262 -0
  121. package/dist/chats-TUZANLQH.js.map +1 -0
  122. package/dist/chunk-25E6SC3F.js +363 -0
  123. package/dist/chunk-25E6SC3F.js.map +1 -0
  124. package/dist/chunk-2GVXNKAE.js +42 -0
  125. package/dist/chunk-2GVXNKAE.js.map +1 -0
  126. package/dist/{chunk-WLDM2TRF.js → chunk-2UFRHW3T.js} +4 -4
  127. package/dist/chunk-2Y5V23PU.js +29 -0
  128. package/dist/chunk-2Y5V23PU.js.map +1 -0
  129. package/dist/chunk-35NYNRRB.js +111 -0
  130. package/dist/chunk-35NYNRRB.js.map +1 -0
  131. package/dist/chunk-3ACMDRSE.js +39 -0
  132. package/dist/chunk-3ACMDRSE.js.map +1 -0
  133. package/dist/chunk-3M6RNCDD.js +26 -0
  134. package/dist/chunk-3M6RNCDD.js.map +1 -0
  135. package/dist/chunk-3VXQYDJN.js +1743 -0
  136. package/dist/chunk-3VXQYDJN.js.map +1 -0
  137. package/dist/chunk-42DF5DF3.js +304 -0
  138. package/dist/chunk-42DF5DF3.js.map +1 -0
  139. package/dist/chunk-44VXKO65.js +106 -0
  140. package/dist/chunk-44VXKO65.js.map +1 -0
  141. package/dist/chunk-4NZ47VXO.js +137 -0
  142. package/dist/chunk-4NZ47VXO.js.map +1 -0
  143. package/dist/chunk-4X3UR372.js +225 -0
  144. package/dist/chunk-4X3UR372.js.map +1 -0
  145. package/dist/chunk-5FEBUCJU.js +25 -0
  146. package/dist/chunk-5FEBUCJU.js.map +1 -0
  147. package/dist/chunk-5HYSKH77.js +315 -0
  148. package/dist/chunk-5HYSKH77.js.map +1 -0
  149. package/dist/chunk-5LBGFQWF.js +310 -0
  150. package/dist/chunk-5LBGFQWF.js.map +1 -0
  151. package/dist/chunk-5MBPIONY.js +29 -0
  152. package/dist/chunk-5MBPIONY.js.map +1 -0
  153. package/dist/chunk-6YMHGIHP.js +346 -0
  154. package/dist/chunk-6YMHGIHP.js.map +1 -0
  155. package/dist/{chunk-VZEDAFAR.js → chunk-6YYSUISH.js} +47 -8
  156. package/dist/chunk-6YYSUISH.js.map +1 -0
  157. package/dist/chunk-7GNU3P7X.js +175 -0
  158. package/dist/chunk-7GNU3P7X.js.map +1 -0
  159. package/dist/chunk-7OHWEF3I.js +98 -0
  160. package/dist/chunk-7OHWEF3I.js.map +1 -0
  161. package/dist/chunk-7TR3QVWM.js +57 -0
  162. package/dist/chunk-7TR3QVWM.js.map +1 -0
  163. package/dist/chunk-AADVCEL4.js +817 -0
  164. package/dist/chunk-AADVCEL4.js.map +1 -0
  165. package/dist/chunk-AG62YO7C.js +96 -0
  166. package/dist/chunk-AG62YO7C.js.map +1 -0
  167. package/dist/chunk-AIRIT4GF.js +75 -0
  168. package/dist/chunk-AIRIT4GF.js.map +1 -0
  169. package/dist/chunk-AP3TP6VG.js +139 -0
  170. package/dist/chunk-AP3TP6VG.js.map +1 -0
  171. package/dist/chunk-APP475IQ.js +474 -0
  172. package/dist/chunk-APP475IQ.js.map +1 -0
  173. package/dist/chunk-AR7PU7BB.js +76 -0
  174. package/dist/chunk-AR7PU7BB.js.map +1 -0
  175. package/dist/chunk-B4S72KSS.js +172 -0
  176. package/dist/chunk-B4S72KSS.js.map +1 -0
  177. package/dist/chunk-BIPIL4QA.js +486 -0
  178. package/dist/chunk-BIPIL4QA.js.map +1 -0
  179. package/dist/chunk-BPUSL5Y2.js +58 -0
  180. package/dist/chunk-BPUSL5Y2.js.map +1 -0
  181. package/dist/chunk-BR32GHYD.js +65 -0
  182. package/dist/chunk-BR32GHYD.js.map +1 -0
  183. package/dist/chunk-CAMX6OHF.js +3182 -0
  184. package/dist/chunk-CAMX6OHF.js.map +1 -0
  185. package/dist/chunk-CE7RTOX6.js +494 -0
  186. package/dist/chunk-CE7RTOX6.js.map +1 -0
  187. package/dist/{chunk-MF7YA62W.js → chunk-CUL3VB4L.js} +10 -5
  188. package/dist/chunk-CUL3VB4L.js.map +1 -0
  189. package/dist/chunk-CVEY353K.js +66 -0
  190. package/dist/chunk-CVEY353K.js.map +1 -0
  191. package/dist/chunk-CWXADUKL.js +1599 -0
  192. package/dist/chunk-CWXADUKL.js.map +1 -0
  193. package/dist/chunk-D46NOXRY.js +6212 -0
  194. package/dist/chunk-D46NOXRY.js.map +1 -0
  195. package/dist/chunk-D5FY4FAK.js +24 -0
  196. package/dist/chunk-D5FY4FAK.js.map +1 -0
  197. package/dist/chunk-DGCUPJZD.js +39 -0
  198. package/dist/chunk-DGCUPJZD.js.map +1 -0
  199. package/dist/chunk-DNCLWSHO.js +41 -0
  200. package/dist/chunk-DNCLWSHO.js.map +1 -0
  201. package/dist/chunk-DUPURL26.js +97 -0
  202. package/dist/chunk-DUPURL26.js.map +1 -0
  203. package/dist/chunk-DXJYQ5P2.js +625 -0
  204. package/dist/chunk-DXJYQ5P2.js.map +1 -0
  205. package/dist/chunk-E2ZOSNF5.js +96 -0
  206. package/dist/chunk-E2ZOSNF5.js.map +1 -0
  207. package/dist/chunk-E3HYHT7C.js +274 -0
  208. package/dist/chunk-E3HYHT7C.js.map +1 -0
  209. package/dist/chunk-EDLZGTGN.js +216 -0
  210. package/dist/chunk-EDLZGTGN.js.map +1 -0
  211. package/dist/{chunk-XHC4LMK4.js → chunk-EIGXX6KI.js} +16 -8
  212. package/dist/chunk-EIGXX6KI.js.map +1 -0
  213. package/dist/chunk-EPDE7ZRU.js +174 -0
  214. package/dist/chunk-EPDE7ZRU.js.map +1 -0
  215. package/dist/chunk-ERSX3MKH.js +34 -0
  216. package/dist/chunk-ERSX3MKH.js.map +1 -0
  217. package/dist/chunk-F7HRLPR5.js +67 -0
  218. package/dist/chunk-F7HRLPR5.js.map +1 -0
  219. package/dist/chunk-FEG6MN4H.js +84 -0
  220. package/dist/chunk-FEG6MN4H.js.map +1 -0
  221. package/dist/chunk-FKOECEVC.js +126 -0
  222. package/dist/chunk-FKOECEVC.js.map +1 -0
  223. package/dist/chunk-FMGW2NZI.js +106 -0
  224. package/dist/chunk-FMGW2NZI.js.map +1 -0
  225. package/dist/chunk-FPZKKNDK.js +98 -0
  226. package/dist/chunk-FPZKKNDK.js.map +1 -0
  227. package/dist/chunk-G3ZDLPNZ.js +206 -0
  228. package/dist/chunk-G3ZDLPNZ.js.map +1 -0
  229. package/dist/chunk-GIWHHCD6.js +145 -0
  230. package/dist/chunk-GIWHHCD6.js.map +1 -0
  231. package/dist/chunk-GOJXKIFQ.js +1605 -0
  232. package/dist/chunk-GOJXKIFQ.js.map +1 -0
  233. package/dist/chunk-GRQ2AXDX.js +9 -0
  234. package/dist/chunk-GRQ2AXDX.js.map +1 -0
  235. package/dist/chunk-GXDLWBOY.js +73 -0
  236. package/dist/chunk-GXDLWBOY.js.map +1 -0
  237. package/dist/chunk-HAE4WWFQ.js +455 -0
  238. package/dist/chunk-HAE4WWFQ.js.map +1 -0
  239. package/dist/chunk-HEEAC2YG.js +541 -0
  240. package/dist/chunk-HEEAC2YG.js.map +1 -0
  241. package/dist/chunk-I2DNBEV6.js +4227 -0
  242. package/dist/chunk-I2DNBEV6.js.map +1 -0
  243. package/dist/chunk-I4FTS5EE.js +455 -0
  244. package/dist/chunk-I4FTS5EE.js.map +1 -0
  245. package/dist/chunk-IA4KJU7O.js +3151 -0
  246. package/dist/chunk-IA4KJU7O.js.map +1 -0
  247. package/dist/chunk-IELPT4K2.js +74 -0
  248. package/dist/chunk-IELPT4K2.js.map +1 -0
  249. package/dist/chunk-IJMWEO4P.js +57 -0
  250. package/dist/chunk-IJMWEO4P.js.map +1 -0
  251. package/dist/chunk-IVIJJXXT.js +62 -0
  252. package/dist/chunk-IVIJJXXT.js.map +1 -0
  253. package/dist/chunk-JAU6OAFK.js +455 -0
  254. package/dist/chunk-JAU6OAFK.js.map +1 -0
  255. package/dist/chunk-JD3W3ON7.js +188 -0
  256. package/dist/chunk-JD3W3ON7.js.map +1 -0
  257. package/dist/chunk-JLWBK3VC.js +5187 -0
  258. package/dist/chunk-JLWBK3VC.js.map +1 -0
  259. package/dist/chunk-JPK34QPS.js +134 -0
  260. package/dist/chunk-JPK34QPS.js.map +1 -0
  261. package/dist/chunk-JXJD6RC5.js +169 -0
  262. package/dist/chunk-JXJD6RC5.js.map +1 -0
  263. package/dist/chunk-JXMZEOHV.js +333 -0
  264. package/dist/chunk-JXMZEOHV.js.map +1 -0
  265. package/dist/chunk-K6TDB2KV.js +1442 -0
  266. package/dist/chunk-K6TDB2KV.js.map +1 -0
  267. package/dist/chunk-KIGGMKAE.js +66 -0
  268. package/dist/chunk-KIGGMKAE.js.map +1 -0
  269. package/dist/chunk-KKJ4KJCW.js +29 -0
  270. package/dist/chunk-KKJ4KJCW.js.map +1 -0
  271. package/dist/chunk-KONA5PSR.js +55 -0
  272. package/dist/chunk-KONA5PSR.js.map +1 -0
  273. package/dist/chunk-KVHRW7KO.js +60 -0
  274. package/dist/chunk-KVHRW7KO.js.map +1 -0
  275. package/dist/chunk-LA6PPSNA.js +65 -0
  276. package/dist/chunk-LA6PPSNA.js.map +1 -0
  277. package/dist/chunk-LKPJADL2.js +74 -0
  278. package/dist/chunk-LKPJADL2.js.map +1 -0
  279. package/dist/chunk-LM7N7IQR.js +297 -0
  280. package/dist/chunk-LM7N7IQR.js.map +1 -0
  281. package/dist/chunk-LWAEHLKV.js +74 -0
  282. package/dist/chunk-LWAEHLKV.js.map +1 -0
  283. package/dist/chunk-M6UNISGO.js +66 -0
  284. package/dist/chunk-M6UNISGO.js.map +1 -0
  285. package/dist/chunk-MFSIACRB.js +207 -0
  286. package/dist/chunk-MFSIACRB.js.map +1 -0
  287. package/dist/chunk-MIJAGBEP.js +23992 -0
  288. package/dist/chunk-MIJAGBEP.js.map +1 -0
  289. package/dist/chunk-MYTDK3AL.js +2102 -0
  290. package/dist/chunk-MYTDK3AL.js.map +1 -0
  291. package/dist/chunk-MYURCD23.js +6667 -0
  292. package/dist/chunk-MYURCD23.js.map +1 -0
  293. package/dist/chunk-MZQ5DX6S.js +125 -0
  294. package/dist/chunk-MZQ5DX6S.js.map +1 -0
  295. package/dist/chunk-NFSLRRIE.js +77 -0
  296. package/dist/chunk-NFSLRRIE.js.map +1 -0
  297. package/dist/chunk-NMDP7FZP.js +479 -0
  298. package/dist/chunk-NMDP7FZP.js.map +1 -0
  299. package/dist/chunk-NMGELUIA.js +183 -0
  300. package/dist/chunk-NMGELUIA.js.map +1 -0
  301. package/dist/chunk-NOK7MSVJ.js +533 -0
  302. package/dist/chunk-NOK7MSVJ.js.map +1 -0
  303. package/dist/chunk-O2EVJALZ.js +133 -0
  304. package/dist/chunk-O2EVJALZ.js.map +1 -0
  305. package/dist/chunk-OIL6PU5W.js +35 -0
  306. package/dist/chunk-OIL6PU5W.js.map +1 -0
  307. package/dist/chunk-P4NSJS54.js +20 -0
  308. package/dist/chunk-P4NSJS54.js.map +1 -0
  309. package/dist/chunk-P5T7OZKV.js +26 -0
  310. package/dist/chunk-P5T7OZKV.js.map +1 -0
  311. package/dist/chunk-PFBQERWX.js +10 -0
  312. package/dist/chunk-PFBQERWX.js.map +1 -0
  313. package/dist/chunk-PSWVSLJU.js +56 -0
  314. package/dist/chunk-PSWVSLJU.js.map +1 -0
  315. package/dist/chunk-PY2NJ6XZ.js +191 -0
  316. package/dist/chunk-PY2NJ6XZ.js.map +1 -0
  317. package/dist/chunk-PZ4OM2LK.js +45 -0
  318. package/dist/chunk-PZ4OM2LK.js.map +1 -0
  319. package/dist/chunk-Q2EKN7NI.js +1079 -0
  320. package/dist/chunk-Q2EKN7NI.js.map +1 -0
  321. package/dist/chunk-Q6ULQMWG.js +41 -0
  322. package/dist/chunk-Q6ULQMWG.js.map +1 -0
  323. package/dist/chunk-QMLGJ5OW.js +2891 -0
  324. package/dist/chunk-QMLGJ5OW.js.map +1 -0
  325. package/dist/chunk-R7QV5N2S.js +846 -0
  326. package/dist/chunk-R7QV5N2S.js.map +1 -0
  327. package/dist/chunk-RCS4JKUD.js +23 -0
  328. package/dist/chunk-RCS4JKUD.js.map +1 -0
  329. package/dist/chunk-RR3KT2E7.js +665 -0
  330. package/dist/chunk-RR3KT2E7.js.map +1 -0
  331. package/dist/chunk-SEPPFM5S.js +228 -0
  332. package/dist/chunk-SEPPFM5S.js.map +1 -0
  333. package/dist/chunk-SQ7DRYCC.js +150 -0
  334. package/dist/chunk-SQ7DRYCC.js.map +1 -0
  335. package/dist/chunk-SYULM665.js +610 -0
  336. package/dist/chunk-SYULM665.js.map +1 -0
  337. package/dist/chunk-TKT3OHZ6.js +170 -0
  338. package/dist/chunk-TKT3OHZ6.js.map +1 -0
  339. package/dist/chunk-TNOSX3PJ.js +136 -0
  340. package/dist/chunk-TNOSX3PJ.js.map +1 -0
  341. package/dist/chunk-TTVKI54A.js +160 -0
  342. package/dist/chunk-TTVKI54A.js.map +1 -0
  343. package/dist/chunk-U55UZRIB.js +592 -0
  344. package/dist/chunk-U55UZRIB.js.map +1 -0
  345. package/dist/chunk-UI6BKYQD.js +225 -0
  346. package/dist/chunk-UI6BKYQD.js.map +1 -0
  347. package/dist/chunk-UKE4IZSA.js +337 -0
  348. package/dist/chunk-UKE4IZSA.js.map +1 -0
  349. package/dist/chunk-UKLDW4UW.js +46 -0
  350. package/dist/chunk-UKLDW4UW.js.map +1 -0
  351. package/dist/chunk-V6XXXEXZ.js +76 -0
  352. package/dist/chunk-V6XXXEXZ.js.map +1 -0
  353. package/dist/chunk-VCZSZCXY.js +197 -0
  354. package/dist/chunk-VCZSZCXY.js.map +1 -0
  355. package/dist/chunk-VJQWUF66.js +92 -0
  356. package/dist/chunk-VJQWUF66.js.map +1 -0
  357. package/dist/chunk-VSU5R34H.js +76 -0
  358. package/dist/chunk-VSU5R34H.js.map +1 -0
  359. package/dist/chunk-W4SA4CMR.js +296 -0
  360. package/dist/chunk-W4SA4CMR.js.map +1 -0
  361. package/dist/chunk-WFUMNDCE.js +111 -0
  362. package/dist/chunk-WFUMNDCE.js.map +1 -0
  363. package/dist/chunk-WGCGKU3M.js +51 -0
  364. package/dist/chunk-WGCGKU3M.js.map +1 -0
  365. package/dist/chunk-WHWNXLTD.js +166 -0
  366. package/dist/chunk-WHWNXLTD.js.map +1 -0
  367. package/dist/chunk-WN42X2OE.js +509 -0
  368. package/dist/chunk-WN42X2OE.js.map +1 -0
  369. package/dist/chunk-WN4KX7GE.js +25 -0
  370. package/dist/chunk-WN4KX7GE.js.map +1 -0
  371. package/dist/chunk-XIY7P54H.js +84 -0
  372. package/dist/chunk-XIY7P54H.js.map +1 -0
  373. package/dist/chunk-XPLTWUMN.js +103 -0
  374. package/dist/chunk-XPLTWUMN.js.map +1 -0
  375. package/dist/chunk-Y6T5ZKBK.js +19 -0
  376. package/dist/chunk-Y6T5ZKBK.js.map +1 -0
  377. package/dist/chunk-YGGRQXDP.js +382 -0
  378. package/dist/chunk-YGGRQXDP.js.map +1 -0
  379. package/dist/chunk-YMBB4JBD.js +1830 -0
  380. package/dist/chunk-YMBB4JBD.js.map +1 -0
  381. package/dist/chunk-YNWM426O.js +159 -0
  382. package/dist/chunk-YNWM426O.js.map +1 -0
  383. package/dist/chunk-YQSBHWOI.js +41 -0
  384. package/dist/chunk-YTF3IVMF.js +149 -0
  385. package/dist/chunk-YTF3IVMF.js.map +1 -0
  386. package/dist/chunk-Z3ENMCFE.js +94 -0
  387. package/dist/chunk-Z3ENMCFE.js.map +1 -0
  388. package/dist/chunk-Z7MWSXLG.js +94 -0
  389. package/dist/chunk-Z7MWSXLG.js.map +1 -0
  390. package/dist/chunk-ZIXHS6AM.js +42 -0
  391. package/dist/chunk-ZIXHS6AM.js.map +1 -0
  392. package/dist/chunk-ZJ7TQUCU.js +4410 -0
  393. package/dist/chunk-ZJ7TQUCU.js.map +1 -0
  394. package/dist/chunk-ZNQRDLSS.js +52 -0
  395. package/dist/chunk-ZNQRDLSS.js.map +1 -0
  396. package/dist/chunk-ZPGGSXU3.js +275 -0
  397. package/dist/chunk-ZPGGSXU3.js.map +1 -0
  398. package/dist/claim-NXYQZEMC.js +197 -0
  399. package/dist/claim-NXYQZEMC.js.map +1 -0
  400. package/dist/cli.js +104 -70061
  401. package/dist/cli.js.map +1 -1
  402. package/dist/client-EURRWXPW.js +19 -0
  403. package/dist/code-FKQW7V7N.js +76 -0
  404. package/dist/code-FKQW7V7N.js.map +1 -0
  405. package/dist/companies-5ZH47E4H.js +195 -0
  406. package/dist/companies-5ZH47E4H.js.map +1 -0
  407. package/dist/complete-62OQPRHW.js +81 -0
  408. package/dist/complete-62OQPRHW.js.map +1 -0
  409. package/dist/config-OZOHIAOJ.js +88 -0
  410. package/dist/config-OZOHIAOJ.js.map +1 -0
  411. package/dist/connect-6DQFYKGN.js +42 -0
  412. package/dist/content-PCGSX2QU.js +85 -0
  413. package/dist/content-PCGSX2QU.js.map +1 -0
  414. package/dist/conversation-NS7JHTPK.js +93 -0
  415. package/dist/conversation-NS7JHTPK.js.map +1 -0
  416. package/dist/conversion-report-7QSWB2FY.js +125 -0
  417. package/dist/conversion-report-7QSWB2FY.js.map +1 -0
  418. package/dist/conversion-upload-command-XESIAQPU.js +438 -0
  419. package/dist/conversion-upload-command-XESIAQPU.js.map +1 -0
  420. package/dist/conversion-writes-BGOVLBS5.js +120 -0
  421. package/dist/conversion-writes-BGOVLBS5.js.map +1 -0
  422. package/dist/conversions-46MI57VC.js +135 -0
  423. package/dist/conversions-46MI57VC.js.map +1 -0
  424. package/dist/conversions-IYIWW4O7.js +76 -0
  425. package/dist/conversions-IYIWW4O7.js.map +1 -0
  426. package/dist/countries-5OBUVLLD.js +82 -0
  427. package/dist/countries-5OBUVLLD.js.map +1 -0
  428. package/dist/create-BEDPXUB7.js +236 -0
  429. package/dist/create-BEDPXUB7.js.map +1 -0
  430. package/dist/create-LLTMBBGV.js +207 -0
  431. package/dist/create-LLTMBBGV.js.map +1 -0
  432. package/dist/create-VNJ2VH3A.js +59 -0
  433. package/dist/create-VNJ2VH3A.js.map +1 -0
  434. package/dist/create-ZYKG2XOP.js +138 -0
  435. package/dist/create-ZYKG2XOP.js.map +1 -0
  436. package/dist/creatives-2LL66X4E.js +51 -0
  437. package/dist/creatives-2LL66X4E.js.map +1 -0
  438. package/dist/creatives-3MEMSUKJ.js +182 -0
  439. package/dist/creatives-3MEMSUKJ.js.map +1 -0
  440. package/dist/creatives-XI2DGQUZ.js +87 -0
  441. package/dist/creatives-XI2DGQUZ.js.map +1 -0
  442. package/dist/credentials-63PRTM3K.js +287 -0
  443. package/dist/credentials-63PRTM3K.js.map +1 -0
  444. package/dist/critique-IQI7CCTT.js +213 -0
  445. package/dist/critique-IQI7CCTT.js.map +1 -0
  446. package/dist/critique-UV7FPG45.js +1449 -0
  447. package/dist/critique-UV7FPG45.js.map +1 -0
  448. package/dist/crm-OERYUOBS.js +224 -0
  449. package/dist/crm-OERYUOBS.js.map +1 -0
  450. package/dist/crm-VNO3QTQG.js +318 -0
  451. package/dist/crm-VNO3QTQG.js.map +1 -0
  452. package/dist/crop-B52KIQ4O.js +113 -0
  453. package/dist/crop-B52KIQ4O.js.map +1 -0
  454. package/dist/currency-GGWF5DMU.js +88 -0
  455. package/dist/currency-GGWF5DMU.js.map +1 -0
  456. package/dist/custom-conversions-7WDBTC4X.js +125 -0
  457. package/dist/custom-conversions-7WDBTC4X.js.map +1 -0
  458. package/dist/customers-FOPXEGCB.js +56 -0
  459. package/dist/decide-PK7WNSQ2.js +199 -0
  460. package/dist/decide-PK7WNSQ2.js.map +1 -0
  461. package/dist/delete-56LKNEGA.js +71 -0
  462. package/dist/delete-56LKNEGA.js.map +1 -0
  463. package/dist/delete-EZ7HHOOD.js +69 -0
  464. package/dist/delete-EZ7HHOOD.js.map +1 -0
  465. package/dist/delete-JSYM7QKN.js +54 -0
  466. package/dist/delete-JSYM7QKN.js.map +1 -0
  467. package/dist/delete-NOUWBNZM.js +66 -0
  468. package/dist/delete-NOUWBNZM.js.map +1 -0
  469. package/dist/delete-T33AWV63.js +63 -0
  470. package/dist/delete-T33AWV63.js.map +1 -0
  471. package/dist/delete-YSYVFL6W.js +71 -0
  472. package/dist/delete-YSYVFL6W.js.map +1 -0
  473. package/dist/demographics-LQGFUS4F.js +138 -0
  474. package/dist/demographics-LQGFUS4F.js.map +1 -0
  475. package/dist/describe-AAVYIFE3.js +97 -0
  476. package/dist/describe-AAVYIFE3.js.map +1 -0
  477. package/dist/describe-UQFLWVFR.js +97 -0
  478. package/dist/describe-UQFLWVFR.js.map +1 -0
  479. package/dist/dimensions-QDXBG2XC.js +101 -0
  480. package/dist/dimensions-QDXBG2XC.js.map +1 -0
  481. package/dist/discard-V4LQ7ZGA.js +66 -0
  482. package/dist/discard-V4LQ7ZGA.js.map +1 -0
  483. package/dist/discover-6TEBPVNC.js +93 -0
  484. package/dist/discover-6TEBPVNC.js.map +1 -0
  485. package/dist/discover-SBZPB7T2.js +172 -0
  486. package/dist/discover-SBZPB7T2.js.map +1 -0
  487. package/dist/domain-65J2DEDB.js +98 -0
  488. package/dist/domain-65J2DEDB.js.map +1 -0
  489. package/dist/download-LV3GPOWV.js +299 -0
  490. package/dist/download-LV3GPOWV.js.map +1 -0
  491. package/dist/draft-DDFFTZ43.js +233 -0
  492. package/dist/draft-DDFFTZ43.js.map +1 -0
  493. package/dist/draft-FIKJXNIQ.js +281 -0
  494. package/dist/draft-FIKJXNIQ.js.map +1 -0
  495. package/dist/draft-GYGWTMBU.js +307 -0
  496. package/dist/draft-GYGWTMBU.js.map +1 -0
  497. package/dist/draft-KNXVZAZV.js +217 -0
  498. package/dist/draft-KNXVZAZV.js.map +1 -0
  499. package/dist/draft-N4LFPKTA.js +100 -0
  500. package/dist/draft-N4LFPKTA.js.map +1 -0
  501. package/dist/draft-NG2DPL2X.js +306 -0
  502. package/dist/draft-NG2DPL2X.js.map +1 -0
  503. package/dist/draft-QILZ7M7N.js +328 -0
  504. package/dist/draft-QILZ7M7N.js.map +1 -0
  505. package/dist/draft-XPO5RWST.js +103 -0
  506. package/dist/draft-XPO5RWST.js.map +1 -0
  507. package/dist/engine/index.d.ts +213 -127
  508. package/dist/engine/index.js +18 -4
  509. package/dist/{env-4P5HOGNA.js → env-TQ2XS2KY.js} +12 -2
  510. package/dist/env-TQ2XS2KY.js.map +1 -0
  511. package/dist/experiment-FQNKMORZ.js +1397 -0
  512. package/dist/experiment-FQNKMORZ.js.map +1 -0
  513. package/dist/export-4IZQZAPF.js +168 -0
  514. package/dist/export-4IZQZAPF.js.map +1 -0
  515. package/dist/extract-DZMGVQ7D.js +113 -0
  516. package/dist/extract-DZMGVQ7D.js.map +1 -0
  517. package/dist/facets-FAAOFHBF.js +114 -0
  518. package/dist/facets-FAAOFHBF.js.map +1 -0
  519. package/dist/favorites-DD2LNSTG.js +178 -0
  520. package/dist/favorites-DD2LNSTG.js.map +1 -0
  521. package/dist/feed-TUVFNX2U.js +177 -0
  522. package/dist/feed-TUVFNX2U.js.map +1 -0
  523. package/dist/feedback-NWOOZOFW.js +66 -0
  524. package/dist/feedback-NWOOZOFW.js.map +1 -0
  525. package/dist/feedback-record-CFPUKLMY.js +175 -0
  526. package/dist/feedback-record-CFPUKLMY.js.map +1 -0
  527. package/dist/fetch-LEY77E7V.js +176 -0
  528. package/dist/fetch-LEY77E7V.js.map +1 -0
  529. package/dist/fetch-O6UHNXWB.js +139 -0
  530. package/dist/fetch-O6UHNXWB.js.map +1 -0
  531. package/dist/find-4XKIBF4D.js +134 -0
  532. package/dist/find-4XKIBF4D.js.map +1 -0
  533. package/dist/fit-ODVVXV2Q.js +45 -0
  534. package/dist/fit-ODVVXV2Q.js.map +1 -0
  535. package/dist/flows-QKPC63AF.js +247 -0
  536. package/dist/flows-QKPC63AF.js.map +1 -0
  537. package/dist/follow-RCOXTZGY.js +94 -0
  538. package/dist/follow-RCOXTZGY.js.map +1 -0
  539. package/dist/follow-competitors-SQ5XBFTK.js +112 -0
  540. package/dist/follow-competitors-SQ5XBFTK.js.map +1 -0
  541. package/dist/following-VDU3BHC4.js +113 -0
  542. package/dist/following-VDU3BHC4.js.map +1 -0
  543. package/dist/fonts-WM2MJDVJ.js +34 -0
  544. package/dist/fonts-WM2MJDVJ.js.map +1 -0
  545. package/dist/forecast-2GJKBNBM.js +168 -0
  546. package/dist/forecast-2GJKBNBM.js.map +1 -0
  547. package/dist/forecast-7K3TAHDL.js +104 -0
  548. package/dist/forecast-7K3TAHDL.js.map +1 -0
  549. package/dist/funding-HTFVZLLG.js +85 -0
  550. package/dist/funding-HTFVZLLG.js.map +1 -0
  551. package/dist/funnel-CSPK5SPZ.js +394 -0
  552. package/dist/funnel-CSPK5SPZ.js.map +1 -0
  553. package/dist/ga4-2RC4EH7V.js +55 -0
  554. package/dist/ga4-2RC4EH7V.js.map +1 -0
  555. package/dist/generate-TPDOBCKQ.js +262 -0
  556. package/dist/generate-TPDOBCKQ.js.map +1 -0
  557. package/dist/get-4YZ4PI3B.js +56 -0
  558. package/dist/get-4YZ4PI3B.js.map +1 -0
  559. package/dist/get-FH2LIEYL.js +63 -0
  560. package/dist/get-FH2LIEYL.js.map +1 -0
  561. package/dist/get-GZLCDXXW.js +61 -0
  562. package/dist/get-GZLCDXXW.js.map +1 -0
  563. package/dist/get-HFU6ZJPX.js +78 -0
  564. package/dist/get-HFU6ZJPX.js.map +1 -0
  565. package/dist/get-TSPQYEKC.js +59 -0
  566. package/dist/get-TSPQYEKC.js.map +1 -0
  567. package/dist/get-TY3RXYNZ.js +63 -0
  568. package/dist/get-TY3RXYNZ.js.map +1 -0
  569. package/dist/get-VPW33XTN.js +92 -0
  570. package/dist/get-VPW33XTN.js.map +1 -0
  571. package/dist/gif-JFEYPFFI.js +94 -0
  572. package/dist/gif-JFEYPFFI.js.map +1 -0
  573. package/dist/google-R6RD4L6Z.js +136 -0
  574. package/dist/google-R6RD4L6Z.js.map +1 -0
  575. package/dist/google-VPQNRVIB.js +3190 -0
  576. package/dist/google-VPQNRVIB.js.map +1 -0
  577. package/dist/google-ads-WWM5KIRS.js +195 -0
  578. package/dist/google-ads-WWM5KIRS.js.map +1 -0
  579. package/dist/group-7AV6UL26.js +43 -0
  580. package/dist/group-7AV6UL26.js.map +1 -0
  581. package/dist/group-BVQZEZIC.js +43 -0
  582. package/dist/group-BVQZEZIC.js.map +1 -0
  583. package/dist/gsc-SQ42WAQE.js +30 -0
  584. package/dist/gsc-SQ42WAQE.js.map +1 -0
  585. package/dist/history-BNNHFURR.js +67 -0
  586. package/dist/history-BNNHFURR.js.map +1 -0
  587. package/dist/history-KBK5TP65.js +133 -0
  588. package/dist/history-KBK5TP65.js.map +1 -0
  589. package/dist/hubspot-GAAWWVLL.js +779 -0
  590. package/dist/hubspot-GAAWWVLL.js.map +1 -0
  591. package/dist/icon-OYTTSNSL.js +137 -0
  592. package/dist/icon-OYTTSNSL.js.map +1 -0
  593. package/dist/ideas-CELMD3BL.js +32 -0
  594. package/dist/ideas-CELMD3BL.js.map +1 -0
  595. package/dist/images-QHV4ECAP.js +90 -0
  596. package/dist/images-QHV4ECAP.js.map +1 -0
  597. package/dist/improve-W6GZNT2A.js +86 -0
  598. package/dist/improve-W6GZNT2A.js.map +1 -0
  599. package/dist/ingest-SH35YX6X.js +23 -0
  600. package/dist/ingest-SH35YX6X.js.map +1 -0
  601. package/dist/ingest-UWCGJZXV.js +107 -0
  602. package/dist/ingest-UWCGJZXV.js.map +1 -0
  603. package/dist/insights-IW7LGAWU.js +423 -0
  604. package/dist/insights-IW7LGAWU.js.map +1 -0
  605. package/dist/insights-QH54F56A.js +122 -0
  606. package/dist/insights-QH54F56A.js.map +1 -0
  607. package/dist/inspect-6Z6HEMBI.js +189 -0
  608. package/dist/inspect-6Z6HEMBI.js.map +1 -0
  609. package/dist/inspiration-RDQ3Y3N3.js +53 -0
  610. package/dist/inspiration-RDQ3Y3N3.js.map +1 -0
  611. package/dist/intent-5GSSCFZ2.js +95 -0
  612. package/dist/intent-5GSSCFZ2.js.map +1 -0
  613. package/dist/job-URVXJP75.js +202 -0
  614. package/dist/job-URVXJP75.js.map +1 -0
  615. package/dist/job-create-S4SECUVF.js +109 -0
  616. package/dist/job-create-S4SECUVF.js.map +1 -0
  617. package/dist/job-status-253SUCTJ.js +74 -0
  618. package/dist/job-status-253SUCTJ.js.map +1 -0
  619. package/dist/keep-GPSYDIGJ.js +78 -0
  620. package/dist/keep-GPSYDIGJ.js.map +1 -0
  621. package/dist/keyword-gap-NTFDX43B.js +130 -0
  622. package/dist/keyword-gap-NTFDX43B.js.map +1 -0
  623. package/dist/keyword-metrics-NKZRCF4L.js +197 -0
  624. package/dist/keyword-metrics-NKZRCF4L.js.map +1 -0
  625. package/dist/keywords-for-site-NQUPJNUR.js +128 -0
  626. package/dist/keywords-for-site-NQUPJNUR.js.map +1 -0
  627. package/dist/landing-AHNZSZHY.js +28 -0
  628. package/dist/landing-AHNZSZHY.js.map +1 -0
  629. package/dist/landings-NEF4PQL2.js +151 -0
  630. package/dist/landings-NEF4PQL2.js.map +1 -0
  631. package/dist/languages-3RDPPPTE.js +55 -0
  632. package/dist/languages-3RDPPPTE.js.map +1 -0
  633. package/dist/languages-CQX3YOIT.js +40 -0
  634. package/dist/languages-CQX3YOIT.js.map +1 -0
  635. package/dist/launches-GBHLJH5S.js +19 -0
  636. package/dist/launches-GBHLJH5S.js.map +1 -0
  637. package/dist/layerize-Q56C6LFG.js +190 -0
  638. package/dist/layerize-Q56C6LFG.js.map +1 -0
  639. package/dist/leads-5MUVPXA2.js +90 -0
  640. package/dist/leads-5MUVPXA2.js.map +1 -0
  641. package/dist/leads-JHUM6FYR.js +293 -0
  642. package/dist/leads-JHUM6FYR.js.map +1 -0
  643. package/dist/learn-EMV7RWTB.js +203 -0
  644. package/dist/learn-EMV7RWTB.js.map +1 -0
  645. package/dist/library-6VUFHTEK.js +109 -0
  646. package/dist/library-6VUFHTEK.js.map +1 -0
  647. package/dist/lighthouse-57U2GMPV.js +75 -0
  648. package/dist/lighthouse-57U2GMPV.js.map +1 -0
  649. package/dist/line-item-writes-GMIZYHLB.js +208 -0
  650. package/dist/line-item-writes-GMIZYHLB.js.map +1 -0
  651. package/dist/line-items-B5HAC47U.js +103 -0
  652. package/dist/line-items-B5HAC47U.js.map +1 -0
  653. package/dist/link-B6ZJFGFE.js +64 -0
  654. package/dist/link-B6ZJFGFE.js.map +1 -0
  655. package/dist/linkedin-FJ3OUYT2.js +1008 -0
  656. package/dist/linkedin-FJ3OUYT2.js.map +1 -0
  657. package/dist/list-2MBSU4ZX.js +63 -0
  658. package/dist/list-2MBSU4ZX.js.map +1 -0
  659. package/dist/list-EFUPHLG3.js +303 -0
  660. package/dist/list-EFUPHLG3.js.map +1 -0
  661. package/dist/list-G57ZO4PG.js +50 -0
  662. package/dist/list-G57ZO4PG.js.map +1 -0
  663. package/dist/list-JCSWZWDI.js +57 -0
  664. package/dist/list-JCSWZWDI.js.map +1 -0
  665. package/dist/list-QOSPRCH4.js +151 -0
  666. package/dist/list-QOSPRCH4.js.map +1 -0
  667. package/dist/list-RINCJOAC.js +76 -0
  668. package/dist/list-RINCJOAC.js.map +1 -0
  669. package/dist/list-SRNXHS6L.js +51 -0
  670. package/dist/list-SRNXHS6L.js.map +1 -0
  671. package/dist/list-YJSO4M5Q.js +65 -0
  672. package/dist/list-YJSO4M5Q.js.map +1 -0
  673. package/dist/locations-HW2Y5OJO.js +67 -0
  674. package/dist/locations-HW2Y5OJO.js.map +1 -0
  675. package/dist/locations-XOHI3VWI.js +40 -0
  676. package/dist/locations-XOHI3VWI.js.map +1 -0
  677. package/dist/log-SZDYUMM3.js +92 -0
  678. package/dist/log-SZDYUMM3.js.map +1 -0
  679. package/dist/logo-KXTGIYBI.js +18 -0
  680. package/dist/logo-KXTGIYBI.js.map +1 -0
  681. package/dist/lookup-X6O5UNJH.js +22 -0
  682. package/dist/lookup-X6O5UNJH.js.map +1 -0
  683. package/dist/make-SGCBJTRR.js +633 -0
  684. package/dist/make-SGCBJTRR.js.map +1 -0
  685. package/dist/map-ZK46VVL3.js +404 -0
  686. package/dist/map-ZK46VVL3.js.map +1 -0
  687. package/dist/mcp-NCM5TQUG.js +463 -0
  688. package/dist/mcp-NCM5TQUG.js.map +1 -0
  689. package/dist/media-MI4EE7L4.js +89 -0
  690. package/dist/media-MI4EE7L4.js.map +1 -0
  691. package/dist/media-QUTQOBA7.js +15 -0
  692. package/dist/media-QUTQOBA7.js.map +1 -0
  693. package/dist/media-sources-MS3RMQ6A.js +32 -0
  694. package/dist/media-sources-MS3RMQ6A.js.map +1 -0
  695. package/dist/members-IGHLTQKW.js +44 -0
  696. package/dist/members-IGHLTQKW.js.map +1 -0
  697. package/dist/meta-E3JOUOSS.js +69 -0
  698. package/dist/meta-E3JOUOSS.js.map +1 -0
  699. package/dist/metrics-HQ7XJAYQ.js +152 -0
  700. package/dist/metrics-HQ7XJAYQ.js.map +1 -0
  701. package/dist/models-PGX3FBHU.js +155 -0
  702. package/dist/models-PGX3FBHU.js.map +1 -0
  703. package/dist/normalize-FPJ6GSOY.js +806 -0
  704. package/dist/normalize-FPJ6GSOY.js.map +1 -0
  705. package/dist/normalize-LHD5LVFK.js +141 -0
  706. package/dist/normalize-LHD5LVFK.js.map +1 -0
  707. package/dist/options-CPHN3RMO.js +121 -0
  708. package/dist/options-CPHN3RMO.js.map +1 -0
  709. package/dist/output-GQFJ2T5B.js +24 -0
  710. package/dist/output-GQFJ2T5B.js.map +1 -0
  711. package/dist/page-VTTSBC6Y.js +105 -0
  712. package/dist/page-VTTSBC6Y.js.map +1 -0
  713. package/dist/pages-PMZVNVQM.js +66 -0
  714. package/dist/pages-PMZVNVQM.js.map +1 -0
  715. package/dist/performance-ECIJJEFV.js +24 -0
  716. package/dist/performance-ECIJJEFV.js.map +1 -0
  717. package/dist/pinterest-UDNGOWDM.js +96 -0
  718. package/dist/pinterest-UDNGOWDM.js.map +1 -0
  719. package/dist/pixels-OYZDGCH3.js +108 -0
  720. package/dist/pixels-OYZDGCH3.js.map +1 -0
  721. package/dist/pixels-XKGNTCFX.js +60 -0
  722. package/dist/pixels-XKGNTCFX.js.map +1 -0
  723. package/dist/plan-DZS3TVIJ.js +207 -0
  724. package/dist/plan-DZS3TVIJ.js.map +1 -0
  725. package/dist/preview-DR6MXOGI.js +169 -0
  726. package/dist/preview-DR6MXOGI.js.map +1 -0
  727. package/dist/profile-VOVZG44G.js +159 -0
  728. package/dist/profile-VOVZG44G.js.map +1 -0
  729. package/dist/promoted-tweet-writes-UJJI5SQL.js +180 -0
  730. package/dist/promoted-tweet-writes-UJJI5SQL.js.map +1 -0
  731. package/dist/promoted-tweets-O5RCETPX.js +119 -0
  732. package/dist/promoted-tweets-O5RCETPX.js.map +1 -0
  733. package/dist/properties-MKVF7MUK.js +101 -0
  734. package/dist/properties-MKVF7MUK.js.map +1 -0
  735. package/dist/publish-RRYU3NNX.js +322 -0
  736. package/dist/publish-RRYU3NNX.js.map +1 -0
  737. package/dist/query-CNWQ6STR.js +61 -0
  738. package/dist/query-CNWQ6STR.js.map +1 -0
  739. package/dist/query-DBSBZ73C.js +247 -0
  740. package/dist/query-DBSBZ73C.js.map +1 -0
  741. package/dist/query-QK4U4TEL.js +236 -0
  742. package/dist/query-QK4U4TEL.js.map +1 -0
  743. package/dist/questionnaire-OVJWNUVV.js +93 -0
  744. package/dist/questionnaire-OVJWNUVV.js.map +1 -0
  745. package/dist/read-L2QIVJTL.js +141 -0
  746. package/dist/read-L2QIVJTL.js.map +1 -0
  747. package/dist/reddit-K6CKJZRF.js +26 -0
  748. package/dist/reddit-K6CKJZRF.js.map +1 -0
  749. package/dist/refresh-IF4P57JJ.js +94 -0
  750. package/dist/refresh-IF4P57JJ.js.map +1 -0
  751. package/dist/release-H4EL3J6R.js +60 -0
  752. package/dist/release-H4EL3J6R.js.map +1 -0
  753. package/dist/relevant-pages-CRI2NLWG.js +99 -0
  754. package/dist/relevant-pages-CRI2NLWG.js.map +1 -0
  755. package/dist/remove-DKSHQRNS.js +50 -0
  756. package/dist/remove-DKSHQRNS.js.map +1 -0
  757. package/dist/remove-JKSCGKQG.js +48 -0
  758. package/dist/remove-JKSCGKQG.js.map +1 -0
  759. package/dist/reopen-B26V2GEJ.js +63 -0
  760. package/dist/reopen-B26V2GEJ.js.map +1 -0
  761. package/dist/rerun-6WKE4MPY.js +84 -0
  762. package/dist/rerun-6WKE4MPY.js.map +1 -0
  763. package/dist/research-O3IVF3MM.js +62 -0
  764. package/dist/research-O3IVF3MM.js.map +1 -0
  765. package/dist/research-SC7S6IPV.js +262 -0
  766. package/dist/research-SC7S6IPV.js.map +1 -0
  767. package/dist/reset-7HMOB2KE.js +54 -0
  768. package/dist/reset-7HMOB2KE.js.map +1 -0
  769. package/dist/reset-THPEXZDK.js +54 -0
  770. package/dist/reset-THPEXZDK.js.map +1 -0
  771. package/dist/resolve-HX5R52A3.js +121 -0
  772. package/dist/resolve-HX5R52A3.js.map +1 -0
  773. package/dist/retry-4ENRUJOJ.js +62 -0
  774. package/dist/retry-4ENRUJOJ.js.map +1 -0
  775. package/dist/retry-ELIMI7U5.js +60 -0
  776. package/dist/retry-ELIMI7U5.js.map +1 -0
  777. package/dist/retry-failed-2OYMCB55.js +45 -0
  778. package/dist/retry-failed-2OYMCB55.js.map +1 -0
  779. package/dist/run-CY4BAIQI.js +65 -0
  780. package/dist/run-CY4BAIQI.js.map +1 -0
  781. package/dist/run-GXPPPDGI.js +59 -0
  782. package/dist/run-GXPPPDGI.js.map +1 -0
  783. package/dist/scaffold-ad-X6VPBVTB.js +1548 -0
  784. package/dist/scaffold-ad-X6VPBVTB.js.map +1 -0
  785. package/dist/scaffold-static-ad-LKOOZSDP.js +971 -0
  786. package/dist/scaffold-static-ad-LKOOZSDP.js.map +1 -0
  787. package/dist/scaffold-video-NAOIFIM4.js +872 -0
  788. package/dist/scaffold-video-NAOIFIM4.js.map +1 -0
  789. package/dist/schedule-TLYT5UXM.js +66 -0
  790. package/dist/schedule-TLYT5UXM.js.map +1 -0
  791. package/dist/schedule-V654LLZ2.js +61 -0
  792. package/dist/schedule-V654LLZ2.js.map +1 -0
  793. package/dist/scheduled-agents-MJNUZYEK.js +49 -0
  794. package/dist/scheduled-agents-MJNUZYEK.js.map +1 -0
  795. package/dist/schema-DN4WKWUM.js +132 -0
  796. package/dist/schema-DN4WKWUM.js.map +1 -0
  797. package/dist/schema-MZTVCNP4.js +63 -0
  798. package/dist/schema-MZTVCNP4.js.map +1 -0
  799. package/dist/scrape-T3DA7ER7.js +2241 -0
  800. package/dist/scrape-T3DA7ER7.js.map +1 -0
  801. package/dist/screenshot-EIGC6SZB.js +102 -0
  802. package/dist/screenshot-EIGC6SZB.js.map +1 -0
  803. package/dist/search-2SVUDZIX.js +224 -0
  804. package/dist/search-2SVUDZIX.js.map +1 -0
  805. package/dist/search-34NFJ5F6.js +26 -0
  806. package/dist/search-34NFJ5F6.js.map +1 -0
  807. package/dist/search-BWE3OPOY.js +91 -0
  808. package/dist/search-BWE3OPOY.js.map +1 -0
  809. package/dist/search-EYYAOZND.js +92 -0
  810. package/dist/search-EYYAOZND.js.map +1 -0
  811. package/dist/search-EZZMYU4Y.js +174 -0
  812. package/dist/search-EZZMYU4Y.js.map +1 -0
  813. package/dist/search-copy-VKQ2OOBM.js +168 -0
  814. package/dist/search-copy-VKQ2OOBM.js.map +1 -0
  815. package/dist/seeds-HQYSVFIX.js +101 -0
  816. package/dist/seeds-HQYSVFIX.js.map +1 -0
  817. package/dist/select-3SIBANY6.js +94 -0
  818. package/dist/select-3SIBANY6.js.map +1 -0
  819. package/dist/sends-I7VQFE4S.js +309 -0
  820. package/dist/sends-I7VQFE4S.js.map +1 -0
  821. package/dist/sequences-JHSEJJGN.js +146 -0
  822. package/dist/sequences-JHSEJJGN.js.map +1 -0
  823. package/dist/set-prompt-RAG7RJOD.js +185 -0
  824. package/dist/set-prompt-RAG7RJOD.js.map +1 -0
  825. package/dist/setup-links-TNRBFS5Z.js +141 -0
  826. package/dist/setup-links-TNRBFS5Z.js.map +1 -0
  827. package/dist/{shared-6762QE6R.js → shared-AT3FXPAG.js} +8 -6
  828. package/dist/shared-AT3FXPAG.js.map +1 -0
  829. package/dist/shopify-LUETQ5NT.js +3819 -0
  830. package/dist/shopify-LUETQ5NT.js.map +1 -0
  831. package/dist/site-SDL6LF6D.js +177 -0
  832. package/dist/site-SDL6LF6D.js.map +1 -0
  833. package/dist/sitemaps-FG37N5EB.js +87 -0
  834. package/dist/sitemaps-FG37N5EB.js.map +1 -0
  835. package/dist/sites-FIXK4Y3O.js +101 -0
  836. package/dist/sites-FIXK4Y3O.js.map +1 -0
  837. package/dist/skills-OKVCVQVD.js +47 -0
  838. package/dist/skills-OKVCVQVD.js.map +1 -0
  839. package/dist/sources-ISAUZFRN.js +30 -0
  840. package/dist/sources-ISAUZFRN.js.map +1 -0
  841. package/dist/sources-LQTJXAJG.js +421 -0
  842. package/dist/sources-LQTJXAJG.js.map +1 -0
  843. package/dist/stale-2L7NTLC6.js +63 -0
  844. package/dist/stale-2L7NTLC6.js.map +1 -0
  845. package/dist/stats-ZWZ7BAHV.js +34 -0
  846. package/dist/stats-ZWZ7BAHV.js.map +1 -0
  847. package/dist/status-4QBSIHO7.js +62 -0
  848. package/dist/status-4QBSIHO7.js.map +1 -0
  849. package/dist/sticker-FLRZM3BI.js +94 -0
  850. package/dist/sticker-FLRZM3BI.js.map +1 -0
  851. package/dist/stock-2CSMWRWV.js +179 -0
  852. package/dist/stock-2CSMWRWV.js.map +1 -0
  853. package/dist/studio-TTTR6N7D.js +49 -0
  854. package/dist/studio-TTTR6N7D.js.map +1 -0
  855. package/dist/sync-DH7FTPGG.js +54 -0
  856. package/dist/sync-DH7FTPGG.js.map +1 -0
  857. package/dist/sync-G5CS2RYV.js +54 -0
  858. package/dist/sync-G5CS2RYV.js.map +1 -0
  859. package/dist/sync-UADA6M33.js +265 -0
  860. package/dist/sync-UADA6M33.js.map +1 -0
  861. package/dist/sync-definition-ATMMOJ37.js +52 -0
  862. package/dist/sync-definition-ATMMOJ37.js.map +1 -0
  863. package/dist/tag-manager-NK3ZHSJB.js +43 -0
  864. package/dist/tag-manager-NK3ZHSJB.js.map +1 -0
  865. package/dist/tags-4RBZWDHS.js +20 -0
  866. package/dist/tags-4RBZWDHS.js.map +1 -0
  867. package/dist/tags-M7ATU2R7.js +26 -0
  868. package/dist/tags-M7ATU2R7.js.map +1 -0
  869. package/dist/tags-MXJKIBL4.js +20 -0
  870. package/dist/tags-MXJKIBL4.js.map +1 -0
  871. package/dist/tags-YG5EGPBW.js +20 -0
  872. package/dist/tags-YG5EGPBW.js.map +1 -0
  873. package/dist/tags-ZP4O3I2F.js +224 -0
  874. package/dist/tags-ZP4O3I2F.js.map +1 -0
  875. package/dist/targeting-constants-ZGBX3VWU.js +118 -0
  876. package/dist/targeting-constants-ZGBX3VWU.js.map +1 -0
  877. package/dist/targeting-criteria-BTB2RVI4.js +113 -0
  878. package/dist/targeting-criteria-BTB2RVI4.js.map +1 -0
  879. package/dist/targets-DEGJD2N6.js +102 -0
  880. package/dist/targets-DEGJD2N6.js.map +1 -0
  881. package/dist/templates-FZDWQSTV.js +178 -0
  882. package/dist/templates-FZDWQSTV.js.map +1 -0
  883. package/dist/testimonials-TI5EDABS.js +32 -0
  884. package/dist/testimonials-TI5EDABS.js.map +1 -0
  885. package/dist/themes-3RV3HNNE.js +94 -0
  886. package/dist/themes-3RV3HNNE.js.map +1 -0
  887. package/dist/top-companies-OKH7UNKX.js +108 -0
  888. package/dist/top-companies-OKH7UNKX.js.map +1 -0
  889. package/dist/translate-IUQBBVE6.js +598 -0
  890. package/dist/translate-IUQBBVE6.js.map +1 -0
  891. package/dist/triggers-2NWMXQ5P.js +141 -0
  892. package/dist/triggers-2NWMXQ5P.js.map +1 -0
  893. package/dist/tweets-X64YDEAA.js +123 -0
  894. package/dist/tweets-X64YDEAA.js.map +1 -0
  895. package/dist/unfollow-PIONCSBL.js +46 -0
  896. package/dist/unfollow-PIONCSBL.js.map +1 -0
  897. package/dist/unlink-UAPLQMK6.js +67 -0
  898. package/dist/unlink-UAPLQMK6.js.map +1 -0
  899. package/dist/unstage-BJJ5M7MK.js +95 -0
  900. package/dist/unstage-BJJ5M7MK.js.map +1 -0
  901. package/dist/unstage-X2BYGH2S.js +84 -0
  902. package/dist/unstage-X2BYGH2S.js.map +1 -0
  903. package/dist/update-7YK3VSOK.js +142 -0
  904. package/dist/update-7YK3VSOK.js.map +1 -0
  905. package/dist/update-BHG7BTK3.js +155 -0
  906. package/dist/update-BHG7BTK3.js.map +1 -0
  907. package/dist/update-CDJXKEVA.js +63 -0
  908. package/dist/update-CDJXKEVA.js.map +1 -0
  909. package/dist/update-RZXDAMAG.js +98 -0
  910. package/dist/update-RZXDAMAG.js.map +1 -0
  911. package/dist/upload-DSZEXNHH.js +126 -0
  912. package/dist/upload-DSZEXNHH.js.map +1 -0
  913. package/dist/upload-IWFYKD7A.js +150 -0
  914. package/dist/upload-IWFYKD7A.js.map +1 -0
  915. package/dist/upscale-EYCEYRWE.js +109 -0
  916. package/dist/upscale-EYCEYRWE.js.map +1 -0
  917. package/dist/url-options-RA3XISLN.js +130 -0
  918. package/dist/url-options-RA3XISLN.js.map +1 -0
  919. package/dist/url-params-OGZXF6MT.js +98 -0
  920. package/dist/url-params-OGZXF6MT.js.map +1 -0
  921. package/dist/use-E2TA2K6J.js +95 -0
  922. package/dist/use-E2TA2K6J.js.map +1 -0
  923. package/dist/validate-C6HWDI6K.js +88 -0
  924. package/dist/validate-C6HWDI6K.js.map +1 -0
  925. package/dist/variant-ETHB6XUM.js +338 -0
  926. package/dist/variant-ETHB6XUM.js.map +1 -0
  927. package/dist/videos-A2X5AARB.js +39 -0
  928. package/dist/videos-A2X5AARB.js.map +1 -0
  929. package/dist/view-BVEZRRV2.js +121 -0
  930. package/dist/view-BVEZRRV2.js.map +1 -0
  931. package/dist/viewer-check-W4ICSBHO.js +68 -0
  932. package/dist/viewer-check-W4ICSBHO.js.map +1 -0
  933. package/dist/web-GJSFDBBE.js +140 -0
  934. package/dist/web-GJSFDBBE.js.map +1 -0
  935. package/dist/winners-MJDKCGEZ.js +113 -0
  936. package/dist/winners-MJDKCGEZ.js.map +1 -0
  937. package/dist/winning-ads-NNU5MM75.js +84 -0
  938. package/dist/winning-ads-NNU5MM75.js.map +1 -0
  939. package/dist/write-commands-5I5KY6ZS.js +1015 -0
  940. package/dist/write-commands-5I5KY6ZS.js.map +1 -0
  941. package/dist/write-commands-DA6FIFAO.js +737 -0
  942. package/dist/write-commands-DA6FIFAO.js.map +1 -0
  943. package/dist/write-commands-KTPISQRE.js +206 -0
  944. package/dist/write-commands-KTPISQRE.js.map +1 -0
  945. package/dist/write-commands-QBGIWU27.js +713 -0
  946. package/dist/write-commands-QBGIWU27.js.map +1 -0
  947. package/dist/x-VCL5VRXC.js +47 -0
  948. package/dist/x-VCL5VRXC.js.map +1 -0
  949. package/package.json +9 -2
  950. package/dist/chunk-HJEMOSPH.js +0 -1292
  951. package/dist/chunk-HJEMOSPH.js.map +0 -1
  952. package/dist/chunk-JHKW6IDX.js +0 -9989
  953. package/dist/chunk-JHKW6IDX.js.map +0 -1
  954. package/dist/chunk-MF7YA62W.js.map +0 -1
  955. package/dist/chunk-VZEDAFAR.js.map +0 -1
  956. package/dist/chunk-XHC4LMK4.js.map +0 -1
  957. package/dist/client-GR6YL3YX.js +0 -17
  958. package/dist/output-NMQXZF3Z.js +0 -18
  959. /package/dist/{chunk-WLDM2TRF.js.map → chunk-2UFRHW3T.js.map} +0 -0
  960. /package/dist/{client-GR6YL3YX.js.map → chunk-YQSBHWOI.js.map} +0 -0
  961. /package/dist/{env-4P5HOGNA.js.map → client-EURRWXPW.js.map} +0 -0
  962. /package/dist/{output-NMQXZF3Z.js.map → connect-6DQFYKGN.js.map} +0 -0
  963. /package/dist/{shared-6762QE6R.js.map → customers-FOPXEGCB.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/research/customers.ts"],"sourcesContent":["import { mkdir, readdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type {\n ResearchFetchRequest,\n ResearchFetchResponse,\n ResearchRedditItem,\n TestimonialsSearchRequest,\n} from \"@baker/api\";\nimport { CUSTOMER_INSIGHTS_MODEL } from \"@baker/canvas-contract\";\nimport { defineCommand } from \"citty\";\nimport { parse as parseYaml } from \"yaml\";\nimport { z } from \"zod\";\nimport { apiGet, apiPost } from \"../../client.ts\";\nimport { askAboutText, type ReviewUsage } from \"../../engine/nodes/local/lib/render-review.ts\";\nimport { writeJson } from \"../../output.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport { findWorkspaceRoot } from \"../canvas/normalize-paths.ts\";\nimport { holdUnbilledSpend } from \"../canvas/unbilled-spend.ts\";\nimport { findSubreddits, searchReddit } from \"./reddit.ts\";\n\n/**\n * `baker research customers` — what real customers say, kept only where they said it.\n *\n * Ads start from a customer's own words. An agent asked for those words writes plausible ones,\n * and a plausible quote is the one thing an ad must never carry. So nothing here is written by\n * the agent or the model: the model only POINTS at a span of a fetched text, and the code keeps\n * that span only if it is in that text as written (`keepVerbatim`). One Knowledge file per\n * insight, `status: observed`.\n */\n\nexport const INSIGHT_TYPES = [\n \"accommodation\",\n \"failed_solution\",\n \"nearly_didnt\",\n \"word\",\n \"moment\",\n \"pain\",\n \"objection\",\n \"desire\",\n \"proof\",\n \"other\",\n] as const;\nexport type InsightType = (typeof INSIGHT_TYPES)[number];\n\nexport const FORCES = [\"push\", \"pull\", \"anxiety\", \"habit\"] as const;\nexport type Force = (typeof FORCES)[number];\n\nexport type SourceKind = \"review\" | \"testimonial\" | \"reddit\" | \"web\";\n\n/** One text a customer wrote, as the model is shown it and the gate checks it. */\nexport type CustomerSource = {\n /** What the insight cites: a URL, or `testimonials:<id>`. */\n ref: string;\n kind: SourceKind;\n text: string;\n /** One line: who said it, where. */\n context: string;\n /** When it was said, YYYY-MM-DD, when the source knows. */\n saidOn?: string;\n};\n\n/** What the model points at: a span of source number `source` (1-based, as the prompt numbers them). */\nexport type Candidate = {\n source: number;\n quote: string;\n type: InsightType;\n force?: Force;\n persona?: string;\n};\n\n/** A candidate whose quote is in its source as written. */\nexport type VerbatimInsight = Omit<Candidate, \"source\"> & { source: CustomerSource };\n\nexport const MAX_QUOTE_CHARS = 280;\n\n/** Curly and prime quote marks, by code point: single ones read as ', double ones as \". */\nconst SINGLE_QUOTES = new Set([0x2018, 0x2019, 0x201a, 0x201b, 0x2032]);\nconst DOUBLE_QUOTES = new Set([0x201c, 0x201d, 0x201e, 0x201f, 0x2033]);\n\nfunction foldChar(char: string): string {\n if (/\\s/.test(char)) return \" \";\n const code = char.codePointAt(0) ?? 0;\n if (SINGLE_QUOTES.has(code)) return \"'\";\n if (DOUBLE_QUOTES.has(code)) return '\"';\n return char.normalize(\"NFKC\").toLowerCase();\n}\n\n/**\n * A text in the form quotes are compared in (curly quotes straightened, spacing collapsed, case\n * folded), with, for each folded character, where it starts in the original.\n */\nfunction foldWithOffsets(text: string): { folded: string; offsets: number[] } {\n let folded = \"\";\n const offsets: number[] = [];\n let at = 0;\n for (const char of text) {\n const out = foldChar(char);\n const collapses = out === \" \" && (folded.length === 0 || folded.endsWith(\" \"));\n if (!collapses) {\n for (const piece of out) {\n folded += piece;\n offsets.push(at);\n }\n }\n at += char.length;\n }\n if (folded.endsWith(\" \")) {\n folded = folded.slice(0, -1);\n offsets.pop();\n }\n return { folded, offsets };\n}\n\n/**\n * Where `quote` sits in `text` under the comparison form, as the original's own characters\n * (spacing collapsed), or null when it is not there.\n */\nfunction findVerbatim(quote: string, text: string): string | null {\n const needle = foldWithOffsets(quote).folded;\n if (needle.length === 0) return null;\n const { folded, offsets } = foldWithOffsets(text);\n const start = folded.indexOf(needle);\n if (start < 0) return null;\n const last = offsets[start + needle.length - 1] ?? 0;\n const end = last + (String.fromCodePoint(text.codePointAt(last) ?? 0).length || 1);\n return text.slice(offsets[start], end).replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * The gate: a candidate survives only if its quote is in the source it cites, and what is kept\n * is the source's own spelling of that span, not the model's copy of it. Everything else (a\n * paraphrase, a quote cited to the wrong text, a source that does not exist) is dropped and\n * counted, never repaired; a span longer than MAX_QUOTE_CHARS is counted apart. Pure.\n */\nexport function keepVerbatim(\n candidates: readonly Candidate[],\n sources: readonly CustomerSource[],\n): { kept: VerbatimInsight[]; dropped: number; tooLong: number } {\n const kept: VerbatimInsight[] = [];\n let dropped = 0;\n let tooLong = 0;\n for (const { source: index, ...rest } of candidates) {\n const source = sources[index - 1];\n const quote = source ? findVerbatim(rest.quote, source.text) : null;\n if (!source || !quote) {\n dropped++;\n continue;\n }\n if (quote.length > MAX_QUOTE_CHARS) {\n tooLong++;\n continue;\n }\n kept.push({ ...rest, quote, source });\n }\n return { kept, dropped, tooLong };\n}\n\nconst SLUG_WORDS = 6;\n\n/** Lowercase ASCII words, accents dropped. */\nfunction asciiWords(text: string): string[] {\n return text\n .normalize(\"NFKD\")\n .replace(/\\p{M}/gu, \"\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \" \")\n .trim()\n .split(\" \")\n .filter(Boolean);\n}\n\n/** The file name an insight gets: its type, then the first words of its quote, kebab-case ASCII. Pure. */\nfunction insightSlug(type: InsightType, quote: string): string {\n return [type.replace(/_/g, \"-\"), ...asciiWords(quote).slice(0, SLUG_WORDS)].join(\"-\");\n}\n\nexport type PlannedInsight = { id: string; insight: VerbatimInsight };\n\n/**\n * Which insights to write and under what id. The first five types first (they write most of an\n * ad), at most `limit`. A quote already on file (or already planned) is skipped; an id held by a\n * different quote gets a `-2`, `-3`… so a file is never overwritten. Pure.\n */\nexport function planInsightWrites(\n insights: readonly VerbatimInsight[],\n existing: readonly { id: string; quote: string }[],\n limit: number,\n): { writes: PlannedInsight[]; skippedExisting: number } {\n const quotes = new Set(existing.map((e) => foldWithOffsets(e.quote).folded));\n const ids = new Set(existing.map((e) => e.id));\n const ranked = [...insights].sort((a, b) => INSIGHT_TYPES.indexOf(a.type) - INSIGHT_TYPES.indexOf(b.type));\n const writes: PlannedInsight[] = [];\n let skippedExisting = 0;\n for (const insight of ranked) {\n const folded = foldWithOffsets(insight.quote).folded;\n if (quotes.has(folded)) {\n skippedExisting++;\n continue;\n }\n if (writes.length >= limit) continue;\n const base = insightSlug(insight.type, insight.quote);\n let id = base;\n for (let n = 2; ids.has(id); n++) id = `${base}-${n}`;\n quotes.add(folded);\n ids.add(id);\n writes.push({ id, insight });\n }\n return { writes, skippedExisting };\n}\n\n/** A frontmatter string, YAML-safe: a JSON string is a valid double-quoted YAML scalar. */\nfunction yamlScalar(value: string): string {\n return JSON.stringify(value);\n}\n\nconst TITLE_CHARS = 70;\n\n/** The quote's opening words as the entry's title, in quote marks, so the Knowledge list reads as what was said. */\nfunction insightTitle(quote: string): string {\n const text = quote.replace(/[\"“”]/g, \"\").replace(/\\s+/g, \" \").trim();\n if (text.length <= TITLE_CHARS) return `“${text}”`;\n const cut = text.slice(0, TITLE_CHARS);\n return `“${cut.slice(0, cut.lastIndexOf(\" \")).replace(/[,;:.]$/, \"\")}…”`;\n}\n\n/**\n * The insight's Knowledge file (`src/content/insights/<id>.md`): frontmatter per the `insights`\n * collection, `status: observed`, and one line of context as the body. Pure.\n */\nexport function renderInsightFile(insight: VerbatimInsight, opts: { today: string; product?: string }): string {\n const { source } = insight;\n const lines = [\n \"---\",\n `title: ${yamlScalar(insightTitle(insight.quote))}`,\n `type: ${insight.type}`,\n `quote: ${yamlScalar(insight.quote)}`,\n `source: ${yamlScalar(source.ref)}`,\n `sourceKind: ${source.kind}`,\n `seenAt: ${yamlScalar(source.saidOn ?? opts.today)}`,\n \"status: observed\",\n ];\n if (insight.force) lines.push(`force: ${insight.force}`);\n if (insight.persona?.trim()) lines.push(`persona: ${yamlScalar(insight.persona.trim())}`);\n if (opts.product) lines.push(`product: ${yamlScalar(opts.product)}`);\n lines.push(\"---\", \"\", source.context.replace(/\\s+/g, \" \").trim(), \"\");\n return lines.join(\"\\n\");\n}\n\n/** How much of one review or comment the model reads (and the gate checks against). */\nconst MAX_SHORT_SOURCE_CHARS = 1_500;\n\nconst PLATFORM_NAMES: Record<string, string> = {\n google: \"Google\",\n trustpilot: \"Trustpilot\",\n yelp: \"Yelp\",\n tripadvisor: \"Tripadvisor\",\n g2: \"G2\",\n capterra: \"Capterra\",\n amazon: \"Amazon\",\n app_store: \"App Store\",\n google_play: \"Google Play\",\n};\n\n/** One library review as `/api/testimonials` returns it, read loosely so a new field never empties the list. */\nconst LibraryReviewSchema = z.object({\n _id: z.string().min(1),\n reviewText: z.string(),\n sourceType: z.string().optional(),\n reviewerName: z.string().optional(),\n rating: z.number().optional(),\n reviewDate: z.number().optional(),\n});\n\nfunction dayOf(ms: number | string): string | undefined {\n const date = new Date(ms);\n return Number.isNaN(date.getTime()) ? undefined : date.toISOString().slice(0, 10);\n}\n\n/** \"A …\" or \"An …\", ending in one full stop. */\nfunction sentence(rest: string): string {\n const line = `${/^[aeiou]/i.test(rest) ? \"An\" : \"A\"} ${rest}`;\n return line.endsWith(\".\") ? line : `${line}.`;\n}\n\n/** \"A 4★ Trustpilot review by Marta G.\" */\nfunction reviewContext(review: z.infer<typeof LibraryReviewSchema>): string {\n const platform = review.sourceType ? `${PLATFORM_NAMES[review.sourceType] ?? review.sourceType} ` : \"\";\n const rating = review.rating !== undefined ? `${review.rating}★ ` : \"\";\n const by = review.reviewerName?.trim() ? ` by ${review.reviewerName.trim()}` : \"\";\n return sentence(`${rating}${platform}review${by}`);\n}\n\n/** The company's reviews (a plain list from `/api/testimonials`) as sources, each cited `testimonials:<id>`. Pure. */\nexport function sourcesFromTestimonials(data: unknown): CustomerSource[] {\n const list = Array.isArray(data) ? data : [];\n return list.flatMap((item): CustomerSource[] => {\n const parsed = LibraryReviewSchema.safeParse(item);\n if (!parsed.success) return [];\n const review = parsed.data;\n const text = review.reviewText.trim().slice(0, MAX_SHORT_SOURCE_CHARS);\n if (!text) return [];\n const saidOn = review.reviewDate !== undefined ? dayOf(review.reviewDate) : undefined;\n return [\n {\n ref: `testimonials:${review._id}`,\n kind: \"review\",\n text,\n context: reviewContext(review),\n ...(saidOn ? { saidOn } : {}),\n },\n ];\n });\n}\n\n/** Reddit posts and comments as sources, each cited by its own permalink; a post's title counts as its words. Pure. */\nexport function sourcesFromReddit(items: readonly ResearchRedditItem[]): CustomerSource[] {\n return items.flatMap((item): CustomerSource[] => {\n const words = item.kind === \"post\" ? [item.title ?? \"\", item.text].filter((t) => t.trim()).join(\"\\n\\n\") : item.text;\n const text = words.trim().slice(0, MAX_SHORT_SOURCE_CHARS);\n if (!text) return [];\n const under = item.kind === \"comment\" && item.title ? `, under ${JSON.stringify(item.title)}` : \"\";\n const saidOn = dayOf(item.createdAt);\n return [\n {\n ref: item.permalink,\n kind: \"reddit\",\n text,\n context: `A Reddit ${item.kind} in r/${item.subreddit}${under}.`,\n ...(saidOn ? { saidOn } : {}),\n },\n ];\n });\n}\n\n/** How much of one web page the model reads (and the gate checks against). */\nconst MAX_PAGE_SOURCE_CHARS = 6_000;\n\n/** Pages read with `research fetch` as sources, each cited by where the read landed. Pure. */\nexport function sourcesFromPages(pages: readonly ResearchFetchResponse[]): CustomerSource[] {\n return pages.flatMap((page): CustomerSource[] => {\n const text = page.content.trim().slice(0, MAX_PAGE_SOURCE_CHARS);\n if (!text) return [];\n const host = URL.canParse(page.finalUrl) ? new URL(page.finalUrl).host : page.finalUrl;\n const title = page.title?.trim() ? `, ${JSON.stringify(page.title.trim())}` : \"\";\n return [{ ref: page.finalUrl, kind: \"web\", text, context: `A page on ${host}${title}.` }];\n });\n}\n\n/**\n * The classification prompt: numbered texts, and the instruction to point at exact spans of\n * them. What comes back is only a pointer; `keepVerbatim` decides what is kept. Pure.\n */\nexport function buildCustomersPrompt(sources: readonly CustomerSource[], focus?: string): string {\n return [\n `Below are ${sources.length} numbered texts written by real customers (reviews, testimonials, forum posts and comments, web pages)${focus ? `, gathered about: ${focus}` : \"\"}.`,\n \"Find the customer truths in them, the material ads are written from.\",\n \"\",\n \"Rules:\",\n \"- Every quote must be an EXACT substring of the text it cites: the same words, in the same order, with the same spelling and typos. Copy, never paraphrase, translate, summarize, correct or join two passages.\",\n `- The shortest span that carries the truth, at most ${MAX_QUOTE_CHARS} characters.`,\n \"- Only the customer's own words: skip a seller's reply, an ad, a page's marketing copy, and a text with no truth in it. Return fewer, or none, rather than invent.\",\n \"- type: accommodation (a workaround they live with), failed_solution (what they tried before that failed them), nearly_didnt (what nearly stopped them buying), word (their own word or phrase for the problem), moment (the moment that started their search), pain, objection, desire, proof (a result they got), other.\",\n \"- force, when it speaks to one: push (what pushes them off the old way), pull (what draws them to the new one), anxiety (what they fear about changing), habit (what keeps them where they are).\",\n '- persona: a few words on who is speaking, only when the text says it (\"restaurant owner\", \"night-shift courier\").',\n \"\",\n 'Reply with only this JSON: {\"insights\":[{\"source\":1,\"quote\":\"\",\"type\":\"\",\"force\":\"\",\"persona\":\"\"}]}',\n \"\",\n \"Texts:\",\n ...sources.map((source, i) => `[${i + 1}] ${source.text}`),\n ].join(\"\\n\");\n}\n\nconst AnswerSchema = z.object({ insights: z.array(z.unknown()) });\n\nconst CandidateSchema = z.object({\n source: z.coerce.number().int().positive(),\n quote: z.string().trim().min(1),\n type: z.enum(INSIGHT_TYPES).catch(\"other\"),\n force: z.enum(FORCES).optional().catch(undefined),\n persona: z.string().trim().optional().catch(undefined),\n});\n\n/** The model's spans, or null when the reply is not the asked shape. An item that is not a span is dropped. Pure. */\nexport function candidatesFrom(answer: unknown): Candidate[] | null {\n const parsed = AnswerSchema.safeParse(answer);\n if (!parsed.success) return null;\n return parsed.data.insights.flatMap((item): Candidate[] => {\n const candidate = CandidateSchema.safeParse(item);\n if (!candidate.success) return [];\n const { source, quote, type, force, persona } = candidate.data;\n return [{ source, quote, type, ...(force ? { force } : {}), ...(persona ? { persona } : {}) }];\n });\n}\n\n/** Sources in batches of at most `budget` characters of text; a source is never split. Pure. */\nexport function batchSources(sources: readonly CustomerSource[], budget: number): CustomerSource[][] {\n const batches: CustomerSource[][] = [];\n let current: CustomerSource[] = [];\n let size = 0;\n for (const source of sources) {\n if (current.length > 0 && size + source.text.length > budget) {\n batches.push(current);\n current = [];\n size = 0;\n }\n current.push(source);\n size += source.text.length;\n }\n if (current.length > 0) batches.push(current);\n return batches;\n}\n\n/** How many insights answered per source; null when the source was not asked or did not answer. */\nexport type SourceCounts = { testimonials: number | null; reddit: number | null; web: number | null };\n\nconst FEW_OBSERVED = 5;\n\n/** What the agent does next. Pure. */\nexport function customersHints(input: { written: number; sources: SourceCounts }): string[] {\n const { written, sources } = input;\n const widen =\n 'Search in the customers\\' own words with --query \"<the words they write>\" (their phrasing, not a category name), or add --web.';\n if (written === 0) {\n return [\n \"No customer words were found to keep, so nothing was written. Import where customers already talk: `baker testimonials sources add <review page link>` (Google, Trustpilot, G2, app stores…) brings their reviews into the library; then run this again.\",\n ...(sources.reddit === null\n ? ['Reddit was not read: pass --focus \"<product>\" or --query \"<their words>\".']\n : [widen]),\n \"Until there are observed truths, ad ideas go in as explore bets: an idea with an empty `evidence` list.\",\n ];\n }\n const cite = `Cite these by id in an idea's \\`evidence\\` (src/creatives/_ideas/<idea>.md); write the ad from the quote as said.`;\n return written < FEW_OBSERVED ? [`Only ${written} observed. ${widen}`, cite] : [cite];\n}\n\n// ---------------------------------------------------------------------------\n// The command: gather, classify, gate, write\n// ---------------------------------------------------------------------------\n\nconst INSIGHTS_DIR = path.join(\"src\", \"content\", \"insights\");\nconst BATCH_CHARS = 24_000;\nconst MAX_BATCHES = 5;\nconst WEB_PAGES = 3;\nconst DEFAULT_LIMIT = 20;\nconst SHOWN_QUOTE_CHARS = 120;\nconst READ_TIMEOUT_MS = 180_000;\n\nconst DESCRIPTION = `Gather what real customers say and keep it as Knowledge: one file per customer truth in src/content/insights/<id>.md, each a quote found word for word in its source (status: observed). Ads and ideas are written from these.\n\nStart here: baker research customers --focus \"<product or persona>\"\n\nReads the company's review library, Reddit (with --focus or --query) and, with --web, a few web pages. A model only points at spans; a quote is kept only if it appears verbatim in the text it came from, and everything else is dropped and counted. Never write an insight by hand.\n\nExamples:\n baker research customers --focus \"payroll app for restaurants\"\n baker research customers --query \"chasing invoices\" --web\n baker research customers --dry-run`;\n\nconst ARGS = {\n focus: {\n type: \"string\",\n required: false,\n description:\n 'The product or persona to listen for, e.g. \"payroll for restaurants\". Also the Reddit search when --query is not given.',\n },\n query: {\n type: \"string\",\n required: false,\n description: 'Search terms in the customers\\' own words, e.g. \"chasing invoices\". Used for Reddit and the web.',\n },\n limit: { type: \"string\", required: false, description: `Most insights written (default ${DEFAULT_LIMIT}).` },\n web: {\n type: \"boolean\",\n required: false,\n default: false,\n description: `Also read up to ${WEB_PAGES} web pages where customers talk about it (slower).`,\n },\n \"dry-run\": {\n type: \"boolean\",\n required: false,\n default: false,\n description: \"Show what would be written; write nothing.\",\n },\n full: {\n type: \"boolean\",\n required: false,\n default: false,\n description: \"Add each insight's whole quote, source and context.\",\n },\n} as const;\n\nregisterSchema({ command: \"research.customers\", description: DESCRIPTION, args: ARGS });\n\nconst QuoteFrontmatter = z.object({ quote: z.string() });\n\n/** An insight file's `quote`, or \"\" when it has none that reads. */\nfunction quoteOf(raw: string): string {\n const front = raw.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---/)?.[1];\n if (!front) return \"\";\n try {\n const parsed = QuoteFrontmatter.safeParse(parseYaml(front));\n return parsed.success ? parsed.data.quote : \"\";\n } catch {\n return \"\";\n }\n}\n\n/** The insights already on file, id and quote. Never throws. */\nasync function readExistingInsights(dir: string): Promise<{ id: string; quote: string }[]> {\n const files = (await readdir(dir).catch(() => [] as string[])).filter((f) => f.endsWith(\".md\"));\n return await Promise.all(\n files.map(async (file) => ({\n id: file.slice(0, -3),\n quote: quoteOf(await readFile(path.join(dir, file), \"utf8\").catch(() => \"\")),\n })),\n );\n}\n\n/** The product entries' names (file slugs). Never throws. */\nasync function productSlugs(root: string): Promise<string[]> {\n const files = await readdir(path.join(root, \"src\", \"content\", \"products\")).catch(() => [] as string[]);\n return files.filter((f) => f.endsWith(\".md\")).map((f) => f.slice(0, -3));\n}\n\n/** The library's reviews: the ones about --focus when given, else the latest. Null when the library did not answer. */\nasync function gatherTestimonials(focus: string | undefined): Promise<CustomerSource[] | null> {\n try {\n const search: TestimonialsSearchRequest = { query: focus ?? \"\", limit: 40 };\n const data = focus\n ? await apiPost<unknown>(\"/api/testimonials/search\", search)\n : await apiGet<unknown>(\"/api/testimonials\", { limit: \"50\" });\n return sourcesFromTestimonials(data);\n } catch {\n return null;\n }\n}\n\n/** Reddit posts and comments matching `query`, in the subreddits where it is talked about. Null when Reddit did not answer. */\nasync function gatherReddit(query: string): Promise<CustomerSource[] | null> {\n const subreddits = await findSubreddits({ query: query.slice(0, 100), limit: 3 })\n .then((r) => r.results.filter((s) => s.access !== \"private\").map((s) => s.name))\n .catch(() => [] as string[]);\n const answers = await Promise.allSettled([\n searchReddit({ query, subreddits, kind: \"posts\", limit: 15 }),\n ...(subreddits.length > 0 ? [searchReddit({ query, subreddits, kind: \"comments\", limit: 25 })] : []),\n ]);\n if (answers.every((a) => a.status === \"rejected\")) return null;\n const seen = new Set<string>();\n const items = answers\n .flatMap((a) => (a.status === \"fulfilled\" ? a.value.results : []))\n .filter((item) => !seen.has(item.id) && Boolean(seen.add(item.id)));\n return sourcesFromReddit(items);\n}\n\nconst ExploreAnswer = z.object({ sources: z.array(z.object({ url: z.string() })) });\n\n/**\n * Web research cites its pages through Google's grounding redirect; a quote must cite the page\n * itself, so the redirect is followed once (no body read). Any other URL, or a redirect that does\n * not answer, is kept as it is.\n */\nasync function resolveGroundingRedirect(url: string): Promise<string> {\n if (!URL.canParse(url) || new URL(url).host !== \"vertexaisearch.cloud.google.com\") return url;\n try {\n const response = await fetch(url, { method: \"HEAD\", redirect: \"manual\", signal: AbortSignal.timeout(15_000) });\n const location = response.headers.get(\"location\");\n return location && URL.canParse(location) ? location : url;\n } catch {\n return url;\n }\n}\n\n/** A few web pages where customers talk about `topic`, each read whole. Null when the web did not answer. */\nasync function gatherWeb(topic: string): Promise<CustomerSource[] | null> {\n let urls: string[];\n try {\n const found = ExploreAnswer.parse(\n await apiPost<unknown>(\n \"/api/research/explore\",\n {\n question: `Which pages carry first-hand customer comments about ${topic}, in the customers' own words: reviews, complaints, forum threads?`,\n depth: \"medium\",\n },\n { timeoutMs: READ_TIMEOUT_MS },\n ),\n );\n urls = (await Promise.all(found.sources.slice(0, WEB_PAGES * 2).map((s) => resolveGroundingRedirect(s.url))))\n .filter((u) => !/reddit\\.com/i.test(u))\n .filter((u, i, all) => all.indexOf(u) === i);\n } catch {\n return null;\n }\n const pages = await Promise.allSettled(\n urls.slice(0, WEB_PAGES).map((url) => {\n const body: ResearchFetchRequest = { url };\n return apiPost<ResearchFetchResponse>(\"/api/research/fetch\", body, { timeoutMs: READ_TIMEOUT_MS });\n }),\n );\n return sourcesFromPages(pages.flatMap((p) => (p.status === \"fulfilled\" ? [p.value] : [])));\n}\n\n/** One batch's spans, asked at most twice; null when the model never answered in shape. */\nasync function classifyBatch(\n batch: CustomerSource[],\n focus: string | undefined,\n onSpend: (usage: ReviewUsage) => void,\n): Promise<Candidate[] | null> {\n const prompt = buildCustomersPrompt(batch, focus);\n for (let attempt = 0; attempt < 2; attempt++) {\n const candidates = candidatesFrom(await askAboutText(CUSTOMER_INSIGHTS_MODEL, prompt, onSpend));\n if (candidates) return candidates;\n }\n return null;\n}\n\n/** Sources taken in turn from each list, so every kind reaches the model when there is more than it reads. */\nfunction interleave(lists: readonly CustomerSource[][]): CustomerSource[] {\n const out: CustomerSource[] = [];\n const longest = Math.max(0, ...lists.map((l) => l.length));\n for (let i = 0; i < longest; i++) {\n for (const list of lists) {\n const source = list[i];\n if (source) out.push(source);\n }\n }\n return out;\n}\n\nfunction fail(code: string, message: string, fix: string): never {\n writeJson({ ok: false, error: { code, message, fix } });\n process.exit(1);\n}\n\n/** Every source asked at once; one that does not answer is null and never stops the rest. */\nasync function gatherSources(opts: { focus?: string; topic?: string; web: boolean }) {\n const { focus, topic, web: withWeb } = opts;\n const [testimonials, reddit, web] = await Promise.all([\n gatherTestimonials(focus),\n topic ? gatherReddit(topic) : Promise.resolve(null),\n withWeb && topic ? gatherWeb(topic) : Promise.resolve(null),\n ]);\n const counts: SourceCounts = {\n testimonials: testimonials?.length ?? null,\n reddit: reddit?.length ?? null,\n web: web?.length ?? null,\n };\n return { all: interleave([testimonials ?? [], reddit ?? [], web ?? []]), counts };\n}\n\n/**\n * Every batch classified and gated; null when the model answered no batch at all. The spend\n * waits in the workspace's canvas cache: no run record carries these calls, so the next render\n * of this workspace bills them.\n */\nasync function classifyAll(\n sources: readonly CustomerSource[],\n focus: string | undefined,\n root: string,\n): Promise<{ kept: VerbatimInsight[]; dropped: number; tooLong: number } | null> {\n const batches = batchSources(sources, BATCH_CHARS).slice(0, MAX_BATCHES);\n const spent: ReviewUsage[] = [];\n const answers = await Promise.all(batches.map((batch) => classifyBatch(batch, focus, (u) => spent.push(u))));\n await holdUnbilledSpend(path.join(root, \"canvas\", \".cache\"), spent);\n if (batches.length > 0 && answers.every((a) => a === null)) return null;\n const result = { kept: [] as VerbatimInsight[], dropped: 0, tooLong: 0 };\n batches.forEach((batch, i) => {\n const gated = keepVerbatim(answers[i] ?? [], batch);\n result.kept.push(...gated.kept);\n result.dropped += gated.dropped;\n result.tooLong += gated.tooLong;\n });\n return result;\n}\n\n/** Writes each planned file, never over one that appeared since the plan (`wx`); returns what was written. */\nasync function writeInsights(\n dir: string,\n writes: readonly PlannedInsight[],\n opts: { today: string; product?: string },\n): Promise<PlannedInsight[]> {\n if (writes.length === 0) return [];\n await mkdir(dir, { recursive: true });\n const written: PlannedInsight[] = [];\n for (const entry of writes) {\n const file = renderInsightFile(entry.insight, opts);\n const ok = await writeFile(path.join(dir, `${entry.id}.md`), file, { encoding: \"utf8\", flag: \"wx\" }).then(\n () => true,\n () => false,\n );\n if (ok) written.push(entry);\n }\n return written;\n}\n\nfunction writtenRow({ id, insight }: PlannedInsight, full: boolean) {\n const quote =\n insight.quote.length > SHOWN_QUOTE_CHARS ? `${insight.quote.slice(0, SHOWN_QUOTE_CHARS)}…` : insight.quote;\n if (!full) return { id, type: insight.type, quote };\n return {\n id,\n type: insight.type,\n quote,\n full_quote: insight.quote,\n source: insight.source.ref,\n context: insight.source.context,\n ...(insight.force ? { force: insight.force } : {}),\n ...(insight.persona ? { persona: insight.persona } : {}),\n };\n}\n\n/** What the run listens for: the product a --focus names, and the words Reddit and the web are searched with. */\nasync function resolveTopic(root: string, focus: string | undefined, query: string | undefined) {\n const products = await productSlugs(root);\n const product = focus ? products.find((slug) => slug === asciiWords(focus).join(\"-\")) : undefined;\n const firstProduct = products[0];\n const topic = query ?? focus ?? (firstProduct ? asciiWords(firstProduct).join(\" \") : undefined);\n return { product, topic };\n}\n\n/**\n * Gathers, classifies, gates and writes customer truths into the workspace; null when the model\n * answered no batch. Shared with `baker creatives brief`, which runs it when few quotes are on file.\n */\nexport async function researchCustomers(\n root: string,\n opts: { focus?: string; query?: string; limit?: number; web?: boolean; dryRun?: boolean },\n) {\n const { focus, query, limit = DEFAULT_LIMIT, web = false, dryRun = false } = opts;\n const { product, topic } = await resolveTopic(root, focus, query);\n const { all, counts } = await gatherSources({ focus, topic, web });\n const gated = await classifyAll(all, focus, root);\n if (!gated) return null;\n const dir = path.join(root, INSIGHTS_DIR);\n const plan = planInsightWrites(gated.kept, await readExistingInsights(dir), limit);\n const today = new Date().toISOString().slice(0, 10);\n const shown = dryRun\n ? plan.writes\n : await writeInsights(dir, plan.writes, { today, ...(product ? { product } : {}) });\n return { shown, plan, gated, counts };\n}\n\nexport const customersCommand = defineCommand({\n meta: { name: \"customers\", description: DESCRIPTION },\n args: ARGS,\n async run({ args }) {\n const focus = args.focus?.trim() || undefined;\n const query = args.query?.trim() || undefined;\n const limit = args.limit === undefined ? DEFAULT_LIMIT : Number(args.limit);\n if (!Number.isInteger(limit) || limit < 1 || limit > 100) {\n fail(\"VALIDATION_ERROR\", \"--limit must be a whole number from 1 to 100.\", \"Run it again with --limit 20.\");\n }\n const dryRun = Boolean(args[\"dry-run\"]);\n const root = findWorkspaceRoot(process.cwd()) ?? process.cwd();\n const found = await researchCustomers(root, { focus, query, limit, web: Boolean(args.web), dryRun });\n if (!found) {\n fail(\n \"UNAVAILABLE\",\n \"The model that picks out customer words did not answer (no gateway key here, or it failed twice).\",\n \"Run it again. Do not write insights by hand: an insight is only a quote this command found in its source.\",\n );\n }\n const { shown, plan, gated, counts } = found;\n\n writeJson({\n ok: true,\n data: {\n ...(dryRun ? { dry_run: true } : {}),\n written: shown.map((entry) => writtenRow(entry, Boolean(args.full))),\n skipped_existing: plan.skippedExisting,\n dropped_not_verbatim: gated.dropped,\n ...(gated.tooLong > 0 ? { dropped_too_long: gated.tooLong } : {}),\n sources: counts,\n },\n hints: customersHints({ written: shown.length, sources: counts }),\n });\n },\n});\n"],"mappings":"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","names":[]}
@@ -0,0 +1,225 @@
1
+ // ../api/src/capabilities/surfaces.ts
2
+ var CAPABILITY_SURFACES = [
3
+ "google-ads",
4
+ "meta-ads",
5
+ "linkedin-ads",
6
+ "x-ads",
7
+ "chatgpt-ads",
8
+ "tag-manager",
9
+ "ga4",
10
+ "gsc",
11
+ "shopify"
12
+ ];
13
+ var CAPABILITY_SURFACE_SPECS = {
14
+ "google-ads": {
15
+ id: "google-ads",
16
+ label: "Google Ads",
17
+ provider: "google-ads",
18
+ resourceNoun: "ad account",
19
+ writePath: "staged-live",
20
+ writeScopes: ["https://www.googleapis.com/auth/adwords"],
21
+ commands: "baker ads google"
22
+ },
23
+ "meta-ads": {
24
+ id: "meta-ads",
25
+ label: "Meta Ads",
26
+ provider: "meta",
27
+ resourceNoun: "ad account",
28
+ writePath: "staged-live",
29
+ writeScopes: ["ads_management"],
30
+ commands: "baker ads meta"
31
+ },
32
+ "linkedin-ads": {
33
+ id: "linkedin-ads",
34
+ label: "LinkedIn Ads",
35
+ provider: "linkedin",
36
+ resourceNoun: "ad account",
37
+ writePath: "staged-live",
38
+ writeScopes: ["rw_ads"],
39
+ commands: "baker ads linkedin"
40
+ },
41
+ "x-ads": {
42
+ id: "x-ads",
43
+ label: "X Ads",
44
+ provider: "x-ads",
45
+ resourceNoun: "ad account",
46
+ writePath: "staged-live",
47
+ /**
48
+ * Empty on purpose, and the one surface where that does NOT mean read-only.
49
+ * X Ads authenticates with OAuth 1.0a, which has no scope strings at all —
50
+ * write access is granted to the *app* by X's Ads API access review, not
51
+ * per connection. There is therefore no scope to check, and inventing one
52
+ * would make `scopeBlockers` refuse every X write for a permission that
53
+ * does not exist.
54
+ */
55
+ writeScopes: [],
56
+ commands: "baker ads x"
57
+ },
58
+ "chatgpt-ads": {
59
+ id: "chatgpt-ads",
60
+ label: "ChatGPT Ads",
61
+ // Connected with the client's own Ads API key (`chatgptAdsConnections`), not an OAuth grant.
62
+ provider: "chatgpt-ads",
63
+ resourceNoun: "ad account",
64
+ writePath: "staged-live",
65
+ /**
66
+ * Empty because the pasted key has no scopes: it reaches its one account
67
+ * whole. When OpenAI approves Baker's OAuth app this becomes
68
+ * `ads.admin.all.write` and `connectsWith` goes away.
69
+ */
70
+ writeScopes: [],
71
+ commands: "baker ads chatgpt",
72
+ connectsWith: "api-key"
73
+ },
74
+ "tag-manager": {
75
+ id: "tag-manager",
76
+ label: "Tag Manager",
77
+ provider: "google-tag-manager",
78
+ resourceNoun: "container",
79
+ writePath: "staged-immediate",
80
+ writeScopes: [
81
+ "https://www.googleapis.com/auth/tagmanager.edit.containers",
82
+ "https://www.googleapis.com/auth/tagmanager.edit.containerversions",
83
+ "https://www.googleapis.com/auth/tagmanager.publish"
84
+ ],
85
+ commands: "baker tag-manager"
86
+ },
87
+ ga4: {
88
+ id: "ga4",
89
+ label: "Google Analytics 4",
90
+ provider: "google-analytics",
91
+ resourceNoun: "property",
92
+ // Like Tag Manager: staged during the chat, applied for real at publish,
93
+ // every time. A connection made before writes existed is
94
+ // read-only until it is reconnected, and `access` does NOT say so — it
95
+ // reports what the Baker app asks Google for, which is now app-wide
96
+ // read-write. The per-company signal is `scopeBlockers`, which compares
97
+ // `writeScopes` against the scopes that connection actually recorded.
98
+ writePath: "staged-immediate",
99
+ writeScopes: ["https://www.googleapis.com/auth/analytics.edit"],
100
+ commands: "baker ga4"
101
+ },
102
+ gsc: {
103
+ id: "gsc",
104
+ label: "Search Console",
105
+ provider: "google-search-console",
106
+ resourceNoun: "site",
107
+ writePath: "read-only",
108
+ writeScopes: ["https://www.googleapis.com/auth/webmasters"],
109
+ commands: "baker gsc"
110
+ },
111
+ shopify: {
112
+ id: "shopify",
113
+ label: "Shopify store",
114
+ provider: "shopify",
115
+ resourceNoun: "store",
116
+ // Staged during the chat and applied to the real store when it completes,
117
+ // every time; each applied change can be put back by another publish
118
+ // (`baker shopify undo`). The write permissions are optional scopes the
119
+ // store grants when a change first needs one, so `scopeBlockers` is the
120
+ // per-company signal.
121
+ writePath: "staged-immediate",
122
+ writeScopes: [
123
+ "write_products",
124
+ "write_publications",
125
+ "write_discounts",
126
+ "write_online_store_navigation",
127
+ "write_marketing_events"
128
+ ],
129
+ commands: "baker shopify"
130
+ }
131
+ };
132
+
133
+ // ../api/src/capabilities/index.ts
134
+ import { z } from "zod";
135
+ var capabilitySurfaceSchema = z.enum(CAPABILITY_SURFACES);
136
+ var capabilitiesRequestSchema = z.object({
137
+ /** Narrow to one surface. Omit for every surface the company could use. */
138
+ surface: capabilitySurfaceSchema.optional(),
139
+ /** Include the field-level contract of every op, not just the entity list. */
140
+ full: z.boolean().optional(),
141
+ /**
142
+ * Who the chat acts as (`BAKER_ACTING_USER_ID`). Adds that person's own
143
+ * connected tools — they load for this turn, and for nobody else's.
144
+ */
145
+ actingUserId: z.string().optional()
146
+ });
147
+ var capabilityResourceSchema = z.object({
148
+ id: z.string(),
149
+ name: z.string().optional()
150
+ });
151
+ var capabilityOpSchema = z.object({
152
+ kind: z.string(),
153
+ /** True when the op changes something that already exists and must be named. */
154
+ needsTarget: z.boolean(),
155
+ required: z.array(z.string()),
156
+ optional: z.array(z.string()),
157
+ /** Field → the values it accepts, for fields that take a fixed set. */
158
+ choices: z.record(z.string(), z.array(z.string())),
159
+ /** False when the platform accepts fields beyond the listed ones. */
160
+ fieldsAreComplete: z.boolean()
161
+ });
162
+ var capabilityLimitViewSchema = z.object({
163
+ capability: z.string(),
164
+ cause: z.enum(["not_built", "provider_forbids", "no_permission"]),
165
+ detail: z.string()
166
+ });
167
+ var capabilityWriteModeSchema = z.enum(["live", "applies-at-publish", "none"]);
168
+ var capabilitySurfaceReportSchema = z.object({
169
+ surface: capabilitySurfaceSchema,
170
+ label: z.string(),
171
+ connected: z.boolean(),
172
+ /** What the user picked when connecting. Empty when nothing is selected yet. */
173
+ resources: z.array(capabilityResourceSchema),
174
+ access: z.enum(["read-write", "read-only", "not-connected"]),
175
+ writeMode: capabilityWriteModeSchema,
176
+ /** One sentence about the write mode, safe to repeat to the user. */
177
+ writeModeNote: z.string(),
178
+ /** Entities this surface can change at all, e.g. "campaign", "keyword". */
179
+ writableEntities: z.array(z.string()),
180
+ /** Things wrong with the connection itself: needs reconnecting, missing a permission. */
181
+ blockers: z.array(z.string()),
182
+ /** What cannot be done here, and why. */
183
+ limits: z.array(capabilityLimitViewSchema),
184
+ /** The per-op contract. Present when one surface was asked for, or with `full`. */
185
+ ops: z.array(capabilityOpSchema).optional(),
186
+ /** Where to look next: `baker ads google`, `baker ga4`, … */
187
+ commands: z.string()
188
+ });
189
+ var capabilityToolSchema = z.object({
190
+ /** `microsoft_clarity`, `hubspot`, or the name the user gave a custom server. */
191
+ key: z.string(),
192
+ label: z.string(),
193
+ /** `mcp` — tools in the agent's own list. `platform` — signed in, read through the CLI. */
194
+ kind: z.enum(["mcp", "platform"]),
195
+ /** How to actually reach it, in one phrase the agent can act on. */
196
+ reach: z.string(),
197
+ /**
198
+ * Whether it can be used right now.
199
+ *
200
+ * A connection that exists and is expired is worse than one that is absent:
201
+ * it reads as available and fails at the moment it is needed, which on an
202
+ * unattended run is a report with a hole in it and no explanation.
203
+ */
204
+ ready: z.boolean(),
205
+ /** Why it is not ready, or what it is for. Absent when neither needs saying. */
206
+ note: z.string().optional()
207
+ });
208
+ var capabilitiesResponseSchema = z.object({
209
+ ok: z.literal(true),
210
+ data: z.object({
211
+ surfaces: z.array(capabilitySurfaceReportSchema),
212
+ /**
213
+ * Everything else this company can reach. Shared connections only —
214
+ * a teammate's private per-user connection belongs to whoever started the
215
+ * session and is visible in the agent's own tool list, not here.
216
+ */
217
+ tools: z.array(capabilityToolSchema)
218
+ })
219
+ });
220
+
221
+ export {
222
+ CAPABILITY_SURFACES,
223
+ CAPABILITY_SURFACE_SPECS
224
+ };
225
+ //# sourceMappingURL=chunk-UI6BKYQD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../api/src/capabilities/surfaces.ts","../../api/src/capabilities/index.ts"],"sourcesContent":["/**\n * The marketing surfaces Baker can reach, and — the part that exists nowhere\n * else — what it cannot do on each of them.\n *\n * Every other introspection surface (`baker schema <cmd>`, the family docs)\n * describes what the agent CAN do. An agent that needs to know a capability is\n * absent has, until now, only been able to find out by trying: promising a GA4\n * property merge and then discovering the connection is read-only, or probing\n * four spellings of a conversion-action field that does not exist. Both cost a\n * retraction in front of a client.\n *\n * This module is deliberately thin on prose and heavy on `evidence`. A\n * hand-maintained \"cannot do\" list rots the same way the Tag Manager built-in\n * trigger whitelist in this repo rotted down to one entry, so each limit carries\n * a machine-checkable claim about the code that makes it true, and\n * `packages/backend/convex/capabilities/coverage.test.ts` fails when a claim\n * stops holding — when the scope is finally requested, when the op ships, when\n * the guard is renamed away. `asserted` is the escape hatch for the handful of\n * facts that live outside this repo entirely, and it has to say why.\n */\n\nexport const CAPABILITY_SURFACES = [\n \"google-ads\",\n \"meta-ads\",\n \"linkedin-ads\",\n \"x-ads\",\n \"chatgpt-ads\",\n \"tag-manager\",\n \"ga4\",\n \"gsc\",\n \"shopify\",\n] as const;\nexport type CapabilitySurfaceId = (typeof CAPABILITY_SURFACES)[number];\n\n/**\n * How a change on this surface reaches the outside world.\n * - `staged-live` — staged during the chat and applied against the real\n * ad account at publish. The per-company write flags\n * that could once make this simulated are retired, so\n * a completed chat spends the client's money.\n * - `staged-immediate` — staged during the chat and applied at publish for\n * real, every time. Tag Manager: completing the chat\n * changes the user's production container.\n * - `read-only` — nothing here writes.\n *\n * The first two split on consequence, not on certainty: both always apply, but\n * one costs ad spend and the other cuts a container version, and the agent has\n * to tell the user which.\n */\nexport type CapabilityWritePath = \"staged-live\" | \"staged-immediate\" | \"read-only\";\n\nexport interface CapabilitySurfaceSpec {\n id: CapabilitySurfaceId;\n /** How the user names it. */\n label: string;\n /** The `oauthProviders.type` this surface connects through; `chatgpt-ads` connects with a pasted key instead. */\n provider: string;\n /** What the user picks when connecting: \"ad account\", \"property\", \"container\". */\n resourceNoun: string;\n writePath: CapabilityWritePath;\n /**\n * OAuth scopes that would grant writes. Access is derived by intersecting these\n * with the scopes the app actually requests — which is why \"GA4 is read-only\"\n * is a fact about the connection, not a sentence someone typed.\n */\n writeScopes: string[];\n /** Where to look next on this surface. */\n commands: string;\n /**\n * How the company connects. Absent is an OAuth grant, whose scopes decide\n * access. `api-key` is a pasted key that reaches one account whole, so the\n * write path alone decides it.\n */\n connectsWith?: \"api-key\";\n}\n\nexport const CAPABILITY_SURFACE_SPECS: Readonly<Record<CapabilitySurfaceId, CapabilitySurfaceSpec>> = {\n \"google-ads\": {\n id: \"google-ads\",\n label: \"Google Ads\",\n provider: \"google-ads\",\n resourceNoun: \"ad account\",\n writePath: \"staged-live\",\n writeScopes: [\"https://www.googleapis.com/auth/adwords\"],\n commands: \"baker ads google\",\n },\n \"meta-ads\": {\n id: \"meta-ads\",\n label: \"Meta Ads\",\n provider: \"meta\",\n resourceNoun: \"ad account\",\n writePath: \"staged-live\",\n writeScopes: [\"ads_management\"],\n commands: \"baker ads meta\",\n },\n \"linkedin-ads\": {\n id: \"linkedin-ads\",\n label: \"LinkedIn Ads\",\n provider: \"linkedin\",\n resourceNoun: \"ad account\",\n writePath: \"staged-live\",\n writeScopes: [\"rw_ads\"],\n commands: \"baker ads linkedin\",\n },\n \"x-ads\": {\n id: \"x-ads\",\n label: \"X Ads\",\n provider: \"x-ads\",\n resourceNoun: \"ad account\",\n writePath: \"staged-live\",\n /**\n * Empty on purpose, and the one surface where that does NOT mean read-only.\n * X Ads authenticates with OAuth 1.0a, which has no scope strings at all —\n * write access is granted to the *app* by X's Ads API access review, not\n * per connection. There is therefore no scope to check, and inventing one\n * would make `scopeBlockers` refuse every X write for a permission that\n * does not exist.\n */\n writeScopes: [],\n commands: \"baker ads x\",\n },\n \"chatgpt-ads\": {\n id: \"chatgpt-ads\",\n label: \"ChatGPT Ads\",\n // Connected with the client's own Ads API key (`chatgptAdsConnections`), not an OAuth grant.\n provider: \"chatgpt-ads\",\n resourceNoun: \"ad account\",\n writePath: \"staged-live\",\n /**\n * Empty because the pasted key has no scopes: it reaches its one account\n * whole. When OpenAI approves Baker's OAuth app this becomes\n * `ads.admin.all.write` and `connectsWith` goes away.\n */\n writeScopes: [],\n commands: \"baker ads chatgpt\",\n connectsWith: \"api-key\",\n },\n \"tag-manager\": {\n id: \"tag-manager\",\n label: \"Tag Manager\",\n provider: \"google-tag-manager\",\n resourceNoun: \"container\",\n writePath: \"staged-immediate\",\n writeScopes: [\n \"https://www.googleapis.com/auth/tagmanager.edit.containers\",\n \"https://www.googleapis.com/auth/tagmanager.edit.containerversions\",\n \"https://www.googleapis.com/auth/tagmanager.publish\",\n ],\n commands: \"baker tag-manager\",\n },\n ga4: {\n id: \"ga4\",\n label: \"Google Analytics 4\",\n provider: \"google-analytics\",\n resourceNoun: \"property\",\n // Like Tag Manager: staged during the chat, applied for real at publish,\n // every time. A connection made before writes existed is\n // read-only until it is reconnected, and `access` does NOT say so — it\n // reports what the Baker app asks Google for, which is now app-wide\n // read-write. The per-company signal is `scopeBlockers`, which compares\n // `writeScopes` against the scopes that connection actually recorded.\n writePath: \"staged-immediate\",\n writeScopes: [\"https://www.googleapis.com/auth/analytics.edit\"],\n commands: \"baker ga4\",\n },\n gsc: {\n id: \"gsc\",\n label: \"Search Console\",\n provider: \"google-search-console\",\n resourceNoun: \"site\",\n writePath: \"read-only\",\n writeScopes: [\"https://www.googleapis.com/auth/webmasters\"],\n commands: \"baker gsc\",\n },\n shopify: {\n id: \"shopify\",\n label: \"Shopify store\",\n provider: \"shopify\",\n resourceNoun: \"store\",\n // Staged during the chat and applied to the real store when it completes,\n // every time; each applied change can be put back by another publish\n // (`baker shopify undo`). The write permissions are optional scopes the\n // store grants when a change first needs one, so `scopeBlockers` is the\n // per-company signal.\n writePath: \"staged-immediate\",\n writeScopes: [\n \"write_products\",\n \"write_publications\",\n \"write_discounts\",\n \"write_online_store_navigation\",\n \"write_marketing_events\",\n ],\n commands: \"baker shopify\",\n },\n};\n\n/**\n * Why a capability is missing. The distinction is what decides what the agent\n * tells the user, so it is part of the contract rather than left to prose:\n * - `not_built` — the platform allows it, Baker has not built it. It may\n * be possible by hand in the platform's own interface.\n * - `provider_forbids` — the platform rejects it however it is asked. Nobody can\n * do it, so do not hand the user a manual route.\n * - `no_permission` — the connection was never granted the access. Reading\n * works, changing does not; it is manual work today.\n */\nexport type CapabilityLimitCause = \"not_built\" | \"provider_forbids\" | \"no_permission\";\n\n/**\n * The checkable claim behind a limit. `coverage.test.ts` re-derives each one.\n */\nexport type CapabilityLimitEvidence =\n /** The app never requests this OAuth scope, so nothing can write here. */\n | { kind: \"scope\"; scope: string }\n /** No staged op with these kinds exists, so there is nothing to stage. */\n | { kind: \"noOpKind\"; kinds: string[] }\n /** A field on a staged op does not accept this value. */\n | { kind: \"noChoice\"; opKind: string; field: string; value: string }\n /** A stage-time guard refuses it before anything is spent. */\n | { kind: \"guard\"; module: string; symbol: string }\n /** Nothing in this repository encodes it; the note says why. */\n | { kind: \"asserted\"; note: string };\n\nexport interface CapabilityLimit {\n surface: CapabilitySurfaceId;\n /** What an agent would set out to do, in the words it would use. */\n capability: string;\n cause: CapabilityLimitCause;\n /** Why it cannot happen and what to do instead. Agent-facing, plain English. */\n detail: string;\n evidence: CapabilityLimitEvidence;\n}\n\n/**\n * Ordered by how often getting it wrong has cost something. Keep entries to\n * things an agent would plausibly promise a client before checking.\n */\nexport const CAPABILITY_LIMITS: readonly CapabilityLimit[] = [\n {\n surface: \"shopify\",\n capability: \"Edit the store's theme files — templates, sections, the theme's code or its stylesheet\",\n cause: \"provider_forbids\",\n detail:\n \"Shopify only lets an app write theme files with an exemption it grants case by case, and editing a merchant's theme breaks the App Store's rules for an app like Baker. Say exactly what to change and where (Online Store → Themes → Customize), and carry on with the rest of the job.\",\n evidence: {\n kind: \"asserted\",\n note: \"Shopify's rule, not this repository's: `write_themes` needs Shopify's exemption and App Store requirement 5.1.1 forbids theme edits by an app of this kind. The app's TOML declares no `write_themes` (scopes.test.ts holds the backend's list equal to it).\",\n },\n },\n {\n surface: \"shopify\",\n capability: \"Create or delete products, change stock levels, or change whether a product is published\",\n cause: \"not_built\",\n detail:\n \"Baker changes products' copy, SEO, tags, type, options' SKU, barcode, weight and price, custom fields, collections, discount codes, redirects and its own campaigns in Shopify Marketing. Making or removing a product, its stock and its status are the merchant's, in Shopify admin; say what to do there and carry on.\",\n evidence: {\n kind: \"noOpKind\",\n kinds: [\"shopify.product.create\", \"shopify.product.delete\", \"shopify.inventory.set\", \"shopify.product.publish\"],\n },\n },\n {\n surface: \"shopify\",\n capability: \"Make a discount code for named customers or a customer segment\",\n cause: \"not_built\",\n detail:\n \"Every discount code Baker creates is for everyone who has the code. A code for named customers or a segment is made in Shopify admin → Discounts.\",\n evidence: {\n kind: \"noOpKind\",\n kinds: [\"shopify.discountCode.createForCustomers\", \"shopify.discountAutomatic.create\"],\n },\n },\n {\n surface: \"shopify\",\n capability: \"Make a collection whose products join by rules (a tag, a price, a type), or delete one\",\n cause: \"not_built\",\n detail:\n \"Baker makes collections of hand-picked products and adds or removes products by hand. A collection whose products join by its rules is set up in Shopify admin; Baker refuses to delete one, because undo could not rebuild its rules.\",\n evidence: { kind: \"guard\", module: \"shopify/writes/collectionRestore.ts\", symbol: \"restorability\" },\n },\n {\n surface: \"ga4\",\n capability:\n \"Create, merge or delete a property; add or edit a data stream; change the property's time zone or currency\",\n cause: \"not_built\",\n detail:\n \"Baker configures what a property MEASURES — key events, custom dimensions and metrics, custom events, audiences, the data retention window — plus the property's name, industry category and Google Ads link. It does not create or merge properties or touch data streams. Time zone and currency are deliberately excluded even though the API allows them: both change how every future day is bucketed without reprocessing history, so a correction puts a step in the middle of every time series the user compares against. Tell the user exactly what to change in the Google Analytics admin screens and carry on with the rest of the job.\",\n evidence: {\n kind: \"noOpKind\",\n kinds: [\"ga4.dataStream.create\", \"ga4.dataStream.update\", \"ga4.property.create\"],\n },\n },\n {\n surface: \"ga4\",\n capability: \"Change who is already in an audience, or build one from a sequence of steps\",\n cause: \"provider_forbids\",\n detail:\n \"An audience can be CREATED and ARCHIVED here, and its name and description changed. Everything that defines who is in it — the conditions, the membership window, the exclusion mode — is marked Immutable by Google and cannot be edited on an audience that exists, however it is asked. Fixing a definition therefore means archiving the audience and creating a replacement, which does NOT carry the users the first one gathered. Say that before staging the archive. Sequence-based audiences (`sequenceFilter`) are not offered: they are the easiest shape in this API to get subtly wrong and the mistake is permanent, so build them by hand in Google Analytics if one is genuinely needed.\",\n evidence: {\n kind: \"asserted\",\n note: \"The immutability is Google's, declared in the Admin API v1alpha `Audience` resource (`filter_clauses`, `membership_duration_days` and `exclusion_duration_mode` are all marked Immutable) — no code in this repository can be read to confirm a rule the provider enforces. What this repo does hold is the consequence: `GA4_IMMUTABLE_FIELDS.audience` in `packages/api/src/ga4/ops.ts` drives the refusal, and `ga4.test.ts` pins that an update carrying one of those fields is rejected with the archive-and-recreate wording rather than a zod key error.\",\n },\n },\n {\n surface: \"ga4\",\n capability: \"Try a Google Analytics configuration change without it taking effect\",\n cause: \"not_built\",\n detail:\n \"Google Analytics changes always apply to the real property: staged changes apply when the chat completes, and an applied change is in effect immediately — there is no version to publish afterwards and no undo. The user reviewing the Analytics tab and completing the chat is the review, so agree the changes with them before you complete it.\",\n evidence: {\n kind: \"asserted\",\n note: \"An absence: the GA4 executor has no simulated branch and GA4 drafts have no `mode` column, and no test can assert the absence of a mode that was never modelled. The nearest positive check is that the three ad surfaces do carry one — a `mode` column on their drafts and an `executeSimulated` branch in each executor — which the `staged-live` vs `staged-immediate` write paths already encode. Their per-company write gates are retired, so every ad draft is stamped `live`; the branch survives only for drafts published while the gates existed.\",\n },\n },\n {\n surface: \"gsc\",\n capability:\n \"Change anything in Search Console — add or verify a property, submit or delete a sitemap, set a preferred domain\",\n cause: \"no_permission\",\n detail:\n \"Baker's Search Console connection is read-only (webmasters.readonly). `baker gsc sitemaps` lists what is already submitted; it cannot submit one. Hand submission to the user in Search Console and carry on.\",\n evidence: { kind: \"scope\", scope: \"https://www.googleapis.com/auth/webmasters\" },\n },\n {\n surface: \"x-ads\",\n capability: \"Change anything in X Ads — create or edit campaigns, line items, or promoted posts\",\n cause: \"not_built\",\n detail:\n \"X Ads is a read-only surface in Baker: there are no staged write ops for it, so nothing can be staged and nothing publishes. Report on it freely; route any change to the user in X Ads Manager.\",\n evidence: { kind: \"noOpKind\", kinds: [\"x.campaign.create\", \"x.campaign.update\", \"x.lineItem.create\"] },\n },\n {\n surface: \"google-ads\",\n capability:\n \"Change a conversion action that Google itself created — Smart campaign calls and directions, the in-ad lead form's submit, YouTube subscriptions and follow-on views, Floodlight and Search Ads 360 imports, store visits, codeless webpage actions\",\n cause: \"provider_forbids\",\n detail:\n \"Google rejects every write against one of its own conversion actions, a rename as flatly as a removal. Baker refuses these at stage time so no publish is spent on them. There is no manual route either — the Google Ads interface will not change them — so do not hand the user one. Leave the action alone and say so.\",\n evidence: {\n module: \"ads/google/writes/conversionSafety.ts\",\n kind: \"guard\",\n symbol: \"googleOwnedConversionRefusal\",\n },\n },\n {\n surface: \"google-ads\",\n capability:\n \"Switch a demographic dimension — age, gender, parental status, household income — between Targeting and Observation\",\n cause: \"not_built\",\n detail:\n \"`baker ads google audiences targeting` sets the AUDIENCE dimension only. The demographic rows are read before every write and sent back exactly as they were, so nothing is lost — but changing one is manual work in the Google Ads interface. Say which one to change and where, and carry on with the rest of the job.\",\n evidence: { kind: \"noChoice\", opKind: \"google.targetingSetting.set\", field: \"audience\", value: \"AGE_RANGE\" },\n },\n {\n surface: \"google-ads\",\n capability: \"Hide a conversion action (status HIDDEN)\",\n cause: \"provider_forbids\",\n detail:\n 'Google denies HIDDEN on every conversion-action write (\"the field\\'s value is on a deny-list for this field\"), so it is not part of the write contract — even though actions hidden long ago still read back as HIDDEN. To take an action out of automated bidding while it keeps measuring, demote it: `baker ads google conversions update <id> --no-primary`. To stop it counting, set status REMOVED.',\n evidence: { kind: \"noChoice\", opKind: \"google.conversionAction.update\", field: \"status\", value: \"HIDDEN\" },\n },\n {\n surface: \"google-ads\",\n capability:\n \"Build a combined, converters or lookalike audience from an audience or conversion action created in the same chat\",\n cause: \"provider_forbids\",\n detail:\n \"Google builds these lists from audiences and conversion actions that already exist in the account; one created in the same publish is not found. Stage and publish the parts first, then build the combined, converters or lookalike audience on their ids in a later chat — and tell the user it takes two publishes.\",\n evidence: {\n kind: \"asserted\",\n note: \"Enforced by `existingRefSchema` inside `audienceCreateSchema` (packages/api ops.ts), which no capability check reads; the provider half is live on v25: a logical operand on a list created in the same request was RESOURCE_NOT_FOUND, a basic list over a conversion action created with it INVALID_CONVERSION_TYPE, and lookalike seeds are int64 ids.\",\n },\n },\n {\n surface: \"google-ads\",\n capability: \"Create a Google Analytics (GA4) conversion action in Google Ads\",\n cause: \"provider_forbids\",\n detail:\n \"Google's API cannot create a Google Analytics conversion — they are imported, not created. Make sure the event is a key event in Google Analytics and the property is linked to Google Ads, then ask the user to import it in Google Ads (Goals → Conversions → New conversion action → Import → Google Analytics 4). To measure it with a Google Ads tag instead, stage a WEBPAGE conversion.\",\n evidence: {\n kind: \"noChoice\",\n opKind: \"google.conversionAction.create\",\n field: \"type\",\n value: \"GOOGLE_ANALYTICS_4_CUSTOM\",\n },\n },\n {\n surface: \"google-ads\",\n capability: \"Target the area around the business's own locations (a location group)\",\n cause: \"not_built\",\n detail:\n 'A location group targets a radius around the account\\'s location assets, and Baker cannot stage location assets yet — Google refuses a location group on an account without them. Target a radius around an address or a point instead (`criterionType: \"proximity\"` on `campaign-criteria add`), or tell the user to add the business locations in Google Ads; carry on with the rest of the job.',\n evidence: {\n kind: \"asserted\",\n note: 'The refusal is in the shared criterion contract, not a Convex guard: `criterionSpecSchema` in `packages/api/src/ads-google/criteria.ts` answers `criterionType: \"locationGroup\"` with LOCATION_GROUP_MESSAGE, pinned by `criteria.test.ts`. Live on v25 (3865083115, no location assets) every location-group variant was refused — `enable_customer_level_location_asset_set` with \"The error code is not in this version.\", a geo-constant group with `location_group.feed` REQUIRED.',\n },\n },\n {\n surface: \"google-ads\",\n capability: \"Create a Video or Local campaign\",\n cause: \"provider_forbids\",\n detail:\n \"Google's API does not create Video campaigns at all (refused for every sub-type and bidding), and Local campaigns were retired into Performance Max. For video on YouTube, stage a Demand Gen campaign with a Demand Gen video ad; for store visits, Performance Max. A Video views or reach campaign is the user's to create in Google Ads — say so, with the settings you recommend. Existing Video campaigns can still be read, paused and edited.\",\n evidence: { kind: \"noChoice\", opKind: \"google.campaign.create\", field: \"channelType\", value: \"VIDEO\" },\n },\n {\n surface: \"google-ads\",\n capability: \"Create a Smart campaign\",\n cause: \"not_built\",\n detail:\n \"A Smart campaign's business details (phone, website, business profile) are a setting Google refuses to check before publishing (RESOURCE_DOES_NOT_SUPPORT_VALIDATE_ONLY), so Baker cannot stage one it could validate. Stage a Search or Performance Max campaign instead, or hand the Smart campaign to the user in Google Ads and carry on with the rest of the job. Shopping, App, Travel and Hotel campaigns ARE stageable — each with the account link it needs. Existing Smart campaigns can still be read, paused and edited.\",\n evidence: { kind: \"noChoice\", opKind: \"google.campaign.create\", field: \"channelType\", value: \"SMART\" },\n },\n {\n surface: \"google-ads\",\n capability:\n \"Create a campaign of a retired sub-type — Search or Display Express, Gmail, Smart Display, Smart Shopping, Video action, app promotion on Search\",\n cause: \"provider_forbids\",\n detail:\n \"Google refuses every one of these on a create. Leave the sub-type out for a standard campaign of the same type; Gmail and Video action now run through Demand Gen, Smart Shopping through Performance Max.\",\n evidence: {\n kind: \"noChoice\",\n opKind: \"google.campaign.create\",\n field: \"channelSubType\",\n value: \"DISPLAY_GMAIL_AD\",\n },\n },\n {\n surface: \"google-ads\",\n capability: \"Set a campaign budget to accelerated delivery\",\n cause: \"provider_forbids\",\n detail:\n \"Google still stores a budget set to accelerated delivery, but refuses to attach it to any campaign, so it can never spend. Every budget is staged with standard delivery (Google paces it across the day). If the user wants to spend faster, raise the daily amount instead — and say that is what you did.\",\n evidence: { kind: \"noChoice\", opKind: \"google.budget.create\", field: \"deliveryMethod\", value: \"ACCELERATED\" },\n },\n {\n surface: \"google-ads\",\n capability: \"Create or edit a call ad (call-only ad)\",\n cause: \"provider_forbids\",\n detail:\n \"Google removed the call ad from its API, so nobody can create one or change an existing one through it. To take phone calls from search, stage a responsive search ad and tell the user to add the phone number as a call asset in Google Ads (Baker cannot stage call assets yet). Carry on with the rest of the job.\",\n evidence: {\n kind: \"asserted\",\n note: 'The format sits inside the ad content union, not on a top-level payload field, so no `noChoice` check can see it. `adContentSchema` answers `format: \"call\"` with CALL_AD_RETIRED_MESSAGE (packages/api ops.test.ts pins it); the provider half is v25\\'s `Ad` message having no `call_ad` — a validateOnly request on 3865083115 was refused `Unknown name \"callAd\"` (2026-10-08).',\n },\n },\n {\n surface: \"google-ads\",\n capability: \"Remove a device setting from a campaign once it has one\",\n cause: \"provider_forbids\",\n detail:\n \"A device criterion can be added with `campaign-criteria add` and re-bid afterwards, but Google rejects every removal of one — including a criterion the same account created itself days earlier (observed). So the undo for a bid boost is NOT a removal: it is `baker ads google campaign-criteria update <criterion-resource-name> --bid-modifier 1`, where 0 stops ads serving on that device and 0.1–10.0 bid down or up. Read `campaign_criterion.resource_name` and `campaign_criterion.bid_modifier` (type = DEVICE) first to see which devices the campaign already has. Baker refuses a staged device removal before publish; don't abort the job over it.\",\n evidence: {\n kind: \"guard\",\n module: \"ads/google/writes/stage.ts\",\n symbol: \"deviceCriterionRemovalRefusal\",\n },\n },\n {\n surface: \"google-ads\",\n capability: \"Change which conversion action counts calls from ads (account call reporting)\",\n cause: \"provider_forbids\",\n detail:\n \"Google's API refuses any write of the account's call conversion action, even the one it already uses. Call reporting itself and whether calls count as conversions ARE stageable (`baker ads google account update --call-reporting --call-conversions`). Hand the action choice to the user: Google Ads → Admin → Account settings → Call reporting. Carry on with the rest of the job.\",\n evidence: {\n kind: \"asserted\",\n note: '`customerUpdateSchema` is strict and carries no callConversionAction, so an op naming it is refused at stage; the provider half: a validateOnly customer update of `call_reporting_setting.call_conversion_action` on 3865083115 — with the live value and with another action — was refused \"The error code is not in this version.\" (v25, 2026-10-08).',\n },\n },\n {\n surface: \"google-ads\",\n capability: \"Put a label on an asset (sitelink, image, callout …)\",\n cause: \"provider_forbids\",\n detail:\n \"Google Ads has no labels on assets — its API labels campaigns, ad groups, ads and keywords only, and staging refuses an asset. Label the campaign or ad group that uses the asset, or give the asset a findable name, and carry on with the rest of the job.\",\n evidence: { kind: \"noChoice\", opKind: \"google.label.attach\", field: \"level\", value: \"asset\" },\n },\n {\n surface: \"google-ads\",\n capability: \"Put a label on the advertiser account itself\",\n cause: \"provider_forbids\",\n detail:\n \"Google applies a label to an account only from the manager account above it (CANNOT_ATTACH_NON_MANAGER_LABEL_TO_CUSTOMER, live v25), and Baker works inside the advertiser account. Label the campaigns instead, or tell the user to label the account from their manager account in Google Ads; carry on with the rest of the job.\",\n evidence: { kind: \"noChoice\", opKind: \"google.label.attach\", field: \"level\", value: \"customer\" },\n },\n {\n surface: \"google-ads\",\n capability: \"Change billing, payment methods, or account-level spend limits\",\n cause: \"not_built\",\n detail:\n \"Nothing that touches money setup is stageable — no op exists for it. Report on spend, then hand billing changes to the user in Google Ads. Account settings that are not money (auto-tagging, the account tracking template and final URL suffix, call reporting, video inventory) ARE stageable: `baker ads google account update`.\",\n evidence: {\n kind: \"noOpKind\",\n kinds: [\"google.billingSetup.create\", \"google.accountBudget.create\"],\n },\n },\n {\n surface: \"meta-ads\",\n capability:\n \"Push delivery to an ad — dedicate a share of the campaign or ad-set budget to one ad for a set number of days\",\n cause: \"not_built\",\n detail:\n 'Meta ships push delivery as an Ads Manager control only: the Marketing API\\'s ad object takes a schedule, a display sequence and tracking, and nothing that dedicates budget to one ad. So nothing can stage it and no publish can apply it — do not offer to switch it on, and never report a starved ad as pushed. Hand the user the click path and the settings you are recommending: Ad level > Ad setup > \"show more settings\" (next to ad scheduling) > \"Help ensure delivery by dedicating a portion of your budget to your ad\", then the percentage of budget and the number of days, for the one ad you name. It needs at least 2 ads in the ad set, and only one ad per ad set should be pushed. Then carry on with the rest of the job.',\n evidence: { kind: \"noOpKind\", kinds: [\"ad.pushDelivery\"] },\n },\n {\n surface: \"linkedin-ads\",\n capability: \"Move a live ad to another ad set, or change a live ad set's type, locale, or associated organization\",\n cause: \"provider_forbids\",\n detail:\n \"LinkedIn treats these as create-only: they can be corrected while the change is still staged, but not on something already live. Baker refuses the amend rather than staging a write LinkedIn will reject. Create the replacement instead, and say why.\",\n evidence: { kind: \"guard\", module: \"ads/linkedin/writes/amend.ts\", symbol: \"rejectedLiveKeys\" },\n },\n {\n surface: \"linkedin-ads\",\n capability: \"Use a video from the Baker media library, or a document, as LinkedIn ad creative\",\n cause: \"not_built\",\n detail:\n \"Only images upload to LinkedIn today; video and document creative are not built. Stage an image creative, or tell the user to upload the video in Campaign Manager, and carry on with the rest of the job.\",\n evidence: {\n kind: \"asserted\",\n note: \"Enforced by a throw inside the LinkedIn media uploader (ads/linkedin/writes/media.ts), not by the shared op contract — the op kind exists and accepts the reference, so no schema or op-kind check can see it.\",\n },\n },\n {\n surface: \"tag-manager\",\n capability: \"Create, delete, or move a Tag Manager account, container, or workspace\",\n cause: \"not_built\",\n detail:\n \"Baker works inside the containers the company connected — it changes tags, triggers, variables, folders, built-in variables and container settings, and nothing above that level. Ask the user to create the container in Tag Manager and connect it, then carry on.\",\n evidence: {\n kind: \"noOpKind\",\n kinds: [\n \"tagManager.container.create\",\n \"tagManager.container.delete\",\n \"tagManager.account.create\",\n \"tagManager.workspace.create\",\n ],\n },\n },\n {\n surface: \"tag-manager\",\n capability: \"Try a container change without it going live\",\n cause: \"not_built\",\n detail:\n \"Tag Manager changes always apply to the real container: staged changes apply to its working workspace when the chat completes, and a clean run cuts and publishes a container version, which takes them live on the site. Completing the chat is the review, so get the user's agreement before you complete it.\",\n evidence: {\n kind: \"asserted\",\n note: \"An absence: the Tag Manager executor has no simulated branch and its drafts have no `mode` column, and no test can assert the absence of a mode that was never modelled. The nearest positive check is that the three ad surfaces do carry one — a `mode` column on their drafts and an `executeSimulated` branch in each executor — which the `staged-live` vs `staged-immediate` write paths already encode. Their per-company write gates are retired, so every ad draft is stamped `live`; the branch survives only for drafts published while the gates existed.\",\n },\n },\n];\n","/**\n * Contract for `/api/capabilities` — what Baker can and cannot do for this\n * company, answered before any work starts (`baker capabilities`).\n *\n * Convex `Id<T>` values are plain `z.string()`; this package must not depend on\n * `convex`. Nothing here carries a token, key, or anything a credential could be\n * reconstructed from — the response names accounts and permissions, never\n * secrets.\n */\nimport { z } from \"zod\";\nimport { CAPABILITY_SURFACES } from \"./surfaces\";\n\nexport { describeOpUnion, type OpDescription } from \"./op-fields\";\nexport {\n CAPABILITY_LIMITS,\n CAPABILITY_SURFACE_SPECS,\n CAPABILITY_SURFACES,\n type CapabilityLimit,\n type CapabilityLimitCause,\n type CapabilityLimitEvidence,\n type CapabilitySurfaceId,\n type CapabilitySurfaceSpec,\n type CapabilityWritePath,\n} from \"./surfaces\";\n\nexport const capabilitySurfaceSchema = z.enum(CAPABILITY_SURFACES);\n\nexport const capabilitiesRequestSchema = z.object({\n /** Narrow to one surface. Omit for every surface the company could use. */\n surface: capabilitySurfaceSchema.optional(),\n /** Include the field-level contract of every op, not just the entity list. */\n full: z.boolean().optional(),\n /**\n * Who the chat acts as (`BAKER_ACTING_USER_ID`). Adds that person's own\n * connected tools — they load for this turn, and for nobody else's.\n */\n actingUserId: z.string().optional(),\n});\nexport type CapabilitiesRequest = z.infer<typeof capabilitiesRequestSchema>;\n\n/** A connected account, property, site or container. Identity only. */\nexport const capabilityResourceSchema = z.object({\n id: z.string(),\n name: z.string().optional(),\n});\nexport type CapabilityResource = z.infer<typeof capabilityResourceSchema>;\n\nexport const capabilityOpSchema = z.object({\n kind: z.string(),\n /** True when the op changes something that already exists and must be named. */\n needsTarget: z.boolean(),\n required: z.array(z.string()),\n optional: z.array(z.string()),\n /** Field → the values it accepts, for fields that take a fixed set. */\n choices: z.record(z.string(), z.array(z.string())),\n /** False when the platform accepts fields beyond the listed ones. */\n fieldsAreComplete: z.boolean(),\n});\nexport type CapabilityOp = z.infer<typeof capabilityOpSchema>;\n\nexport const capabilityLimitViewSchema = z.object({\n capability: z.string(),\n cause: z.enum([\"not_built\", \"provider_forbids\", \"no_permission\"]),\n detail: z.string(),\n});\nexport type CapabilityLimitView = z.infer<typeof capabilityLimitViewSchema>;\n\n/**\n * `live` — writes reach the real platform at publish.\n * `applies-at-publish` — publishing changes the real thing, with no version step after.\n * `none` — this surface does not write.\n *\n * There is no `simulated`: the per-company gates that produced it on Google,\n * Meta and LinkedIn are all retired, so no surface can report a write that\n * touches nothing. Leaving the value in the contract would keep alive the one\n * sentence this report exists to prevent — \"your ads are only a preview\".\n */\nexport const capabilityWriteModeSchema = z.enum([\"live\", \"applies-at-publish\", \"none\"]);\nexport type CapabilityWriteMode = z.infer<typeof capabilityWriteModeSchema>;\n\nexport const capabilitySurfaceReportSchema = z.object({\n surface: capabilitySurfaceSchema,\n label: z.string(),\n connected: z.boolean(),\n /** What the user picked when connecting. Empty when nothing is selected yet. */\n resources: z.array(capabilityResourceSchema),\n access: z.enum([\"read-write\", \"read-only\", \"not-connected\"]),\n writeMode: capabilityWriteModeSchema,\n /** One sentence about the write mode, safe to repeat to the user. */\n writeModeNote: z.string(),\n /** Entities this surface can change at all, e.g. \"campaign\", \"keyword\". */\n writableEntities: z.array(z.string()),\n /** Things wrong with the connection itself: needs reconnecting, missing a permission. */\n blockers: z.array(z.string()),\n /** What cannot be done here, and why. */\n limits: z.array(capabilityLimitViewSchema),\n /** The per-op contract. Present when one surface was asked for, or with `full`. */\n ops: z.array(capabilityOpSchema).optional(),\n /** Where to look next: `baker ads google`, `baker ga4`, … */\n commands: z.string(),\n});\nexport type CapabilitySurfaceReport = z.infer<typeof capabilitySurfaceReportSchema>;\n\n/**\n * A source that is available to this company but is not one of the seven\n * marketing surfaces above.\n *\n * These exist because \"what do I have?\" had no single answer, and the gap was\n * not academic: Microsoft Clarity arrives over MCP and HubSpot is read through\n * the CLI, so neither appears in `surfaces` — and an agent that checked only\n * this command concluded it had no Clarity while Clarity was sitting in its own\n * tool list. That is the source most likely to change what it decides.\n *\n * Deliberately NOT modelled as a surface. A surface carries `ops`,\n * `writableEntities` and a write mode, all of which describe a staged-write\n * contract Baker owns. An MCP toolkit has none of that — Baker did not define\n * its tools and cannot enumerate their fields — so filing one under `surfaces`\n * would mean either lying about the contract or leaving four fields empty on\n * every row and inviting the reader to wonder which.\n */\nexport const capabilityToolSchema = z.object({\n /** `microsoft_clarity`, `hubspot`, or the name the user gave a custom server. */\n key: z.string(),\n label: z.string(),\n /** `mcp` — tools in the agent's own list. `platform` — signed in, read through the CLI. */\n kind: z.enum([\"mcp\", \"platform\"]),\n /** How to actually reach it, in one phrase the agent can act on. */\n reach: z.string(),\n /**\n * Whether it can be used right now.\n *\n * A connection that exists and is expired is worse than one that is absent:\n * it reads as available and fails at the moment it is needed, which on an\n * unattended run is a report with a hole in it and no explanation.\n */\n ready: z.boolean(),\n /** Why it is not ready, or what it is for. Absent when neither needs saying. */\n note: z.string().optional(),\n});\nexport type CapabilityTool = z.infer<typeof capabilityToolSchema>;\n\nexport const capabilitiesResponseSchema = z.object({\n ok: z.literal(true),\n data: z.object({\n surfaces: z.array(capabilitySurfaceReportSchema),\n /**\n * Everything else this company can reach. Shared connections only —\n * a teammate's private per-user connection belongs to whoever started the\n * session and is visible in the agent's own tool list, not here.\n */\n tools: z.array(capabilityToolSchema),\n }),\n});\nexport type CapabilitiesResponse = z.infer<typeof capabilitiesResponseSchema>;\n"],"mappings":"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","names":[]}