@pikku/cli 0.12.25 → 0.12.26

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 (115) hide show
  1. package/console-app/assets/{index-D4DgafuS.js → index-Ba9K10XZ.js} +4 -4
  2. package/console-app/index.html +1 -1
  3. package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
  4. package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
  5. package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
  6. package/dist/.pikku/cli/pikku-cli-channel.js +6 -1
  7. package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
  8. package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
  9. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
  10. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +9 -0
  11. package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
  12. package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
  13. package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
  14. package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
  15. package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
  16. package/dist/.pikku/function/pikku-function-types.gen.d.ts +1 -1
  17. package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
  18. package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
  19. package/dist/.pikku/function/pikku-functions-meta.gen.json +116 -101
  20. package/dist/.pikku/function/pikku-functions.gen.js +3 -1
  21. package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
  22. package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
  23. package/dist/.pikku/http/pikku-http-wirings-meta.gen.js +1 -1
  24. package/dist/.pikku/http/pikku-http-wirings.gen.d.ts +1 -1
  25. package/dist/.pikku/http/pikku-http-wirings.gen.js +1 -1
  26. package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
  27. package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
  28. package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
  29. package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
  30. package/dist/.pikku/pikku-meta-service.gen.d.ts +1 -1
  31. package/dist/.pikku/pikku-meta-service.gen.js +1 -1
  32. package/dist/.pikku/pikku-services.gen.d.ts +1 -1
  33. package/dist/.pikku/pikku-types.gen.d.ts +1 -1
  34. package/dist/.pikku/pikku-types.gen.js +1 -1
  35. package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
  36. package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
  37. package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
  38. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
  39. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
  40. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
  41. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +10 -9
  42. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
  43. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
  44. package/dist/.pikku/schemas/register.gen.js +7 -5
  45. package/dist/.pikku/schemas/schemas/DbAuditInput.schema.json +1 -0
  46. package/dist/.pikku/schemas/schemas/PikkuTestsCoverageInput.schema.json +1 -1
  47. package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
  48. package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
  49. package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
  50. package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
  51. package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
  52. package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
  53. package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
  54. package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
  55. package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
  56. package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
  57. package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
  58. package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
  59. package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
  60. package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
  61. package/dist/bin/pikku-bin.mjs +2 -2
  62. package/dist/src/cli.wiring.js +8 -0
  63. package/dist/src/fabric/functions/validate.function.js +1 -1
  64. package/dist/src/functions/commands/db-audit.d.ts +1 -0
  65. package/dist/src/functions/commands/db-audit.js +67 -0
  66. package/dist/src/functions/commands/db-migrate.js +5 -8
  67. package/dist/src/functions/commands/db-reset.js +9 -8
  68. package/dist/src/functions/commands/db-seed.js +9 -8
  69. package/dist/src/functions/commands/db-shared.d.ts +2 -4
  70. package/dist/src/functions/commands/db-shared.js +15 -5
  71. package/dist/src/functions/commands/dev.js +14 -8
  72. package/dist/src/functions/commands/new-addon.js +2 -2
  73. package/dist/src/functions/commands/tests-coverage.d.ts +3 -0
  74. package/dist/src/functions/commands/tests-coverage.js +34 -0
  75. package/dist/src/functions/db/annotation-parser.d.ts +31 -0
  76. package/dist/src/functions/db/annotation-parser.js +93 -0
  77. package/dist/src/functions/db/db-codegen.d.ts +24 -0
  78. package/dist/src/functions/db/db-codegen.js +276 -0
  79. package/dist/src/functions/db/db-introspector.d.ts +15 -0
  80. package/dist/src/functions/db/db-introspector.js +1 -0
  81. package/dist/src/functions/db/db-migrator.d.ts +32 -0
  82. package/dist/src/functions/db/db-migrator.js +65 -0
  83. package/dist/src/functions/db/local-db.d.ts +27 -33
  84. package/dist/src/functions/db/local-db.js +100 -53
  85. package/dist/src/functions/db/postgres/postgres-introspector.d.ts +10 -0
  86. package/dist/src/functions/db/postgres/postgres-introspector.js +54 -0
  87. package/dist/src/functions/db/postgres/postgres-migrator.d.ts +9 -0
  88. package/dist/src/functions/db/postgres/postgres-migrator.js +32 -0
  89. package/dist/src/functions/db/sqlite/sqlite-introspector.d.ts +9 -0
  90. package/dist/src/functions/db/sqlite/sqlite-introspector.js +35 -0
  91. package/dist/src/functions/db/sqlite/sqlite-migrator.d.ts +10 -0
  92. package/dist/src/functions/db/sqlite/sqlite-migrator.js +36 -0
  93. package/dist/src/functions/validate/workspace-validate.js +3 -2
  94. package/dist/src/functions/wirings/ai-agent/serialize-public-agent.js +2 -1
  95. package/dist/src/functions/wirings/console/serialize-console-functions.js +4 -4
  96. package/dist/src/functions/wirings/functions/serialize-addon-types.js +1 -1
  97. package/dist/src/scaffold/rpc-remote.gen.js +1 -1
  98. package/dist/src/services.js +2 -0
  99. package/dist/tsconfig.tsbuildinfo +1 -1
  100. package/package.json +5 -3
  101. package/skills/pikku-testing/SKILL.md +208 -0
  102. package/dist/src/functions/db/sql-migrator.d.ts +0 -26
  103. package/dist/src/functions/db/sql-migrator.js +0 -104
  104. package/dist/src/functions/db/sqlite-codegen.d.ts +0 -45
  105. package/dist/src/functions/db/sqlite-codegen.js +0 -294
  106. /package/dist/src/functions/db/{seed.d.ts → sqlite/seed.d.ts} +0 -0
  107. /package/dist/src/functions/db/{seed.js → sqlite/seed.js} +0 -0
  108. /package/dist/src/functions/db/{sqlite-kysely.d.ts → sqlite/sqlite-kysely.d.ts} +0 -0
  109. /package/dist/src/functions/db/{sqlite-kysely.js → sqlite/sqlite-kysely.js} +0 -0
  110. /package/dist/src/functions/db/{sqlite-runtime-bun.d.ts → sqlite/sqlite-runtime-bun.d.ts} +0 -0
  111. /package/dist/src/functions/db/{sqlite-runtime-bun.js → sqlite/sqlite-runtime-bun.js} +0 -0
  112. /package/dist/src/functions/db/{sqlite-runtime-node.d.ts → sqlite/sqlite-runtime-node.d.ts} +0 -0
  113. /package/dist/src/functions/db/{sqlite-runtime-node.js → sqlite/sqlite-runtime-node.js} +0 -0
  114. /package/dist/src/functions/db/{sqlite-runtime.d.ts → sqlite/sqlite-runtime.d.ts} +0 -0
  115. /package/dist/src/functions/db/{sqlite-runtime.js → sqlite/sqlite-runtime.js} +0 -0
