@pikku/cli 0.12.90 → 0.12.91

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 (127) hide show
  1. package/README.md +25 -2
  2. package/console-app/assets/{index-C5Bd44e4.js → index-CpkvmAGb.js} +140 -140
  3. package/console-app/assets/{index-CSzCJzBb.css → index-D0HG8q0B.css} +1 -1
  4. package/console-app/index.html +2 -2
  5. package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
  6. package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
  7. package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
  8. package/dist/.pikku/cli/pikku-cli-channel.js +1 -1
  9. package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +1 -1
  10. package/dist/.pikku/cli/pikku-cli-client.gen.js +1 -1
  11. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.d.ts +1 -1
  12. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.js +1 -1
  13. package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
  14. package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
  15. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
  16. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +22 -0
  17. package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
  18. package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
  19. package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
  20. package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
  21. package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
  22. package/dist/.pikku/function/pikku-function-types.gen.d.ts +4 -4
  23. package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
  24. package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
  25. package/dist/.pikku/function/pikku-functions-meta.gen.json +9 -9
  26. package/dist/.pikku/function/pikku-functions.gen.js +1 -1
  27. package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
  28. package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
  29. package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
  30. package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
  31. package/dist/.pikku/pikku-bootstrap-scenarios.gen.d.ts +8 -0
  32. package/dist/.pikku/pikku-bootstrap-scenarios.gen.js +8 -0
  33. package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
  34. package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
  35. package/dist/.pikku/pikku-meta-service.gen.d.ts +1 -1
  36. package/dist/.pikku/pikku-meta-service.gen.js +1 -1
  37. package/dist/.pikku/pikku-services.gen.d.ts +1 -1
  38. package/dist/.pikku/pikku-types.gen.d.ts +1 -1
  39. package/dist/.pikku/pikku-types.gen.js +1 -1
  40. package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
  41. package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
  42. package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
  43. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
  44. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
  45. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
  46. package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.d.ts +1 -0
  47. package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.js +10 -0
  48. package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.json +1 -0
  49. package/dist/.pikku/scenarios/pikku-scenario-functions.gen.d.ts +4 -0
  50. package/dist/.pikku/scenarios/pikku-scenario-functions.gen.js +1 -0
  51. package/dist/.pikku/scenarios/pikku-scenario-wirings-meta.gen.d.ts +1 -0
  52. package/dist/.pikku/scenarios/pikku-scenario-wirings-meta.gen.js +10 -0
  53. package/dist/.pikku/scenarios/pikku-scenario-wirings.gen.d.ts +4 -0
  54. package/dist/.pikku/scenarios/pikku-scenario-wirings.gen.js +1 -0
  55. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
  56. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
  57. package/dist/.pikku/schemas/register.gen.js +1 -1
  58. package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
  59. package/dist/.pikku/schemas/schemas/ScenarioRunInput.schema.json +1 -1
  60. package/dist/.pikku/scopes/pikku-scope-types.gen.d.ts +1 -1
  61. package/dist/.pikku/scopes/pikku-scope-types.gen.js +1 -1
  62. package/dist/.pikku/scopes/pikku-scopes.gen.d.ts +1 -1
  63. package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
  64. package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
  65. package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
  66. package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
  67. package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
  68. package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
  69. package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
  70. package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
  71. package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
  72. package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
  73. package/dist/.pikku/workflow/pikku-scenario-actors.gen.d.ts +19 -0
  74. package/dist/.pikku/workflow/pikku-scenario-actors.gen.js +17 -0
  75. package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +152 -3
  76. package/dist/.pikku/workflow/pikku-workflow-types.gen.js +39 -1
  77. package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
  78. package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
  79. package/dist/bin/pikku-bin.mjs +2 -2
  80. package/dist/src/cli.wiring.js +22 -0
  81. package/dist/src/functions/commands/dev.js +2 -0
  82. package/dist/src/functions/commands/load-user-project.d.ts +7 -0
  83. package/dist/src/functions/commands/load-user-project.js +21 -0
  84. package/dist/src/functions/commands/pikku-command-bootstrap.js +12 -0
  85. package/dist/src/functions/commands/scenario-browser.d.ts +69 -0
  86. package/dist/src/functions/commands/scenario-browser.js +60 -0
  87. package/dist/src/functions/commands/scenario-formatter.d.ts +81 -0
  88. package/dist/src/functions/commands/scenario-formatter.js +120 -0
  89. package/dist/src/functions/commands/scenario-ladder.d.ts +66 -0
  90. package/dist/src/functions/commands/scenario-ladder.js +132 -0
  91. package/dist/src/functions/commands/scenario-plan.d.ts +61 -0
  92. package/dist/src/functions/commands/scenario-plan.js +106 -0
  93. package/dist/src/functions/commands/scenario.d.ts +18 -0
  94. package/dist/src/functions/commands/scenario.js +305 -38
  95. package/dist/src/functions/commands/serve.js +2 -0
  96. package/dist/src/functions/wirings/functions/pikku-command-functions.js +26 -8
  97. package/dist/src/functions/wirings/functions/serialize-function-types.js +3 -3
  98. package/dist/src/functions/wirings/scenarios/scenario-partition.d.ts +29 -0
  99. package/dist/src/functions/wirings/scenarios/scenario-partition.js +58 -0
  100. package/dist/src/functions/wirings/scenarios/serialize-feature-meta.d.ts +14 -0
  101. package/dist/src/functions/wirings/scenarios/serialize-feature-meta.js +29 -0
  102. package/dist/src/functions/wirings/scenarios/serialize-scenario-meta.d.ts +12 -0
  103. package/dist/src/functions/wirings/scenarios/serialize-scenario-meta.js +56 -0
  104. package/dist/src/functions/wirings/scenarios/serialize-scenario-registration.d.ts +7 -0
  105. package/dist/src/functions/wirings/scenarios/serialize-scenario-registration.js +40 -0
  106. package/dist/src/functions/wirings/workflow/pikku-command-workflow.js +43 -8
  107. package/dist/src/functions/wirings/workflow/serialize-scenario-actors.d.ts +1 -1
  108. package/dist/src/functions/wirings/workflow/serialize-scenario-actors.js +13 -2
  109. package/dist/src/functions/wirings/workflow/serialize-scenario-step-map.d.ts +4 -0
  110. package/dist/src/functions/wirings/workflow/serialize-scenario-step-map.js +62 -0
  111. package/dist/src/functions/wirings/workflow/serialize-workflow-bootstrap-map.js +10 -3
  112. package/dist/src/functions/wirings/workflow/serialize-workflow-map.js +10 -3
  113. package/dist/src/functions/wirings/workflow/serialize-workflow-meta.js +4 -4
  114. package/dist/src/functions/wirings/workflow/serialize-workflow-types.d.ts +1 -1
  115. package/dist/src/functions/wirings/workflow/serialize-workflow-types.js +232 -3
  116. package/dist/src/server/server-ready.d.ts +12 -0
  117. package/dist/src/server/server-ready.js +12 -0
  118. package/dist/src/server/spawn-dev-server.d.ts +50 -0
  119. package/dist/src/server/spawn-dev-server.js +112 -0
  120. package/dist/src/services.js +12 -1
  121. package/dist/src/utils/meta-diff.js +5 -2
  122. package/dist/src/utils/pikku-cli-config.js +26 -0
  123. package/dist/src/utils/resolve-scenario-actors.d.ts +23 -0
  124. package/dist/src/utils/resolve-scenario-actors.js +74 -0
  125. package/dist/tsconfig.tsbuildinfo +1 -1
  126. package/package.json +15 -5
  127. package/skills/pikku-scenario/SKILL.md +196 -29
