@beignet/cli 0.0.50 → 0.0.52

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 (105) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +64 -22
  3. package/dist/analysis/layers.d.ts.map +1 -1
  4. package/dist/analysis/layers.js +4 -2
  5. package/dist/analysis/layers.js.map +1 -1
  6. package/dist/analysis/port-wiring.d.ts.map +1 -1
  7. package/dist/analysis/port-wiring.js +2 -1
  8. package/dist/analysis/port-wiring.js.map +1 -1
  9. package/dist/analysis/source-files.d.ts +15 -0
  10. package/dist/analysis/source-files.d.ts.map +1 -0
  11. package/dist/analysis/source-files.js +52 -0
  12. package/dist/analysis/source-files.js.map +1 -0
  13. package/dist/analysis/workspace.d.ts.map +1 -1
  14. package/dist/analysis/workspace.js +21 -25
  15. package/dist/analysis/workspace.js.map +1 -1
  16. package/dist/app-map-changes.d.ts.map +1 -1
  17. package/dist/app-map-changes.js +5 -7
  18. package/dist/app-map-changes.js.map +1 -1
  19. package/dist/app-map.d.ts.map +1 -1
  20. package/dist/app-map.js +33 -30
  21. package/dist/app-map.js.map +1 -1
  22. package/dist/check.d.ts +12 -0
  23. package/dist/check.d.ts.map +1 -1
  24. package/dist/check.js +92 -25
  25. package/dist/check.js.map +1 -1
  26. package/dist/git-changes.d.ts +17 -1
  27. package/dist/git-changes.d.ts.map +1 -1
  28. package/dist/git-changes.js +118 -84
  29. package/dist/git-changes.js.map +1 -1
  30. package/dist/index.d.ts +2 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +35 -6
  33. package/dist/index.js.map +1 -1
  34. package/dist/inspect.d.ts.map +1 -1
  35. package/dist/inspect.js +436 -112
  36. package/dist/inspect.js.map +1 -1
  37. package/dist/lint.d.ts.map +1 -1
  38. package/dist/lint.js +3 -6
  39. package/dist/lint.js.map +1 -1
  40. package/dist/make.d.ts.map +1 -1
  41. package/dist/make.js +0 -2
  42. package/dist/make.js.map +1 -1
  43. package/dist/mcp.d.ts.map +1 -1
  44. package/dist/mcp.js +23 -5
  45. package/dist/mcp.js.map +1 -1
  46. package/dist/operational-process.d.ts +1 -0
  47. package/dist/operational-process.d.ts.map +1 -1
  48. package/dist/operational-process.js.map +1 -1
  49. package/dist/operational-runner.js +1 -0
  50. package/dist/operational-runner.js.map +1 -1
  51. package/dist/outbox.d.ts +1 -0
  52. package/dist/outbox.d.ts.map +1 -1
  53. package/dist/outbox.js +58 -12
  54. package/dist/outbox.js.map +1 -1
  55. package/dist/templates/agents.d.ts.map +1 -1
  56. package/dist/templates/agents.js +43 -15
  57. package/dist/templates/agents.js.map +1 -1
  58. package/dist/templates/base.js +5 -5
  59. package/dist/templates/db/mysql.d.ts.map +1 -1
  60. package/dist/templates/db/mysql.js +51 -22
  61. package/dist/templates/db/mysql.js.map +1 -1
  62. package/dist/templates/db/postgres.d.ts.map +1 -1
  63. package/dist/templates/db/postgres.js +60 -20
  64. package/dist/templates/db/postgres.js.map +1 -1
  65. package/dist/templates/db/sqlite.d.ts.map +1 -1
  66. package/dist/templates/db/sqlite.js +51 -23
  67. package/dist/templates/db/sqlite.js.map +1 -1
  68. package/dist/templates/shadcn.js +1 -1
  69. package/dist/templates/shadcn.js.map +1 -1
  70. package/dist/templates/shared.js +4 -4
  71. package/dist/templates/shared.js.map +1 -1
  72. package/dist/templates/testing.d.ts.map +1 -1
  73. package/dist/templates/testing.js +7 -19
  74. package/dist/templates/testing.js.map +1 -1
  75. package/dist/test-discovery.d.ts +9 -0
  76. package/dist/test-discovery.d.ts.map +1 -0
  77. package/dist/test-discovery.js +40 -0
  78. package/dist/test-discovery.js.map +1 -0
  79. package/package.json +7 -5
  80. package/skills/app-structure/SKILL.md +37 -10
  81. package/src/analysis/layers.ts +4 -2
  82. package/src/analysis/port-wiring.ts +2 -1
  83. package/src/analysis/source-files.ts +61 -0
  84. package/src/analysis/workspace.ts +27 -31
  85. package/src/app-map-changes.ts +10 -8
  86. package/src/app-map.ts +43 -32
  87. package/src/check.ts +115 -25
  88. package/src/git-changes.ts +218 -86
  89. package/src/index.ts +53 -8
  90. package/src/inspect.ts +627 -146
  91. package/src/lint.ts +6 -5
  92. package/src/make.ts +0 -2
  93. package/src/mcp.ts +34 -11
  94. package/src/operational-process.ts +1 -0
  95. package/src/operational-runner.ts +1 -0
  96. package/src/outbox.ts +63 -12
  97. package/src/templates/agents.ts +43 -15
  98. package/src/templates/base.ts +5 -5
  99. package/src/templates/db/mysql.ts +51 -22
  100. package/src/templates/db/postgres.ts +60 -20
  101. package/src/templates/db/sqlite.ts +51 -23
  102. package/src/templates/shadcn.ts +1 -1
  103. package/src/templates/shared.ts +4 -4
  104. package/src/templates/testing.ts +12 -19
  105. package/src/test-discovery.ts +53 -0
