@pikku/cli 0.12.91 → 0.12.93

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 (241) hide show
  1. package/LICENSE +106 -0
  2. package/console-app/assets/{index-D0HG8q0B.css → index-BYj7ZbUU.css} +1 -1
  3. package/console-app/assets/{index-CpkvmAGb.js → index-CmAplHjZ.js} +151 -149
  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 +16 -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-contracts-meta.gen.json +15 -0
  14. package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
  15. package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
  16. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
  17. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +48 -0
  18. package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
  19. package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
  20. package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
  21. package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
  22. package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
  23. package/dist/.pikku/function/pikku-function-types.gen.d.ts +1 -1
  24. package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
  25. package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
  26. package/dist/.pikku/function/pikku-functions-meta.gen.json +73 -40
  27. package/dist/.pikku/function/pikku-functions.gen.js +1 -3
  28. package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
  29. package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
  30. package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
  31. package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
  32. package/dist/.pikku/pikku-bootstrap-scenarios.gen.d.ts +2 -1
  33. package/dist/.pikku/pikku-bootstrap-scenarios.gen.js +2 -1
  34. package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
  35. package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
  36. package/dist/.pikku/pikku-meta-service.gen.d.ts +1 -1
  37. package/dist/.pikku/pikku-meta-service.gen.js +1 -1
  38. package/dist/.pikku/pikku-services.gen.d.ts +1 -1
  39. package/dist/.pikku/pikku-types.gen.d.ts +1 -1
  40. package/dist/.pikku/pikku-types.gen.js +1 -1
  41. package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
  42. package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
  43. package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
  44. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
  45. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
  46. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
  47. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +3 -1
  48. package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.js +1 -1
  49. package/dist/.pikku/scenarios/pikku-scenario-functions.gen.d.ts +1 -1
  50. package/dist/.pikku/scenarios/pikku-scenario-wirings-meta.gen.js +1 -1
  51. package/dist/.pikku/scenarios/pikku-scenario-wirings.gen.d.ts +1 -1
  52. package/dist/.pikku/scenarios/schemas/register.gen.d.ts +4 -0
  53. package/dist/.pikku/scenarios/schemas/register.gen.js +4 -0
  54. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
  55. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
  56. package/dist/.pikku/schemas/register.gen.js +13 -3
  57. package/dist/.pikku/schemas/schemas/FabricSecretsListOutput.schema.json +1 -1
  58. package/dist/.pikku/schemas/schemas/FabricSecretsRotateInput.schema.json +1 -0
  59. package/dist/.pikku/schemas/schemas/FabricSecretsRotateOutput.schema.json +1 -0
  60. package/dist/.pikku/schemas/schemas/FabricSecretsSetOutput.schema.json +1 -1
  61. package/dist/.pikku/schemas/schemas/KnowledgeIndexInput.schema.json +1 -0
  62. package/dist/.pikku/schemas/schemas/KnowledgeIndexOutput.schema.json +1 -0
  63. package/dist/.pikku/schemas/schemas/KnowledgeValidateInput.schema.json +1 -0
  64. package/dist/.pikku/schemas/schemas/KnowledgeValidateOutput.schema.json +1 -0
  65. package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
  66. package/dist/.pikku/schemas/schemas/ScenarioRunInput.schema.json +1 -1
  67. package/dist/.pikku/scopes/pikku-scope-types.gen.d.ts +1 -1
  68. package/dist/.pikku/scopes/pikku-scope-types.gen.js +1 -1
  69. package/dist/.pikku/scopes/pikku-scopes.gen.d.ts +1 -1
  70. package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
  71. package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
  72. package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
  73. package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
  74. package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
  75. package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
  76. package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
  77. package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
  78. package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
  79. package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
  80. package/dist/.pikku/workflow/meta/allWorkflow.gen.json +2 -8
  81. package/dist/.pikku/workflow/pikku-scenario-actors.gen.d.ts +1 -1
  82. package/dist/.pikku/workflow/pikku-scenario-actors.gen.js +1 -1
  83. package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
  84. package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
  85. package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
  86. package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
  87. package/dist/bin/pikku-bin.mjs +2 -2
  88. package/dist/src/cli.wiring.js +29 -0
  89. package/dist/src/deploy/analyzer/analyzer.js +22 -5
  90. package/dist/src/deploy/build-pipeline.js +5 -1
  91. package/dist/src/fabric/fabric-commands.d.ts +37 -9
  92. package/dist/src/fabric/fabric-commands.js +12 -0
  93. package/dist/src/fabric/functions/domains-add.function.d.ts +4 -4
  94. package/dist/src/fabric/functions/secrets-list.function.d.ts +16 -4
  95. package/dist/src/fabric/functions/secrets-list.function.js +12 -10
  96. package/dist/src/fabric/functions/secrets-rotate.function.d.ts +24 -0
  97. package/dist/src/fabric/functions/secrets-rotate.function.js +36 -0
  98. package/dist/src/fabric/functions/secrets-set.function.d.ts +8 -4
  99. package/dist/src/fabric/functions/secrets-set.function.js +18 -7
  100. package/dist/src/fabric/functions/validate.function.js +16 -7
  101. package/dist/src/fabric/lib/http.d.ts +7 -1
  102. package/dist/src/fabric/lib/sealed-box.d.ts +16 -0
  103. package/dist/src/fabric/lib/sealed-box.js +72 -0
  104. package/dist/src/functions/commands/dev.js +9 -0
  105. package/dist/src/functions/commands/knowledge-index.d.ts +30 -0
  106. package/dist/src/functions/commands/knowledge-index.js +11 -0
  107. package/dist/src/functions/commands/knowledge-validate.d.ts +33 -0
  108. package/dist/src/functions/commands/knowledge-validate.js +11 -0
  109. package/dist/src/functions/commands/new-addon.d.ts +18 -0
  110. package/dist/src/functions/commands/new-addon.js +40 -24
  111. package/dist/src/functions/commands/pikku-command-bootstrap.js +1 -0
  112. package/dist/src/functions/commands/scenario-browser.d.ts +17 -2
  113. package/dist/src/functions/commands/scenario-browser.js +16 -8
  114. package/dist/src/functions/commands/scenario-environment.d.ts +32 -0
  115. package/dist/src/functions/commands/scenario-environment.js +61 -0
  116. package/dist/src/functions/commands/scenario.d.ts +6 -0
  117. package/dist/src/functions/commands/scenario.js +14 -9
  118. package/dist/src/functions/commands/skills.js +27 -61
  119. package/dist/src/functions/db/db-codegen.d.ts +6 -0
  120. package/dist/src/functions/db/db-codegen.js +9 -0
  121. package/dist/src/functions/db/db-migrator.js +14 -0
  122. package/dist/src/functions/db/local-db.d.ts +8 -0
  123. package/dist/src/functions/db/local-db.js +24 -2
  124. package/dist/src/functions/db/migration-identifiers.d.ts +58 -0
  125. package/dist/src/functions/db/migration-identifiers.js +262 -0
  126. package/dist/src/functions/db/migration-provenance.d.ts +35 -0
  127. package/dist/src/functions/db/migration-provenance.js +80 -0
  128. package/dist/src/functions/db/schema-sql.d.ts +43 -0
  129. package/dist/src/functions/db/schema-sql.js +135 -0
  130. package/dist/src/functions/db/sqlite/sqlite-kysely.js +22 -2
  131. package/dist/src/functions/knowledge/render.d.ts +3 -0
  132. package/dist/src/functions/knowledge/render.js +66 -0
  133. package/dist/src/functions/knowledge/schemas.d.ts +51 -0
  134. package/dist/src/functions/knowledge/schemas.js +25 -0
  135. package/dist/src/functions/wirings/credentials/serialize-credentials-types.js +8 -1
  136. package/dist/src/functions/wirings/functions/schemas.js +13 -1
  137. package/dist/src/functions/wirings/rpc/pikku-command-rpc.js +6 -1
  138. package/dist/src/functions/wirings/scenarios/register-scenario-instrumentation.d.ts +10 -0
  139. package/dist/src/functions/wirings/scenarios/register-scenario-instrumentation.js +102 -0
  140. package/dist/src/functions/wirings/scenarios/scenario-partition.d.ts +13 -0
  141. package/dist/src/functions/wirings/scenarios/scenario-partition.js +15 -2
  142. package/dist/src/functions/wirings/scenarios/scenario-schema-partition.d.ts +33 -0
  143. package/dist/src/functions/wirings/scenarios/scenario-schema-partition.js +49 -0
  144. package/dist/src/functions/wirings/secrets/serialize-secrets-types.js +10 -3
  145. package/dist/src/functions/wirings/variables/serialize-variables-types.js +8 -1
  146. package/dist/src/functions/workflows/all.workflow.js +2 -7
  147. package/dist/src/utils/file-writer.js +14 -2
  148. package/dist/src/utils/pikku-cli-config.d.ts +14 -0
  149. package/dist/src/utils/pikku-cli-config.js +34 -0
  150. package/dist/src/utils/remove-legacy-scaffold-file.d.ts +14 -0
  151. package/dist/src/utils/remove-legacy-scaffold-file.js +23 -0
  152. package/dist/src/utils/serialize-schemas.d.ts +3 -1
  153. package/dist/src/utils/serialize-schemas.js +39 -4
  154. package/dist/tsconfig.tsbuildinfo +1 -1
  155. package/package.json +10 -9
  156. package/dist/.pikku/schemas/schemas/PikkuScenarioFunctionsOutput.schema.json +0 -1
  157. package/dist/src/functions/wirings/scenarios/pikku-command-scenario-functions.d.ts +0 -1
  158. package/dist/src/functions/wirings/scenarios/pikku-command-scenario-functions.js +0 -31
  159. package/dist/src/functions/wirings/scenarios/serialize-scenario-functions.d.ts +0 -10
  160. package/dist/src/functions/wirings/scenarios/serialize-scenario-functions.js +0 -104
  161. package/skills/pikku-addon/SKILL.md +0 -243
  162. package/skills/pikku-addon/references/addon-package-manifest.md +0 -63
  163. package/skills/pikku-ai-agent/SKILL.md +0 -231
  164. package/skills/pikku-ai-vercel/SKILL.md +0 -82
  165. package/skills/pikku-ai-voice/SKILL.md +0 -88
  166. package/skills/pikku-audit/SKILL.md +0 -175
  167. package/skills/pikku-aws/SKILL.md +0 -111
  168. package/skills/pikku-backblaze/SKILL.md +0 -71
  169. package/skills/pikku-better-auth/SKILL.md +0 -298
  170. package/skills/pikku-cli/SKILL.md +0 -198
  171. package/skills/pikku-cli/references/complete-example.md +0 -82
  172. package/skills/pikku-concepts/SKILL.md +0 -250
  173. package/skills/pikku-concepts/references/concept-mapping.md +0 -556
  174. package/skills/pikku-concepts/references/packages.md +0 -29
  175. package/skills/pikku-config/SKILL.md +0 -212
  176. package/skills/pikku-cron/SKILL.md +0 -214
  177. package/skills/pikku-deploy-azure/SKILL.md +0 -71
  178. package/skills/pikku-deploy-cloudflare/SKILL.md +0 -82
  179. package/skills/pikku-deploy-express/SKILL.md +0 -86
  180. package/skills/pikku-deploy-fastify/SKILL.md +0 -73
  181. package/skills/pikku-deploy-lambda/SKILL.md +0 -110
  182. package/skills/pikku-deploy-nextjs/SKILL.md +0 -78
  183. package/skills/pikku-deploy-uws/SKILL.md +0 -88
  184. package/skills/pikku-deps/SKILL.md +0 -98
  185. package/skills/pikku-emails/SKILL.md +0 -163
  186. package/skills/pikku-fabric/SKILL.md +0 -318
  187. package/skills/pikku-fabric-debug/SKILL.md +0 -112
  188. package/skills/pikku-feature/SKILL.md +0 -258
  189. package/skills/pikku-gateway-slack/SKILL.md +0 -115
  190. package/skills/pikku-http/SKILL.md +0 -220
  191. package/skills/pikku-http/references/http-options.md +0 -55
  192. package/skills/pikku-i18n/SKILL.md +0 -137
  193. package/skills/pikku-info/SKILL.md +0 -100
  194. package/skills/pikku-jose/SKILL.md +0 -105
  195. package/skills/pikku-kysely/SKILL.md +0 -219
  196. package/skills/pikku-machine-auth/SKILL.md +0 -183
  197. package/skills/pikku-mcp/SKILL.md +0 -241
  198. package/skills/pikku-middleware/SKILL.md +0 -231
  199. package/skills/pikku-middleware/references/middleware-patterns.md +0 -61
  200. package/skills/pikku-mongodb/SKILL.md +0 -105
  201. package/skills/pikku-n8n-import/SKILL.md +0 -109
  202. package/skills/pikku-n8n-import/SPEC.md +0 -84
  203. package/skills/pikku-n8n-import/references/addon-mapping.md +0 -121
  204. package/skills/pikku-n8n-import/references/code-translation.md +0 -121
  205. package/skills/pikku-n8n-import/references/loops-and-control.md +0 -87
  206. package/skills/pikku-paraglide/SKILL.md +0 -117
  207. package/skills/pikku-permissions/SKILL.md +0 -192
  208. package/skills/pikku-pino/SKILL.md +0 -79
  209. package/skills/pikku-product-second-opinion/README.md +0 -43
  210. package/skills/pikku-product-second-opinion/SKILL.md +0 -158
  211. package/skills/pikku-product-second-opinion/example/sample-report.md +0 -90
  212. package/skills/pikku-product-second-opinion/references/report-template.md +0 -73
  213. package/skills/pikku-queue/SKILL.md +0 -240
  214. package/skills/pikku-react/SKILL.md +0 -212
  215. package/skills/pikku-react-query/SKILL.md +0 -242
  216. package/skills/pikku-realtime/SKILL.md +0 -236
  217. package/skills/pikku-realtime/references/other-routes.md +0 -23
  218. package/skills/pikku-redis/SKILL.md +0 -90
  219. package/skills/pikku-rpc/SKILL.md +0 -171
  220. package/skills/pikku-rtl/SKILL.md +0 -219
  221. package/skills/pikku-scenario/SKILL.md +0 -382
  222. package/skills/pikku-schedule/SKILL.md +0 -57
  223. package/skills/pikku-schema-ajv/SKILL.md +0 -62
  224. package/skills/pikku-schema-cfworker/SKILL.md +0 -63
  225. package/skills/pikku-security/SKILL.md +0 -108
  226. package/skills/pikku-services/SKILL.md +0 -248
  227. package/skills/pikku-services/references/audit-wire-service.md +0 -34
  228. package/skills/pikku-software-archaeology/README.md +0 -70
  229. package/skills/pikku-software-archaeology/SKILL.md +0 -186
  230. package/skills/pikku-software-archaeology/references/blueprint.schema.json +0 -625
  231. package/skills/pikku-software-archaeology/references/pikku-mapping.md +0 -49
  232. package/skills/pikku-software-archaeology/scripts/validate.mjs +0 -173
  233. package/skills/pikku-tag-middleware/SKILL.md +0 -13
  234. package/skills/pikku-template-clone/SKILL.md +0 -40
  235. package/skills/pikku-trigger/SKILL.md +0 -181
  236. package/skills/pikku-versioning/SKILL.md +0 -173
  237. package/skills/pikku-websocket/SKILL.md +0 -243
  238. package/skills/pikku-workflow/SKILL.md +0 -172
  239. package/skills/pikku-workflow/references/workflow-reference.md +0 -63
  240. package/skills/pikku-workflows-client/SKILL.md +0 -150
  241. package/skills/pikku-ws/SKILL.md +0 -47