@@ -0,0 +1,74 @@
1
+ /** Domain for the email of an actor nobody declared. Synthetic either way. */
2
+ const AUTO_ACTOR_EMAIL_DOMAIN = 'actors.local';
3
+ /** `orgAdmin` → `org-admin`, so a derived email reads like an email. */
4
+ const kebab = (key) => key
5
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
6
+ .replace(/[^a-zA-Z0-9]+/g, '-')
7
+ .toLowerCase();
8
+ /**
9
+ * The actor registry a run actually sees: every declared actor, plus one
10
+ * materialised actor for each persona nobody declared an actor for.
11
+ *
12
+ * A persona is the KIND of person (its `description`); an actor is one BODY
13
+ * that signs in, with an email of its own. Most apps want exactly one body per
14
+ * kind, so declaring the persona is enough — this fills in the actor. You only
15
+ * write an actor by hand when a scenario needs TWO of the same kind, which is
16
+ * what tenant-isolation and peer-sharing scenarios are made of.
17
+ *
18
+ * Every consumer must resolve through here rather than reading
19
+ * `config.scenarios.actors` directly: codegen emits `scenarioActorConfigs` from
20
+ * it (and `ScenarioActorName` is a `keyof` over that literal, so an actor missing
21
+ * at codegen time can never be referenced in a typed step), while `scenario run`
22
+ * builds the HTTP and Playwright actor maps from it. Those were already three
23
+ * separate reads of the same field before personas existed.
24
+ */
25
+ export const resolveScenarioActors = (scenarios) => {
26
+ const personas = scenarios?.personas ?? {};
27
+ const declared = scenarios?.actors ?? {};
28
+ const resolved = {};
29
+ for (const [name, actor] of Object.entries(declared)) {
30
+ // An actor named after a persona belongs to it without having to say so —
31
+ // the common case is one body per kind and they share the obvious name.
32
+ const persona = actor.persona ?? (personas[name] ? name : undefined);
33
+ if (persona && !personas[persona]) {
34
+ throw new Error(`Scenario actor '${name}' names persona '${persona}', which is not declared in scenarios.personas` +
35
+ `${Object.keys(personas).length ? ` (declared: ${Object.keys(personas).join(', ')})` : ' (no personas are declared)'}`);
36
+ }
37
+ resolved[name] = persona ? { ...actor, persona } : actor;
38
+ }
39
+ const claimed = new Set(Object.values(resolved)
40
+ .map((actor) => actor.persona)
41
+ .filter((persona) => Boolean(persona)));
42
+ for (const [persona, config] of Object.entries(personas)) {
43
+ if (claimed.has(persona))
44
+ continue;
45
+ // A `system` persona is the app acting on its own. There is nobody to sign
46
+ // in, so minting an actor for it would only produce a scenario that tries.
47
+ // Declaring one by hand is still allowed — a service account is a body.
48
+ if (config.kind === 'system')
49
+ continue;
50
+ resolved[persona] = {
51
+ persona,
52
+ email: `${kebab(persona)}@${AUTO_ACTOR_EMAIL_DOMAIN}`,
53
+ };
54
+ }
55
+ assertDistinctEmails(resolved);
56
+ return resolved;
57
+ };
58
+ /**
59
+ * Two actors sharing an email are the same user row — sign-in keys on email
60
+ * alone (see `HttpScenarioActors.signIn`). That silently collapses exactly the
61
+ * scenarios a second body exists for: an isolation scenario whose two owners
62
+ * are one user passes by construction and proves nothing.
63
+ */
64
+ const assertDistinctEmails = (actors) => {
65
+ const byEmail = new Map();
66
+ for (const [name, actor] of Object.entries(actors)) {
67
+ const email = actor.email.toLowerCase();
68
+ const owner = byEmail.get(email);
69
+ if (owner) {
70
+ throw new Error(`Scenario actors '${owner}' and '${name}' share the email '${actor.email}' — they would sign in as the same user`);
71
+ }
72
+ byEmail.set(email, name);
73
+ }
74
+ };
@@ -1 +1 @@
1
- {"root":["../bin/pikku.ts","../src/cli.wiring.ts","../src/services.ts","../src/deploy/build-pipeline.ts","../src/deploy/provider-adapter.ts","../src/deploy/server-entry.ts","../src/deploy/analyzer/analyzer.ts","../src/deploy/analyzer/index.ts","../src/deploy/analyzer/manifest.ts","../src/deploy/bundler/bun-bundler.ts","../src/deploy/bundler/bundler.interface.ts","../src/deploy/bundler/bundler.ts","../src/deploy/bundler/dep-extractor.ts","../src/deploy/bundler/index.ts","../src/deploy/bundler/node-bundler.ts","../src/deploy/bundler/types.ts","../src/deploy/codegen/index.ts","../src/deploy/codegen/per-unit-codegen.ts","../src/deploy/plan/executor.ts","../src/deploy/plan/formatter.ts","../src/deploy/plan/index.ts","../src/deploy/plan/planner.ts","../src/deploy/plan/provider.ts","../src/deploy/plan/types.ts","../src/fabric/fabric-commands.ts","../src/fabric/functions/add.function.ts","../src/fabric/functions/addon-verify.function.ts","../src/fabric/functions/db-schema.function.ts","../src/fabric/functions/deploy-list.function.ts","../src/fabric/functions/deploy-units.function.ts","../src/fabric/functions/deploy.function.ts","../src/fabric/functions/domains-add.function.ts","../src/fabric/functions/domains-list.function.ts","../src/fabric/functions/domains-remove.function.ts","../src/fabric/functions/errors.function.ts","../src/fabric/functions/init.function.ts","../src/fabric/functions/link.function.ts","../src/fabric/functions/llm-key.function.ts","../src/fabric/functions/login.function.ts","../src/fabric/functions/logs.function.ts","../src/fabric/functions/metrics.function.ts","../src/fabric/functions/publish.function.ts","../src/fabric/functions/rollback.function.ts","../src/fabric/functions/secrets-list.function.ts","../src/fabric/functions/secrets-set.function.ts","../src/fabric/functions/smoke.function.ts","../src/fabric/functions/status.function.ts","../src/fabric/functions/trace.function.ts","../src/fabric/functions/validate.function.ts","../src/fabric/lib/config.ts","../src/fabric/lib/console-url.ts","../src/fabric/lib/frontend-typecheck.ts","../src/fabric/lib/git.ts","../src/fabric/lib/http.ts","../src/fabric/lib/not-implemented.ts","../src/fabric/lib/output.ts","../src/fabric/lib/prompt.ts","../src/fabric/lib/stage.ts","../src/fabric/sdk/http-map.gen.d.ts","../src/fabric/sdk/pikku-fetch.gen.ts","../src/fabric/sdk/pikku-rpc.gen.ts","../src/fabric/sdk/rpc-map.gen.d.ts","../src/functions/commands/all.ts","../src/functions/commands/audit.ts","../src/functions/commands/binary.ts","../src/functions/commands/bootstrap.ts","../src/functions/commands/bun-coverage-loader.ts","../src/functions/commands/db-audit.ts","../src/functions/commands/db-baseline.ts","../src/functions/commands/db-check.ts","../src/functions/commands/db-codegen.ts","../src/functions/commands/db-export.ts","../src/functions/commands/db-generate.ts","../src/functions/commands/db-migrate.ts","../src/functions/commands/db-reset.ts","../src/functions/commands/db-seed.ts","../src/functions/commands/db-shared.ts","../src/functions/commands/deploy-apply.ts","../src/functions/commands/deploy-info.ts","../src/functions/commands/deploy-plan.ts","../src/functions/commands/dev-ai-runner.ts","../src/functions/commands/dev.ts","../src/functions/commands/emails-init.ts","../src/functions/commands/enable.ts","../src/functions/commands/import-n8n.ts","../src/functions/commands/info.ts","../src/functions/commands/load-user-project.ts","../src/functions/commands/login.ts","../src/functions/commands/meta.ts","../src/functions/commands/new-addon.ts","../src/functions/commands/new-function.ts","../src/functions/commands/new-middleware.ts","../src/functions/commands/new-permission.ts","../src/functions/commands/new-wiring.ts","../src/functions/commands/pikku-command-bootstrap.ts","../src/functions/commands/pikku-command-summary.ts","../src/functions/commands/scenario.ts","../src/functions/commands/scopes-audit.ts","../src/functions/commands/scopes-prune.ts","../src/functions/commands/scopes-shared.ts","../src/functions/commands/serve-console.ts","../src/functions/commands/serve.ts","../src/functions/commands/skills.ts","../src/functions/commands/start-coverage.ts","../src/functions/commands/versions-check.ts","../src/functions/commands/versions-init.ts","../src/functions/commands/versions-update.ts","../src/functions/commands/watch.ts","../src/functions/commands/workspace-validate.ts","../src/functions/db/annotation-parser.ts","../src/functions/db/better-auth-schema.ts","../src/functions/db/coercion-plugin.ts","../src/functions/db/db-codegen.ts","../src/functions/db/db-introspector.ts","../src/functions/db/db-migrator.ts","../src/functions/db/local-db.ts","../src/functions/db/zod-codegen.ts","../src/functions/db/postgres/pglite-kysely.ts","../src/functions/db/postgres/postgres-introspector.ts","../src/functions/db/postgres/postgres-migrator.ts","../src/functions/db/sqlite/seed.ts","../src/functions/db/sqlite/sqlite-introspector.ts","../src/functions/db/sqlite/sqlite-kysely.ts","../src/functions/db/sqlite/sqlite-migrator.ts","../src/functions/db/sqlite/sqlite-runtime-bun.ts","../src/functions/db/sqlite/sqlite-runtime-node.ts","../src/functions/db/sqlite/sqlite-runtime.ts","../src/functions/runtimes/fetch/index.ts","../src/functions/runtimes/nextjs/pikku-command-nextjs.ts","../src/functions/runtimes/nextjs/serialize-nextjs-backend-worker-rpc-wrapper.ts","../src/functions/runtimes/nextjs/serialize-nextjs-backend-wrapper.ts","../src/functions/runtimes/nextjs/serialize-nextjs-http-wrapper.ts","../src/functions/runtimes/tanstack-start/pikku-command-tanstack-start.ts","../src/functions/runtimes/tanstack-start/serialize-tanstack-start-shim.ts","../src/functions/runtimes/websocket/pikku-command-websocket-typed.ts","../src/functions/runtimes/websocket/serialize-websocket-wrapper.ts","../src/functions/validate/workspace-validate.ts","../src/functions/wirings/ai-agent/pikku-command-ai-agent-types.ts","../src/functions/wirings/ai-agent/pikku-command-ai-agent.ts","../src/functions/wirings/ai-agent/pikku-command-public-agent.ts","../src/functions/wirings/ai-agent/serialize-agent-map.ts","../src/functions/wirings/ai-agent/serialize-ai-agent-types.ts","../src/functions/wirings/ai-agent/serialize-public-agent.ts","../src/functions/wirings/auth/pikku-command-auth.ts","../src/functions/wirings/auth/serialize-auth-gen.ts","../src/functions/wirings/auth/serialize-auth-meta.ts","../src/functions/wirings/auth/serialize-auth-types.ts","../src/functions/wirings/channels/pikku-channels.ts","../src/functions/wirings/channels/pikku-command-channel-types.ts","../src/functions/wirings/channels/pikku-command-channels-map.ts","../src/functions/wirings/channels/pikku-command-channels.ts","../src/functions/wirings/channels/serialize-channel-types.ts","../src/functions/wirings/channels/serialize-typed-channel-map.ts","../src/functions/wirings/cli/pikku-command-cli-entry.ts","../src/functions/wirings/cli/pikku-command-cli-types.ts","../src/functions/wirings/cli/pikku-command-cli.ts","../src/functions/wirings/cli/serialize-channel-cli-client.ts","../src/functions/wirings/cli/serialize-channel-cli.ts","../src/functions/wirings/cli/serialize-cli-types.ts","../src/functions/wirings/cli/serialize-local-cli-bootstrap.ts","../src/functions/wirings/console/pikku-command-console-functions.ts","../src/functions/wirings/console/pikku-command-node-types.ts","../src/functions/wirings/console/pikku-command-nodes-meta.ts","../src/functions/wirings/console/serialize-console-functions.ts","../src/functions/wirings/console/serialize-node-types.ts","../src/functions/wirings/credentials/pikku-command-credentials.ts","../src/functions/wirings/credentials/serialize-credentials-types.ts","../src/functions/wirings/emails/pikku-command-emails.ts","../src/functions/wirings/emails/serialize-emails.ts","../src/functions/wirings/functions/pikku-command-addon-types.ts","../src/functions/wirings/functions/pikku-command-function-types-split.ts","../src/functions/wirings/functions/pikku-command-function-types.ts","../src/functions/wirings/functions/pikku-command-functions.ts","../src/functions/wirings/functions/pikku-command-services.ts","../src/functions/wirings/functions/schemas.ts","../src/functions/wirings/functions/serialize-addon-refs.ts","../src/functions/wirings/functions/serialize-addon-types.ts","../src/functions/wirings/functions/serialize-function-imports.ts","../src/functions/wirings/functions/serialize-function-types.ts","../src/functions/wirings/functions/serialize-pikku-types-hub.ts","../src/functions/wirings/gateway/pikku-command-gateway.ts","../src/functions/wirings/gateway/serialize-gateway-meta.ts","../src/functions/wirings/graph/pikku-command-graph-wirings.ts","../src/functions/wirings/graph/serialize-graph-wirings.ts","../src/functions/wirings/http/pikku-command-http-map.ts","../src/functions/wirings/http/pikku-command-http-routes.ts","../src/functions/wirings/http/pikku-command-http-types.ts","../src/functions/wirings/http/pikku-command-openapi.ts","../src/functions/wirings/http/pikku-http-routes.ts","../src/functions/wirings/http/serialize-fetch-wrapper.ts","../src/functions/wirings/http/serialize-http-types.ts","../src/functions/wirings/http/serialize-typed-http-map.ts","../src/functions/wirings/mcp/pikku-command-mcp-json.ts","../src/functions/wirings/mcp/pikku-command-mcp-types.ts","../src/functions/wirings/mcp/pikku-command-mcp.ts","../src/functions/wirings/mcp/serialize-mcp-types.ts","../src/functions/wirings/middleware/pikku-command-middleware.ts","../src/functions/wirings/middleware/serialize-middleware-imports.ts","../src/functions/wirings/package/pikku-command-package-types.ts","../src/functions/wirings/package/pikku-command-package.ts","../src/functions/wirings/package/serialize-package-types.ts","../src/functions/wirings/package/serialize-package.ts","../src/functions/wirings/permissions/pikku-command-permissions.ts","../src/functions/wirings/permissions/serialize-permissions-imports.ts","../src/functions/wirings/queue/pikku-command-queue-map.ts","../src/functions/wirings/queue/pikku-command-queue-service.ts","../src/functions/wirings/queue/pikku-command-queue-types.ts","../src/functions/wirings/queue/pikku-command-queue.ts","../src/functions/wirings/queue/pikku-queue-map.ts","../src/functions/wirings/queue/pikku-queue.ts","../src/functions/wirings/queue/serialize-queue-map.ts","../src/functions/wirings/queue/serialize-queue-meta.ts","../src/functions/wirings/queue/serialize-queue-types.ts","../src/functions/wirings/queue/serialize-queue-wrapper.ts","../src/functions/wirings/realtime/pikku-command-events-scaffold.ts","../src/functions/wirings/realtime/pikku-command-realtime.ts","../src/functions/wirings/realtime/serialize-events-scaffold.ts","../src/functions/wirings/realtime/serialize-realtime-client.ts","../src/functions/wirings/rpc/pikku-command-public-rpc.ts","../src/functions/wirings/rpc/pikku-command-react-query.ts","../src/functions/wirings/rpc/pikku-command-remote-rpc.ts","../src/functions/wirings/rpc/pikku-command-rpc-client.ts","../src/functions/wirings/rpc/pikku-command-rpc-map.ts","../src/functions/wirings/rpc/pikku-command-rpc.ts","../src/functions/wirings/rpc/serialize-public-rpc.ts","../src/functions/wirings/rpc/serialize-react-query-hooks.ts","../src/functions/wirings/rpc/serialize-remote-rpc.ts","../src/functions/wirings/rpc/serialize-rpc-wrapper.ts","../src/functions/wirings/rpc/serialize-typed-rpc-map.ts","../src/functions/wirings/scenarios/pikku-command-scenario-functions.ts","../src/functions/wirings/scenarios/serialize-scenario-functions.ts","../src/functions/wirings/scheduler/pikku-command-scheduler-types.ts","../src/functions/wirings/scheduler/pikku-command-scheduler.ts","../src/functions/wirings/scheduler/serialize-scheduler-meta.ts","../src/functions/wirings/scheduler/serialize-scheduler-types.ts","../src/functions/wirings/scopes/pikku-command-scopes.ts","../src/functions/wirings/scopes/serialize-scopes-types.ts","../src/functions/wirings/secrets/pikku-command-secrets.ts","../src/functions/wirings/secrets/serialize-secrets-types.ts","../src/functions/wirings/triggers/pikku-command-trigger-types.ts","../src/functions/wirings/triggers/pikku-command-trigger.ts","../src/functions/wirings/triggers/serialize-trigger-meta.ts","../src/functions/wirings/triggers/serialize-trigger-types.ts","../src/functions/wirings/user-admin/pikku-command-user-admin-functions.ts","../src/functions/wirings/user-admin/serialize-user-admin-functions.ts","../src/functions/wirings/variables/pikku-command-variables.ts","../src/functions/wirings/variables/serialize-variables-types.ts","../src/functions/wirings/webhook/pikku-command-webhook.ts","../src/functions/wirings/webhook/serialize-webhook.ts","../src/functions/wirings/workflow/pikku-command-workflow-routes.ts","../src/functions/wirings/workflow/pikku-command-workflow.ts","../src/functions/wirings/workflow/serialize-scenario-actors.ts","../src/functions/wirings/workflow/serialize-workflow-bootstrap-map.ts","../src/functions/wirings/workflow/serialize-workflow-map.ts","../src/functions/wirings/workflow/serialize-workflow-meta.ts","../src/functions/wirings/workflow/serialize-workflow-registration.ts","../src/functions/wirings/workflow/serialize-workflow-routes.ts","../src/functions/wirings/workflow/serialize-workflow-types.ts","../src/functions/workflows/all.workflow.ts","../src/middleware/log-command-info-and-time.ts","../src/server/bun-server-runner.ts","../src/server/dev-server-runner.interface.ts","../src/server/node-server-runner.ts","../src/services/cli-logger-forwarder.service.ts","../src/services/cli-logger.service.ts","../src/utils/assert-single-core-version.ts","../src/utils/check-required-types.ts","../src/utils/cli-session.ts","../src/utils/command-summary.ts","../src/utils/contract-versions.ts","../src/utils/detect-better-auth.ts","../src/utils/device-auth.ts","../src/utils/file-import-path.ts","../src/utils/file-imports-serializer.ts","../src/utils/file-writer.ts","../src/utils/generate-bootstrap-file.ts","../src/utils/get-cli-version.ts","../src/utils/meta-diff.ts","../src/utils/parse-cli-filters.ts","../src/utils/pikku-cli-config.ts","../src/utils/pikku-files-and-methods.ts","../src/utils/precise-coverage-map.ts","../src/utils/remove-legacy-scaffold-file.ts","../src/utils/serialize-import-map.ts","../src/utils/serialize-meta-ts.ts","../src/utils/serialize-schemas.ts","../src/utils/strip-verbose-meta.ts","../src/utils/tsc-check.ts","../.pikku/pikku-bootstrap.gen.ts","../.pikku/pikku-meta-service.gen.ts","../.pikku/pikku-services.gen.ts","../.pikku/pikku-types.gen.ts","../.pikku/agent/pikku-agent-map.gen.d.ts","../.pikku/agent/pikku-agent-types.gen.ts","../.pikku/auth/auth.types.ts","../.pikku/channel/pikku-channel-types.gen.ts","../.pikku/cli/pikku-cli-channel.ts","../.pikku/cli/pikku-cli-client.gen.ts","../.pikku/cli/pikku-cli-contracts-meta.gen.ts","../.pikku/cli/pikku-cli-types.gen.ts","../.pikku/cli/pikku-cli-wirings-meta.gen.ts","../.pikku/cli/pikku-cli-wirings.gen.ts","../.pikku/cli/pikku-cli.gen.ts","../.pikku/console/pikku-node-types.gen.ts","../.pikku/function/pikku-function-types.gen.ts","../.pikku/function/pikku-functions-meta.gen.ts","../.pikku/function/pikku-functions.gen.ts","../.pikku/http/pikku-http-types.gen.ts","../.pikku/mcp/pikku-mcp-types.gen.ts","../.pikku/node/pikku-node-types.gen.ts","../.pikku/queue/pikku-queue-types.gen.ts","../.pikku/queue/pikku-queue-workers-wirings-map.gen.d.ts","../.pikku/queue/pikku-queue-workers-wirings-meta.gen.ts","../.pikku/queue/pikku-queue-workers-wirings.gen.ts","../.pikku/rpc/pikku-rpc-wirings-map.gen.d.ts","../.pikku/rpc/pikku-rpc-wirings-map.internal.gen.d.ts","../.pikku/rpc/pikku-rpc-wirings-map.remote.gen.d.ts","../.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.ts","../.pikku/scheduler/pikku-scheduler-types.gen.ts","../.pikku/schemas/register.gen.ts","../.pikku/scopes/pikku-scope-types.gen.ts","../.pikku/scopes/pikku-scopes.gen.ts","../.pikku/secrets/pikku-secret-types.gen.ts","../.pikku/secrets/pikku-secrets.gen.ts","../.pikku/trigger/pikku-trigger-types.gen.ts","../.pikku/variables/pikku-variable-types.gen.ts","../.pikku/variables/pikku-variables.gen.ts","../.pikku/workflow/pikku-workflow-map.gen.d.ts","../.pikku/workflow/pikku-workflow-types.gen.ts","../.pikku/workflow/pikku-workflow-wirings-meta.gen.ts","../.pikku/workflow/pikku-workflow-wirings.gen.ts","../types/application-types.d.ts","../types/bun-sqlite.d.ts","../types/config.d.ts"],"version":"6.0.3"}
1
+ {"root":["../bin/pikku.ts","../src/cli.wiring.ts","../src/services.ts","../src/deploy/build-pipeline.ts","../src/deploy/provider-adapter.ts","../src/deploy/server-entry.ts","../src/deploy/analyzer/analyzer.ts","../src/deploy/analyzer/index.ts","../src/deploy/analyzer/manifest.ts","../src/deploy/bundler/bun-bundler.ts","../src/deploy/bundler/bundler.interface.ts","../src/deploy/bundler/bundler.ts","../src/deploy/bundler/dep-extractor.ts","../src/deploy/bundler/index.ts","../src/deploy/bundler/node-bundler.ts","../src/deploy/bundler/types.ts","../src/deploy/codegen/index.ts","../src/deploy/codegen/per-unit-codegen.ts","../src/deploy/plan/executor.ts","../src/deploy/plan/formatter.ts","../src/deploy/plan/index.ts","../src/deploy/plan/planner.ts","../src/deploy/plan/provider.ts","../src/deploy/plan/types.ts","../src/fabric/fabric-commands.ts","../src/fabric/functions/add.function.ts","../src/fabric/functions/addon-verify.function.ts","../src/fabric/functions/db-schema.function.ts","../src/fabric/functions/deploy-list.function.ts","../src/fabric/functions/deploy-units.function.ts","../src/fabric/functions/deploy.function.ts","../src/fabric/functions/domains-add.function.ts","../src/fabric/functions/domains-list.function.ts","../src/fabric/functions/domains-remove.function.ts","../src/fabric/functions/errors.function.ts","../src/fabric/functions/init.function.ts","../src/fabric/functions/link.function.ts","../src/fabric/functions/llm-key.function.ts","../src/fabric/functions/login.function.ts","../src/fabric/functions/logs.function.ts","../src/fabric/functions/metrics.function.ts","../src/fabric/functions/publish.function.ts","../src/fabric/functions/rollback.function.ts","../src/fabric/functions/secrets-list.function.ts","../src/fabric/functions/secrets-set.function.ts","../src/fabric/functions/smoke.function.ts","../src/fabric/functions/status.function.ts","../src/fabric/functions/trace.function.ts","../src/fabric/functions/validate.function.ts","../src/fabric/lib/config.ts","../src/fabric/lib/console-url.ts","../src/fabric/lib/frontend-typecheck.ts","../src/fabric/lib/git.ts","../src/fabric/lib/http.ts","../src/fabric/lib/not-implemented.ts","../src/fabric/lib/output.ts","../src/fabric/lib/prompt.ts","../src/fabric/lib/stage.ts","../src/fabric/sdk/http-map.gen.d.ts","../src/fabric/sdk/pikku-fetch.gen.ts","../src/fabric/sdk/pikku-rpc.gen.ts","../src/fabric/sdk/rpc-map.gen.d.ts","../src/functions/commands/all.ts","../src/functions/commands/audit.ts","../src/functions/commands/binary.ts","../src/functions/commands/bootstrap.ts","../src/functions/commands/bun-coverage-loader.ts","../src/functions/commands/db-audit.ts","../src/functions/commands/db-baseline.ts","../src/functions/commands/db-check.ts","../src/functions/commands/db-codegen.ts","../src/functions/commands/db-export.ts","../src/functions/commands/db-generate.ts","../src/functions/commands/db-migrate.ts","../src/functions/commands/db-reset.ts","../src/functions/commands/db-seed.ts","../src/functions/commands/db-shared.ts","../src/functions/commands/deploy-apply.ts","../src/functions/commands/deploy-info.ts","../src/functions/commands/deploy-plan.ts","../src/functions/commands/dev-ai-runner.ts","../src/functions/commands/dev.ts","../src/functions/commands/emails-init.ts","../src/functions/commands/enable.ts","../src/functions/commands/import-n8n.ts","../src/functions/commands/info.ts","../src/functions/commands/load-user-project.ts","../src/functions/commands/login.ts","../src/functions/commands/meta.ts","../src/functions/commands/new-addon.ts","../src/functions/commands/new-function.ts","../src/functions/commands/new-middleware.ts","../src/functions/commands/new-permission.ts","../src/functions/commands/new-wiring.ts","../src/functions/commands/pikku-command-bootstrap.ts","../src/functions/commands/pikku-command-summary.ts","../src/functions/commands/scenario-browser.ts","../src/functions/commands/scenario-formatter.ts","../src/functions/commands/scenario-ladder.ts","../src/functions/commands/scenario-plan.ts","../src/functions/commands/scenario.ts","../src/functions/commands/scopes-audit.ts","../src/functions/commands/scopes-prune.ts","../src/functions/commands/scopes-shared.ts","../src/functions/commands/serve-console.ts","../src/functions/commands/serve.ts","../src/functions/commands/skills.ts","../src/functions/commands/start-coverage.ts","../src/functions/commands/versions-check.ts","../src/functions/commands/versions-init.ts","../src/functions/commands/versions-update.ts","../src/functions/commands/watch.ts","../src/functions/commands/workspace-validate.ts","../src/functions/db/annotation-parser.ts","../src/functions/db/better-auth-schema.ts","../src/functions/db/coercion-plugin.ts","../src/functions/db/db-codegen.ts","../src/functions/db/db-introspector.ts","../src/functions/db/db-migrator.ts","../src/functions/db/local-db.ts","../src/functions/db/zod-codegen.ts","../src/functions/db/postgres/pglite-kysely.ts","../src/functions/db/postgres/postgres-introspector.ts","../src/functions/db/postgres/postgres-migrator.ts","../src/functions/db/sqlite/seed.ts","../src/functions/db/sqlite/sqlite-introspector.ts","../src/functions/db/sqlite/sqlite-kysely.ts","../src/functions/db/sqlite/sqlite-migrator.ts","../src/functions/db/sqlite/sqlite-runtime-bun.ts","../src/functions/db/sqlite/sqlite-runtime-node.ts","../src/functions/db/sqlite/sqlite-runtime.ts","../src/functions/runtimes/fetch/index.ts","../src/functions/runtimes/nextjs/pikku-command-nextjs.ts","../src/functions/runtimes/nextjs/serialize-nextjs-backend-worker-rpc-wrapper.ts","../src/functions/runtimes/nextjs/serialize-nextjs-backend-wrapper.ts","../src/functions/runtimes/nextjs/serialize-nextjs-http-wrapper.ts","../src/functions/runtimes/tanstack-start/pikku-command-tanstack-start.ts","../src/functions/runtimes/tanstack-start/serialize-tanstack-start-shim.ts","../src/functions/runtimes/websocket/pikku-command-websocket-typed.ts","../src/functions/runtimes/websocket/serialize-websocket-wrapper.ts","../src/functions/validate/workspace-validate.ts","../src/functions/wirings/ai-agent/pikku-command-ai-agent-types.ts","../src/functions/wirings/ai-agent/pikku-command-ai-agent.ts","../src/functions/wirings/ai-agent/pikku-command-public-agent.ts","../src/functions/wirings/ai-agent/serialize-agent-map.ts","../src/functions/wirings/ai-agent/serialize-ai-agent-types.ts","../src/functions/wirings/ai-agent/serialize-public-agent.ts","../src/functions/wirings/auth/pikku-command-auth.ts","../src/functions/wirings/auth/serialize-auth-gen.ts","../src/functions/wirings/auth/serialize-auth-meta.ts","../src/functions/wirings/auth/serialize-auth-types.ts","../src/functions/wirings/channels/pikku-channels.ts","../src/functions/wirings/channels/pikku-command-channel-types.ts","../src/functions/wirings/channels/pikku-command-channels-map.ts","../src/functions/wirings/channels/pikku-command-channels.ts","../src/functions/wirings/channels/serialize-channel-types.ts","../src/functions/wirings/channels/serialize-typed-channel-map.ts","../src/functions/wirings/cli/pikku-command-cli-entry.ts","../src/functions/wirings/cli/pikku-command-cli-types.ts","../src/functions/wirings/cli/pikku-command-cli.ts","../src/functions/wirings/cli/serialize-channel-cli-client.ts","../src/functions/wirings/cli/serialize-channel-cli.ts","../src/functions/wirings/cli/serialize-cli-types.ts","../src/functions/wirings/cli/serialize-local-cli-bootstrap.ts","../src/functions/wirings/console/pikku-command-console-functions.ts","../src/functions/wirings/console/pikku-command-node-types.ts","../src/functions/wirings/console/pikku-command-nodes-meta.ts","../src/functions/wirings/console/serialize-console-functions.ts","../src/functions/wirings/console/serialize-node-types.ts","../src/functions/wirings/credentials/pikku-command-credentials.ts","../src/functions/wirings/credentials/serialize-credentials-types.ts","../src/functions/wirings/emails/pikku-command-emails.ts","../src/functions/wirings/emails/serialize-emails.ts","../src/functions/wirings/functions/pikku-command-addon-types.ts","../src/functions/wirings/functions/pikku-command-function-types-split.ts","../src/functions/wirings/functions/pikku-command-function-types.ts","../src/functions/wirings/functions/pikku-command-functions.ts","../src/functions/wirings/functions/pikku-command-services.ts","../src/functions/wirings/functions/schemas.ts","../src/functions/wirings/functions/serialize-addon-refs.ts","../src/functions/wirings/functions/serialize-addon-types.ts","../src/functions/wirings/functions/serialize-function-imports.ts","../src/functions/wirings/functions/serialize-function-types.ts","../src/functions/wirings/functions/serialize-pikku-types-hub.ts","../src/functions/wirings/gateway/pikku-command-gateway.ts","../src/functions/wirings/gateway/serialize-gateway-meta.ts","../src/functions/wirings/graph/pikku-command-graph-wirings.ts","../src/functions/wirings/graph/serialize-graph-wirings.ts","../src/functions/wirings/http/pikku-command-http-map.ts","../src/functions/wirings/http/pikku-command-http-routes.ts","../src/functions/wirings/http/pikku-command-http-types.ts","../src/functions/wirings/http/pikku-command-openapi.ts","../src/functions/wirings/http/pikku-http-routes.ts","../src/functions/wirings/http/serialize-fetch-wrapper.ts","../src/functions/wirings/http/serialize-http-types.ts","../src/functions/wirings/http/serialize-typed-http-map.ts","../src/functions/wirings/mcp/pikku-command-mcp-json.ts","../src/functions/wirings/mcp/pikku-command-mcp-types.ts","../src/functions/wirings/mcp/pikku-command-mcp.ts","../src/functions/wirings/mcp/serialize-mcp-types.ts","../src/functions/wirings/middleware/pikku-command-middleware.ts","../src/functions/wirings/middleware/serialize-middleware-imports.ts","../src/functions/wirings/package/pikku-command-package-types.ts","../src/functions/wirings/package/pikku-command-package.ts","../src/functions/wirings/package/serialize-package-types.ts","../src/functions/wirings/package/serialize-package.ts","../src/functions/wirings/permissions/pikku-command-permissions.ts","../src/functions/wirings/permissions/serialize-permissions-imports.ts","../src/functions/wirings/queue/pikku-command-queue-map.ts","../src/functions/wirings/queue/pikku-command-queue-service.ts","../src/functions/wirings/queue/pikku-command-queue-types.ts","../src/functions/wirings/queue/pikku-command-queue.ts","../src/functions/wirings/queue/pikku-queue-map.ts","../src/functions/wirings/queue/pikku-queue.ts","../src/functions/wirings/queue/serialize-queue-map.ts","../src/functions/wirings/queue/serialize-queue-meta.ts","../src/functions/wirings/queue/serialize-queue-types.ts","../src/functions/wirings/queue/serialize-queue-wrapper.ts","../src/functions/wirings/realtime/pikku-command-events-scaffold.ts","../src/functions/wirings/realtime/pikku-command-realtime.ts","../src/functions/wirings/realtime/serialize-events-scaffold.ts","../src/functions/wirings/realtime/serialize-realtime-client.ts","../src/functions/wirings/rpc/pikku-command-public-rpc.ts","../src/functions/wirings/rpc/pikku-command-react-query.ts","../src/functions/wirings/rpc/pikku-command-remote-rpc.ts","../src/functions/wirings/rpc/pikku-command-rpc-client.ts","../src/functions/wirings/rpc/pikku-command-rpc-map.ts","../src/functions/wirings/rpc/pikku-command-rpc.ts","../src/functions/wirings/rpc/serialize-public-rpc.ts","../src/functions/wirings/rpc/serialize-react-query-hooks.ts","../src/functions/wirings/rpc/serialize-remote-rpc.ts","../src/functions/wirings/rpc/serialize-rpc-wrapper.ts","../src/functions/wirings/rpc/serialize-typed-rpc-map.ts","../src/functions/wirings/scenarios/pikku-command-scenario-functions.ts","../src/functions/wirings/scenarios/scenario-partition.ts","../src/functions/wirings/scenarios/serialize-feature-meta.ts","../src/functions/wirings/scenarios/serialize-scenario-functions.ts","../src/functions/wirings/scenarios/serialize-scenario-meta.ts","../src/functions/wirings/scenarios/serialize-scenario-registration.ts","../src/functions/wirings/scheduler/pikku-command-scheduler-types.ts","../src/functions/wirings/scheduler/pikku-command-scheduler.ts","../src/functions/wirings/scheduler/serialize-scheduler-meta.ts","../src/functions/wirings/scheduler/serialize-scheduler-types.ts","../src/functions/wirings/scopes/pikku-command-scopes.ts","../src/functions/wirings/scopes/serialize-scopes-types.ts","../src/functions/wirings/secrets/pikku-command-secrets.ts","../src/functions/wirings/secrets/serialize-secrets-types.ts","../src/functions/wirings/triggers/pikku-command-trigger-types.ts","../src/functions/wirings/triggers/pikku-command-trigger.ts","../src/functions/wirings/triggers/serialize-trigger-meta.ts","../src/functions/wirings/triggers/serialize-trigger-types.ts","../src/functions/wirings/user-admin/pikku-command-user-admin-functions.ts","../src/functions/wirings/user-admin/serialize-user-admin-functions.ts","../src/functions/wirings/variables/pikku-command-variables.ts","../src/functions/wirings/variables/serialize-variables-types.ts","../src/functions/wirings/webhook/pikku-command-webhook.ts","../src/functions/wirings/webhook/serialize-webhook.ts","../src/functions/wirings/workflow/pikku-command-workflow-routes.ts","../src/functions/wirings/workflow/pikku-command-workflow.ts","../src/functions/wirings/workflow/serialize-scenario-actors.ts","../src/functions/wirings/workflow/serialize-scenario-step-map.ts","../src/functions/wirings/workflow/serialize-workflow-bootstrap-map.ts","../src/functions/wirings/workflow/serialize-workflow-map.ts","../src/functions/wirings/workflow/serialize-workflow-meta.ts","../src/functions/wirings/workflow/serialize-workflow-registration.ts","../src/functions/wirings/workflow/serialize-workflow-routes.ts","../src/functions/wirings/workflow/serialize-workflow-types.ts","../src/functions/workflows/all.workflow.ts","../src/middleware/log-command-info-and-time.ts","../src/server/bun-server-runner.ts","../src/server/dev-server-runner.interface.ts","../src/server/node-server-runner.ts","../src/server/server-ready.ts","../src/server/spawn-dev-server.ts","../src/services/cli-logger-forwarder.service.ts","../src/services/cli-logger.service.ts","../src/utils/assert-single-core-version.ts","../src/utils/check-required-types.ts","../src/utils/cli-session.ts","../src/utils/command-summary.ts","../src/utils/contract-versions.ts","../src/utils/detect-better-auth.ts","../src/utils/device-auth.ts","../src/utils/file-import-path.ts","../src/utils/file-imports-serializer.ts","../src/utils/file-writer.ts","../src/utils/generate-bootstrap-file.ts","../src/utils/get-cli-version.ts","../src/utils/meta-diff.ts","../src/utils/parse-cli-filters.ts","../src/utils/pikku-cli-config.ts","../src/utils/pikku-files-and-methods.ts","../src/utils/precise-coverage-map.ts","../src/utils/remove-legacy-scaffold-file.ts","../src/utils/resolve-scenario-actors.ts","../src/utils/serialize-import-map.ts","../src/utils/serialize-meta-ts.ts","../src/utils/serialize-schemas.ts","../src/utils/strip-verbose-meta.ts","../src/utils/tsc-check.ts","../.pikku/pikku-bootstrap-scenarios.gen.ts","../.pikku/pikku-bootstrap.gen.ts","../.pikku/pikku-meta-service.gen.ts","../.pikku/pikku-services.gen.ts","../.pikku/pikku-types.gen.ts","../.pikku/agent/pikku-agent-map.gen.d.ts","../.pikku/agent/pikku-agent-types.gen.ts","../.pikku/auth/auth.types.ts","../.pikku/channel/pikku-channel-types.gen.ts","../.pikku/cli/pikku-cli-channel.ts","../.pikku/cli/pikku-cli-client.gen.ts","../.pikku/cli/pikku-cli-contracts-meta.gen.ts","../.pikku/cli/pikku-cli-types.gen.ts","../.pikku/cli/pikku-cli-wirings-meta.gen.ts","../.pikku/cli/pikku-cli-wirings.gen.ts","../.pikku/cli/pikku-cli.gen.ts","../.pikku/console/pikku-node-types.gen.ts","../.pikku/function/pikku-function-types.gen.ts","../.pikku/function/pikku-functions-meta.gen.ts","../.pikku/function/pikku-functions.gen.ts","../.pikku/http/pikku-http-types.gen.ts","../.pikku/mcp/pikku-mcp-types.gen.ts","../.pikku/node/pikku-node-types.gen.ts","../.pikku/queue/pikku-queue-types.gen.ts","../.pikku/queue/pikku-queue-workers-wirings-map.gen.d.ts","../.pikku/queue/pikku-queue-workers-wirings-meta.gen.ts","../.pikku/queue/pikku-queue-workers-wirings.gen.ts","../.pikku/rpc/pikku-rpc-wirings-map.gen.d.ts","../.pikku/rpc/pikku-rpc-wirings-map.internal.gen.d.ts","../.pikku/rpc/pikku-rpc-wirings-map.remote.gen.d.ts","../.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.ts","../.pikku/scenarios/pikku-scenario-functions-meta.gen.ts","../.pikku/scenarios/pikku-scenario-functions.gen.ts","../.pikku/scenarios/pikku-scenario-wirings-meta.gen.ts","../.pikku/scenarios/pikku-scenario-wirings.gen.ts","../.pikku/scheduler/pikku-scheduler-types.gen.ts","../.pikku/schemas/register.gen.ts","../.pikku/scopes/pikku-scope-types.gen.ts","../.pikku/scopes/pikku-scopes.gen.ts","../.pikku/secrets/pikku-secret-types.gen.ts","../.pikku/secrets/pikku-secrets.gen.ts","../.pikku/trigger/pikku-trigger-types.gen.ts","../.pikku/variables/pikku-variable-types.gen.ts","../.pikku/variables/pikku-variables.gen.ts","../.pikku/workflow/pikku-scenario-actors.gen.ts","../.pikku/workflow/pikku-scenario-step-map.gen.d.ts","../.pikku/workflow/pikku-workflow-map.gen.d.ts","../.pikku/workflow/pikku-workflow-types.gen.ts","../.pikku/workflow/pikku-workflow-wirings-meta.gen.ts","../.pikku/workflow/pikku-workflow-wirings.gen.ts","../types/application-types.d.ts","../types/bun-sqlite.d.ts","../types/config.d.ts"],"version":"6.0.3"}
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@pikku/cli",
3
- "version": "0.12.90",
3
+ "version": "0.12.91",
4
+ "description": "Pikku CLI — code generation, dev server, migrations and deployment",
4
5
  "author": "yasser.fadl@gmail.com",
