@funkai/cli 0.1.0 → 0.1.2

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 (42) hide show
  1. package/.turbo/turbo-build.log +15 -16
  2. package/CHANGELOG.md +15 -0
  3. package/README.md +1 -1
  4. package/dist/index.mjs +5018 -298
  5. package/dist/index.mjs.map +1 -1
  6. package/package.json +5 -5
  7. package/src/commands/generate.ts +4 -62
  8. package/src/commands/prompts/generate.ts +75 -48
  9. package/src/commands/prompts/lint.ts +62 -44
  10. package/src/commands/prompts/setup.ts +2 -7
  11. package/src/commands/validate.ts +4 -27
  12. package/src/index.ts +6 -1
  13. package/src/lib/prompts/codegen.ts +12 -16
  14. package/src/lib/prompts/flatten.ts +2 -7
  15. package/src/lib/prompts/frontmatter.ts +28 -33
  16. package/src/lib/prompts/lint.ts +8 -8
  17. package/src/lib/prompts/paths.ts +5 -5
  18. package/src/lib/prompts/pipeline.ts +6 -7
  19. package/.turbo/turbo-test$colon$coverage.log +0 -36
  20. package/.turbo/turbo-test.log +0 -26
  21. package/.turbo/turbo-typecheck.log +0 -4
  22. package/coverage/lcov-report/base.css +0 -224
  23. package/coverage/lcov-report/block-navigation.js +0 -87
  24. package/coverage/lcov-report/commands/create.ts.html +0 -208
  25. package/coverage/lcov-report/commands/generate.ts.html +0 -388
  26. package/coverage/lcov-report/commands/index.html +0 -161
  27. package/coverage/lcov-report/commands/lint.ts.html +0 -331
  28. package/coverage/lcov-report/commands/setup.ts.html +0 -493
  29. package/coverage/lcov-report/favicon.png +0 -0
  30. package/coverage/lcov-report/index.html +0 -131
  31. package/coverage/lcov-report/lib/codegen.ts.html +0 -805
  32. package/coverage/lcov-report/lib/extract-variables.ts.html +0 -181
  33. package/coverage/lcov-report/lib/flatten.ts.html +0 -385
  34. package/coverage/lcov-report/lib/frontmatter.ts.html +0 -487
  35. package/coverage/lcov-report/lib/index.html +0 -191
  36. package/coverage/lcov-report/lib/lint.ts.html +0 -307
  37. package/coverage/lcov-report/lib/paths.ts.html +0 -487
  38. package/coverage/lcov-report/prettify.css +0 -1
  39. package/coverage/lcov-report/prettify.js +0 -2
  40. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  41. package/coverage/lcov-report/sorter.js +0 -210
  42. package/coverage/lcov.info +0 -749
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@funkai/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "private": false,
5
5
  "description": "CLI for the funkai AI SDK framework",
6
6
  "keywords": [
@@ -26,18 +26,18 @@
26
26
  },
27
27
  "type": "module",
28
28
  "dependencies": {
29
- "@kidd-cli/core": "^0.4.0",
29
+ "@kidd-cli/core": "^0.5.0",
30
30
  "liquidjs": "^10.25.0",
31
31
  "ts-pattern": "^5.9.0",
32
32
  "yaml": "^2.8.2",
33
33
  "zod": "^4.3.6",
34
- "@funkai/prompts": "0.1.0"
34
+ "@funkai/prompts": "0.1.2"
35
35
  },
36
36
  "devDependencies": {
37
- "@kidd-cli/cli": "^0.2.0",
37
+ "@kidd-cli/cli": "^0.3.0",
38
38
  "@types/node": "^25.5.0",
39
39
  "@vitest/coverage-v8": "^4.1.0",
40
- "tsdown": "^0.21.2",
40
+ "tsdown": "^0.21.3",
41
41
  "typescript": "^5.9.3",
42
42
  "vitest": "^4.1.0"
43
43
  },
