@keystrokehq/cli 0.1.147 → 0.1.149

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 (179) hide show
  1. package/README.md +35 -42
  2. package/dist/{alias-RTYYYW3D-CLFgrowj.mjs → alias-RTYYYW3D-BDy5K94v.mjs} +2 -2
  3. package/dist/{alias-RTYYYW3D-CLFgrowj.mjs.map → alias-RTYYYW3D-BDy5K94v.mjs.map} +1 -1
  4. package/dist/{awk2-LA3USKJP-BbsfXVlR.mjs → awk2-LA3USKJP-bQiQEw4P.mjs} +8 -8
  5. package/dist/{awk2-LA3USKJP-BbsfXVlR.mjs.map → awk2-LA3USKJP-bQiQEw4P.mjs.map} +1 -1
  6. package/dist/{base64-C2AIWVNC-C0WIgu5V.mjs → base64-C2AIWVNC-DMnyEdfa.mjs} +2 -2
  7. package/dist/{base64-C2AIWVNC-C0WIgu5V.mjs.map → base64-C2AIWVNC-DMnyEdfa.mjs.map} +1 -1
  8. package/dist/{basename-UB3CIYNI-BgNN3bGm.mjs → basename-UB3CIYNI-DOxZLtwj.mjs} +2 -2
  9. package/dist/{basename-UB3CIYNI-BgNN3bGm.mjs.map → basename-UB3CIYNI-DOxZLtwj.mjs.map} +1 -1
  10. package/dist/{bash-YZ33HQZQ-N6YyKtUH.mjs → bash-YZ33HQZQ-D4vRBW1d.mjs} +2 -2
  11. package/dist/{bash-YZ33HQZQ-N6YyKtUH.mjs.map → bash-YZ33HQZQ-D4vRBW1d.mjs.map} +1 -1
  12. package/dist/{cat-TSFMZVYS-Dz3-oHsV.mjs → cat-TSFMZVYS-D8QgnfyP.mjs} +3 -3
  13. package/dist/{cat-TSFMZVYS-Dz3-oHsV.mjs.map → cat-TSFMZVYS-D8QgnfyP.mjs.map} +1 -1
  14. package/dist/{chmod-TFEPA42X-YF02QJUv.mjs → chmod-TFEPA42X-CRWIslQq.mjs} +2 -2
  15. package/dist/{chmod-TFEPA42X-YF02QJUv.mjs.map → chmod-TFEPA42X-CRWIslQq.mjs.map} +1 -1
  16. package/dist/{chunk-5H5SCKJM-BvfXlL01.mjs → chunk-5H5SCKJM-BaNr0aSJ.mjs} +4 -4
  17. package/dist/{chunk-5H5SCKJM-BvfXlL01.mjs.map → chunk-5H5SCKJM-BaNr0aSJ.mjs.map} +1 -1
  18. package/dist/{chunk-EBAPSGAO-Ctfslw2R.mjs → chunk-EBAPSGAO-BRba1GMs.mjs} +2 -2
  19. package/dist/{chunk-EBAPSGAO-Ctfslw2R.mjs.map → chunk-EBAPSGAO-BRba1GMs.mjs.map} +1 -1
  20. package/dist/{chunk-LEKBROJD-CJMrAyu9.mjs → chunk-LEKBROJD-D1fMh3yQ.mjs} +3 -3
  21. package/dist/{chunk-LEKBROJD-CJMrAyu9.mjs.map → chunk-LEKBROJD-D1fMh3yQ.mjs.map} +1 -1
  22. package/dist/{clear-HKGFEOF6-CekN2x-O.mjs → clear-HKGFEOF6-Cy0E2H3t.mjs} +2 -2
  23. package/dist/{clear-HKGFEOF6-CekN2x-O.mjs.map → clear-HKGFEOF6-Cy0E2H3t.mjs.map} +1 -1
  24. package/dist/{column-XT6UFXNQ-DHENV9D2.mjs → column-XT6UFXNQ-czPN0bKF.mjs} +2 -2
  25. package/dist/{column-XT6UFXNQ-DHENV9D2.mjs.map → column-XT6UFXNQ-czPN0bKF.mjs.map} +1 -1
  26. package/dist/{comm-VV2LDX2J-ppxDJFkY.mjs → comm-VV2LDX2J-nTDBS00q.mjs} +2 -2
  27. package/dist/{comm-VV2LDX2J-ppxDJFkY.mjs.map → comm-VV2LDX2J-nTDBS00q.mjs.map} +1 -1
  28. package/dist/{cp-BISAAS7A-CMWayU4n.mjs → cp-BISAAS7A-CXqDGSmH.mjs} +3 -3
  29. package/dist/{cp-BISAAS7A-CMWayU4n.mjs.map → cp-BISAAS7A-CXqDGSmH.mjs.map} +1 -1
  30. package/dist/{cut-OKARJCCV-Bt8b58eI.mjs → cut-OKARJCCV-8_v90N99.mjs} +3 -3
  31. package/dist/{cut-OKARJCCV-Bt8b58eI.mjs.map → cut-OKARJCCV-8_v90N99.mjs.map} +1 -1
  32. package/dist/{date-UUUPW43J-B7T5OTZZ.mjs → date-UUUPW43J-BiJvTWWs.mjs} +2 -2
  33. package/dist/{date-UUUPW43J-B7T5OTZZ.mjs.map → date-UUUPW43J-BiJvTWWs.mjs.map} +1 -1
  34. package/dist/{diff-MWJFIG7X-DhnPc_5r.mjs → diff-MWJFIG7X-D5by0o7Y.mjs} +2 -2
  35. package/dist/{diff-MWJFIG7X-DhnPc_5r.mjs.map → diff-MWJFIG7X-D5by0o7Y.mjs.map} +1 -1
  36. package/dist/{dirname-MPHRFUTI-Dkb3S4OX.mjs → dirname-MPHRFUTI-VCKXiC16.mjs} +2 -2
  37. package/dist/{dirname-MPHRFUTI-Dkb3S4OX.mjs.map → dirname-MPHRFUTI-VCKXiC16.mjs.map} +1 -1
  38. package/dist/dist-BlsDG7kb.mjs +3 -0
  39. package/dist/{dist-E6dh6qXe.mjs → dist-C6adeAws.mjs} +1006 -138
  40. package/dist/dist-C6adeAws.mjs.map +1 -0
  41. package/dist/dist-DJQnugPi.mjs +1829 -0
  42. package/dist/dist-DJQnugPi.mjs.map +1 -0
  43. package/dist/{dist-B72RPrho.mjs → dist-DSkS8uEB.mjs} +43888 -28664
  44. package/dist/dist-DSkS8uEB.mjs.map +1 -0
  45. package/dist/dist-Dq1kkbLy.mjs +4 -0
  46. package/dist/{du-572XNP42-ClP4jXB1.mjs → du-572XNP42-C_zifijt.mjs} +3 -3
  47. package/dist/{du-572XNP42-ClP4jXB1.mjs.map → du-572XNP42-C_zifijt.mjs.map} +1 -1
  48. package/dist/{env-36M5BO7M-CsP_aiWr.mjs → env-36M5BO7M-CEbFSWHW.mjs} +6 -6
  49. package/dist/{env-36M5BO7M-CsP_aiWr.mjs.map → env-36M5BO7M-CEbFSWHW.mjs.map} +1 -1
  50. package/dist/{expand-JSPG6VOP-B-YUvYpu.mjs → expand-JSPG6VOP-CxlV2zRG.mjs} +2 -2
  51. package/dist/{expand-JSPG6VOP-B-YUvYpu.mjs.map → expand-JSPG6VOP-CxlV2zRG.mjs.map} +1 -1
  52. package/dist/{expr-5JAACS4X-1TBq84gG.mjs → expr-5JAACS4X-CM1VDr6S.mjs} +2 -2
  53. package/dist/{expr-5JAACS4X-1TBq84gG.mjs.map → expr-5JAACS4X-CM1VDr6S.mjs.map} +1 -1
  54. package/dist/{file-IPZJC3FQ-DcZNOWyY.mjs → file-IPZJC3FQ-DYa9X4WH.mjs} +17 -17
  55. package/dist/file-IPZJC3FQ-DYa9X4WH.mjs.map +1 -0
  56. package/dist/{find-INTH3OLC-6p47KeeT.mjs → find-INTH3OLC-CPiHWE9r.mjs} +4 -4
  57. package/dist/{find-INTH3OLC-6p47KeeT.mjs.map → find-INTH3OLC-CPiHWE9r.mjs.map} +1 -1
  58. package/dist/{fold-4TQNYMSW-C54bHzLd.mjs → fold-4TQNYMSW-B4tfWHg3.mjs} +2 -2
  59. package/dist/{fold-4TQNYMSW-C54bHzLd.mjs.map → fold-4TQNYMSW-B4tfWHg3.mjs.map} +1 -1
  60. package/dist/{grep-V3LQVMRQ-D99Bq7Kj.mjs → grep-V3LQVMRQ-BbRYJxzz.mjs} +3 -3
  61. package/dist/{grep-V3LQVMRQ-D99Bq7Kj.mjs.map → grep-V3LQVMRQ-BbRYJxzz.mjs.map} +1 -1
  62. package/dist/{gzip-O5ASJAFY-CZDRROqP.mjs → gzip-O5ASJAFY-rKFFXJyd.mjs} +2 -2
  63. package/dist/{gzip-O5ASJAFY-CZDRROqP.mjs.map → gzip-O5ASJAFY-rKFFXJyd.mjs.map} +1 -1
  64. package/dist/{head-442HYESI-D96RMdki.mjs → head-442HYESI-sl2UFkqV.mjs} +2 -2
  65. package/dist/{head-442HYESI-D96RMdki.mjs.map → head-442HYESI-sl2UFkqV.mjs.map} +1 -1
  66. package/dist/{history-WYYKSLSZ-ACNQVupn.mjs → history-WYYKSLSZ-BQO1BlWh.mjs} +2 -2
  67. package/dist/{history-WYYKSLSZ-ACNQVupn.mjs.map → history-WYYKSLSZ-BQO1BlWh.mjs.map} +1 -1
  68. package/dist/{html-to-markdown-JW4MSQZO-DQOxFIvF.mjs → html-to-markdown-JW4MSQZO-CJGwkgpQ.mjs} +2 -2
  69. package/dist/{html-to-markdown-JW4MSQZO-DQOxFIvF.mjs.map → html-to-markdown-JW4MSQZO-CJGwkgpQ.mjs.map} +1 -1
  70. package/dist/index.mjs +9 -1
  71. package/dist/index.mjs.map +1 -1
  72. package/dist/{join-TBRGI3LQ-B8I9tkJ5.mjs → join-TBRGI3LQ-BAeS4llp.mjs} +2 -2
  73. package/dist/{join-TBRGI3LQ-B8I9tkJ5.mjs.map → join-TBRGI3LQ-BAeS4llp.mjs.map} +1 -1
  74. package/dist/{jq-4XLYLOS5-wFZYfsfJ.mjs → jq-4XLYLOS5-BqwoG7Hj.mjs} +7 -7
  75. package/dist/{jq-4XLYLOS5-wFZYfsfJ.mjs.map → jq-4XLYLOS5-BqwoG7Hj.mjs.map} +1 -1
  76. package/dist/{js-exec-N5KEZBH7-CoRL1IOd.mjs → js-exec-N5KEZBH7-DbXmMwbQ.mjs} +13 -13
  77. package/dist/{js-exec-N5KEZBH7-CoRL1IOd.mjs.map → js-exec-N5KEZBH7-DbXmMwbQ.mjs.map} +1 -1
  78. package/dist/{ln-4LGSXXGD-Dg0R9i5G.mjs → ln-4LGSXXGD-CpN9ORGB.mjs} +2 -2
  79. package/dist/{ln-4LGSXXGD-Dg0R9i5G.mjs.map → ln-4LGSXXGD-CpN9ORGB.mjs.map} +1 -1
  80. package/dist/{ls-ZJGQER7M-DLDSfI4x.mjs → ls-ZJGQER7M-B0J6G8Ao.mjs} +3 -3
  81. package/dist/{ls-ZJGQER7M-DLDSfI4x.mjs.map → ls-ZJGQER7M-B0J6G8Ao.mjs.map} +1 -1
  82. package/dist/{maybe-auto-update-CKoJBwJ_.mjs → maybe-auto-update-dzy8lzxn.mjs} +13 -8
  83. package/dist/maybe-auto-update-dzy8lzxn.mjs.map +1 -0
  84. package/dist/{md5sum-SPU24VSG-DQc8sqXO.mjs → md5sum-SPU24VSG-CETB591F.mjs} +3 -3
  85. package/dist/{md5sum-SPU24VSG-DQc8sqXO.mjs.map → md5sum-SPU24VSG-CETB591F.mjs.map} +1 -1
  86. package/dist/{mkdir-MEPGZOB6-BjUKzhdL.mjs → mkdir-MEPGZOB6-B5bpLWTB.mjs} +6 -6
  87. package/dist/{mkdir-MEPGZOB6-BjUKzhdL.mjs.map → mkdir-MEPGZOB6-B5bpLWTB.mjs.map} +1 -1
  88. package/dist/{mv-W5BIQ646-CdSIyY-U.mjs → mv-W5BIQ646-7tYLVIVw.mjs} +3 -3
  89. package/dist/{mv-W5BIQ646-CdSIyY-U.mjs.map → mv-W5BIQ646-7tYLVIVw.mjs.map} +1 -1
  90. package/dist/{nl-WSDW7I4O-DmtCnyKU.mjs → nl-WSDW7I4O-CHnycLPl.mjs} +2 -2
  91. package/dist/{nl-WSDW7I4O-DmtCnyKU.mjs.map → nl-WSDW7I4O-CHnycLPl.mjs.map} +1 -1
  92. package/dist/{paste-7JC6S4DX-CtmM5Qy8.mjs → paste-7JC6S4DX-CKUaf7iE.mjs} +2 -2
  93. package/dist/{paste-7JC6S4DX-CtmM5Qy8.mjs.map → paste-7JC6S4DX-CKUaf7iE.mjs.map} +1 -1
  94. package/dist/{printf-TWGXF445-B7cTysaa.mjs → printf-TWGXF445-Byg8yI9x.mjs} +3 -3
  95. package/dist/{printf-TWGXF445-B7cTysaa.mjs.map → printf-TWGXF445-Byg8yI9x.mjs.map} +1 -1
  96. package/dist/{program-OcNo9lRF.mjs → program-CyirDIA2.mjs} +4538 -1013
  97. package/dist/program-CyirDIA2.mjs.map +1 -0
  98. package/dist/{python3-POMOR4OA-CKy80mpF.mjs → python3-POMOR4OA-D-6P4EKs.mjs} +17 -17
  99. package/dist/python3-POMOR4OA-D-6P4EKs.mjs.map +1 -0
  100. package/dist/{readlink-OPJF4DL5-Rc1Mz_Xx.mjs → readlink-OPJF4DL5-CGS-PxkH.mjs} +2 -2
  101. package/dist/{readlink-OPJF4DL5-Rc1Mz_Xx.mjs.map → readlink-OPJF4DL5-CGS-PxkH.mjs.map} +1 -1
  102. package/dist/{rev-5EHFX4EJ-3dd9vwHW.mjs → rev-5EHFX4EJ-BLJdSt1D.mjs} +2 -2
  103. package/dist/{rev-5EHFX4EJ-3dd9vwHW.mjs.map → rev-5EHFX4EJ-BLJdSt1D.mjs.map} +1 -1
  104. package/dist/{rg-S4FXYXWB-BbXVo6JX.mjs → rg-S4FXYXWB-Ekm2aMrv.mjs} +14 -14
  105. package/dist/{rg-S4FXYXWB-BbXVo6JX.mjs.map → rg-S4FXYXWB-Ekm2aMrv.mjs.map} +1 -1
  106. package/dist/{rm-SSGETQVQ-Ch53Rmrr.mjs → rm-SSGETQVQ-DV-525hw.mjs} +6 -6
  107. package/dist/{rm-SSGETQVQ-Ch53Rmrr.mjs.map → rm-SSGETQVQ-DV-525hw.mjs.map} +1 -1
  108. package/dist/{rmdir-OC4ZLPYA-D3QCHlIB.mjs → rmdir-OC4ZLPYA-BGOrZMUa.mjs} +3 -3
  109. package/dist/{rmdir-OC4ZLPYA-D3QCHlIB.mjs.map → rmdir-OC4ZLPYA-BGOrZMUa.mjs.map} +1 -1
  110. package/dist/{run-package-manager-update-DgeSZuUc.mjs → run-package-manager-update-C4uA6xWB.mjs} +281 -66
  111. package/dist/run-package-manager-update-C4uA6xWB.mjs.map +1 -0
  112. package/dist/{sed-S5UIK574-DE1KeTk3.mjs → sed-S5UIK574-C3nurgzc.mjs} +4 -4
  113. package/dist/{sed-S5UIK574-DE1KeTk3.mjs.map → sed-S5UIK574-C3nurgzc.mjs.map} +1 -1
  114. package/dist/{sha1sum-2PTOAFR6-DNjSNcYK.mjs → sha1sum-2PTOAFR6-GDQNigjA.mjs} +3 -3
  115. package/dist/{sha1sum-2PTOAFR6-DNjSNcYK.mjs.map → sha1sum-2PTOAFR6-GDQNigjA.mjs.map} +1 -1
  116. package/dist/{sha256sum-NS7D3IXX-BMaCKkT5.mjs → sha256sum-NS7D3IXX-bI78J2Ek.mjs} +3 -3
  117. package/dist/{sha256sum-NS7D3IXX-BMaCKkT5.mjs.map → sha256sum-NS7D3IXX-bI78J2Ek.mjs.map} +1 -1
  118. package/dist/skills-bundle/_AGENTS.mcp.md +9 -9
  119. package/dist/skills-bundle/_AGENTS.md +88 -47
  120. package/dist/{sleep-X22JJINO-Do5hEQQW.mjs → sleep-X22JJINO-gsrMSr5k.mjs} +2 -2
  121. package/dist/{sleep-X22JJINO-Do5hEQQW.mjs.map → sleep-X22JJINO-gsrMSr5k.mjs.map} +1 -1
  122. package/dist/{sort-SW2YEO5B-B7j1zw8k.mjs → sort-SW2YEO5B-D5UsbJuA.mjs} +3 -3
  123. package/dist/{sort-SW2YEO5B-B7j1zw8k.mjs.map → sort-SW2YEO5B-D5UsbJuA.mjs.map} +1 -1
  124. package/dist/{split-4KKZZXXE-h8GD4HP4.mjs → split-4KKZZXXE-D_eM0wGE.mjs} +2 -2
  125. package/dist/{split-4KKZZXXE-h8GD4HP4.mjs.map → split-4KKZZXXE-D_eM0wGE.mjs.map} +1 -1
  126. package/dist/{sqlite3-CGOEFJAO-DvzzghDg.mjs → sqlite3-CGOEFJAO-Eu-N4sPa.mjs} +3 -3
  127. package/dist/{sqlite3-CGOEFJAO-DvzzghDg.mjs.map → sqlite3-CGOEFJAO-Eu-N4sPa.mjs.map} +1 -1
  128. package/dist/{stat-CD34IZ4P-B5ZOJh4J.mjs → stat-CD34IZ4P-BS1XgX8K.mjs} +2 -2
  129. package/dist/{stat-CD34IZ4P-B5ZOJh4J.mjs.map → stat-CD34IZ4P-BS1XgX8K.mjs.map} +1 -1
  130. package/dist/{strings-6WDHLGMX-DdiEdoL-.mjs → strings-6WDHLGMX-BGTuHTcR.mjs} +2 -2
  131. package/dist/{strings-6WDHLGMX-DdiEdoL-.mjs.map → strings-6WDHLGMX-BGTuHTcR.mjs.map} +1 -1
  132. package/dist/{tail-R4PCA2C4-CUfroNeu.mjs → tail-R4PCA2C4-CfCvDsXY.mjs} +2 -2
  133. package/dist/{tail-R4PCA2C4-CUfroNeu.mjs.map → tail-R4PCA2C4-CfCvDsXY.mjs.map} +1 -1
  134. package/dist/{tar-STHHZTZ6-DRf60e-G.mjs → tar-STHHZTZ6-CzlFhy51.mjs} +3 -3
  135. package/dist/{tar-STHHZTZ6-DRf60e-G.mjs.map → tar-STHHZTZ6-CzlFhy51.mjs.map} +1 -1
  136. package/dist/{tee-YUZ2FKCJ-po_dfyc_.mjs → tee-YUZ2FKCJ-rZEvi44P.mjs} +2 -2
  137. package/dist/{tee-YUZ2FKCJ-po_dfyc_.mjs.map → tee-YUZ2FKCJ-rZEvi44P.mjs.map} +1 -1
  138. package/dist/templates/hello-world/README.md +1 -1
  139. package/dist/templates/hello-world/package.json +2 -3
  140. package/dist/{time-D4LNBSWX-DVWhAldK.mjs → time-D4LNBSWX-D_2r6q9s.mjs} +6 -6
  141. package/dist/{time-D4LNBSWX-DVWhAldK.mjs.map → time-D4LNBSWX-D_2r6q9s.mjs.map} +1 -1
  142. package/dist/{timeout-YDCRSLPQ-B_yntmXU.mjs → timeout-YDCRSLPQ-BCyope7T.mjs} +7 -7
  143. package/dist/{timeout-YDCRSLPQ-B_yntmXU.mjs.map → timeout-YDCRSLPQ-BCyope7T.mjs.map} +1 -1
  144. package/dist/{touch-UA33VN3N-oW1SBT1r.mjs → touch-UA33VN3N-NfG_nyJw.mjs} +2 -2
  145. package/dist/{touch-UA33VN3N-oW1SBT1r.mjs.map → touch-UA33VN3N-NfG_nyJw.mjs.map} +1 -1
  146. package/dist/{tr-36LHWFRQ-CTq3z6wq.mjs → tr-36LHWFRQ-BqtCYOhC.mjs} +3 -3
  147. package/dist/{tr-36LHWFRQ-CTq3z6wq.mjs.map → tr-36LHWFRQ-BqtCYOhC.mjs.map} +1 -1
  148. package/dist/{tree-YLD52CNT-CIozNsLQ.mjs → tree-YLD52CNT-BjNKvvwq.mjs} +3 -3
  149. package/dist/{tree-YLD52CNT-CIozNsLQ.mjs.map → tree-YLD52CNT-BjNKvvwq.mjs.map} +1 -1
  150. package/dist/{unexpand-CADSA4VO-Cq9DTcUg.mjs → unexpand-CADSA4VO-BRBq66Ny.mjs} +2 -2
  151. package/dist/{unexpand-CADSA4VO-Cq9DTcUg.mjs.map → unexpand-CADSA4VO-BRBq66Ny.mjs.map} +1 -1
  152. package/dist/{uniq-XSIZR6PB-D5lt-IXF.mjs → uniq-XSIZR6PB-CEAOHvgb.mjs} +3 -3
  153. package/dist/{uniq-XSIZR6PB-D5lt-IXF.mjs.map → uniq-XSIZR6PB-CEAOHvgb.mjs.map} +1 -1
  154. package/dist/{wc-LF7NU4LA-BFPabrwD.mjs → wc-LF7NU4LA-DQsmzFSM.mjs} +3 -3
  155. package/dist/{wc-LF7NU4LA-BFPabrwD.mjs.map → wc-LF7NU4LA-DQsmzFSM.mjs.map} +1 -1
  156. package/dist/{which-XEM24D5D-2LvlkpUo.mjs → which-XEM24D5D-ClMwNewh.mjs} +2 -2
  157. package/dist/{which-XEM24D5D-2LvlkpUo.mjs.map → which-XEM24D5D-ClMwNewh.mjs.map} +1 -1
  158. package/dist/{xan-Y6WF3IRG-DjKO96Pj.mjs → xan-Y6WF3IRG-CvZAKNm2.mjs} +7 -7
  159. package/dist/{xan-Y6WF3IRG-DjKO96Pj.mjs.map → xan-Y6WF3IRG-CvZAKNm2.mjs.map} +1 -1
  160. package/dist/{xargs-MGZPH7AX-D2bIgrdg.mjs → xargs-MGZPH7AX-DaERa6_Q.mjs} +6 -6
  161. package/dist/{xargs-MGZPH7AX-D2bIgrdg.mjs.map → xargs-MGZPH7AX-DaERa6_Q.mjs.map} +1 -1
  162. package/dist/{yq-4QJW3EQG-XhB3aACo.mjs → yq-4QJW3EQG-DABmi_in.mjs} +88 -88
  163. package/dist/yq-4QJW3EQG-DABmi_in.mjs.map +1 -0
  164. package/package.json +3 -6
  165. package/dist/dist-B72RPrho.mjs.map +0 -1
  166. package/dist/dist-CBVf3SwI.mjs +0 -11661
  167. package/dist/dist-CBVf3SwI.mjs.map +0 -1
  168. package/dist/dist-CyKcvwuI.mjs +0 -816
  169. package/dist/dist-CyKcvwuI.mjs.map +0 -1
  170. package/dist/dist-Duu6X1Sh.mjs +0 -4
  171. package/dist/dist-E6dh6qXe.mjs.map +0 -1
  172. package/dist/file-IPZJC3FQ-DcZNOWyY.mjs.map +0 -1
  173. package/dist/maybe-auto-update-CKoJBwJ_.mjs.map +0 -1
  174. package/dist/program-OcNo9lRF.mjs.map +0 -1
  175. package/dist/python3-POMOR4OA-CKy80mpF.mjs.map +0 -1
  176. package/dist/run-package-manager-update-DgeSZuUc.mjs.map +0 -1
  177. package/dist/watch-app-DTIeKrbl-CSpsNzVG.mjs +0 -100
  178. package/dist/watch-app-DTIeKrbl-CSpsNzVG.mjs.map +0 -1
  179. package/dist/yq-4QJW3EQG-XhB3aACo.mjs.map +0 -1