5
6
  "license": "BUSL-1.1",
6
7
  "imports": {
@@ -32,7 +33,7 @@
32
33
  "@pikku/bun-server": "^0.12.4",
33
34
  "@pikku/deploy-cloudflare": "^0.12.8",
34
35
  "@pikku/fetch": "^0.12.8",
35
- "@pikku/inspector": "^0.12.47",
36
+ "@pikku/inspector": "^0.12.48",
36
37
  "@pikku/kysely": "^0.13.4",
37
38
  "@pikku/kysely-node-sqlite": "^0.12.3",
38
39
  "@pikku/n8n-import": "^0.0.3",
@@ -60,10 +61,12 @@
60
61
  "zod-to-ts": "^2.1.0"
61
62
  },
62
63
  "peerDependencies": {
63
- "@pikku/core": "^0.12.69"
64
+ "@pikku/core": "^0.12.70",
65
+ "@pikku/playwright": "^0.12.70"
64
66
  },
65
67
  "devDependencies": {
66
- "@pikku/core": "^0.12.69",
68
+ "@pikku/core": "^0.12.70",
69
+ "@pikku/playwright": "^0.12.70",
67
70
  "@types/istanbul-lib-instrument": "^1.7.7",
68
71
  "@types/node": "^24.11.0",
69
72
  "@types/pg": "^8.11.0",
@@ -79,6 +82,13 @@
79
82
  "node": ">=24"
80
83
  },
