@pikku/cli 0.12.154 → 0.12.155

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 (279) hide show
  1. package/console-app/assets/{HelpPanel-BPFBvwZj.js → HelpPanel-Ndvkqpn8.js} +1 -1
  2. package/console-app/assets/{abnfDiagram-VCTEODGH-DDuocZ0S.js → abnfDiagram-VCTEODGH-DvUR4gej.js} +1 -1
  3. package/console-app/assets/architecture-7GRP2DOG-DJkDVzM_.js +1 -0
  4. package/console-app/assets/{architectureDiagram-5GKGNRK7-bFIt59Dq.js → architectureDiagram-5GKGNRK7-HLwJ3llk.js} +1 -1
  5. package/console-app/assets/{blockDiagram-I7D4REHJ-Bge8309x.js → blockDiagram-I7D4REHJ-LMSdIVfc.js} +1 -1
  6. package/console-app/assets/{c4Diagram-7LVT6UL2-BdJOmC5x.js → c4Diagram-7LVT6UL2-CcWW9nYv.js} +1 -1
  7. package/console-app/assets/channel-C6yZyX_m.js +1 -0
  8. package/console-app/assets/{chunk-4HAMMTFA-Cenx-5I1.js → chunk-4HAMMTFA-Dxcu8ptc.js} +1 -1
  9. package/console-app/assets/{chunk-75Z2AOVW-CAGQ08f_.js → chunk-75Z2AOVW-BBINCcJe.js} +1 -1
  10. package/console-app/assets/{chunk-DU6HZSFF-Bhji7Bhy.js → chunk-DU6HZSFF-BgJhrYpo.js} +1 -1
  11. package/console-app/assets/{chunk-F27PBJKO-D7gTX3dk.js → chunk-F27PBJKO-CctviqIo.js} +1 -1
  12. package/console-app/assets/{chunk-GMAD6QVW-DkRx7Brv.js → chunk-GMAD6QVW-BJ-InAqp.js} +1 -1
  13. package/console-app/assets/{chunk-GVQU2GXP-DEWdO9pP.js → chunk-GVQU2GXP-DaeerGJS.js} +1 -1
  14. package/console-app/assets/{chunk-IMKFNOWR-C1Vtain1.js → chunk-IMKFNOWR-eOSAFAc9.js} +1 -1
  15. package/console-app/assets/{chunk-L3NEJ4N5-B_nm0es0.js → chunk-L3NEJ4N5-DRfMBpkp.js} +1 -1
  16. package/console-app/assets/{chunk-OSK3NFVY-C0EPlVq0.js → chunk-OSK3NFVY-DMZ2WBA1.js} +1 -1
  17. package/console-app/assets/{chunk-P2QGCYS3-qs_HwIoO.js → chunk-P2QGCYS3-d0BFQiY1.js} +1 -1
  18. package/console-app/assets/{chunk-POPQ4Y6H-CJWbAVy_.js → chunk-POPQ4Y6H-D4zICDtR.js} +1 -1
  19. package/console-app/assets/{chunk-PWAF6VOD-CmyETkG4.js → chunk-PWAF6VOD-_v9wUl6m.js} +1 -1
  20. package/console-app/assets/{chunk-SHT3W25Y-Coqn0qc9.js → chunk-SHT3W25Y-DZ3Wa0Mc.js} +1 -1
  21. package/console-app/assets/{chunk-SVP7TREG-D1E3L3Ry.js → chunk-SVP7TREG-2yCR3ywB.js} +1 -1
  22. package/console-app/assets/{chunk-TICWLB2K-bsfeT6VF.js → chunk-TICWLB2K-CtulM0X6.js} +1 -1
  23. package/console-app/assets/chunk-XXDRQBXY-CLsn_tEh.js +1 -0
  24. package/console-app/assets/classDiagram-ZZMXUADV-D7FKceOo.js +1 -0
  25. package/console-app/assets/classDiagram-v2-VYDZK3BY-D7FKceOo.js +1 -0
  26. package/console-app/assets/{cose-bilkent-JH36ORCC-H5-jGbyx.js → cose-bilkent-JH36ORCC-DNc5wiJ_.js} +1 -1
  27. package/console-app/assets/{cynefin-OW5HDTMX-CljdWyve.js → cynefin-OW5HDTMX-CQPn9kED.js} +1 -1
  28. package/console-app/assets/{cynefinDiagram-5FMLGOSQ-DmDd9Ruh.js → cynefinDiagram-5FMLGOSQ-CkW1ZG13.js} +1 -1
  29. package/console-app/assets/{dagre-ChLSY7zR.js → dagre-BcTdbH8b.js} +1 -1
  30. package/console-app/assets/{dagre-GXQ25YYZ-DT48xQuH.js → dagre-GXQ25YYZ-Cgvwy7_U.js} +1 -1
  31. package/console-app/assets/{diagram-S7CK7UJ4-DKPk5LKU.js → diagram-S7CK7UJ4-JB3GlMwZ.js} +1 -1
  32. package/console-app/assets/{diagram-UQ7AKVKN-BWnhjDbO.js → diagram-UQ7AKVKN-CaIeYJXa.js} +1 -1
  33. package/console-app/assets/{diagram-VSXAHHWV-1XCGd7TX.js → diagram-VSXAHHWV-Cku8J3KG.js} +1 -1
  34. package/console-app/assets/{diagram-VX7I27RA-8dIoEZIX.js → diagram-VX7I27RA-Dp3jeYrS.js} +1 -1
  35. package/console-app/assets/{diagram-Z3DM3KII-CgFhlsHg.js → diagram-Z3DM3KII-B56Ys0Pf.js} +1 -1
  36. package/console-app/assets/{ebnfDiagram-PWID7BFC-j8nbgcPz.js → ebnfDiagram-PWID7BFC-CfxeEpk1.js} +1 -1
  37. package/console-app/assets/{erDiagram-RLTQ6QDP-fQNmZd6-.js → erDiagram-RLTQ6QDP-Dp9sOoSf.js} +1 -1
  38. package/console-app/assets/eventmodeling-NTZA5JFV-CccBkMWb.js +1 -0
  39. package/console-app/assets/flowDiagram-HODETNUW-Cp_XHTFC.js +1 -0
  40. package/console-app/assets/{ganttDiagram-EL5Y4UJY-D8pzapyN.js → ganttDiagram-EL5Y4UJY-BsD1LYkb.js} +1 -1
  41. package/console-app/assets/{gitGraph-4MIJSDKK-BvRsGeLo.js → gitGraph-4MIJSDKK-CSHhAZoD.js} +1 -1
  42. package/console-app/assets/{gitGraphDiagram-WWUBYQGX-C_qwjJL5.js → gitGraphDiagram-WWUBYQGX-CZ_0OI7F.js} +1 -1
  43. package/console-app/assets/{graphlib-9R2fmYel.js → graphlib-Bpf494dL.js} +1 -1
  44. package/console-app/assets/{index-DMQFSpKy.js → index-DXtR4J7Y.js} +68 -68
  45. package/console-app/assets/{info-A6RAGUB7-BIjzE3Zr.js → info-A6RAGUB7-Cym2YsaS.js} +1 -1
  46. package/console-app/assets/{infoDiagram-27XIBGKW-DbFqdvGy.js → infoDiagram-27XIBGKW-n9atnl-K.js} +1 -1
  47. package/console-app/assets/{ishikawaDiagram-5VMMS53U-D5ei52Uz.js → ishikawaDiagram-5VMMS53U-BeLDkr8-.js} +1 -1
  48. package/console-app/assets/{journeyDiagram-3NMN7TZE-DOVQGQxF.js → journeyDiagram-3NMN7TZE-B__R_eOL.js} +1 -1
  49. package/console-app/assets/{kanban-definition-UXKFOSKX-D8cjrKvj.js → kanban-definition-UXKFOSKX-Cwsl1hYB.js} +1 -1
  50. package/console-app/assets/{line-S23S00r8.js → line-UWFHtT2i.js} +1 -1
  51. package/console-app/assets/{linear-C2q7Mgrm.js → linear-BHDHoGpb.js} +1 -1
  52. package/console-app/assets/{mermaid-parser.core-DFVvyiUd.js → mermaid-parser.core-CyGW9xht.js} +3 -3
  53. package/console-app/assets/{mermaid.core-C85pnBPI.js → mermaid.core-zeBKxakC.js} +4 -4
  54. package/console-app/assets/{mindmap-definition-YA3MSWOX-Bqn28yl9.js → mindmap-definition-YA3MSWOX-bZ2kbbMM.js} +1 -1
  55. package/console-app/assets/{packet-AYTQ26CC-Cj1kD_Xa.js → packet-AYTQ26CC-DtH3ZjsO.js} +1 -1
  56. package/console-app/assets/{pegDiagram-XKGWAZYB-DJ12pyU4.js → pegDiagram-XKGWAZYB-Cy-M_2Zc.js} +1 -1
  57. package/console-app/assets/{pie-WAS4IAKB-BUmyuH7f.js → pie-WAS4IAKB-DEZDAaJW.js} +1 -1
  58. package/console-app/assets/{pieDiagram-E7YTZNPT-jTvMRCtY.js → pieDiagram-E7YTZNPT-Ce3Yl--P.js} +1 -1
  59. package/console-app/assets/{quadrantDiagram-AXDQQJYC-D826kpcV.js → quadrantDiagram-AXDQQJYC-BTK8v4H5.js} +1 -1
  60. package/console-app/assets/{radar-RG4KPBEZ-CYbTAeXH.js → radar-RG4KPBEZ-CTPhaLOE.js} +1 -1
  61. package/console-app/assets/{railroad-74A4TZTK-mfMkjDWk.js → railroad-74A4TZTK-DMa9G1LV.js} +1 -1
  62. package/console-app/assets/railroad-abnf-HS5TGJTU-K0DgRobv.js +1 -0
  63. package/console-app/assets/railroad-ebnf-LZEXJU2U-CHEGHd9y.js +1 -0
  64. package/console-app/assets/railroad-peg-WCYAUIDC-EYHvZbXp.js +1 -0
  65. package/console-app/assets/{railroadDiagram-O6MQD6OU-CGlOEAk5.js → railroadDiagram-O6MQD6OU-CYbkYMqD.js} +1 -1
  66. package/console-app/assets/{requirementDiagram-BXWQKSXE-DY_zQ4Qu.js → requirementDiagram-BXWQKSXE-DjWjfWOk.js} +1 -1
  67. package/console-app/assets/{sankeyDiagram-P5KCCOFB-B4QJZukx.js → sankeyDiagram-P5KCCOFB-6sAcPgDK.js} +1 -1
  68. package/console-app/assets/{sequenceDiagram-WJ2MYXX4-DTERMwcf.js → sequenceDiagram-WJ2MYXX4-DzyU1CIr.js} +1 -1
  69. package/console-app/assets/{src-CRoiE_Pf.js → src-0ppm3vZe.js} +1 -1
  70. package/console-app/assets/{stateDiagram-D77RDMKH-BLnCP1RM.js → stateDiagram-D77RDMKH-S5osVh5p.js} +1 -1
  71. package/console-app/assets/stateDiagram-v2-MP3YSRHH-BZUe_KiH.js +1 -0
  72. package/console-app/assets/{swimlanes-42K2YHIH-CwYZgjxi.js → swimlanes-42K2YHIH-Dd7HjelH.js} +1 -1
  73. package/console-app/assets/swimlanesDiagram-VR7AAH4N-D6xRypPY.js +8 -0
  74. package/console-app/assets/{timeline-definition-24CTP7MA-BEv4uhRy.js → timeline-definition-24CTP7MA-eZ3AIIpc.js} +1 -1
  75. package/console-app/assets/{treeView-Q6P3EWNA-CHhQVPzu.js → treeView-Q6P3EWNA-DF5sOT6y.js} +1 -1
  76. package/console-app/assets/{treemap-WGGIJYW6-DSnq4EZT.js → treemap-WGGIJYW6-Bob0iUUb.js} +1 -1
  77. package/console-app/assets/{vennDiagram-4TSXK5OY-CHT6P8GK.js → vennDiagram-4TSXK5OY-CeowTqyG.js} +1 -1
  78. package/console-app/assets/{wardley-WFR3VGLG-yPMtiazL.js → wardley-WFR3VGLG-DrnQFkZZ.js} +1 -1
  79. package/console-app/assets/{wardleyDiagram-VM6X3IG4-Df2U4u0X.js → wardleyDiagram-VM6X3IG4-Dsfkp6D5.js} +1 -1
  80. package/console-app/assets/{xychartDiagram-S5SC5T6Z-D4bRAEWS.js → xychartDiagram-S5SC5T6Z-YC_qsmJw.js} +1 -1
  81. package/console-app/index.html +1 -1
  82. package/dist/.pikku/addon/index.d.ts +1 -1
  83. package/dist/.pikku/addon/index.js +1 -1
  84. package/dist/.pikku/addon/pikku-addon-types.gen.d.ts +1 -1
  85. package/dist/.pikku/addon/pikku-addon-types.gen.js +1 -1
  86. package/dist/.pikku/agent/index.d.ts +1 -1
  87. package/dist/.pikku/agent/index.js +1 -1
  88. package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
  89. package/dist/.pikku/agent/pikku-model-aliases.gen.js +1 -1
  90. package/dist/.pikku/analytics/index.d.ts +1 -1
  91. package/dist/.pikku/analytics/index.js +1 -1
  92. package/dist/.pikku/analytics/pikku-analytics-types.gen.d.ts +1 -1
  93. package/dist/.pikku/analytics/pikku-analytics-types.gen.js +1 -1
  94. package/dist/.pikku/auth/index.d.ts +1 -1
  95. package/dist/.pikku/auth/index.js +1 -1
  96. package/dist/.pikku/auth/pikku-auth-types.gen.d.ts +1 -1
  97. package/dist/.pikku/auth/pikku-auth-types.gen.js +1 -1
  98. package/dist/.pikku/channel/index.d.ts +1 -1
  99. package/dist/.pikku/channel/index.js +1 -1
  100. package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
  101. package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
  102. package/dist/.pikku/cli/index.d.ts +1 -1
  103. package/dist/.pikku/cli/index.js +1 -1
  104. package/dist/.pikku/cli/pikku-cli-channel.js +1 -1
  105. package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +1 -1
  106. package/dist/.pikku/cli/pikku-cli-client.gen.js +15 -5
  107. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.d.ts +1 -1
  108. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.js +1 -1
  109. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.json +1 -1
  110. package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
  111. package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
  112. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
  113. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +1 -1
  114. package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
  115. package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
  116. package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
  117. package/dist/.pikku/cli/pikku-cli.gen.js +15 -6
  118. package/dist/.pikku/error/index.d.ts +1 -1
  119. package/dist/.pikku/error/index.js +1 -1
  120. package/dist/.pikku/error/pikku-error-types.gen.d.ts +1 -1
  121. package/dist/.pikku/error/pikku-error-types.gen.js +1 -1
  122. package/dist/.pikku/function/index.d.ts +1 -1
  123. package/dist/.pikku/function/index.js +1 -1
  124. package/dist/.pikku/function/pikku-function-types.gen.d.ts +1 -1
  125. package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
  126. package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
  127. package/dist/.pikku/function/pikku-functions-meta.gen.json +31 -31
  128. package/dist/.pikku/function/pikku-functions.gen.js +1 -1
  129. package/dist/.pikku/gateway/index.d.ts +1 -1
  130. package/dist/.pikku/gateway/index.js +1 -1
  131. package/dist/.pikku/gateway/pikku-gateway-types.gen.d.ts +1 -1
  132. package/dist/.pikku/gateway/pikku-gateway-types.gen.js +1 -1
  133. package/dist/.pikku/http/index.d.ts +1 -1
  134. package/dist/.pikku/http/index.js +1 -1
  135. package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
  136. package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
  137. package/dist/.pikku/mcp/index.d.ts +1 -1
  138. package/dist/.pikku/mcp/index.js +1 -1
  139. package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
  140. package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
  141. package/dist/.pikku/middleware/index.d.ts +1 -1
  142. package/dist/.pikku/middleware/index.js +1 -1
  143. package/dist/.pikku/middleware/pikku-middleware-types.gen.d.ts +1 -1
  144. package/dist/.pikku/middleware/pikku-middleware-types.gen.js +1 -1
  145. package/dist/.pikku/pikku-bootstrap-scenarios.gen.d.ts +1 -1
  146. package/dist/.pikku/pikku-bootstrap-scenarios.gen.js +1 -1
  147. package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
  148. package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
  149. package/dist/.pikku/pikku-services.gen.d.ts +1 -1
  150. package/dist/.pikku/queue/index.d.ts +1 -1
  151. package/dist/.pikku/queue/index.js +1 -1
  152. package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
  153. package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
  154. package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
  155. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
  156. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
  157. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
  158. package/dist/.pikku/scenarios/index.d.ts +1 -1
  159. package/dist/.pikku/scenarios/index.js +1 -1
  160. package/dist/.pikku/scenarios/pikku-personas.gen.js +1 -1
  161. package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.js +1 -1
  162. package/dist/.pikku/scenarios/pikku-scenario-functions.gen.d.ts +1 -1
  163. package/dist/.pikku/scenarios/pikku-scenario-types.gen.d.ts +1 -1
  164. package/dist/.pikku/scenarios/pikku-scenario-wirings-meta.gen.js +1 -1
  165. package/dist/.pikku/scenarios/pikku-scenario-wirings.gen.d.ts +1 -1
  166. package/dist/.pikku/scenarios/schemas/register.gen.d.ts +1 -1
  167. package/dist/.pikku/scenarios/schemas/register.gen.js +1 -1
  168. package/dist/.pikku/scheduler/index.d.ts +1 -1
  169. package/dist/.pikku/scheduler/index.js +1 -1
  170. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
  171. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
  172. package/dist/.pikku/schemas/register.gen.js +1 -1
  173. package/dist/.pikku/scopes/index.d.ts +1 -1
  174. package/dist/.pikku/scopes/index.js +1 -1
  175. package/dist/.pikku/scopes/pikku-flags.gen.d.ts +1 -1
  176. package/dist/.pikku/scopes/pikku-personas.gen.js +1 -1
  177. package/dist/.pikku/scopes/pikku-roles.gen.d.ts +1 -1
  178. package/dist/.pikku/scopes/pikku-scope-types.gen.d.ts +1 -1
  179. package/dist/.pikku/scopes/pikku-scope-types.gen.js +1 -1
  180. package/dist/.pikku/scopes/pikku-scopes.gen.d.ts +1 -1
  181. package/dist/.pikku/secrets/index.d.ts +1 -1
  182. package/dist/.pikku/secrets/index.js +1 -1
  183. package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
  184. package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
  185. package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
  186. package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
  187. package/dist/.pikku/services/pikku-meta-service.gen.d.ts +1 -1
  188. package/dist/.pikku/services/pikku-meta-service.gen.js +1 -1
  189. package/dist/.pikku/setup/index.d.ts +1 -1
  190. package/dist/.pikku/setup/index.js +1 -1
  191. package/dist/.pikku/setup/pikku-setup-types.gen.d.ts +1 -1
  192. package/dist/.pikku/setup/pikku-setup-types.gen.js +1 -1
  193. package/dist/.pikku/trigger/index.d.ts +1 -1
  194. package/dist/.pikku/trigger/index.js +1 -1
  195. package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
  196. package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
  197. package/dist/.pikku/variables/index.d.ts +1 -1
  198. package/dist/.pikku/variables/index.js +1 -1
  199. package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
  200. package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
  201. package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
  202. package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
  203. package/dist/.pikku/workflow/index.d.ts +1 -1
  204. package/dist/.pikku/workflow/index.js +1 -1
  205. package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
  206. package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
  207. package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
  208. package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
  209. package/dist/bin/pikku-bin.mjs +2 -2
  210. package/dist/bin/pikku.js +32 -2
  211. package/dist/src/fabric/fabric-commands.js +3 -1
  212. package/dist/src/fabric/functions/add.function.js +4 -3
  213. package/dist/src/fabric/functions/changes-file.function.js +2 -1
  214. package/dist/src/fabric/functions/changes-shot.function.js +3 -2
  215. package/dist/src/fabric/functions/db-schema.function.js +3 -2
  216. package/dist/src/fabric/functions/deploy-list.function.js +3 -2
  217. package/dist/src/fabric/functions/deploy-units.function.js +3 -2
  218. package/dist/src/fabric/functions/deploy.function.js +4 -4
  219. package/dist/src/fabric/functions/domains-add.function.js +4 -3
  220. package/dist/src/fabric/functions/domains-list.function.js +3 -2
  221. package/dist/src/fabric/functions/domains-remove.function.js +5 -4
  222. package/dist/src/fabric/functions/errors.function.js +3 -2
  223. package/dist/src/fabric/functions/findings-flush.function.js +2 -1
  224. package/dist/src/fabric/functions/init.function.js +3 -2
  225. package/dist/src/fabric/functions/link.function.js +10 -10
  226. package/dist/src/fabric/functions/login.function.js +4 -3
  227. package/dist/src/fabric/functions/logs.function.js +2 -2
  228. package/dist/src/fabric/functions/metrics.function.js +3 -2
  229. package/dist/src/fabric/functions/projects-list.function.js +2 -1
  230. package/dist/src/fabric/functions/publish.function.js +7 -6
  231. package/dist/src/fabric/functions/report.function.js +4 -3
  232. package/dist/src/fabric/functions/rollback.function.js +3 -2
  233. package/dist/src/fabric/functions/secrets-delete.function.js +5 -4
  234. package/dist/src/fabric/functions/secrets-list.function.js +3 -2
  235. package/dist/src/fabric/functions/secrets-rotate.function.js +4 -3
  236. package/dist/src/fabric/functions/secrets-set.function.js +11 -4
  237. package/dist/src/fabric/functions/smoke.function.js +4 -3
  238. package/dist/src/fabric/functions/status.function.js +3 -2
  239. package/dist/src/fabric/functions/trace.function.js +3 -2
  240. package/dist/src/fabric/functions/variables-get.function.js +3 -2
  241. package/dist/src/fabric/functions/variables-set.function.js +3 -2
  242. package/dist/src/fabric/lib/changes.js +3 -2
  243. package/dist/src/fabric/lib/config.js +2 -1
  244. package/dist/src/fabric/lib/deployment.js +2 -1
  245. package/dist/src/fabric/lib/git.d.ts +10 -1
  246. package/dist/src/fabric/lib/git.js +10 -1
  247. package/dist/src/fabric/lib/prompt.d.ts +14 -5
  248. package/dist/src/fabric/lib/prompt.js +78 -15
  249. package/dist/src/fabric/lib/sealed-box.js +3 -2
  250. package/dist/src/fabric/lib/stage.js +3 -2
  251. package/dist/src/functions/commands/watch.js +5 -2
  252. package/dist/src/functions/wirings/agent/serialize-public-agent.js +2 -0
  253. package/dist/src/functions/wirings/cli/serialize-channel-cli-client.js +18 -4
  254. package/dist/src/functions/wirings/cli/serialize-local-cli-bootstrap.js +16 -5
  255. package/dist/src/functions/wirings/functions/pikku-command-addon-types.js +26 -5
  256. package/dist/src/functions/wirings/functions/serialize-addon-types.d.ts +1 -1
  257. package/dist/src/functions/wirings/functions/serialize-addon-types.js +46 -1
  258. package/dist/src/functions/wirings/mcp/pikku-command-mcp.js +3 -1
  259. package/dist/src/functions/wirings/middleware/pikku-command-middleware.js +13 -1
  260. package/dist/src/functions/wirings/middleware/serialize-middleware-imports.d.ts +13 -0
  261. package/dist/src/functions/wirings/middleware/serialize-middleware-imports.js +48 -8
  262. package/dist/src/utils/pikku-cli-config-error.d.ts +8 -3
  263. package/dist/src/utils/pikku-cli-config-error.js +8 -3
  264. package/dist/src/utils/pikku-cli-config.js +1 -1
  265. package/dist/tsconfig.tsbuildinfo +1 -1
  266. package/package.json +8 -8
  267. package/surface.json +4 -16
  268. package/console-app/assets/architecture-7GRP2DOG-ClxOnHTX.js +0 -1
  269. package/console-app/assets/channel-c0xM4cPi.js +0 -1
  270. package/console-app/assets/chunk-XXDRQBXY-BkM8vXTQ.js +0 -1
  271. package/console-app/assets/classDiagram-ZZMXUADV-yCAU184A.js +0 -1
  272. package/console-app/assets/classDiagram-v2-VYDZK3BY-yCAU184A.js +0 -1
  273. package/console-app/assets/eventmodeling-NTZA5JFV-bHToGR6p.js +0 -1
  274. package/console-app/assets/flowDiagram-HODETNUW-Dd1RiDsS.js +0 -1
  275. package/console-app/assets/railroad-abnf-HS5TGJTU-nuNyByRg.js +0 -1
  276. package/console-app/assets/railroad-ebnf-LZEXJU2U-BztHKlS5.js +0 -1
  277. package/console-app/assets/railroad-peg-WCYAUIDC-Bw7jp-js.js +0 -1
  278. package/console-app/assets/stateDiagram-v2-MP3YSRHH-Bv8nfhYK.js +0 -1
  279. package/console-app/assets/swimlanesDiagram-VR7AAH4N-BtAfsGDG.js +0 -8
