@beignet/cli 0.0.40 → 0.0.42

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 (111) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +139 -17
  3. package/dist/analysis/source-index.d.ts +38 -0
  4. package/dist/analysis/source-index.d.ts.map +1 -0
  5. package/dist/analysis/source-index.js +271 -0
  6. package/dist/analysis/source-index.js.map +1 -0
  7. package/dist/analysis/workspace.d.ts +16 -0
  8. package/dist/analysis/workspace.d.ts.map +1 -0
  9. package/dist/analysis/workspace.js +134 -0
  10. package/dist/analysis/workspace.js.map +1 -0
  11. package/dist/app-map-schema.d.ts +5 -0
  12. package/dist/app-map-schema.d.ts.map +1 -0
  13. package/dist/app-map-schema.js +26 -0
  14. package/dist/app-map-schema.js.map +1 -0
  15. package/dist/app-map.d.ts +96 -0
  16. package/dist/app-map.d.ts.map +1 -0
  17. package/dist/app-map.js +1141 -0
  18. package/dist/app-map.js.map +1 -0
  19. package/dist/check.d.ts +7 -0
  20. package/dist/check.d.ts.map +1 -1
  21. package/dist/check.js +20 -5
  22. package/dist/check.js.map +1 -1
  23. package/dist/choices.d.ts +18 -0
  24. package/dist/choices.d.ts.map +1 -1
  25. package/dist/choices.js +35 -0
  26. package/dist/choices.js.map +1 -1
  27. package/dist/db.d.ts +49 -13
  28. package/dist/db.d.ts.map +1 -1
  29. package/dist/db.js +202 -21
  30. package/dist/db.js.map +1 -1
  31. package/dist/doctor-fixes.d.ts +64 -0
  32. package/dist/doctor-fixes.d.ts.map +1 -0
  33. package/dist/doctor-fixes.js +142 -0
  34. package/dist/doctor-fixes.js.map +1 -0
  35. package/dist/explain.d.ts +100 -0
  36. package/dist/explain.d.ts.map +1 -0
  37. package/dist/explain.js +606 -0
  38. package/dist/explain.js.map +1 -0
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +165 -21
  41. package/dist/index.js.map +1 -1
  42. package/dist/inspect.d.ts +33 -9
  43. package/dist/inspect.d.ts.map +1 -1
  44. package/dist/inspect.js +406 -119
  45. package/dist/inspect.js.map +1 -1
  46. package/dist/lib.d.ts +10 -2
  47. package/dist/lib.d.ts.map +1 -1
  48. package/dist/lib.js +5 -2
  49. package/dist/lib.js.map +1 -1
  50. package/dist/make/shared.js +3 -3
  51. package/dist/make/shared.js.map +1 -1
  52. package/dist/make.d.ts.map +1 -1
  53. package/dist/make.js +63 -2
  54. package/dist/make.js.map +1 -1
  55. package/dist/mcp.d.ts +1 -1
  56. package/dist/mcp.d.ts.map +1 -1
  57. package/dist/mcp.js +188 -12
  58. package/dist/mcp.js.map +1 -1
  59. package/dist/preflight.d.ts.map +1 -1
  60. package/dist/preflight.js +10 -0
  61. package/dist/preflight.js.map +1 -1
  62. package/dist/provider-add.d.ts.map +1 -1
  63. package/dist/provider-add.js +167 -13
  64. package/dist/provider-add.js.map +1 -1
  65. package/dist/provider-audit.d.ts +6 -0
  66. package/dist/provider-audit.d.ts.map +1 -1
  67. package/dist/provider-audit.js +63 -15
  68. package/dist/provider-audit.js.map +1 -1
  69. package/dist/templates/agents.d.ts.map +1 -1
  70. package/dist/templates/agents.js +35 -6
  71. package/dist/templates/agents.js.map +1 -1
  72. package/dist/templates/base.d.ts.map +1 -1
  73. package/dist/templates/base.js +13 -7
  74. package/dist/templates/base.js.map +1 -1
  75. package/dist/templates/index.d.ts +1 -1
  76. package/dist/templates/index.d.ts.map +1 -1
  77. package/dist/templates/index.js +8 -1
  78. package/dist/templates/index.js.map +1 -1
  79. package/dist/templates/server.d.ts +3 -0
  80. package/dist/templates/server.d.ts.map +1 -1
  81. package/dist/templates/server.js +55 -1
  82. package/dist/templates/server.js.map +1 -1
  83. package/dist/templates/shared.d.ts +2 -1
  84. package/dist/templates/shared.d.ts.map +1 -1
  85. package/dist/templates/shared.js +8 -5
  86. package/dist/templates/shared.js.map +1 -1
  87. package/package.json +3 -2
  88. package/skills/app-structure/SKILL.md +48 -6
  89. package/src/analysis/source-index.ts +395 -0
  90. package/src/analysis/workspace.ts +180 -0
  91. package/src/app-map-schema.ts +28 -0
  92. package/src/app-map.ts +1705 -0
  93. package/src/check.ts +27 -4
  94. package/src/choices.ts +57 -0
  95. package/src/db.ts +276 -28
  96. package/src/doctor-fixes.ts +252 -0
  97. package/src/explain.ts +894 -0
  98. package/src/index.ts +237 -31
  99. package/src/inspect.ts +567 -147
  100. package/src/lib.ts +64 -1
  101. package/src/make/shared.ts +3 -3
  102. package/src/make.ts +90 -2
  103. package/src/mcp.ts +292 -12
  104. package/src/preflight.ts +14 -0
  105. package/src/provider-add.ts +211 -12
  106. package/src/provider-audit.ts +127 -22
  107. package/src/templates/agents.ts +35 -6
  108. package/src/templates/base.ts +25 -6
  109. package/src/templates/index.ts +18 -1
  110. package/src/templates/server.ts +58 -1
  111. package/src/templates/shared.ts +15 -7