81
84
  "exports": {
82
- ".": "./dist/bin/pikku.js"
85
+ ".": "./dist/bin/pikku.js",
86
+ "./server/spawn-dev-server": "./dist/src/server/spawn-dev-server.js",
87
+ "./server/server-ready": "./dist/src/server/server-ready.js"
88
+ },
89
+ "peerDependenciesMeta": {
90
+ "@pikku/playwright": {
91
+ "optional": true
92
+ }
83
93
  }
84
94
  }
@@ -5,12 +5,12 @@ description: >-
5
5
  test coverage. A scenario (pikkuScenario) drives the app the way users do — steps run as actors
6
6
  over the real transport against a running server — so a flow doubles as an e2e test and a
7
7
  staged/production health check. Covers scenario.do / expectEventually / expectError /
8
- expectService, actors and environments in pikku.config.json, SCENARIO_ACTOR_SECRET, the
8
+ expectService, declared steps via pikkuScenarioStep (including browser steps driven by
9
+ @pikku/playwright), actors and environments in pikku.config.json, SCENARIO_ACTOR_SECRET, the
9
10
  `pikku scenario list|run` commands, live function coverage via `pikku dev --coverage`, and
10
11
  plain unit tests for pure function logic. TRIGGER when: user asks about scenarios, testing a