@@ -0,0 +1,1829 @@
1
+ #!/usr/bin/env node
2
+ import { an as PROJECT_MANIFEST_REL_PATH, cn as PROJECT_SOURCE_IGNORED_DIRS, dn as PROJECT_SOURCE_MAX_TOTAL_BYTES, fi as isIgnoredProjectSourceFileName, ln as PROJECT_SOURCE_MAX_FILES, mi as isProbablyBinaryProjectSource, un as PROJECT_SOURCE_MAX_FILE_BYTES } from "./dist-C6adeAws.mjs";
3
+ import { at as classifyCall, ct as locateWorkflow, dt as entryIdFromFile, ft as readKeystrokeIgnoreDirective, it as packDirFromDisk, ot as computeCallSiteIds, pt as shouldSkipKeystrokeModuleFile, st as diagnoseWorkflowSource } from "./dist-DSkS8uEB.mjs";
4
+ import { createRequire, isBuiltin } from "node:module";
5
+ import "node:os";
6
+ import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
7
+ import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, rmSync, statSync, writeFileSync } from "node:fs";
8
+ import { fileURLToPath } from "node:url";
9
+ import { createHash } from "node:crypto";
10
+ import { build, mergeConfig } from "tsdown";
11
+ import ts from "typescript";
12
+ //#region ../../packages/build/dist/walk-project-CLy8GqGX.mjs
13
+ function toPosix$1(path) {
14
+ return path.split(sep).join("/");
15
+ }
16
+ function projectRelativePath(root, filePath) {
17
+ return toPosix$1(relative(root, normalizeBuildFilePath(filePath)));
18
+ }
19
+ /** Normalize paths so /var and /private/var compare equal on macOS. */
20
+ function normalizeBuildFilePath(filePath) {
21
+ const absolute = resolve(filePath);
22
+ try {
23
+ return realpathSync.native(absolute);
24
+ } catch {
25
+ return absolute;
26
+ }
27
+ }
28
+ function normalizeModuleId(id, root) {
29
+ if (id.startsWith("\0")) return null;
30
+ const normalized = normalizeBuildFilePath(id.startsWith("file://") ? fileURLToPath(id) : id);
31
+ if (!normalized.startsWith(normalizeBuildFilePath(root))) return null;
32
+ return normalized;
33
+ }
34
+ function formatImportGuardError(root, ignoredPath, importer) {
35
+ const ignored = projectRelativePath(root, ignoredPath);
36
+ if (importer) return `Cannot import "${ignored}" (@keystroke ignore) from "${projectRelativePath(root, importer)}". Remove the directive or stop importing it from a shipped module.`;
37
+ return `Cannot import "${ignored}" (@keystroke ignore). Remove the directive or stop importing it from a shipped module.`;
38
+ }
39
+ /** Throw when a built module imports a `@keystroke ignore` source file. */
40
+ function keystrokeIgnoreGuardPlugin(options) {
41
+ const root = normalizeBuildFilePath(options.root);
42
+ const ignoredFiles = new Set(options.ignoredFiles.map((filePath) => normalizeBuildFilePath(filePath)));
43
+ function assertNotIgnored(filePath, importer) {
44
+ const normalized = normalizeBuildFilePath(filePath);
45
+ if (!ignoredFiles.has(normalized)) return;
46
+ throw new Error(formatImportGuardError(root, normalized, importer));
47
+ }
48
+ return {
49
+ name: "keystroke-ignore-guard",
50
+ async resolveId(source, importer, resolveOptions) {
51
+ if (resolveOptions?.isEntry || !importer) return null;
52
+ const resolved = await this.resolve(source, importer, {
53
+ ...resolveOptions,
54
+ skipSelf: true
55
+ });
56
+ if (!resolved) return null;
57
+ assertNotIgnored(typeof resolved === "string" ? resolved : resolved.id, importer);
58
+ return null;
59
+ },
60
+ load(id) {
61
+ const normalized = normalizeModuleId(id, root);
62
+ if (!normalized) return null;
63
+ assertNotIgnored(normalized);
64
+ return null;
65
+ }
66
+ };
67
+ }
68
+ const MAX_FILE_BYTES = PROJECT_SOURCE_MAX_FILE_BYTES;
69
+ const MAX_TOTAL_BYTES = PROJECT_SOURCE_MAX_TOTAL_BYTES;
70
+ const MAX_FILES = PROJECT_SOURCE_MAX_FILES;
71
+ function toPosix$6(path) {
72
+ return path.split(sep).join("/");
73
+ }
74
+ function classifyBuildEntry(root, srcRoot, filePath) {
75
+ const relativePath = toPosix$6(relative(root, filePath));
76
+ const agentsPrefix = `${toPosix$6(relative(root, join(srcRoot, "agents")))}/`;
77
+ const workflowsPrefix = `${toPosix$6(relative(root, join(srcRoot, "workflows")))}/`;
78
+ const triggersPrefix = `${toPosix$6(relative(root, join(srcRoot, "triggers")))}/`;
79
+ const actionsPrefix = `${toPosix$6(relative(root, join(srcRoot, "actions")))}/`;
80
+ if (relativePath.startsWith(agentsPrefix) && /\.(ts|mts)$/.test(relativePath) && !/\.(int\.)?test\.(ts|mts)$/.test(relativePath)) {
81
+ const id = entryIdFromFile(join(srcRoot, "agents"), filePath, { nestedEntry: "agent" });
82
+ return id ? {
83
+ entryKey: `agents/${id}`,
84
+ entryPath: filePath
85
+ } : null;
86
+ }
87
+ if (relativePath.startsWith(actionsPrefix) && /\.(ts|mts)$/.test(relativePath) && !/\.(int\.)?test\.(ts|mts)$/.test(relativePath)) {
88
+ const id = entryIdFromFile(join(srcRoot, "actions"), filePath, { nestedEntry: "action" });
89
+ return id ? {
90
+ entryKey: `actions/${id}`,
91
+ entryPath: filePath
92
+ } : null;
93
+ }
94
+ if (relativePath.startsWith(workflowsPrefix) && /\.(ts|mts)$/.test(relativePath) && !/\.(int\.)?test\.(ts|mts)$/.test(relativePath)) {
95
+ const id = entryIdFromFile(join(srcRoot, "workflows"), filePath, { nestedEntry: "workflow" });
96
+ return id ? {
97
+ entryKey: `workflows/${id}`,
98
+ entryPath: filePath
99
+ } : null;
100
+ }
101
+ if (relativePath.startsWith(triggersPrefix) && /\.(ts|mts)$/.test(relativePath) && !/\.(int\.)?test\.(ts|mts)$/.test(relativePath)) {
102
+ const id = entryIdFromFile(join(srcRoot, "triggers"), filePath, { nestedEntry: "trigger" });
103
+ return id ? {
104
+ entryKey: `triggers/${id}`,
105
+ entryPath: filePath
106
+ } : null;
107
+ }
108
+ return null;
109
+ }
110
+ function shouldSkipIgnoredModule(filePath, phase) {
111
+ return shouldSkipKeystrokeModuleFile(readKeystrokeIgnoreDirective(filePath), phase);
112
+ }
113
+ function isSrcTypeScriptFile(srcRoot, filePath) {
114
+ const relativePath = toPosix$6(relative(srcRoot, filePath));
115
+ if (relativePath.startsWith("..")) return false;
116
+ return /\.(ts|mts)$/.test(relativePath);
117
+ }
118
+ function walkTree(root, dir, srcRoot, phase, collectSources, sourceFiles, buildEntries, ignoredFiles, totals) {
119
+ for (const name of readdirSync(dir).sort()) {
120
+ if (collectSources && (sourceFiles.length >= MAX_FILES || totals.bytes >= MAX_TOTAL_BYTES)) return;
121
+ const absolute = join(dir, name);
122
+ const stats = statSync(absolute);
123
+ if (stats.isDirectory()) {
124
+ if (PROJECT_SOURCE_IGNORED_DIRS.has(name)) continue;
125
+ walkTree(root, absolute, srcRoot, phase, collectSources, sourceFiles, buildEntries, ignoredFiles, totals);
126
+ continue;
127
+ }
128
+ if (!stats.isFile()) continue;
129
+ const isUnderSrc = isSrcTypeScriptFile(srcRoot, absolute);
130
+ const skipIgnored = isUnderSrc ? shouldSkipIgnoredModule(absolute, phase) : false;
131
+ if (isUnderSrc && skipIgnored) ignoredFiles.push(normalizeBuildFilePath(absolute));
132
+ const buildEntry = classifyBuildEntry(root, srcRoot, absolute);
133
+ if (buildEntry && !skipIgnored) buildEntries[buildEntry.entryKey] = buildEntry.entryPath;
134
+ if (!collectSources) continue;
135
+ if (stats.size > MAX_FILE_BYTES || isIgnoredProjectSourceFileName(name)) continue;
136
+ const buffer = readFileSync(absolute);
137
+ if (isProbablyBinaryProjectSource(buffer)) continue;
138
+ totals.bytes += buffer.byteLength;
139
+ sourceFiles.push({
140
+ path: toPosix$6(relative(root, absolute)),
141
+ contents: buffer.toString("utf8"),
142
+ hash: createHash("sha256").update(buffer).digest("hex")
143
+ });
144
+ }
145
+ }
146
+ /**
147
+ * One full-tree walk of the project: classifies tsdown entries and optionally
148
+ * collects deploy source files (path + contents + hash) under snapshot limits.
149
+ */
150
+ function walkProject(root, srcDirOrOptions = "src", maybeOptions) {
151
+ const srcDir = typeof srcDirOrOptions === "string" ? srcDirOrOptions : srcDirOrOptions.srcDir ?? "src";
152
+ const options = typeof srcDirOrOptions === "string" ? maybeOptions ?? {} : srcDirOrOptions;
153
+ const collectSources = options.collectSources ?? false;
154
+ const phase = options.phase ?? "build";
155
+ const sourceFiles = [];
156
+ const buildEntries = {};
157
+ const ignoredFiles = [];
158
+ walkTree(root, root, join(root, srcDir), phase, collectSources, sourceFiles, buildEntries, ignoredFiles, { bytes: 0 });
159
+ return {
160
+ sourceFiles,
161
+ buildEntries,
162
+ ignoredFiles
163
+ };
164
+ }
165
+ //#endregion
166
+ //#region ../../packages/tsdown-config/deps.js
167
+ /** Native addons kept external — resolved from the CLI runtime at app start. */
168
+ const NATIVE_RUNTIME_DEPS = [
169
+ "pg",
170
+ "better-sqlite3",
171
+ "@parcel/watcher"
172
+ ];
173
+ /**
174
+ * Framework/runtime `@keystrokehq/*` shipped in the project-server image, so user-app builds
175
+ * keep them external and resolve them from the runtime at boot. Everything else under the scope
176
+ * (Composio catalog integrations like `@keystrokehq/posthog`, …) is bundled into the artifact.
177
+ *
178
+ * This set MUST equal the `@keystrokehq/*` dependency closure of `@keystrokehq/project-runtime`
179
+ * (the deploy image) — `deps.test.ts` enforces it. To change what stays external, change what the
180
+ * runtime image depends on; do not edit this list by hand. `exa` is the only integration
181
+ * package the framework imports directly (web search); `gateway` ships Slack and other channel
182
+ * adapters in the runtime image.
183
+ */
184
+ const RUNTIME_KEYSTROKE_PACKAGES = new Set([
185
+ "access-control",
186
+ "action",
187
+ "agent",
188
+ "app",
189
+ "auth",
190
+ "build",
191
+ "config",
192
+ "credentials",
193
+ "database",
194
+ "exa",
195
+ "gateway",
196
+ "hosting",
197
+ "http",
198
+ "keystroke",
199
+ "manifest",
200
+ "mcp",
201
+ "memory",
202
+ "oauth",
203
+ "platform-database",
204
+ "project-runtime",
205
+ "projects",
206
+ "runtime",
207
+ "sandbox",
208
+ "scheduler",
209
+ "sdk",
210
+ "secrets",
211
+ "shared",
212
+ "storage",
213
+ "telemetry",
214
+ "tracing",
215
+ "trigger",
216
+ "tsdown-config",
217
+ "web-search",
218
+ "worker",
219
+ "workflow",
220
+ "workflow-canvas"
221
+ ]);
222
+ /** Matches framework/runtime `@keystrokehq/*` kept external during user-app builds. */
223
+ const FRAMEWORK_KEYSTROKE_EXTERNAL = new RegExp(`^@keystrokehq\\/(?:${[...RUNTIME_KEYSTROKE_PACKAGES].sort().join("|")})(?:\\/|$)`);
224
+ function keystrokePackageName(name) {
225
+ if (!name.startsWith("@keystrokehq/")) return null;
226
+ return name.slice(13).split("/")[0] ?? null;
227
+ }
228
+ function isRuntimeKeystrokePackage(name) {
229
+ const pkg = keystrokePackageName(name);
230
+ return pkg !== null && RUNTIME_KEYSTROKE_PACKAGES.has(pkg);
231
+ }
232
+ /**
233
+ * Kept external so .d.ts emission does not inline internal/inferred types.
234
+ *
235
+ * `typescript` is external because the TS compiler cannot be cleanly bundled into
236
+ * ESM — it mixes `require()`/`__filename` with top-level await, which Node rejects
237
+ * with `ERR_AMBIGUOUS_MODULE_SYNTAX` on load. Packages that use the compiler
238
+ * (`workflow-canvas`, `manifest`, `build`) declare it as a dependency, so it
239
+ * resolves from `node_modules` at runtime instead of being inlined.
240
+ */
241
+ const LIBRARY_EXTERNAL_DEPS = [
242
+ "better-auth",
243
+ /^@better-auth\//,
244
+ /^better-auth\//,
245
+ "typescript"
246
+ ];
247
+ /** Kept external when bundling published entry points (cli, keystroke, platform). */
248
+ const BUNDLED_ENTRY_EXTERNAL_DEPS = [...[
249
+ ...NATIVE_RUNTIME_DEPS,
250
+ "dockerode",
251
+ "ssh2",
252
+ "cpu-features",
253
+ "microsandbox",
254
+ /^@aws-sdk\//,
255
+ /^@napi-rs\//,
256
+ "hono",
257
+ /^@hono\//,
258
+ "undici"
259
+ ], ...LIBRARY_EXTERNAL_DEPS];
260
+ /** Bundle into CLI — device login uses Better Auth client only. */
261
+ const BETTER_AUTH_CLIENT_BUNDLE_PATTERNS = [/^better-auth\/client$/, /^better-auth\/client\//];
262
+ function isNativeRuntimeDep(id) {
263
+ return NATIVE_RUNTIME_DEPS.some((dep) => id === dep || id.startsWith(`${dep}/`));
264
+ }
265
+ function packageName(id) {
266
+ if (id.startsWith("@")) {
267
+ const [scope, name] = id.split("/");
268
+ return name ? `${scope}/${name}` : id;
269
+ }
270
+ return id.split("/")[0] ?? id;
271
+ }
272
+ /** Zod ships in the project-runtime image; keep one copy out of user-app artifacts. */
273
+ function isRuntimeSharedNpmDep(id) {
274
+ return packageName(id) === "zod";
275
+ }
276
+ function isRuntimeExternal(id) {
277
+ const name = packageName(id);
278
+ if (isNativeRuntimeDep(name)) return true;
279
+ if (isRuntimeSharedNpmDep(name)) return true;
280
+ if (name.startsWith("@keystrokehq/")) return isRuntimeKeystrokePackage(name);
281
+ if (name === "better-auth" || name.startsWith("@better-auth/")) return true;
282
+ return false;
283
+ }
284
+ /** Library packages resolve npm deps from node_modules at runtime. */
285
+ function libraryBuildDepsConfig() {
286
+ return {
287
+ alwaysBundle: (_id) => null,
288
+ neverBundle: [
289
+ ...NATIVE_RUNTIME_DEPS,
290
+ /^@keystrokehq\//,
291
+ ...LIBRARY_EXTERNAL_DEPS
292
+ ],
293
+ onlyBundle: false
294
+ };
295
+ }
296
+ /** Bundle npm deps into dist; resolve @keystrokehq/*, zod, and natives from the runtime. */
297
+ function userAppBuildDepsConfig() {
298
+ return {
299
+ alwaysBundle: (id, _importer) => {
300
+ if (id.startsWith(".") || id.startsWith("/") || isBuiltin(id)) return null;
301
+ return isRuntimeExternal(id) ? null : true;
302
+ },
303
+ neverBundle: [
304
+ ...NATIVE_RUNTIME_DEPS,
305
+ FRAMEWORK_KEYSTROKE_EXTERNAL,
306
+ /^zod(?:\/|$)/,
307
+ ...LIBRARY_EXTERNAL_DEPS
308
+ ],
309
+ onlyBundle: false
310
+ };
311
+ }
312
+ /**
313
+ * Published entry packages (cli, keystroke, platform): declare bundled @keystrokehq/*
314
+ * in dependencies (changesets release graph ignores devDependencies). Inlining is
315
+ * driven by alwaysBundle below, not by dep kind. Runtime npm deps stay external.
316
+ *
317
+ * `@keystrokehq/keystroke` uses workspace:>=0.0.0 ranges so private primitive
318
+ * patches do not cascade-publish the facade; CLI/platform keep workspace:*.
319
+ */
320
+ function bundledEntryDepsConfig() {
321
+ return {
322
+ alwaysBundle: [/^@keystrokehq\//],
323
+ neverBundle: [...BUNDLED_ENTRY_EXTERNAL_DEPS],
324
+ onlyBundle: false
325
+ };
326
+ }
327
+ [...BETTER_AUTH_CLIENT_BUNDLE_PATTERNS];
328
+ //#endregion
329
+ //#region ../../packages/tsdown-config/index.js
330
+ const baseTsdownConfig = {
331
+ format: ["esm", "cjs"],
332
+ dts: true,
333
+ clean: true,
334
+ sourcemap: true,
335
+ target: "node20",
336
+ deps: libraryBuildDepsConfig()
337
+ };
338
+ bundledEntryDepsConfig();
339
+ //#endregion
340
+ //#region ../../packages/build/dist/index.mjs
341
+ /**
342
+ * Build-time injection of the deterministic structural `callSiteId` into every
343
+ * durable step call in a workflow source file, so the runtime emits
344
+ * `step:<callSiteId>#<occurrence>` correlation ids (and `step:<callSiteId>`
345
+ * credential consumer ids) that line up 1:1 with the canvas graph nodes the
346
+ * deploy-time producer mints from the same source. There is no user-authored
347
+ * step id — identity is entirely internal and injected here.
348
+ *
349
+ * Injection shape by kind (the `callSiteId` is the same id `computeCallSiteIds`
350
+ * returns, which equals the producer's step-node id):
351
+ * - action/sub-workflow `x.run(i)` → `x.run(i).__site("<id>")` (builder method)
352
+ * - agent `a.prompt(i, opts?)` → `__site` merged into the prompt options
353
+ * - llm `promptLlm(i, opts?)` → `__site` merged into the options
354
+ * - hook `ctx.hook(opts?)` → `__site` merged into the options
355
+ * - sleep `ctx.sleep(d, opts?)` → `__site` merged into a second options arg
356
+ */
357
+ function injectCallSiteIds(code, fileName) {
358
+ const sourceFile = ts.createSourceFile(fileName, code, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
359
+ const located = locateWorkflow(sourceFile);
360
+ if (!located) return code;
361
+ const ids = computeCallSiteIds(sourceFile);
362
+ if (ids.size === 0) return code;
363
+ const edits = [];
364
+ for (const [node, id] of ids) {
365
+ const info = classifyCall(node, located.ctxParamName);
366
+ if (!info) continue;
367
+ if (info.callKind === "workflow-step") {
368
+ edits.push({
369
+ pos: node.getEnd(),
370
+ text: `.__site(${JSON.stringify(id)})`
371
+ });
372
+ continue;
373
+ }
374
+ if (info.callKind === "agent" || info.callKind === "llm") {
375
+ pushOptionsEdit(edits, node, id);
376
+ continue;
377
+ }
378
+ if (info.callKind === "hook") {
379
+ pushHookOptionsEdit(edits, node, id);
380
+ continue;
381
+ }
382
+ if (info.callKind === "wait") pushSleepOptionsEdit(edits, node, id);
383
+ }
384
+ if (edits.length === 0) return code;
385
+ edits.sort((a, b) => b.pos - a.pos);
386
+ let out = code;
387
+ for (const edit of edits) out = out.slice(0, edit.pos) + edit.text + out.slice(edit.pos);
388
+ return out;
389
+ }
390
+ /**
391
+ * Merge `__site: "<id>"` into a call's options argument (agents / promptLlm).
392
+ * - no 2nd arg → append `, { __site: "id" }`
393
+ * - 2nd arg object literal → insert `__site: "id", ` after its `{`
394
+ * - 2nd arg anything else → wrap as `{ ...orig, __site: "id" }`
395
+ */
396
+ function pushOptionsEdit(edits, call, id) {
397
+ const literal = JSON.stringify(id);
398
+ const optionsArg = call.arguments[1];
399
+ if (!optionsArg) {
400
+ const firstArg = call.arguments[0];
401
+ const insertAt = firstArg ? firstArg.getEnd() : call.getEnd() - 1;
402
+ edits.push({
403
+ pos: insertAt,
404
+ text: `, { __site: ${literal} }`
405
+ });
406
+ return;
407
+ }
408
+ if (ts.isObjectLiteralExpression(optionsArg)) {
409
+ edits.push({
410
+ pos: optionsArg.getStart() + 1,
411
+ text: ` __site: ${literal},`
412
+ });
413
+ return;
414
+ }
415
+ edits.push({
416
+ pos: optionsArg.getStart(),
417
+ text: "{ ..."
418
+ });
419
+ edits.push({
420
+ pos: optionsArg.getEnd(),
421
+ text: `, __site: ${literal} }`
422
+ });
423
+ }
424
+ /** Merge `__site` into `ctx.hook(opts?)` — options are the first (only) argument. */
425
+ function pushHookOptionsEdit(edits, call, id) {
426
+ const literal = JSON.stringify(id);
427
+ const optionsArg = call.arguments[0];
428
+ if (!optionsArg) {
429
+ edits.push({
430
+ pos: call.getEnd() - 1,
431
+ text: `{ __site: ${literal} }`
432
+ });
433
+ return;
434
+ }
435
+ if (ts.isObjectLiteralExpression(optionsArg)) {
436
+ edits.push({
437
+ pos: optionsArg.getStart() + 1,
438
+ text: ` __site: ${literal},`
439
+ });
440
+ return;
441
+ }
442
+ edits.push({
443
+ pos: optionsArg.getStart(),
444
+ text: "{ ..."
445
+ });
446
+ edits.push({
447
+ pos: optionsArg.getEnd(),
448
+ text: `, __site: ${literal} }`
449
+ });
450
+ }
451
+ /** Append `{ __site }` as the second arg to `ctx.sleep(duration)`. */
452
+ function pushSleepOptionsEdit(edits, call, id) {
453
+ const literal = JSON.stringify(id);
454
+ const durationArg = call.arguments[0];
455
+ const insertAt = durationArg ? durationArg.getEnd() : call.getEnd() - 1;
456
+ edits.push({
457
+ pos: insertAt,
458
+ text: `, { __site: ${literal} }`
459
+ });
460
+ }
461
+ function toPosix$5(path) {
462
+ return path.split(sep).join("/");
463
+ }
464
+ /**
465
+ * Rolldown plugin that runs {@link injectCallSiteIds} over workflow source files
466
+ * (and their same-file helpers) before transpile. Scoped to `src/workflows/` so
467
+ * non-workflow modules are untouched; cross-file helpers stay unkeyed by design.
468
+ */
469
+ function callSiteIdInjectionPlugin(options) {
470
+ const srcDir = options.srcDir ?? "src";
471
+ const workflowsPrefix = toPosix$5(`${options.root}/${srcDir}/workflows/`);
472
+ return {
473
+ name: "keystroke-call-site-ids",
474
+ transform(code, id) {
475
+ const normalized = toPosix$5(id);
476
+ if (!normalized.startsWith(workflowsPrefix) || !normalized.endsWith(".ts")) return null;
477
+ const transformed = injectCallSiteIds(code, normalized);
478
+ return transformed === code ? null : {
479
+ code: transformed,
480
+ map: null
481
+ };
482
+ }
483
+ };
484
+ }
485
+ const TEST_FILE = /\.(test|int\.test|spec)\.ts$/;
486
+ function toPosix$4(path) {
487
+ return path.split(sep).join("/");
488
+ }
489
+ function collectTsFiles(dir, out) {
490
+ let entries;
491
+ try {
492
+ entries = readdirSync(dir);
493
+ } catch {
494
+ return;
495
+ }
496
+ for (const entry of entries) {
497
+ if (entry === "node_modules" || entry.startsWith(".")) continue;
498
+ const full = join(dir, entry);
499
+ if (statSync(full).isDirectory()) {
500
+ collectTsFiles(full, out);
501
+ continue;
502
+ }
503
+ if (entry.endsWith(".ts") && !TEST_FILE.test(entry)) out.push(full);
504
+ }
505
+ }
506
+ /**
507
+ * Run the workflow-canvas reliability checks over every `src/**` module. Errors
508
+ * (steps outside a workflow, steps nested as call arguments) block the build;
509
+ * warnings (opaque code-blocks, dropped spread inputs) explain each degraded
510
+ * construct. Best-effort per-file: an unparseable file is skipped, never fatal.
511
+ */
512
+ function collectWorkflowDiagnostics(root, srcDir = "src") {
513
+ const srcRoot = join(root, srcDir);
514
+ if (!existsSync(srcRoot)) return [];
515
+ const files = [];
516
+ collectTsFiles(srcRoot, files);
517
+ const diagnostics = [];
518
+ for (const file of files) {
519
+ const rel = toPosix$4(relative(root, file));
520
+ try {
521
+ const source = readFileSync(file, "utf8");
522
+ diagnostics.push(...diagnoseWorkflowSource(source, rel));
523
+ } catch {}
524
+ }
525
+ return diagnostics;
526
+ }
527
+ function formatDiagnostic(diagnostic) {
528
+ return ` ${diagnostic.line !== void 0 ? `${diagnostic.fileName}:${diagnostic.line}:${diagnostic.column ?? 1}` : diagnostic.fileName}\n ${diagnostic.message}`;
529
+ }
530
+ /** Throw when any blocking (error-severity) diagnostic is found. */
531
+ function assertWorkflowDiagnosticErrorsFrom(diagnostics) {
532
+ const errors = diagnostics.filter((d) => d.severity === "error");
533
+ if (errors.length > 0) throw new Error(`Workflow canvas: ${errors.length} unsupported construct(s) must be fixed before deploy:\n${errors.map(formatDiagnostic).join("\n")}\n`);
534
+ }
535
+ /** Print soft (warning-severity) diagnostics after a successful build. */
536
+ function warnWorkflowDiagnosticsFrom(diagnostics) {
537
+ const warnings = diagnostics.filter((d) => d.severity === "warning");
538
+ if (warnings.length > 0) console.warn(`\n⚠ Workflow canvas: ${warnings.length} construct(s) will render as a degraded (opaque) canvas:\n${warnings.map(formatDiagnostic).join("\n")}\n`);
539
+ }
540
+ const CACHE_DIR = ".keystroke/cache";
541
+ const CACHE_KEY_FILE = "route-manifest.key";
542
+ const CACHE_MANIFEST_DIR = "manifest";
543
+ function cachePaths(projectRoot) {
544
+ const dir = join(projectRoot, CACHE_DIR);
545
+ return {
546
+ keyPath: join(dir, CACHE_KEY_FILE),
547
+ manifestDir: join(dir, CACHE_MANIFEST_DIR)
548
+ };
549
+ }
550
+ /** Fingerprint of integration package versions resolved from the project. */
551
+ function integrationPackagesFingerprint(projectRoot) {
552
+ const hash = createHash("sha256");
553
+ const packageJsonPath = join(projectRoot, "package.json");
554
+ if (!existsSync(packageJsonPath)) return hash.digest("hex");
555
+ const raw = readFileSync(packageJsonPath, "utf8");
556
+ hash.update(raw);
557
+ let dependencies = {};
558
+ try {
559
+ dependencies = JSON.parse(raw).dependencies ?? {};
560
+ } catch {
561
+ return hash.digest("hex");
562
+ }
563
+ const require = createRequire(packageJsonPath);
564
+ for (const name of Object.keys(dependencies).sort()) {
565
+ if (!name.startsWith("@keystrokehq/")) continue;
566
+ try {
567
+ const resolved = require.resolve(`${name}/package.json`);
568
+ hash.update(name);
569
+ hash.update("\0");
570
+ hash.update(readFileSync(resolved, "utf8"));
571
+ hash.update("\0");
572
+ } catch {
573
+ hash.update(name);
574
+ hash.update("\0missing\0");
575
+ }
576
+ }
577
+ return hash.digest("hex");
578
+ }
579
+ /**
580
+ * Content-addressed key for the deploy route-manifest. Invalidates when project
581
+ * sources, build entries, ignore set, phase, or integration package versions change.
582
+ */
583
+ function computeRouteManifestCacheKey(input) {
584
+ const hash = createHash("sha256");
585
+ hash.update(input.phase);
586
+ hash.update("\0");
587
+ hash.update(input.integrationFingerprint);
588
+ hash.update("\0");
589
+ for (const key of [...input.buildEntryKeys].sort()) {
590
+ hash.update(key);
591
+ hash.update("\0");
592
+ }
593
+ for (const file of [...input.ignoredFiles].sort()) {
594
+ hash.update(file);
595
+ hash.update("\0");
596
+ }
597
+ for (const file of [...input.sourceFiles].sort((a, b) => a.path.localeCompare(b.path))) {
598
+ hash.update(file.path);
599
+ hash.update("\0");
600
+ hash.update(file.hash);
601
+ hash.update("\0");
602
+ }
603
+ return hash.digest("hex");
604
+ }
605
+ /** True when `.keystroke/cache/route-manifest.key` matches `cacheKey`. */
606
+ function isRouteManifestCacheHit(projectRoot, cacheKey) {
607
+ const { keyPath, manifestDir } = cachePaths(projectRoot);
608
+ if (!existsSync(keyPath) || !existsSync(join(manifestDir, "manifest.json"))) return false;
609
+ return readFileSync(keyPath, "utf8").trim() === cacheKey;
610
+ }
611
+ /** Restore cached modular manifest into `dist/.keystroke/` when the key matches. */
612
+ function tryRestoreCachedRouteManifest(projectRoot, cacheKey) {
613
+ if (!isRouteManifestCacheHit(projectRoot, cacheKey)) return false;
614
+ const { manifestDir } = cachePaths(projectRoot);
615
+ const dest = join(projectRoot, "dist", ".keystroke");
616
+ mkdirSync(dest, { recursive: true });
617
+ for (const name of [
618
+ "manifest.json",
619
+ "modules",
620
+ "catalogs",
621
+ "assets",
622
+ "build-index.json"
623
+ ]) {
624
+ const from = join(manifestDir, name);
625
+ if (!existsSync(from)) continue;
626
+ cpSync(from, join(dest, name), { recursive: true });
627
+ }
628
+ const assetsModule = join(manifestDir, "assets.mjs");
629
+ if (existsSync(assetsModule)) cpSync(assetsModule, join(dest, "assets.mjs"));
630
+ return existsSync(join(projectRoot, PROJECT_MANIFEST_REL_PATH));
631
+ }
632
+ /** Persist the just-emitted modular manifest into the deploy cache. */
633
+ function storeCachedRouteManifest(projectRoot, cacheKey) {
634
+ const sourceMeta = join(projectRoot, "dist", ".keystroke");
635
+ if (!existsSync(join(sourceMeta, "manifest.json"))) return;
636
+ const { keyPath, manifestDir } = cachePaths(projectRoot);
637
+ rmSync(manifestDir, {
638
+ recursive: true,
639
+ force: true
640
+ });
641
+ mkdirSync(manifestDir, { recursive: true });
642
+ for (const name of [
643
+ "manifest.json",
644
+ "modules",
645
+ "catalogs",
646
+ "assets",
647
+ "assets.mjs",
648
+ "build-index.json"
649
+ ]) {
650
+ const from = join(sourceMeta, name);
651
+ if (!existsSync(from)) continue;
652
+ cpSync(from, join(manifestDir, name), { recursive: true });
653
+ }
654
+ mkdirSync(dirname(keyPath), { recursive: true });
655
+ writeFileSync(keyPath, `${cacheKey}\n`);
656
+ }
657
+ /**
658
+ * True when a prior deploy `dist/` still has the compiled outputs for every
659
+ * build entry (so we can skip tsdown when the content-hash cache hits).
660
+ */
661
+ function distDeployOutputsPresent(projectRoot, buildEntries) {
662
+ const distRoot = join(projectRoot, "dist");
663
+ if (!existsSync(distRoot)) return false;
664
+ for (const entryKey of Object.keys(buildEntries)) if (!existsSync(join(distRoot, entryKey === "config" ? "config.mjs" : `${entryKey}.mjs`))) return false;
665
+ if (!existsSync(join(distRoot, ".keystroke", "assets.mjs"))) return false;
666
+ return true;
667
+ }
668
+ const SKIP_DIRS = new Set([".git", "node_modules"]);
669
+ /** Content hash of every file under a skill/files pack directory. */
670
+ function hashAssetPackDir(dirPath) {
671
+ const hash = createHash("sha256");
672
+ const walk = (current) => {
673
+ for (const name of readdirSync(current).sort()) {
674
+ if (SKIP_DIRS.has(name)) continue;
675
+ const abs = join(current, name);
676
+ const st = statSync(abs);
677
+ if (st.isDirectory()) {
678
+ walk(abs);
679
+ continue;
680
+ }
681
+ if (!st.isFile()) continue;
682
+ hash.update(relative(dirPath, abs).replace(/\\/g, "/"));
683
+ hash.update("\0");
684
+ hash.update(readFileSync(abs));
685
+ hash.update("\0");
686
+ }
687
+ };
688
+ if (!statSync(dirPath, { throwIfNoEntry: false })?.isDirectory()) return hash.digest("hex");
689
+ walk(dirPath);
690
+ return hash.digest("hex");
691
+ }
692
+ function listPackIds(rootPath) {
693
+ if (!statSync(rootPath, { throwIfNoEntry: false })?.isDirectory()) return [];
694
+ return readdirSync(rootPath).filter((name) => !SKIP_DIRS.has(name)).filter((name) => statSync(join(rootPath, name)).isDirectory()).sort();
695
+ }
696
+ function shardRelPath(kind, id) {
697
+ return `${kind}/${id}.json`;
698
+ }
699
+ function readIndex(assetsRoot) {
700
+ const path = join(assetsRoot, "index.json");
701
+ if (!existsSync(path)) return;
702
+ try {
703
+ return JSON.parse(readFileSync(path, "utf8"));
704
+ } catch {
705
+ return;
706
+ }
707
+ }
708
+ function loadShard(assetsRoot, rel) {
709
+ const abs = join(assetsRoot, rel);
710
+ if (!existsSync(abs)) return;
711
+ try {
712
+ return JSON.parse(readFileSync(abs, "utf8"));
713
+ } catch {
714
+ return;
715
+ }
716
+ }
717
+ function renderAssetModule$3(manifest) {
718
+ return `export default ${JSON.stringify(manifest)};\n`;
719
+ }
720
+ function packKind(input) {
721
+ const kindRoot = join(input.projectRoot, input.srcDir, input.kind);
722
+ const prevById = new Map((input.kind === "skills" ? input.previous?.skills : input.previous?.files)?.map((ref) => [ref.id, ref]) ?? []);
723
+ const packs = {};
724
+ const refs = [];
725
+ const wrote = [];
726
+ const skipped = [];
727
+ for (const id of listPackIds(kindRoot)) {
728
+ const packDir = join(kindRoot, id);
729
+ const contentHash = hashAssetPackDir(packDir);
730
+ const path = shardRelPath(input.kind, id);
731
+ const existing = prevById.get(id)?.contentHash === contentHash ? loadShard(input.assetsRoot, path) : void 0;
732
+ let packed;
733
+ if (existing) {
734
+ packed = existing;
735
+ skipped.push(path);
736
+ } else {
737
+ packed = packDirFromDisk(packDir);
738
+ const abs = join(input.assetsRoot, path);
739
+ mkdirSync(dirname(abs), { recursive: true });
740
+ writeFileSync(abs, `${JSON.stringify(packed)}\n`);
741
+ wrote.push(path);
742
+ }
743
+ packs[id] = packed;
744
+ refs.push({
745
+ id,
746
+ path,
747
+ contentHash
748
+ });
749
+ }
750
+ return {
751
+ packs,
752
+ refs,
753
+ wrote,
754
+ skipped
755
+ };
756
+ }
757
+ function removeOrphanShards(assetsRoot, kind, keep) {
758
+ const kindDir = join(assetsRoot, kind);
759
+ if (!existsSync(kindDir)) return;
760
+ for (const name of readdirSync(kindDir)) {
761
+ if (!name.endsWith(".json")) continue;
762
+ const rel = `${kind}/${name}`;
763
+ if (!keep.has(rel)) rmSync(join(kindDir, name), { force: true });
764
+ }
765
+ }
766
+ /**
767
+ * Pack `src/skills` + `src/files` into per-pack shards with content-hash skip.
768
+ * Composes `dist/.keystroke/assets.mjs` only when at least one shard changed
769
+ * (or the composed module is missing) so the runtime loader stays unchanged.
770
+ */
771
+ function packModularProjectAssets(input) {
772
+ const srcDir = input.srcDir ?? "src";
773
+ const outDir = input.outDir ?? "dist";
774
+ const keystrokeDir = join(input.projectRoot, outDir, ".keystroke");
775
+ const assetsRoot = join(keystrokeDir, "assets");
776
+ mkdirSync(assetsRoot, { recursive: true });
777
+ const previous = readIndex(assetsRoot);
778
+ const skills = packKind({
779
+ projectRoot: input.projectRoot,
780
+ srcDir,
781
+ kind: "skills",
782
+ assetsRoot,
783
+ previous
784
+ });
785
+ const files = packKind({
786
+ projectRoot: input.projectRoot,
787
+ srcDir,
788
+ kind: "files",
789
+ assetsRoot,
790
+ previous
791
+ });
792
+ removeOrphanShards(assetsRoot, "skills", new Set(skills.refs.map((ref) => ref.path)));
793
+ removeOrphanShards(assetsRoot, "files", new Set(files.refs.map((ref) => ref.path)));
794
+ const index = {
795
+ version: 1,
796
+ skills: skills.refs,
797
+ files: files.refs
798
+ };
799
+ writeFileSync(join(assetsRoot, "index.json"), `${JSON.stringify(index)}\n`);
800
+ const manifest = {
801
+ skills: skills.packs,
802
+ files: files.packs
803
+ };
804
+ const assetsModulePath = join(keystrokeDir, "assets.mjs");
805
+ const wroteShards = [...skills.wrote, ...files.wrote];
806
+ const skippedShards = [...skills.skipped, ...files.skipped];
807
+ const prevSkillIds = (previous?.skills ?? []).map((r) => r.id).join("\0");
808
+ const nextSkillIds = skills.refs.map((r) => r.id).join("\0");
809
+ const prevFileIds = (previous?.files ?? []).map((r) => r.id).join("\0");
810
+ const nextFileIds = files.refs.map((r) => r.id).join("\0");
811
+ const membershipChanged = prevSkillIds !== nextSkillIds || prevFileIds !== nextFileIds;
812
+ const anyDirty = wroteShards.length > 0 || !existsSync(assetsModulePath) || membershipChanged;
813
+ let wroteAssetsModule = false;
814
+ if (anyDirty) {
815
+ writeFileSync(assetsModulePath, renderAssetModule$3(manifest));
816
+ wroteAssetsModule = true;
817
+ }
818
+ return {
819
+ manifest,
820
+ index,
821
+ wroteShards,
822
+ skippedShards,
823
+ wroteAssetsModule
824
+ };
825
+ }
826
+ /** Relative path under project root. */
827
+ const BUILD_INDEX_REL_PATH = "dist/.keystroke/build-index.json";
828
+ function toPosix$3(path) {
829
+ return path.replace(/\\/g, "/");
830
+ }
831
+ function sha256Bytes(data) {
832
+ return createHash("sha256").update(data).digest("hex");
833
+ }
834
+ function compactJson(value) {
835
+ return `${JSON.stringify(value)}\n`;
836
+ }
837
+ /** sha256 over sorted (path, file bytes) for project-relative inputs. */
838
+ function hashSourceInputs(projectRoot, inputs) {
839
+ const hash = createHash("sha256");
840
+ for (const rel of [...inputs].sort()) {
841
+ hash.update(rel);
842
+ hash.update("\0");
843
+ const abs = join(projectRoot, rel);
844
+ if (existsSync(abs) && statSync(abs).isFile()) hash.update(readFileSync(abs));
845
+ else hash.update("missing");
846
+ hash.update("\0");
847
+ }
848
+ return hash.digest("hex");
849
+ }
850
+ /** Fingerprint bundled package.json files (version bumps dirty consumers). */
851
+ function hashBundledPackages(projectRoot, packages) {
852
+ const hash = createHash("sha256");
853
+ const packageJsonPath = join(projectRoot, "package.json");
854
+ if (!existsSync(packageJsonPath)) return hash.digest("hex");
855
+ const require = createRequire(packageJsonPath);
856
+ for (const name of [...packages].sort()) {
857
+ hash.update(name);
858
+ hash.update("\0");
859
+ try {
860
+ const resolved = require.resolve(`${name}/package.json`);
861
+ hash.update(readFileSync(resolved, "utf8"));
862
+ } catch {
863
+ hash.update("missing");
864
+ }
865
+ hash.update("\0");
866
+ }
867
+ return hash.digest("hex");
868
+ }
869
+ function buildIndexPath(projectRoot) {
870
+ return join(projectRoot, BUILD_INDEX_REL_PATH);
871
+ }
872
+ function tryReadBuildIndex(projectRoot) {
873
+ const path = buildIndexPath(projectRoot);
874
+ if (!existsSync(path)) return;
875
+ try {
876
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
877
+ if (parsed.version !== 1 || typeof parsed.entries !== "object") return;
878
+ return parsed;
879
+ } catch {
880
+ return;
881
+ }
882
+ }
883
+ function writeBuildIndex(projectRoot, index) {
884
+ const path = buildIndexPath(projectRoot);
885
+ mkdirSync(dirname(path), { recursive: true });
886
+ writeFileSync(path, compactJson(index));
887
+ }
888
+ /**
889
+ * Compare on-disk build-index to current sources / bundled package fingerprints.
890
+ * Does not run the bundler.
891
+ */
892
+ function listDirtyEntries(projectRoot, currentEntryKeys) {
893
+ const index = tryReadBuildIndex(projectRoot);
894
+ const expected = [...currentEntryKeys].filter((key) => key !== "config").sort();
895
+ if (!index) return {
896
+ dirty: expected,
897
+ forceFull: true,
898
+ reason: "missing build-index"
899
+ };
900
+ const indexed = Object.keys(index.entries).sort();
901
+ if (indexed.length !== expected.length || indexed.some((key, i) => key !== expected[i])) return {
902
+ dirty: expected,
903
+ forceFull: true,
904
+ reason: "entry membership changed"
905
+ };
906
+ const dirty = [];
907
+ for (const key of expected) {
908
+ const entry = index.entries[key];
909
+ if (!existsSync(join(projectRoot, "dist", entry.artifactPath))) {
910
+ dirty.push(key);
911
+ continue;
912
+ }
913
+ if (hashSourceInputs(projectRoot, entry.inputs) !== entry.sourceHash) {
914
+ dirty.push(key);
915
+ continue;
916
+ }
917
+ if (hashBundledPackages(projectRoot, entry.packages) !== entry.packagesHash) dirty.push(key);
918
+ }
919
+ return {
920
+ dirty,
921
+ forceFull: false
922
+ };
923
+ }
924
+ /** Default manifest shard paths for an entry key (best-effort). */
925
+ function defaultManifestPathsForEntry(entryKey) {
926
+ const [kind, ...rest] = entryKey.split("/");
927
+ const id = rest.join("/");
928
+ if (!kind || !id) return [];
929
+ if (kind === "agents") return [`modules/agents/${id}.json`];
930
+ if (kind === "workflows") return [`modules/workflows/${id}.json`, `modules/workflows/${id}.flow.json`];
931
+ if (kind === "triggers") return [`modules/triggers/${id}.json`];
932
+ if (kind === "actions") return ["catalogs/actions.json"];
933
+ return [];
934
+ }
935
+ /** Build a BuildIndexEntry from closure facts + emitted artifact bytes. */
936
+ function makeBuildIndexEntry(input) {
937
+ return {
938
+ sourceHash: hashSourceInputs(input.projectRoot, input.inputs),
939
+ artifactHash: sha256Bytes(input.artifactBytes),
940
+ artifactPath: toPosix$3(input.artifactPath),
941
+ inputs: [...input.inputs].sort(),
942
+ packages: [...input.packages].sort(),
943
+ packagesHash: hashBundledPackages(input.projectRoot, input.packages),
944
+ manifestPaths: defaultManifestPathsForEntry(input.entryKey)
945
+ };
946
+ }
947
+ function toPosix$2(path) {
948
+ return path.split(sep).join("/");
949
+ }
950
+ function projectRelativeModuleId$1(root, id) {
951
+ if (id.startsWith("\0") || id.includes("\0") || id.startsWith("node:")) return null;
952
+ let absolute = id;
953
+ if (id.startsWith("file://")) absolute = fileURLToPath(id);
954
+ if (!isAbsolute(absolute) && !absolute.startsWith(".")) return null;
955
+ const normalizedRoot = normalizeBuildFilePath(root);
956
+ let normalizedAbsolute;
957
+ try {
958
+ normalizedAbsolute = normalizeBuildFilePath(absolute);
959
+ } catch {
960
+ return null;
961
+ }
962
+ const relativePath = toPosix$2(relative(normalizedRoot, normalizedAbsolute));
963
+ if (!relativePath || relativePath.startsWith("..") || relativePath.includes("node_modules/") || relativePath.startsWith("node_modules/")) return null;
964
+ return relativePath;
965
+ }
966
+ function packageNameFromModuleId$1(id) {
967
+ if (id.startsWith("\0") || id.includes("\0") || id.startsWith("node:")) return null;
968
+ let absolute = id;
969
+ try {
970
+ if (id.startsWith("file://")) absolute = fileURLToPath(id);
971
+ } catch {
972
+ return null;
973
+ }
974
+ const normalized = absolute.replace(/\\/g, "/");
975
+ const index = normalized.lastIndexOf("/node_modules/");
976
+ if (index < 0) return null;
977
+ const rest = normalized.slice(index + 14);
978
+ if (!rest || rest.startsWith(".")) return null;
979
+ if (rest.startsWith("@")) {
980
+ const parts = rest.split("/");
981
+ if (parts.length < 2 || !parts[0] || !parts[1]) return null;
982
+ return `${parts[0]}/${parts[1]}`;
983
+ }
984
+ return rest.split("/")[0] || null;
985
+ }
986
+ function isFrameworkExternalPackage(name) {
987
+ if (!name.startsWith("@keystrokehq/")) return false;
988
+ const pkg = name.slice(13).split("/")[0] ?? "";
989
+ return RUNTIME_KEYSTROKE_PACKAGES.has(pkg);
990
+ }
991
+ /**
992
+ * Collect per-entry source inputs + bundled packages from the emit graph.
993
+ * Used to write `build-index.json` after tsdown.
994
+ */
995
+ function entryClosurePlugin(options) {
996
+ const root = normalizeBuildFilePath(options.root);
997
+ return {
998
+ name: "keystroke-entry-closure",
999
+ generateBundle(_outputOptions, bundle) {
1000
+ const closures = /* @__PURE__ */ new Map();
1001
+ for (const output of Object.values(bundle)) {
1002
+ if (output.type !== "chunk" || !output.isEntry) continue;
1003
+ const entryKey = output.name.replace(/\\/g, "/");
1004
+ if (entryKey === "config" || entryKey.includes("\0")) continue;
1005
+ if (!entryKey.startsWith("agents/") && !entryKey.startsWith("actions/") && !entryKey.startsWith("workflows/") && !entryKey.startsWith("triggers/")) continue;
1006
+ const inputs = /* @__PURE__ */ new Set();
1007
+ const packages = /* @__PURE__ */ new Set();
1008
+ const moduleIds = "moduleIds" in output && Array.isArray(output.moduleIds) ? output.moduleIds : Object.keys(output.modules ?? {});
1009
+ for (const moduleId of moduleIds) {
1010
+ const rel = projectRelativeModuleId$1(root, moduleId);
1011
+ if (rel) inputs.add(rel);
1012
+ const pkg = packageNameFromModuleId$1(moduleId);
1013
+ if (pkg && !isFrameworkExternalPackage(pkg) && pkg !== "zod") packages.add(pkg);
1014
+ }
1015
+ if (output.facadeModuleId) {
1016
+ const entryRel = projectRelativeModuleId$1(root, output.facadeModuleId);
1017
+ if (entryRel) inputs.add(entryRel);
1018
+ }
1019
+ closures.set(entryKey, {
1020
+ inputs: [...inputs].sort(),
1021
+ packages: [...packages].sort()
1022
+ });
1023
+ }
1024
+ options.onClosures(closures);
1025
+ }
1026
+ };
1027
+ }
1028
+ const ASSETS_MODULE$2 = "@keystrokehq/assets";
1029
+ const VIRTUAL_PREFIX$1 = `\0${ASSETS_MODULE$2}:`;
1030
+ function renderAssetModule$2(manifest) {
1031
+ return `export default ${JSON.stringify(manifest)};\n`;
1032
+ }
1033
+ /** Resolve `@keystrokehq/assets` without re-packing on every entry. */
1034
+ function agentAssetsResolvePlugin(manifest) {
1035
+ return {
1036
+ name: "keystroke-assets-resolve",
1037
+ resolveId(source) {
1038
+ if (source !== ASSETS_MODULE$2) return null;
1039
+ return `${VIRTUAL_PREFIX$1}manifest`;
1040
+ },
1041
+ load(id) {
1042
+ if (id !== `${VIRTUAL_PREFIX$1}manifest`) return null;
1043
+ return renderAssetModule$2(manifest);
1044
+ }
1045
+ };
1046
+ }
1047
+ /**
1048
+ * Build each entry in isolation so local imports are inlined (self-contained
1049
+ * `.mjs`) and closures include transitive project sources — same contract as
1050
+ * `buildFilteredApp`.
1051
+ */
1052
+ async function buildSelfContainedEntries(options) {
1053
+ const root = options.root;
1054
+ const srcDir = options.srcDir ?? "src";
1055
+ const outDir = options.outDir ?? "dist";
1056
+ const phase = options.phase ?? "build";
1057
+ const distRoot = join(root, outDir);
1058
+ const clean = options.clean ?? true;
1059
+ const allEntries = {
1060
+ ...options.configEntry ? { config: options.configEntry } : {},
1061
+ ...options.buildEntries
1062
+ };
1063
+ const entryKeys = Object.keys(allEntries).sort();
1064
+ if (entryKeys.length === 0) throw new Error("Nothing to build — add keystroke.config.ts or modules under src/");
1065
+ const dirtySet = new Set(options.dirtyKeys && options.dirtyKeys.length > 0 ? options.dirtyKeys : entryKeys.filter((key) => key !== "config").concat(options.configEntry ? ["config"] : []));
1066
+ if (options.configEntry && (clean || dirtySet.size > 0)) dirtySet.add("config");
1067
+ if (clean && existsSync(distRoot)) rmSync(distRoot, {
1068
+ recursive: true,
1069
+ force: true
1070
+ });
1071
+ const packed = packModularProjectAssets({
1072
+ projectRoot: root,
1073
+ srcDir,
1074
+ outDir
1075
+ });
1076
+ const closures = /* @__PURE__ */ new Map();
1077
+ const previous = tryReadBuildIndex(root);
1078
+ for (const entryKey of [...dirtySet].sort()) {
1079
+ const entryPath = allEntries[entryKey];
1080
+ if (!entryPath) continue;
1081
+ const plugins = [
1082
+ keystrokeIgnoreGuardPlugin({
1083
+ root,
1084
+ ignoredFiles: options.ignoredFiles
1085
+ }),
1086
+ agentAssetsResolvePlugin(packed.manifest),
1087
+ entryClosurePlugin({
1088
+ root,
1089
+ onClosures: (next) => {
1090
+ for (const [key, value] of next) closures.set(key, value);
1091
+ }
1092
+ })
1093
+ ];
1094
+ if (entryKey.startsWith("workflows/")) plugins.splice(1, 0, callSiteIdInjectionPlugin({
1095
+ root,
1096
+ srcDir
1097
+ }));
1098
+ await build(mergeConfig(baseTsdownConfig, {
1099
+ entry: { [entryKey]: entryPath },
1100
+ format: ["esm"],
1101
+ outDir: distRoot,
1102
+ clean: false,
1103
+ dts: false,
1104
+ sourcemap: phase === "deploy" ? false : true,
1105
+ ...phase === "deploy" ? { logLevel: "error" } : {},
1106
+ loader: { ".md": "text" },
1107
+ deps: userAppBuildDepsConfig(),
1108
+ plugins
1109
+ }));
1110
+ }
1111
+ const entries = {};
1112
+ for (const key of Object.keys(options.buildEntries).sort()) {
1113
+ if (closures.has(key)) {
1114
+ const closure = closures.get(key);
1115
+ const artifactPath = `${key}.mjs`;
1116
+ const abs = join(distRoot, artifactPath);
1117
+ if (!existsSync(abs)) continue;
1118
+ entries[key] = makeBuildIndexEntry({
1119
+ projectRoot: root,
1120
+ entryKey: key,
1121
+ inputs: closure.inputs,
1122
+ packages: closure.packages,
1123
+ artifactPath,
1124
+ artifactBytes: readFileSync(abs)
1125
+ });
1126
+ continue;
1127
+ }
1128
+ if (previous?.entries[key]) entries[key] = previous.entries[key];
1129
+ }
1130
+ const index = {
1131
+ version: 1,
1132
+ integrationFingerprint: integrationPackagesFingerprint(root),
1133
+ entries
1134
+ };
1135
+ writeBuildIndex(root, index);
1136
+ return {
1137
+ closures,
1138
+ index
1139
+ };
1140
+ }
1141
+ /** Analyzer stdout / plan digest contract version for Modal Precise Deploy. */
1142
+ const ANALYZER_CONTRACT_VERSION = "safe-filtered-deploy-v3";
1143
+ const PACKAGE_MANIFEST_FILES = new Set(["package.json"]);
1144
+ const LOCKFILE_NAMES = new Set([
1145
+ "package-lock.json",
1146
+ "pnpm-lock.yaml",
1147
+ "yarn.lock",
1148
+ "bun.lock",
1149
+ "bun.lockb",
1150
+ "npm-shrinkwrap.json"
1151
+ ]);
1152
+ function toPosix(path) {
1153
+ return path.split(sep).join("/");
1154
+ }
1155
+ function requireFull(code, reason) {
1156
+ return {
1157
+ requireFull: true,
1158
+ code,
1159
+ reason
1160
+ };
1161
+ }
1162
+ function isDeployableResourceKey(key) {
1163
+ return key.startsWith("agents/") || key.startsWith("workflows/");
1164
+ }
1165
+ function kindFromResourceKey(key) {
1166
+ if (key.startsWith("agents/")) return "agent";
1167
+ if (key.startsWith("workflows/")) return "workflow";
1168
+ return null;
1169
+ }
1170
+ /** Normalize caller paths to project-relative posix form. */
1171
+ function normalizeProjectRelativePath(root, path) {
1172
+ const withoutDot = path.trim().replace(/\\/g, "/").replace(/^\.\//, "");
1173
+ const absolute = isAbsolute(withoutDot) ? withoutDot : join(normalizeBuildFilePath(root), withoutDot);
1174
+ const relativePath = toPosix(relative(normalizeBuildFilePath(root), normalizeBuildFilePath(absolute)));
1175
+ if (!relativePath || relativePath === "." || relativePath.startsWith("..")) throw new Error(`Path "${path}" is outside project root`);
1176
+ return relativePath;
1177
+ }
1178
+ function basenamePosix(path) {
1179
+ const parts = path.split("/");
1180
+ return parts[parts.length - 1] ?? path;
1181
+ }
1182
+ function isPackageManifestPath(path) {
1183
+ return PACKAGE_MANIFEST_FILES.has(basenamePosix(path));
1184
+ }
1185
+ function isLockfilePath(path) {
1186
+ return LOCKFILE_NAMES.has(basenamePosix(path));
1187
+ }
1188
+ function normalizeChanges(root, changedPaths) {
1189
+ const byPath = /* @__PURE__ */ new Map();
1190
+ for (const change of changedPaths) {
1191
+ const raw = typeof change === "string" ? {
1192
+ path: change,
1193
+ kind: "modified"
1194
+ } : change;
1195
+ let path;
1196
+ try {
1197
+ path = normalizeProjectRelativePath(root, raw.path);
1198
+ } catch {
1199
+ return requireFull("unproven_safe", `Changed path "${raw.path}" cannot be normalized to a project-relative source path`);
1200
+ }
1201
+ let previousPath;
1202
+ if (raw.previousPath) try {
1203
+ previousPath = normalizeProjectRelativePath(root, raw.previousPath);
1204
+ } catch {
1205
+ return requireFull("unproven_safe", `Rename previous path "${raw.previousPath}" cannot be normalized`);
1206
+ }
1207
+ const normalized = {
1208
+ path,
1209
+ kind: raw.kind,
1210
+ ...previousPath ? { previousPath } : {}
1211
+ };
1212
+ const existing = byPath.get(path);
1213
+ if (existing && existing.kind !== normalized.kind) return requireFull("ambiguous_ownership", `Changed path "${path}" has ambiguous change kinds (${existing.kind} vs ${normalized.kind})`);
1214
+ byPath.set(path, normalized);
1215
+ }
1216
+ return [...byPath.values()];
1217
+ }
1218
+ function projectRelativeModuleId(root, id) {
1219
+ if (id.startsWith("\0") || id.includes("\0") || id.startsWith("node:")) return null;
1220
+ let absolute = id;
1221
+ if (id.startsWith("file://")) absolute = fileURLToPath(id);
1222
+ if (!isAbsolute(absolute) && !absolute.startsWith(".")) return null;
1223
+ const normalizedRoot = normalizeBuildFilePath(root);
1224
+ let normalizedAbsolute;
1225
+ try {
1226
+ normalizedAbsolute = normalizeBuildFilePath(absolute);
1227
+ } catch {
1228
+ return null;
1229
+ }
1230
+ if (!normalizedAbsolute.startsWith(normalizedRoot + sep) && normalizedAbsolute !== normalizedRoot) {
1231
+ const rel = toPosix(relative(normalizedRoot, normalizedAbsolute));
1232
+ if (!rel || rel.startsWith("..") || rel.includes("node_modules/")) return null;
1233
+ }
1234
+ const relativePath = toPosix(relative(normalizedRoot, normalizedAbsolute));
1235
+ if (!relativePath || relativePath.startsWith("..") || relativePath.includes("node_modules/") || relativePath.startsWith("node_modules/")) return null;
1236
+ return relativePath;
1237
+ }
1238
+ /** Extract a package name from a resolved module id under node_modules. */
1239
+ function packageNameFromModuleId(id) {
1240
+ if (id.startsWith("\0") || id.includes("\0") || id.startsWith("node:")) return null;
1241
+ let absolute = id;
1242
+ try {
1243
+ if (id.startsWith("file://")) absolute = fileURLToPath(id);
1244
+ } catch {
1245
+ return null;
1246
+ }
1247
+ const normalized = absolute.replace(/\\/g, "/");
1248
+ const index = normalized.lastIndexOf("/node_modules/");
1249
+ if (index < 0) return null;
1250
+ const rest = normalized.slice(index + 14);
1251
+ if (!rest || rest.startsWith(".")) return null;
1252
+ if (rest.startsWith("@")) {
1253
+ const parts = rest.split("/");
1254
+ if (parts.length < 2 || !parts[0] || !parts[1]) return null;
1255
+ return `${parts[0]}/${parts[1]}`;
1256
+ }
1257
+ return rest.split("/")[0] || null;
1258
+ }
1259
+ function isRuntimeExternalPackage(name) {
1260
+ if (!name.startsWith("@keystrokehq/")) return false;
1261
+ const pkg = name.slice(13).split("/")[0] ?? "";
1262
+ return RUNTIME_KEYSTROKE_PACKAGES.has(pkg);
1263
+ }
1264
+ function readDependencyMap(packageJsonContents) {
1265
+ try {
1266
+ const parsed = JSON.parse(packageJsonContents);
1267
+ const map = /* @__PURE__ */ new Map();
1268
+ for (const field of [
1269
+ "dependencies",
1270
+ "devDependencies",
1271
+ "optionalDependencies",
1272
+ "peerDependencies"
1273
+ ]) {
1274
+ const value = parsed[field];
1275
+ if (!value || typeof value !== "object" || Array.isArray(value)) continue;
1276
+ for (const [name, version] of Object.entries(value)) if (typeof version === "string") map.set(name, version);
1277
+ }
1278
+ return map;
1279
+ } catch {
1280
+ return null;
1281
+ }
1282
+ }
1283
+ function changedDependencyNames(base, draft) {
1284
+ const names = new Set([...base.keys(), ...draft.keys()]);
1285
+ const changed = [];
1286
+ for (const name of names) if ((base.get(name) ?? null) !== (draft.get(name) ?? null)) changed.push(name);
1287
+ return changed.sort();
1288
+ }
1289
+ function collectModuleGraphPlugin(graph) {
1290
+ return {
1291
+ name: "keystroke-collect-module-graph",
1292
+ async resolveId(source, importer, resolveOptions) {
1293
+ if (!importer || resolveOptions?.isEntry) return null;
1294
+ if (!await this.resolve(source, importer, {
1295
+ ...resolveOptions,
1296
+ skipSelf: true
1297
+ })) {
1298
+ const existing = graph.unresolvedByImporter.get(importer) ?? [];
1299
+ existing.push(source);
1300
+ graph.unresolvedByImporter.set(importer, existing);
1301
+ }
1302
+ return null;
1303
+ },
1304
+ buildEnd() {
1305
+ for (const id of this.getModuleIds()) {
1306
+ const info = this.getModuleInfo(id);
1307
+ if (!info) continue;
1308
+ graph.byId.set(id, {
1309
+ importedIds: [...info.importedIds],
1310
+ dynamicallyImportedIds: [...info.dynamicallyImportedIds]
1311
+ });
1312
+ }
1313
+ }
1314
+ };
1315
+ }
1316
+ function closureFromGraph(root, resourceKey, entryAbsolute, graph) {
1317
+ const kind = kindFromResourceKey(resourceKey);
1318
+ if (!kind) throw new Error(`Not a deployable workflow/agent key: ${resourceKey}`);
1319
+ const entryNormalized = normalizeBuildFilePath(entryAbsolute);
1320
+ const queue = [];
1321
+ for (const id of graph.byId.keys()) try {
1322
+ if (normalizeBuildFilePath(id.startsWith("file://") ? fileURLToPath(id) : id) === entryNormalized) {
1323
+ queue.push(id);
1324
+ break;
1325
+ }
1326
+ } catch {}
1327
+ if (queue.length === 0) {
1328
+ const entryRel = toPosix(relative(normalizeBuildFilePath(root), entryNormalized));
1329
+ for (const id of graph.byId.keys()) if (projectRelativeModuleId(root, id) === entryRel) {
1330
+ queue.push(id);
1331
+ break;
1332
+ }
1333
+ }
1334
+ const seen = /* @__PURE__ */ new Set();
1335
+ const inputs = /* @__PURE__ */ new Set();
1336
+ const packages = /* @__PURE__ */ new Set();
1337
+ let hasDynamicImports = false;
1338
+ const unresolvedImports = /* @__PURE__ */ new Set();
1339
+ while (queue.length > 0) {
1340
+ const id = queue.pop();
1341
+ if (seen.has(id)) continue;
1342
+ seen.add(id);
1343
+ const relativePath = projectRelativeModuleId(root, id);
1344
+ if (relativePath) inputs.add(relativePath);
1345
+ const packageName = packageNameFromModuleId(id);
1346
+ if (packageName && !isRuntimeExternalPackage(packageName)) packages.add(packageName);
1347
+ for (const unresolved of graph.unresolvedByImporter.get(id) ?? []) unresolvedImports.add(unresolved);
1348
+ const node = graph.byId.get(id);
1349
+ if (!node) continue;
1350
+ if (node.dynamicallyImportedIds.length > 0) hasDynamicImports = true;
1351
+ for (const imported of node.importedIds) queue.push(imported);
1352
+ for (const imported of node.dynamicallyImportedIds) queue.push(imported);
1353
+ }
1354
+ const entryPath = projectRelativeModuleId(root, entryAbsolute) ?? toPosix(relative(normalizeBuildFilePath(root), entryNormalized));
1355
+ inputs.add(entryPath);
1356
+ return {
1357
+ resourceKey,
1358
+ kind,
1359
+ entryPath,
1360
+ inputs: [...inputs].sort(),
1361
+ packages: [...packages].sort(),
1362
+ hasDynamicImports,
1363
+ unresolvedImports: [...unresolvedImports].sort()
1364
+ };
1365
+ }
1366
+ /**
1367
+ * Analyze bundler input closures for every deployable workflow and agent entry.
1368
+ *
1369
+ * Uses the same tsdown/rolldown resolver settings as artifact builds so aliases,
1370
+ * package exports, TS resolution, and externals match production.
1371
+ */
1372
+ async function analyzeDeployableClosures(options = {}) {
1373
+ const root = normalizeBuildFilePath(options.root ?? process.cwd());
1374
+ const walked = walkProject(root, {
1375
+ srcDir: options.srcDir ?? "src",
1376
+ phase: options.phase ?? "deploy"
1377
+ });
1378
+ const entries = {};
1379
+ for (const [key, absolute] of Object.entries(walked.buildEntries)) if (isDeployableResourceKey(key)) entries[key] = absolute;
1380
+ const entryList = Object.entries(entries).sort(([a], [b]) => a.localeCompare(b));
1381
+ if (entryList.length === 0) return {
1382
+ closures: [],
1383
+ failures: []
1384
+ };
1385
+ mkdirSync(join(root, ".keystroke"), { recursive: true });
1386
+ const scratchRoot = mkdtempSync(join(root, ".keystroke", "closure-analyze-"));
1387
+ const previous = process.cwd();
1388
+ const closures = [];
1389
+ const failures = [];
1390
+ try {
1391
+ process.chdir(root);
1392
+ for (const [resourceKey, entryPath] of entryList) {
1393
+ const graph = {
1394
+ byId: /* @__PURE__ */ new Map(),
1395
+ unresolvedByImporter: /* @__PURE__ */ new Map()
1396
+ };
1397
+ const outDir = join(scratchRoot, "dist", resourceKey.replaceAll("/", "__"));
1398
+ try {
1399
+ await build(mergeConfig(baseTsdownConfig, {
1400
+ entry: { [resourceKey]: entryPath },
1401
+ format: ["esm"],
1402
+ outDir,
1403
+ clean: true,
1404
+ dts: false,
1405
+ sourcemap: false,
1406
+ logLevel: "error",
1407
+ loader: { ".md": "text" },
1408
+ deps: userAppBuildDepsConfig(),
1409
+ plugins: [collectModuleGraphPlugin(graph)]
1410
+ }));
1411
+ const closure = closureFromGraph(root, resourceKey, entryPath, graph);
1412
+ closures.push(closure);
1413
+ } catch (error) {
1414
+ const message = error instanceof Error ? error.message : String(error);
1415
+ failures.push({
1416
+ resourceKey,
1417
+ reason: message
1418
+ });
1419
+ }
1420
+ }
1421
+ } finally {
1422
+ process.chdir(previous);
1423
+ rmSync(scratchRoot, {
1424
+ recursive: true,
1425
+ force: true
1426
+ });
1427
+ }
1428
+ return {
1429
+ closures,
1430
+ failures
1431
+ };
1432
+ }
1433
+ function ownershipIndex(closures) {
1434
+ const index = /* @__PURE__ */ new Map();
1435
+ for (const closure of closures) for (const input of closure.inputs) {
1436
+ const owners = index.get(input) ?? [];
1437
+ owners.push(closure.resourceKey);
1438
+ index.set(input, owners);
1439
+ }
1440
+ for (const [path, owners] of index) index.set(path, [...new Set(owners)].sort());
1441
+ return index;
1442
+ }
1443
+ function packageOwnershipIndex(closures) {
1444
+ const packageOwners = /* @__PURE__ */ new Map();
1445
+ for (const closure of closures) for (const packageName of closure.packages) {
1446
+ const owners = packageOwners.get(packageName) ?? [];
1447
+ owners.push(closure.resourceKey);
1448
+ packageOwners.set(packageName, owners);
1449
+ }
1450
+ for (const [packageName, owners] of packageOwners) packageOwners.set(packageName, [...new Set(owners)].sort());
1451
+ return packageOwners;
1452
+ }
1453
+ function unionOwners(...lists) {
1454
+ return [...new Set(lists.flatMap((list) => list ?? []))].sort();
1455
+ }
1456
+ function intersectsRequested(owners, requested) {
1457
+ return owners.some((owner) => requested.has(owner));
1458
+ }
1459
+ function sortCandidateOps(ops) {
1460
+ return [...ops].sort((a, b) => {
1461
+ const byPath = a.path.localeCompare(b.path);
1462
+ if (byPath !== 0) return byPath;
1463
+ return a.op.localeCompare(b.op);
1464
+ });
1465
+ }
1466
+ /**
1467
+ * Transition ownership for a changed path:
1468
+ * - added → D0 owners
1469
+ * - deleted → M0 owners
1470
+ * - modified → M0 ∪ D0 owners
1471
+ * - renamed → previousPath M0 ∪ new path D0 (promote both ops when either side matches)
1472
+ */
1473
+ function transitionAttribution(change, draftOwnersByPath, mainOwnersByPath) {
1474
+ if (change.kind === "renamed") {
1475
+ if (!change.previousPath) return requireFull("ambiguous_ownership", `Renamed path "${change.path}" is missing previousPath; filtered deploy cannot attribute ownership`);
1476
+ return {
1477
+ owners: unionOwners(mainOwnersByPath.get(change.previousPath), draftOwnersByPath.get(change.path)),
1478
+ ops: [{
1479
+ path: change.previousPath,
1480
+ op: "delete"
1481
+ }, {
1482
+ path: change.path,
1483
+ op: "upsert"
1484
+ }]
1485
+ };
1486
+ }
1487
+ if (change.kind === "added") return {
1488
+ owners: draftOwnersByPath.get(change.path) ?? [],
1489
+ ops: [{
1490
+ path: change.path,
1491
+ op: "upsert"
1492
+ }]
1493
+ };
1494
+ if (change.kind === "deleted") return {
1495
+ owners: mainOwnersByPath.get(change.path) ?? [],
1496
+ ops: [{
1497
+ path: change.path,
1498
+ op: "delete"
1499
+ }]
1500
+ };
1501
+ return {
1502
+ owners: unionOwners(mainOwnersByPath.get(change.path), draftOwnersByPath.get(change.path)),
1503
+ ops: [{
1504
+ path: change.path,
1505
+ op: "upsert"
1506
+ }]
1507
+ };
1508
+ }
1509
+ function filteredSuccess(input) {
1510
+ return {
1511
+ requireFull: false,
1512
+ resourceKeys: [...input.resourceKeys].sort(),
1513
+ impactedResourceKeys: [...input.impactedResourceKeys].sort(),
1514
+ expansions: [...input.expansions].sort((a, b) => a.resourceKey.localeCompare(b.resourceKey)),
1515
+ sourceDelta: [...input.sourceDelta].sort(),
1516
+ candidateOps: sortCandidateOps(input.candidateOps),
1517
+ impactCompleteness: input.impactCompleteness,
1518
+ warnings: [...input.warnings]
1519
+ };
1520
+ }
1521
+ /**
1522
+ * Compute the smallest safe filtered resource set + source delta for a draft delta.
1523
+ *
1524
+ * Dual-graph (M0/D0) transition ownership promotes only paths attributable to
1525
+ * the requested resources. Impacts are M0 consumers of promoted paths (candidate
1526
+ * = M0 + sourceDelta). Incomplete main-impact enumeration is soft-unknown, not
1527
+ * a hard block.
1528
+ */
1529
+ async function computeSafeFilteredDeploy(options) {
1530
+ const root = normalizeBuildFilePath(options.root ?? process.cwd());
1531
+ const srcDir = options.srcDir ?? "src";
1532
+ const phase = options.phase ?? "deploy";
1533
+ const normalized = normalizeChanges(root, options.changedPaths);
1534
+ if ("requireFull" in normalized && normalized.requireFull) return normalized;
1535
+ const changes = normalized;
1536
+ const packageManifestChanges = [];
1537
+ const lockfileChanges = [];
1538
+ const sourceLikeChanges = [];
1539
+ for (const change of changes) {
1540
+ if (isPackageManifestPath(change.path)) {
1541
+ packageManifestChanges.push(change);
1542
+ continue;
1543
+ }
1544
+ if (isLockfilePath(change.path)) {
1545
+ lockfileChanges.push(change);
1546
+ continue;
1547
+ }
1548
+ sourceLikeChanges.push(change);
1549
+ }
1550
+ const selected = [...new Set(options.selectedResourceKeys)];
1551
+ if (selected.length === 0) return requireFull("unknown_selected_key", "At least one selected resource key is required");
1552
+ const draftAnalysis = options.closures !== void 0 ? {
1553
+ closures: options.closures,
1554
+ failures: options.failures ?? []
1555
+ } : await analyzeDeployableClosures({
1556
+ root,
1557
+ srcDir,
1558
+ phase
1559
+ });
1560
+ const draftClosures = draftAnalysis.closures;
1561
+ const draftFailures = draftAnalysis.failures;
1562
+ const draftByKey = new Map(draftClosures.map((closure) => [closure.resourceKey, closure]));
1563
+ const draftFailedKeys = new Set(draftFailures.map((failure) => failure.resourceKey));
1564
+ const mainClosures = options.mainClosures ?? draftClosures;
1565
+ const mainFailures = options.mainClosures !== void 0 ? options.mainFailures ?? [] : draftFailures;
1566
+ const mainByKey = new Map(mainClosures.map((closure) => [closure.resourceKey, closure]));
1567
+ const mainFailedKeys = new Set(mainFailures.map((failure) => failure.resourceKey));
1568
+ for (const key of selected) {
1569
+ if (draftFailedKeys.has(key)) {
1570
+ const failure = draftFailures.find((item) => item.resourceKey === key);
1571
+ return requireFull("unproven_safe", `Selected resource "${key}" failed bundler analysis; filtered deploy cannot prove a complete closure` + (failure ? `: ${failure.reason}` : ""));
1572
+ }
1573
+ if (!draftByKey.has(key)) return requireFull("unknown_selected_key", `Unknown selected resource key "${key}". Use keys like agents/foo or workflows/bar`);
1574
+ }
1575
+ for (const key of selected) {
1576
+ const closure = draftByKey.get(key);
1577
+ if (closure.hasDynamicImports || closure.unresolvedImports.length > 0) return requireFull("dynamic_or_unresolved_import", `Selected resource "${key}" has dynamic or unresolved imports; filtered deploy cannot prove a complete closure`);
1578
+ }
1579
+ const draftOwnersByPath = ownershipIndex(draftClosures);
1580
+ const mainOwnersByPath = ownershipIndex(mainClosures);
1581
+ const mainPackageOwners = packageOwnershipIndex(mainClosures);
1582
+ const requestedSet = new Set(selected);
1583
+ const sourceDelta = /* @__PURE__ */ new Set();
1584
+ const candidateOpsByKey = /* @__PURE__ */ new Map();
1585
+ const expansions = /* @__PURE__ */ new Map();
1586
+ const impactedSet = /* @__PURE__ */ new Set();
1587
+ const warnings = [];
1588
+ let impactCompleteness = "complete";
1589
+ const markUnknown = (warning) => {
1590
+ impactCompleteness = "unknown";
1591
+ if (!warnings.includes(warning)) warnings.push(warning);
1592
+ };
1593
+ const addCandidateOp = (op) => {
1594
+ const key = `${op.op}:${op.path}`;
1595
+ candidateOpsByKey.set(key, op);
1596
+ sourceDelta.add(op.path);
1597
+ };
1598
+ const markImpact = (resourceKey, sharedInputs, reason) => {
1599
+ if (requestedSet.has(resourceKey)) return;
1600
+ impactedSet.add(resourceKey);
1601
+ const existing = expansions.get(resourceKey);
1602
+ const mergedInputs = existing ? [...new Set([...existing.sharedInputs, ...sharedInputs])].sort() : [...sharedInputs].sort();
1603
+ expansions.set(resourceKey, {
1604
+ resourceKey,
1605
+ reason: existing ? `${existing.reason}; ${reason}` : reason,
1606
+ sharedInputs: mergedInputs
1607
+ });
1608
+ };
1609
+ const selectedEntryPaths = new Set(selected.map((key) => draftByKey.get(key)?.entryPath).filter((path) => Boolean(path)));
1610
+ for (const change of sourceLikeChanges) {
1611
+ const attribution = transitionAttribution(change, draftOwnersByPath, mainOwnersByPath);
1612
+ if ("requireFull" in attribution) return attribution;
1613
+ const { owners, ops } = attribution;
1614
+ if ((selectedEntryPaths.has(change.path) || change.previousPath != null && selectedEntryPaths.has(change.previousPath) || selected.some((key) => {
1615
+ const mainEntry = mainByKey.get(key)?.entryPath;
1616
+ return mainEntry === change.path || mainEntry === change.previousPath;
1617
+ })) && !intersectsRequested(owners, requestedSet)) return requireFull("missing_ownership", `Changed path "${change.path}" must be included for the selected resource(s) but selected ownership cannot be proven`);
1618
+ if (!intersectsRequested(owners, requestedSet)) continue;
1619
+ for (const op of ops) addCandidateOp(op);
1620
+ for (const op of ops) {
1621
+ const mainOwners = mainOwnersByPath.get(op.path) ?? [];
1622
+ for (const owner of mainOwners) {
1623
+ if (requestedSet.has(owner)) continue;
1624
+ const mainClosure = mainByKey.get(owner);
1625
+ if (!mainClosure) {
1626
+ if (mainFailedKeys.has(owner)) {
1627
+ markUnknown(`Main-tip analysis failed for "${owner}"; additional owners of promoted path "${op.path}" may be hidden`);
1628
+ continue;
1629
+ }
1630
+ markUnknown(`Promoted path "${op.path}" lists main owner "${owner}" without an analyzable main closure`);
1631
+ continue;
1632
+ }
1633
+ if (mainClosure.hasDynamicImports || mainClosure.unresolvedImports.length > 0) markUnknown(`Impacted main resource "${owner}" has dynamic or unresolved imports; additional impacts may be hidden`);
1634
+ markImpact(owner, [op.path], `Shared input ${`"${op.path}"`} also used by requested resource(s) on main`);
1635
+ }
1636
+ }
1637
+ }
1638
+ if (packageManifestChanges.length > 0 || lockfileChanges.length > 0) {
1639
+ const packageResult = attributePackageChanges({
1640
+ root,
1641
+ packageManifestChanges,
1642
+ lockfileChanges,
1643
+ baseManifestFiles: options.baseManifestFiles ?? [],
1644
+ mainClosures,
1645
+ draftClosures,
1646
+ requestedSet,
1647
+ mainPackageOwners
1648
+ });
1649
+ if (packageResult.include) {
1650
+ for (const path of packageResult.manifestDelta) addCandidateOp({
1651
+ path,
1652
+ op: "upsert"
1653
+ });
1654
+ for (const expansion of packageResult.expansions) markImpact(expansion.resourceKey, expansion.sharedInputs, expansion.reason);
1655
+ if (packageResult.unknownCompleteness) for (const warning of packageResult.warnings) markUnknown(warning);
1656
+ }
1657
+ }
1658
+ if (mainFailures.length > 0 && sourceDelta.size > 0) {
1659
+ const failedList = [...mainFailedKeys].sort().join(", ");
1660
+ if (![...sourceDelta].every((path) => selectedEntryPaths.has(path))) markUnknown(`Main-tip bundler analysis failed for deployable resource(s) ${failedList}; additional owners of promoted shared paths may be hidden`);
1661
+ }
1662
+ if (sourceDelta.size === 0) return filteredSuccess({
1663
+ resourceKeys: selected,
1664
+ impactedResourceKeys: [],
1665
+ expansions: [],
1666
+ sourceDelta: [],
1667
+ candidateOps: [],
1668
+ impactCompleteness: "complete",
1669
+ warnings: []
1670
+ });
1671
+ return filteredSuccess({
1672
+ resourceKeys: [...requestedSet, ...impactedSet],
1673
+ impactedResourceKeys: [...impactedSet],
1674
+ expansions: [...expansions.values()],
1675
+ sourceDelta: [...sourceDelta],
1676
+ candidateOps: [...candidateOpsByKey.values()],
1677
+ impactCompleteness,
1678
+ warnings
1679
+ });
1680
+ }
1681
+ function attributePackageChanges(input) {
1682
+ if (input.packageManifestChanges.length === 0) return { include: false };
1683
+ if (input.baseManifestFiles.length === 0) return { include: false };
1684
+ const draftPackageJsonPath = join(input.root, "package.json");
1685
+ let draftPackageJson;
1686
+ try {
1687
+ draftPackageJson = readFileSync(draftPackageJsonPath, "utf8");
1688
+ } catch {
1689
+ return { include: false };
1690
+ }
1691
+ const basePackageJson = new Map(input.baseManifestFiles.map((file) => [file.path.replace(/\\/g, "/"), file.contents])).get("package.json");
1692
+ if (basePackageJson == null) return { include: false };
1693
+ const baseDeps = readDependencyMap(basePackageJson);
1694
+ const draftDeps = readDependencyMap(draftPackageJson);
1695
+ if (!baseDeps || !draftDeps) return { include: false };
1696
+ const changedPackages = changedDependencyNames(baseDeps, draftDeps);
1697
+ if (changedPackages.length === 0) return { include: false };
1698
+ const runtimeChanged = changedPackages.filter((name) => isRuntimeExternalPackage(name));
1699
+ const bundledChanged = changedPackages.filter((name) => !isRuntimeExternalPackage(name));
1700
+ const selectedConsumesBundled = [...input.requestedSet].some((key) => {
1701
+ const draft = input.draftClosures.find((item) => item.resourceKey === key);
1702
+ const main = input.mainClosures.find((item) => item.resourceKey === key);
1703
+ const packages = new Set([...draft?.packages ?? [], ...main?.packages ?? []]);
1704
+ return bundledChanged.some((name) => packages.has(name));
1705
+ });
1706
+ if (runtimeChanged.length === 0 && !selectedConsumesBundled) return { include: false };
1707
+ const expansions = /* @__PURE__ */ new Map();
1708
+ const markImpact = (resourceKey, reason, sharedInputs) => {
1709
+ if (input.requestedSet.has(resourceKey)) return;
1710
+ const existing = expansions.get(resourceKey);
1711
+ expansions.set(resourceKey, {
1712
+ resourceKey,
1713
+ reason: existing ? `${existing.reason}; ${reason}` : reason,
1714
+ sharedInputs: [...new Set([...existing?.sharedInputs ?? [], ...sharedInputs])].sort()
1715
+ });
1716
+ };
1717
+ if (runtimeChanged.length > 0) for (const closure of input.mainClosures) markImpact(closure.resourceKey, `Runtime package update (${runtimeChanged.map((name) => `"${name}"`).join(", ")}) requires rebuilding all resources from main`, runtimeChanged);
1718
+ for (const packageName of bundledChanged) {
1719
+ if (!selectedConsumesBundled) continue;
1720
+ const owners = input.mainPackageOwners.get(packageName) ?? [];
1721
+ for (const owner of owners) markImpact(owner, `Bundled package "${packageName}" changed and is imported by this resource`, [packageName]);
1722
+ }
1723
+ const manifestDelta = [...input.packageManifestChanges.map((change) => change.path), ...input.lockfileChanges.map((change) => change.path)].sort();
1724
+ const warnings = [];
1725
+ let unknownCompleteness = false;
1726
+ if (input.lockfileChanges.length > 0) {
1727
+ unknownCompleteness = true;
1728
+ warnings.push("Lockfile included with selected package change; lockfile resolution may hide additional package consumers");
1729
+ }
1730
+ return {
1731
+ include: true,
1732
+ manifestDelta,
1733
+ expansions: [...expansions.values()],
1734
+ unknownCompleteness,
1735
+ warnings
1736
+ };
1737
+ }
1738
+ /** Build user agents, workflows, triggers, and config to `dist/`. */
1739
+ async function buildApp(options = {}) {
1740
+ const root = options.root ?? process.cwd();
1741
+ const srcDir = options.srcDir ?? "src";
1742
+ const emitManifest = options.emitManifest ?? true;
1743
+ const collectSources = options.collectSources ?? false;
1744
+ const phase = options.phase ?? "build";
1745
+ const previous = process.cwd();
1746
+ const walked = walkProject(root, {
1747
+ srcDir,
1748
+ collectSources,
1749
+ phase
1750
+ });
1751
+ const timings = {
1752
+ bundleMs: 0,
1753
+ manifestMs: 0,
1754
+ manifestCacheHit: false,
1755
+ bundleSkipped: false
1756
+ };
1757
+ const cacheKey = phase === "deploy" && collectSources && walked.sourceFiles.length > 0 ? computeRouteManifestCacheKey({
1758
+ phase,
1759
+ sourceFiles: walked.sourceFiles,
1760
+ buildEntryKeys: Object.keys(walked.buildEntries),
1761
+ ignoredFiles: walked.ignoredFiles,
1762
+ integrationFingerprint: integrationPackagesFingerprint(root)
1763
+ }) : null;
1764
+ try {
1765
+ process.chdir(root);
1766
+ if (cacheKey && emitManifest && isRouteManifestCacheHit(root, cacheKey) && distDeployOutputsPresent(root, walked.buildEntries)) {
1767
+ const manifestStarted = Date.now();
1768
+ tryRestoreCachedRouteManifest(root, cacheKey);
1769
+ timings.manifestCacheHit = true;
1770
+ timings.bundleSkipped = true;
1771
+ timings.manifestMs = Date.now() - manifestStarted;
1772
+ return {
1773
+ sourceFiles: walked.sourceFiles,
1774
+ timings
1775
+ };
1776
+ }
1777
+ const dirtyResult = listDirtyEntries(root, Object.keys(walked.buildEntries));
1778
+ const skipBundle = !dirtyResult.forceFull && dirtyResult.dirty.length === 0 && distDeployOutputsPresent(root, walked.buildEntries);
1779
+ const workflowDiagnostics = collectWorkflowDiagnostics(root, srcDir);
1780
+ assertWorkflowDiagnosticErrorsFrom(workflowDiagnostics);
1781
+ try {
1782
+ if (skipBundle) {
1783
+ packModularProjectAssets({
1784
+ projectRoot: root,
1785
+ srcDir,
1786
+ outDir: options.outDir ?? "dist"
1787
+ });
1788
+ timings.bundleSkipped = true;
1789
+ } else {
1790
+ const bundleStarted = Date.now();
1791
+ const configEntry = existsSync(join(root, "keystroke.config.ts")) ? join(root, "keystroke.config.ts") : void 0;
1792
+ await buildSelfContainedEntries({
1793
+ root,
1794
+ srcDir,
1795
+ outDir: options.outDir ?? "dist",
1796
+ phase,
1797
+ clean: dirtyResult.forceFull && (options.clean ?? true),
1798
+ buildEntries: walked.buildEntries,
1799
+ ignoredFiles: walked.ignoredFiles,
1800
+ dirtyKeys: dirtyResult.forceFull ? void 0 : dirtyResult.dirty,
1801
+ configEntry
1802
+ });
1803
+ timings.bundleMs = Date.now() - bundleStarted;
1804
+ }
1805
+ } finally {
1806
+ warnWorkflowDiagnosticsFrom(workflowDiagnostics);
1807
+ }
1808
+ if (emitManifest) {
1809
+ const manifestStarted = Date.now();
1810
+ if (cacheKey && tryRestoreCachedRouteManifest(root, cacheKey)) timings.manifestCacheHit = true;
1811
+ else {
1812
+ const { emitStoredRouteManifestForProject } = await import("./dist-Dq1kkbLy.mjs");
1813
+ await emitStoredRouteManifestForProject(root);
1814
+ if (cacheKey) storeCachedRouteManifest(root, cacheKey);
1815
+ }
1816
+ timings.manifestMs = Date.now() - manifestStarted;
1817
+ }
1818
+ } finally {
1819
+ process.chdir(previous);
1820
+ }
1821
+ return {
1822
+ sourceFiles: walked.sourceFiles,
1823
+ timings
1824
+ };
1825
+ }
1826
+ //#endregion
1827
+ export { buildApp as a, computeSafeFilteredDeploy as c, normalizeProjectRelativePath as d, tryReadBuildIndex as f, assertWorkflowDiagnosticErrorsFrom as i, injectCallSiteIds as l, BUILD_INDEX_REL_PATH as n, callSiteIdInjectionPlugin as o, warnWorkflowDiagnosticsFrom as p, analyzeDeployableClosures as r, collectWorkflowDiagnostics as s, ANALYZER_CONTRACT_VERSION as t, listDirtyEntries as u };
1828
+
1829
+ //# sourceMappingURL=dist-DJQnugPi.mjs.map