@pikku/cli 0.12.32 → 0.12.34

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 (76) hide show
  1. package/cli.schema.json +1 -1
  2. package/console-app/assets/index-DsW0T00Z.js +233 -0
  3. package/console-app/index.html +1 -1
  4. package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
  5. package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
  6. package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
  7. package/dist/.pikku/cli/pikku-cli-channel.js +1 -1
  8. package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
  9. package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
  10. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
  11. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +1 -0
  12. package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
  13. package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
  14. package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
  15. package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
  16. package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
  17. package/dist/.pikku/function/pikku-function-types.gen.d.ts +1 -1
  18. package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
  19. package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
  20. package/dist/.pikku/function/pikku-functions-meta.gen.json +158 -158
  21. package/dist/.pikku/function/pikku-functions.gen.js +1 -1
  22. package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
  23. package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
  24. package/dist/.pikku/http/pikku-http-wirings-meta.gen.js +1 -1
  25. package/dist/.pikku/http/pikku-http-wirings.gen.d.ts +1 -1
  26. package/dist/.pikku/http/pikku-http-wirings.gen.js +1 -1
  27. package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
  28. package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
  29. package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
  30. package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
  31. package/dist/.pikku/pikku-meta-service.gen.d.ts +1 -1
  32. package/dist/.pikku/pikku-meta-service.gen.js +1 -1
  33. package/dist/.pikku/pikku-services.gen.d.ts +2 -1
  34. package/dist/.pikku/pikku-services.gen.js +1 -0
  35. package/dist/.pikku/pikku-types.gen.d.ts +1 -1
  36. package/dist/.pikku/pikku-types.gen.js +1 -1
  37. package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
  38. package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
  39. package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
  40. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
  41. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
  42. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
  43. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +8 -8
  44. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
  45. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
  46. package/dist/.pikku/schemas/register.gen.js +11 -11
  47. package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
  48. package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
  49. package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
  50. package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
  51. package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
  52. package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
  53. package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
  54. package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
  55. package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
  56. package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
  57. package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
  58. package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
  59. package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
  60. package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
  61. package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
  62. package/dist/bin/pikku-bin.mjs +2 -2
  63. package/dist/src/deploy/analyzer/analyzer.js +7 -4
  64. package/dist/src/fabric/fabric-commands.d.ts +3 -3
  65. package/dist/src/fabric/functions/llm-key.function.d.ts +4 -4
  66. package/dist/src/functions/db/db-codegen.js +7 -3
  67. package/dist/src/functions/db/zod-codegen.js +81 -6
  68. package/dist/src/functions/wirings/console/serialize-console-functions.js +6 -0
  69. package/dist/src/functions/wirings/mcp/pikku-command-mcp-json.js +1 -1
  70. package/dist/src/functions/wirings/rpc/serialize-rpc-wrapper.js +8 -0
  71. package/dist/src/functions/workflows/all.workflow.js +1 -1
  72. package/dist/src/scaffold/rpc-remote.gen.js +1 -1
  73. package/dist/src/utils/pikku-cli-config.js +3 -0
  74. package/package.json +5 -5
  75. package/skills/pikku-workflow/SKILL.md +31 -2
  76. package/console-app/assets/index-BkiCv5R3.js +0 -229
@@ -67,14 +67,67 @@ function emitZodModule(tables) {
67
67
  }
68
68
  return `${lines.join('\n')}\n`;
69
69
  }