@@ -1,6 +1,7 @@
1
1
  import { databaseLocalUrl, databaseStartCommand } from "../choices.js";
2
2
  import { shadcnDependencies, shadcnDevDependencies } from "./shadcn.js";
3
3
  import {
4
+ currentGeneratedPackageScripts,
4
5
  externalVersions,
5
6
  hasStarterProvider,
6
7
  json,
@@ -97,11 +98,11 @@ export function packageJson(ctx: TemplateContext): string {
97
98
  start: "next start",
98
99
  lint: "biome lint .",
99
100
  format: "biome format --write .",
100
- test: "tsx lib/beignet-test-runner.ts",
101
+ test: currentGeneratedPackageScripts.test,
101
102
  typecheck: "tsc --noEmit",
102
103
  "db:generate": "drizzle-kit generate",
103
104
  "db:migrate": "drizzle-kit migrate",
104
- "db:reset": "tsx infra/db/reset.ts",
105
+ "db:reset": currentGeneratedPackageScripts["db:reset"],
105
106
  };
106
107
 
107
108
  return json({
@@ -268,11 +269,13 @@ ${firstOpen}
268
269
  \`\`\`bash
269
270
  # in another terminal
270
271
  ${cli} routes
272
+ ${cli} map
271
273
  ${cli} check
272
274
  \`\`\`
273
275
 
274
- \`routes\` shows the contracts Beignet can inspect. \`check\` runs the whole
275
- validation loop in one pass: \`${cli} lint\` (dependency direction),
276
+ \`routes\` shows the contracts Beignet can inspect. \`map\` shows how features,
277
+ use cases, workflows, ports, providers, and tests connect. \`check\` runs the
278
+ whole validation loop in one pass: \`${cli} lint\` (dependency direction),
276
279
  \`${cli} doctor --strict\` (route, OpenAPI, and resource drift), and the
277
280
  \`lint\`, \`typecheck\`, and \`test\` package scripts. Use \`${format}\` to
278
281
  apply Biome formatting.
@@ -306,6 +309,10 @@ Use \`${cli} make feature projects --recipe full-slice\` when you want a richer
306
309
 
307
310
  ## App map
308
311
 
312
+ Run \`${cli} map\` for the current architecture or \`${cli} map --json\` for
313
+ the versioned graph used by coding agents. Add \`--feature todos\` to focus on
314
+ one slice and its direct relationships.
315
+
309
316
  - \`features/todos/contracts.ts\` owns the HTTP contract and reuses shared feature schemas.
310
317
  - \`features/todos/schemas.ts\` owns shared DTO and validation schemas used by contracts, use cases, ports, tests, and clients.
311
318
  - \`features/todos/client/\` may own todos-specific data-fetching helpers and React Query hooks.
@@ -391,8 +398,10 @@ export function providersDoc(ctx: TemplateContext): string {
391
398
  "- Package: `@beignet/core` (`@beignet/core/events`, `@beignet/core/jobs`)",
392
399
  "- Package: `@beignet/provider-jobs-inngest`",
393
400
  "- Peer dependency: `inngest`",
394
- "- The starter wires `createInngestJobsProvider()` in `server/providers.ts`.",
401
+ "- The starter shares one Inngest client between `createInngestJobsProvider(...)` and `app/api/inngest/route.ts`.",
395
402
  "- Define jobs with `defineJob(...)` and dispatch them through `ctx.ports.jobs.dispatch(...)`.",
403
+ "- `beignet make job` registers feature job collections in `server/inngest.ts`.",
404
+ "- Use `INNGEST_DEV=1` only locally; production needs `INNGEST_EVENT_KEY` and `INNGEST_SIGNING_KEY`.",
396
405
  "- Use `ctx.ports.inngest` only as an escape hatch for Inngest-specific workflow APIs; prefer `ctx.ports.jobs.dispatch(...)` for Beignet jobs.",
397
406
  "",
398
407
  );
@@ -471,7 +480,17 @@ export function envExample(ctx: TemplateContext): string {
471
480
  ];
472
481
 
473
482
  if (hasStarterProvider(ctx, "jobs-inngest")) {
474
- lines.push("INNGEST_APP_NAME=beignet-app", "# INNGEST_EVENT_KEY=", "");
483
+ lines.push(
484
+ "# Local development connects the app to the Inngest dev server.",
485
+ "INNGEST_APP_NAME=beignet-app",
486
+ "INNGEST_DEV=1",
487
+ "# Production cloud dispatch and endpoint verification.",
488
+ "# INNGEST_EVENT_KEY=",
489
+ "# INNGEST_SIGNING_KEY=",
490
+ "# Optional signing-key rotation fallback.",
491
+ "# INNGEST_SIGNING_KEY_FALLBACK=",
492
+ "",
493
+ );
475
494
  }
476
495
 
477
496
  if (hasStarterProvider(ctx, "mail-resend")) {
@@ -19,6 +19,8 @@ import { dbFiles } from "./db/index.js";
19
19
  import {
20
20
  betterAuth,
21
21
  env,
22
+ inngestClient,
23
+ inngestRegistry,
22
24
  ports,
23
25
  portWiring,
24
26
  server,
@@ -26,7 +28,11 @@ import {
26
28
  serverProviders,
27
29
  } from "./server.js";
28
30
  import { shadcnTemplateFiles } from "./shadcn.js";
29
- import type { TemplateContext, TemplateFile } from "./shared.js";
31
+ import {
32
+ hasStarterProvider,
33
+ type TemplateContext,
34
+ type TemplateFile,
35
+ } from "./shared.js";
30
36
  import { shellTemplateFiles } from "./shell.js";
31
37
  import { testSupportTemplateFiles } from "./testing.js";
32
38
  import { todosFiles } from "./todos.js";
@@ -144,6 +150,17 @@ export function getTemplateFiles(ctx: TemplateContext): TemplateFile[] {
144
150
  { path: "server/providers.ts", content: serverProviders(ctx) },
145
151
  ];
146
152
 
153
+ if (hasStarterProvider(ctx, "jobs-inngest")) {
154
+ templateFiles.push(
155
+ { path: "infra/inngest.ts", content: inngestClient() },
156
+ { path: "server/inngest.ts", content: inngestRegistry() },
157
+ {
158
+ path: "app/api/inngest/route.ts",
159
+ content: serverFiles.inngestRoute,
160
+ },
161
+ );
162
+ }
163
+
147
164
  if (ctx.api) {
148
165
  templateFiles.push(
149
166
  { path: "app/layout.tsx", content: serverFiles.apiLayout },
@@ -24,6 +24,9 @@ export function serverProviders(ctx: TemplateContext): string {
24
24
  : undefined,
25
25
  'import * as schema from "@/infra/db/schema";',
26
26
  'import { databaseClient } from "@/infra/db/client";',
27
+ hasStarterProvider(ctx, "jobs-inngest")
28
+ ? 'import { inngest } from "@/infra/inngest";'
29
+ : undefined,
27
30
  'import { starterDatabaseProvider } from "@/infra/db/provider";',
28
31
  'import { auth } from "@/lib/better-auth";',
29
32
  'import type { AuthSessionMetadata, AuthUser } from "@/ports/auth";',
@@ -36,7 +39,7 @@ export function serverProviders(ctx: TemplateContext): string {
36
39
  `\t${db.providerInstance},`,
37
40
  "\tstarterDatabaseProvider,",
38
41
  hasStarterProvider(ctx, "jobs-inngest")
39
- ? "\tcreateInngestJobsProvider(),"
42
+ ? "\tcreateInngestJobsProvider({ client: inngest }),"
40
43
  : undefined,
41
44
  hasStarterProvider(ctx, "mail-resend")
42
45
  ? "\tcreateResendMailProvider(),"
@@ -162,6 +165,14 @@ export function env(ctx: TemplateContext): string {
162
165
  \t\t\t.default("${databaseLocalUrl(ctx.database, ctx.name)}"),
163
166
  \t\t${ctx.database === "postgres" ? "POSTGRES" : "MYSQL"}_DB_POOL_MAX: z.coerce.number().int().positive().default(5),`;
164
167
 
168
+ const inngestEnvLines = hasStarterProvider(ctx, "jobs-inngest")
169
+ ? `\t\tINNGEST_APP_NAME: z.string().min(1).default("beignet-app"),
170
+ \t\tINNGEST_DEV: z.enum(["0", "1"]).optional(),
171
+ \t\tINNGEST_EVENT_KEY: z.string().min(1).optional(),
172
+ \t\tINNGEST_SIGNING_KEY: z.string().min(1).optional(),
173
+ \t\tINNGEST_SIGNING_KEY_FALLBACK: z.string().min(1).optional(),`
174
+ : "";
175
+
165
176
  return `import { createEnv } from "@beignet/core/config";
166
177
  import { z } from "zod";
167
178
 
@@ -198,6 +209,7 @@ ${databaseEnvLines}
198
209
  .default("info"),
199
210
  LOG_FORMAT: z.enum(["pretty", "json"]).default("json"),
200
211
  LOG_SERVICE: z.string().default("beignet-app"),
212
+ ${inngestEnvLines}
201
213
  },
202
214
  runtimeEnv: process.env,
203
215
  });
@@ -209,6 +221,42 @@ export const isDevtoolsEnabled =
209
221
  `;
210
222
  }
211
223
 
224
+ export function inngestClient(): string {
225
+ return `import { Inngest } from "inngest";
226
+ import { env } from "@/lib/env";
227
+
228
+ /** Shared by the Beignet jobs provider and the Inngest serve endpoint. */
229
+ export const inngest = new Inngest({
230
+ id: env.INNGEST_APP_NAME,
231
+ });
232
+ `;
233
+ }
234
+
235
+ export function inngestRegistry(): string {
236
+ return `import { createServiceActor } from "@beignet/core/ports";
237
+ import { createInngestJobFunctions } from "@beignet/provider-jobs-inngest";
238
+ import type { AppContext } from "@/app-context";
239
+ import { inngest } from "@/infra/inngest";
240
+ import { getServer } from "@/server";
241
+
242
+ /** Central registry updated by \`beignet make job\`. */
243
+ export const inngestJobs = [] as const;
244
+
245
+ export const inngestFunctions = createInngestJobFunctions<AppContext>({
246
+ client: inngest,
247
+ jobs: inngestJobs,
248
+ ctx: async () => {
249
+ const server = await getServer();
250
+ return server.createServiceContext({
251
+ actor: createServiceActor("beignet-inngest"),
252
+ });
253
+ },
254
+ instrumentation: async () => (await getServer()).ports,
255
+ errorReporter: async () => (await getServer()).ports.errorReporter,
256
+ });
257
+ `;
258
+ }
259
+
212
260
  export function betterAuth(ctx: TemplateContext): string {
213
261
  const connectionByDatabase = {
214
262
  sqlite: `import { betterAuth } from "better-auth";
@@ -672,6 +720,15 @@ export function GET(request: Request): Promise<Response> {
672
720
  export function POST(request: Request): Promise<Response> {
673
721
  return handleAuthRoute("POST", request);
674
722
  }
723
+ `,
724
+ inngestRoute: `import { serve } from "inngest/next";
725
+ import { inngest } from "@/infra/inngest";
726
+ import { inngestFunctions } from "@/server/inngest";
727
+
728
+ export const { GET, POST, PUT } = serve({
729
+ client: inngest,
730
+ functions: inngestFunctions,
731
+ });
675
732
  `,
676
733
  // API-only scaffold frontend: a minimal layout and landing page that point
677
734
  // at the contract-backed API surface, plus a typed client without React
@@ -48,7 +48,7 @@ export const externalVersions = {
48
48
  bullmq: "^5.0.0",
49
49
  drizzleKit: "^0.31.10",
50
50
  drizzleOrm: "^0.45.2",
51
- inngest: "^3.54.0",
51
+ inngest: "^4.12.1",
52
52
  libsqlClient: "^0.14.0",
53
53
  vercelBlob: "^2.5.0",
54
54
  mysql2: "^3.12.0",
@@ -67,18 +67,26 @@ export const externalVersions = {
67
67
  upstashRedis: "^1.0.0",
68
68
  };
69
69
 
70
- export const legacyGeneratedPackageScripts: Record<string, string> = {
71
- "db:reset": "bun infra/db/reset.ts",
72
- "db:seed": "bun server/seed.ts",
73
- test: "bun test",
74
- };
70
+ export const legacyGeneratedPackageScripts: Record<string, readonly string[]> =
71
+ {
72
+ "db:reset": ["bun infra/db/reset.ts"],
73
+ "db:seed": ["bun server/seed.ts"],
74
+ test: ["bun test", "tsx lib/beignet-test-runner.ts"],
75
+ };
75
76
 
76
77
  export const currentGeneratedPackageScripts: Record<string, string> = {
77
78
  "db:reset": "tsx infra/db/reset.ts",
78
79
  "db:seed": "tsx server/seed.ts",
79
- test: "tsx lib/beignet-test-runner.ts",
80
+ test: "node --import tsx lib/beignet-test-runner.ts",
80
81
  };
81
82
 
83
+ export function isLegacyGeneratedPackageScript(
84
+ name: string,
85
+ command: string | undefined,
86
+ ): boolean {
87
+ return legacyGeneratedPackageScripts[name]?.includes(command ?? "") ?? false;
88
+ }
89
+
82
90
  /**
83
91
  * Dialect-specific names used when rendering database-aware templates.
84
92
  */