@pikku/cli 0.12.93 → 0.12.99

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 (346) hide show
  1. package/console-app/assets/abnfDiagram-VRR7QNED-CytV-CG1.js +1 -0
  2. package/console-app/assets/arc-C5PvmnaA.js +1 -0
  3. package/console-app/assets/architecture-TIHT7OUA-C1_ScvPX.js +1 -0
  4. package/console-app/assets/architectureDiagram-ZJ3FMSHR-CJ2xb7C-.js +36 -0
  5. package/console-app/assets/array-BifhSqXX.js +1 -0
  6. package/console-app/assets/blockDiagram-677ZJIJ3-CCecrBrk.js +132 -0
  7. package/console-app/assets/c4Diagram-LMCZKHZV-CBnpukvQ.js +10 -0
  8. package/console-app/assets/channel-CwDOkXGI.js +1 -0
  9. package/console-app/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
  10. package/console-app/assets/chunk-32BRIVSS-D8qWWZRQ.js +1 -0
  11. package/console-app/assets/chunk-52WLFC77-BEpXHMsp.js +10 -0
  12. package/console-app/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
  13. package/console-app/assets/chunk-7BUUIJ7U-Bb538aSH.js +1 -0
  14. package/console-app/assets/chunk-C7G6YPKG-DsHUMkOp.js +1 -0
  15. package/console-app/assets/chunk-EX3LRPZG-mM7TjVx9.js +231 -0
  16. package/console-app/assets/chunk-FWX5IMBZ-CndRAn18.js +2 -0
  17. package/console-app/assets/chunk-HOUHSVGY-D1kT8umn.js +1 -0
  18. package/console-app/assets/chunk-ICXQ74PX-CeSaGyro.js +2 -0
  19. package/console-app/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
  20. package/console-app/assets/chunk-KEIR6QF5-DNzq6p3w.js +161 -0
  21. package/console-app/assets/chunk-MOJQB5TN-CaZOCHYr.js +88 -0
  22. package/console-app/assets/chunk-OGEWGWER-CnB1CsPt.js +1 -0
  23. package/console-app/assets/chunk-PUDLZKDR-BbGulHJm.js +156 -0
  24. package/console-app/assets/chunk-Q4XR5HBZ-BywwzeeR.js +70 -0
  25. package/console-app/assets/chunk-RYQCIY6F-CV0R1Adv.js +1 -0
  26. package/console-app/assets/chunk-V7JOEXUC-DGFaAWzB.js +206 -0
  27. package/console-app/assets/chunk-VAUOI2AC-DxPUd8Yb.js +1 -0
  28. package/console-app/assets/chunk-VR4S4FIN-D4-UaW_J.js +1 -0
  29. package/console-app/assets/chunk-WYO6CB5R-D_TFN0d9.js +127 -0
  30. package/console-app/assets/chunk-XXDRQBXY-BzVuweA_.js +1 -0
  31. package/console-app/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
  32. package/console-app/assets/chunk-ZGVPDNZ5-C6hdkGQb.js +62 -0
  33. package/console-app/assets/chunk-ZIRB5QZD-H-kepumB.js +32 -0
  34. package/console-app/assets/classDiagram-OUVF2IWQ-CTYJkTT0.js +1 -0
  35. package/console-app/assets/classDiagram-v2-EOCWNBFH-CTYJkTT0.js +1 -0
  36. package/console-app/assets/cose-bilkent-JH36ORCC-B6ZPxN6v.js +1 -0
  37. package/console-app/assets/cynefin-VYW2F7L2-D_nmxNz_.js +1 -0
  38. package/console-app/assets/cynefinDiagram-TSTJHNR4-CHy5QN0S.js +62 -0
  39. package/console-app/assets/cytoscape.esm-h6BdjjI9.js +321 -0
  40. package/console-app/assets/dagre-CXRCoUWR.js +1 -0
  41. package/console-app/assets/dagre-VKFMJZFB-DYfukM34.js +4 -0
  42. package/console-app/assets/defaultLocale-C8Fc0cco.js +1 -0
  43. package/console-app/assets/diagram-FQU43EPY-Dgb9TPSB.js +3 -0
  44. package/console-app/assets/diagram-G47NLZAW-CnFNZs9Z.js +24 -0
  45. package/console-app/assets/diagram-NH7WQ7WH-DN7h2DU-.js +24 -0
  46. package/console-app/assets/diagram-OA4YK3LP-RLaQaNtK.js +30 -0
  47. package/console-app/assets/diagram-WEI45ONY-DxHWhVGd.js +41 -0
  48. package/console-app/assets/dist-BaJNIo4I.js +1 -0
  49. package/console-app/assets/ebnfDiagram-CCIWWBDH-UN3Z81-l.js +1 -0
  50. package/console-app/assets/erDiagram-Q63AITRT-C9lGAY3i.js +85 -0
  51. package/console-app/assets/eventmodeling-45OFAUF4-Dc5wNSSK.js +1 -0
  52. package/console-app/assets/flowDiagram-23GEKE2U-zPyGHMi4.js +1 -0
  53. package/console-app/assets/ganttDiagram-NO4QXBWP-CvBjBcdK.js +292 -0
  54. package/console-app/assets/gitGraph-TEB2WS4Q-Cs5Z9jMo.js +1 -0
  55. package/console-app/assets/gitGraphDiagram-IHSO6WYX-B0i_IJ5r.js +106 -0
  56. package/console-app/assets/graphlib-B8gBHxth.js +1 -0
  57. package/console-app/assets/{index-CmAplHjZ.js → index-71U8EEj7.js} +155 -153
  58. package/console-app/assets/{index-BYj7ZbUU.css → index-BXMjqLQ5.css} +1 -1
  59. package/console-app/assets/info-DKCQHKI2-DHL0afNl.js +1 -0
  60. package/console-app/assets/infoDiagram-FWYZ7A6U-CBWykodX.js +2 -0
  61. package/console-app/assets/init-D6jRqBbL.js +1 -0
  62. package/console-app/assets/ishikawaDiagram-FXEZZL3T-DM377eW_.js +70 -0
  63. package/console-app/assets/journeyDiagram-5HDEW3XC-BpX_-Cns.js +139 -0
  64. package/console-app/assets/kanban-definition-HUTT4EX6-D3xFsQkO.js +89 -0
  65. package/console-app/assets/katex-Vhh-h91d.js +257 -0
  66. package/console-app/assets/line-CTSKHTE0.js +1 -0
  67. package/console-app/assets/linear-R5GlBvXT.js +1 -0
  68. package/console-app/assets/map-DsCK-0Cs.js +1 -0
  69. package/console-app/assets/mermaid-parser.core-CkHk4BPi.js +7 -0
  70. package/console-app/assets/mermaid.core-CcjGXuV6.js +11 -0
  71. package/console-app/assets/mindmap-definition-LN4V7U3C-CtolazqQ.js +96 -0
  72. package/console-app/assets/ordinal-hYBb2elL.js +1 -0
  73. package/console-app/assets/packet-7NZHBO7P-BxSOj_Ny.js +1 -0
  74. package/console-app/assets/path-BWPyau1x.js +1 -0
  75. package/console-app/assets/pegDiagram-2B236MQR-BNsMtxsM.js +1 -0
  76. package/console-app/assets/pie-RZYD4A2V-BbkKQBA5.js +1 -0
  77. package/console-app/assets/pieDiagram-ENE6RG2P-BAZLIz2f.js +39 -0
  78. package/console-app/assets/quadrantDiagram-ABIIQ3AL-Dpvn-1Fs.js +7 -0
  79. package/console-app/assets/radar-I7S5WNFK-B-uKXIAH.js +1 -0
  80. package/console-app/assets/railroad-3IZDKUUU-BHXXK04t.js +1 -0
  81. package/console-app/assets/railroad-abnf-AHOZXSZD-tXSQaBvY.js +1 -0
  82. package/console-app/assets/railroad-ebnf-EBAXGLYW-DG3aohR0.js +1 -0
  83. package/console-app/assets/railroad-peg-LSFZ7HO6-DY_gBA-x.js +1 -0
  84. package/console-app/assets/railroadDiagram-RFXS5EU6-DfUApEQj.js +1 -0
  85. package/console-app/assets/requirementDiagram-TGXJPOKE-B2zX0jqo.js +84 -0
  86. package/console-app/assets/rough.esm-CSKSodPl.js +1 -0
  87. package/console-app/assets/sankeyDiagram-HTMAVEWB-CbQ2zc7z.js +40 -0
  88. package/console-app/assets/sequenceDiagram-DBY2YBRQ-BLT8PXI_.js +162 -0
  89. package/console-app/assets/sizeCapture-X5ZJPWSS-B0uUizjq.js +1 -0
  90. package/console-app/assets/src-BLuPUFWW.js +1 -0
  91. package/console-app/assets/stateDiagram-2N3HPSRC-BvEyVp85.js +1 -0
  92. package/console-app/assets/stateDiagram-v2-6OUMAXLB-RGKS9iU4.js +1 -0
  93. package/console-app/assets/swimlanes-5IMT3BWC-1AZ459s6.js +2 -0
  94. package/console-app/assets/swimlanesDiagram-G3AALYLV-Ck_0-rfN.js +8 -0
  95. package/console-app/assets/timeline-definition-FHXFAJF6-dLuvH4s2.js +120 -0
  96. package/console-app/assets/treeView-QDETBFTQ-xL2msjo2.js +1 -0
  97. package/console-app/assets/treemap-6X3UGDF4-C98ichVP.js +1 -0
  98. package/console-app/assets/vennDiagram-L72KCM5P-HbUmidhv.js +34 -0
  99. package/console-app/assets/wardley-OPB4EBWU-C4gJS-m2.js +1 -0
  100. package/console-app/assets/wardleyDiagram-EHGQE667-B7b-LB02.js +78 -0
  101. package/console-app/assets/xychartDiagram-FW5EYKEG-Cm03zUGy.js +7 -0
  102. package/console-app/index.html +2 -2
  103. package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
  104. package/dist/.pikku/auth/auth.types.d.ts +1 -1
  105. package/dist/.pikku/auth/auth.types.js +1 -1
  106. package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
  107. package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
  108. package/dist/.pikku/cli/pikku-cli-channel.d.ts +13 -15
  109. package/dist/.pikku/cli/pikku-cli-channel.js +62 -8
  110. package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +14 -4
  111. package/dist/.pikku/cli/pikku-cli-client.gen.js +55 -18
  112. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.d.ts +1 -1
  113. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.js +1 -1
  114. package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
  115. package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
  116. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
  117. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +136 -10
  118. package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
  119. package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
  120. package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
  121. package/dist/.pikku/cli/pikku-cli.gen.js +18 -2
  122. package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
  123. package/dist/.pikku/function/pikku-function-types.gen.d.ts +64 -23
  124. package/dist/.pikku/function/pikku-function-types.gen.js +27 -1
  125. package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
  126. package/dist/.pikku/function/pikku-functions-meta.gen.json +171 -37
  127. package/dist/.pikku/function/pikku-functions.gen.js +13 -3
  128. package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
  129. package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
  130. package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
  131. package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
  132. package/dist/.pikku/pikku-bootstrap-scenarios.gen.d.ts +1 -1
  133. package/dist/.pikku/pikku-bootstrap-scenarios.gen.js +1 -1
  134. package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
  135. package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
  136. package/dist/.pikku/pikku-meta-service.gen.d.ts +1 -1
  137. package/dist/.pikku/pikku-meta-service.gen.js +1 -1
  138. package/dist/.pikku/pikku-services.gen.d.ts +2 -1
  139. package/dist/.pikku/pikku-services.gen.js +1 -0
  140. package/dist/.pikku/pikku-types.gen.d.ts +1 -1
  141. package/dist/.pikku/pikku-types.gen.js +1 -1
  142. package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
  143. package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
  144. package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
  145. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
  146. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
  147. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
  148. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +8 -1
  149. package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.js +1 -1
  150. package/dist/.pikku/scenarios/pikku-scenario-functions.gen.d.ts +1 -1
  151. package/dist/.pikku/scenarios/pikku-scenario-wirings-meta.gen.js +1 -1
  152. package/dist/.pikku/scenarios/pikku-scenario-wirings.gen.d.ts +1 -1
  153. package/dist/.pikku/scenarios/schemas/register.gen.d.ts +1 -1
  154. package/dist/.pikku/scenarios/schemas/register.gen.js +1 -1
  155. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
  156. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
  157. package/dist/.pikku/schemas/register.gen.js +15 -5
  158. package/dist/.pikku/schemas/schemas/DbResetInput.schema.json +1 -1
  159. package/dist/.pikku/schemas/schemas/PersonaRunInput.schema.json +1 -0
  160. package/dist/.pikku/schemas/schemas/PersonaSyncInput.schema.json +1 -0
  161. package/dist/.pikku/schemas/schemas/PikkuPersonasInput.schema.json +1 -0
  162. package/dist/.pikku/schemas/schemas/PikkuRolesInput.schema.json +1 -0
  163. package/dist/.pikku/schemas/schemas/PikkuVirtualUserFunctionsOutput.schema.json +1 -0
  164. package/dist/.pikku/schemas/schemas/RolesPruneInput.schema.json +1 -0
  165. package/dist/.pikku/scopes/pikku-personas-meta.gen.json +1 -0
  166. package/dist/.pikku/scopes/pikku-personas.gen.d.ts +36 -0
  167. package/dist/.pikku/scopes/pikku-personas.gen.js +17 -0
  168. package/dist/.pikku/scopes/pikku-roles-meta.gen.json +1 -0
  169. package/dist/.pikku/scopes/pikku-roles.gen.d.ts +30 -0
  170. package/dist/.pikku/scopes/pikku-roles.gen.js +18 -0
  171. package/dist/.pikku/scopes/pikku-scope-types.gen.d.ts +4 -2
  172. package/dist/.pikku/scopes/pikku-scope-types.gen.js +3 -2
  173. package/dist/.pikku/scopes/pikku-scopes.gen.d.ts +1 -1
  174. package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +2 -2
  175. package/dist/.pikku/secrets/pikku-secret-types.gen.js +2 -2
  176. package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
  177. package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
  178. package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
  179. package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
  180. package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +2 -2
  181. package/dist/.pikku/variables/pikku-variable-types.gen.js +2 -2
  182. package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
  183. package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
  184. package/dist/.pikku/workflow/meta/allWorkflow.gen.json +46 -16
  185. package/dist/.pikku/workflow/pikku-personas.gen.d.ts +15 -0
  186. package/dist/.pikku/workflow/pikku-personas.gen.js +17 -0
  187. package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +101 -24
  188. package/dist/.pikku/workflow/pikku-workflow-types.gen.js +22 -2
  189. package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
  190. package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
  191. package/dist/bin/pikku-bin.mjs +2 -2
  192. package/dist/bin/pikku.js +0 -0
  193. package/dist/src/cli.wiring.js +108 -8
  194. package/dist/src/deploy/analyzer/analyzer.js +14 -0
  195. package/dist/src/deploy/analyzer/manifest.d.ts +11 -0
  196. package/dist/src/fabric/functions/validate.function.js +77 -177
  197. package/dist/src/functions/commands/all.d.ts +1 -1
  198. package/dist/src/functions/commands/bootstrap.d.ts +1 -1
  199. package/dist/src/functions/commands/bootstrap.js +3 -0
  200. package/dist/src/functions/commands/db-audit.js +1 -1
  201. package/dist/src/functions/commands/db-baseline.js +1 -1
  202. package/dist/src/functions/commands/db-check.js +6 -5
  203. package/dist/src/functions/commands/db-codegen.js +1 -1
  204. package/dist/src/functions/commands/db-generate.js +1 -1
  205. package/dist/src/functions/commands/db-migrate.js +1 -1
  206. package/dist/src/functions/commands/db-reset.d.ts +15 -1
  207. package/dist/src/functions/commands/db-reset.js +18 -6
  208. package/dist/src/functions/commands/db-shared.d.ts +14 -0
  209. package/dist/src/functions/commands/deploy-info.d.ts +1 -1
  210. package/dist/src/functions/commands/dev-ai-runner.d.ts +16 -4
  211. package/dist/src/functions/commands/dev-ai-runner.js +63 -29
  212. package/dist/src/functions/commands/dev.js +10 -5
  213. package/dist/src/functions/commands/enable.d.ts +8 -8
  214. package/dist/src/functions/commands/enable.js +15 -19
  215. package/dist/src/functions/commands/{scenario-environment.d.ts → environment.d.ts} +9 -6
  216. package/dist/src/functions/commands/{scenario-environment.js → environment.js} +5 -4
  217. package/dist/src/functions/commands/new-addon.js +14 -14
  218. package/dist/src/functions/commands/persona-sync.d.ts +33 -0
  219. package/dist/src/functions/commands/persona-sync.js +151 -0
  220. package/dist/src/functions/commands/persona.d.ts +58 -0
  221. package/dist/src/functions/commands/persona.js +215 -0
  222. package/dist/src/functions/commands/roles-audit.d.ts +1 -0
  223. package/dist/src/functions/commands/roles-audit.js +37 -0
  224. package/dist/src/functions/commands/roles-prune.d.ts +16 -0
  225. package/dist/src/functions/commands/roles-prune.js +52 -0
  226. package/dist/src/functions/commands/roles-shared.d.ts +40 -0
  227. package/dist/src/functions/commands/roles-shared.js +77 -0
  228. package/dist/src/functions/commands/scenario-browser.d.ts +3 -3
  229. package/dist/src/functions/commands/scenario-browser.js +1 -1
  230. package/dist/src/functions/commands/scenario-ladder.d.ts +44 -2
  231. package/dist/src/functions/commands/scenario-ladder.js +52 -3
  232. package/dist/src/functions/commands/scenario.d.ts +7 -0
  233. package/dist/src/functions/commands/scenario.js +82 -18
  234. package/dist/src/functions/commands/scopes-shared.d.ts +12 -0
  235. package/dist/src/functions/commands/scopes-shared.js +2 -2
  236. package/dist/src/functions/commands/serve.js +8 -4
  237. package/dist/src/functions/commands/versions-check.js +3 -3
  238. package/dist/src/functions/commands/virtual-user-formatter.d.ts +30 -0
  239. package/dist/src/functions/commands/virtual-user-formatter.js +65 -0
  240. package/dist/src/functions/db/annotation-parser.d.ts +14 -0
  241. package/dist/src/functions/db/annotation-parser.js +50 -2
  242. package/dist/src/functions/db/better-auth-schema.js +2 -1
  243. package/dist/src/functions/db/db-codegen.d.ts +12 -0
  244. package/dist/src/functions/db/db-codegen.js +149 -16
  245. package/dist/src/functions/db/local-db.d.ts +87 -6
  246. package/dist/src/functions/db/local-db.js +239 -35
  247. package/dist/src/functions/db/sqlite/dev-seed.d.ts +12 -0
  248. package/dist/src/functions/db/sqlite/dev-seed.js +23 -0
  249. package/dist/src/functions/db/sqlite/sqlite-runtime-bun.js +1 -1
  250. package/dist/src/functions/validate/bootstrap-checks.d.ts +19 -0
  251. package/dist/src/functions/validate/bootstrap-checks.js +90 -0
  252. package/dist/src/functions/validate/persona-checks.d.ts +24 -0
  253. package/dist/src/functions/validate/persona-checks.js +136 -0
  254. package/dist/src/functions/validate/scenario-file-checks.d.ts +17 -0
  255. package/dist/src/functions/validate/scenario-file-checks.js +123 -0
  256. package/dist/src/functions/validate/shared-checks.d.ts +59 -0
  257. package/dist/src/functions/validate/shared-checks.js +311 -0
  258. package/dist/src/functions/validate/workspace-validate.d.ts +1 -2
  259. package/dist/src/functions/validate/workspace-validate.js +4 -196
  260. package/dist/src/functions/wirings/ai-agent/pikku-command-public-agent.js +2 -1
  261. package/dist/src/functions/wirings/ai-agent/serialize-public-agent.js +1 -0
  262. package/dist/src/functions/wirings/auth/serialize-auth-gen.d.ts +2 -2
  263. package/dist/src/functions/wirings/auth/serialize-auth-gen.js +24 -9
  264. package/dist/src/functions/wirings/auth/serialize-auth-types.d.ts +3 -1
  265. package/dist/src/functions/wirings/auth/serialize-auth-types.js +3 -1
  266. package/dist/src/functions/wirings/channels/pikku-channels.d.ts +1 -1
  267. package/dist/src/functions/wirings/channels/serialize-typed-channel-map.js +10 -2
  268. package/dist/src/functions/wirings/cli/pikku-command-cli-entry.js +9 -4
  269. package/dist/src/functions/wirings/cli/serialize-channel-cli-client.d.ts +7 -3
  270. package/dist/src/functions/wirings/cli/serialize-channel-cli-client.js +64 -28
  271. package/dist/src/functions/wirings/cli/serialize-channel-cli.js +63 -6
  272. package/dist/src/functions/wirings/cli/serialize-cli-entrypoint-guard.d.ts +12 -0
  273. package/dist/src/functions/wirings/cli/serialize-cli-entrypoint-guard.js +28 -0
  274. package/dist/src/functions/wirings/cli/serialize-local-cli-bootstrap.js +4 -1
  275. package/dist/src/functions/wirings/console/serialize-console-functions.js +5 -8
  276. package/dist/src/functions/wirings/functions/serialize-addon-types.js +1 -1
  277. package/dist/src/functions/wirings/functions/serialize-function-types.js +106 -32
  278. package/dist/src/functions/wirings/middleware/serialize-middleware-imports.js +25 -9
  279. package/dist/src/functions/wirings/package/pikku-command-package-types.d.ts +3 -3
  280. package/dist/src/functions/wirings/package/serialize-package-types.js +5 -3
  281. package/dist/src/functions/wirings/personas/personas-secrets-file.d.ts +8 -0
  282. package/dist/src/functions/wirings/personas/personas-secrets-file.js +9 -0
  283. package/dist/src/functions/wirings/personas/pikku-command-personas.d.ts +7 -0
  284. package/dist/src/functions/wirings/personas/pikku-command-personas.js +57 -0
  285. package/dist/src/functions/wirings/personas/serialize-personas-secrets.d.ts +16 -0
  286. package/dist/src/functions/wirings/personas/serialize-personas-secrets.js +34 -0
  287. package/dist/src/functions/wirings/personas/serialize-personas-types.d.ts +18 -0
  288. package/dist/src/functions/wirings/personas/serialize-personas-types.js +76 -0
  289. package/dist/src/functions/wirings/queue/serialize-queue-map.js +2 -1
  290. package/dist/src/functions/wirings/queue/serialize-queue-wrapper.js +2 -1
  291. package/dist/src/functions/wirings/realtime/pikku-command-events-scaffold.js +2 -1
  292. package/dist/src/functions/wirings/roles/pikku-command-roles.d.ts +7 -0
  293. package/dist/src/functions/wirings/roles/pikku-command-roles.js +33 -0
  294. package/dist/src/functions/wirings/roles/serialize-roles-types.d.ts +14 -0
  295. package/dist/src/functions/wirings/roles/serialize-roles-types.js +55 -0
  296. package/dist/src/functions/wirings/rpc/pikku-command-public-rpc.js +2 -1
  297. package/dist/src/functions/wirings/scenarios/register-scenario-instrumentation.d.ts +3 -3
  298. package/dist/src/functions/wirings/scenarios/register-scenario-instrumentation.js +3 -3
  299. package/dist/src/functions/wirings/scopes/serialize-scopes-types.d.ts +1 -1
  300. package/dist/src/functions/wirings/scopes/serialize-scopes-types.js +1 -1
  301. package/dist/src/functions/wirings/user-admin/pikku-command-user-admin-functions.js +2 -1
  302. package/dist/src/functions/wirings/user-admin/serialize-user-admin-functions.js +2 -2
  303. package/dist/src/functions/wirings/virtual-user/pikku-command-virtual-user-functions.d.ts +1 -0
  304. package/dist/src/functions/wirings/virtual-user/pikku-command-virtual-user-functions.js +42 -0
  305. package/dist/src/functions/wirings/virtual-user/serialize-virtual-user-functions.d.ts +28 -0
  306. package/dist/src/functions/wirings/virtual-user/serialize-virtual-user-functions.js +439 -0
  307. package/dist/src/functions/wirings/workflow/pikku-command-workflow-routes.js +2 -1
  308. package/dist/src/functions/wirings/workflow/pikku-command-workflow.js +13 -13
  309. package/dist/src/functions/wirings/workflow/serialize-personas.d.ts +10 -0
  310. package/dist/src/functions/wirings/workflow/serialize-personas.js +46 -0
  311. package/dist/src/functions/wirings/workflow/serialize-scenario-step-map.js +13 -4
  312. package/dist/src/functions/wirings/workflow/serialize-workflow-types.js +170 -40
  313. package/dist/src/functions/workflows/all.workflow.js +55 -16
  314. package/dist/src/server/bun-server-runner.d.ts +2 -2
  315. package/dist/src/server/bun-server-runner.js +5 -1
  316. package/dist/src/server/content-signing-jwt.d.ts +13 -0
  317. package/dist/src/server/content-signing-jwt.js +51 -0
  318. package/dist/src/server/dev-server-runner.interface.d.ts +10 -2
  319. package/dist/src/server/node-server-runner.d.ts +2 -2
  320. package/dist/src/server/node-server-runner.js +2 -1
  321. package/dist/src/services/cli-logger.service.d.ts +28 -16
  322. package/dist/src/services/cli-logger.service.js +25 -16
  323. package/dist/src/services.d.ts +3 -1
  324. package/dist/src/services.js +10 -1
  325. package/dist/src/utils/file-import-path.js +9 -0
  326. package/dist/src/utils/pikku-cli-config.js +52 -2
  327. package/dist/src/utils/resolve-personas.d.ts +27 -0
  328. package/dist/src/utils/resolve-personas.js +35 -0
  329. package/dist/src/utils/resolve-scaffold-feature.d.ts +19 -0
  330. package/dist/src/utils/resolve-scaffold-feature.js +49 -0
  331. package/dist/tsconfig.tsbuildinfo +1 -1
  332. package/package.json +20 -17
  333. package/dist/.pikku/schemas/schemas/BootstrapInput.schema.json +0 -1
  334. package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +0 -1
  335. package/dist/.pikku/schemas/schemas/ScenarioRunInput.schema.json +0 -1
  336. package/dist/.pikku/workflow/pikku-scenario-actors.gen.d.ts +0 -19
  337. package/dist/.pikku/workflow/pikku-scenario-actors.gen.js +0 -17
  338. package/dist/src/functions/commands/db-seed.d.ts +0 -1
  339. package/dist/src/functions/commands/db-seed.js +0 -24
  340. package/dist/src/functions/db/sqlite/seed.d.ts +0 -11
  341. package/dist/src/functions/db/sqlite/seed.js +0 -22
  342. package/dist/src/functions/wirings/workflow/serialize-scenario-actors.d.ts +0 -2
  343. package/dist/src/functions/wirings/workflow/serialize-scenario-actors.js +0 -40
  344. package/dist/src/utils/resolve-scenario-actors.d.ts +0 -23
  345. package/dist/src/utils/resolve-scenario-actors.js +0 -74
  346. /package/dist/.pikku/schemas/schemas/{DbSeedInput.schema.json → RolesAuditInput.schema.json} +0 -0