@@ -1,78 +1,20 @@
1
- import { mkdirSync, writeFileSync } from "node:fs";
2
- import { resolve } from "node:path";
3
-
4
1
  import { command } from "@kidd-cli/core";
5
- import { match } from "ts-pattern";
6
- import { z } from "zod";
7
2
 
8
- import { generatePromptModule, generateRegistry } from "@/lib/prompts/codegen.js";
9
- import { hasLintErrors } from "@/lib/prompts/lint.js";
10
- import { runGeneratePipeline } from "@/lib/prompts/pipeline.js";
3
+ import { generateArgs, handleGenerate } from "./prompts/generate.js";
11
4
 
12
5
  export default command({
13
6
  description: "Run all code generation across the funkai SDK",
14
- args: z.object({
15
- out: z.string().describe("Output directory for generated files"),
16
- roots: z.array(z.string()).describe("Root directories to scan for .prompt files"),
17
- partials: z.string().optional().describe("Custom partials directory"),
18
- silent: z.boolean().default(false).describe("Suppress output except errors"),
19
- }),
7
+ args: generateArgs,
20
8
  handler(ctx) {
21
- const { out, roots, partials, silent } = ctx.args;
9
+ const { silent } = ctx.args;
22
10
 
23
11
  // --- Prompts codegen ---
24
12
  if (!silent) {
25
13
  ctx.logger.info("Running prompts code generation...");
26
14
  }
27
15
 
28
- const { discovered, lintResults, prompts } = runGeneratePipeline({ roots, out, partials });
29
-
30
- if (!silent) {
31
- ctx.logger.info(`Found ${discovered} prompt(s)`);
32
- }
33
-
34
- for (const prompt of prompts) {
35
- if (!silent) {
36
- const varCount = prompt.schema.length;
37
- const varList = match(varCount > 0)
38
- .with(true, () => ` (${prompt.schema.map((v) => v.name).join(", ")})`)
39
- .otherwise(() => "");
40
- ctx.logger.step(`${prompt.name}${varList}`);
41
- }
42
- }
43
-
44
- for (const result of lintResults) {
45
- for (const diag of result.diagnostics) {
46
- if (diag.level === "error") {
47
- ctx.logger.error(diag.message);
48
- } else {
49
- ctx.logger.warn(diag.message);
50
- }
51
- }
52
- }
53
-
54
- if (hasLintErrors([...lintResults])) {
55
- ctx.fail("Lint errors found. Fix them before generating.");
56
- }
57
-
58
- const outDir = resolve(out);
59
- // oxlint-disable-next-line security/detect-non-literal-fs-filename -- safe: output directory from CLI config
60
- mkdirSync(outDir, { recursive: true });
61
-
62
- for (const prompt of prompts) {
63
- const content = generatePromptModule(prompt);
64
- // oxlint-disable-next-line security/detect-non-literal-fs-filename -- safe: writing generated module to output directory
65
- writeFileSync(resolve(outDir, `${prompt.name}.ts`), content, "utf-8");
66
- }
67
-
68
- const registryContent = generateRegistry([...prompts]);
69
- // oxlint-disable-next-line security/detect-non-literal-fs-filename -- safe: writing generated registry to output directory
70
- writeFileSync(resolve(outDir, "index.ts"), registryContent, "utf-8");
16
+ handleGenerate(ctx.args, ctx.logger, ctx.fail);
71
17
 
72
18
  // --- Future: agents codegen ---
73
-
74
- if (!silent) {
75
- ctx.logger.success(`Generated ${prompts.length} prompt module(s) + registry → ${outDir}`);
76
- }
77
19
  },
78
20
  });
@@ -2,70 +2,97 @@ import { mkdirSync, writeFileSync } from "node:fs";
2
2
  import { resolve } from "node:path";
3
3
 
4
4
  import { command } from "@kidd-cli/core";
5
- import { match } from "ts-pattern";
6
5
  import { z } from "zod";
7
6
 
8
7
  import { generatePromptModule, generateRegistry } from "@/lib/prompts/codegen.js";
9
8
  import { hasLintErrors } from "@/lib/prompts/lint.js";