11
- Pikku function, test coverage, end-to-end flows, or health checks. DO NOT TRIGGER when: user
12
- asks about browser/UI e2e (that is @pikku/cucumber, out of scope), running an existing test
13
- suite (use Bash), or CI configuration.
12
+ Pikku function, test coverage, end-to-end flows, browser/UI e2e, or health checks. DO NOT
13
+ TRIGGER when: user asks about running an existing test suite (use Bash) or CI configuration.
14
14
  installGroups: [core]
15
15
  ---
16
16
 
@@ -35,7 +35,7 @@ A scenario is a `pikkuScenario` export that drives the app **as real actors over
35
35
  Consequences that matter, and bite if ignored:
36
36
 
37
37
  - **There is no state reset.** A scenario runs against a live server. Scope what you create (unique ids, your own rows) and never assume a clean database.
38
- - **Every step needs an actor.** `scenario.do(...)` without `{ actor }` throws `Scenario tried to run '<rpc>' as an internal step…`. There is no bare internal-RPC step.
38
+ - **Every effect runs as somebody, or as a declared step.** `scenario.do(...)` without `{ actor }` throws `Scenario tried to run '<rpc>' as an internal step…` there is no bare internal-RPC step. The other way to do work is `scenario.step/given/when/then`, which runs a `pikkuScenarioStep`; its actor is optional (setup steps have none) unless it declares `browser: true`.
39
39
  - **Actors must be configured and signed in**, or the scenario cannot run.
