@pikku/cli 0.12.118 → 0.12.119

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 (247) hide show
  1. package/CHANGELOG.md +172 -0
  2. package/console-app/assets/{abnfDiagram-N423BO3Z-WNIAg_Oa.js → abnfDiagram-N423BO3Z-CiK5F2ml.js} +1 -1
  3. package/console-app/assets/architecture-TIHT7OUA-FMO1RByN.js +1 -0
  4. package/console-app/assets/{architectureDiagram-T3A2C74G-DM698mgf.js → architectureDiagram-T3A2C74G-g4Elcs_0.js} +1 -1
  5. package/console-app/assets/{blockDiagram-VBNYF7ZC-DPfy9K5S.js → blockDiagram-VBNYF7ZC-CI6muc3M.js} +1 -1
  6. package/console-app/assets/{c4Diagram-5PPSVZJV-DhLbbBbX.js → c4Diagram-5PPSVZJV-CjzL9yGp.js} +1 -1
  7. package/console-app/assets/channel-Dp8A5NJg.js +1 -0
  8. package/console-app/assets/{chunk-2GRJ4B5K-C1RQ1gvs.js → chunk-2GRJ4B5K-C68TKOLb.js} +1 -1
  9. package/console-app/assets/{chunk-4I5QYGJK-BkzSdNc_.js → chunk-4I5QYGJK-D_DINIPO.js} +1 -1
  10. package/console-app/assets/{chunk-5RXB4S5H-DZpBpdcU.js → chunk-5RXB4S5H-D8mEuiea.js} +1 -1
  11. package/console-app/assets/{chunk-6Q2QTUOP-mZObxdld.js → chunk-6Q2QTUOP-CVNqLnb8.js} +1 -1
  12. package/console-app/assets/{chunk-7Z6QIM7H-C0HbxZEa.js → chunk-7Z6QIM7H-Bnih6HyS.js} +1 -1
  13. package/console-app/assets/{chunk-GF5L2VYU-DXPVwWqW.js → chunk-GF5L2VYU-C5efrbFt.js} +1 -1
  14. package/console-app/assets/{chunk-I66GZJ75-pVpq9ckD.js → chunk-I66GZJ75-dckv50K3.js} +1 -1
  15. package/console-app/assets/{chunk-JQJVKLGR-DJQ8K4wK.js → chunk-JQJVKLGR-HirBo6LQ.js} +1 -1
  16. package/console-app/assets/{chunk-KBJHAD2P-B8XuxRCO.js → chunk-KBJHAD2P-lknhmPj0.js} +1 -1
  17. package/console-app/assets/{chunk-NSK5VX7P-cYzQU4bD.js → chunk-NSK5VX7P-tGAl7zxF.js} +1 -1
  18. package/console-app/assets/{chunk-QR6OTTB3-CNoTFsqn.js → chunk-QR6OTTB3-BlSKCrEq.js} +1 -1
  19. package/console-app/assets/{chunk-RYQCIY6F-DoKRUO_N.js → chunk-RYQCIY6F-CwQmwEV-.js} +1 -1
  20. package/console-app/assets/{chunk-UBXNYLIW-BqcIoUpU.js → chunk-UBXNYLIW-D1Dn6ZK0.js} +1 -1
  21. package/console-app/assets/{chunk-W5SLKNZC-p0Qalbjj.js → chunk-W5SLKNZC-DOkZHhST.js} +1 -1
  22. package/console-app/assets/{chunk-WRU74C26-DUMn96Dr.js → chunk-WRU74C26-CB4orIKm.js} +1 -1
  23. package/console-app/assets/chunk-XXDRQBXY-BMybY6E-.js +1 -0
  24. package/console-app/assets/classDiagram-JCYQIIEL-C-K-UAUR.js +1 -0
  25. package/console-app/assets/classDiagram-v2-OCEON4UE-C-K-UAUR.js +1 -0
  26. package/console-app/assets/{cose-bilkent-JH36ORCC-BCh3BlPI.js → cose-bilkent-JH36ORCC-stBhaqpU.js} +1 -1
  27. package/console-app/assets/{cynefin-VYW2F7L2-ZfghUZsD.js → cynefin-VYW2F7L2-Bb1nmKWZ.js} +1 -1
  28. package/console-app/assets/{cynefinDiagram-MW4NZA55-DcV3QXCe.js → cynefinDiagram-MW4NZA55-Bp8fMJi-.js} +1 -1
  29. package/console-app/assets/{dagre-BPFWXLBN.js → dagre-DshmzimC.js} +1 -1
  30. package/console-app/assets/{dagre-VZM6K2ZE-DETshBO-.js → dagre-VZM6K2ZE-DIl1klf5.js} +1 -1
  31. package/console-app/assets/{diagram-7IWD3JNH-CsLX3P2o.js → diagram-7IWD3JNH-DdkSOxKT.js} +1 -1
  32. package/console-app/assets/{diagram-B4RE2ZJO-o2zcxm5S.js → diagram-B4RE2ZJO-9Dj9O4L8.js} +1 -1
  33. package/console-app/assets/{diagram-LBJQPF4R-BD2zKU21.js → diagram-LBJQPF4R-CxBb73tU.js} +1 -1
  34. package/console-app/assets/{diagram-Q27KOJAE-DHaacyna.js → diagram-Q27KOJAE-CPpUmnvb.js} +1 -1
  35. package/console-app/assets/{diagram-UB23O5K3-pSLCMUyV.js → diagram-UB23O5K3-7wV_Db6W.js} +1 -1
  36. package/console-app/assets/{ebnfDiagram-BXEA7PRR-BDzawX3O.js → ebnfDiagram-BXEA7PRR-Cxzbf8pk.js} +1 -1
  37. package/console-app/assets/{erDiagram-JOGREHBK-CyYnPmbN.js → erDiagram-JOGREHBK-BBPLq83P.js} +1 -1
  38. package/console-app/assets/eventmodeling-45OFAUF4-CLUnygIv.js +1 -0
  39. package/console-app/assets/flowDiagram-UKHOOZJN-D3mDcWWx.js +1 -0
  40. package/console-app/assets/{ganttDiagram-PKOTCBZU-3fhCBbPA.js → ganttDiagram-PKOTCBZU-Erh7WK4H.js} +1 -1
  41. package/console-app/assets/{gitGraph-TEB2WS4Q-CdLRkVux.js → gitGraph-TEB2WS4Q-o5FLRF57.js} +1 -1
  42. package/console-app/assets/{gitGraphDiagram-DS77QQ5N-CC1epdKw.js → gitGraphDiagram-DS77QQ5N-BFbsaenX.js} +1 -1
  43. package/console-app/assets/{index-GruDnAhJ.css → index-Mq-YbqNO.css} +1 -1
  44. package/console-app/assets/{index-BRmokG9t.js → index-w2ZoJr8X.js} +178 -178
  45. package/console-app/assets/{info-DKCQHKI2-BJs8WkzC.js → info-DKCQHKI2-Dkcrdr1w.js} +1 -1
  46. package/console-app/assets/{infoDiagram-6WML65LV-uoOwoIeI.js → infoDiagram-6WML65LV-iZVC5Wzy.js} +1 -1
  47. package/console-app/assets/{ishikawaDiagram-WSZJBQD7-vCUJhwTi.js → ishikawaDiagram-WSZJBQD7-BjV8LLeA.js} +1 -1
  48. package/console-app/assets/{journeyDiagram-NVQOT4AX-D2QcIlLG.js → journeyDiagram-NVQOT4AX-D3rpLjYi.js} +1 -1
  49. package/console-app/assets/{kanban-definition-27J2QSJJ-JwwKowmR.js → kanban-definition-27J2QSJJ-Dds5TFyv.js} +1 -1
  50. package/console-app/assets/{line-h2oRreYF.js → line-D1rUAT18.js} +1 -1
  51. package/console-app/assets/{linear-Dz002X_a.js → linear-fQ_6Sc79.js} +1 -1
  52. package/console-app/assets/{mermaid-parser.core-DTgmT0AA.js → mermaid-parser.core-B9Q-4IXF.js} +3 -3
  53. package/console-app/assets/{mermaid.core-1jSEDr-j.js → mermaid.core-bPhADShw.js} +4 -4
  54. package/console-app/assets/{mindmap-definition-FAOFIHXS-C3Txxhj4.js → mindmap-definition-FAOFIHXS-CULlU6Fy.js} +1 -1
  55. package/console-app/assets/{packet-7NZHBO7P-BGG7zIK2.js → packet-7NZHBO7P-DpwzoQpc.js} +1 -1
  56. package/console-app/assets/{pegDiagram-VL7TDLO6--g1r_rov.js → pegDiagram-VL7TDLO6-B9fKKc4F.js} +1 -1
  57. package/console-app/assets/{pie-RZYD4A2V-C5OepMH7.js → pie-RZYD4A2V-DkXpqWAI.js} +1 -1
  58. package/console-app/assets/{pieDiagram-7S7Q4E2Y-DGD_LzGm.js → pieDiagram-7S7Q4E2Y-Bcpn2rUM.js} +1 -1
  59. package/console-app/assets/{quadrantDiagram-CIZ2JOQS-CyBQQlD2.js → quadrantDiagram-CIZ2JOQS-Bd5wWFj_.js} +1 -1
  60. package/console-app/assets/{radar-I7S5WNFK-CaBOAO95.js → radar-I7S5WNFK-ylw-u3HI.js} +1 -1
  61. package/console-app/assets/{railroad-3IZDKUUU-2aTWN4Pw.js → railroad-3IZDKUUU-D4LMucL-.js} +1 -1
  62. package/console-app/assets/railroad-abnf-AHOZXSZD-CRTVzK1g.js +1 -0
  63. package/console-app/assets/railroad-ebnf-EBAXGLYW-CB13ugAF.js +1 -0
  64. package/console-app/assets/railroad-peg-LSFZ7HO6-AN8zyQYp.js +1 -0
  65. package/console-app/assets/{railroadDiagram-AXF67PYL-3Nr0rlTp.js → railroadDiagram-AXF67PYL-CZukQql9.js} +1 -1
  66. package/console-app/assets/{requirementDiagram-LRYGKXZP-BN7sEwSa.js → requirementDiagram-LRYGKXZP-Ou4nRENK.js} +1 -1
  67. package/console-app/assets/{sankeyDiagram-W5VNT64P-CXZR46wO.js → sankeyDiagram-W5VNT64P-BKdG-c_o.js} +1 -1
  68. package/console-app/assets/{sequenceDiagram-SI44F4Z6-DNtmdJ4U.js → sequenceDiagram-SI44F4Z6-Dc7d5obe.js} +1 -1
  69. package/console-app/assets/{src-x1E3pJJ-.js → src-BFb2oeKx.js} +1 -1
  70. package/console-app/assets/{stateDiagram-OKZ733FA-B_GyYdl_.js → stateDiagram-OKZ733FA-BA9fuN7b.js} +1 -1
  71. package/console-app/assets/stateDiagram-v2-UEYNNEHI-D13a6mUd.js +1 -0
  72. package/console-app/assets/{swimlanes-SLNWSIFB-D4N7VdF7.js → swimlanes-SLNWSIFB-l-ETgM83.js} +1 -1
  73. package/console-app/assets/swimlanesDiagram-ULZ7WXOC-BsC-B2Z9.js +8 -0
  74. package/console-app/assets/{timeline-definition-Z64GVDOM-DU5rsOWQ.js → timeline-definition-Z64GVDOM-Uj_ByeVr.js} +1 -1
  75. package/console-app/assets/{treeView-QDETBFTQ-DaKM_9sB.js → treeView-QDETBFTQ-BvFRkVGY.js} +1 -1
  76. package/console-app/assets/{treemap-6X3UGDF4-BabsKtZY.js → treemap-6X3UGDF4-BV5T7Dw9.js} +1 -1
  77. package/console-app/assets/{vennDiagram-T6HMQDX7-Dniftpq0.js → vennDiagram-T6HMQDX7-DAFU8gAo.js} +1 -1
  78. package/console-app/assets/{wardley-OPB4EBWU-BWffQNys.js → wardley-OPB4EBWU-MLNuhuiA.js} +1 -1
  79. package/console-app/assets/{wardleyDiagram-T6FBY63Y-CQ74fVdn.js → wardleyDiagram-T6FBY63Y-B1lCTfi1.js} +1 -1
  80. package/console-app/assets/{xychartDiagram-ELKLHX3M-D-XxbGIL.js → xychartDiagram-ELKLHX3M-Bw3zhuWc.js} +1 -1
  81. package/console-app/index.html +2 -2
  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/auth/index.d.ts +1 -1
  91. package/dist/.pikku/auth/index.js +1 -1
  92. package/dist/.pikku/auth/pikku-auth-types.gen.d.ts +1 -1
  93. package/dist/.pikku/auth/pikku-auth-types.gen.js +1 -1
  94. package/dist/.pikku/channel/index.d.ts +1 -1
  95. package/dist/.pikku/channel/index.js +1 -1
  96. package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
  97. package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
  98. package/dist/.pikku/cli/index.d.ts +1 -1
  99. package/dist/.pikku/cli/index.js +1 -1
  100. package/dist/.pikku/cli/pikku-cli-channel.js +1 -1
  101. package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +1 -1
  102. package/dist/.pikku/cli/pikku-cli-client.gen.js +1 -1
  103. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.d.ts +1 -1
  104. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.js +1 -1
  105. package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
  106. package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
  107. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
  108. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +2 -9
  109. package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
  110. package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
  111. package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
  112. package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
  113. package/dist/.pikku/error/index.d.ts +1 -1
  114. package/dist/.pikku/error/index.js +1 -1
  115. package/dist/.pikku/error/pikku-error-types.gen.d.ts +1 -1
  116. package/dist/.pikku/error/pikku-error-types.gen.js +1 -1
  117. package/dist/.pikku/function/index.d.ts +1 -1
  118. package/dist/.pikku/function/index.js +1 -1
  119. package/dist/.pikku/function/pikku-function-types.gen.d.ts +1 -1
  120. package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
  121. package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
  122. package/dist/.pikku/function/pikku-functions-meta.gen.json +8 -6
  123. package/dist/.pikku/function/pikku-functions.gen.js +1 -3
  124. package/dist/.pikku/gateway/index.d.ts +1 -1
  125. package/dist/.pikku/gateway/index.js +1 -1
  126. package/dist/.pikku/gateway/pikku-gateway-types.gen.d.ts +1 -1
  127. package/dist/.pikku/gateway/pikku-gateway-types.gen.js +1 -1
  128. package/dist/.pikku/http/index.d.ts +1 -1
  129. package/dist/.pikku/http/index.js +1 -1
  130. package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
  131. package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
  132. package/dist/.pikku/mcp/index.d.ts +1 -1
  133. package/dist/.pikku/mcp/index.js +1 -1
  134. package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
  135. package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
  136. package/dist/.pikku/middleware/index.d.ts +1 -1
  137. package/dist/.pikku/middleware/index.js +1 -1
  138. package/dist/.pikku/middleware/pikku-middleware-types.gen.d.ts +1 -1
  139. package/dist/.pikku/middleware/pikku-middleware-types.gen.js +1 -1
  140. package/dist/.pikku/pikku-bootstrap-scenarios.gen.d.ts +1 -1
  141. package/dist/.pikku/pikku-bootstrap-scenarios.gen.js +1 -1
  142. package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
  143. package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
  144. package/dist/.pikku/pikku-services.gen.d.ts +1 -1
  145. package/dist/.pikku/queue/index.d.ts +1 -1
  146. package/dist/.pikku/queue/index.js +1 -1
  147. package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
  148. package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
  149. package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
  150. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
  151. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
  152. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
  153. package/dist/.pikku/scenarios/index.d.ts +1 -1
  154. package/dist/.pikku/scenarios/index.js +1 -1
  155. package/dist/.pikku/scenarios/pikku-personas.gen.d.ts +11 -0
  156. package/dist/.pikku/scenarios/pikku-personas.gen.js +12 -1
  157. package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.js +1 -1
  158. package/dist/.pikku/scenarios/pikku-scenario-functions.gen.d.ts +1 -1
  159. package/dist/.pikku/scenarios/pikku-scenario-types.gen.d.ts +1 -1
  160. package/dist/.pikku/scenarios/pikku-scenario-wirings-meta.gen.js +1 -1
  161. package/dist/.pikku/scenarios/pikku-scenario-wirings.gen.d.ts +1 -1
  162. package/dist/.pikku/scenarios/schemas/register.gen.d.ts +1 -1
  163. package/dist/.pikku/scenarios/schemas/register.gen.js +1 -1
  164. package/dist/.pikku/scheduler/index.d.ts +1 -1
  165. package/dist/.pikku/scheduler/index.js +1 -1
  166. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
  167. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
  168. package/dist/.pikku/schemas/register.gen.js +1 -1
  169. package/dist/.pikku/schemas/schemas/PersonaSyncInput.schema.json +1 -1
  170. package/dist/.pikku/scopes/index.d.ts +1 -1
  171. package/dist/.pikku/scopes/index.js +1 -1
  172. package/dist/.pikku/scopes/pikku-personas.gen.js +1 -1
  173. package/dist/.pikku/scopes/pikku-roles.gen.d.ts +1 -1
  174. package/dist/.pikku/scopes/pikku-scope-types.gen.d.ts +1 -1
  175. package/dist/.pikku/scopes/pikku-scope-types.gen.js +1 -1
  176. package/dist/.pikku/scopes/pikku-scopes.gen.d.ts +1 -1
  177. package/dist/.pikku/secrets/index.d.ts +1 -1
  178. package/dist/.pikku/secrets/index.js +1 -1
  179. package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
  180. package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
  181. package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
  182. package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
  183. package/dist/.pikku/services/pikku-meta-service.gen.d.ts +1 -1
  184. package/dist/.pikku/services/pikku-meta-service.gen.js +1 -1
  185. package/dist/.pikku/setup/index.d.ts +1 -1
  186. package/dist/.pikku/setup/index.js +1 -1
  187. package/dist/.pikku/setup/pikku-setup-types.gen.d.ts +1 -1
  188. package/dist/.pikku/setup/pikku-setup-types.gen.js +1 -1
  189. package/dist/.pikku/trigger/index.d.ts +1 -1
  190. package/dist/.pikku/trigger/index.js +1 -1
  191. package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
  192. package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
  193. package/dist/.pikku/variables/index.d.ts +1 -1
  194. package/dist/.pikku/variables/index.js +1 -1
  195. package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
  196. package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
  197. package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
  198. package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
  199. package/dist/.pikku/workflow/index.d.ts +1 -1
  200. package/dist/.pikku/workflow/index.js +1 -1
  201. package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
  202. package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
  203. package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
  204. package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
  205. package/dist/bin/pikku-bin.mjs +2 -2
  206. package/dist/src/cli.wiring.js +1 -9
  207. package/dist/src/fabric/lib/git.js +31 -1
  208. package/dist/src/functions/commands/dev.js +2 -0
  209. package/dist/src/functions/commands/persona-sync.d.ts +14 -22
  210. package/dist/src/functions/commands/persona-sync.js +29 -107
  211. package/dist/src/functions/commands/serve.js +2 -0
  212. package/dist/src/functions/validate/auth-plugin-checks.d.ts +16 -0
  213. package/dist/src/functions/validate/auth-plugin-checks.js +165 -0
  214. package/dist/src/functions/validate/persona-checks.js +1 -1
  215. package/dist/src/functions/validate/shared-checks.js +12 -0
  216. package/dist/src/functions/validate/websocket-deps-checks.d.ts +30 -0
  217. package/dist/src/functions/validate/websocket-deps-checks.js +42 -0
  218. package/dist/src/functions/wirings/personas/serialize-personas-secrets.d.ts +1 -1
  219. package/dist/src/functions/wirings/personas/serialize-personas-secrets.js +1 -1
  220. package/dist/src/functions/wirings/scopes/pikku-command-scopes.d.ts +10 -0
  221. package/dist/src/functions/wirings/scopes/pikku-command-scopes.js +20 -3
  222. package/dist/src/functions/wirings/workflow/pikku-command-workflow.js +1 -1
  223. package/dist/src/functions/wirings/workflow/serialize-personas.d.ts +2 -1
  224. package/dist/src/functions/wirings/workflow/serialize-personas.js +20 -1
  225. package/dist/src/server/actor-sign-in.d.ts +5 -0
  226. package/dist/src/server/actor-sign-in.js +27 -0
  227. package/dist/src/server/node-server-runner.d.ts +11 -0
  228. package/dist/src/server/node-server-runner.js +33 -8
  229. package/dist/src/services.js +3 -1
  230. package/dist/src/utils/resolve-from-project.d.ts +29 -0
  231. package/dist/src/utils/resolve-from-project.js +45 -0
  232. package/dist/tsconfig.tsbuildinfo +1 -1
  233. package/package.json +18 -10
  234. package/snippets.json +1 -1
  235. package/surface.json +2 -2
  236. package/console-app/assets/architecture-TIHT7OUA-CIT-Nug2.js +0 -1
  237. package/console-app/assets/channel-DQC6cL1c.js +0 -1
  238. package/console-app/assets/chunk-XXDRQBXY-Dgz5VbWO.js +0 -1
  239. package/console-app/assets/classDiagram-JCYQIIEL-1ASFocNV.js +0 -1
  240. package/console-app/assets/classDiagram-v2-OCEON4UE-1ASFocNV.js +0 -1
  241. package/console-app/assets/eventmodeling-45OFAUF4-BYJ0A5k-.js +0 -1
  242. package/console-app/assets/flowDiagram-UKHOOZJN-CVn87uiP.js +0 -1
  243. package/console-app/assets/railroad-abnf-AHOZXSZD-TU7k5gB_.js +0 -1
  244. package/console-app/assets/railroad-ebnf-EBAXGLYW-DbArPBkM.js +0 -1
  245. package/console-app/assets/railroad-peg-LSFZ7HO6-TzB93z4K.js +0 -1
  246. package/console-app/assets/stateDiagram-v2-UEYNNEHI-D7V_HITc.js +0 -1
  247. package/console-app/assets/swimlanesDiagram-ULZ7WXOC-C4XcIHKT.js +0 -8