10
9
  import { runGeneratePipeline } from "@/lib/prompts/pipeline.js";
11
10
 
12
- export default command({
13
- description: "Generate TypeScript modules from .prompt files",
14
- args: z.object({
15
- out: z.string().describe("Output directory for generated files"),
16
- roots: z.array(z.string()).describe("Root directories to scan for .prompt files"),
17
- partials: z.string().optional().describe("Custom partials directory"),
18
- silent: z.boolean().default(false).describe("Suppress output except errors"),
19
- }),
20
- handler(ctx) {
21
- const { out, roots, partials, silent } = ctx.args;
11
+ export const generateArgs = z.object({
12
+ out: z.string().describe("Output directory for generated files"),
13
+ roots: z.array(z.string()).describe("Root directories to scan for .prompt files"),
14
+ partials: z.string().optional().describe("Custom partials directory"),
15
+ silent: z.boolean().default(false).describe("Suppress output except errors"),
16
+ });
17
+
18
+ export type GenerateArgs = z.infer<typeof generateArgs>;
19
+
20
+ /**
21
+ * Shared handler for prompts code generation.
22
+ *
23
+ * @param args - Parsed CLI arguments.
24
+ * @param logger - Logger instance from the command context.
25
+ * @param fail - Failure callback from the command context.
26
+ */
27
+ export function handleGenerate(
28
+ args: {
29
+ readonly out: string;
30
+ readonly roots: readonly string[];
31
+ readonly partials?: string;
32
+ readonly silent: boolean;
33
+ },
34
+ logger: {
35
+ info: (msg: string) => void;
36
+ step: (msg: string) => void;
37
+ error: (msg: string) => void;
38
+ warn: (msg: string) => void;
39
+ success: (msg: string) => void;
40
+ },
41
+ fail: (msg: string) => never,
42
+ ): void {
43
+ const { out, roots, partials, silent } = args;
44
+
45
+ const { discovered, lintResults, prompts } = runGeneratePipeline({ roots, out, partials });
22
46
 
23
- const { discovered, lintResults, prompts } = runGeneratePipeline({ roots, out, partials });
47
+ if (!silent) {
48
+ logger.info(`Found ${discovered} prompt(s)`);
49
+ }
24
50
 
25
- if (!silent) {
26
- ctx.logger.info(`Found ${discovered} prompt(s)`);
51
+ if (!silent) {
52
+ for (const prompt of prompts) {
53
+ const varList =
54
+ prompt.schema.length > 0 ? ` (${prompt.schema.map((v) => v.name).join(", ")})` : "";
55
+ logger.step(`${prompt.name}${varList}`);
27
56
  }
57
+ }
28
58
 
29
- if (!silent) {
30
- prompts.forEach((prompt) => {
31
- const varCount = prompt.schema.length;
32
- const varList = match(varCount > 0)
33
- .with(true, () => ` (${prompt.schema.map((v) => v.name).join(", ")})`)
34
- .otherwise(() => "");
35
- ctx.logger.step(`${prompt.name}${varList}`);
36
- });
59
+ for (const result of lintResults) {
60
+ for (const diag of result.diagnostics) {
61
+ if (diag.level === "error") {
62
+ logger.error(diag.message);
63
+ } else {
64
+ logger.warn(diag.message);
65
+ }
37
66
  }
67
+ }
38
68
 
39
- lintResults
40
- .flatMap((result) => result.diagnostics)
41
- .forEach((diag) => {
42
- if (diag.level === "error") {
43
- ctx.logger.error(diag.message);
44
- } else {
45
- ctx.logger.warn(diag.message);
46
- }
47
- });
69
+ if (hasLintErrors(lintResults)) {
70
+ fail("Lint errors found. Fix them before generating.");
71
+ }
48
72
 
49
- if (hasLintErrors([...lintResults])) {
50
- ctx.fail("Lint errors found. Fix them before generating.");
51
- }
73
+ const outDir = resolve(out);
74
+ // oxlint-disable-next-line security/detect-non-literal-fs-filename -- safe: output directory from CLI config
75
+ mkdirSync(outDir, { recursive: true });
52
76
 
53
- const outDir = resolve(out);
54
- // oxlint-disable-next-line security/detect-non-literal-fs-filename -- safe: output directory from CLI config
55
- mkdirSync(outDir, { recursive: true });
77
+ for (const prompt of prompts) {
78
+ const content = generatePromptModule(prompt);
79
+ // oxlint-disable-next-line security/detect-non-literal-fs-filename -- safe: writing generated module to output directory
80
+ writeFileSync(resolve(outDir, `${prompt.name}.ts`), content, "utf-8");
81
+ }
56
82
 
57
- prompts.forEach((prompt) => {
58
- const content = generatePromptModule(prompt);
59
- // oxlint-disable-next-line security/detect-non-literal-fs-filename -- safe: writing generated module to output directory
60
- writeFileSync(resolve(outDir, `${prompt.name}.ts`), content, "utf-8");
61
- });
83
+ const registryContent = generateRegistry(prompts);
84
+ // oxlint-disable-next-line security/detect-non-literal-fs-filename -- safe: writing generated registry to output directory
85
+ writeFileSync(resolve(outDir, "index.ts"), registryContent, "utf-8");
62
86
 
63
- const registryContent = generateRegistry([...prompts]);
64
- // oxlint-disable-next-line security/detect-non-literal-fs-filename -- safe: writing generated registry to output directory
65
- writeFileSync(resolve(outDir, "index.ts"), registryContent, "utf-8");
87
+ if (!silent) {
88
+ logger.success(`Generated ${prompts.length} prompt module(s) + registry ${outDir}`);
89
+ }
90
+ }
66
91
 
67
- if (!silent) {
68
- ctx.logger.success(`Generated ${prompts.length} prompt module(s) + registry → ${outDir}`);
69
- }
92
+ export default command({
93
+ description: "Generate TypeScript modules from .prompt files",
94
+ args: generateArgs,
95
+ handler(ctx) {
96
+ handleGenerate(ctx.args, ctx.logger, ctx.fail);
70
97
  },
71
98
  });
@@ -1,57 +1,75 @@
1
1
  import { command } from "@kidd-cli/core";
2
- import { match } from "ts-pattern";
3
2
  import { z } from "zod";
4
3
 
5
4
  import { hasLintErrors } from "@/lib/prompts/lint.js";
6
5
  import { runLintPipeline } from "@/lib/prompts/pipeline.js";
7
6
 
8
- export default command({
9
- description: "Validate .prompt files for schema/template mismatches",
10
- args: z.object({
11
- roots: z.array(z.string()).describe("Root directories to scan for .prompt files"),
12
- partials: z.string().optional().describe("Custom partials directory"),
13
- silent: z.boolean().default(false).describe("Suppress output except errors"),
14
- }),
15
- handler(ctx) {
16
- const { roots, partials, silent } = ctx.args;
7
+ export const lintArgs = z.object({
8
+ roots: z.array(z.string()).describe("Root directories to scan for .prompt files"),
9
+ partials: z.string().optional().describe("Custom partials directory"),
10
+ silent: z.boolean().default(false).describe("Suppress output except errors"),
11
+ });
17
12
 
18
- const { discovered, results } = runLintPipeline({ roots, partials });
13
+ export type LintArgs = z.infer<typeof lintArgs>;
19
14
 
20
- if (!silent) {
21
- ctx.logger.info(`Linting ${discovered} prompt(s)...`);
22
- }
15
+ /**
16
+ * Shared handler for prompts lint/validation.
17
+ *
18
+ * @param args - Parsed CLI arguments.
19
+ * @param logger - Logger instance from the command context.
20
+ * @param fail - Failure callback from the command context.
21
+ */
22
+ export function handleLint(
23
+ args: { readonly roots: readonly string[]; readonly partials?: string; readonly silent: boolean },
24
+ logger: {
25
+ info: (msg: string) => void;
26
+ error: (msg: string) => void;
27
+ warn: (msg: string) => void;
28
+ },
29
+ fail: (msg: string) => never,
30
+ ): void {
31
+ const { roots, partials, silent } = args;
23
32
 
24
- const diagnostics = results.flatMap((result) => result.diagnostics);
25
-
26
- diagnostics.forEach((diag) => {
27
- if (diag.level === "error") {
28
- ctx.logger.error(diag.message);
29
- } else {
30
- ctx.logger.warn(diag.message);
31
- }
32
- });
33
-
34
- const errorCount = diagnostics.filter((d) => d.level === "error").length;
35
- const warnCount = diagnostics.filter((d) => d.level !== "error").length;
36
-
37
- if (!silent) {
38
- const summary = [
39
- `${discovered} prompt(s) linted`,
40
- match(errorCount > 0)
41
- .with(true, () => `${errorCount} error(s)`)
42
- .otherwise(() => undefined),
43
- match(warnCount > 0)
44
- .with(true, () => `${warnCount} warning(s)`)
45
- .otherwise(() => undefined),
46
- ]
47
- .filter(Boolean)
48
- .join(", ");
49
-
50
- ctx.logger.info(summary);
51
- }
33
+ const { discovered, results } = runLintPipeline({ roots, partials });
34
+
35
+ if (!silent) {
36
+ logger.info(`Linting ${discovered} prompt(s)...`);
37
+ }
38
+
39
+ const diagnostics = results.flatMap((result) => result.diagnostics);
52
40
 
53
- if (hasLintErrors([...results])) {
54
- ctx.fail("Lint errors found.");
41
+ for (const diag of diagnostics) {
42
+ if (diag.level === "error") {
43
+ logger.error(diag.message);
44
+ } else {
45
+ logger.warn(diag.message);
55
46
  }
47
+ }
48
+
49
+ const errorCount = diagnostics.filter((d) => d.level === "error").length;
50
+ const warnCount = diagnostics.filter((d) => d.level !== "error").length;
51
+
52
+ if (!silent) {
53
+ const summary = [
54
+ `${discovered} prompt(s) linted`,
55
+ errorCount > 0 ? `${errorCount} error(s)` : undefined,
56
+ warnCount > 0 ? `${warnCount} warning(s)` : undefined,
57
+ ]
58
+ .filter(Boolean)
59
+ .join(", ");
60
+
61
+ logger.info(summary);
62
+ }
63
+
64
+ if (hasLintErrors(results)) {
65
+ fail("Lint errors found.");
66
+ }
67
+ }
68
+
69
+ export default command({
70
+ description: "Validate .prompt files for schema/template mismatches",
71
+ args: lintArgs,
72
+ handler(ctx) {
73
+ handleLint(ctx.args, ctx.logger, ctx.fail);
56
74
  },
57
75
  });
@@ -2,7 +2,6 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { resolve } from "node:path";
3
3
 
4
4
  import { command } from "@kidd-cli/core";
5
- import { match } from "ts-pattern";
6
5
 
7
6
  const VSCODE_DIR = ".vscode";
8
7
  const SETTINGS_FILE = "settings.json";
@@ -76,14 +75,10 @@ export default command({
76
75
 
77
76
  if (shouldGitignore) {
78
77
  const gitignorePath = resolve(GITIGNORE_FILE);
79
- const existing = match(existsSync(gitignorePath))
80
- .with(true, () => readFileSync(gitignorePath, "utf-8"))
81
- .otherwise(() => "");
78
+ const existing = existsSync(gitignorePath) ? readFileSync(gitignorePath, "utf-8") : "";
82
79
 
83
80
  if (!existing.includes(GITIGNORE_ENTRY)) {
84
- const separator = match(existing.length > 0 && !existing.endsWith("\n"))
85
- .with(true, () => "\n")
86
- .otherwise(() => "");
81
+ const separator = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
87
82
  const block = `${separator}\n# Generated prompt client (created by \`funkai prompts generate\`)\n${GITIGNORE_ENTRY}\n`;
88
83
  writeFileSync(gitignorePath, existing + block, "utf-8");
89
84
  ctx.logger.success(`Added ${GITIGNORE_ENTRY} to ${gitignorePath}`);
@@ -1,45 +1,22 @@
1
1
  import { command } from "@kidd-cli/core";
2
- import { match } from "ts-pattern";
3
- import { z } from "zod";
4
2
 
5
- import { hasLintErrors } from "@/lib/prompts/lint.js";
6
- import { runLintPipeline } from "@/lib/prompts/pipeline.js";
3
+ import { handleLint, lintArgs } from "./prompts/lint.js";
7
4
 
8
5
  export default command({
9
6
  description: "Run all validations across the funkai SDK",
10
- args: z.object({
11
- roots: z.array(z.string()).describe("Root directories to scan for .prompt files"),
12
- partials: z.string().optional().describe("Custom partials directory"),
13
- silent: z.boolean().default(false).describe("Suppress output except errors"),
14
- }),
7
+ args: lintArgs,
15
8
  handler(ctx) {
16
- const { roots, partials, silent } = ctx.args;
9
+ const { silent } = ctx.args;
17
10
 
18
11
  // --- Prompts validation ---
19
12
  if (!silent) {
20
13
  ctx.logger.info("Running prompts validation...");
21
14
  }
22
15
 
23
- const { discovered, results } = runLintPipeline({ roots, partials });
24
-
25
- if (!silent) {
26
- ctx.logger.info(`Found ${discovered} prompt(s)`);
27
- }
28
-
29
- const diagnostics = results.flatMap((result) => result.diagnostics);
30
-
31
- for (const diag of diagnostics) {
32
- match(diag.level)
33
- .with("error", () => ctx.logger.error(diag.message))
34
- .otherwise(() => ctx.logger.warn(diag.message));
35
- }
16
+ handleLint(ctx.args, ctx.logger, ctx.fail);
36
17
 
37
18
  // --- Future: agents validation ---
38
19
 
39
- if (hasLintErrors([...results])) {
40
- ctx.fail("Validation errors found.");
41
- }
42
-
43
20
  if (!silent) {
44
21
  ctx.logger.success("All validations passed.");
45
22
  }
package/src/index.ts CHANGED
@@ -1,7 +1,12 @@
1
+ import { createRequire } from "node:module";
2
+
1
3
  import { cli } from "@kidd-cli/core";
2
4
 
5
+ const require = createRequire(import.meta.url);
6
+ const packageJson = require("../package.json") as { readonly version: string };
7
+
3
8
  await cli({
4
9
  description: "CLI for the funkai AI SDK framework",
5
10
  name: "funkai",
6
- version: "0.4.0",
11
+ version: packageJson.version,
7
12
  });
@@ -6,11 +6,11 @@ import type { SchemaVariable } from "./frontmatter.js";
6
6
  * Fully parsed prompt ready for code generation.
7
7
  */
8
8
  export interface ParsedPrompt {
9
- name: string;
10
- group?: string;
11
- schema: SchemaVariable[];
12
- template: string;
13
- sourcePath: string;
9
+ readonly name: string;
10
+ readonly group?: string;
11
+ readonly schema: readonly SchemaVariable[];
12
+ readonly template: string;
13
+ readonly sourcePath: string;
14
14
  }
15
15
 
16
16
  /**
@@ -57,7 +57,7 @@ function escapeTemplateLiteral(str: string): string {
57
57
  *
58
58
  * @private
59
59
  */
60
- function generateSchemaExpression(vars: SchemaVariable[]): string {
60
+ function generateSchemaExpression(vars: readonly SchemaVariable[]): string {
61
61
  if (vars.length === 0) {
62
62
  return "z.object({})";
63
63
  }
@@ -65,9 +65,7 @@ function generateSchemaExpression(vars: SchemaVariable[]): string {
65
65
  const fields = vars
66
66
  .map((v) => {
67
67
  const base = "z.string()";
68
- const expr = match(v.required)
69
- .with(true, () => base)
70
- .otherwise(() => `${base}.optional()`);
68
+ const expr = v.required ? base : `${base}.optional()`;
71
69
  return ` ${v.name}: ${expr},`;
72
70
  })
73
71
  .join("\n");
@@ -95,16 +93,14 @@ const HEADER = [
95
93
  export function generatePromptModule(prompt: ParsedPrompt): string {
96
94
  const escaped = escapeTemplateLiteral(prompt.template);
97
95
  const schemaExpr = generateSchemaExpression(prompt.schema);
98
- const groupValue = match(prompt.group != null)
99
- .with(true, () => `'${prompt.group}' as const`)
100
- .otherwise(() => "undefined");
96
+ const groupValue = prompt.group != null ? `'${prompt.group}' as const` : "undefined";
101
97
 
102
98
  const lines: string[] = [
103
99
  HEADER,
104
100
  `// Source: ${prompt.sourcePath}`,
105
101
  "",
106
102
  "import { z } from 'zod'",
107
- "import { engine } from '@funkai/prompts'",
103
+ "import { liquidEngine } from '@funkai/prompts'",
108
104
  "",
109
105
  `const schema = ${schemaExpr}`,
110
106
  "",
@@ -119,7 +115,7 @@ export function generatePromptModule(prompt: ParsedPrompt): string {
119
115
  ...match(prompt.schema.length)
120
116
  .with(0, () => [
121
117
  " render(variables?: undefined): string {",
122
- " return engine.parseAndRenderSync(template, {})",
118
+ " return liquidEngine.parseAndRenderSync(template, {})",
123
119
  " },",
124
120
  " validate(variables?: undefined): Variables {",
125
121
  " return schema.parse(variables ?? {})",
@@ -127,7 +123,7 @@ export function generatePromptModule(prompt: ParsedPrompt): string {
127
123
  ])
128
124
  .otherwise(() => [
129
125
  " render(variables: Variables): string {",
130
- " return engine.parseAndRenderSync(template, schema.parse(variables))",
126
+ " return liquidEngine.parseAndRenderSync(template, schema.parse(variables))",
131
127
  " },",
132
128
  " validate(variables: unknown): Variables {",
133
129
  " return schema.parse(variables)",
@@ -214,7 +210,7 @@ function serializeTree(node: TreeNode, indent: number): string[] {
214
210
  * Prompts are organized into a nested object structure based on their
215
211
  * `group` field, with each `/`-separated segment becoming a nesting level.
216
212
  */
217
- export function generateRegistry(prompts: ParsedPrompt[]): string {
213
+ export function generateRegistry(prompts: readonly ParsedPrompt[]): string {
218
214
  const sorted = [...prompts].toSorted((a, b) => a.name.localeCompare(b.name));
219
215
 
220
216
  const imports = sorted
@@ -1,5 +1,4 @@
1
1
  import { Liquid } from "liquidjs";
2
- import { match } from "ts-pattern";
3
2
 
4
3
  // oxlint-disable-next-line security/detect-unsafe-regex -- template parsing, not adversarial input
5
4
  const RENDER_TAG_RE = /\{%-?\s*render\s+'([^']+)'(?:\s*,\s*(.*?))?\s*-?%\}/g;
@@ -40,12 +39,8 @@ function parseParams(raw: string, partialName: string): Record<string, string> {
40
39
  */
41
40
  function parseRenderTags(template: string): RenderTag[] {
42
41
  return [...template.matchAll(RENDER_TAG_RE)].map((m) => {
43
- const rawParams = match(m[2] != null)
44
- .with(true, () => m[2].trim())
45
- .otherwise(() => "");
46
- const params = match(rawParams.length > 0)
47
- .with(true, () => parseParams(rawParams, m[1]))
48
- .otherwise(() => ({}));
42
+ const rawParams = m[2] != null ? m[2].trim() : "";
43
+ const params = rawParams.length > 0 ? parseParams(rawParams, m[1]) : {};
49
44
 
50
45
  return { fullMatch: m[0], partialName: m[1], params };
51
46
  });