@pikku/cli 0.12.90 → 0.12.92

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 (264) hide show
  1. package/LICENSE +106 -0
  2. package/README.md +25 -2
  3. package/console-app/assets/{index-CSzCJzBb.css → index-D0HG8q0B.css} +1 -1
  4. package/console-app/assets/{index-C5Bd44e4.js → index-DDpIMCpy.js} +149 -149
  5. package/console-app/index.html +2 -2
  6. package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
  7. package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
  8. package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
  9. package/dist/.pikku/cli/pikku-cli-channel.js +6 -1
  10. package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +1 -1
  11. package/dist/.pikku/cli/pikku-cli-client.gen.js +1 -1
  12. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.d.ts +1 -1
  13. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.js +1 -1
  14. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.json +15 -0
  15. package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
  16. package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
  17. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
  18. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +43 -0
  19. package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
  20. package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
  21. package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
  22. package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
  23. package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
  24. package/dist/.pikku/function/pikku-function-types.gen.d.ts +4 -4
  25. package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
  26. package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
  27. package/dist/.pikku/function/pikku-functions-meta.gen.json +39 -44
  28. package/dist/.pikku/function/pikku-functions.gen.js +1 -3
  29. package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
  30. package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
  31. package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
  32. package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
  33. package/dist/.pikku/pikku-bootstrap-scenarios.gen.d.ts +9 -0
  34. package/dist/.pikku/pikku-bootstrap-scenarios.gen.js +9 -0
  35. package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
  36. package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
  37. package/dist/.pikku/pikku-meta-service.gen.d.ts +1 -1
  38. package/dist/.pikku/pikku-meta-service.gen.js +1 -1
  39. package/dist/.pikku/pikku-services.gen.d.ts +1 -1
  40. package/dist/.pikku/pikku-types.gen.d.ts +1 -1
  41. package/dist/.pikku/pikku-types.gen.js +1 -1
  42. package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
  43. package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
  44. package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
  45. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
  46. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
  47. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
  48. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +1 -1
  49. package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.d.ts +1 -0
  50. package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.js +10 -0
  51. package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.json +1 -0
  52. package/dist/.pikku/scenarios/pikku-scenario-functions.gen.d.ts +4 -0
  53. package/dist/.pikku/scenarios/pikku-scenario-functions.gen.js +1 -0
  54. package/dist/.pikku/scenarios/pikku-scenario-wirings-meta.gen.d.ts +1 -0
  55. package/dist/.pikku/scenarios/pikku-scenario-wirings-meta.gen.js +10 -0
  56. package/dist/.pikku/scenarios/pikku-scenario-wirings.gen.d.ts +4 -0
  57. package/dist/.pikku/scenarios/pikku-scenario-wirings.gen.js +1 -0
  58. package/dist/.pikku/scenarios/schemas/register.gen.d.ts +4 -0
  59. package/dist/.pikku/scenarios/schemas/register.gen.js +4 -0
  60. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
  61. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
  62. package/dist/.pikku/schemas/register.gen.js +5 -3
  63. package/dist/.pikku/schemas/schemas/FabricSecretsListOutput.schema.json +1 -1
  64. package/dist/.pikku/schemas/schemas/FabricSecretsRotateInput.schema.json +1 -0
  65. package/dist/.pikku/schemas/schemas/FabricSecretsRotateOutput.schema.json +1 -0
  66. package/dist/.pikku/schemas/schemas/FabricSecretsSetOutput.schema.json +1 -1
  67. package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
  68. package/dist/.pikku/schemas/schemas/ScenarioRunInput.schema.json +1 -1
  69. package/dist/.pikku/scopes/pikku-scope-types.gen.d.ts +1 -1
  70. package/dist/.pikku/scopes/pikku-scope-types.gen.js +1 -1
  71. package/dist/.pikku/scopes/pikku-scopes.gen.d.ts +1 -1
  72. package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
  73. package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
  74. package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
  75. package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
  76. package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
  77. package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
  78. package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
  79. package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
  80. package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
  81. package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
  82. package/dist/.pikku/workflow/meta/allWorkflow.gen.json +2 -8
  83. package/dist/.pikku/workflow/pikku-scenario-actors.gen.d.ts +19 -0
  84. package/dist/.pikku/workflow/pikku-scenario-actors.gen.js +17 -0
  85. package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +152 -3
  86. package/dist/.pikku/workflow/pikku-workflow-types.gen.js +39 -1
  87. package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
  88. package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
  89. package/dist/bin/pikku-bin.mjs +2 -2
  90. package/dist/src/cli.wiring.js +28 -0
  91. package/dist/src/deploy/analyzer/analyzer.js +22 -5
  92. package/dist/src/deploy/build-pipeline.js +5 -1
  93. package/dist/src/fabric/fabric-commands.d.ts +37 -9
  94. package/dist/src/fabric/fabric-commands.js +12 -0
  95. package/dist/src/fabric/functions/domains-add.function.d.ts +4 -4
  96. package/dist/src/fabric/functions/secrets-list.function.d.ts +16 -4
  97. package/dist/src/fabric/functions/secrets-list.function.js +12 -10
  98. package/dist/src/fabric/functions/secrets-rotate.function.d.ts +24 -0
  99. package/dist/src/fabric/functions/secrets-rotate.function.js +36 -0
  100. package/dist/src/fabric/functions/secrets-set.function.d.ts +8 -4
  101. package/dist/src/fabric/functions/secrets-set.function.js +18 -7
  102. package/dist/src/fabric/lib/http.d.ts +7 -1
  103. package/dist/src/fabric/lib/sealed-box.d.ts +16 -0
  104. package/dist/src/fabric/lib/sealed-box.js +72 -0
  105. package/dist/src/functions/commands/dev.js +11 -0
  106. package/dist/src/functions/commands/load-user-project.d.ts +7 -0
  107. package/dist/src/functions/commands/load-user-project.js +21 -0
  108. package/dist/src/functions/commands/pikku-command-bootstrap.js +13 -0
  109. package/dist/src/functions/commands/scenario-browser.d.ts +84 -0
  110. package/dist/src/functions/commands/scenario-browser.js +68 -0
  111. package/dist/src/functions/commands/scenario-environment.d.ts +32 -0
  112. package/dist/src/functions/commands/scenario-environment.js +61 -0
  113. package/dist/src/functions/commands/scenario-formatter.d.ts +81 -0
  114. package/dist/src/functions/commands/scenario-formatter.js +120 -0
  115. package/dist/src/functions/commands/scenario-ladder.d.ts +66 -0
  116. package/dist/src/functions/commands/scenario-ladder.js +132 -0
  117. package/dist/src/functions/commands/scenario-plan.d.ts +61 -0
  118. package/dist/src/functions/commands/scenario-plan.js +106 -0
  119. package/dist/src/functions/commands/scenario.d.ts +24 -0
  120. package/dist/src/functions/commands/scenario.js +322 -50
  121. package/dist/src/functions/commands/serve.js +2 -0
  122. package/dist/src/functions/commands/skills.js +27 -61
  123. package/dist/src/functions/db/db-codegen.d.ts +6 -0
  124. package/dist/src/functions/db/db-codegen.js +9 -0
  125. package/dist/src/functions/db/db-migrator.js +14 -0
  126. package/dist/src/functions/db/local-db.d.ts +8 -0
  127. package/dist/src/functions/db/local-db.js +24 -2
  128. package/dist/src/functions/db/migration-identifiers.d.ts +58 -0
  129. package/dist/src/functions/db/migration-identifiers.js +262 -0
  130. package/dist/src/functions/db/migration-provenance.d.ts +35 -0
  131. package/dist/src/functions/db/migration-provenance.js +80 -0
  132. package/dist/src/functions/db/schema-sql.d.ts +43 -0
  133. package/dist/src/functions/db/schema-sql.js +135 -0
  134. package/dist/src/functions/db/sqlite/sqlite-kysely.js +22 -2
  135. package/dist/src/functions/wirings/functions/pikku-command-functions.js +26 -8
  136. package/dist/src/functions/wirings/functions/schemas.js +13 -1
  137. package/dist/src/functions/wirings/functions/serialize-function-types.js +3 -3
  138. package/dist/src/functions/wirings/rpc/pikku-command-rpc.js +6 -1
  139. package/dist/src/functions/wirings/scenarios/register-scenario-instrumentation.d.ts +10 -0
  140. package/dist/src/functions/wirings/scenarios/register-scenario-instrumentation.js +102 -0
  141. package/dist/src/functions/wirings/scenarios/scenario-partition.d.ts +42 -0
  142. package/dist/src/functions/wirings/scenarios/scenario-partition.js +71 -0
  143. package/dist/src/functions/wirings/scenarios/scenario-schema-partition.d.ts +33 -0
  144. package/dist/src/functions/wirings/scenarios/scenario-schema-partition.js +49 -0
  145. package/dist/src/functions/wirings/scenarios/serialize-feature-meta.d.ts +14 -0
  146. package/dist/src/functions/wirings/scenarios/serialize-feature-meta.js +29 -0
  147. package/dist/src/functions/wirings/scenarios/serialize-scenario-meta.d.ts +12 -0
  148. package/dist/src/functions/wirings/scenarios/serialize-scenario-meta.js +56 -0
  149. package/dist/src/functions/wirings/scenarios/serialize-scenario-registration.d.ts +7 -0
  150. package/dist/src/functions/wirings/scenarios/serialize-scenario-registration.js +40 -0
  151. package/dist/src/functions/wirings/workflow/pikku-command-workflow.js +43 -8
  152. package/dist/src/functions/wirings/workflow/serialize-scenario-actors.d.ts +1 -1
  153. package/dist/src/functions/wirings/workflow/serialize-scenario-actors.js +13 -2
  154. package/dist/src/functions/wirings/workflow/serialize-scenario-step-map.d.ts +4 -0
  155. package/dist/src/functions/wirings/workflow/serialize-scenario-step-map.js +62 -0
  156. package/dist/src/functions/wirings/workflow/serialize-workflow-bootstrap-map.js +10 -3
  157. package/dist/src/functions/wirings/workflow/serialize-workflow-map.js +10 -3
  158. package/dist/src/functions/wirings/workflow/serialize-workflow-meta.js +4 -4
  159. package/dist/src/functions/wirings/workflow/serialize-workflow-types.d.ts +1 -1
  160. package/dist/src/functions/wirings/workflow/serialize-workflow-types.js +232 -3
  161. package/dist/src/functions/workflows/all.workflow.js +2 -7
  162. package/dist/src/server/server-ready.d.ts +12 -0
  163. package/dist/src/server/server-ready.js +12 -0
  164. package/dist/src/server/spawn-dev-server.d.ts +50 -0
  165. package/dist/src/server/spawn-dev-server.js +112 -0
  166. package/dist/src/services.js +12 -1
  167. package/dist/src/utils/file-writer.js +14 -2
  168. package/dist/src/utils/meta-diff.js +5 -2
  169. package/dist/src/utils/pikku-cli-config.d.ts +14 -0
  170. package/dist/src/utils/pikku-cli-config.js +60 -0
  171. package/dist/src/utils/remove-legacy-scaffold-file.d.ts +14 -0
  172. package/dist/src/utils/remove-legacy-scaffold-file.js +23 -0
  173. package/dist/src/utils/resolve-scenario-actors.d.ts +23 -0
  174. package/dist/src/utils/resolve-scenario-actors.js +74 -0
  175. package/dist/src/utils/serialize-schemas.d.ts +3 -1
  176. package/dist/src/utils/serialize-schemas.js +39 -4
  177. package/dist/tsconfig.tsbuildinfo +1 -1
  178. package/package.json +18 -8
  179. package/dist/.pikku/schemas/schemas/PikkuScenarioFunctionsOutput.schema.json +0 -1
  180. package/dist/src/functions/wirings/scenarios/pikku-command-scenario-functions.d.ts +0 -1
  181. package/dist/src/functions/wirings/scenarios/pikku-command-scenario-functions.js +0 -31
  182. package/dist/src/functions/wirings/scenarios/serialize-scenario-functions.d.ts +0 -10
  183. package/dist/src/functions/wirings/scenarios/serialize-scenario-functions.js +0 -104
  184. package/skills/pikku-addon/SKILL.md +0 -243
  185. package/skills/pikku-addon/references/addon-package-manifest.md +0 -63
  186. package/skills/pikku-ai-agent/SKILL.md +0 -231
  187. package/skills/pikku-ai-vercel/SKILL.md +0 -82
  188. package/skills/pikku-ai-voice/SKILL.md +0 -88
  189. package/skills/pikku-audit/SKILL.md +0 -175
  190. package/skills/pikku-aws/SKILL.md +0 -111
  191. package/skills/pikku-backblaze/SKILL.md +0 -71
  192. package/skills/pikku-better-auth/SKILL.md +0 -298
  193. package/skills/pikku-cli/SKILL.md +0 -198
  194. package/skills/pikku-cli/references/complete-example.md +0 -82
  195. package/skills/pikku-concepts/SKILL.md +0 -250
  196. package/skills/pikku-concepts/references/concept-mapping.md +0 -556
  197. package/skills/pikku-concepts/references/packages.md +0 -29
  198. package/skills/pikku-config/SKILL.md +0 -212
  199. package/skills/pikku-cron/SKILL.md +0 -214
  200. package/skills/pikku-deploy-azure/SKILL.md +0 -71
  201. package/skills/pikku-deploy-cloudflare/SKILL.md +0 -82
  202. package/skills/pikku-deploy-express/SKILL.md +0 -86
  203. package/skills/pikku-deploy-fastify/SKILL.md +0 -73
  204. package/skills/pikku-deploy-lambda/SKILL.md +0 -110
  205. package/skills/pikku-deploy-nextjs/SKILL.md +0 -78
  206. package/skills/pikku-deploy-uws/SKILL.md +0 -88
  207. package/skills/pikku-deps/SKILL.md +0 -98
  208. package/skills/pikku-emails/SKILL.md +0 -163
  209. package/skills/pikku-fabric/SKILL.md +0 -318
  210. package/skills/pikku-fabric-debug/SKILL.md +0 -112
  211. package/skills/pikku-feature/SKILL.md +0 -258
  212. package/skills/pikku-gateway-slack/SKILL.md +0 -115
  213. package/skills/pikku-http/SKILL.md +0 -220
  214. package/skills/pikku-http/references/http-options.md +0 -55
  215. package/skills/pikku-i18n/SKILL.md +0 -137
  216. package/skills/pikku-info/SKILL.md +0 -100
  217. package/skills/pikku-jose/SKILL.md +0 -105
  218. package/skills/pikku-kysely/SKILL.md +0 -219
  219. package/skills/pikku-machine-auth/SKILL.md +0 -183
  220. package/skills/pikku-mcp/SKILL.md +0 -241
  221. package/skills/pikku-middleware/SKILL.md +0 -231
  222. package/skills/pikku-middleware/references/middleware-patterns.md +0 -61
  223. package/skills/pikku-mongodb/SKILL.md +0 -105
  224. package/skills/pikku-n8n-import/SKILL.md +0 -109
  225. package/skills/pikku-n8n-import/SPEC.md +0 -84
  226. package/skills/pikku-n8n-import/references/addon-mapping.md +0 -121
  227. package/skills/pikku-n8n-import/references/code-translation.md +0 -121
  228. package/skills/pikku-n8n-import/references/loops-and-control.md +0 -87
  229. package/skills/pikku-paraglide/SKILL.md +0 -117
  230. package/skills/pikku-permissions/SKILL.md +0 -192
  231. package/skills/pikku-pino/SKILL.md +0 -79
  232. package/skills/pikku-product-second-opinion/README.md +0 -43
  233. package/skills/pikku-product-second-opinion/SKILL.md +0 -158
  234. package/skills/pikku-product-second-opinion/example/sample-report.md +0 -90
  235. package/skills/pikku-product-second-opinion/references/report-template.md +0 -73
  236. package/skills/pikku-queue/SKILL.md +0 -240
  237. package/skills/pikku-react/SKILL.md +0 -212
  238. package/skills/pikku-react-query/SKILL.md +0 -242
  239. package/skills/pikku-realtime/SKILL.md +0 -236
  240. package/skills/pikku-realtime/references/other-routes.md +0 -23
  241. package/skills/pikku-redis/SKILL.md +0 -90
  242. package/skills/pikku-rpc/SKILL.md +0 -171
  243. package/skills/pikku-rtl/SKILL.md +0 -219
  244. package/skills/pikku-scenario/SKILL.md +0 -215
  245. package/skills/pikku-schedule/SKILL.md +0 -57
  246. package/skills/pikku-schema-ajv/SKILL.md +0 -62
  247. package/skills/pikku-schema-cfworker/SKILL.md +0 -63
  248. package/skills/pikku-security/SKILL.md +0 -108
  249. package/skills/pikku-services/SKILL.md +0 -248
  250. package/skills/pikku-services/references/audit-wire-service.md +0 -34
  251. package/skills/pikku-software-archaeology/README.md +0 -70
  252. package/skills/pikku-software-archaeology/SKILL.md +0 -186
  253. package/skills/pikku-software-archaeology/references/blueprint.schema.json +0 -625
  254. package/skills/pikku-software-archaeology/references/pikku-mapping.md +0 -49
  255. package/skills/pikku-software-archaeology/scripts/validate.mjs +0 -173
  256. package/skills/pikku-tag-middleware/SKILL.md +0 -13
  257. package/skills/pikku-template-clone/SKILL.md +0 -40
  258. package/skills/pikku-trigger/SKILL.md +0 -181
  259. package/skills/pikku-versioning/SKILL.md +0 -173
  260. package/skills/pikku-websocket/SKILL.md +0 -243
  261. package/skills/pikku-workflow/SKILL.md +0 -172
  262. package/skills/pikku-workflow/references/workflow-reference.md +0 -63
  263. package/skills/pikku-workflows-client/SKILL.md +0 -150
  264. package/skills/pikku-ws/SKILL.md +0 -47