@@ -1,6 +1,7 @@
1
1
  import { extname } from 'node:path';
2
2
  import { resolveApiContext } from './config.js';
3
3
  import { getFabricRPC } from './http.js';
4
+ import { FabricPreconditionError } from './errors.js';
4
5
  /**
5
6
  * Resolve the three things every `changes` command needs: the api url, a
6
7
  * bearer, and the project the queue belongs to.
@@ -12,7 +13,7 @@ import { getFabricRPC } from './http.js';
12
13
  export async function changesContext(apiUrlOverride, projectIdOverride) {
13
14
  const ctx = await resolveApiContext({ apiUrlOverride });
14
15
  if (!ctx.token)
15
- throw new Error('Not logged in. Run `pikku fabric login` first.');
16
+ throw new FabricPreconditionError('Not logged in. Run `pikku fabric login` first.');
16
17
  return {
17
18
  rpc: getFabricRPC({ apiUrl: ctx.apiUrl, token: ctx.token }),
18
19
  projectId: projectIdOverride ?? ctx.projectId,
@@ -20,7 +21,7 @@ export async function changesContext(apiUrlOverride, projectIdOverride) {
20
21
  }
21
22
  export function requireProjectId(projectId) {
22
23
  if (!projectId)
23
- throw new Error('No fabric project. Pass --project-id, or run `pikku fabric link` in the checkout.');
24
+ throw new FabricPreconditionError('No fabric project. Pass --project-id, or run `pikku fabric link` in the checkout.');
24
25
  return projectId;
25
26
  }
26
27
  /**
@@ -2,6 +2,7 @@ import { readFile, writeFile, mkdir } from 'node:fs/promises';
2
2
  import { existsSync } from 'node:fs';
3
3
  import { dirname, join } from 'node:path';
4
4
  import { homedir } from 'node:os';
5
+ import { FabricPreconditionError } from './errors.js';
5
6
  const DEFAULT_API_URL = 'https://api.pikkufabric.com';
6
7
  const projectConfigName = 'pikkufabric.config.json';
7
8
  const authFilePath = join(homedir(), '.fabric', 'auth.json');
@@ -52,7 +53,7 @@ export async function writeProjectConfig(cwd, config) {
52
53
  raw = await readFile(path, 'utf8');
53
54
  }
54
55
  catch (error) {
55
- throw new Error(`Cannot read ${projectConfigName} at ${path} (${error.message}) — refusing to overwrite it`);
56
+ throw new FabricPreconditionError(`Cannot read ${projectConfigName} at ${path} (${error.message}) — refusing to overwrite it`);
56
57
  }
57
58
  try {
58
59
  const parsed = JSON.parse(raw);
@@ -1,3 +1,4 @@
1
+ import { FabricPreconditionError } from './errors.js';
1
2
  const IN_FLIGHT = new Set(['queued', 'planning', 'building', 'deploying']);
2
3
  const SUCCEEDED = new Set(['active']);
3
4
  const FAILED = new Set([
@@ -313,7 +314,7 @@ export function reconcileDeployedRef({ requested, actual, deploymentId, }) {
313
314
  if (actual === requested)
314
315
  return actual;
315
316
  const short = (sha) => sha.slice(0, 8);
316
- throw new Error([
317
+ throw new FabricPreconditionError([
317
318
  `Refusing to continue: deployment ${deploymentId} is pinned to ${short(actual)}, not the ${short(requested)} you asked for.`,
318
319
  'A deployment already parked for this branch was attached to rather than a new one being cut,',
319
320
  'so continuing would deploy a different commit than the one named.',
@@ -1,9 +1,18 @@
1
+ import { PikkuError } from '@pikku/core/errors';
1
2
  /**
2
3
  * Local git probes for the deploy safety checks (clean tree, HEAD == remote,
3
4
  * ref resolution). Shell out to `git` rather than depend on simple-git —
4
5
  * matches what wrangler/vercel/fly do, no runtime dep.
5
6
  */