@@ -15,7 +15,7 @@
15
15
  // lives outside the app schema, so `db generate` never diffs against it.
16
16
  //
17
17
  // The Better Auth tables were generated with
18
- // `bunx @better-auth/cli generate` against a scratch app configured with
18
+ // `bunx auth generate` against a scratch app configured with
19
19
  // drizzleAdapter(db, { provider: "pg" }), then normalized to the starter's
20
20
  // conventions (tabs, no relations, no extra indexes, no column defaults).
21
21
 
@@ -51,7 +51,7 @@ export function closeDatabaseClient(): Promise<void> {
51
51
  return closePromise;
52
52
  }
53
53
  `,
54
- dbSchema: `import { boolean, index, pgTable, text, timestamp } from "drizzle-orm/pg-core";
54
+ dbSchema: `import { boolean, index, pgTable, text, timestamp, uniqueIndex } from "drizzle-orm/pg-core";
55
55
 
56
56
  export const user = pgTable("user", {
57
57
  id: text("id").primaryKey(),
@@ -76,23 +76,33 @@ export const session = pgTable("session", {
76
76
  .references(() => user.id, { onDelete: "cascade" }),
77
77
  });
78
78
 
79
- export const account = pgTable("account", {
80
- id: text("id").primaryKey(),
81
- accountId: text("account_id").notNull(),
82
- providerId: text("provider_id").notNull(),
83
- userId: text("user_id")
84
- .notNull()
85
- .references(() => user.id, { onDelete: "cascade" }),
86
- accessToken: text("access_token"),
87
- refreshToken: text("refresh_token"),
88
- idToken: text("id_token"),
89
- accessTokenExpiresAt: timestamp("access_token_expires_at"),
90
- refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
91
- scope: text("scope"),
92
- password: text("password"),
93
- createdAt: timestamp("created_at").notNull(),
94
- updatedAt: timestamp("updated_at").notNull(),
95
- });
79
+ export const account = pgTable(
80
+ "account",
81
+ {
82
+ id: text("id").primaryKey(),
83
+ issuer: text("issuer").notNull(),
84
+ accountId: text("account_id").notNull(),
85
+ providerId: text("provider_id").notNull(),
86
+ userId: text("user_id")
87
+ .notNull()
88
+ .references(() => user.id, { onDelete: "cascade" }),
89
+ accessToken: text("access_token"),
90
+ refreshToken: text("refresh_token"),
91
+ idToken: text("id_token"),
92
+ accessTokenExpiresAt: timestamp("access_token_expires_at"),
93
+ refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
94
+ scope: text("scope"),
95
+ password: text("password"),
96
+ createdAt: timestamp("created_at").notNull(),
97
+ updatedAt: timestamp("updated_at").notNull(),
98
+ },
99
+ (table) => [
100
+ uniqueIndex("account_issuer_accountId_uidx").on(
101
+ table.issuer,
102
+ table.accountId,
103
+ ),
104
+ ],
105
+ );
96
106
 
97
107
  export const verification = pgTable("verification", {
98
108
  id: text("id").primaryKey(),
@@ -413,6 +423,7 @@ const postgresStarterMigration = {
413
423
  // above, with the provider idempotency setup statements appended.
414
424
  starterMigrationSql: `CREATE TABLE "account" (
415
425
  "id" text PRIMARY KEY NOT NULL,
426
+ "issuer" text NOT NULL,
416
427
  "account_id" text NOT NULL,
417
428
  "provider_id" text NOT NULL,
418
429
  "user_id" text NOT NULL,
@@ -470,6 +481,7 @@ CREATE TABLE "verification" (
470
481
  ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
471
482
  ALTER TABLE "session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
472
483
  ALTER TABLE "todos" ADD CONSTRAINT "todos_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
484
+ CREATE UNIQUE INDEX "account_issuer_accountId_uidx" ON "account" USING btree ("issuer","account_id");--> statement-breakpoint
473
485
  CREATE INDEX "todos_user_idx" ON "todos" USING btree ("user_id","created_at");
474
486
  --> statement-breakpoint
475
487
  CREATE TABLE IF NOT EXISTS "idempotency_records" (
@@ -517,6 +529,12 @@ CREATE INDEX IF NOT EXISTS "idempotency_records_expires_idx" ON "idempotency_rec
517
529
  "primaryKey": true,
518
530
  "notNull": true
519
531
  },
532
+ "issuer": {
533
+ "name": "issuer",
534
+ "type": "text",
535
+ "primaryKey": false,
536
+ "notNull": true
537
+ },
520
538
  "account_id": {
521
539
  "name": "account_id",
522
540
  "type": "text",
@@ -590,7 +608,29 @@ CREATE INDEX IF NOT EXISTS "idempotency_records_expires_idx" ON "idempotency_rec
590
608
  "notNull": true
591
609
  }
592
610
  },
593
- "indexes": {},
611
+ "indexes": {
612
+ "account_issuer_accountId_uidx": {
613
+ "name": "account_issuer_accountId_uidx",
614
+ "columns": [
615
+ {
616
+ "expression": "issuer",
617
+ "isExpression": false,
618
+ "asc": true,
619
+ "nulls": "last"
620
+ },
621
+ {
622
+ "expression": "account_id",
623
+ "isExpression": false,
624
+ "asc": true,
625
+ "nulls": "last"
626
+ }
627
+ ],
628
+ "isUnique": true,
629
+ "concurrently": false,
630
+ "method": "btree",
631
+ "with": {}
632
+ }
633
+ },
594
634
  "foreignKeys": {
595
635
  "account_user_id_user_id_fk": {
596
636
  "name": "account_user_id_user_id_fk",
@@ -42,7 +42,7 @@ export function closeDatabaseClient(): Promise<void> {
42
42
  return closePromise;
43
43
  }
44
44
  `,
45
- dbSchema: `import { index, integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
45
+ dbSchema: `import { index, integer, sqliteTable, text, uniqueIndex } from "drizzle-orm/sqlite-core";
46
46
 
47
47
  export const user = sqliteTable("user", {
48
48
  id: text("id").primaryKey(),
@@ -69,27 +69,37 @@ export const session = sqliteTable("session", {
69
69
  .references(() => user.id, { onDelete: "cascade" }),
70
70
  });
71
71
 
72
- export const account = sqliteTable("account", {
73
- id: text("id").primaryKey(),
74
- accountId: text("account_id").notNull(),
75
- providerId: text("provider_id").notNull(),
76
- userId: text("user_id")
77
- .notNull()
78
- .references(() => user.id, { onDelete: "cascade" }),
79
- accessToken: text("access_token"),
80
- refreshToken: text("refresh_token"),
81
- idToken: text("id_token"),
82
- accessTokenExpiresAt: integer("access_token_expires_at", {
83
- mode: "timestamp",
84
- }),
85
- refreshTokenExpiresAt: integer("refresh_token_expires_at", {
86
- mode: "timestamp",
87
- }),
88
- scope: text("scope"),
89
- password: text("password"),
90
- createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
91
- updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
92
- });
72
+ export const account = sqliteTable(
73
+ "account",
74
+ {
75
+ id: text("id").primaryKey(),
76
+ issuer: text("issuer").notNull(),
77
+ accountId: text("account_id").notNull(),
78
+ providerId: text("provider_id").notNull(),
79
+ userId: text("user_id")
80
+ .notNull()
81
+ .references(() => user.id, { onDelete: "cascade" }),
82
+ accessToken: text("access_token"),
83
+ refreshToken: text("refresh_token"),
84
+ idToken: text("id_token"),
85
+ accessTokenExpiresAt: integer("access_token_expires_at", {
86
+ mode: "timestamp",
87
+ }),
88
+ refreshTokenExpiresAt: integer("refresh_token_expires_at", {
89
+ mode: "timestamp",
90
+ }),
91
+ scope: text("scope"),
92
+ password: text("password"),
93
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
94
+ updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
95
+ },
96
+ (table) => [
97
+ uniqueIndex("account_issuer_accountId_uidx").on(
98
+ table.issuer,
99
+ table.accountId,
100
+ ),
101
+ ],
102
+ );
93
103
 
94
104
  export const verification = sqliteTable("verification", {
95
105
  id: text("id").primaryKey(),
@@ -452,6 +462,7 @@ export async function createTestDatabase(): Promise<TestDatabase> {
452
462
  // above, with the provider idempotency setup statements appended.
453
463
  starterMigrationSql: `CREATE TABLE \`account\` (
454
464
  \`id\` text PRIMARY KEY NOT NULL,
465
+ \`issuer\` text NOT NULL,
455
466
  \`account_id\` text NOT NULL,
456
467
  \`provider_id\` text NOT NULL,
457
468
  \`user_id\` text NOT NULL,
@@ -467,6 +478,7 @@ export async function createTestDatabase(): Promise<TestDatabase> {
467
478
  FOREIGN KEY (\`user_id\`) REFERENCES \`user\`(\`id\`) ON UPDATE no action ON DELETE cascade
468
479
  );
469
480
  --> statement-breakpoint
481
+ CREATE UNIQUE INDEX \`account_issuer_accountId_uidx\` ON \`account\` (\`issuer\`,\`account_id\`);--> statement-breakpoint
470
482
  CREATE TABLE \`session\` (
471
483
  \`id\` text PRIMARY KEY NOT NULL,
472
484
  \`expires_at\` integer NOT NULL,
@@ -555,6 +567,13 @@ CREATE INDEX IF NOT EXISTS "idempotency_records_expires_idx" ON "idempotency_rec
555
567
  "notNull": true,
556
568
  "autoincrement": false
557
569
  },
570
+ "issuer": {
571
+ "name": "issuer",
572
+ "type": "text",
573
+ "primaryKey": false,
574
+ "notNull": true,
575
+ "autoincrement": false
576
+ },
558
577
  "account_id": {
559
578
  "name": "account_id",
560
579
  "type": "text",
@@ -640,7 +659,16 @@ CREATE INDEX IF NOT EXISTS "idempotency_records_expires_idx" ON "idempotency_rec
640
659
  "autoincrement": false
641
660
  }
642
661
  },
643
- "indexes": {},
662
+ "indexes": {
663
+ "account_issuer_accountId_uidx": {
664
+ "name": "account_issuer_accountId_uidx",
665
+ "columns": [
666
+ "issuer",
667
+ "account_id"
668
+ ],
669
+ "isUnique": true
670
+ }
671
+ },
644
672
  "foreignKeys": {
645
673
  "account_user_id_user_id_fk": {
646
674
  "name": "account_user_id_user_id_fk",
@@ -561,7 +561,7 @@ export const shadcnDependencies: Record<string, string> = {
561
561
  clsx: "^2.1.1",
562
562
  "lucide-react": "^1.16.0",
563
563
  "radix-ui": "^1.4.3",
564
- shadcn: "^4.7.0",
564
+ shadcn: "^4.19.0",
565
565
  "tailwind-merge": "^3.6.0",
566
566
  "tw-animate-css": "^1.4.0",
567
567
  };
@@ -32,7 +32,7 @@ export type TemplateContext = {
32
32
 
33
33
  export const externalVersions = {
34
34
  biome: "^2.4.14",
35
- next: "^16.2.10",
35
+ next: "^16.3.2",
36
36
  react: "^19.2.5",
37
37
  reactDom: "^19.2.5",
38
38
  tsx: "^4.22.4",
@@ -44,13 +44,13 @@ export const externalVersions = {
44
44
  tanstackReactQuery: "^5.100.7",
45
45
  hookformResolvers: "^5.0.0",
46
46
  reactHookForm: "^7.74.0",
47
- betterAuth: "1.6.25",
47
+ betterAuth: "1.7.1",
48
48
  bullmq: "^5.0.0",
49
49
  drizzleKit: "^0.31.10",
50
50
  drizzleOrm: "^0.45.2",
51
- inngest: "^4.12.1",
51
+ inngest: "^4.18.1",
52
52
  libsqlClient: "^0.14.0",
53
- vercelBlob: "^2.5.0",
53
+ vercelBlob: "^2.8.0",
54
54
  mysql2: "^3.12.0",
55
55
  pg: "^8.13.0",
56
56
  pglite: "^0.5.2",
@@ -1,3 +1,9 @@
1
+ import {
2
+ appTestFilePattern,
3
+ configuredTestDirectoryPathKeys,
4
+ configuredTestFilePathKeys,
5
+ defaultAppTestRoots,
6
+ } from "../test-discovery.js";
1
7
  import type { TemplateFile } from "./shared.js";
2
8
 
3
9
  export const testHelperTemplateFile: TemplateFile = {
@@ -408,16 +414,9 @@ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
408
414
  import path from "node:path";
409
415
  import { pathToFileURL } from "node:url";
410
416
 
411
- const defaultTestRoots = [
412
- "app",
413
- "features",
414
- "infra",
415
- "lib",
416
- "ports",
417
- "server",
418
- "tests",
419
- "src/tests",
420
- ];
417
+ const defaultTestRoots = ${JSON.stringify(defaultAppTestRoots, null, 2)};
418
+ const configuredTestDirectoryPathKeys = ${JSON.stringify(configuredTestDirectoryPathKeys)};
419
+ const configuredTestFilePathKeys = ${JSON.stringify(configuredTestFilePathKeys)};
421
420
  const ignoredDirectories = new Set([
422
421
  ".beignet-local",
423
422
  ".git",
@@ -427,7 +426,7 @@ const ignoredDirectories = new Set([
427
426
  "dist",
428
427
  "node_modules",
429
428
  ]);
430
- const testFilePattern = /\\.(test|spec)\\.[cm]?[tj]sx?$/;
429
+ const testFilePattern = /${appTestFilePattern.source}/;
431
430
 
432
431
  const configFileNames = [
433
432
  "beignet.config.ts",
@@ -532,14 +531,8 @@ async function configuredRoots(cwd: string): Promise<string[]> {
532
531
  }
533
532
  const paths = isObjectRecord(config.paths) ? config.paths : {};
534
533
  return [
535
- paths.tests,
536
- paths.features,
537
- parentPath(paths.routes),
538
- parentPath(paths.server),
539
- parentPath(paths.portWiring),
540
- parentPath(paths.ports),
541
- parentPath(paths.useCaseBuilder),
542
- parentPath(paths.routesBuilder),
534
+ ...configuredTestDirectoryPathKeys.map((key) => paths[key]),
535
+ ...configuredTestFilePathKeys.map((key) => parentPath(paths[key])),
543
536
  ].filter((root): root is string => Boolean(root) && root !== ".");
544
537
  }
545
538
 
@@ -0,0 +1,53 @@
1
+ import path from "node:path";
2
+ import { type BeignetPaths, directoryPath } from "./config.js";
3
+
4
+ export const defaultAppTestRoots = [
5
+ "app",
6
+ "features",
7
+ "infra",
8
+ "lib",
9
+ "ports",
10
+ "server",
11
+ "tests",
12
+ "src/tests",
13
+ ] as const;
14
+
15
+ export const configuredTestDirectoryPathKeys = [
16
+ "tests",
17
+ "features",
18
+ ] as const satisfies readonly (keyof BeignetPaths)[];
19
+
20
+ export const configuredTestFilePathKeys = [
21
+ "routes",
22
+ "server",
23
+ "portWiring",
24
+ "ports",
25
+ "useCaseBuilder",
26
+ "routesBuilder",
27
+ ] as const satisfies readonly (keyof BeignetPaths)[];
28
+
29
+ export const appTestFilePattern = /\.(test|spec)\.[cm]?[jt]sx?$/;
30
+
31
+ export function appTestRoots(paths: BeignetPaths): string[] {
32
+ const roots = [
33
+ ...defaultAppTestRoots,
34
+ ...configuredTestDirectoryPathKeys.map((key) => paths[key]),
35
+ ...configuredTestFilePathKeys.map((key) =>
36
+ directoryPath(path.posix.dirname(paths[key])),
37
+ ),
38
+ ];
39
+ return Array.from(
40
+ new Set(roots.map(directoryPath).filter((root) => root && root !== ".")),
41
+ );
42
+ }
43
+
44
+ export function isAppTestFile(file: string): boolean {
45
+ return appTestFilePattern.test(file);
46
+ }
47
+
48
+ export function isWithinAppTestRoots(
49
+ file: string,
50
+ roots: readonly string[],
51
+ ): boolean {
52
+ return roots.some((root) => file.startsWith(`${root}/`));
53
+ }