70
+ /**
71
+ * Resolve a Kysely field type to a `{ schema, generated }` pair, where `schema`
72
+ * is the zod expression for the *row* (select) shape and `generated` is true
73
+ * when the column is optional on insert.
74
+ *
75
+ * `db-codegen` emits two field shapes depending on a column's classification:
76
+ * - public columns → `Generated<T>`, bare `T`, `T | null`, or a public
77
+ * bool/date column as `Generated<ColumnType<base, rw, rw>>`
78
+ * - private/pii/secret columns (the default is `private`) →
79
+ * `ColumnType<Brand<base> | null, insert | undefined, update>`
80
+ * where Brand is `Private` | `Pii` | `Secret`.
81
+ *
82
+ * For `ColumnType<Select, Insert, Update>` the row schema comes from `Select`
83
+ * and the column is insert-optional when `Insert` admits `undefined` (Kysely's
84
+ * encoding for default/auto/generated columns).
85
+ */
70
86
  function zodForType(tsType) {
71
- const generatedMatch = tsType.match(/^Generated<(.+)>$/);
72
- const generated = generatedMatch !== null;
73
- let inner = generated ? generatedMatch[1].trim() : tsType;
87
+ let inner = tsType.trim();
88
+ let generated = false;
89
+ // Peel a single `Generated<…>` wrapper. For public bool/date columns this
90
+ // wraps a `ColumnType<…>`, so the unwrapped inner is handled below.
91
+ const generatedMatch = inner.match(/^Generated<(.+)>$/);
92
+ if (generatedMatch) {
93
+ generated = true;
94
+ inner = generatedMatch[1].trim();
95
+ }
96
+ // `ColumnType<Select, Insert, Update>` — classified columns and wrapped
97
+ // public bool/date columns. Row schema from Select; optional from Insert.
98
+ if (inner.startsWith('ColumnType<') && inner.endsWith('>')) {
99
+ const args = splitGenericArgs(inner.slice('ColumnType<'.length, -1));
100
+ const selectT = args[0]?.trim() ?? 'unknown';
101
+ const insertT = args[1]?.trim() ?? '';
102
+ if (unionIncludesUndefined(insertT)) {
103
+ generated = true;
104
+ }
105
+ return { schema: scalarSchema(selectT), generated };
106
+ }
107
+ return { schema: scalarSchema(inner), generated };
108
+ }
109
+ /**
110
+ * Resolve a scalar/select type expression to a zod expression. Handles a
111
+ * trailing `| null`, classification brands (`Private`/`Pii`/`Secret`), arrays,
112
+ * and the known scalar bases. Unknown bases fall back to `z.unknown()` so
113
+ * generation stays total.
114
+ */
115
+ function scalarSchema(tsType) {
116
+ let inner = tsType.trim();
117
+ // Defensive: a Select arg may itself be `Generated<…>` in older schemas.
118
+ const generatedMatch = inner.match(/^Generated<(.+)>$/);
119
+ if (generatedMatch) {
120
+ inner = generatedMatch[1].trim();
121
+ }
74
122
  const nullable = inner.endsWith(' | null');
75
123
  if (nullable) {
76
124
  inner = inner.slice(0, -' | null'.length).trim();
77
125
  }
126
+ // Unwrap a classification brand: `Private<T>` / `Pii<T>` / `Secret<T>` → T.
127
+ const brandMatch = inner.match(/^(?:Private|Pii|Secret)<(.+)>$/);
128
+ if (brandMatch) {
129
+ inner = brandMatch[1].trim();
130
+ }
78
131
  let schema;
79
132
  switch (inner) {
80
133
  case 'string':
@@ -94,8 +147,7 @@ function zodForType(tsType) {
94
147
  break;
95
148
  default:
96
149
  if (inner.endsWith('[]')) {
97
- const item = zodForType(inner.slice(0, -2).trim()).schema;
98
- schema = `z.array(${item})`;
150
+ schema = `z.array(${scalarSchema(inner.slice(0, -2).trim())})`;
99
151
  }
100
152
  else {
101
153
  schema = 'z.unknown()';
@@ -105,5 +157,28 @@ function zodForType(tsType) {
105
157
  if (nullable) {
106
158
  schema += '.nullable()';
107
159
  }
108
- return { schema, generated };
160
+ return schema;
161
+ }
162
+ /** Split the generic argument list of `Foo<a, b, c>` on top-level commas. */
163
+ function splitGenericArgs(args) {
164
+ const parts = [];
165
+ let depth = 0;
166
+ let start = 0;
167
+ for (let i = 0; i < args.length; i++) {
168
+ const char = args[i];
169
+ if (char === '<')
170
+ depth++;
171
+ else if (char === '>')
172
+ depth--;
173
+ else if (char === ',' && depth === 0) {
174
+ parts.push(args.slice(start, i));
175
+ start = i + 1;
176
+ }
177
+ }
178
+ parts.push(args.slice(start));
179
+ return parts;
180
+ }
181
+ /** True when a union type expression contains `undefined` as a top-level member. */
182
+ function unionIncludesUndefined(union) {
183
+ return union.split('|').some((member) => member.trim() === 'undefined');
109
184
  }
@@ -99,6 +99,12 @@ export const consoleRoutes = defineHTTPRoutes({
99
99
  sse: true,
100
100
  func: ref('console:streamWorkflowRun'),
101
101
  },
102
+ functionTestsStream: {
103
+ route: '/function-tests/stream',
104
+ method: 'get',
105
+ sse: true,
106
+ func: ref('console:streamFunctionTests'),
107
+ },
102
108
  },
103
109
  })
104
110
 
@@ -5,7 +5,7 @@ import { serializeMCPJson } from '@pikku/inspector';
5
5
  export const pikkuMCPJSON = pikkuSessionlessFunc({
6
6
  func: async ({ logger, config, getInspectorState }) => {
7
7
  const state = await getInspectorState();
8
- const mcpJsonFile = config.clientFiles?.mcpJsonFile;
8
+ const mcpJsonFile = config.mcpJsonFile ?? config.clientFiles?.mcpJsonFile;
9
9
  if (mcpJsonFile) {
10
10
  const mcpJson = serializeMCPJson(logger, state);
11
11
  await writeFileInDir(logger, mcpJsonFile, mcpJson, {
@@ -133,6 +133,14 @@ export class PikkuRPC {
133
133
  return await this.pikkuFetch.post(\`${globalHTTPPrefix}/rpc/agent/\${String(agentName)}/approve\` as never, input) as any
134
134
  },
135
135
  }
136
+
137
+ subscribeToSSE<T = unknown>(
138
+ path: string,
139
+ handler: (event: T) => void,
140
+ onError?: (err: unknown) => void
141
+ ): { close: () => void } {
142
+ return this.pikkuFetch.subscribeToSSE(path, handler, onError)
143
+ }
136
144
  }
137
145
 
138
146
  export const pikkuRPC = new PikkuRPC();
@@ -208,8 +208,8 @@ export const allWorkflow = pikkuWorkflowComplexFunc({
208
208
  if (gateways) {
209
209
  allImports.push(config.gatewaysWiringFile);
210
210
  }
211
+ await workflow.do('MCP JSON', 'pikkuMCPJSON', null);
211
212
  if (mcp) {
212
- await workflow.do('MCP JSON', 'pikkuMCPJSON', null);
213
213
  allImports.push(config.mcpWiringsMetaFile, config.mcpWiringsFile);
214
214
  }
215
215
  if (cli) {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * This file was generated by @pikku/cli@0.12.32
2
+ * This file was generated by @pikku/cli@0.12.34
3
3
  */
4
4
  /**
5
5
  * Auto-generated remote internal RPC queue worker and HTTP endpoint
@@ -309,6 +309,9 @@ const _getPikkuCLIConfig = async (logger, configFile = undefined, requiredFields
309
309
  if (!result.mcpTypesFile) {
310
310
  result.mcpTypesFile = join(mcpDir, 'pikku-mcp-types.gen.ts');
311
311
  }
312
+ if (!result.mcpJsonFile) {
313
+ result.mcpJsonFile = join(mcpDir, 'mcp.gen.json');
314
+ }
312
315
  // AI Agent
313
316
  const agentDir = join(result.outDir, 'agent');
314
317
  if (!result.agentWiringsFile) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/cli",
3
- "version": "0.12.32",
3
+ "version": "0.12.34",
4
4
  "author": "yasser.fadl@gmail.com",
5
5
  "license": "BUSL-1.1",
6
6
  "imports": {
@@ -26,13 +26,13 @@
26
26
  },
27
27
  "dependencies": {
28
28
  "@openapi-contrib/json-schema-to-openapi-schema": "^4.3.1",
29
- "@pikku/core": "^0.12.29",
29
+ "@pikku/core": "^0.12.31",
30
30
  "@pikku/deploy-cloudflare": "^0.12.3",
31
- "@pikku/fetch": "^0.12.2",
32
- "@pikku/inspector": "^0.12.15",
31
+ "@pikku/fetch": "^0.12.3",
32
+ "@pikku/inspector": "^0.12.19",
33
33
  "@pikku/kysely": "^0.12.14",
34
34
  "@pikku/kysely-node-sqlite": "^0.12.1",
35
- "@pikku/node-http-server": "^0.12.1",
35
+ "@pikku/node-http-server": "^0.12.2",
36
36
  "@pikku/openapi-parser": "^0.12.10",
37
37
  "@pikku/schedule": "^0.12.0",
38
38
  "@pikku/ws": "^0.12.2",
@@ -47,7 +47,7 @@ const myWorkflow = pikkuWorkflowFunc<InputType, OutputType>(
47
47
  ### Workflow Step Types
48
48
 
49
49
  ```typescript
50
- // RPC step — execute a Pikku function as a queue job
50
+ // RPC step — run a named Pikku function as a step
51
51
  // workflow.do(stepName, funcName, data, options?)
52
52
  const result = await workflow.do(
53
53
  'Create profile',
@@ -58,11 +58,40 @@ const result = await workflow.do(
58
58
  { retries: 3, retryDelay: '1s' }
59
59
  )
60
60
 
61
- // Inline step — immediate execution, cached for replay
61
+ // Inline closure step — immediate execution, cached for replay
62
62
  // workflow.do(stepName, asyncFn)
63
63
  const result = await workflow.do('Generate message', async () => {
64
64
  return `Welcome, ${data.email}!`
65
65
  })
66
+ ```
67
+
68
+ ### Step execution: inline vs queue dispatch
69
+
70
+ Whether a step runs **inline** (same process/session, no queue round-trip) or is **dispatched to the queue** is decided **purely by the step's function** — there is no workflow-level or per-call `inline` flag.
71
+
72
+ - **Steps default to inline.** Most steps don't need their own worker; running them inline avoids a queue round-trip per step, so a normally-started workflow executes its whole chain in one orchestrator pass.
73
+ - **`inline: false` opts a function out.** Set `inline: false` on the **function config** (`pikkuFunc` / `pikkuSessionlessFunc`, same level as `auth`/`expose`) to dispatch that step via the queue — for expensive/long-running steps that deserve their own worker, retry isolation, and concurrency limits. It is **not** a `workflow.do(...)` option (those are only `retries`/`retryDelay`/`description`).
74
+
75
+ The rule (`dispatchStep`):
76
+
77
+ | Function `inline` | `queueService` present? | Result |
78
+ |---|---|---|
79
+ | default / `true` | any | **inline** |
80
+ | `false` | yes | **queued** (own worker) |
81
+ | `false` | no | **inline + a `logger.warn`** (misconfiguration: can't dispatch) |
82
+
83
+ ```typescript
84
+ // Push this one expensive step onto the queue; every other step stays inline:
85
+ export const renderLargeReport = pikkuSessionlessFunc({
86
+ inline: false, // dispatch via queue instead of running inline
87
+ input: ReportInput,
88
+ output: ReportOutput,
89
+ func: async (services, data) => { /* ... */ },
90
+ })
91
+ ```
92
+
93
+ - **Run-level `inline` is separate** and only controls whether the *whole run* executes in-process without queue infrastructure (it's set automatically when there is no `queueService`, or via `startWorkflow(..., { inline: true })`). It governs sleep handling, **not** per-step dispatch — step dispatch is always per-function.
94
+ - `inline: false` requires a `queueService`; without one the step still runs (so the workflow progresses) but emits a `logger.warn` so the misconfiguration is visible.
66
95
 
67
96
  // Sleep — durable pause (duration: '5min', '1h', '30s', '1d')
68
97
  await workflow.sleep('Wait 5 minutes', '5min')