@@ -40,11 +40,26 @@ function variableSchemaName(name, field) {
40
40
  // addHTTPMiddleware('*') call as the session middleware: the inspector keys
41
41
  // route-middleware groups by pattern, so a second '*' registration from another
42
42
  // file would silently displace this one in deployed units.
43
+ //
44
+ // The session carries the two scope roots the console addon gates itself on.
45
+ // Without them this token authenticates but authorizes nothing: `wireAddon`
46
+ // gates the whole addon on `admin`, so every console:* RPC — reads included —
47
+ // answers MissingScopeError, and an external console can reach the deployment
48
+ // while being unable to do a single thing in it.
49
+ //
50
+ // Roots rather than a wildcard: a parent grant satisfies its children, so
51
+ // `admin` covers `admin:*` and `pikku` covers `pikku:scopes:*`/`pikku:audit:*`,
52
+ // which is every scope the console's own functions require. A `*` would also
53
+ // hand the token every scope the HOST app declares, which is authority the
54
+ // console never asks for.
43
55
  const consoleTokenMiddlewareLines = () => [
44
56
  ` authBearer({`,
45
57
  ` token: {`,
46
58
  ` secretId: 'PIKKU_CONSOLE_TOKEN',`,
47
- ` userSession: { userId: 'pikku-console-token' },`,
59
+ ` userSession: {`,
60
+ ` userId: 'pikku-console-token',`,
61
+ ` scopes: ['admin', 'pikku'],`,
62
+ ` },`,
48
63
  ` },`,
49
64
  ` }),`,
50
65
  ];
@@ -59,22 +74,22 @@ export const serializeAuthGen = (definition, providers, authFile, typesDeclarati
59
74
  // the package's `imports` map (e.g. a project's `pikku/` dir), where `#pikku`
60
75
  // would not resolve. This mirrors how the console/agent scaffolds import it.
61
76
  const pikkuTypesImportPath = getFileImportRelativePath(authFile, typesDeclarationFile, packageMappings);
62
- // ─── Secrets file: Zod schemas + wireSecret/wireVariable ──────────────────
77
+ // ─── Secrets file: Zod schemas + defineSecret/defineVariable ──────────────────
63
78
  const secrets = [
64
79
  '// AUTO-GENERATED by pikku CLI — do not edit',
65
80
  '',
66
- `import { wireSecret } from '@pikku/core/secret'`,
81
+ `import { defineSecret } from '@pikku/core/secret'`,
67
82
  ];
68
83
  const hasVariables = known.some((name) => PROVIDER_REGISTRY[name].variables);
69
84
  if (hasVariables) {
70
- secrets.push(`import { wireVariable } from '@pikku/core/variable'`);
85
+ secrets.push(`import { defineVariable } from '@pikku/core/variable'`);
71
86
  }
72
87
  secrets.push(`import { z } from 'zod'`, '');
73
88
  // better-auth's session-signing secret is always required (its BETTER_AUTH_SECRET
74
89
  // env convention). Wire it so the platform collects it, regardless of providers.
75
90
  secrets.push(`export const BetterAuthSecretSchema = z.string()`);
76
91
  secrets.push('');
77
- secrets.push(`wireSecret({`);
92
+ secrets.push(`defineSecret({`);
78
93
  secrets.push(` name: 'betterAuthSecret',`);
79
94
  secrets.push(` displayName: 'Better Auth Secret',`);
80
95
  secrets.push(` description: 'Signing secret for better-auth sessions',`);
@@ -92,12 +107,12 @@ export const serializeAuthGen = (definition, providers, authFile, typesDeclarati
92
107
  secrets.push(`})`);
93
108
  secrets.push('');
94
109
  }
95
- // wireSecret for each provider.
110
+ // defineSecret for each provider.
96
111
  for (const name of known) {
97
112
  const def = PROVIDER_REGISTRY[name];
98
113
  const schemaName = providerSchemaName(name);
99
114
  const secretName = providerSecretName(name);
100
- secrets.push(`wireSecret({`);
115
+ secrets.push(`defineSecret({`);
101
116
  secrets.push(` name: '${secretName}',`);
102
117
  secrets.push(` displayName: '${def.displayName}',`);
103
118
  secrets.push(` secretId: '${def.secretId}',`);
@@ -105,7 +120,7 @@ export const serializeAuthGen = (definition, providers, authFile, typesDeclarati
105
120
  secrets.push(`})`);
106
121
  secrets.push('');
107
122
  }
108
- // wireVariable for providers with non-secret config (issuer, tenantId, etc.).
123
+ // defineVariable for providers with non-secret config (issuer, tenantId, etc.).
109
124
  for (const name of known) {
110
125
  const def = PROVIDER_REGISTRY[name];
111
126
  if (!def.variables)
@@ -116,7 +131,7 @@ export const serializeAuthGen = (definition, providers, authFile, typesDeclarati
116
131
  const schemaName = variableSchemaName(name, field);
117
132
  secrets.push(`export const ${schemaName} = z.string()`);
118
133
  secrets.push('');
119
- secrets.push(`wireVariable({`);
134
+ secrets.push(`defineVariable({`);
120
135
  secrets.push(` name: '${name}_${field}',`);
121
136
  secrets.push(` displayName: '${def.displayName} ${capitalize(field)}',`);
122
137
  secrets.push(` description: '${meta.description}',`);
@@ -16,7 +16,9 @@
16
16
  * them at runtime — the same treatment addon services get from
17
17
  * `pikkuAddonServices`. That gives the factory typed, map-aware access:
18
18
  *
19
- * socialProviders: { github: await secrets.getSecret('GITHUB_OAUTH') }
19
+ * socialProviders: {
20
+ * github: (await secrets.getSecret('GITHUB_OAUTH')).reveal(),
21
+ * }
20
22
  *
21
23
  * with no inline `getSecrets<{ ... }>()` generic, because the secret types flow
22
24
  * from the generated `CredentialsMap`.
@@ -17,7 +17,9 @@ import { getFileImportRelativePath } from '../../../utils/file-import-path.js';
17
17
  * them at runtime — the same treatment addon services get from
18
18
  * `pikkuAddonServices`. That gives the factory typed, map-aware access:
19
19
  *
20
- * socialProviders: { github: await secrets.getSecret('GITHUB_OAUTH') }
20
+ * socialProviders: {
21
+ * github: (await secrets.getSecret('GITHUB_OAUTH')).reveal(),
22
+ * }
21
23
  *
22
24
  * with no inline `getSecrets<{ ... }>()` generic, because the secret types flow
23
25
  * from the generated `CredentialsMap`.
@@ -1 +1 @@
1
- export declare const pikkuChannels: import("#pikku").PikkuFunctionConfig<void, void, "rpc" | "session", import("#pikku").PikkuFunctionSessionless<void, void, "rpc" | "session", import("#pikku").WiredServices> | import("#pikku").PikkuFunction<void, void, "rpc" | "session", import("#pikku").WiredServices>, undefined, undefined>;
1
+ export declare const pikkuChannels: import("#pikku").PikkuFunctionSessionlessConfig<void, void, "rpc" | "session", import("#pikku").PikkuFunctionSessionless<void, void, "rpc" | "session", import("#pikku").WiredServices>, undefined, undefined>;
@@ -109,15 +109,23 @@ function generateChannels(logger, typesMap, functionsMeta, addonFunctions, chann
109
109
  }
110
110
  }
111
111
  }
112
+ /**
113
+ * A route or message key that is not a bare identifier has to be quoted to be
114
+ * a legal property name. Channel routes are author-chosen strings and a CLI
115
+ * channel's are command ids, where `app-smoke` and `registry.search` are the
116
+ * norm — unquoted, each one ends the property early and the whole map fails
117
+ * to parse. Quoted only when it has to be, so existing output is unchanged.
118
+ */
119
+ const propertyKey = (key) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? key : `'${key}'`;
112
120
  let routesStr = 'export type ChannelsMap = {\n';
113
121
  for (const [channelPath, { routes, message }] of Object.entries(channelsObject)) {
114
122
  routesStr += ` readonly '${channelPath}': {\n`;
115
123
  // Add `routes` object
116
124
  routesStr += ` readonly routes: {\n`;
117
125
  for (const [key, methods] of Object.entries(routes)) {
118
- routesStr += ` readonly ${key}: {\n`;
126
+ routesStr += ` readonly ${propertyKey(key)}: {\n`;
119
127
  for (const [method, handler] of Object.entries(methods)) {
120
- routesStr += ` readonly ${method}: ChannelHandler<${formatTypeArray(handler.inputTypes) || 'void'}, ${formatTypeArray(handler.outputTypes) || 'never'}>,\n`;
128
+ routesStr += ` readonly ${propertyKey(method)}: ChannelHandler<${formatTypeArray(handler.inputTypes) || 'void'}, ${formatTypeArray(handler.outputTypes) || 'never'}>,\n`;
121
129
  }
122
130
  routesStr += ' },\n';
123
131
  }
@@ -64,15 +64,20 @@ export const pikkuCLIEntry = pikkuSessionlessFunc({
64
64
  // Generate client code if clientPath is provided
65
65
  if (channelClientPath) {
66
66
  const channelClientFile = join(config.rootDir, channelClientPath);
67
- // Validate that renderers don't depend on services (client-side renderers can't access server services)
67
+ // A renderer for a CLI-over-channel program runs on the client, where
68
+ // there is no service container to resolve from — the only thing the
69
+ // runtime can hand it is a logger. Anything else it destructures
70
+ // would be undefined at runtime, so it fails generation instead.
68
71
  const rendererNames = collectRendererNames(programMeta);
69
72
  const problematicRenderers = [];
70
73
  for (const rendererName of rendererNames) {
71
74
  const rendererMeta = visitState.cli.meta.renderers[rendererName];
72
- if (rendererMeta?.services?.services?.length > 0) {
75
+ const services = rendererMeta?.services?.services ?? [];
76
+ const unavailable = services.filter((name) => name !== 'logger');
77
+ if (unavailable.length > 0) {
73
78
  problematicRenderers.push({
74
79
  name: rendererName,
75
- services: rendererMeta.services.services,
80
+ services: unavailable,
76
81
  });
77
82
  }
78
83
  }
@@ -81,7 +86,7 @@ export const pikkuCLIEntry = pikkuSessionlessFunc({
81
86
  const details = problematicRenderers
82
87
  .map((r) => ` - ${r.name} depends on: ${r.services.join(', ')}`)
83
88
  .join('\n');
84
- logger.critical(ErrorCode.CLI_CLIENTSIDE_RENDERER_HAS_SERVICES, `Cannot generate CLI channel client for '${programName}': renderers cannot depend on services (client-side execution)\n${details}\n\nRenderers used in CLI-over-channel must be service-free since they execute on the client.`);
89
+ logger.critical(ErrorCode.CLI_CLIENTSIDE_RENDERER_HAS_SERVICES, `Cannot generate CLI channel client for '${programName}': a renderer reached for a service that does not exist on the client\n${details}\n\nRenderers in a CLI-over-channel program run on the client side of the socket, where the only available service is 'logger'.`);
85
90
  // Delete existing client file if it exists
86
91
  if (existsSync(channelClientFile)) {
87
92
  await rm(channelClientFile);
@@ -5,7 +5,11 @@ import type { Config } from '../../../../types/application-types.js';
5
5
  */
6
6
  export declare function collectRendererNames(programMeta: CLIProgramMeta): Set<string>;
7
7
  /**
8
- * Serializes a CLI-over-Channel client bootstrap file
9
- * Similar to local CLI bootstrap but uses WebSocket connection
8
+ * Serializes a CLI-over-Channel client bootstrap file.
9
+ *
10
+ * The client deliberately does NOT import the CLI bootstrap: loading the
11
+ * command tree here would bind the client's version to the server's, which is
12
+ * the coupling running commands remotely exists to remove. Renderers are the
13
+ * only local artefact, and they are optional.
10
14
  */
11
- export declare function serializeChannelCLIClient(programName: string, programMeta: CLIProgramMeta, clientFile: string, config: Config, cliBootstrapPath: string, channelRoute?: string, renderersMeta?: Record<string, any>): string;
15
+ export declare function serializeChannelCLIClient(programName: string, programMeta: CLIProgramMeta, clientFile: string, config: Config, _cliBootstrapPath: string, channelRoute?: string, renderersMeta?: Record<string, any>): string;
@@ -1,4 +1,5 @@
1
1
  import { getFileImportRelativePath } from '../../../utils/file-import-path.js';
2
+ import { DIRECT_EXECUTION_GUARD } from './serialize-cli-entrypoint-guard.js';
2
3
  /**
3
4
  * Collect all unique renderer names from CLI metadata (populated by inspector)
4
5
  */
@@ -65,14 +66,16 @@ function buildRenderersMap(programMeta, renderersMeta) {
65
66
  return `{\n${entries.join(',\n')}\n }`;
66
67
  }
67
68
  /**
68
- * Serializes a CLI-over-Channel client bootstrap file
69
- * Similar to local CLI bootstrap but uses WebSocket connection
69
+ * Serializes a CLI-over-Channel client bootstrap file.
70
+ *
71
+ * The client deliberately does NOT import the CLI bootstrap: loading the
72
+ * command tree here would bind the client's version to the server's, which is
73
+ * the coupling running commands remotely exists to remove. Renderers are the
74
+ * only local artefact, and they are optional.
70
75
  */
71
- export function serializeChannelCLIClient(programName, programMeta, clientFile, config, cliBootstrapPath, channelRoute, renderersMeta) {
76
+ export function serializeChannelCLIClient(programName, programMeta, clientFile, config, _cliBootstrapPath, channelRoute, renderersMeta) {
72
77
  const capitalizedName = programName.charAt(0).toUpperCase() + programName.slice(1).replace(/-/g, '');
73
78
  const finalChannelRoute = channelRoute || `/cli/${programName}`;
74
- // Get relative import path to CLI bootstrap (for metadata)
75
- const bootstrapImportPath = getFileImportRelativePath(clientFile, cliBootstrapPath, config.packageMappings);
76
79
  // Collect all unique renderer names from CLI metadata (populated by inspector)
77
80
  const rendererNames = collectRendererNames(programMeta);
78
81
  // Generate renderer imports from their source files
@@ -105,32 +108,48 @@ export function serializeChannelCLIClient(programName, programMeta, clientFile,
105
108
  ? resolveRendererBinding(programMeta.defaultRenderName, renderersMeta)
106
109
  : null;
107
110
  const defaultRendererCode = defaultRendererBinding
108
- ? `,\n defaultRenderer: ${defaultRendererBinding}`
111
+ ? `,\n defaultRenderer: ${defaultRendererBinding} as CorePikkuCLIClientRender<any>`
109
112
  : '';
110
113
  return `
111
- import { executeCLIViaChannel } from '@pikku/core/cli/channel'
114
+ import { executeRawCLIViaChannel } from '@pikku/core/cli/channel'
115
+ import type { CorePikkuCLIClientRender } from '@pikku/core/cli/channel'
116
+ import type { Capabilities } from '@pikku/core/channel'
112
117
  import { CorePikkuWebsocket } from '@pikku/websocket'
113
- import '${bootstrapImportPath}'
114
118
  ${rendererImports}
115
119
  /**
116
120
  * ${capitalizedName} CLI Client (via WebSocket Channel)
117
- * Executes CLI commands over a WebSocket connection
121
+ *
122
+ * Forwards argv to the server untouched — the command tree is never parsed
123
+ * here, so this client stays valid as the server's commands change. Renderers
124
+ * are matched by the command id the server reports; anything it doesn't
125
+ * recognise falls back to JSON.
126
+ *
127
+ * \`capabilities\` are the functions this client agrees to run on the server's
128
+ * behalf (a git sha, a local path). It is an allowlist, not a convenience —
129
+ * nothing outside it is reachable from the server. A bare function is
130
+ * unclassified and so needs approval before every call; write
131
+ * \`{ execute, needsApproval: false }\` for one that may run unattended.
118
132
  */
119
133
  export async function ${capitalizedName}CLIClient(
120
134
  ws: WebSocket,
121
- args?: string[]
122
- ): Promise<void> {
135
+ args?: string[],
136
+ capabilities: Capabilities = {}
137
+ ): Promise<number> {
123
138
  // Create Pikku WebSocket wrapper
124
139
  const pikkuWS = new CorePikkuWebsocket(ws)
125
140
 
126
- // Register renderers for CLI commands
127
- const renderers = ${renderersMap}
141
+ // Renderers are declared against this app's \`SingletonServices\`, but on this
142
+ // side of the socket the only service that exists is a logger. The cast is
143
+ // sound because generation refuses to emit this file at all when a renderer
144
+ // reaches for anything else — see CLI_CLIENTSIDE_RENDERER_HAS_SERVICES. It is
145
+ // localised here so \`executeRawCLIViaChannel\` can keep an honest signature.
146
+ const renderers = ${renderersMap} as Record<string, CorePikkuCLIClientRender<any>>
128
147
 
129
- await executeCLIViaChannel({
130
- programName: '${programName}',
148
+ return executeRawCLIViaChannel({
131
149
  pikkuWS,
132
150
  args,
133
- renderers${defaultRendererCode},
151
+ renderers,
152
+ capabilities${defaultRendererCode},
134
153
  })
135
154
  }
136
155
 
@@ -138,15 +157,17 @@ export async function ${capitalizedName}CLIClient(
138
157
  export default ${capitalizedName}CLIClient
139
158
 
140
159
  // For direct execution (if this file is run directly)
141
- if (import.meta.url === \`file://\${process.argv[1]}\`) {
160
+ ${DIRECT_EXECUTION_GUARD}
161
+
162
+ if (isDirectExecution) {
142
163
  const url = process.env.PIKKU_WS_URL || 'ws://localhost:4002${finalChannelRoute}'
143
164
 
144
165
  // Attach credentials so the channel authenticates like any other pikku client.
145
166
  // A machine API key (PIKKU_API_KEY -> x-api-key) takes precedence; otherwise
146
167
  // the human session token saved by \`pikku login\` (~/.pikku/session.json ->
147
- // Authorization: Bearer) is used. This block only runs under Node (direct
148
- // execution), so reading the session file and using the 'ws' headers option
149
- // is safe the browser WebSocket cannot set custom headers anyway.
168
+ // Authorization: Bearer) is used. This block only runs on a server runtime
169
+ // (direct execution), so reading the session file is safe a browser could
170
+ // neither reach it nor set custom headers on its WebSocket.
150
171
  const headers: Record<string, string> = {}
151
172
  if (process.env.PIKKU_API_KEY) {
152
173
  headers['x-api-key'] = process.env.PIKKU_API_KEY
@@ -173,21 +194,36 @@ if (import.meta.url === \`file://\${process.argv[1]}\`) {
173
194
  }
174
195
  const hasAuth = Object.keys(headers).length > 0
175
196
 
176
- // Custom headers require the Node 'ws' module the global/browser WebSocket
177
- // cannot set them so prefer 'ws' whenever we have credentials to send.
197
+ // Node's global WebSocket reads its second argument as subprotocols and drops
198
+ // custom headers on the floor, so credentials there need the 'ws' module.
199
+ // Bun's honours them natively, and reaching for 'ws' under Bun would load its
200
+ // compatibility shim for nothing. Detected once, the way the CLI picks its
201
+ // dev-server runner.
202
+ const isBun = typeof (globalThis as { Bun?: unknown }).Bun !== 'undefined'
203
+
204
+ // Only the header-carrying Bun call needs the cast: the DOM lib types the
205
+ // second argument as subprotocols, which is what Node implements.
206
+ type WebSocketWithHeaders = new (
207
+ url: string,
208
+ options: { headers: Record<string, string> }
209
+ ) => WebSocket
210
+
178
211
  let ws: WebSocket
179
- if (hasAuth || typeof WebSocket === 'undefined') {
212
+ if (!isBun && (hasAuth || typeof WebSocket === 'undefined')) {
180
213
  const wsModule = await import('ws')
181
214
  ws = new wsModule.default(url, { headers }) as unknown as WebSocket
215
+ } else if (hasAuth) {
216
+ ws = new (WebSocket as unknown as WebSocketWithHeaders)(url, { headers })
182
217
  } else {
183
218
  ws = new WebSocket(url)
184
219
  }
185
220
 
186
- ${capitalizedName}CLIClient(ws, process.argv.slice(2)).catch(error => {
187
- console.error('Fatal channel CLI error:', error)
188
- // TODO: We get an error code even when it exists cleanly, investigate
189
- // process.exit(1)
190
- })
221
+ ${capitalizedName}CLIClient(ws, process.argv.slice(2))
222
+ .then((exitCode) => process.exit(exitCode))
223
+ .catch(error => {
224
+ console.error('Fatal channel CLI error:', error)
225
+ process.exit(1)
226
+ })
191
227
  }
192
228
  `;
193
229
  }
@@ -60,7 +60,7 @@ export function serializeChannelCLI(programName, programMeta, channelFile, funct
60
60
  import { wireChannel } from '${channelTypesPath}'
61
61
  import { pikkuMiddleware${hasAddonFuncs ? ', ref' : ''}, pikkuSessionlessFunc } from '${functionTypesPath}'
62
62
  import { generateCommandHelp } from '@pikku/core/cli'
63
- import { handleRawCLI } from '@pikku/core/cli/channel'
63
+ import { handleRawCLI, type RawCLIFrame } from '@pikku/core/cli/channel'
64
64
  import { pikkuState } from '@pikku/core/internal'
65
65
  ${imports}
66
66
 
@@ -97,22 +97,79 @@ export const cliHelp = pikkuSessionlessFunc<{ args?: string[] }, { help: string
97
97
  },
98
98
  })
99
99
 
100
- export const cliRaw = pikkuSessionlessFunc<{ args: string[] }, { help?: string; result?: unknown; error?: string }>({
100
+ /**
101
+ * Raw entry point: the client forwards argv untouched and this side owns
102
+ * parsing, so a client binary never carries the command tree and its version
103
+ * is free to drift from the server's.
104
+ *
105
+ * Progressive output is streamed on the same channel rather than returned,
106
+ * and the terminating control frame carries the exit code so the client
107
+ * process can exit non-zero.
108
+ */
109
+ export const cliRaw = pikkuSessionlessFunc<{ args: string[] }, RawCLIFrame>({
101
110
  auth: false,
102
- func: async (services, data: { args: string[] }) => {
103
- return handleRawCLI({
111
+ func: async (services, data: { args: string[] }, { channel, session }) => {
112
+ const { help, result, error, exitCode, commandId } = await handleRawCLI({
104
113
  programName: '${programName}',
105
114
  args: data.args,
106
115
  singletonServices: services as any,
116
+ createWireServices: pikkuState(null, 'package', 'factories')?.createWireServices,
117
+ // The connection authenticated during its upgrade — commands run as it.
118
+ session,
119
+ // The socket the command arrived on, so \`channel.remote(...)\` inside a
120
+ // command reaches the client that invoked it.
121
+ transport: channel,
122
+ onOutput: (output, commandId) =>
123
+ channel?.send({ action: 'cli-output', commandId, data: output }),
107
124
  })
125
+
126
+ // A failed parse carries both: the error says what was wrong, the help
127
+ // says what was available. The error goes last so it is the line still on
128
+ // screen after the help text has scrolled past.
129
+ if (help !== undefined) {
130
+ await channel?.send({ action: 'cli-help', help })
131
+ if (error !== undefined) {
132
+ await channel?.send({ action: 'cli-error', error })
133
+ }
134
+ } else if (error !== undefined) {
135
+ await channel?.send({ action: 'cli-error', error })
136
+ } else if (result !== undefined) {
137
+ await channel?.send({ action: 'cli-result', commandId, result })
138
+ }
139
+
140
+ // Returned rather than sent so the runtime tags it with the routing key,
141
+ // and so the terminal frame cannot be emitted before the ones above it.
142
+ return { action: 'cli-control', event: 'complete', exitCode }
108
143
  },
109
144
  })
110
145
 
146
+ ${programMeta.auth === true
147
+ ? `/**
148
+ * Refuses a connection that arrives without a session.
149
+ *
150
+ * A CLI authenticates once, when it connects — there is no later message that
151
+ * would establish a session, so a connection that starts anonymous can never
152
+ * run anything. Saying so immediately and hanging up gives the caller a
153
+ * non-zero exit instead of a socket that silently refuses every command.
154
+ */
155
+ export const cliRequireSession = pikkuSessionlessFunc<void, RawCLIFrame | void>({
156
+ auth: false,
157
+ func: async (_services, _data, { channel, session }) => {
158
+ if (session) {
159
+ return
160
+ }
161
+ await channel?.send({ action: 'cli-error', error: 'Authentication required' })
162
+ await channel?.send({ action: 'cli-control', event: 'complete', exitCode: 1 })
163
+ await channel?.close()
164
+ },
165
+ })
166
+ `
167
+ : ''}
111
168
  wireChannel({
112
169
  name: '${finalChannelName}',
113
170
  route: '${finalChannelRoute}',
114
- auth: false,
115
- onMessageWiring: {
171
+ auth: ${programMeta.auth === true},
172
+ ${programMeta.auth === true ? ' onConnect: cliRequireSession,\n' : ''} onMessageWiring: {
116
173
  command: {
117
174
  '__help': {
118
175
  func: cliHelp,
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The snippet every generated CLI entrypoint uses to decide whether it is being
3
+ * run or merely imported. It declares `isDirectExecution`; the caller writes the
4
+ * `if`.
5
+ *
6
+ * `import.meta.url === \`file://${process.argv[1]}\`` — the shape this replaces —
7
+ * is false for any CLI invoked through a symlinked bin, because Node reports the
8
+ * symlink in argv and the realpath in the URL, so the block never ran for an
9
+ * installed `node_modules/.bin/<name>`. It also fails on paths the URL has to
10
+ * percent-encode, such as one containing a space.
11
+ */
12
+ export declare const DIRECT_EXECUTION_GUARD = "const isDirectExecution = await (async () => {\n if (typeof import.meta.main === 'boolean') {\n return import.meta.main\n }\n // Node exposes import.meta.main from 24.2; earlier 24.x compares realpaths,\n // which is what it is shorthand for.\n try {\n const { fileURLToPath } = await import('node:url')\n const { realpathSync } = await import('node:fs')\n return (\n process.argv[1] !== undefined &&\n realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)\n )\n } catch {\n return false\n }\n})()";
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The snippet every generated CLI entrypoint uses to decide whether it is being
3
+ * run or merely imported. It declares `isDirectExecution`; the caller writes the
4
+ * `if`.
5
+ *
6
+ * `import.meta.url === \`file://${process.argv[1]}\`` — the shape this replaces —
7
+ * is false for any CLI invoked through a symlinked bin, because Node reports the
8
+ * symlink in argv and the realpath in the URL, so the block never ran for an
9
+ * installed `node_modules/.bin/<name>`. It also fails on paths the URL has to
10
+ * percent-encode, such as one containing a space.
11
+ */
12
+ export const DIRECT_EXECUTION_GUARD = `const isDirectExecution = await (async () => {
13
+ if (typeof import.meta.main === 'boolean') {
14
+ return import.meta.main
15
+ }
16
+ // Node exposes import.meta.main from 24.2; earlier 24.x compares realpaths,
17
+ // which is what it is shorthand for.
18
+ try {
19
+ const { fileURLToPath } = await import('node:url')
20
+ const { realpathSync } = await import('node:fs')
21
+ return (
22
+ process.argv[1] !== undefined &&
23
+ realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)
24
+ )
25
+ } catch {
26
+ return false
27
+ }
28
+ })()`;
@@ -1,4 +1,5 @@
1
1
  import { getFileImportRelativePath } from '../../../utils/file-import-path.js';
2
+ import { DIRECT_EXECUTION_GUARD } from './serialize-cli-entrypoint-guard.js';
2
3
  /**
3
4
  * Serializes the local (in-program) CLI bootstrap code
4
5
  */
@@ -40,7 +41,9 @@ ${wireServicesFactory ? ' createWireServices,' : ''}
40
41
  export default ${capitalizedName}CLI
41
42
 
42
43
  // For direct execution (if this file is run directly)
43
- if (import.meta.url === \`file://\${process.argv[1]}\`) {
44
+ ${DIRECT_EXECUTION_GUARD}
45
+
46
+ if (isDirectExecution) {
44
47
  ${capitalizedName}CLI(process.argv.slice(2)).catch(error => {
45
48
  console.error('Fatal error:', error.message)
46
49
  process.exit(1)
@@ -40,6 +40,7 @@ import {
40
40
  } from './console.schemas.gen.js'
41
41
 
42
42
  export const pikkuConsoleSetSecret = pikkuFunc({
43
+ secretBroker: true,
43
44
  tags: ['pikku'],
44
45
  description: 'Set the value of a secret',
45
46
  expose: true,
@@ -89,6 +90,7 @@ export const pikkuConsoleSetVariable = pikkuFunc({
89
90
  })
90
91
 
91
92
  export const pikkuConsoleHasSecret = pikkuFunc({
93
+ secretBroker: true,
92
94
  tags: ['pikku'],
93
95
  description: 'Check if a secret exists without reading its value',
94
96
  expose: true,
@@ -101,6 +103,7 @@ export const pikkuConsoleHasSecret = pikkuFunc({
101
103
  })
102
104
 
103
105
  export const pikkuConsoleGetSecret = pikkuFunc({
106
+ secretBroker: true,
104
107
  tags: ['pikku'],
105
108
  description: 'Get the current value of a secret',
106
109
  expose: true,
@@ -112,7 +115,7 @@ export const pikkuConsoleGetSecret = pikkuFunc({
112
115
  return { exists: false, value: null }
113
116
  }
114
117
  const value = await secrets.getSecret(secretId)
115
- return { exists: true, value }
118
+ return { exists: true, value: value.reveal() }
116
119
  },
117
120
  })
118
121
 
@@ -129,13 +132,7 @@ export const consoleRoutes = defineHTTPRoutes({
129
132
  },
130
133
  })
131
134
 
132
- // The console addon's functions have no authorization of their own. An app
133
- // gates the whole privileged surface (credential read/write, source editing,
134
- // package install) with a single package-scoped global permission —
135
- // addGlobalPermission([isAdmin], '@pikku/addon-console') — which is resolved in
136
- // the addon's package namespace, so it applies to every one of its functions at
137
- // once. Apps that don't register one are unaffected (no globals => allow).
138
- wireAddon({ name: 'console', package: '@pikku/addon-console' })
135
+ wireAddon({ name: 'console', package: '@pikku/addon-console', scopes: ['admin'] })
139
136
  wireHTTPRoutes({ basePath: '${globalHTTPPrefix}', routes: { console: consoleRoutes } })
140
137
  `;
141
138
  return { schemas, functions };
@@ -53,7 +53,7 @@ export const pikkuAddonConfig = <ExistingServices extends Omit<Partial<Singleton
53
53
  * { secrets }
54
54
  * ) => {
55
55
  * const creds = await secrets.getSecret<GithubCredentials>('GITHUB_CREDENTIALS')
56
- * const github = new GithubService(creds)
56
+ * const github = new GithubService(creds.reveal())
57
57
  * return { github }
58
58
  * })
59
59
  * \`\`\`