40
40
 
41
41
  Scenarios live in `srcDirectories` like any other function — by convention `*.scenario.ts`.
@@ -84,24 +84,167 @@ A scenario takes the same config fields as a workflow (`title`, `description`, `
84
84
 
85
85
  ### The scenario API
86
86
 
87
- | Call | Purpose |
88
- | --- | --- |
89
- | `scenario.do(step, rpc, data, { actor })` | Run an RPC as that actor. The step name is what appears in the run output. |
87
+ | Call | Purpose |
88
+ | ------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- |
89
+ | `scenario.do(step, rpc, data, { actor })` | Run an RPC as that actor. The step name is what appears in the run output. |
90
90
  | `scenario.expectEventually(step, rpc, data, predicate, { actor, within, interval })` | Poll until `predicate(out)` passes or `within` elapses. For anything asynchronous — queues, workers, eventual state. |
91
- | `scenario.expectError(step, rpc, data, { actor, matches })` | Assert the call **fails**. For fault injection and negative paths. |
92
- | `scenario.expectService(step, 'service.method', { actor, calledWith })` | Assert a stubbed service was called. Requires the server to run with `--test`. |
91
+ | `scenario.expectError(step, rpc, data, { actor, matches })` | Assert the call **fails**. For fault injection and negative paths. |
92
+ | `scenario.expectService(step, 'service.method', { actor, calledWith })` | Assert a stubbed service was called. Requires the server to run with `--test`. |
93
+ | `scenario.step(step, stepName, data, { actor })` | Run a declared `pikkuScenarioStep`. `given`/`when`/`then` are the same call with a keyword in the rendered prose. |
93
94
 
94
95
  `expectEventually` is **scenario-only**. Calling it from a `pikkuWorkflowFunc` is a critical inspector error (`PKU675`) pointing you at `pikkuScenario`.
95
96
 
96
- Prefer `expectEventually` over sleeping. There is no `beforeEach`/`afterEach` — a scenario is a plain async function.
97
+ Prefer `expectEventually` over sleeping.
98
+
99
+ ### Setup and teardown (`before` / `after`)
100
+
101
+ A scenario config takes `before` and `after`. Both have the **same signature as `func`** — `(services, data, wire)` — with the return value discarded:
102
+
103
+ ```typescript
104
+ const resetsCredentials = async (_services, _data, { actors }) => {
105
+ await actors!.admin!.invoke('resetCredentials', {})
106
+ }
107
+
108
+ export const credentialScenario = pikkuScenario({
109
+ title: 'A credential is loaded on first use',
110
+ tags: ['scenario', 'credential'],
111
+ before: resetsCredentials,
112
+ after: removesInstalledAddon,
113
+ func: async (services, data, { scenario, actors }) => { /* … */ },
114
+ })
115
+ ```
116
+
117
+ | Rule |
118
+ | -------------------------------------------------------------------------------------------------------- |
119
+ | `before` throwing skips the body and fails the run — but `after` still runs. |
120
+ | `after` always runs, in a `finally`, whether the scenario passed or failed. |
121
+ | `after` throwing fails a run that would otherwise have passed. |
122
+ | `after` throwing on an already-failed run attaches as the `cause` and never replaces the original error. |
123
+ | Neither runs when the run is suspended or waiting — teardown only fires at a terminal outcome. |
124
+ | Hooks are **not** ladder rows. The runner records nothing for them; a failure is labelled by phase. |
125
+
126
+ A hook reaches the app the same way the body does: through `wire.actors`. If you want cleanup to be *visible* on the ladder, make it an ordinary `scenario.then(...)` instead.
127
+
128
+ Hooks are scenario-only. A `before`/`after` on a `pikkuWorkflowFunc` never runs — a workflow is durable and resumable, so a callback that reran on every replay would have no honest meaning.
129
+
130
+ ### Grouping scenarios (`pikkuFeature`)
131
+
132
+ `pikkuFeature` groups scenarios the way gherkin's `Feature:` groups `Scenario:`. Scenarios are referenced by **imported identifier**, so a renamed or deleted scenario is a compile error rather than a silent skip:
133
+
134
+ ```typescript
135
+ import { pikkuFeature } from '#pikku/workflow/pikku-workflow-types.gen.js'
136
+ import {
137
+ credentialLazyLoadScenario,
138
+ credentialRoundTripScenario,
139
+ } from './credential.scenario.js'
140
+
141
+ export const credentialFeature = pikkuFeature({
142
+ name: 'Credential API',
143
+ description: 'Credentials resolve lazily and are scoped per user',
144
+ tags: ['credential'],
145
+ before: startsMockOAuthServer,
146
+ after: stopsMockOAuthServer,
147
+ scenarios: [
148
+ credentialLazyLoadScenario,
149
+ ...['stripe', 'google', 'hmac-key'].map((name) => ({
150
+ scenario: credentialRoundTripScenario,
151
+ data: { name },
152
+ })),
153
+ ],
154
+ })
155
+ ```
156
+
157
+ | Rule |
158
+ | ---------------------------------------------------------------------------------------------------------------------------------------- |
159
+ | The **export identifier is the feature's id**; `name` is the human-readable label. Both must be exported or the build fails. |
160
+ | A `{ scenario, data }` entry is gherkin's `Examples:` — one run per entry. `data` is typed against that scenario's input. |
161
+ | Feature hooks run **once around the whole group** (`before → a → b → c → after`), _not_ per scenario. `after` runs in a `finally`. |
162
+ | There is deliberately **no `Background:`**. Per-scenario setup is the scenario's own `before`, referencing a shared function. |
163
+ | A scenario's effective tags are its own **plus** the feature's, so `--tags credential` selects through the feature. |
164
+ | A scenario need not belong to a feature — one with no input still runs standalone. |
165
+ | Membership is resolved by **object identity** at runtime, which is why a loop works and why a scenario built inline in a feature is an error. |
166
+
167
+ The **feature is the run unit**: `--flows` on a scenario whose every feature entry carries `data` errors and names the features containing it, because the feature is what supplies that data. Use `--features` for those. A scenario referenced bare anywhere, or in no feature at all, still runs standalone.
168
+
169
+ ### Declared steps (`pikkuScenarioStep`)
170
+
171
+ `scenario.do` can only name an RPC. A **step** is a named, typed unit of scenario behaviour whose body is an ordinary pikku function — so it can call several RPCs as its actor, assert, or drive a browser.
172
+
173
+ ```typescript
174
+ import { pikkuScenarioStep } from '#pikku/workflow/pikku-workflow-types.gen.js'
175
+ import { requireActor } from '@pikku/core/workflow'
176
+
177
+ export const buysAnApple = pikkuScenarioStep<
178
+ { qty: number },
179
+ { orderId: string }
180
+ >({
181
+ name: 'buysAnApple',
182
+ description: 'buys an apple',
183
+ template: 'buys {qty} apples',
184
+ func: async (_services, { qty }, { scenarioStep }) => {
185
+ return await requireActor(scenarioStep).invoke('placeOrder', { qty })
186
+ },
187
+ })
188
+ ```
189
+
190
+ ```typescript
191
+ await scenario.given(
192
+ 'buys an apple',
193
+ 'buysAnApple',
194
+ { qty: 1 },
195
+ { actor: actors.shopper }
196
+ )
197
+ // reporter renders: Given the shopper buys 1 apples ✓ 412ms
198
+ ```
199
+
200
+ Rules that bite:
201
+
202
+ - **The step is referenced by its typed string name, not by importing the const** — exactly like `workflow.do`. The name is the step's `pikkuFuncId` and is checked against the generated step map. A non-literal target is a critical error (`PKU678`).
203
+ - **Steps are not RPCs.** They are deliberately never network-callable — a browser-driving step must not be.
204
+ - **`actor.invoke` is typed over the exposed RPC map**, so the name and the payload are checked and the result comes back narrowed — no cast. `actor.invokeRaw(name, data, { headers })` is the same call reporting `{ status, ok, body }` instead of throwing; use it whenever the refusal *is* the assertion.
205
+ - **`actor` and `env` are optional on the wire**, because a pure assertion step needs neither. Narrow them with `requireActor(scenarioStep)` and `requireScenarioEnv(scenarioStep)` from `@pikku/core/workflow` rather than a local guard — both name the step and say what to pass. `env` is `{ apiUrl, appUrl? }` from the environment the run targets, and is how a raw-HTTP step learns the target's URL: a step runs in the CLI process, where there is no `variables` service and `process.env` is not the answer.
206
+ - **Steps default to `retries: 0`**, unlike ordinary workflow steps. Retrying a failed assertion is wrong; pass `retries` explicitly if a step is genuinely flaky-by-nature.
207
+ - **Step results are persisted**, so return JSON-serialisable data — never a `Locator` or a client object.
208
+ - **`description` documents the step; `template` is what the report renders.** `template`'s `{placeholders}` are filled from the input the step was called with, so one step reads differently for each call — `sees {state} addon {packageName}` reports as "sees available addon @pikku/addon-stripe". Reflect every input field in the template, and type the values so they read as words (`state?: 'installed' | 'available'`, not `installed?: boolean`). A placeholder with no value renders as nothing and the whitespace collapses.
209
+ - Prose precedence is `options.description` → the step's `template` → the step's own `description` → the positional step name. Repeated names get `#1`, `#2` ordinals, so a `for` loop over a data set is how you write a Scenario Outline. A loop-generated step name is not statically known, so it is matched back to its declaration by step function instead — which works as long as that function's call sites agree on their phase, actor and prose. Two call sites that disagree make the loop step report under its bare runtime name.
210
+
211
+ ### Browser steps
212
+
213
+ A step declaring `browser: true` gets `wire.browser` — a session bound to **its actor**, signed in through the same `signInPath` + `SCENARIO_ACTOR_SECRET` path the HTTP actors use, so the browser and the RPC calls are one identity. Calling such a step without an actor is a critical error (`PKU677`).
214
+
215
+ ```typescript
216
+ export const opensTheCart = pikkuScenarioStep<
217
+ { path: string },
218
+ { url: string },
219
+ true
220
+ >({
221
+ name: 'opensTheCart',
222
+ description: 'opens the cart',
223
+ browser: true,
224
+ func: async (_services, { path }, { browser }) => {
225
+ await browser.goto(path)
226
+ return { url: browser.page.url() }
227
+ },
228
+ })
229
+ ```
230
+
231
+ - Install `@pikku/playwright` and `@playwright/test`, and import `@pikku/playwright` once (`import type {} from '@pikku/playwright'`) so `browser.page` is a typed Playwright `Page`. Without it you still get the structural `goto`/`screenshot` handle.
232
+ - The environment needs an `appUrl` beside its `apiUrl`. `pikku scenario run` fails fast before running anything if a browser scenario has no `appUrl` or the driver is not installed.
233
+ - `pikku scenario run <env> --no-browser` **skips** scenarios containing browser steps and reports them as skipped — it does not fail them. That is how a machine with no browser stays green.
234
+ - Playwright auto-waits; do not wrap `page.click` in `expectEventually`.
97
235
 
98
236
  ## Configuration
99
237
 
100
- Actors and environments live in `pikku.config.json`:
238
+ Personas, actors and environments live in `pikku.config.json`:
101
239
 
102
240
  ```json
103
241
  {
104
242
  "scenarios": {
243
+ "personas": {
244
+ "shopper": { "description": "Buys things here", "primary": true },
245
+ "support": { "description": "Answers for the shop", "proficiency": "power" },
246
+ "reminders": { "description": "The shop chasing abandoned carts", "kind": "system" }
247
+ },
105
248
  "actors": {
106
249
  "shopper": {
107
250
  "email": "shopper@actors.local",
@@ -109,7 +252,7 @@ Actors and environments live in `pikku.config.json`:
109
252
  "jobTitle": "First-time buyer",
110
253
  "personality": "Impatient shopper who abandons slow checkouts"
111
254
  },
112
- "support": { "email": "support@actors.local", "name": "Support" }
255
+ "shopperB": { "persona": "shopper", "email": "shopper-b@actors.local" }
113
256
  },
114
257
  "environments": {
115
258
  "local": {
@@ -121,23 +264,37 @@ Actors and environments live in `pikku.config.json`:
121
264
  }
122
265
  ```
123
266
 
267
+ ### Personas and actors
268
+
269
+ A **persona** is a kind of person; an **actor** is one body that signs in as one. Above, `support` is declared only as a persona — its actor is materialised (`support@actors.local`), so `actors.support` works without an `actors` entry. Write an actor by hand only when you need something the materialised one wouldn't have:
270
+
271
+ - a **real email or personality** for it, like `shopper`;
272
+ - a **second body of the same persona**, like `shopperB` — which is what tenant isolation, peer sharing, and "another member's row" scenarios are made of. Two actors of one persona must be two different users, so **two actors sharing an email is an error**.
273
+
274
+ A persona holds only what is true of that kind of person for the app's whole lifetime — `description`, `primary` (whose experience the product is), `kind`, `proficiency`. What someone is trying to get done, and the circumstances they are doing it in, belong to the **scenario**, not to them.
275
+
276
+ `kind: "system"` is the app acting on its own — a schedule, a cleanup, a send. It gets **no actor**: there is nobody to sign in. Give it one by hand only if it genuinely has a service account.
277
+
278
+ An actor with no `persona` is its own persona, so a project that never declares any keeps working unchanged.
279
+
124
280
  - `environments.<name>.apiUrl` is required. `signInPath` defaults to `/auth/sign-in/actor`, `rpcPath` to `/rpc`.
125
281
  - **`SCENARIO_ACTOR_SECRET` is an environment variable and never goes in `pikku.config.json`.** It signs actors in. `pikku scenario run` throws without it; a server auto-building actors warns and runs without them.
126
282
 
127
283
  ## Running
128
284
 
129
285
  ```bash
130
- pikku scenario list # name [tags] + description; takes no options
286
+ pikku scenario list # features with their scenarios indented, then ungrouped scenarios
131
287
  SCENARIO_ACTOR_SECRET=… pikku scenario run local
132
288
  SCENARIO_ACTOR_SECRET=… pikku scenario run local --flows orderSupportScenario
289
+ SCENARIO_ACTOR_SECRET=… pikku scenario run local --features credentialFeature
133
290
  SCENARIO_ACTOR_SECRET=… pikku scenario run local --tags smoke,scenario
134
291
  ```
135
292
 
136
- `run` takes the environment as a **required positional** — the key from `scenarios.environments`. `--flows`/`-f` filters by scenario name, `--tags`/`-t` by tag (match-any).
293
+ `run` takes the environment as a **required positional** — the key from `scenarios.environments`. `--flows`/`-f` filters by scenario name, `--features` by feature id, `--tags`/`-t` by tag (match-any). Every filter narrows the same plan, so narrowing a feature to two of its five scenarios still runs the feature's hooks exactly once around those two.
137
294
 
138
- Output is `PASS <name> (<ms>) → <output>` / `FAIL <name> (<ms>): <error>`, then `N/M scenarios passed against '<env>'`.
295
+ Output is `PASS <name> (<ms>) → <output>` / `FAIL <name> (<ms>): <error>`, then `N/M scenarios passed against '<env>'`. A scenario inside a feature is named `<Feature> › <scenario> <data>`.
139
296
 
140
- **Exit code is 1** if any scenario fails *or* if no scenario matched the filter — a typo'd `--flows` is a hard error, not a silent zero-run pass. It throws outright on an unknown environment, an unknown flow name, or a missing `SCENARIO_ACTOR_SECRET`.
297
+ **Exit code is 1** if any scenario fails _or_ if no scenario matched the filter — a typo'd `--flows` is a hard error, not a silent zero-run pass. It throws outright on an unknown environment, an unknown flow name, or a missing `SCENARIO_ACTOR_SECRET`.
141
298
 
142
299
  ## Coverage
143
300
 
@@ -160,7 +317,15 @@ SCENARIO_ACTOR_SECRET=… pikku scenario run local --coverage
160
317
  The run resets coverage before each scenario and snapshots after, writing **`<outDir>/coverage/scenario-coverage.json`**:
161
318
 
162
319
  ```jsonc
163
- { "generatedAt": "…", "environment": "local", "scenarios": { "<name>": { /* FunctionCoverageReport */ } } }
320
+ {
321
+ "generatedAt": "…",
322
+ "environment": "local",
323
+ "scenarios": {
324
+ "<name>": {
325
+ /* FunctionCoverageReport */
326
+ },
327
+ },
328
+ }
164
329
  ```
165
330
 
166
331
  Coverage is best-effort: it disables itself with a warning if the server is not collecting or the first actor cannot invoke, and it needs at least one configured actor. If you get no coverage, check those first.
@@ -184,7 +349,9 @@ import assert from 'node:assert'
184
349
 
185
350
  describe('createTodo', () => {
186
351
  test('creates a todo', async () => {
187
- const services = { todoStore: { add: async (title: string) => ({ id: '1', title }) } }
352
+ const services = {
353
+ todoStore: { add: async (title: string) => ({ id: '1', title }) },
354
+ }
188
355
  const result = await createTodo.func(services as any, { title: 'Buy milk' })
189
356
  assert.equal(result.title, 'Buy milk')
190
357
  })
@@ -199,16 +366,16 @@ Services are plain objects — a Pikku function is pure business logic, so a moc
199
366
 
200
367
  ## Red flags
201
368
 
202
- | Smell | Why it's wrong |
203
- | --- | --- |
204
- | `pikku tests …` | Removed in #865. Use `pikku scenario`. |
205
- | `.feature` files / Gherkin for function tests | Scenarios are TypeScript, not Gherkin. The in-process cucumber function world was deleted. |
206
- | `scenario.do(...)` with no `{ actor }` | Throws. Every step runs as somebody. |
207
- | A scenario per function | Scenarios are user flows. One flow covers many functions; that is the point. |
208
- | Assuming a clean database | There is no state reset — it may be a staging server. Scope what you create. |
209
- | `sleep()` before asserting | Use `expectEventually`. |
210
- | `expectEventually` in a `pikkuWorkflowFunc` | `PKU675` — scenario-only. |
211
- | Coverage silently 0 | Server not run with `--coverage`, `verboseMeta` off, `scaffold.scenarios` unset, or no actors configured. |
369
+ | Smell | Why it's wrong |
370
+ | --------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
371
+ | `pikku tests …` | Removed in #865. Use `pikku scenario`. |
372
+ | `.feature` files / Gherkin for function tests | Scenarios are TypeScript, not Gherkin. The in-process cucumber function world was deleted. |
373
+ | `scenario.do(...)` with no `{ actor }` | Throws. Every step runs as somebody. |
374
+ | A scenario per function | Scenarios are user flows. One flow covers many functions; that is the point. |
375
+ | Assuming a clean database | There is no state reset — it may be a staging server. Scope what you create. |
376
+ | `sleep()` before asserting | Use `expectEventually`. |
377
+ | `expectEventually` in a `pikkuWorkflowFunc` | `PKU675` — scenario-only. |
378
+ | Coverage silently 0 | Server not run with `--coverage`, `verboseMeta` off, `scaffold.scenarios` unset, or no actors configured. |
212
379
 
213
380
  `@pikku/cucumber` is a **browser/e2e** harness (`Actor`, `BrowserWorld`, `PersonaData`, `DbUtils`) — out of scope here.
214
381