6
- export declare class GitError extends Error {
7
+ /**
8
+ * A `git` invocation that came back non-zero.
9
+ *
10
+ * A `PikkuError`, because the message already carries the whole diagnosis —
11
+ * which command, which exit code, and git's own stderr — and ten frames of the
12
+ * spawn helper in front of "fatal: not a git repository" answer a question
13
+ * nobody asked. `--verbose` / `PIKKU_DEBUG` still prints the stack.
14
+ */
15
+ export declare class GitError extends PikkuError {
7
16
  command: string;
8
17
  exitCode: number;
9
18
  stderr: string;
@@ -1,11 +1,20 @@
1
1
  import { spawn } from 'node:child_process';
2
2
  import { FabricPreconditionError } from './errors.js';
3
+ import { PikkuError } from '@pikku/core/errors';
3
4
  /**
4
5
  * Local git probes for the deploy safety checks (clean tree, HEAD == remote,
5
6
  * ref resolution). Shell out to `git` rather than depend on simple-git —
6
7
  * matches what wrangler/vercel/fly do, no runtime dep.
7
8
  */
8
- export class GitError extends Error {
9
+ /**
10
+ * A `git` invocation that came back non-zero.
11
+ *
12
+ * A `PikkuError`, because the message already carries the whole diagnosis —
13
+ * which command, which exit code, and git's own stderr — and ten frames of the
14
+ * spawn helper in front of "fatal: not a git repository" answer a question
15
+ * nobody asked. `--verbose` / `PIKKU_DEBUG` still prints the stack.
16
+ */
17
+ export class GitError extends PikkuError {
9
18
  command;
10
19
  exitCode;
11
20
  stderr;
@@ -1,12 +1,21 @@
1
1
  /**
2
- * Read a line from stdin with optional masking. Used for secret-set when the
3
- * user didn't pass `--value` on the command line so we can avoid leaving
4
- * the plaintext in shell history.
2
+ * Ask for a value that should not end up in shell history.
3
+ *
4
+ * With a tty this is a prompt. Without one — piped input, CI, an agent — the
5
+ * value is read from stdin instead, because scripting `pikku fabric secrets
6
+ * set` is a reasonable thing to want, and because a prompt with nobody to
7
+ * answer it is a hang. If stdin is closed or empty, `nonInteractiveHint` tells
8
+ * the caller which flag to reach for; it is raised as a `PikkuError` so
9
+ * `formatCLIError` prints that sentence and nothing else.
5
10
  */
6
- export declare function promptSecret(label: string): Promise<string>;
11
+ export declare function promptSecret(label: string, { nonInteractiveHint }: {
12
+ nonInteractiveHint: string;
13
+ }): Promise<string>;
7
14
  /**
8
15
  * Classic yes/no confirmation. Returns `defaultYes` on an empty answer.
9
16
  * Callers must gate on `process.stdin.isTTY` first — there is no human to
10
- * answer in a non-interactive session, so prompting there would hang.
17
+ * answer in a non-interactive session, so prompting there would hang. The
18
+ * guard below is the backstop for a caller that forgets: a refusal naming the
19
+ * question beats a process that never returns.
11
20
  */
12
21
  export declare function promptConfirm(label: string, defaultYes?: boolean): Promise<boolean>;
@@ -1,32 +1,95 @@
1
1
  import { createInterface } from 'node:readline/promises';
2
+ import { createInterface as createLineInterface } from 'node:readline';
2
3
  import { stdin, stdout } from 'node:process';
4
+ import { FabricPreconditionError } from './errors.js';
3
5
  /**
4
- * Read a line from stdin with optional masking. Used for secret-set when the
5
- * user didn't pass `--value` on the command line so we can avoid leaving
6
- * the plaintext in shell history.
6
+ * Read the first line stdin has to offer, or `null` if it has none.
7
+ *
8
+ * Resolves on the first newline rather than on EOF, so a pipe that stays open
9
+ * after the value has been written (a harness holding the write end, `cat |`)
10
+ * does not hang the command. `terminal: false` matters: readline's terminal
11
+ * mode tries to drive a tty it does not have, and on a closed stdin the
12
+ * `question()` promise it returns never settles at all — which is how
13
+ * `pikku fabric secrets set NAME < /dev/null` used to end in node's
14
+ * "Detected unsettled top-level await" warning instead of an error.
7
15
  */
8
- export async function promptSecret(label) {
16
+ const readFirstLine = async () => {
17
+ const rl = createLineInterface({ input: stdin, terminal: false });
18
+ try {
19
+ return await new Promise((resolve) => {
20
+ rl.once('line', (line) => resolve(line));
21
+ rl.once('close', () => resolve(null));
22
+ });
23
+ }
24
+ finally {
25
+ rl.close();
26
+ }
27
+ };
28
+ /**
29
+ * Ask for a value that should not end up in shell history.
30
+ *
31
+ * With a tty this is a prompt. Without one — piped input, CI, an agent — the
32
+ * value is read from stdin instead, because scripting `pikku fabric secrets
33
+ * set` is a reasonable thing to want, and because a prompt with nobody to
34
+ * answer it is a hang. If stdin is closed or empty, `nonInteractiveHint` tells
35
+ * the caller which flag to reach for; it is raised as a `PikkuError` so
36
+ * `formatCLIError` prints that sentence and nothing else.
37
+ */
38
+ export async function promptSecret(label, { nonInteractiveHint }) {
39
+ if (!stdin.isTTY) {
40
+ const piped = await readFirstLine();
41
+ const value = piped?.trim() ?? '';
42
+ if (!value) {
43
+ throw new FabricPreconditionError(`${label}: stdin is not a tty and nothing was piped in.\n${nonInteractiveHint}`);
44
+ }
45
+ return value;
46
+ }
9
47
  const rl = createInterface({ input: stdin, output: stdout, terminal: true });
10
48
  // Best-effort masking — the readline API doesn't suppress echo natively;
11
49
  // for hardened input you'd want `read -s` or a tty trick, but for our
12
50
  // CLI the standard prompt is fine and matches what wrangler does.
13
51
  process.stdout.write(`${label}: `);
14
- const value = await rl.question('');
15
- rl.close();
16
- return value.trim();
52
+ try {
53
+ // `question()` never rejects when the stream ends under it, so the close is
54
+ // raced explicitly: ^D at a prompt is an abort, not an infinite wait.
55
+ const value = await Promise.race([
56
+ rl.question(''),
57
+ new Promise((resolve) => rl.once('close', () => resolve(null))),
58
+ ]);
59
+ if (value === null) {
60
+ throw new FabricPreconditionError(`${label}: input closed before a value was given.\n${nonInteractiveHint}`);
61
+ }
62
+ return value.trim();
63
+ }
64
+ finally {
65
+ rl.close();
66
+ }
17
67
  }
18
68
  /**
19
69
  * Classic yes/no confirmation. Returns `defaultYes` on an empty answer.
20
70
  * Callers must gate on `process.stdin.isTTY` first — there is no human to
21
- * answer in a non-interactive session, so prompting there would hang.
71
+ * answer in a non-interactive session, so prompting there would hang. The
72
+ * guard below is the backstop for a caller that forgets: a refusal naming the
73
+ * question beats a process that never returns.
22
74
  */
23
75
  export async function promptConfirm(label, defaultYes = false) {
76
+ if (!stdin.isTTY) {
77
+ throw new FabricPreconditionError(`Cannot ask "${label}" — stdin is not a tty. Re-run interactively, or pass the flag that answers it (--force / --auto-approve / --yes).`);
78
+ }
24
79
  const rl = createInterface({ input: stdin, output: stdout });
25
- const answer = (await rl.question(`${label} [${defaultYes ? 'Y/n' : 'y/N'}] `))
26
- .trim()
27
- .toLowerCase();
28
- rl.close();
29
- if (!answer)
30
- return defaultYes;
31
- return answer === 'y' || answer === 'yes';
80
+ try {
81
+ const answer = await Promise.race([
82
+ rl.question(`${label} [${defaultYes ? 'Y/n' : 'y/N'}] `),
83
+ new Promise((resolve) => rl.once('close', () => resolve(null))),
84
+ ]);
85
+ if (answer === null)
86
+ return false;
87
+ const normalized = answer.trim().toLowerCase();
88
+ if (!normalized)
89
+ return defaultYes;
90
+ return normalized === 'y' || normalized === 'yes';
91
+ }
92
+ finally {
93
+ rl.close();
94
+ }
32
95
  }
@@ -16,6 +16,7 @@
16
16
  * business having one; opening a value happens in the worker.
17
17
  */
18
18
  import { createCipheriv, createPublicKey, diffieHellman, generateKeyPairSync, hkdfSync, randomBytes, } from 'node:crypto';
19
+ import { FabricPreconditionError } from './errors.js';
19
20
  /** Algorithm tag carried by every sealed value. Must match fabric's. */
20
21
  export const SEALED_BOX_ALGORITHM = 'sealed-x25519-v1';
21
22
  /** HKDF domain separator. Must match fabric's byte for byte. */
@@ -60,13 +61,13 @@ function importPublicKey(publicKey) {
60
61
  });
61
62
  }
62
63
  catch (error) {
63
- throw new Error(`Not a valid X25519 public key (${error instanceof Error ? error.message : String(error)})`);
64
+ throw new FabricPreconditionError(`Not a valid X25519 public key (${error instanceof Error ? error.message : String(error)})`);
64
65
  }
65
66
  // A public key of the wrong curve would still ECDH, just against a key the
66
67
  // stage's worker cannot match — the failure would surface as an unopenable
67
68
  // secret much later, so refuse it at the point the type is still knowable.
68
69
  if (key.asymmetricKeyType !== 'x25519') {
69
- throw new Error(`Stage sealing key is ${key.asymmetricKeyType}, expected x25519 — this CLI is too old for it, run \`npm i -g @pikku/cli\``);
70
+ throw new FabricPreconditionError(`Stage sealing key is ${key.asymmetricKeyType}, expected x25519 — this CLI is too old for it, run \`npm i -g @pikku/cli\``);
70
71
  }
71
72
  return key;
72
73
  }
@@ -1,3 +1,4 @@
1
+ import { FabricPreconditionError } from './errors.js';
1
2
  /**
2
3
  * Resolve a stage from (projectId, branch) via the `listStages` RPC. The
3
4
  * stageId-based read RPCs (listDeployments, listDeploymentWorkers,
@@ -22,13 +23,13 @@ export async function resolveStage(rpc, projectId, branch) {
22
23
  if (stages.length === 1 && only) {
23
24
  return { stageId: only.stageId, branch: only.branch };
24
25
  }
25
- throw new Error(stages.length === 0
26
+ throw new FabricPreconditionError(stages.length === 0
26
27
  ? 'No stages deployed for this project yet — run `pikku fabric deploy apply <branch>` first.'
27
28
  : `--branch is required — this project has ${stages.length} stages: ${known.join(', ')}`);
28
29
  }
29
30
  const stage = stages.find((s) => s.branch === branch);
30
31
  if (!stage) {
31
- throw new Error(`No stage for branch "${branch}".${known.length ? ` Existing: ${known.join(', ')}` : ''}`);
32
+ throw new FabricPreconditionError(`No stage for branch "${branch}".${known.length ? ` Existing: ${known.join(', ')}` : ''}`);
32
33
  }
33
34
  return { stageId: stage.stageId, branch: stage.branch };
34
35
  }
@@ -30,8 +30,11 @@ export const watch = pikkuSessionlessFunc({
30
30
  });
31
31
  }
32
32
  catch (err) {
33
- console.error(err);
34
- logger.error('Error running watch');
33
+ // Through the logger, so it obeys --log-level and the dev server's
34
+ // formatting. `console.error(err)` printed a bare stack over the top
35
+ // of the watch output no matter what verbosity was asked for.
36
+ logger.error(`Error running watch: ${err instanceof Error ? err.message : String(err)}`);
37
+ logger.debug(err instanceof Error ? (err.stack ?? '') : String(err));
35
38
  }
36
39
  };
37
40
  // A codegen pass holds a whole ts.Program, so two overlapping passes double
@@ -203,6 +203,7 @@ export const agentRoutes = defineHTTPRoutes({
203
203
  route: '${globalHTTPPrefix}/rpc/agent/:agentName/stream',
204
204
  method: 'post',
205
205
  sse: true,
206
+ streamProtocol: 'agui',
206
207
  func: agentStreamCaller,
207
208
  },
208
209
  agentApprove: {
@@ -214,6 +215,7 @@ export const agentRoutes = defineHTTPRoutes({
214
215
  route: '${globalHTTPPrefix}/rpc/agent/:agentName/resume',
215
216
  method: 'post',
216
217
  sse: true,
218
+ streamProtocol: 'agui',
217
219
  func: agentResumeCaller,
218
220
  },
219
221
  },
@@ -112,6 +112,7 @@ export function serializeChannelCLIClient(programName, programMeta, clientFile,
112
112
  : '';
113
113
  return `
114
114
  import { executeRawCLIViaChannel } from '@pikku/core/cli/channel'
115
+ import { formatCLIError, wantsStackTrace } from '@pikku/core/cli'
115
116
  import type { CorePikkuCLIClientRender } from '@pikku/core/cli/channel'
116
117
  import type { Capabilities } from '@pikku/core/channel'
117
118
  import { CorePikkuWebsocket } from '@pikku/websocket'
@@ -218,12 +219,25 @@ if (isDirectExecution) {
218
219
  ws = new WebSocket(url)
219
220
  }
220
221
 
222
+ // Whatever comes back is printed the way the rest of the CLI prints errors:
223
+ // a deliberate error as its message, anything unexpected with its stack, and
224
+ // either with a stack under --verbose / PIKKU_DEBUG.
225
+ const reportFatal = (error: unknown): void => {
226
+ // stderr is asynchronous when it is a pipe, so exiting on the next line can
227
+ // truncate the diagnostic. Exit from the write callback, with exitCode set
228
+ // first in case the stream is already gone and the callback never fires.
229
+ process.exitCode = 1
230
+ process.stderr.write(
231
+ formatCLIError(error, { verbose: wantsStackTrace(process.argv.slice(2)) }) + '\\n',
232
+ () => process.exit(1)
233
+ )
234
+ }
235
+ process.on('uncaughtException', reportFatal)
236
+ process.on('unhandledRejection', reportFatal)
237
+
221
238
  ${capitalizedName}CLIClient(ws, process.argv.slice(2))
222
239
  .then((exitCode) => process.exit(exitCode))
223
- .catch(error => {
224
- console.error('Fatal channel CLI error:', error)
225
- process.exit(1)
226
- })
240
+ .catch(reportFatal)
227
241
  }
228
242
  `;
229
243
  }
@@ -14,7 +14,7 @@ export function serializeLocalCLIBootstrap(programName, _programMeta, bootstrapF
14
14
  : null;
15
15
  const cliBootstrapPath = getFileImportRelativePath(bootstrapFile, config.bootstrapFile, config.packageMappings);
16
16
  return `
17
- import { executeCLI, CLIError } from '@pikku/core/cli'
17
+ import { executeCLI, CLIError, formatCLIError, wantsStackTrace } from '@pikku/core/cli'
18
18
  ${pikkuConfigFactory ? `import { ${pikkuConfigFactory.variable} as createConfig } from '${pikkuConfigPath}'` : ''}
19
19
  import { ${singletonServicesFactory.variable} as createSingletonServices } from '${singletonServicesPath}'
20
20
  ${wireServicesFactory ? `import { ${wireServicesFactory.variable} as createWireServices } from '${wireServicesPath}'` : ''}
@@ -44,10 +44,21 @@ export default ${capitalizedName}CLI
44
44
  ${DIRECT_EXECUTION_GUARD}
45
45
 
46
46
  if (isDirectExecution) {
47
- ${capitalizedName}CLI(process.argv.slice(2)).catch(error => {
48
- console.error('Fatal error:', error.message)
49
- process.exit(1)
50
- })
47
+ const reportFatal = (error: unknown): void => {
48
+ // executeCLI already printed a CLIError; it carries the exit code, not text.
49
+ if (error instanceof CLIError) process.exit(error.exitCode)
50
+ // stderr is asynchronous when it is a pipe, so exiting on the next line can
51
+ // truncate the diagnostic. Exit from the write callback, with exitCode set
52
+ // first in case the stream is already gone and the callback never fires.
53
+ process.exitCode = 1
54
+ process.stderr.write(
55
+ formatCLIError(error, { verbose: wantsStackTrace(process.argv.slice(2)) }) + '\\n',
56
+ () => process.exit(1)
57
+ )
58
+ }
59
+ process.on('uncaughtException', reportFatal)
60
+ process.on('unhandledRejection', reportFatal)
61
+ ${capitalizedName}CLI(process.argv.slice(2)).catch(reportFatal)
51
62
  }
52
63
  `;
53
64
  }
@@ -5,6 +5,25 @@ import { checkRequiredTypes } from '../../../utils/check-required-types.js';
5
5
  import { writeFileInDir } from '../../../utils/file-writer.js';
6
6
  import { logCommandInfoAndTime } from '../../../middleware/log-command-info-and-time.js';
7
7
  import { serializeAddonInstallTypes, serializeAddonTypes, } from './serialize-addon-types.js';
8
+ /**
9
+ * The functions each installed addon publishes, by package — what `mcp` on a
10
+ * `wireAddon` is typed against. A package wired twice contributes the same
11
+ * names under both namespaces, and a remote addon contributes none: its
12
+ * functions run on the host, and it is `wireRemoteAddon` that installs it.
13
+ */
14
+ const addonFunctionNames = (state) => {
15
+ const names = {};
16
+ for (const [namespace, decl] of state.rpc.wireAddonDeclarations) {
17
+ if (decl.remote) {
18
+ continue;
19
+ }
20
+ const meta = state.addonFunctions[namespace];
21
+ if (meta) {
22
+ names[decl.package] = Object.keys(meta);
23
+ }
24
+ }
25
+ return names;
26
+ };
8
27
  export const pikkuAddonTypes = pikkuSessionlessFunc({
9
28
  func: async ({ logger, config, getInspectorState }, input) => {
10
29
  const { addonTypesFile, addonSetupTypesFile, packageMappings, servicesFile, secretsFile, credentialsFile, variablesFile, } = config;
@@ -15,14 +34,16 @@ export const pikkuAddonTypes = pikkuSessionlessFunc({
15
34
  await rm(config.addon ? addonTypesFile : addonSetupTypesFile, {
16
35
  force: true,
17
36
  });
18
- // An application installs addons; an addon package declares itself. Both
19
- // halves are static, so the app half needs no inspector pass and is written
20
- // on the bootstrap run as readily as on the full one.
37
+ const bootstrap = input?.bootstrap === true;
38
+ // An application installs addons; an addon package declares itself. The app
39
+ // half is written on the bootstrap run too — `wireAddon` has to resolve
40
+ // before the inspector can read the calls that say which addons are
41
+ // installed — but only the full run knows what each addon publishes, so
42
+ // that is when `mcp` gets its names.
21
43
  if (!config.addon) {
22
- await writeFileInDir(logger, addonTypesFile, serializeAddonInstallTypes());
44
+ await writeFileInDir(logger, addonTypesFile, serializeAddonInstallTypes(bootstrap ? {} : addonFunctionNames(await getInspectorState())));
23
45
  return;
24
46
  }
25
- const bootstrap = input?.bootstrap === true;
26
47
  if (bootstrap) {
27
48
  await writeFileInDir(logger, addonSetupTypesFile, 'export {}\n');
28
49
  return;
@@ -10,5 +10,5 @@
10
10
  * `#pikku/addon/<leaf>` — a depth at which an application has nothing to match,
11
11
  * leaving the resolver to fall back to Node's per-package `imports`.
12
12
  */
13
- export declare const serializeAddonInstallTypes: () => string;
13
+ export declare const serializeAddonInstallTypes: (addonFunctionNames?: Record<string, string[]>) => string;
14
14
  export declare const serializeAddonTypes: (singletonServicesTypeImport: string, singletonServicesTypeName: string, configTypeImport: string, requiredServicesTypeImport: string, typedSecretServiceImport: string, typedVariablesServiceImport: string, typedCredentialServiceImport?: string | null) => string;
@@ -10,12 +10,57 @@
10
10
  * `#pikku/addon/<leaf>` — a depth at which an application has nothing to match,
11
11
  * leaving the resolver to fall back to Node's per-package `imports`.
12
12
  */
13
- export const serializeAddonInstallTypes = () => `/**
13
+ export const serializeAddonInstallTypes = (addonFunctionNames = {}) => {
14
+ const packages = Object.entries(addonFunctionNames).filter(([, names]) => names.length > 0);
15
+ // Nothing installed yet — the bootstrap run writes this before any addon's
16
+ // metadata has been read, and a project with no addons never gets more.
17
+ if (packages.length === 0) {
18
+ return `/**
14
19
  * Installing an addon into this application
15
20
  */
16
21
 
17
22
  export { wireAddon, wireRemoteAddon } from '@pikku/core/addon'
18
23
  `;
24
+ }
25
+ const entries = packages
26
+ .map(([pkg, names]) => ` ${JSON.stringify(pkg)}: ${names
27
+ .map((name) => JSON.stringify(name))
28
+ .join(' | ')}`)
29
+ .join('\n');
30
+ return `/**
31
+ * Installing an addon into this application
32
+ */
33
+
34
+ import { wireAddon as wireAddonCore } from '@pikku/core/addon'
35
+ import type { WireAddonConfig } from '@pikku/core/addon'
36
+
37
+ export { wireRemoteAddon } from '@pikku/core/addon'
38
+
39
+ /**
40
+ * The functions each installed addon publishes. \`mcp\` names them.
41
+ */
42
+ type AddonFunctions = {
43
+ ${entries}
44
+ }
45
+
46
+ type AddonFunctionName<Package extends string> =
47
+ Package extends keyof AddonFunctions ? AddonFunctions[Package] : string
48
+
49
+ /**
50
+ * Installs an addon into this project: its functions, wirings and scopes become
51
+ * part of the app, under the namespace and options given here.
52
+ *
53
+ * \`mcp: true\` offers every function the addon itself declared as a tool; a list
54
+ * names the functions to offer, checked against the ones the addon publishes.
55
+ */
56
+ export const wireAddon = <Package extends string>(
57
+ config: Omit<WireAddonConfig, 'package' | 'mcp'> & {
58
+ package: Package
59
+ mcp?: boolean | AddonFunctionName<Package>[]
60
+ }
61
+ ): void => wireAddonCore(config)
62
+ `;
63
+ };
19
64
  export const serializeAddonTypes = (singletonServicesTypeImport, singletonServicesTypeName, configTypeImport, requiredServicesTypeImport, typedSecretServiceImport, typedVariablesServiceImport, typedCredentialServiceImport = null) => {
20
65
  return `/**
21
66
  * Addon package types for pikkuAddonConfig and pikkuAddonServices
@@ -44,7 +44,9 @@ const generateArgumentsFromSchema = async (inputSchema, schemaDirectory, typesMa
44
44
  }
45
45
  catch (e) {
46
46
  logger.warn(`Command MCP: Could not load schema for type: ${uniqueName} from ${schemaPath}`);
47
- console.error(e);
47
+ // The warning above is the actionable half; the cause is detail, and detail
48
+ // belongs behind the verbosity control rather than on everyone's stderr.
49
+ logger.debug(e instanceof Error ? (e.stack ?? e.message) : String(e));
48
50
  return [];
49
51
  }
50
52
  };
@@ -13,10 +13,22 @@ export const pikkuMiddleware = pikkuSessionlessFunc({
13
13
  const hasDefinitions = Object.keys(state.middleware.definitions).length > 0;
14
14
  const hasChannelMiddleware = state.channelMiddleware.tagMiddleware.size > 0 ||
15
15
  Object.keys(state.channelMiddleware.definitions).length > 0;
16
+ // A project whose only middleware is `addGlobalMiddleware([...])` over
17
+ // middleware defined in a package (a session bridge, say) has no group and
18
+ // no local definition, and used to generate no middleware file at all — so
19
+ // the registration never ran.
20
+ // `globalFiles` is the current record, but the serializer also still reads
21
+ // `global:*` out of `instances` so that a state serialized by an older
22
+ // inspector keeps working. This gate decides whether the serializer runs at
23
+ // all, so it has to accept exactly what the serializer accepts — otherwise
24
+ // an older state is dropped here and the file it needed is never written.
25
+ const hasGlobalMiddleware = (state.middleware.globalFiles?.size ?? 0) > 0 ||
26
+ Object.keys(state.middleware.instances).some((id) => id.startsWith('global:'));
16
27
  if (hasHTTPGroups ||
17
28
  hasTagGroups ||
18
29
  hasDefinitions ||
19
- hasChannelMiddleware) {
30
+ hasChannelMiddleware ||
31
+ hasGlobalMiddleware) {
20
32
  const metaData = state.middlewareGroupsMeta;
21
33
  await writeFileInDir(logger, config.middlewareGroupsMetaJsonFile, JSON.stringify(metaData, null, 2));
22
34
  await writeFileInDir(logger, middlewareFile, serializeMiddlewareImports(middlewareFile, middleware, state.http, packageMappings, state));
@@ -1,2 +1,15 @@
1
1
  import type { InspectorMiddlewareState, InspectorHTTPState, InspectorState } from '@pikku/inspector';
2
2
  export declare const serializeMiddlewareImports: (outputPath: string, middlewareState: InspectorMiddlewareState, httpState: InspectorHTTPState, packageMappings?: Record<string, string>, fullState?: InspectorState) => string;
3
+ /**
4
+ * Fail the build if a file that calls `addGlobalMiddleware` has no side-effect
5
+ * import in the generated middleware file.
6
+ *
7
+ * Auth commonly lives in global middleware, and a deployed unit that misses its
8
+ * import does not fail to build — it serves every authenticated route a 401
9
+ * with a clean build log. Checking the emitted text (rather than the set it was
10
+ * built from) is what makes this a check and not a restatement: it fails if the
11
+ * emit is ever dropped, put behind a condition, or handed a path the import
12
+ * list does not actually carry. It cannot fire on a build that does emit the
13
+ * import.
14
+ */
15
+ export declare const assertGlobalMiddlewareImported: (outputPath: string, output: string, globalImportPaths: Map<string, string>) => void;
@@ -54,21 +54,34 @@ export const serializeMiddlewareImports = (outputPath, middlewareState, httpStat
54
54
  // Global middleware (addGlobalMiddleware) is registered by a top-level call
55
55
  // at module evaluation, so a side-effect import of its source file runs the
56
56
  // registration. Unlike tag/http middleware it has no associated wire group —
57
- // it lives only in `instances` keyed `global:*` — so the per-unit `--names`
58
- // filter leaves it out of every deployed unit (the `state.http.files`
59
- // fallback that add-middleware adds gets stripped by that filter). Emitting
60
- // it here, into the always-bootstrap-imported pikku-middleware.gen.ts,
61
- // guarantees global middleware registers in every unit. A duplicate import
62
- // in full builds is harmless — module bodies evaluate once.
57
+ // the inspector records it as a source file in `globalFiles` (and as
58
+ // `global:*` entries in `instances`) — so the per-unit `--names` filter
59
+ // leaves it out of every deployed unit (the `state.http.files` fallback that
60
+ // add-middleware adds gets stripped by that filter). Emitting it here, into
61
+ // the always-bootstrap-imported pikku-middleware.gen.ts, guarantees global
62
+ // middleware registers in every unit. A duplicate import in full builds is
63
+ // harmless — module bodies evaluate once.
63
64
  //
64
65
  // `isFactoryCall` is not consulted: it distinguishes `mw()` from `mw` as an
65
66
  // array element, not a deferred registration behind an exported factory, and
66
67
  // addGlobalMiddleware registers at module evaluation under either form.
68
+ //
69
+ // `globalFiles` is the primary source: it is a plain set of file names, where
70
+ // `instances` is a map whose keys an unrelated registration could once
71
+ // collide with. The `global:*` sweep stays as well, so a state serialized by
72
+ // an older inspector (no `globalFiles`) still emits its imports.
73
+ const globalSourceFiles = new Set(middlewareState.globalFiles ?? []);
67
74
  for (const [instanceId, instance] of Object.entries(middlewareState.instances)) {
68
75
  if (instanceId.startsWith('global:')) {
69
- directImports.add(getFileImportRelativePath(outputPath, instance.sourceFile, packageMappings));
76
+ globalSourceFiles.add(instance.sourceFile);
70
77
  }
71
78
  }
79
+ const globalImportPaths = new Map();
80
+ for (const sourceFile of globalSourceFiles) {
81
+ const filePath = getFileImportRelativePath(outputPath, sourceFile, packageMappings);
82
+ globalImportPaths.set(sourceFile, filePath);
83
+ directImports.add(filePath);
84
+ }
72
85
  const allFactories = new Map([
73
86
  ...httpFactories,
74
87
  ...tagFactories,
@@ -90,5 +103,32 @@ export const serializeMiddlewareImports = (outputPath, middlewareState, httpStat
90
103
  serializedFactoryCalls.push(`${exportName}()`);
91
104
  }
92
105
  }
93
- return [...serializedImports, ...serializedFactoryCalls].join('\n');
106
+ const output = [...serializedImports, ...serializedFactoryCalls].join('\n');
107
+ assertGlobalMiddlewareImported(outputPath, output, globalImportPaths);
108
+ return output;
109
+ };
110
+ /**
111
+ * Fail the build if a file that calls `addGlobalMiddleware` has no side-effect
112
+ * import in the generated middleware file.
113
+ *
114
+ * Auth commonly lives in global middleware, and a deployed unit that misses its
115
+ * import does not fail to build — it serves every authenticated route a 401
116
+ * with a clean build log. Checking the emitted text (rather than the set it was
117
+ * built from) is what makes this a check and not a restatement: it fails if the
118
+ * emit is ever dropped, put behind a condition, or handed a path the import
119
+ * list does not actually carry. It cannot fire on a build that does emit the
120
+ * import.
121
+ */
122
+ export const assertGlobalMiddlewareImported = (outputPath, output, globalImportPaths) => {
123
+ const missing = [...globalImportPaths.entries()].filter(([, filePath]) => !output.includes(`import '${filePath}'`));
124
+ if (missing.length === 0) {
125
+ return;
126
+ }
127
+ throw new Error(`Global middleware would not be registered in ${outputPath}.\n` +
128
+ `These files call addGlobalMiddleware() but no side-effect import for them was emitted:\n` +
129
+ missing.map(([sourceFile]) => ` - ${sourceFile}`).join('\n') +
130
+ `\n\nGlobal middleware — auth gates included — only runs if its module is imported, so ` +
131
+ `this build would start up with it silently missing. Re-run \`pikku all\`; if it persists, ` +
132
+ `register the middleware from a file that also makes a wire registration ` +
133
+ `(e.g. addHTTPMiddleware) and report this as a pikku bug.`);
94
134
  };