@@ -1,294 +0,0 @@
1
- import { readFileSync, writeFileSync, mkdirSync, readdirSync } from 'node:fs';
2
- import { dirname, join } from 'node:path';
3
- const SKIP_TABLES = new Set(['sqlite_sequence', 'sql_migrations']);
4
- function snakeToPascal(name) {
5
- return name
6
- .split('_')
7
- .map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())
8
- .join('');
9
- }
10
- function snakeToCamel(name) {
11
- return name.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
12
- }
13
- function mapType(sqlType) {
14
- const upper = sqlType.toUpperCase();
15
- if (upper.includes('INT'))
16
- return 'number';
17
- if (upper.includes('CHAR') ||
18
- upper.includes('CLOB') ||
19
- upper.includes('TEXT')) {
20
- return 'string';
21
- }
22
- if (upper.includes('BLOB'))
23
- return 'Buffer';
24
- if (upper.includes('REAL') ||
25
- upper.includes('FLOA') ||
26
- upper.includes('DOUB')) {
27
- return 'number';
28
- }
29
- if (upper.includes('NUMERIC') || upper.includes('DECIMAL'))
30
- return 'number';
31
- if (upper.includes('BOOL'))
32
- return 'number';
33
- return 'string';
34
- }
35
- function listTables(db) {
36
- const tableRows = db
37
- .prepare(`SELECT name FROM sqlite_master
38
- WHERE type = 'table'
39
- AND name NOT LIKE 'sqlite\\_%' ESCAPE '\\'
40
- ORDER BY name`)
41
- .all();
42
- return tableRows
43
- .filter((t) => !SKIP_TABLES.has(t.name))
44
- .map((t) => {
45
- const allColumns = db
46
- .prepare(`PRAGMA table_xinfo(${escapeIdentifier(t.name)})`)
47
- .all();
48
- // hidden: 0=regular, 2=virtual generated, 3=stored generated — include all; skip 1 (vtab hidden)
49
- const columns = allColumns.filter((c) => c.hidden !== 1);
50
- return { name: t.name, columns };
51
- });
52
- }
53
- function escapeIdentifier(name) {
54
- return `"${name.replace(/"/g, '""')}"`;
55
- }
56
- // ─── Annotation parsing ──────────────────────────────────────────────────────
57
- /**
58
- * Determine column kind from naming conventions:
59
- * *_at / *_on → date
60
- * is_* / has_* / can_* → bool
61
- */
62
- function annotationFromName(colName) {
63
- if (/_at$|_on$/.test(colName))
64
- return { kind: 'date' };
65
- if (/^is_|^has_|^can_/.test(colName))
66
- return { kind: 'bool' };
67
- return null;
68
- }
69
- /**
70
- * Parse `-- @bool | @date | @json [TypescriptType]` inline annotations from
71
- * migration SQL files. The TypeScript type is optional and only meaningful for
72
- * `@json` — it controls the generated TypeScript type (e.g. `string[]`,
73
- * `Record<string, number>`).
74
- *
75
- * Returns an AnnotationMap: { table_name: { col_name: ColAnnotation } }.
76
- */
77
- export function parseAnnotations(migrationsDir) {
78
- let files;
79
- try {
80
- files = readdirSync(migrationsDir)
81
- .filter((f) => f.endsWith('.sql'))
82
- .sort();
83
- }
84
- catch {
85
- return {};
86
- }
87
- const result = {};
88
- for (const file of files) {
89
- const content = readFileSync(join(migrationsDir, file), 'utf8');
90
- const createTablePattern = /CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?"?(\w+)"?\s*\(([^;]+)\)/gis;
91
- let tableMatch;
92
- while ((tableMatch = createTablePattern.exec(content)) !== null) {
93
- const tableName = tableMatch[1].toLowerCase();
94
- const body = tableMatch[2];
95
- for (const line of body.split('\n')) {
96
- const trimmed = line.trim();
97
- if (/^(PRIMARY|UNIQUE|CHECK|FOREIGN|CONSTRAINT)/i.test(trimmed))
98
- continue;
99
- // Match: col_name TYPE ... -- @kind [optional ts type]
100
- const annotationMatch = trimmed.match(/^(\w+)\s+\w.*?--\s*@(bool|date|json)(?:\s+(.+?))?$/i);
101
- if (annotationMatch) {
102
- const colName = annotationMatch[1].toLowerCase();
103
- const kind = annotationMatch[2].toLowerCase();
104
- const tsType = annotationMatch[3]?.trim() || undefined;
105
- if (!result[tableName])
106
- result[tableName] = {};
107
- result[tableName][colName] = {
108
- kind,
109
- tsType: kind === 'json' ? tsType : undefined,
110
- };
111
- }
112
- }
113
- }
114
- }
115
- return result;
116
- }
117
- /**
118
- * Merge explicit SQL annotations with naming-convention-based ones.
119
- * Explicit annotations take precedence.
120
- */
121
- function buildAnnotationMap(tables, explicit) {
122
- const merged = {};
123
- for (const table of tables) {
124
- const explicitCols = explicit[table.name] ?? {};
125
- for (const col of table.columns) {
126
- const annotation = explicitCols[col.name] ?? annotationFromName(col.name);
127
- if (annotation) {
128
- if (!merged[table.name])
129
- merged[table.name] = {};
130
- merged[table.name][col.name] = annotation;
131
- }
132
- }
133
- }
134
- return merged;
135
- }
136
- // ─── Type expression ─────────────────────────────────────────────────────────
137
- function columnTypeExpression(col, annotation) {
138
- const nullable = !col.notnull && col.pk === 0;
139
- const hasDefault = col.dflt_value !== null && col.dflt_value !== undefined;
140
- const isAutoInt = col.pk === 1 && mapType(col.type) === 'number';
141
- const isGenerated = col.hidden === 2 || col.hidden === 3;
142
- const wrap = (inner) => hasDefault || isAutoInt || isGenerated ? `Generated<${inner}>` : inner;
143
- if (annotation?.kind === 'bool') {
144
- const base = nullable ? 'boolean | null' : 'boolean';
145
- const rw = nullable ? 'boolean | number | null' : 'boolean | number';
146
- return wrap(`ColumnType<${base}, ${rw}, ${rw}>`);
147
- }
148
- if (annotation?.kind === 'date') {
149
- const base = nullable ? 'Date | null' : 'Date';
150
- const rw = nullable ? 'Date | string | null' : 'Date | string';
151
- return wrap(`ColumnType<${base}, ${rw}, ${rw}>`);
152
- }
153
- if (annotation?.kind === 'json') {
154
- const base = annotation.tsType
155
- ? nullable
156
- ? `${annotation.tsType} | null`
157
- : annotation.tsType
158
- : nullable
159
- ? 'unknown | null'
160
- : 'unknown';
161
- return wrap(base);
162
- }
163
- // Default: plain SQL-mapped type
164
- const base = mapType(col.type);
165
- if (isAutoInt)
166
- return `Generated<${base}>`;
167
- if (hasDefault || isGenerated)
168
- return `Generated<${base}${nullable ? ' | null' : ''}>`;
169
- return nullable ? `${base} | null` : base;
170
- }
171
- // ─── Interface emitter ───────────────────────────────────────────────────────
172
- function emitInterface(table, camelCase, annotations) {
173
- const ifaceName = snakeToPascal(table.name);
174
- const tableCols = annotations[table.name] ?? {};
175
- const fields = table.columns
176
- .map((col) => {
177
- const fieldName = camelCase ? snakeToCamel(col.name) : col.name;
178
- const annotation = tableCols[col.name] ?? null;
179
- const type = columnTypeExpression(col, annotation);
180
- const safeName = /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(fieldName)
181
- ? fieldName
182
- : JSON.stringify(fieldName);
183
- return ` ${safeName}: ${type}`;
184
- })
185
- .join('\n');
186
- return `export interface ${ifaceName} {\n${fields}\n}`;
187
- }
188
- /**
189
- * Introspect the open SQLite database and emit a Kysely DB type to outFile
190
- * plus a CoercionMap to coercionFile.
191
- *
192
- * Columns are annotated via:
193
- * 1. Naming conventions (_at/_on → date; is_/has_/can_ → bool)
194
- * 2. Inline SQL comments: `col_name TYPE ... -- @bool|@date|@json [TsType]`
195
- * For @json, an optional TypeScript type string controls the generated type.
196
- *
197
- * Returns `written: false` if the on-disk file already matches.
198
- */
199
- export function generateSchemaTypes(db, options) {
200
- const camelCase = options.camelCase ?? true;
201
- const tables = listTables(db);
202
- const explicitAnnotations = options.migrationsDir
203
- ? parseAnnotations(options.migrationsDir)
204
- : {};
205
- const annotations = buildAnnotationMap(tables, explicitAnnotations);
206
- // ── schema.d.ts ──
207
- const interfaces = tables
208
- .map((t) => emitInterface(t, camelCase, annotations))
209
- .join('\n\n');
210
- const dbEntries = tables
211
- .map((t) => {
212
- const tableKey = camelCase ? snakeToCamel(t.name) : t.name;
213
- const safe = /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(tableKey)
214
- ? tableKey
215
- : JSON.stringify(tableKey);
216
- return ` ${safe}: ${snakeToPascal(t.name)}`;
217
- })
218
- .join('\n');
219
- const schemaBody = [
220
- `// Generated by @pikku/cli — do not edit by hand.`,
221
- `// Run \`pikku db migrate\` to refresh.`,
222
- ``,
223
- `import type { ColumnType } from 'kysely'`,
224
- ``,
225
- `export type Generated<T> = T extends ColumnType<infer S, infer I, infer U>`,
226
- ` ? ColumnType<S, I | undefined, U>`,
227
- ` : ColumnType<T, T | undefined, T>`,
228
- ``,
229
- interfaces,
230
- ``,
231
- `export interface DB {`,
232
- dbEntries,
233
- `}`,
234
- ``,
235
- ].join('\n');
236
- // ── coercion.gen.ts (runtime map — only kind, not tsType) ──
237
- const runtimeMap = {};
238
- for (const [table, cols] of Object.entries(annotations)) {
239
- for (const [col, ann] of Object.entries(cols)) {
240
- if (!runtimeMap[table])
241
- runtimeMap[table] = {};
242
- runtimeMap[table][col] = ann.kind;
243
- }
244
- }
245
- const coercionEntries = Object.entries(runtimeMap)
246
- .map(([table, cols]) => {
247
- const colEntries = Object.entries(cols)
248
- .map(([col, kind]) => ` "${col}": "${kind}"`)
249
- .join(',\n');
250
- return ` "${table}": {\n${colEntries}\n }`;
251
- })
252
- .join(',\n');
253
- const coercionBody = [
254
- `// Generated by @pikku/cli — do not edit by hand.`,
255
- `// Run \`pikku db migrate\` to refresh.`,
256
- ``,
257
- `export const coercionMap = {`,
258
- coercionEntries,
259
- `} as const`,
260
- ``,
261
- ].join('\n');
262
- // ── write files ──
263
- let existingSchema = null;
264
- let existingCoercion = null;
265
- try {
266
- existingSchema = readFileSync(options.outFile, 'utf8');
267
- }
268
- catch {
269
- /* ok */
270
- }
271
- try {
272
- existingCoercion = readFileSync(options.coercionFile, 'utf8');
273
- }
274
- catch {
275
- /* ok */
276
- }
277
- const schemaChanged = existingSchema !== schemaBody;
278
- const coercionChanged = existingCoercion !== coercionBody;
279
- if (schemaChanged) {
280
- mkdirSync(dirname(options.outFile), { recursive: true });
281
- writeFileSync(options.outFile, schemaBody, 'utf8');
282
- }
283
- if (coercionChanged) {
284
- mkdirSync(dirname(options.coercionFile), { recursive: true });
285
- writeFileSync(options.coercionFile, coercionBody, 'utf8');
286
- }
287
- return {
288
- outFile: options.outFile,
289
- coercionFile: options.coercionFile,
290
- written: schemaChanged,
291
- coercionWritten: coercionChanged,
292
- tables: tables.map((t) => t.name),
293
- };
294
- }