@@ -1,4 +1,4 @@
1
- export const serializeWorkflowTypes = (functionTypesImportPath, rpcMapImportPath, workflowMapImportPath, agentMapImportPath, scopesImportPath) => {
1
+ export const serializeWorkflowTypes = (functionTypesImportPath, rpcMapImportPath, workflowMapImportPath, agentMapImportPath, scopesImportPath, scenarioStepMapImportPath = './pikku-scenario-step-map.gen.js', scenarioActorsImportPath = './pikku-scenario-actors.gen.js') => {
2
2
  return `import { WorkflowCancelledException } from '@pikku/core/workflow'
3
3
  import { template } from '@pikku/core/workflow'
4
4
  import {
@@ -6,13 +6,17 @@ import {
6
6
  type PikkuWorkflowGraphConfig,
7
7
  type PikkuWorkflowGraphResult,
8
8
  } from '@pikku/core/workflow'
9
- import type { PikkuWorkflowWire, PikkuScenarioWire, WorkflowStepOptions } from '@pikku/core/workflow'
9
+ import type { PikkuWorkflowWire, PikkuScenarioWire, WorkflowStepOptions, ScenarioStepOptions } from '@pikku/core/workflow'
10
10
 
11
11
  export { WorkflowCancelledException }
12
12
  import type { PikkuFunctionSessionless, PikkuFunctionConfig } from '${functionTypesImportPath}'
13
13
  import type { FlattenedRPCMap } from '${rpcMapImportPath}'
14
14
  import type { FlattenedWorkflowMap } from '${workflowMapImportPath}'
15
15
  import type { AgentMap as FlattenedAgentMap } from '${agentMapImportPath}'
16
+ import type { FlattenedScenarioStepMap } from '${scenarioStepMapImportPath}'
17
+ import type { TypedScenarioActors } from '${scenarioActorsImportPath}'
18
+
19
+ export type { TypedScenarioActors }
16
20
 
17
21
  export { template }
18
22
 
@@ -38,7 +42,44 @@ export interface TypedWorkflow extends PikkuWorkflowWire {
38
42
  ): Promise<T>
39
43
  }
40
44
 
41
- export type TypedScenario = TypedWorkflow & Omit<PikkuScenarioWire, keyof PikkuWorkflowWire>
45
+ /**
46
+ * The typed half of a scenario wire: \`step\` and its \`given\`/\`when\`/\`then\`
47
+ * sugar, narrowed to the names declared by \`pikkuScenarioStep\` in this project.
48
+ * The phase only changes the prose the reporter renders.
49
+ */
50
+ export interface TypedScenarioSteps {
51
+ step<K extends keyof FlattenedScenarioStepMap>(
52
+ stepName: string,
53
+ stepFunc: K,
54
+ data?: FlattenedScenarioStepMap[K]['input'],
55
+ options?: ScenarioStepOptions
56
+ ): Promise<FlattenedScenarioStepMap[K]['output']>
57
+
58
+ given<K extends keyof FlattenedScenarioStepMap>(
59
+ stepName: string,
60
+ stepFunc: K,
61
+ data?: FlattenedScenarioStepMap[K]['input'],
62
+ options?: ScenarioStepOptions
63
+ ): Promise<FlattenedScenarioStepMap[K]['output']>
64
+
65
+ when<K extends keyof FlattenedScenarioStepMap>(
66
+ stepName: string,
67
+ stepFunc: K,
68
+ data?: FlattenedScenarioStepMap[K]['input'],
69
+ options?: ScenarioStepOptions
70
+ ): Promise<FlattenedScenarioStepMap[K]['output']>
71
+
72
+ then<K extends keyof FlattenedScenarioStepMap>(
73
+ stepName: string,
74
+ stepFunc: K,
75
+ data?: FlattenedScenarioStepMap[K]['input'],
76
+ options?: ScenarioStepOptions
77
+ ): Promise<FlattenedScenarioStepMap[K]['output']>
78
+ }
79
+
80
+ export type TypedScenario = TypedWorkflow &
81
+ Omit<PikkuScenarioWire, keyof PikkuWorkflowWire | keyof TypedScenarioSteps> &
82
+ TypedScenarioSteps
42
83
 
43
84
  import type { StandardSchemaV1 } from '@standard-schema/spec'
44
85
  import type { InferSchemaOutput, PikkuPermission, PikkuMiddleware, NodeConfig, PikkuApprovalDescription } from '${functionTypesImportPath}'
@@ -129,6 +170,49 @@ export type PikkuScenarioConfigWithSchema<
129
170
  InputSchema extends StandardSchemaV1 ? InferSchemaOutput<InputSchema> : unknown,
130
171
  OutputSchema extends StandardSchemaV1 ? InferSchemaOutput<OutputSchema> : unknown
131
172
  >
173
+ /**
174
+ * Runs before the scenario body. Same signature as \`func\`, but its return
175
+ * value is discarded — a hook is setup, not a step, so it is never recorded
176
+ * on the ladder. Throwing skips the body and fails the run; \`after\` still
177
+ * runs.
178
+ */
179
+ before?: PikkuScenarioHook<InputSchema>
180
+ /**
181
+ * Always runs after the scenario body, in a \`finally\`, whether it passed or
182
+ * failed. Throwing fails a run that would otherwise have passed; on an
183
+ * already-failed run it attaches as the \`cause\` and never replaces the
184
+ * original error.
185
+ */
186
+ after?: PikkuScenarioHook<InputSchema>
187
+ /**
188
+ * Why this scenario is held out of a default run, stated where the scenario
189
+ * is. The scenario still appears in the plan and is reported as skipped
190
+ * rather than quietly omitted; naming it directly with \`--flows\` runs it
191
+ * anyway.
192
+ */
193
+ skip?: string
194
+ }
195
+
196
+ /**
197
+ * A scenario lifecycle hook: the scenario's own \`(services, data, wire)\`
198
+ * signature with its result discarded.
199
+ */
200
+ export type PikkuScenarioHook<
201
+ InputSchema extends StandardSchemaV1 | undefined = undefined
202
+ > = PikkuFunctionScenario<
203
+ InputSchema extends StandardSchemaV1 ? InferSchemaOutput<InputSchema> : unknown,
204
+ void
205
+ >
206
+
207
+ /**
208
+ * Declares a scenario hook. Returns the function verbatim — a hook is never
209
+ * registered, so this exists purely to give an inline hook a call site to be
210
+ * contextually typed from, the way every other pikku primitive is.
211
+ */
212
+ export function pikkuScenarioHook<In = unknown>(
213
+ hook: PikkuFunctionScenario<In, void>
214
+ ): PikkuFunctionScenario<In, void> {
215
+ return hook
132
216
  }
133
217
 
134
218
  /**
@@ -152,6 +236,151 @@ export function pikkuScenario(func: any) {
152
236
  return typeof func === 'function' ? { func } : func
153
237
  }
154
238
 
239
+ /**
240
+ * A scenario as a feature references it. Any \`pikkuScenario\` export is
241
+ * assignable; \`In\` is recovered from it so the paired form's \`data\` is
242
+ * checked against that scenario's own input.
243
+ */
244
+ export type PikkuScenarioRef<In = any, Out = any> = PikkuFunctionConfig<
245
+ In,
246
+ Out,
247
+ 'scenario' | 'actors',
248
+ PikkuFunctionScenario<In, Out>,
249
+ any,
250
+ any
251
+ >
252
+
253
+ /**
254
+ * One entry in a feature's \`scenarios\` list, validated against itself: a bare
255
+ * scenario, or a scenario paired with the input to run it with. The paired form
256
+ * is gherkin's \`Examples:\` written as an ordinary loop.
257
+ */
258
+ export type PikkuFeatureEntry<Entry> = Entry extends {
259
+ scenario: PikkuScenarioRef<infer In>
260
+ }
261
+ ? { scenario: PikkuScenarioRef<In>; data: In }
262
+ : Entry extends PikkuScenarioRef
263
+ ? Entry
264
+ : never
265
+
266
+ export type PikkuFeatureConfig<Scenarios extends readonly unknown[]> = {
267
+ /** Human-readable name. The export identifier is the id. */
268
+ name: string
269
+ description?: string
270
+ tags?: string[]
271
+ scenarios: { [K in keyof Scenarios]: PikkuFeatureEntry<Scenarios[K]> }
272
+ /**
273
+ * Runs ONCE before the whole group — not before each scenario. Per-scenario
274
+ * setup is the scenario's own \`before\`; gherkin's \`Background:\` is
275
+ * deliberately not expressible here.
276
+ */
277
+ before?: PikkuScenarioHook
278
+ after?: PikkuScenarioHook
279
+ }
280
+
281
+ /**
282
+ * A feature: an ordered group of scenarios, mirroring gherkin's Feature ↔
283
+ * Scenario structure. Scenarios are referenced by imported identifier, so a
284
+ * renamed or deleted scenario is a compile error rather than a silent skip.
285
+ *
286
+ * A scenario does not have to belong to a feature — a void-input scenario
287
+ * still runs standalone.
288
+ *
289
+ * \`\`\`ts
290
+ * export const credentialFeature = pikkuFeature({
291
+ * name: 'Credential API',
292
+ * tags: ['credential'],
293
+ * before: startsMockOAuthServer,
294
+ * after: stopsMockOAuthServer,
295
+ * scenarios: [
296
+ * credentialLazyLoadScenario,
297
+ * ...['stripe', 'google'].map((name) => ({
298
+ * scenario: credentialRoundTripScenario,
299
+ * data: { name },
300
+ * })),
301
+ * ],
302
+ * })
303
+ * \`\`\`
304
+ */
305
+ export function pikkuFeature<const Scenarios extends readonly unknown[]>(
306
+ config: PikkuFeatureConfig<Scenarios>
307
+ ): PikkuFeatureConfig<Scenarios> {
308
+ return config
309
+ }
310
+
311
+ export type PikkuFunctionScenarioStep<
312
+ In = unknown,
313
+ Out = never,
314
+ B extends boolean = false
315
+ > = PikkuFunctionSessionless<In, Out, B extends true ? 'scenarioStep' | 'browser' : 'scenarioStep'>
316
+
317
+ export type PikkuScenarioStepConfigWithSchema<
318
+ InputSchema extends StandardSchemaV1 | undefined = undefined,
319
+ OutputSchema extends StandardSchemaV1 | undefined = undefined,
320
+ B extends boolean = false
321
+ > = {
322
+ /** Registered name — this is the string \`scenario.step()\` references. */
323
+ name: string
324
+ /**
325
+ * What this step does, for the console and for whoever reads the source. It
326
+ * is also the fallback prose when no \`template\` is declared, in which case a
327
+ * reporter renders "Given the shopper buys an apple". Defaults to the call
328
+ * site's step name.
329
+ */
330
+ description?: string
331
+ /**
332
+ * The prose a reporter renders for this step, with \`{placeholders}\` filled
333
+ * from the input the step was called with — \`'sees {packageName}'\` reports as
334
+ * "Then the admin sees @pikku/addon-todos". Every input field should appear,
335
+ * so the report names the values under test rather than repeating one
336
+ * sentence per call site.
337
+ */
338
+ template?: string
339
+ /**
340
+ * This step drives a browser. The runner provisions one for the step's actor
341
+ * before calling it — which also makes an actor mandatory — and \`wire.browser\`
342
+ * is non-optional inside \`func\`.
343
+ */
344
+ browser?: B
345
+ title?: string
346
+ tags?: string[]
347
+ input?: InputSchema
348
+ output?: OutputSchema
349
+ errors?: Array<typeof PikkuError>
350
+ func: PikkuFunctionScenarioStep<
351
+ InputSchema extends StandardSchemaV1 ? InferSchemaOutput<InputSchema> : unknown,
352
+ OutputSchema extends StandardSchemaV1 ? InferSchemaOutput<OutputSchema> : unknown,
353
+ B
354
+ >
355
+ }
356
+
357
+ export type PikkuScenarioStepConfig<In, Out, B extends boolean = false> =
358
+ Omit<PikkuScenarioStepConfigWithSchema<undefined, undefined, B>, 'func' | 'input' | 'output'> & {
359
+ func: PikkuFunctionScenarioStep<In, Out, B>
360
+ }
361
+
362
+ /**
363
+ * A named, reusable scenario step. Unlike \`scenario.do\`, which can only name an
364
+ * RPC, a step's body is an ordinary pikku function — so it may drive a browser,
365
+ * invoke RPCs as its actor, or run a workflow.
366
+ *
367
+ * Steps are deliberately NOT registered as RPCs: a browser-driving step must
368
+ * never be network-callable.
369
+ */
370
+ export function pikkuScenarioStep<
371
+ InputSchema extends StandardSchemaV1 | undefined = undefined,
372
+ OutputSchema extends StandardSchemaV1 | undefined = undefined,
373
+ B extends boolean = false
374
+ >(
375
+ config: PikkuScenarioStepConfigWithSchema<InputSchema, OutputSchema, B>
376
+ ): PikkuFunctionConfig<InputSchema extends StandardSchemaV1 ? InferSchemaOutput<InputSchema> : unknown, OutputSchema extends StandardSchemaV1 ? InferSchemaOutput<OutputSchema> : unknown, B extends true ? 'scenarioStep' | 'browser' : 'scenarioStep', PikkuFunctionScenarioStep<InputSchema extends StandardSchemaV1 ? InferSchemaOutput<InputSchema> : unknown, OutputSchema extends StandardSchemaV1 ? InferSchemaOutput<OutputSchema> : unknown, B>, InputSchema, OutputSchema>
377
+ export function pikkuScenarioStep<In, Out = unknown, B extends boolean = false>(
378
+ config: PikkuScenarioStepConfig<In, Out, B>
379
+ ): PikkuFunctionConfig<In, Out, B extends true ? 'scenarioStep' | 'browser' : 'scenarioStep'>
380
+ export function pikkuScenarioStep(config: any) {
381
+ return config
382
+ }
383
+
155
384
  type TypedRef<T> = { $ref: string; path?: string } & { __phantomType?: T }
156
385
 
157
386
  type TemplateString = {
@@ -1,7 +1,7 @@
1
1
  import { existsSync } from 'fs';
2
2
  import { pikkuWorkflowComplexFunc } from '#pikku/workflow/pikku-workflow-types.gen.js';
3
3
  import { assertSingleCoreVersion } from '../../utils/assert-single-core-version.js';
4
- import { pruneLegacyScaffoldFiles } from '../../utils/remove-legacy-scaffold-file.js';
4
+ import { pruneLegacyScaffoldFiles, removeRetiredScaffoldFiles, } from '../../utils/remove-legacy-scaffold-file.js';
5
5
  import { PikkuTypecheckFailedError, renderTscFull, renderTscSummary, runProjectTypecheck, } from '../../utils/tsc-check.js';
6
6
  const scaffoldFiles = (config) => {
7
7
  const files = [];
@@ -17,11 +17,6 @@ const scaffoldFiles = (config) => {
17
17
  file: config.consoleFunctionsFile,
18
18
  generator: 'pikkuConsoleFunctions',
19
19
  });
20
- if (config.scaffold?.scenarios && config.scenariosFunctionsFile)
21
- files.push({
22
- file: config.scenariosFunctionsFile,
23
- generator: 'pikkuScenarioFunctions',
24
- });
25
20
  if (config.scaffold?.userAdmin && config.userAdminFunctionsFile)
26
21
  files.push({
27
22
  file: config.userAdminFunctionsFile,
@@ -46,6 +41,7 @@ export const allWorkflow = pikkuWorkflowComplexFunc({
46
41
  // (workflows/RPCs "disappear"), so refuse to codegen against it.
47
42
  await assertSingleCoreVersion(config.rootDir, logger);
48
43
  await pruneLegacyScaffoldFiles(config);
44
+ await removeRetiredScaffoldFiles(config);
49
45
  const allImports = [];
50
46
  let typesDeclarationFileExists = true;
51
47
  if (!existsSync(config.outDir)) {
@@ -150,7 +146,6 @@ export const allWorkflow = pikkuWorkflowComplexFunc({
150
146
  workflow.do('Graph wirings', 'pikkuGraphWirings', null),
151
147
  workflow.do('Public RPC', 'pikkuPublicRPC', null),
152
148
  workflow.do('Console functions', 'pikkuConsoleFunctions', null),
153
- workflow.do('Scenario functions', 'pikkuScenarioFunctions', null),
154
149
  workflow.do('User admin functions', 'pikkuUserAdminFunctions', null),
155
150
  workflow.do('Events scaffold', 'pikkuEventsScaffold', null),
156
151
  workflow.do('Emails', 'pikkuEmails', null),
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Printed once the server is listening AND the project's `afterStart`
3
+ * lifecycle has resolved.
4
+ *
5
+ * The runtime's own `listening on …` line is emitted inside `server.start()`,
6
+ * which runs *before* `afterStart` — so anything a project seeds there (users,
7
+ * scopes, fixtures) is still pending when it appears, and a parent process
8
+ * that treats it as readiness races the seed. This marker is the point at
9
+ * which the server is actually usable, and it is what `--spawn` waits for.
10
+ */
11
+ export declare const SERVER_READY_MARKER = "pikku: ready";
12
+ export declare const serverReadyLine: (hostname: string, port: number) => string;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Printed once the server is listening AND the project's `afterStart`
3
+ * lifecycle has resolved.
4
+ *
5
+ * The runtime's own `listening on …` line is emitted inside `server.start()`,
6
+ * which runs *before* `afterStart` — so anything a project seeds there (users,
7
+ * scopes, fixtures) is still pending when it appears, and a parent process
8
+ * that treats it as readiness races the seed. This marker is the point at
9
+ * which the server is actually usable, and it is what `--spawn` waits for.
10
+ */
11
+ export const SERVER_READY_MARKER = 'pikku: ready';
12
+ export const serverReadyLine = (hostname, port) => `${SERVER_READY_MARKER} on http://${hostname}:${port}`;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Rejects if anything is already listening on `port`.
3
+ *
4
+ * A readiness check cannot tell "my server" from "someone else's": both answer
5
+ * on the same address once spawned, so a stale server left on the target port
6
+ * silently absorbs a whole run and reports failures that belong to code nobody
7
+ * is looking at. A TCP-level check before spawning is the only point at which
8
+ * the two are distinguishable.
9
+ */
10
+ export declare const assertPortFree: (port: number, host?: string, timeoutMs?: number) => Promise<void>;
11
+ export interface ReadyBarrier {
12
+ /** Feed a chunk of the child's output. */
13
+ observe: (text: string) => void;
14
+ /** Record that the child exited, so the wait fails fast instead of timing out. */
15
+ markExited: (code: number | null) => void;
16
+ wait: (options?: {
17
+ timeoutMs?: number;
18
+ pollMs?: number;
19
+ }) => Promise<void>;
20
+ }
21
+ /**
22
+ * Watches a spawned server's output for the ready marker. Separated from the
23
+ * spawn so the three outcomes that matter — ready, the child died, nothing
24
+ * happened for long enough — are testable without a real process.
25
+ */
26
+ export declare const createReadyBarrier: (label: string) => ReadyBarrier;
27
+ export interface SpawnedServer {
28
+ /** Kills the whole process group, so the server's own children go with it. */
29
+ stop: () => void;
30
+ /** Resolves on the ready marker; rejects if the server dies or never reports. */
31
+ waitUntilReady: (options?: {
32
+ timeoutMs?: number;
33
+ }) => Promise<void>;
34
+ }
35
+ export interface SpawnDevServerOptions {
36
+ cwd: string;
37
+ port: number;
38
+ hostname?: string;
39
+ coverage?: boolean;
40
+ /** Passed through as `--test`, which sets PIKKU_TEST_RUN for isTestRun(). */
41
+ test?: boolean;
42
+ env?: NodeJS.ProcessEnv;
43
+ /** Where the server's own output goes. Defaults to this process's streams. */
44
+ onOutput?: (text: string) => void;
45
+ }
46
+ /**
47
+ * Start `pikku dev` as its own process group and stream its output under a
48
+ * `[server]` prefix. Does not wait — call `waitUntilReady`.
49
+ */
50
+ export declare const spawnDevServer: (options: SpawnDevServerOptions) => Promise<SpawnedServer>;
@@ -0,0 +1,112 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { connect } from 'node:net';
3
+ import { SERVER_READY_MARKER } from './server-ready.js';
4
+ /**
5
+ * Rejects if anything is already listening on `port`.
6
+ *
7
+ * A readiness check cannot tell "my server" from "someone else's": both answer
8
+ * on the same address once spawned, so a stale server left on the target port
9
+ * silently absorbs a whole run and reports failures that belong to code nobody
10
+ * is looking at. A TCP-level check before spawning is the only point at which
11
+ * the two are distinguishable.
12
+ */
13
+ export const assertPortFree = (port, host = '127.0.0.1', timeoutMs = 1000) => new Promise((resolve, reject) => {
14
+ const socket = connect({ port, host });
15
+ const settle = (error) => {
16
+ socket.removeAllListeners();
17
+ socket.destroy();
18
+ error ? reject(error) : resolve();
19
+ };
20
+ socket.setTimeout(timeoutMs);
21
+ socket.on('connect', () => settle(new Error(`Port ${port} is already in use — something is already listening on ${host}:${port}. ` +
22
+ `Stop it, or point this environment's apiUrl at a free port.`)));
23
+ // Nothing listening, or unreachable: either way this process is free to bind.
24
+ socket.on('error', () => settle());
25
+ socket.on('timeout', () => settle());
26
+ });
27
+ /**
28
+ * Watches a spawned server's output for the ready marker. Separated from the
29
+ * spawn so the three outcomes that matter — ready, the child died, nothing
30
+ * happened for long enough — are testable without a real process.
31
+ */
32
+ export const createReadyBarrier = (label) => {
33
+ let ready = false;
34
+ let exit;
35
+ // Stdout arrives in arbitrary chunks, so the marker can straddle two of them.
36
+ // Keep just enough of the tail to rejoin a split marker.
37
+ let tail = '';
38
+ return {
39
+ observe: (text) => {
40
+ if (ready)
41
+ return;
42
+ const window = tail + text;
43
+ if (window.includes(SERVER_READY_MARKER)) {
44
+ ready = true;
45
+ tail = '';
46
+ return;
47
+ }
48
+ tail = window.slice(-SERVER_READY_MARKER.length);
49
+ },
50
+ markExited: (code) => {
51
+ exit = { code };
52
+ },
53
+ wait: async ({ timeoutMs = 120_000, pollMs = 100 } = {}) => {
54
+ const deadline = Date.now() + timeoutMs;
55
+ while (Date.now() < deadline) {
56
+ if (ready)
57
+ return;
58
+ if (exit) {
59
+ throw new Error(`${label} exited with code ${exit.code} before it was ready`);
60
+ }
61
+ await new Promise((r) => setTimeout(r, pollMs));
62
+ }
63
+ throw new Error(`${label} did not report ready within ${timeoutMs / 1000} seconds`);
64
+ },
65
+ };
66
+ };
67
+ /**
68
+ * Start `pikku dev` as its own process group and stream its output under a
69
+ * `[server]` prefix. Does not wait — call `waitUntilReady`.
70
+ */
71
+ export const spawnDevServer = async (options) => {
72
+ const { cwd, port, hostname = '127.0.0.1', coverage, test = true, env, onOutput = (text) => process.stdout.write(text), } = options;
73
+ await assertPortFree(port, hostname);
74
+ const args = ['pikku', 'dev', '--port', String(port)];
75
+ if (coverage)
76
+ args.push('--coverage');
77
+ if (test)
78
+ args.push('--test');
79
+ const child = spawn('npx', args, {
80
+ cwd,
81
+ env: { ...process.env, ...env },
82
+ stdio: 'pipe',
83
+ detached: true,
84
+ });
85
+ const barrier = createReadyBarrier('Server');
86
+ const forward = (chunk) => {
87
+ const text = chunk.toString();
88
+ barrier.observe(text);
89
+ onOutput(text
90
+ .split('\n')
91
+ .map((line) => (line ? `[server] ${line}` : line))
92
+ .join('\n'));
93
+ };
94
+ child.stdout?.on('data', forward);
95
+ child.stderr?.on('data', forward);
96
+ child.on('exit', (code) => barrier.markExited(code));
97
+ return {
98
+ waitUntilReady: barrier.wait,
99
+ stop: () => {
100
+ child.stdout?.destroy();
101
+ child.stderr?.destroy();
102
+ if (child.pid) {
103
+ try {
104
+ process.kill(-child.pid, 'SIGTERM');
105
+ }
106
+ catch {
107
+ // Process group may already be gone
108
+ }
109
+ }
110
+ },
111
+ };
112
+ };
@@ -149,7 +149,14 @@ export const createSingletonServices = async (config) => {
149
149
  let unfilteredStateIsSetupOnly = false;
150
150
  let inspectedTsGeneration;
151
151
  let inspectorInvalidated = false;
152
- const getInspectorState = async (refresh = false, setupOnly = false, bootstrapMode = false) => {
152
+ /**
153
+ * `unfiltered` is for commands that RUN the project rather than generate from
154
+ * it. The CLI filters narrow what gets written out, which is meaningless to a
155
+ * runner and actively wrong for one: `--tags` on `pikku scenario run` selects
156
+ * which scenarios to run, and if it also narrowed the state the runner would
157
+ * lose the very step functions it is about to call.
158
+ */
159
+ const getInspectorState = async (refresh = false, setupOnly = false, bootstrapMode = false, unfiltered = false) => {
153
160
  // In bootstrap mode, return a minimal "zero state" with core types
154
161
  // This allows bootstrap to run immediately without inspecting the codebase
155
162
  if (bootstrapMode) {
@@ -240,6 +247,7 @@ export const createSingletonServices = async (config) => {
240
247
  rootDir,
241
248
  isAddon: !!config.addon,
242
249
  oldProgram,
250
+ tsconfig: config.tsconfig,
243
251
  types: {
244
252
  configFileType: config.configFile,
245
253
  userSessionType: config.userSessionType,
@@ -287,6 +295,9 @@ export const createSingletonServices = async (config) => {
287
295
  }
288
296
  }
289
297
  }
298
+ if (unfiltered) {
299
+ return unfilteredState;
300
+ }
290
301
  // Apply filters as a post-processing step
291
302
  const filteredState = filterInspectorState(unfilteredState, filters, logger);
292
303
  return filteredState;
@@ -1,5 +1,5 @@
1
1
  import { dirname, join } from 'path';
2
- import { mkdir, readFile, writeFile, rm } from 'fs/promises';
2
+ import { mkdir, readFile, rename, writeFile, rm } from 'fs/promises';
3
3
  import { existsSync } from 'fs';
4
4
  import { getCLIVersion } from './get-cli-version.js';
5
5
  export const DO_NOT_MODIFY_COMMENT = `/**
@@ -36,7 +36,19 @@ export const writeFileInDir = async (logger, path, content, { ignoreModifyCommen
36
36
  // Only write if content has changed or file doesn't exist
37
37
  if (existingContent !== content) {
38
38
  await mkdir(dirname(path), { recursive: true });
39
- await writeFile(path, content, 'utf-8');
39
+ // Atomically, because generated files are read while they are generated:
40
+ // `pikku scenario run --spawn` bundles the registers while the dev server it
41
+ // spawned is regenerating them, and `writeFile` truncates before it writes —
42
+ // a reader that lands in that window gets an empty file, not an old one.
43
+ const tmp = `${path}.${process.pid}.tmp`;
44
+ try {
45
+ await writeFile(tmp, content, 'utf-8');
46
+ await rename(tmp, path);
47
+ }
48
+ catch (e) {
49
+ await rm(tmp, { force: true }).catch(() => { });
50
+ throw e;
51
+ }
40
52
  if (TS_FILE_REGEX.test(path)) {
41
53
  tsWriteGeneration++;
42
54
  }
@@ -19,7 +19,7 @@ const UNWRAP = {
19
19
  email: 'templates',
20
20
  agent: 'agentsMeta',
21
21
  };
22
- // Workflows (incl. userflows/scenarios) are written one file per workflow under
22
+ // Workflows (incl. scenarios) are written one file per workflow under
23
23
  // this dir; the file basename (sans `.gen.json`) is the id, `-verbose` excluded.
24
24
  const WORKFLOW_META_DIR = 'workflow/meta';
25
25
  function readJson(path) {
@@ -40,7 +40,10 @@ function readSingle(outDir, category, relPath) {
40
40
  const unwrapKey = UNWRAP[category];
41
41
  if (unwrapKey) {
42
42
  const inner = raw[unwrapKey];
43
- raw = inner && typeof inner === 'object' && !Array.isArray(inner) ? inner : {};
43
+ raw =
44
+ inner && typeof inner === 'object' && !Array.isArray(inner)
45
+ ? inner
46
+ : {};
44
47
  }
45
48
  if (category !== 'http')
46
49
  return raw;
@@ -1,4 +1,18 @@
1
1
  import type { PikkuCLIConfig } from '../../types/config.js';
2
2
  import type { CLILogger } from '../services/cli-logger.service.js';
3
3
  export declare const getPikkuCLIConfig: (logger: CLILogger, configFile: string | undefined, requiredFields: Array<keyof PikkuCLIConfig>, exitProcess?: boolean, outDirOverride?: string) => Promise<PikkuCLIConfig>;
4
+ /** A config that was found and parsed, but says something impossible. */
5
+ export declare class PikkuCLIConfigError extends Error {
6
+ }
7
+ /**
8
+ * The two schema registers must be two directories.
9
+ *
10
+ * `saveSchemas` owns whatever directory it is given: it writes `register.gen.ts`
11
+ * and prunes every schema file that its own required-set does not name. Point the
12
+ * scenario write at `schemaDirectory` and the second call overwrites the app's
13
+ * register with the scenario-only one and deletes the app's schema files — the
14
+ * exact leak the split exists to prevent, silently, and only in a deployed
15
+ * bundle. Nothing downstream can detect it, so it is rejected here.
16
+ */
17
+ export declare const assertSchemaDirectoriesAreDistinct: (config: Pick<PikkuCLIConfig, "schemaDirectory" | "scenarioSchemaDirectory">) => void;
4
18
  export declare const validateCLIConfig: (cliConfig: PikkuCLIConfig, required: Array<keyof PikkuCLIConfig>) => void;