@@ -0,0 +1,80 @@
1
+ import { readdirSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ /**
4
+ * The header `db generate` stamps on every migration it writes.
5
+ *
6
+ * Matching it is what separates a generated migration from one the project
7
+ * authored: a file without this line declares the project's own tables, and
8
+ * anything it creates is app-owned by definition.
9
+ */
10
+ const GENERATED_HEADER = /^-- Generated by `pikku db generate` from (.+)\.\s*$/m;
11
+ /** `0002-pikku-runtime.sql` → `pikku-runtime`. */
12
+ const MIGRATION_LABEL = /^\d+-(.+)\.sql$/;
13
+ /**
14
+ * Strip `--` line comments so a `CREATE TABLE` quoted inside a REVIEW note is
15
+ * not mistaken for one the migration actually runs.
16
+ */
17
+ const stripComments = (sql) => sql.replace(/--[^\n]*/g, '');
18
+ const CREATE_TABLE = /\bCREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?([^\s(;]+)/gi;
19
+ /**
20
+ * Drop the schema qualifier and any quoting, so `"app"."user"` and `user` are
21
+ * the same key.
22
+ *
23
+ * Introspection reports a bare name on SQLite and a qualified one on Postgres,
24
+ * while a migration may write either — comparing on the bare, unquoted name is
25
+ * the only form both sides agree on.
26
+ */
27
+ export function bareUnquotedTableName(name) {
28
+ const last = name.split('.').pop() ?? name;
29
+ return last.replace(/^["'`[]|["'`\]]$/g, '');
30
+ }
31
+ /**
32
+ * Read the table→source map out of a project's migration directory.
33
+ *
34
+ * Provenance is decided at `db generate` time, but the schema JSON is written
35
+ * at `db migrate` time, and the two commands do not have to run together. The
36
+ * migration files are the durable record that survives between them: each
37
+ * generated one carries its origin in a header and its source in its filename,
38
+ * so re-reading them costs a directory scan and needs neither a Better Auth
39
+ * config load nor a live database.
40
+ *
41
+ * Tables absent from the result are app-owned — including every table when the
42
+ * project has no generated migrations at all.
43
+ */
44
+ export function readMigrationProvenance(migrationsDir) {
45
+ const provenance = new Map();
46
+ let files;
47
+ try {
48
+ files = readdirSync(migrationsDir);
49
+ }
50
+ catch {
51
+ // No migrations directory is the ordinary case for a project that has not
52
+ // run `db generate` yet — every table is app-owned.
53
+ return provenance;
54
+ }
55
+ for (const file of files.filter((f) => f.endsWith('.sql')).sort()) {
56
+ let sql;
57
+ try {
58
+ sql = readFileSync(join(migrationsDir, file), 'utf8');
59
+ }
60
+ catch {
61
+ continue;
62
+ }
63
+ const header = GENERATED_HEADER.exec(sql);
64
+ if (!header)
65
+ continue;
66
+ const label = MIGRATION_LABEL.exec(file);
67
+ if (!label)
68
+ continue;
69
+ const source = label[1];
70
+ const origin = header[1];
71
+ for (const match of stripComments(sql).matchAll(CREATE_TABLE)) {
72
+ const table = bareUnquotedTableName(match[1]);
73
+ // First writer wins: a later migration that recreates a table is fixing
74
+ // it, not claiming it.
75
+ if (!provenance.has(table))
76
+ provenance.set(table, { source, origin });
77
+ }
78
+ }
79
+ return provenance;
80
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Reading a schema source's own SQL back out, one table at a time.
3
+ *
4
+ * A source hands `db generate` both what must exist (`tables`) and what creates
5
+ * it (`sql`). The column map is a comparison surface — it answers "is this
6
+ * table there, and does it have these columns" — and it is deliberately lossy:
7
+ * primary keys, foreign keys, uniqueness, check constraints and indexes are all
8
+ * absent from it. So the moment the generator has to *create* something, the
9
+ * only honest source is the SQL, and this is what pulls the relevant part of it
10
+ * out.
11
+ */
12
+ /**
13
+ * Split a SQL script into its top-level statements, semicolons included.
14
+ *
15
+ * A naive `split(';')` is wrong in a way that only shows up later: a semicolon
16
+ * inside a string literal, a quoted identifier or a comment is not a statement
17
+ * boundary, and cutting there yields two fragments that are each valid-looking
18
+ * and neither of which does what the original did.
19
+ */
20
+ export declare function splitStatements(sql: string): string[];
21
+ /**
22
+ * Reduce a written table name to the form two sources can be compared on.
23
+ *
24
+ * The same table is `two_factor` to one writer, `"two_factor"` to Kysely and
25
+ * `public.two_factor` to Postgres introspection. Dropping the schema qualifier,
26
+ * the quoting and the case is the only shape all three agree on.
27
+ */
28
+ export declare function bareTableName(name: string): string;
29
+ /**
30
+ * Every statement in `sql` that builds `table`, in the order the source wrote
31
+ * them.
32
+ *
33
+ * The `CREATE TABLE` and its indexes, plus any `ALTER TABLE` the source uses to
34
+ * hang a constraint on it afterwards — which together are what the column list
35
+ * cannot express. Source order is preserved because it is load-bearing: an
36
+ * index cannot precede its table, and a table cannot precede one it references.
37
+ *
38
+ * An empty result means the source's SQL does not visibly create the table.
39
+ * That is a real answer rather than a failure — a source may create a table
40
+ * from something other than a literal `CREATE TABLE` — and the caller is
41
+ * expected to fall back rather than emit nothing.
42
+ */
43
+ export declare function tableCreationSql(sql: string, table: string): string[];
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Reading a schema source's own SQL back out, one table at a time.
3
+ *
4
+ * A source hands `db generate` both what must exist (`tables`) and what creates
5
+ * it (`sql`). The column map is a comparison surface — it answers "is this
6
+ * table there, and does it have these columns" — and it is deliberately lossy:
7
+ * primary keys, foreign keys, uniqueness, check constraints and indexes are all
8
+ * absent from it. So the moment the generator has to *create* something, the
9
+ * only honest source is the SQL, and this is what pulls the relevant part of it
10
+ * out.
11
+ */
12
+ /**
13
+ * Split a SQL script into its top-level statements, semicolons included.
14
+ *
15
+ * A naive `split(';')` is wrong in a way that only shows up later: a semicolon
16
+ * inside a string literal, a quoted identifier or a comment is not a statement
17
+ * boundary, and cutting there yields two fragments that are each valid-looking
18
+ * and neither of which does what the original did.
19
+ */
20
+ export function splitStatements(sql) {
21
+ const statements = [];
22
+ let start = 0;
23
+ let i = 0;
24
+ const closeQuote = (quote) => {
25
+ i++;
26
+ while (i < sql.length) {
27
+ if (sql[i] === '\\' && quote === "'") {
28
+ i += 2;
29
+ continue;
30
+ }
31
+ if (sql[i] === quote) {
32
+ // A doubled quote is an escaped one, not the end of the literal.
33
+ if (sql[i + 1] === quote) {
34
+ i += 2;
35
+ continue;
36
+ }
37
+ i++;
38
+ return;
39
+ }
40
+ i++;
41
+ }
42
+ };
43
+ while (i < sql.length) {
44
+ const ch = sql[i];
45
+ if (ch === "'" || ch === '"' || ch === '`') {
46
+ closeQuote(ch);
47
+ continue;
48
+ }
49
+ if (ch === '-' && sql[i + 1] === '-') {
50
+ const end = sql.indexOf('\n', i);
51
+ i = end === -1 ? sql.length : end + 1;
52
+ continue;
53
+ }
54
+ if (ch === '/' && sql[i + 1] === '*') {
55
+ const end = sql.indexOf('*/', i + 2);
56
+ i = end === -1 ? sql.length : end + 2;
57
+ continue;
58
+ }
59
+ // Postgres dollar quoting: everything between `$tag$` and its twin is a
60
+ // literal, and a function body written that way is full of semicolons.
61
+ if (ch === '$') {
62
+ const tag = /^\$[A-Za-z_0-9]*\$/.exec(sql.slice(i));
63
+ if (tag) {
64
+ const end = sql.indexOf(tag[0], i + tag[0].length);
65
+ i = end === -1 ? sql.length : end + tag[0].length;
66
+ continue;
67
+ }
68
+ }
69
+ if (ch === ';') {
70
+ const statement = sql.slice(start, i + 1).trim();
71
+ if (statement.length > 1)
72
+ statements.push(statement);
73
+ start = i + 1;
74
+ }
75
+ i++;
76
+ }
77
+ // A script whose last statement has no trailing semicolon still ran it.
78
+ const tail = sql.slice(start).trim();
79
+ if (tail.length > 0)
80
+ statements.push(tail);
81
+ return statements;
82
+ }
83
+ /**
84
+ * Reduce a written table name to the form two sources can be compared on.
85
+ *
86
+ * The same table is `two_factor` to one writer, `"two_factor"` to Kysely and
87
+ * `public.two_factor` to Postgres introspection. Dropping the schema qualifier,
88
+ * the quoting and the case is the only shape all three agree on.
89
+ */
90
+ export function bareTableName(name) {
91
+ const last = name.split('.').pop() ?? name;
92
+ return last.replace(/^["'`[]|["'`\]]$/g, '').toLowerCase();
93
+ }
94
+ const CREATE_TABLE = /^CREATE\s+(?:TEMP(?:ORARY)?\s+|UNLOGGED\s+)*TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?([^\s(]+)/i;
95
+ const CREATE_INDEX = /^CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?:CONCURRENTLY\s+)?(?:IF\s+NOT\s+EXISTS\s+)?\S+\s+ON\s+(?:ONLY\s+)?([^\s(]+)/i;
96
+ const ALTER_TABLE = /^ALTER\s+TABLE\s+(?:IF\s+EXISTS\s+)?(?:ONLY\s+)?([^\s(]+)/i;
97
+ /**
98
+ * Every statement in `sql` that builds `table`, in the order the source wrote
99
+ * them.
100
+ *
101
+ * The `CREATE TABLE` and its indexes, plus any `ALTER TABLE` the source uses to
102
+ * hang a constraint on it afterwards — which together are what the column list
103
+ * cannot express. Source order is preserved because it is load-bearing: an
104
+ * index cannot precede its table, and a table cannot precede one it references.
105
+ *
106
+ * An empty result means the source's SQL does not visibly create the table.
107
+ * That is a real answer rather than a failure — a source may create a table
108
+ * from something other than a literal `CREATE TABLE` — and the caller is
109
+ * expected to fall back rather than emit nothing.
110
+ */
111
+ export function tableCreationSql(sql, table) {
112
+ const wanted = bareTableName(table);
113
+ const statements = [];
114
+ let creates = false;
115
+ for (const statement of splitStatements(sql)) {
116
+ const create = CREATE_TABLE.exec(statement);
117
+ if (create && bareTableName(create[1]) === wanted) {
118
+ creates = true;
119
+ statements.push(statement);
120
+ continue;
121
+ }
122
+ const index = CREATE_INDEX.exec(statement);
123
+ if (index && bareTableName(index[1]) === wanted) {
124
+ statements.push(statement);
125
+ continue;
126
+ }
127
+ const alter = ALTER_TABLE.exec(statement);
128
+ if (alter && bareTableName(alter[1]) === wanted) {
129
+ statements.push(statement);
130
+ }
131
+ }
132
+ // Indexes and alters without the table they belong to would fail on their own,
133
+ // and their presence says the table came from somewhere this cannot read.
134
+ return creates ? statements : [];
135
+ }
@@ -1,4 +1,21 @@
1
1
  import { Kysely, SqliteDialect, CamelCasePlugin, } from 'kysely';
2
+ /**
3
+ * Whether a value is a JSON column's worth of data rather than some other
4
+ * object that merely happens to be one. A `Map`, a `RegExp` or a class
5
+ * instance stringifies to `"{}"` or to a partial view of itself, which would
6
+ * silently persist an empty JSON blob where the caller meant something.
7
+ *
8
+ * Kept in lockstep with `isJsonEncodable` in `@pikku/kysely-sqlite`'s
9
+ * LibsqlWebDialect: whatever binds here under `pikku dev` has to bind the same
10
+ * way once the app is deployed, or the dev and deployed runtimes disagree
11
+ * about what a query may do.
12
+ */
13
+ function isJsonEncodable(v) {
14
+ if (Array.isArray(v))
15
+ return true;
16
+ const proto = Object.getPrototypeOf(v);
17
+ return proto === Object.prototype || proto === null;
18
+ }
2
19
  function coerce(v) {
3
20
  if (v === null || v === undefined)
4
21
  return null;
@@ -8,8 +25,11 @@ function coerce(v) {
8
25
  return v.toISOString();
9
26
  if (v instanceof Uint8Array)
10
27
  return v;
11
- if (typeof v === 'object')
12
- return JSON.stringify(v);
28
+ if (typeof v === 'object') {
29
+ if (isJsonEncodable(v))
30
+ return JSON.stringify(v);
31
+ throw new Error(`sqlite: unsupported argument type ${v.constructor?.name ?? 'object'}`);
32
+ }
13
33
  return v;
14
34
  }
15
35
  // A statement returns rows when it is a SELECT or carries a RETURNING clause.
@@ -0,0 +1,3 @@
1
+ import type { KnowledgeIndexResult, KnowledgeValidateResult } from '@pikku/knowledge';
2
+ export declare const renderKnowledgeValidate: (_services: unknown, { ok, notes, findings }: KnowledgeValidateResult) => void;
3
+ export declare const renderKnowledgeIndex: (_services: unknown, { ok, check, files }: KnowledgeIndexResult) => void;
@@ -0,0 +1,66 @@
1
+ import { added, changed, dim, removed } from '../../fabric/lib/output.js';
2
+ export const renderKnowledgeValidate = (_services, { ok, notes, findings }) => {
3
+ const errors = findings.filter((f) => f.severity === 'error');
4
+ const warns = findings.filter((f) => f.severity === 'warn');
5
+ const infos = findings.filter((f) => f.severity === 'info');
6
+ for (const finding of [...errors, ...warns, ...infos]) {
7
+ const icon = finding.severity === 'error'
8
+ ? removed('✗')
9
+ : finding.severity === 'warn'
10
+ ? changed('⚠')
11
+ : dim('ℹ');
12
+ console.log(`${icon} ${finding.message}`);
13
+ console.log(` ${dim('fix:')} ${finding.fixHint}`);
14
+ console.log();
15
+ }
16
+ const counts = [dim(`${notes} note${notes !== 1 ? 's' : ''}`)];
17
+ if (errors.length) {
18
+ counts.push(removed(`${errors.length} error${errors.length !== 1 ? 's' : ''}`));
19
+ }
20
+ if (warns.length) {
21
+ counts.push(changed(`${warns.length} warning${warns.length !== 1 ? 's' : ''}`));
22
+ }
23
+ console.log('─'.repeat(40));
24
+ console.log(counts.join(' '));
25
+ if (ok && warns.length === 0 && errors.length === 0) {
26
+ console.log(added('✓') + ' ' + dim('the knowledge base is consistent'));
27
+ }
28
+ // An error means the base contradicts itself, which a pipeline has to be able
29
+ // to stop on — so this command reports it the only way a shell can read.
30
+ if (!ok)
31
+ process.exitCode = 1;
32
+ };
33
+ export const renderKnowledgeIndex = (_services, { ok, check, files }) => {
34
+ if (files.length === 0) {
35
+ console.log(dim('No knowledge notes — nothing to index.'));
36
+ return;
37
+ }
38
+ for (const file of files) {
39
+ if (file.action === 'unchanged') {
40
+ console.log(`${dim('=')} ${dim(file.path)}`);
41
+ }
42
+ else if (check) {
43
+ console.log(`${removed('✗')} ${file.path} ${dim(`(${file.action})`)}`);
44
+ }
45
+ else {
46
+ console.log(`${added('✓')} ${file.path} ${dim(`(${file.action})`)}`);
47
+ }
48
+ }
49
+ console.log('─'.repeat(40));
50
+ if (!check) {
51
+ const written = files.filter((f) => f.action !== 'unchanged').length;
52
+ console.log(written === 0
53
+ ? added('✓') + ' ' + dim('every index was already current')
54
+ : added('✓') +
55
+ ` ${written} index file${written !== 1 ? 's' : ''} written`);
56
+ }
57
+ else {
58
+ console.log(ok
59
+ ? added('✓') + ' ' + dim('every index is current')
60
+ : removed('✗') +
61
+ ' ' +
62
+ 'indexes are stale — run `pikku knowledge index`');
63
+ if (!ok)
64
+ process.exitCode = 1;
65
+ }
66
+ };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * The knowledge command schemas, re-bound to variables declared HERE rather than
3
+ * imported straight into the command files.
4
+ *
5
+ * Two things about how the CLI builds itself make this the only shape that works:
6
+ *
7
+ * 1. The build bootstraps with the PUBLISHED CLI and inspector, so the code that
8
+ * reads these schemas is whatever npm has, not what is in this worktree. An
9
+ * identifier imported from `@pikku/knowledge` resolves to that package's
10
+ * `.d.ts`, and importing a declaration file yields a module with no exports at
11
+ * all — every one of them is a type. A binding declared in a `.ts` gives the
12
+ * inspector a file it can execute, and the import inside it resolves to the
13
+ * package's emitted JS.
14
+ * 2. The command files import `#pikku`, which points at `dist/.pikku/` — output
15
+ * that does not exist yet while the bootstrap is running. A schema the
16
+ * inspector has to import therefore cannot live beside a wired function.
17
+ *
18
+ * `schemaRuntimeFile` in the inspector fixes (1) at the root, so once a release
19
+ * carrying it is the bootstrap version, (2) is the only reason this file is here.
20
+ */
21
+ export declare const KnowledgeIndexInputSchema: import("zod").ZodObject<{
22
+ check: import("zod").ZodOptional<import("zod").ZodBoolean>;
23
+ }, import("zod/v4/core").$strip>;
24
+ export declare const KnowledgeIndexOutputSchema: import("zod").ZodObject<{
25
+ ok: import("zod").ZodBoolean;
26
+ check: import("zod").ZodBoolean;
27
+ files: import("zod").ZodArray<import("zod").ZodObject<{
28
+ path: import("zod").ZodString;
29
+ action: import("zod").ZodEnum<{
30
+ created: "created";
31
+ updated: "updated";
32
+ unchanged: "unchanged";
33
+ }>;
34
+ }, import("zod/v4/core").$strip>>;
35
+ }, import("zod/v4/core").$strip>;
36
+ export declare const KnowledgeValidateInputSchema: import("zod").ZodObject<{}, import("zod/v4/core").$strip>;
37
+ export declare const KnowledgeValidateOutputSchema: import("zod").ZodObject<{
38
+ ok: import("zod").ZodBoolean;
39
+ notes: import("zod").ZodNumber;
40
+ findings: import("zod").ZodArray<import("zod").ZodObject<{
41
+ id: import("zod").ZodString;
42
+ severity: import("zod").ZodEnum<{
43
+ error: "error";
44
+ warn: "warn";
45
+ info: "info";
46
+ }>;
47
+ message: import("zod").ZodString;
48
+ path: import("zod").ZodString;
49
+ fixHint: import("zod").ZodString;
50
+ }, import("zod/v4/core").$strip>>;
51
+ }, import("zod/v4/core").$strip>;
@@ -0,0 +1,25 @@
1
+ import { KnowledgeIndexInput, KnowledgeIndexOutput, KnowledgeValidateInput, KnowledgeValidateOutput, } from '@pikku/knowledge';
2
+ /**
3
+ * The knowledge command schemas, re-bound to variables declared HERE rather than
4
+ * imported straight into the command files.
5
+ *
6
+ * Two things about how the CLI builds itself make this the only shape that works:
7
+ *
8
+ * 1. The build bootstraps with the PUBLISHED CLI and inspector, so the code that
9
+ * reads these schemas is whatever npm has, not what is in this worktree. An
10
+ * identifier imported from `@pikku/knowledge` resolves to that package's
11
+ * `.d.ts`, and importing a declaration file yields a module with no exports at
12
+ * all — every one of them is a type. A binding declared in a `.ts` gives the
13
+ * inspector a file it can execute, and the import inside it resolves to the
14
+ * package's emitted JS.
15
+ * 2. The command files import `#pikku`, which points at `dist/.pikku/` — output
16
+ * that does not exist yet while the bootstrap is running. A schema the
17
+ * inspector has to import therefore cannot live beside a wired function.
18
+ *
19
+ * `schemaRuntimeFile` in the inspector fixes (1) at the root, so once a release
20
+ * carrying it is the bootstrap version, (2) is the only reason this file is here.
21
+ */
22
+ export const KnowledgeIndexInputSchema = KnowledgeIndexInput;
23
+ export const KnowledgeIndexOutputSchema = KnowledgeIndexOutput;
24
+ export const KnowledgeValidateInputSchema = KnowledgeValidateInput;
25
+ export const KnowledgeValidateOutputSchema = KnowledgeValidateOutput;
@@ -1,5 +1,12 @@
1
1
  import { validateAndBuildCredentialDefinitionsMeta } from '@pikku/core/credential';
2
2
  import { getFileImportRelativePath } from '../../../utils/file-import-path.js';
3
+ /**
4
+ * A display name is the human-facing label a developer wrote, so an apostrophe
5
+ * in it is ordinary. `JSON.stringify` emits a valid, escaped TypeScript string
6
+ * literal; interpolating the raw text into a quoted one terminates the string
7
+ * and the generated file stops parsing.
8
+ */
9
+ const literal = (value) => JSON.stringify(value);
3
10
  export const serializeCredentialsTypes = ({ definitions, schemaLookup, credentialsFile, packageMappings, }) => {
4
11
  const credentials = validateAndBuildCredentialDefinitionsMeta(definitions, schemaLookup);
5
12
  const credentialEntries = Object.entries(credentials);
@@ -22,7 +29,7 @@ export const serializeCredentialsTypes = ({ definitions, schemaLookup, credentia
22
29
  }
23
30
  const metaParts = [
24
31
  `name: '${name}'`,
25
- `displayName: '${meta.displayName}'`,
32
+ `displayName: ${literal(meta.displayName)}`,
26
33
  `type: '${meta.type}'`,
27
34
  ];
28
35
  if (meta.oauth2) {
@@ -1,6 +1,7 @@
1
1
  import { pikkuSessionlessFunc } from '#pikku';
2
2
  import { saveSchemas } from '../../../utils/serialize-schemas.js';
3
3
  import { logCommandInfoAndTime } from '../../../middleware/log-command-info-and-time.js';
4
+ import { partitionRequiredSchemas } from '../scenarios/scenario-schema-partition.js';
4
5
  export const pikkuSchemas = pikkuSessionlessFunc({
5
6
  func: async ({ logger, config, getInspectorState }) => {
6
7
  const visitState = await getInspectorState();
@@ -16,7 +17,18 @@ export const pikkuSchemas = pikkuSessionlessFunc({
16
17
  Object.keys(visitState.schemas).length === 0) {
17
18
  return undefined;
18
19
  }
19
- await saveSchemas(logger, config.schemaDirectory, visitState.schemas, visitState.requiredSchemas, config.schema?.supportsImportAttributes ?? true, config.addonName || null);
20
+ const supportsImportAttributes = config.schema?.supportsImportAttributes ?? true;
21
+ const { appRequired, scenarioOnly } = partitionRequiredSchemas({
22
+ functionsMeta: visitState.functions.meta,
23
+ requiredSchemas: visitState.requiredSchemas,
24
+ getUniqueName: (name) => visitState.functions.typesMap.getUniqueName(name),
25
+ schemasFromTypes: config.schemasFromTypes,
26
+ });
27
+ await saveSchemas(logger, config.schemaDirectory, visitState.schemas, appRequired, supportsImportAttributes, config.addonName || null);
28
+ // Always written, even when empty — the scenario bootstrap imports it
29
+ // unconditionally, and a project that deleted its last scenario must stop
30
+ // registering the schemas it had.
31
+ await saveSchemas(logger, config.scenarioSchemaDirectory, visitState.schemas, scenarioOnly, supportsImportAttributes, config.addonName || null, 'scenario schemas');
20
32
  return true;
21
33
  },
22
34
  middleware: [
@@ -2,6 +2,7 @@ import { pikkuSessionlessFunc } from '#pikku';
2
2
  import { writeFileInDir } from '../../../utils/file-writer.js';
3
3
  import { logCommandInfoAndTime } from '../../../middleware/log-command-info-and-time.js';
4
4
  import { getFileImportRelativePath } from '../../../utils/file-import-path.js';
5
+ import { withoutScenarios } from '../scenarios/scenario-partition.js';
5
6
  export function filterInternalRPCMeta(internalMeta, functionsMeta) {
6
7
  const filteredInternalMeta = {};
7
8
  for (const [key, value] of Object.entries(internalMeta)) {
@@ -18,7 +19,11 @@ export const pikkuRPC = pikkuSessionlessFunc({
18
19
  // Keep direct function ids and unversioned aliases whose target function
19
20
  // survived filtering. Without the second check, aliases like `listCards`
20
21
  // get dropped even though `listCards@v2` still exists.
21
- const filteredInternalMeta = filterInternalRPCMeta(rpc.internalMeta, functions.meta);
22
+ // Scenarios are excluded along with the steps they call: a scenario name in
23
+ // the app's RPC meta is a name a deployed bundle carries and, in principle,
24
+ // dispatches. Scenario runs don't need the entry — the mapping is the
25
+ // identity, which is also the fallback when a name is absent.
26
+ const filteredInternalMeta = filterInternalRPCMeta(rpc.internalMeta, withoutScenarios(functions.meta));
22
27
  if (Object.keys(filteredInternalMeta).length > 0) {
23
28
  await writeFileInDir(logger, rpcInternalWiringMetaJsonFile, JSON.stringify(filteredInternalMeta, null, 2));
24
29
  const jsonImportPath = getFileImportRelativePath(rpcInternalWiringMetaFile, rpcInternalWiringMetaJsonFile, packageMappings);
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Register the instrumentation into the running dev server's state, so the
3
+ * scenario runner can reach it over `/rpc/<name>` exactly as before.
4
+ *
5
+ * They are registered sessionless: `auth` decides whether a session is
6
+ * *required*, and a sessioned function would demand one regardless of the flag —
7
+ * which is what made `scaffold.scenarios: true` (as opposed to `'auth'`) refuse
8
+ * every call and log a warning about it.
9
+ */
10
+ export declare const registerScenarioInstrumentation: (requireAuth: boolean) => void;
@@ -0,0 +1,102 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { addFunction } from '@pikku/core/function';
4
+ import { pikkuState } from '@pikku/core/internal';
5
+ import { getStubTracker, isTestRun, } from '@pikku/core/services';
6
+ /**
7
+ * The instrumentation `pikku scenario run` calls on the server under test:
8
+ * snapshot/reset live coverage, and reset/read recorded stub calls.
9
+ *
10
+ * These are pikku's, not the application's. They were previously scaffolded into
11
+ * the project as ordinary `pikkuFunc`s, which is why they ended up registered in
12
+ * the app bootstrap and shipped — `expose: true` — inside every deployed bundle.
13
+ * Registering them here instead means the only process that has them is the one
14
+ * that should: a development server. Nothing is generated, nothing is written to
15
+ * the user's source tree, and a bundle cannot carry what was never in its
16
+ * bootstrap.
17
+ *
18
+ * The bodies are unchanged from the generated ones, minus their schemas: an
19
+ * instrumentation endpoint with a single optional string argument has nothing to
20
+ * validate, and dropping the schemas drops the `zod` dependency the scaffold
21
+ * silently required of every project.
22
+ */
23
+ const takeLiveCoverage = {
24
+ func: async ({ coverageService, metaService }) => {
25
+ if (!coverageService?.takeReport || !metaService?.basePath)
26
+ return null;
27
+ let functionsMeta;
28
+ try {
29
+ const content = await readFile(join(metaService.basePath, 'function', 'pikku-functions-meta-verbose.gen.json'), 'utf-8');
30
+ functionsMeta = JSON.parse(content);
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ return await coverageService.takeReport(functionsMeta);
36
+ },
37
+ };
38
+ const resetLiveCoverage = {
39
+ func: async ({ coverageService }) => {
40
+ if (!coverageService)
41
+ return { enabled: false };
42
+ await coverageService.reset();
43
+ return { enabled: true };
44
+ },
45
+ };
46
+ const resetStubs = {
47
+ func: async () => {
48
+ getStubTracker().reset();
49
+ return { enabled: isTestRun() };
50
+ },
51
+ };
52
+ const getStubCalls = {
53
+ func: async (_services, data) => getStubTracker().getCalls(data?.service ?? undefined),
54
+ };
55
+ const instrumentation = {
56
+ pikkuScenarioTakeLiveCoverage: {
57
+ ...takeLiveCoverage,
58
+ title: 'Take Live Coverage',
59
+ description: 'Snapshots the live coverage collected since the server started (or since the last reset) — V8 precise coverage on Node, istanbul instrumentation on Bun — and maps it onto function body spans. Returns null unless the server was started with coverage enabled (pikku dev --coverage).',
60
+ },
61
+ pikkuScenarioResetLiveCoverage: {
62
+ ...resetLiveCoverage,
63
+ title: 'Reset Live Coverage',
64
+ description: 'Clears coverage call counts so the next takeLiveCoverage snapshot is attributable to a single scenario run. Reports enabled: false when the server was not started with coverage enabled.',
65
+ },
66
+ pikkuScenarioResetStubs: {
67
+ ...resetStubs,
68
+ title: 'Reset Stubs',
69
+ description: 'Clears recorded stub calls so the next getStubCalls result is attributable to a single scenario run. Reports enabled: false when the server was not started in test mode.',
70
+ },
71
+ pikkuScenarioGetStubCalls: {
72
+ ...getStubCalls,
73
+ title: 'Get Stub Calls',
74
+ description: 'Returns calls recorded against stubbed/spied services (via the stub()/spy() core utils). Empty unless the server records service calls (pikku dev --test).',
75
+ },
76
+ };
77
+ /**
78
+ * Register the instrumentation into the running dev server's state, so the
79
+ * scenario runner can reach it over `/rpc/<name>` exactly as before.
80
+ *
81
+ * They are registered sessionless: `auth` decides whether a session is
82
+ * *required*, and a sessioned function would demand one regardless of the flag —
83
+ * which is what made `scaffold.scenarios: true` (as opposed to `'auth'`) refuse
84
+ * every call and log a warning about it.
85
+ */
86
+ export const registerScenarioInstrumentation = (requireAuth) => {
87
+ const meta = pikkuState(null, 'function', 'meta');
88
+ for (const [name, { func, title, description }] of Object.entries(instrumentation)) {
89
+ addFunction(name, { func, auth: requireAuth });
90
+ meta[name] = {
91
+ pikkuFuncId: name,
92
+ inputSchemaName: null,
93
+ outputSchemaName: null,
94
+ expose: true,
95
+ sessionless: true,
96
+ tags: ['pikku'],
97
+ title,
98
+ description,
99
+ };
100
+ }
101
+ pikkuState(null, 'function', 'meta', meta);
102
+ };
@@ -12,6 +12,12 @@ export type WiringFileMap = Map<string, {
12
12
  * them in `.pikku/scenarios/`, reachable only from `pikku scenario run`.
13
13
  */
14
14
  export declare const isScenarioStep: (meta: FunctionsMeta[string] | undefined) => boolean;
15
+ /**
16
+ * A scenario's own body is a function too, so the app meta used to carry every
17
+ * scenario's name, schemas and hashes — and a deployed bundle imports that meta
18
+ * wholesale. Both kinds belong on the scenario side of the split.
19
+ */
20
+ export declare const isScenarioFunction: (meta: FunctionsMeta[string] | undefined) => boolean;
15
21
  export declare const partitionScenarioFunctions: (files: WiringFileMap, functionsMeta: FunctionsMeta) => {
16
22
  app: WiringFileMap;
17
23
  scenario: WiringFileMap;
@@ -27,3 +33,10 @@ export declare const partitionScenarioWorkflows: (workflowNames: string[], workf
27
33
  appFiles: WiringFileMap;
28
34
  scenarioFiles: WiringFileMap;
29
35
  };
36
+ /**
37
+ * Drop every scenario and step from a function meta map. The deploy analyzer
38
+ * reads inspector state rather than the partitioned codegen output, so it needs
39
+ * the same split applied before it decides what a deployment contains.
40
+ */
41
+ export declare const withoutScenarios: (functionsMeta: FunctionsMeta) => FunctionsMeta;
42
+ export declare const withoutScenarioWorkflows: (graphMeta: SerializedWorkflowGraphs) => SerializedWorkflowGraphs;