@@ -0,0 +1,165 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { readdir, readFile } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ const lines = (...parts) => parts.join('\n');
5
+ /** Local rather than imported from shared-checks, which imports this module. */
6
+ const readTextSafe = async (path) => {
7
+ if (!existsSync(path))
8
+ return null;
9
+ try {
10
+ return await readFile(path, 'utf8');
11
+ }
12
+ catch {
13
+ return null;
14
+ }
15
+ };
16
+ const stringArray = (value) => Array.isArray(value)
17
+ ? value.filter((v) => typeof v === 'string')
18
+ : [];
19
+ /**
20
+ * Source files under one directory, generated files included — better-auth is
21
+ * routinely configured in a file the auth scaffold wrote.
22
+ */
23
+ const listSourceFiles = async (dir) => {
24
+ if (!existsSync(dir))
25
+ return [];
26
+ try {
27
+ return (await readdir(dir, { recursive: true }))
28
+ .filter((f) => typeof f === 'string' &&
29
+ (f.endsWith('.ts') || f.endsWith('.tsx')) &&
30
+ !f.includes('node_modules'))
31
+ .map((f) => join(dir, f));
32
+ }
33
+ catch {
34
+ return [];
35
+ }
36
+ };
37
+ /**
38
+ * The text inside every `plugins: [...]` array in the file.
39
+ *
40
+ * Bracket-counted rather than parsed: `pikku validate` runs without a TypeScript
41
+ * program, and a `]` inside a string literal in a plugin's options is the only
42
+ * way this misreads an array — at which point the check under-reports rather
43
+ * than inventing a finding.
44
+ */
45
+ const pluginArrays = (text) => {
46
+ const arrays = [];
47
+ const opener = /plugins\s*:\s*\[/g;
48
+ let match;
49
+ while ((match = opener.exec(text))) {
50
+ const start = match.index + match[0].length;
51
+ let depth = 1;
52
+ let i = start;
53
+ while (i < text.length && depth > 0) {
54
+ if (text[i] === '[')
55
+ depth++;
56
+ else if (text[i] === ']')
57
+ depth--;
58
+ i++;
59
+ }
60
+ if (depth === 0)
61
+ arrays.push(text.slice(start, i - 1));
62
+ }
63
+ return arrays;
64
+ };
65
+ const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
66
+ /**
67
+ * How `exported` from `module` can be called in this file: the local name a
68
+ * named import bound it to, or `<namespace>.<exported>` for a namespace import.
69
+ * Empty when the file never imports it, so a local helper of the same name is
70
+ * not mistaken for the package's.
71
+ */
72
+ const importedCallees = (text, module, exported) => {
73
+ const callees = [];
74
+ const imports = /import\s+([\s\S]*?)\s+from\s*['"]([^'"]+)['"]/g;
75
+ let match;
76
+ while ((match = imports.exec(text))) {
77
+ if (match[2] !== module)
78
+ continue;
79
+ const clause = match[1];
80
+ const namespace = clause.match(/\*\s+as\s+([A-Za-z_$][\w$]*)/);
81
+ if (namespace) {
82
+ callees.push(`${namespace[1]}.${exported}`);
83
+ continue;
84
+ }
85
+ const named = clause.match(/\{([\s\S]*?)\}/);
86
+ if (!named)
87
+ continue;
88
+ for (const entry of named[1].split(',')) {
89
+ const [imported, alias] = entry.split(/\s+as\s+/).map((v) => v.trim());
90
+ if (imported === exported)
91
+ callees.push(alias || imported);
92
+ }
93
+ }
94
+ return callees;
95
+ };
96
+ /**
97
+ * Whether `exported` from `module` is wired as a plugin — imported from that
98
+ * package *and* called inside a `plugins: [...]` array. An import left behind
99
+ * after the call was removed configures nothing, and a call somewhere else in
100
+ * the file is not a plugin.
101
+ */
102
+ const configuresPlugin = (text, module, exported) => {
103
+ const callees = importedCallees(text, module, exported);
104
+ if (callees.length === 0)
105
+ return false;
106
+ return pluginArrays(text).some((array) => callees.some((callee) => new RegExp(`(^|[^\\w$.])${escapeRegExp(callee)}\\s*\\(`).test(array)));
107
+ };
108
+ /**
109
+ * Whether better-auth is configured the way pikku supports.
110
+ *
111
+ * Pikku authorizes on scopes, so better-auth's `admin()` — which authorizes its
112
+ * endpoints against a `user.role` column — is unsupported: wiring it means
113
+ * running two authorization models and projecting one onto the other. The
114
+ * inspector refuses it outright at prebuild; this reports the same thing
115
+ * without one, and additionally catches the quieter half of the migration, an
116
+ * app that dropped `admin()` and never wired `ban()`, which keeps its ban
117
+ * columns and its ban UI while silently enforcing nothing.
118
+ */
119
+ export const runAuthPluginChecks = async (root, config) => {
120
+ const findings = [];
121
+ const srcDirectories = stringArray(config?.srcDirectories);
122
+ const searchDirs = srcDirectories.length
123
+ ? srcDirectories
124
+ : [join('packages', 'functions', 'src')];
125
+ const sourceFiles = (await Promise.all(searchDirs.map((dir) => listSourceFiles(join(root, dir))))).flat();
126
+ let bansAnywhere = false;
127
+ const adminFiles = [];
128
+ for (const file of sourceFiles) {
129
+ const text = await readTextSafe(file);
130
+ if (!text)
131
+ continue;
132
+ if (configuresPlugin(text, 'better-auth/plugins', 'admin'))
133
+ adminFiles.push(file);
134
+ if (configuresPlugin(text, '@pikku/better-auth', 'ban'))
135
+ bansAnywhere = true;
136
+ }
137
+ for (const file of adminFiles) {
138
+ findings.push({
139
+ id: 'better-auth-admin-plugin',
140
+ severity: 'error',
141
+ message: "better-auth's admin() plugin is not supported — it authorizes against a user.role column while pikku authorizes on scopes, so one has to be projected onto the other",
142
+ path: file,
143
+ fixHint: lines('Replace it with ban(), which keeps the one capability admin() had that', 'pikku cannot supply from outside better-auth — refusing a banned user a', 'session:', " import { ban } from '@pikku/better-auth'", ' betterAuth({ plugins: [ban()] })', 'User management is already scoped RPCs in @pikku/addon-admin: list,', 'create, ban, remove, revoke sessions and set password.'),
144
+ });
145
+ }
146
+ if (!bansAnywhere && adminFiles.length === 0) {
147
+ const configuresAuth = sourceFiles.length > 0;
148
+ if (configuresAuth) {
149
+ for (const file of sourceFiles) {
150
+ const text = await readTextSafe(file);
151
+ if (!text || !/\bpikkuBetterAuth\s*\(/.test(text))
152
+ continue;
153
+ findings.push({
154
+ id: 'better-auth-no-ban-plugin',
155
+ severity: 'warn',
156
+ message: 'better-auth is configured without ban() — the banned/banReason/banExpires columns do not exist, so banning a user through @pikku/addon-admin has nothing to write and nothing refuses their next sign-in',
157
+ path: file,
158
+ fixHint: lines(" import { ban } from '@pikku/better-auth'", ' betterAuth({ plugins: [ban()] })', 'Wire it wherever the rest of your plugins are, then run', '`pikku db migrate` to add the columns.'),
159
+ });
160
+ break;
161
+ }
162
+ }
163
+ }
164
+ return findings;
165
+ };
@@ -123,7 +123,7 @@ export const runPersonaChecks = async (root, config) => {
123
123
  return findings;
124
124
  }
125
125
  if (!(await hasActorSignIn(sourceFiles))) {
126
- w('personas-no-actor-sign-in', `${personas} persona${personas === 1 ? ' is' : 's are'} declared, but nothing wires actor sign-in — a scenario run signs in over POST /auth/sign-in/actor, so every persona fails to acquire a session`, pikkuConfigPath, lines('Wire the actor plugin where better-auth is configured:', " import { actor } from '@pikku/better-auth'", ' plugins: [actor({ secret: SCENARIO_ACTOR_SECRET })]', 'The plugin refuses every sign-in while the secret is unset, so a stage', 'that must not run scenarios simply leaves SCENARIO_ACTOR_SECRET out.'));
126
+ w('personas-no-actor-sign-in', `${personas} persona${personas === 1 ? ' is' : 's are'} declared, but nothing wires actor sign-in — a scenario run signs in over POST /auth/sign-in/actor, so every persona fails to acquire a session`, pikkuConfigPath, lines('Wire the actor plugin where better-auth is configured:', " import { actor } from '@pikku/better-auth'", ' plugins: [actor({ secret: SCENARIO_ACTOR_SECRET })]', '`pikku dev` turns the endpoint on and mints the secret itself, so there', 'is nothing to configure locally. A deployed stage that must run', 'scenarios opts in with', 'PIKKU_ALLOW_ACTOR_SIGN_IN=passwordless-actor-sign-in; everywhere else', 'the endpoint stays off whatever the environment happens to contain.'));
127
127
  }
128
128
  const environments = config?.environments;
129
129
  const hasEnvironment = typeof environments === 'object' &&
@@ -4,7 +4,10 @@ import { join } from 'node:path';
4
4
  import { runKnowledgeValidate } from '@pikku/knowledge';
5
5
  import { runBootstrapChecks } from './bootstrap-checks.js';
6
6
  import { runPersonaChecks } from './persona-checks.js';
7
+ import { runAuthPluginChecks } from './auth-plugin-checks.js';
7
8
  import { runScenarioFileChecks } from './scenario-file-checks.js';
9
+ import { projectWiresChannels, runWebsocketDepsChecks, } from './websocket-deps-checks.js';
10
+ import { resolveFromProject } from '../../utils/resolve-from-project.js';
8
11
  /**
9
12
  * A malformed config is named, never reported as absent.
10
13
  *
@@ -311,8 +314,17 @@ export async function runSharedProjectChecks(root) {
311
314
  }
312
315
  // ── server bootstrap ───────────────────────────────────────────────────
313
316
  findings.push(...(await runBootstrapChecks(root, rootPkg, pikkuConfig)));
317
+ findings.push(...runWebsocketDepsChecks({
318
+ root,
319
+ runtime: typeof globalThis.Bun !== 'undefined'
320
+ ? 'bun'
321
+ : 'node',
322
+ hasChannels: await projectWiresChannels(root, typeof pikkuConfig?.outDir === 'string' ? pikkuConfig.outDir : '.pikku'),
323
+ resolve: (specifier) => resolveFromProject(root, specifier),
324
+ }));
314
325
  // ── personas, scenario files and the knowledge base ────────────────────
315
326
  findings.push(...(await runPersonaChecks(root, pikkuConfig)));
327
+ findings.push(...(await runAuthPluginChecks(root, pikkuConfig)));
316
328
  const srcDirectories = Array.isArray(pikkuConfig?.srcDirectories)
317
329
  ? pikkuConfig.srcDirectories.filter((d) => typeof d === 'string')
318
330
  : [];
@@ -0,0 +1,30 @@
1
+ import type { ValidateFinding } from './persona-checks.js';
2
+ /**
3
+ * The packages the Node dev/serve path needs to speak WebSocket. Both are
4
+ * optional peers of `@pikku/cli`, because Bun serves WebSockets natively
5
+ * through `@pikku/bun-server` and a Bun project has no use for either.
6
+ */
7
+ export declare const NODE_WEBSOCKET_PACKAGES: readonly ["@pikku/ws", "ws"];
8
+ export type WebsocketDepsInput = {
9
+ root: string;
10
+ /** The runtime the CLI is running on. Bun needs neither package. */
11
+ runtime: 'node' | 'bun';
12
+ /** Whether the project wires any channels. Nothing is reported when not. */
13
+ hasChannels: boolean;
14
+ /** Resolves a specifier from the project. `undefined` when not installed. */
15
+ resolve: (specifier: string) => string | undefined;
16
+ };
17
+ /**
18
+ * Reports the optional WebSocket peers when a Node-hosted project that wires
19
+ * channels is missing them.
20
+ *
21
+ * `pikku dev` / `pikku serve` under Node start over plain HTTP when the
22
+ * packages are absent, rather than failing: a project with no channels does not
23
+ * need them, and making them hard dependencies of the CLI is what put a second
24
+ * `@pikku/core` in the tree. That leaves a project that *does* wire channels
25
+ * with sockets that never connect and nothing pointing at the cause — which is
26
+ * this check.
27
+ */
28
+ export declare function runWebsocketDepsChecks(input: WebsocketDepsInput): ValidateFinding[];
29
+ /** True when codegen produced at least one channel for this project. */
30
+ export declare function projectWiresChannels(root: string, outDir: string): Promise<boolean>;
@@ -0,0 +1,42 @@
1
+ import { join } from 'node:path';
2
+ import { readJsonSafe } from './shared-checks.js';
3
+ /**
4
+ * The packages the Node dev/serve path needs to speak WebSocket. Both are
5
+ * optional peers of `@pikku/cli`, because Bun serves WebSockets natively
6
+ * through `@pikku/bun-server` and a Bun project has no use for either.
7
+ */
8
+ export const NODE_WEBSOCKET_PACKAGES = ['@pikku/ws', 'ws'];
9
+ /**
10
+ * Reports the optional WebSocket peers when a Node-hosted project that wires
11
+ * channels is missing them.
12
+ *
13
+ * `pikku dev` / `pikku serve` under Node start over plain HTTP when the
14
+ * packages are absent, rather than failing: a project with no channels does not
15
+ * need them, and making them hard dependencies of the CLI is what put a second
16
+ * `@pikku/core` in the tree. That leaves a project that *does* wire channels
17
+ * with sockets that never connect and nothing pointing at the cause — which is
18
+ * this check.
19
+ */
20
+ export function runWebsocketDepsChecks(input) {
21
+ const { root, runtime, hasChannels, resolve } = input;
22
+ if (runtime === 'bun' || !hasChannels)
23
+ return [];
24
+ const missing = NODE_WEBSOCKET_PACKAGES.filter((name) => !resolve(name));
25
+ if (missing.length === 0)
26
+ return [];
27
+ const named = missing.join(' and ');
28
+ return [
29
+ {
30
+ id: 'websocket-deps-missing',
31
+ severity: 'error',
32
+ message: `${named} ${missing.length > 1 ? 'are' : 'is'} not installed, but this project wires channels — \`pikku dev\` and \`pikku serve\` will start without WebSocket support and every channel connection will fail`,
33
+ path: join(root, 'package.json'),
34
+ fixHint: `Install ${NODE_WEBSOCKET_PACKAGES.join(' ')} in this project. They are optional peer dependencies of @pikku/cli so that Bun projects, which serve WebSockets natively, do not pull them in`,
35
+ },
36
+ ];
37
+ }
38
+ /** True when codegen produced at least one channel for this project. */
39
+ export async function projectWiresChannels(root, outDir) {
40
+ const meta = await readJsonSafe(join(root, outDir, 'channel', 'pikku-channels-meta.gen.json'));
41
+ return !!meta && Object.keys(meta).length > 0;
42
+ }
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * `SCENARIO_ACTOR_SECRET` is the platform's, not the application's: nothing in
5
5
  * app code reads it. It is consumed by the scenario service when it signs an
6
- * actor in, by `pikku scenario` / `pikku persona` / `pikku persona sync`, and by
6
+ * actor in, by `pikku scenario` / `pikku persona`, and by
7
7
  * the Playwright provider. Declaring it here — rather than leaving every project
8
8
  * to hand-write the same `defineSecret` — is the same reasoning that puts
9
9
  * `BETTER_AUTH_SECRET` in the auth scaffold: a value the framework requires
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * `SCENARIO_ACTOR_SECRET` is the platform's, not the application's: nothing in
5
5
  * app code reads it. It is consumed by the scenario service when it signs an
6
- * actor in, by `pikku scenario` / `pikku persona` / `pikku persona sync`, and by
6
+ * actor in, by `pikku scenario` / `pikku persona`, and by
7
7
  * the Playwright provider. Declaring it here — rather than leaving every project
8
8
  * to hand-write the same `defineSecret` — is the same reasoning that puts
9
9
  * `BETTER_AUTH_SECRET` in the auth scaffold: a value the framework requires
@@ -1,3 +1,13 @@
1
+ import type { PersonaDefinitions } from '@pikku/core/persona';
2
+ import type { ScopeDefinitions } from '@pikku/core/scope';
3
+ /**
4
+ * The declared scopes, plus the `app` tree derived from the personas.
5
+ *
6
+ * Appended here rather than in the inspector because it is not a declaration
7
+ * the AST can find: it is the personas' `app` field read as a scope, and this
8
+ * is the one place the two states are both in hand.
9
+ */
10
+ export declare const withAppScopes: (scopes: ScopeDefinitions, personas: PersonaDefinitions) => ScopeDefinitions;
1
11
  export declare const pikkuScopes: import("#pikku/function").PikkuFunctionConfig<{
2
12
  bootstrap?: boolean;
3
13
  }, void, "rpc" | "session", import("#pikku/function").PikkuFunctionSessionless<{
@@ -4,6 +4,22 @@ import { logCommandInfoAndTime } from '../../../middleware/log-command-info-and-
4
4
  import { serializeScopesTypes } from './serialize-scopes-types.js';
5
5
  import { serializeScopesClient } from './serialize-scopes-client.js';
6
6
  import { validateAndBuildScopeDefinitionsMeta } from '@pikku/core/scope';
7
+ import { APP_SCOPE_ROOT, buildAppScopeDefinition } from '@pikku/core/persona';
8
+ /**
9
+ * The declared scopes, plus the `app` tree derived from the personas.
10
+ *
11
+ * Appended here rather than in the inspector because it is not a declaration
12
+ * the AST can find: it is the personas' `app` field read as a scope, and this
13
+ * is the one place the two states are both in hand.
14
+ */
15
+ export const withAppScopes = (scopes, personas) => {
16
+ const declared = scopes.find((scope) => scope.name === APP_SCOPE_ROOT);
17
+ if (declared) {
18
+ throw new Error(`'${APP_SCOPE_ROOT}' is reserved: it is derived from the apps your personas name, and ${declared.sourceFile ?? 'a defineScope call'} declares it too. Rename that scope root — two trees answering to one name make a grant ambiguous.`);
19
+ }
20
+ const appScopes = buildAppScopeDefinition(personas);
21
+ return appScopes ? [...scopes, appScopes] : scopes;
22
+ };
7
23
  export const pikkuScopes = pikkuSessionlessFunc({
8
24
  func: async ({ logger, config, getInspectorState }, data) => {
9
25
  const { scopesFile, scopesMetaJsonFile } = config;
@@ -19,15 +35,16 @@ export const pikkuScopes = pikkuSessionlessFunc({
19
35
  // Scopes step regenerates it with the declarations once setup has run.
20
36
  const bootstrap = data?.bootstrap ?? false;
21
37
  const state = await getInspectorState(false, bootstrap, bootstrap);
38
+ const definitions = withAppScopes(state.scopes.definitions, state.personas.definitions);
22
39
  const content = serializeScopesTypes({
23
- definitions: state.scopes.definitions,
40
+ definitions,
24
41
  });
25
42
  await writeFileInDir(logger, scopesFile, content);
26
43
  if (scopesClientFile) {
27
- await writeFileInDir(logger, scopesClientFile, serializeScopesClient({ definitions: state.scopes.definitions }));
44
+ await writeFileInDir(logger, scopesClientFile, serializeScopesClient({ definitions }));
28
45
  }
29
46
  if (scopesMetaJsonFile) {
30
- const meta = validateAndBuildScopeDefinitionsMeta(state.scopes.definitions);
47
+ const meta = validateAndBuildScopeDefinitionsMeta(definitions);
31
48
  await writeFileInDir(logger, scopesMetaJsonFile, JSON.stringify(meta, null, 2));
32
49
  }
33
50
  },
@@ -103,7 +103,7 @@ export const pikkuWorkflow = pikkuSessionlessFunc({
103
103
  {
104
104
  const agentMapImportPath = getFileImportRelativePath(config.personasWiringFile, config.agentMapDeclarationFile, packageMappings);
105
105
  const exposedRpcMapImportPath = getFileImportRelativePath(config.personasWiringFile, config.rpcMapDeclarationFile, packageMappings);
106
- await writeFileInDir(logger, config.personasWiringFile, serializePersonas(personas, agentMapImportPath, exposedRpcMapImportPath));
106
+ await writeFileInDir(logger, config.personasWiringFile, serializePersonas(personas, agentMapImportPath, exposedRpcMapImportPath, config.environments ?? {}));
107
107
  // Same reason as the scenario meta above: a project generated before this
108
108
  // moved to `scenarios/` still has a copy under `workflow/`, and tsc
109
109
  // compiles every file in the output tree whether anything imports it.
@@ -1,3 +1,4 @@
1
+ import type { PersonaEnvironment } from '@pikku/core/persona';
1
2
  import type { ResolvedPersona } from '@pikku/core/services';
2
3
  /**
3
4
  * The runtime half of `definePersonas()`.
@@ -7,4 +8,4 @@ import type { ResolvedPersona } from '@pikku/core/services';
7
8
  * to arrive at the same one. Baking them here is what makes that a single fact
8
9
  * rather than three implementations of the same rule.
9
10
  */
10
- export declare const serializePersonas: (personas: Record<string, ResolvedPersona>, agentMapImportPath: string, rpcMapImportPath: string) => string;
11
+ export declare const serializePersonas: (personas: Record<string, ResolvedPersona>, agentMapImportPath: string, rpcMapImportPath: string, environments?: Readonly<Record<string, PersonaEnvironment>>) => string;
@@ -6,7 +6,14 @@
6
6
  * to arrive at the same one. Baking them here is what makes that a single fact
7
7
  * rather than three implementations of the same rule.
8
8
  */
9
- export const serializePersonas = (personas, agentMapImportPath, rpcMapImportPath) => {
9
+ export const serializePersonas = (personas, agentMapImportPath, rpcMapImportPath, environments = {}) => {
10
+ // Only the flag the rule reads. The rest of an environment entry is its
11
+ // apiUrl and paths, which belong to the machine running `pikku scenario` and
12
+ // have no business inside the deployed bundle.
13
+ const projected = Object.fromEntries(Object.entries(environments).map(([name, environment]) => [
14
+ name,
15
+ environment.production ? { production: true } : {},
16
+ ]));
10
17
  return `/** Personas declared with definePersonas() */
11
18
  import { createHttpPersonas } from '@pikku/core/persona'
12
19
  import type { HttpPersonasConfig } from '@pikku/core/persona'
@@ -27,6 +34,18 @@ export type PersonaName = keyof typeof personaConfigs
27
34
  */
28
35
  export const personaList: ResolvedPersona[] = Object.values(personaConfigs)
29
36
 
37
+ /**
38
+ * The \`environments\` block of pikku.config.json, carried into the runtime.
39
+ *
40
+ * A persona's environments are checked twice: at build time against the config,
41
+ * and again wherever a persona is signed in or provisioned, against the
42
+ * environment the running process says it is (\`PIKKU_ENV\`). The second check
43
+ * is not the first one repeated — the build check trusts the file, and the run
44
+ * check does not trust which artifact got deployed — so the rule needs the
45
+ * config on both sides of the build.
46
+ */
47
+ export const personaEnvironments = ${JSON.stringify(projected, null, 2)} as const satisfies Record<string, { production?: boolean }>
48
+
30
49
  export type AgentName = keyof AgentMap & string
31
50
  /**
32
51
  * The personas this project declares, keyed by name — the \`actors\` a scenario
@@ -0,0 +1,5 @@
1
+ import type { Logger } from '@pikku/core/services';
2
+ export declare const ACTOR_SECRET_ENV = "SCENARIO_ACTOR_SECRET";
3
+ export declare const VITE_ACTOR_SECRET_ENV = "VITE_SCENARIO_ACTOR_SECRET";
4
+ export declare const enableDevActorSignIn: (logger: Logger) => void;
5
+ export declare const disableDevActorSignIn: (logger: Logger) => void;
@@ -0,0 +1,27 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import { ACTOR_SIGN_IN_OPT_IN_ENV, DEV_ACTOR_SIGN_IN_ENV, } from '@pikku/better-auth';
3
+ export const ACTOR_SECRET_ENV = 'SCENARIO_ACTOR_SECRET';
4
+ export const VITE_ACTOR_SECRET_ENV = 'VITE_SCENARIO_ACTOR_SECRET';
5
+ const mintEphemeralSecret = () => randomBytes(32).toString('base64url');
6
+ export const enableDevActorSignIn = (logger) => {
7
+ process.env[DEV_ACTOR_SIGN_IN_ENV] = 'true';
8
+ const configured = process.env[ACTOR_SECRET_ENV] || undefined;
9
+ const configuredForFrontend = process.env[VITE_ACTOR_SECRET_ENV] || undefined;
10
+ if (configured &&
11
+ configuredForFrontend &&
12
+ configured !== configuredForFrontend) {
13
+ logger.warn(`${ACTOR_SECRET_ENV} and ${VITE_ACTOR_SECRET_ENV} are set to different values — using ${ACTOR_SECRET_ENV}, since that is the one the server compares against`);
14
+ }
15
+ const secret = configured ?? configuredForFrontend ?? mintEphemeralSecret();
16
+ process.env[ACTOR_SECRET_ENV] = secret;
17
+ process.env[VITE_ACTOR_SECRET_ENV] = secret;
18
+ logger.info((configured ?? configuredForFrontend)
19
+ ? `Actor quick login enabled, using the ${configured ? ACTOR_SECRET_ENV : VITE_ACTOR_SECRET_ENV} already in this environment`
20
+ : 'Actor quick login enabled with a secret minted for this run — nothing to configure, and it is gone when the server stops');
21
+ };
22
+ export const disableDevActorSignIn = (logger) => {
23
+ if (process.env[DEV_ACTOR_SIGN_IN_ENV] !== undefined) {
24
+ logger.warn(`${DEV_ACTOR_SIGN_IN_ENV} was set in this environment and has been cleared — \`pikku serve\` never enables actor sign-in. Set ${ACTOR_SIGN_IN_OPT_IN_ENV} if this stage is meant to run scenarios.`);
25
+ }
26
+ delete process.env[DEV_ACTOR_SIGN_IN_ENV];
27
+ };
@@ -2,11 +2,22 @@
2
2
  * Node dev server runner — `@pikku/node-http-server` + the `ws` WebSocketServer.
3
3
  * Used when the CLI runs under Node. Owns the WebSocketServer so teardown
4
4
  * (close ws then the http server) is encapsulated in the returned instance.
5
+ *
6
+ * `@pikku/ws` and `ws` are optional peers of the CLI, so they are imported
7
+ * dynamically and resolved from the *project* rather than from the CLI: both
8
+ * peer on `@pikku/core`, and a copy loaded out of the CLI's own tree is paired
9
+ * with the CLI's core instead of the project's. A project without them served
10
+ * over plain HTTP — `pikku validate` reports the missing packages.
5
11
  */
6
12
  import type { EventHubService } from '@pikku/core/channel';
7
13
  import type { Logger } from '@pikku/core/services';
8
14
  import type { DevServerRunner, DevServerInstance, DevServerConfig, DevServerOptions } from './dev-server-runner.interface.js';
15
+ export declare const WEBSOCKET_PACKAGES_MISSING = "WebSocket support is disabled: @pikku/ws and ws are not installed in this project. Install them (npm install @pikku/ws ws) to serve channels over Node.";
9
16
  export declare class NodeServerRunner implements DevServerRunner {
17
+ private readonly rootDir;
18
+ private pikkuWs?;
19
+ private ws?;
20
+ constructor(rootDir: string);
10
21
  createEventHub(): Promise<EventHubService<any>>;
11
22
  createServer(config: DevServerConfig, logger: Logger, options?: DevServerOptions): DevServerInstance;
12
23
  }
@@ -2,23 +2,46 @@
2
2
  * Node dev server runner — `@pikku/node-http-server` + the `ws` WebSocketServer.
3
3
  * Used when the CLI runs under Node. Owns the WebSocketServer so teardown
4
4
  * (close ws then the http server) is encapsulated in the returned instance.
5
+ *
6
+ * `@pikku/ws` and `ws` are optional peers of the CLI, so they are imported
7
+ * dynamically and resolved from the *project* rather than from the CLI: both
8
+ * peer on `@pikku/core`, and a copy loaded out of the CLI's own tree is paired
9
+ * with the CLI's core instead of the project's. A project without them served
10
+ * over plain HTTP — `pikku validate` reports the missing packages.
5
11
  */
6
12
  import { LocalEventHubService } from '@pikku/core/channel/local';
7
13
  import { PikkuNodeHTTPServer } from '@pikku/node-http-server';
8
- import { DEFAULT_WS_MAX_PAYLOAD, pikkuWebsocketHandler } from '@pikku/ws';
9
- import { WebSocketServer } from 'ws';
14
+ import { cjsInterop, importFromProject } from '../utils/resolve-from-project.js';
15
+ export const WEBSOCKET_PACKAGES_MISSING = 'WebSocket support is disabled: @pikku/ws and ws are not installed in this project. Install them (npm install @pikku/ws ws) to serve channels over Node.';
10
16
  export class NodeServerRunner {
17
+ rootDir;
18
+ pikkuWs;
19
+ ws;
20
+ constructor(rootDir) {
21
+ this.rootDir = rootDir;
22
+ }
11
23
  async createEventHub() {
24
+ this.pikkuWs = await importFromProject(this.rootDir, '@pikku/ws');
25
+ const ws = await importFromProject(this.rootDir, 'ws');
26
+ this.ws = ws && cjsInterop(ws, 'WebSocketServer');
12
27
  return new LocalEventHubService();
13
28
  }
14
29
  createServer(config, logger, options = {}) {
15
- const wss = new WebSocketServer({
16
- noServer: true,
17
- maxPayload: DEFAULT_WS_MAX_PAYLOAD,
18
- });
30
+ const { pikkuWs, ws } = this;
31
+ if (!pikkuWs || !ws) {
32
+ logger.warn(WEBSOCKET_PACKAGES_MISSING);
33
+ }
34
+ const wss = pikkuWs && ws
35
+ ? new ws.WebSocketServer({
36
+ noServer: true,
37
+ maxPayload: pikkuWs.DEFAULT_WS_MAX_PAYLOAD,
38
+ })
39
+ : undefined;
19
40
  const server = new PikkuNodeHTTPServer(config, logger, {
20
41
  configureServer: (httpServer) => {
21
- pikkuWebsocketHandler({ server: httpServer, wss, logger });
42
+ if (pikkuWs && wss) {
43
+ pikkuWs.pikkuWebsocketHandler({ server: httpServer, wss, logger });
44
+ }
22
45
  },
23
46
  contentSigningJWT: options.contentSigningJWT,
24
47
  // Read off this options object by the transport, not off `config` — so it
@@ -29,7 +52,9 @@ export class NodeServerRunner {
29
52
  init: () => server.init(),
30
53
  start: () => server.start(),
31
54
  stop: async () => {
32
- await new Promise((resolve, reject) => wss.close((err) => (err ? reject(err) : resolve())));
55
+ if (wss) {
56
+ await new Promise((resolve, reject) => wss.close((err) => (err ? reject(err) : resolve())));
57
+ }
33
58
  await server.stop();
34
59
  },
35
60
  };
@@ -353,7 +353,9 @@ export const createSingletonServices = async (config) => {
353
353
  invalidateInspectorState,
354
354
  workflowService,
355
355
  bundler: isBun ? new BunBundler() : new NodeBundler(),
356
- devServerRunner: isBun ? new BunServerRunner() : new NodeServerRunner(),
356
+ devServerRunner: isBun
357
+ ? new BunServerRunner()
358
+ : new NodeServerRunner(rootDir),
357
359
  };
358
360
  };
359
361
  export const createWireServices = async ({ logger }, { cli, channel }) => {
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Resolves a package as the *project* would, not as the CLI would.
3
+ *
4
+ * The CLI is frequently run from somewhere that is not the project — `npx`
5
+ * unpacks it into `~/.npm/_npx/<hash>`, a monorepo hoists it to the workspace
6
+ * root — so a bare `import('pkg')` from CLI code finds the copy sitting next to
7
+ * the CLI. For a package that peers on `@pikku/core` that is the wrong copy:
8
+ * it gets paired with the CLI's core rather than the project's, and the version
9
+ * skew surfaces as a missing subpath export from a package the project never
10
+ * imported. Resolving against the project's own package.json keeps one core in
11
+ * play.
12
+ */
13
+ export declare const resolveFromProject: (rootDir: string, specifier: string) => string | undefined;
14
+ /**
15
+ * Recovers a CommonJS package's exports from an import by path.
16
+ *
17
+ * Node reconstructs a CJS module's named exports only when it is imported by
18
+ * bare specifier. Imported by absolute path — which is the whole point of
19
+ * resolving from the project — the namespace carries `default` and nothing
20
+ * else, so a package like `ws`, which hangs `WebSocketServer` off
21
+ * `module.exports`, arrives with the constructor apparently missing. `probe` is
22
+ * the export that decides which of the two shapes came back.
23
+ */
24
+ export declare const cjsInterop: <T>(mod: T, probe: string) => T;
25
+ /**
26
+ * Imports a package resolved from the project, or `undefined` when it is not
27
+ * installed there. Callers decide whether absence is fatal.
28
+ */
29
+ export declare const importFromProject: <T>(rootDir: string, specifier: string) => Promise<T | undefined>;
@@ -0,0 +1,45 @@
1
+ import { createRequire } from 'node:module';
2
+ import { join } from 'node:path';
3
+ /**
4
+ * Resolves a package as the *project* would, not as the CLI would.
5
+ *
6
+ * The CLI is frequently run from somewhere that is not the project — `npx`
7
+ * unpacks it into `~/.npm/_npx/<hash>`, a monorepo hoists it to the workspace
8
+ * root — so a bare `import('pkg')` from CLI code finds the copy sitting next to
9
+ * the CLI. For a package that peers on `@pikku/core` that is the wrong copy:
10
+ * it gets paired with the CLI's core rather than the project's, and the version
11
+ * skew surfaces as a missing subpath export from a package the project never
12
+ * imported. Resolving against the project's own package.json keeps one core in
13
+ * play.
14
+ */
15
+ export const resolveFromProject = (rootDir, specifier) => {
16
+ try {
17
+ return createRequire(join(rootDir, 'package.json')).resolve(specifier);
18
+ }
19
+ catch {
20
+ return undefined;
21
+ }
22
+ };
23
+ /**
24
+ * Recovers a CommonJS package's exports from an import by path.
25
+ *
26
+ * Node reconstructs a CJS module's named exports only when it is imported by
27
+ * bare specifier. Imported by absolute path — which is the whole point of
28
+ * resolving from the project — the namespace carries `default` and nothing
29
+ * else, so a package like `ws`, which hangs `WebSocketServer` off
30
+ * `module.exports`, arrives with the constructor apparently missing. `probe` is
31
+ * the export that decides which of the two shapes came back.
32
+ */
33
+ export const cjsInterop = (mod, probe) => probe in mod
34
+ ? mod
35
+ : (mod.default ?? mod);
36
+ /**
37
+ * Imports a package resolved from the project, or `undefined` when it is not
38
+ * installed there. Callers decide whether absence is fatal.
39
+ */
40
+ export const importFromProject = async (rootDir, specifier) => {
41
+ const resolved = resolveFromProject(rootDir, specifier);
42
+ if (!resolved)
43
+ return undefined;
44
+ return (await import(resolved));
45
+ };