@beignet/cli 0.0.46 → 0.0.48
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.
- package/CHANGELOG.md +20 -0
- package/README.md +50 -21
- package/dist/check.d.ts +8 -1
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +18 -6
- package/dist/check.js.map +1 -1
- package/dist/db.d.ts +38 -0
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +52 -0
- package/dist/db.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +73 -6
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.ts.map +1 -1
- package/dist/inspect.js +39 -2
- package/dist/inspect.js.map +1 -1
- package/dist/lib.d.ts +2 -2
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +1 -1
- package/dist/lib.js.map +1 -1
- package/dist/make/inbox.js +1 -1
- package/dist/make/inbox.js.map +1 -1
- package/dist/make/payments.js +1 -1
- package/dist/make/payments.js.map +1 -1
- package/dist/make/tenancy.d.ts.map +1 -1
- package/dist/make/tenancy.js +3 -2
- package/dist/make/tenancy.js.map +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +39 -2
- package/dist/mcp.js.map +1 -1
- package/dist/preflight.d.ts +11 -3
- package/dist/preflight.d.ts.map +1 -1
- package/dist/preflight.js +139 -16
- package/dist/preflight.js.map +1 -1
- package/dist/provider-add.d.ts.map +1 -1
- package/dist/provider-add.js +7 -2
- package/dist/provider-add.js.map +1 -1
- package/dist/provider-audit.d.ts +13 -0
- package/dist/provider-audit.d.ts.map +1 -1
- package/dist/provider-audit.js +122 -8
- package/dist/provider-audit.js.map +1 -1
- package/dist/templates/agents.d.ts.map +1 -1
- package/dist/templates/agents.js +14 -7
- package/dist/templates/agents.js.map +1 -1
- package/dist/templates/base.d.ts +1 -0
- package/dist/templates/base.d.ts.map +1 -1
- package/dist/templates/base.js +11 -5
- package/dist/templates/base.js.map +1 -1
- package/dist/templates/db/index.d.ts +1 -0
- package/dist/templates/db/index.d.ts.map +1 -1
- package/dist/templates/db/index.js.map +1 -1
- package/dist/templates/db/migration-status.d.ts +9 -0
- package/dist/templates/db/migration-status.d.ts.map +1 -0
- package/dist/templates/db/migration-status.js +117 -0
- package/dist/templates/db/migration-status.js.map +1 -0
- package/dist/templates/db/mysql.d.ts.map +1 -1
- package/dist/templates/db/mysql.js +23 -0
- package/dist/templates/db/mysql.js.map +1 -1
- package/dist/templates/db/postgres.d.ts.map +1 -1
- package/dist/templates/db/postgres.js +21 -0
- package/dist/templates/db/postgres.js.map +1 -1
- package/dist/templates/db/sqlite.d.ts.map +1 -1
- package/dist/templates/db/sqlite.js +53 -0
- package/dist/templates/db/sqlite.js.map +1 -1
- package/dist/templates/index.d.ts.map +1 -1
- package/dist/templates/index.js +5 -0
- package/dist/templates/index.js.map +1 -1
- package/dist/templates/server.d.ts.map +1 -1
- package/dist/templates/server.js +4 -1
- package/dist/templates/server.js.map +1 -1
- package/dist/templates/shared.d.ts.map +1 -1
- package/dist/templates/shared.js +1 -0
- package/dist/templates/shared.js.map +1 -1
- package/package.json +2 -2
- package/skills/app-structure/SKILL.md +11 -7
- package/src/check.ts +35 -7
- package/src/db.ts +97 -0
- package/src/index.ts +108 -7
- package/src/inspect.ts +76 -1
- package/src/lib.ts +9 -1
- package/src/make/inbox.ts +1 -1
- package/src/make/payments.ts +1 -1
- package/src/make/tenancy.ts +3 -2
- package/src/mcp.ts +56 -1
- package/src/preflight.ts +195 -16
- package/src/provider-add.ts +7 -2
- package/src/provider-audit.ts +210 -18
- package/src/templates/agents.ts +14 -7
- package/src/templates/base.ts +12 -3
- package/src/templates/db/index.ts +1 -0
- package/src/templates/db/migration-status.ts +126 -0
- package/src/templates/db/mysql.ts +23 -0
- package/src/templates/db/postgres.ts +21 -0
- package/src/templates/db/sqlite.ts +53 -0
- package/src/templates/index.ts +5 -0
- package/src/templates/server.ts +4 -1
- package/src/templates/shared.ts +1 -0
package/src/index.ts
CHANGED
|
@@ -134,6 +134,8 @@ type CheckFlags = {
|
|
|
134
134
|
json?: boolean;
|
|
135
135
|
fix?: boolean;
|
|
136
136
|
preflight?: boolean;
|
|
137
|
+
preflightConnect?: boolean;
|
|
138
|
+
connectTimeoutMs?: number;
|
|
137
139
|
cwd?: string;
|
|
138
140
|
};
|
|
139
141
|
|
|
@@ -142,6 +144,7 @@ type PreflightFlags = {
|
|
|
142
144
|
envFile?: string;
|
|
143
145
|
envModule?: string;
|
|
144
146
|
connect?: boolean;
|
|
147
|
+
connectTimeoutMs?: number;
|
|
145
148
|
serverModule?: string;
|
|
146
149
|
cwd?: string;
|
|
147
150
|
};
|
|
@@ -152,6 +155,11 @@ type DbFlags = {
|
|
|
152
155
|
cwd?: string;
|
|
153
156
|
};
|
|
154
157
|
|
|
158
|
+
type DbStatusFlags = {
|
|
159
|
+
json?: boolean;
|
|
160
|
+
cwd?: string;
|
|
161
|
+
};
|
|
162
|
+
|
|
155
163
|
type DbSchemaSyncFlags = DbFlags & {
|
|
156
164
|
dialect?: DatabaseSchemaDialect;
|
|
157
165
|
tables?: readonly DatabaseSchemaTable[];
|
|
@@ -349,6 +357,14 @@ const parsedDateFlag = (brief: string) =>
|
|
|
349
357
|
brief,
|
|
350
358
|
}) as const;
|
|
351
359
|
|
|
360
|
+
const connectTimeoutMsFlag = {
|
|
361
|
+
kind: "parsed",
|
|
362
|
+
parse: parsePositiveInteger,
|
|
363
|
+
optional: true,
|
|
364
|
+
brief:
|
|
365
|
+
"Per migration-status or dependency health check timeout in milliseconds. Defaults to 5000.",
|
|
366
|
+
} as const;
|
|
367
|
+
|
|
352
368
|
const cwdFlag = parsedStringFlag(
|
|
353
369
|
"App directory. Defaults to the current working directory.",
|
|
354
370
|
);
|
|
@@ -411,6 +427,11 @@ const dbFlagParameters = {
|
|
|
411
427
|
cwd: cwdFlag,
|
|
412
428
|
} satisfies FlagParametersForType<DbFlags, CliContext>;
|
|
413
429
|
|
|
430
|
+
const dbStatusFlagParameters = {
|
|
431
|
+
json: jsonFlag,
|
|
432
|
+
cwd: cwdFlag,
|
|
433
|
+
} satisfies FlagParametersForType<DbStatusFlags, CliContext>;
|
|
434
|
+
|
|
414
435
|
const dbSchemaSyncFlagParameters = {
|
|
415
436
|
...dbFlagParameters,
|
|
416
437
|
dialect: {
|
|
@@ -1097,7 +1118,7 @@ const checkCommand = buildCommand<CheckFlags, [], CliContext>({
|
|
|
1097
1118
|
docs: {
|
|
1098
1119
|
brief: "Run the full app validation loop as one command.",
|
|
1099
1120
|
fullDescription:
|
|
1100
|
-
"Runs beignet lint, beignet doctor --strict, and the app's lint, typecheck, and test package scripts through the detected package manager. Every step runs even when an earlier one fails, so one run reports everything. Missing package scripts are skipped, not failed.",
|
|
1121
|
+
"Runs beignet lint, beignet doctor --strict, optional disconnected or connected preflight, and the app's lint, typecheck, and test package scripts through the detected package manager. Every step runs even when an earlier one fails, so one run reports everything. Missing package scripts are skipped, not failed.",
|
|
1101
1122
|
},
|
|
1102
1123
|
parameters: {
|
|
1103
1124
|
flags: {
|
|
@@ -1112,8 +1133,17 @@ const checkCommand = buildCommand<CheckFlags, [], CliContext>({
|
|
|
1112
1133
|
kind: "boolean",
|
|
1113
1134
|
optional: true,
|
|
1114
1135
|
withNegated: false,
|
|
1115
|
-
brief:
|
|
1136
|
+
brief:
|
|
1137
|
+
"Append a disconnected beignet preflight environment step after doctor.",
|
|
1138
|
+
},
|
|
1139
|
+
preflightConnect: {
|
|
1140
|
+
kind: "boolean",
|
|
1141
|
+
optional: true,
|
|
1142
|
+
withNegated: false,
|
|
1143
|
+
brief:
|
|
1144
|
+
"Append beignet preflight --connect after doctor. Implies --preflight.",
|
|
1116
1145
|
},
|
|
1146
|
+
connectTimeoutMs: connectTimeoutMsFlag,
|
|
1117
1147
|
cwd: cwdFlag,
|
|
1118
1148
|
} satisfies FlagParametersForType<CheckFlags, CliContext>,
|
|
1119
1149
|
},
|
|
@@ -1128,6 +1158,8 @@ const checkCommand = buildCommand<CheckFlags, [], CliContext>({
|
|
|
1128
1158
|
cwd: flags.cwd,
|
|
1129
1159
|
fix: flags.fix,
|
|
1130
1160
|
preflight: flags.preflight,
|
|
1161
|
+
preflightConnect: flags.preflightConnect,
|
|
1162
|
+
connectTimeoutMs: flags.connectTimeoutMs,
|
|
1131
1163
|
color,
|
|
1132
1164
|
...(flags.json
|
|
1133
1165
|
? {}
|
|
@@ -1153,7 +1185,7 @@ const preflightCommand = buildCommand<PreflightFlags, [], CliContext>({
|
|
|
1153
1185
|
docs: {
|
|
1154
1186
|
brief: "Validate the deploy environment before shipping.",
|
|
1155
1187
|
fullDescription:
|
|
1156
|
-
"Runtime production gate, unlike the static doctor checks: reads the actual environment the process runs with, verifies every env var installed provider manifests mark as required, flags values still matching .env.example or common placeholders on secret-like keys, and validates the app env schema by importing lib/env.ts. Run it in the deploy pipeline where production configuration is present. Exits 1 on any error finding.",
|
|
1188
|
+
"Runtime production gate, unlike the static doctor checks: reads the actual environment the process runs with, verifies every env var installed provider manifests mark as required, flags values still matching .env.example or common placeholders on secret-like keys, and validates the app env schema by importing lib/env.ts. With --connect, it checks migration status before booting the server and running port health checks. Run it in the deploy pipeline where production configuration is present. Exits 1 on any error finding.",
|
|
1157
1189
|
},
|
|
1158
1190
|
parameters: {
|
|
1159
1191
|
flags: {
|
|
@@ -1169,8 +1201,9 @@ const preflightCommand = buildCommand<PreflightFlags, [], CliContext>({
|
|
|
1169
1201
|
optional: true,
|
|
1170
1202
|
withNegated: false,
|
|
1171
1203
|
brief:
|
|
1172
|
-
"
|
|
1204
|
+
"Check migration status, then boot the app server and run every port's checkHealth(). Needs network and real credentials.",
|
|
1173
1205
|
},
|
|
1206
|
+
connectTimeoutMs: connectTimeoutMsFlag,
|
|
1174
1207
|
serverModule: parsedStringFlag(
|
|
1175
1208
|
"Module exporting getServer, used by --connect. Defaults to server/index.ts.",
|
|
1176
1209
|
),
|
|
@@ -1191,6 +1224,7 @@ const preflightCommand = buildCommand<PreflightFlags, [], CliContext>({
|
|
|
1191
1224
|
envFile: flags.envFile,
|
|
1192
1225
|
envModule: flags.envModule,
|
|
1193
1226
|
connect: flags.connect,
|
|
1227
|
+
connectTimeoutMs: flags.connectTimeoutMs,
|
|
1194
1228
|
serverModule: flags.serverModule,
|
|
1195
1229
|
});
|
|
1196
1230
|
|
|
@@ -1374,6 +1408,42 @@ function databaseCommand(command: DatabaseCommand) {
|
|
|
1374
1408
|
});
|
|
1375
1409
|
}
|
|
1376
1410
|
|
|
1411
|
+
const databaseStatusCommand = buildCommand<DbStatusFlags, [], CliContext>({
|
|
1412
|
+
docs: {
|
|
1413
|
+
brief: "Inspect whether app-owned database migrations are current.",
|
|
1414
|
+
fullDescription:
|
|
1415
|
+
"Runs the app's read-only db:status script. Exit 0 means current, exit 2 means pending migrations, and any other non-zero exit means inspection failed.",
|
|
1416
|
+
},
|
|
1417
|
+
parameters: {
|
|
1418
|
+
flags: dbStatusFlagParameters,
|
|
1419
|
+
},
|
|
1420
|
+
loader: async () => {
|
|
1421
|
+
const { defaultDatabaseCommandMaxOutputBytes, runDatabaseStatus } =
|
|
1422
|
+
await import("./db.js");
|
|
1423
|
+
|
|
1424
|
+
return async function runDbStatus(this: CliContext, flags: DbStatusFlags) {
|
|
1425
|
+
const captureOutput = Boolean(flags.json);
|
|
1426
|
+
const result = await runDatabaseStatus({
|
|
1427
|
+
cwd: flags.cwd,
|
|
1428
|
+
captureOutput,
|
|
1429
|
+
maxOutputBytes: captureOutput
|
|
1430
|
+
? defaultDatabaseCommandMaxOutputBytes
|
|
1431
|
+
: undefined,
|
|
1432
|
+
});
|
|
1433
|
+
|
|
1434
|
+
writeOutput(
|
|
1435
|
+
this,
|
|
1436
|
+
flags.json
|
|
1437
|
+
? JSON.stringify(result, null, 2)
|
|
1438
|
+
: databaseStatusNextSteps(result),
|
|
1439
|
+
);
|
|
1440
|
+
if (result.exitCode !== 0) {
|
|
1441
|
+
this.process.exitCode = result.exitCode;
|
|
1442
|
+
}
|
|
1443
|
+
};
|
|
1444
|
+
},
|
|
1445
|
+
});
|
|
1446
|
+
|
|
1377
1447
|
const dbSchemaSyncCommand = buildCommand<DbSchemaSyncFlags, [], CliContext>({
|
|
1378
1448
|
docs: {
|
|
1379
1449
|
brief: "Sync app-owned re-exports of Beignet provider tables.",
|
|
@@ -1427,7 +1497,8 @@ const dbRoutes = buildRouteMap({
|
|
|
1427
1497
|
reset: databaseCommand("reset"),
|
|
1428
1498
|
schema: dbSchemaRoutes,
|
|
1429
1499
|
seed: databaseCommand("seed"),
|
|
1430
|
-
|
|
1500
|
+
status: databaseStatusCommand,
|
|
1501
|
+
} satisfies Record<DatabaseCommand | "schema" | "status", unknown>,
|
|
1431
1502
|
});
|
|
1432
1503
|
|
|
1433
1504
|
const taskRunCommand = buildCommand<TaskRunFlags, [string], CliContext>({
|
|
@@ -2398,6 +2469,14 @@ type DatabaseCommandNextStepsResult = {
|
|
|
2398
2469
|
dryRun: boolean;
|
|
2399
2470
|
};
|
|
2400
2471
|
|
|
2472
|
+
type DatabaseStatusNextStepsResult = {
|
|
2473
|
+
status: "current" | "pending" | "failed";
|
|
2474
|
+
cwd: string;
|
|
2475
|
+
script: string;
|
|
2476
|
+
runner: string;
|
|
2477
|
+
args: string[];
|
|
2478
|
+
};
|
|
2479
|
+
|
|
2401
2480
|
type DatabaseSchemaSyncNextStepsResult = {
|
|
2402
2481
|
cwd: string;
|
|
2403
2482
|
dialect: DatabaseSchemaDialect;
|
|
@@ -2632,6 +2711,7 @@ Next steps:
|
|
|
2632
2711
|
${envStep}
|
|
2633
2712
|
${startDatabaseStep}Prepare the database:
|
|
2634
2713
|
${cli} db migrate
|
|
2714
|
+
${cli} db status
|
|
2635
2715
|
|
|
2636
2716
|
Start the app:
|
|
2637
2717
|
${run} dev
|
|
@@ -2646,6 +2726,7 @@ Generate a feature:
|
|
|
2646
2726
|
${cli} make feature projects
|
|
2647
2727
|
${cli} db generate
|
|
2648
2728
|
${cli} db migrate
|
|
2729
|
+
${cli} db status
|
|
2649
2730
|
${cli} check`;
|
|
2650
2731
|
}
|
|
2651
2732
|
|
|
@@ -2722,7 +2803,7 @@ function makeResourceNextSteps(result: MakeNextStepsResult): string {
|
|
|
2722
2803
|
return makeNextSteps(result, "resource", [
|
|
2723
2804
|
"Use make resource when the feature maps cleanly to a REST resource with repository-backed persistence.",
|
|
2724
2805
|
"Review the generated schemas and repository fields.",
|
|
2725
|
-
"If this app uses Drizzle, run beignet db generate and beignet db
|
|
2806
|
+
"If this app uses Drizzle, run beignet db generate, beignet db migrate, and beignet db status so the new schema is ready and verified.",
|
|
2726
2807
|
"Run your app's lint, test, and typecheck commands, then beignet lint and beignet doctor.",
|
|
2727
2808
|
]);
|
|
2728
2809
|
}
|
|
@@ -2739,6 +2820,25 @@ Command:
|
|
|
2739
2820
|
${command}`;
|
|
2740
2821
|
}
|
|
2741
2822
|
|
|
2823
|
+
function databaseStatusNextSteps(
|
|
2824
|
+
result: DatabaseStatusNextStepsResult,
|
|
2825
|
+
): string {
|
|
2826
|
+
const command = [result.runner, ...result.args].join(" ");
|
|
2827
|
+
const summary =
|
|
2828
|
+
result.status === "current"
|
|
2829
|
+
? "Database migrations are current."
|
|
2830
|
+
: result.status === "pending"
|
|
2831
|
+
? "Database migrations are pending."
|
|
2832
|
+
: "Database migration status could not be determined.";
|
|
2833
|
+
|
|
2834
|
+
return `${summary}
|
|
2835
|
+
|
|
2836
|
+
Ran ${result.script} in ${result.cwd}
|
|
2837
|
+
|
|
2838
|
+
Command:
|
|
2839
|
+
${command}`;
|
|
2840
|
+
}
|
|
2841
|
+
|
|
2742
2842
|
function databaseSchemaSyncNextSteps(
|
|
2743
2843
|
result: DatabaseSchemaSyncNextStepsResult,
|
|
2744
2844
|
): string {
|
|
@@ -2759,6 +2859,7 @@ ${skippedFiles ? `\nSkipped identical files:\n${skippedFiles}` : ""}
|
|
|
2759
2859
|
Next steps:
|
|
2760
2860
|
Run beignet db generate to produce app-owned Drizzle migrations.
|
|
2761
2861
|
Run beignet db migrate to apply the migration.
|
|
2862
|
+
Run beignet db status to verify the target database.
|
|
2762
2863
|
Run beignet doctor --strict to check provider setup.`;
|
|
2763
2864
|
}
|
|
2764
2865
|
|
|
@@ -2766,7 +2867,7 @@ function makeFeatureNextSteps(result: MakeNextStepsResult): string {
|
|
|
2766
2867
|
return makeNextSteps(result, "feature slice", [
|
|
2767
2868
|
"Use make feature for product capabilities and workflows. Use make resource when the concept is mostly CRUD-shaped.",
|
|
2768
2869
|
"Treat the generated name field as a placeholder and shape the contracts, use cases, and repository around the feature's real workflow.",
|
|
2769
|
-
"If this app uses Drizzle, run beignet db generate and beignet db
|
|
2870
|
+
"If this app uses Drizzle, run beignet db generate, beignet db migrate, and beignet db status so the new schema is ready and verified.",
|
|
2770
2871
|
"Run your app's lint, test, and typecheck commands, then beignet lint and beignet doctor.",
|
|
2771
2872
|
]);
|
|
2772
2873
|
}
|
package/src/inspect.ts
CHANGED
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
import {
|
|
44
44
|
detectedProviderVariants,
|
|
45
45
|
diagnosticPackageJsonFile,
|
|
46
|
+
formatProviderEnvAlternatives,
|
|
46
47
|
formatProviderMetadataIssues,
|
|
47
48
|
installedPackageNames,
|
|
48
49
|
providerDoctorRulesForInstalledPackages,
|
|
@@ -2619,6 +2620,27 @@ async function inspectProductionReadiness(
|
|
|
2619
2620
|
provider.variants,
|
|
2620
2621
|
providerEntries,
|
|
2621
2622
|
)) {
|
|
2623
|
+
const envAlternatives = configuredProviderRequiredEnvAlternatives(
|
|
2624
|
+
variant.requiredEnvAlternatives,
|
|
2625
|
+
config,
|
|
2626
|
+
);
|
|
2627
|
+
if (
|
|
2628
|
+
envAlternatives.length > 0 &&
|
|
2629
|
+
!(await providerRequiredEnvAlternativeExists(
|
|
2630
|
+
targetDir,
|
|
2631
|
+
configFiles,
|
|
2632
|
+
envAlternatives,
|
|
2633
|
+
sourceCache,
|
|
2634
|
+
))
|
|
2635
|
+
) {
|
|
2636
|
+
diagnostics.push({
|
|
2637
|
+
severity: "warning",
|
|
2638
|
+
code: "BEIGNET_PROVIDER_ENV_MISSING",
|
|
2639
|
+
file: "package.json",
|
|
2640
|
+
message: `${provider.packageName} is installed and ${variant.displayName} is registered, but none of its required environment configurations are fully mentioned in app env/config files. Configure ${formatProviderEnvAlternatives(envAlternatives)}, or remove the provider registration.`,
|
|
2641
|
+
});
|
|
2642
|
+
}
|
|
2643
|
+
|
|
2622
2644
|
for (const envVar of configuredProviderRequiredEnv(
|
|
2623
2645
|
variant.requiredEnv,
|
|
2624
2646
|
config,
|
|
@@ -2669,6 +2691,27 @@ async function inspectProductionReadiness(
|
|
|
2669
2691
|
continue;
|
|
2670
2692
|
}
|
|
2671
2693
|
|
|
2694
|
+
const envAlternatives = configuredProviderRequiredEnvAlternatives(
|
|
2695
|
+
provider.requiredEnvAlternatives ?? [],
|
|
2696
|
+
config,
|
|
2697
|
+
);
|
|
2698
|
+
if (
|
|
2699
|
+
envAlternatives.length > 0 &&
|
|
2700
|
+
!(await providerRequiredEnvAlternativeExists(
|
|
2701
|
+
targetDir,
|
|
2702
|
+
configFiles,
|
|
2703
|
+
envAlternatives,
|
|
2704
|
+
sourceCache,
|
|
2705
|
+
))
|
|
2706
|
+
) {
|
|
2707
|
+
diagnostics.push({
|
|
2708
|
+
severity: "warning",
|
|
2709
|
+
code: "BEIGNET_PROVIDER_ENV_MISSING",
|
|
2710
|
+
file: "package.json",
|
|
2711
|
+
message: `${provider.packageName} is installed, but none of its required environment configurations are fully mentioned in app env/config files. Configure ${formatProviderEnvAlternatives(envAlternatives)}, or remove the unused provider package.`,
|
|
2712
|
+
});
|
|
2713
|
+
}
|
|
2714
|
+
|
|
2672
2715
|
for (const envVar of configuredProviderRequiredEnv(
|
|
2673
2716
|
provider.requiredEnv ?? [],
|
|
2674
2717
|
config,
|
|
@@ -5175,7 +5218,7 @@ async function inspectDatabaseLifecycleDrift(
|
|
|
5175
5218
|
}
|
|
5176
5219
|
|
|
5177
5220
|
if (hasDrizzleArtifacts) {
|
|
5178
|
-
for (const script of ["db:generate", "db:migrate"] as const) {
|
|
5221
|
+
for (const script of ["db:generate", "db:migrate", "db:status"] as const) {
|
|
5179
5222
|
if (packageScripts[script]) continue;
|
|
5180
5223
|
diagnostics.push({
|
|
5181
5224
|
severity: "warning",
|
|
@@ -5257,6 +5300,12 @@ async function inspectDatabaseLifecycleDrift(
|
|
|
5257
5300
|
file: `${infrastructurePath}/db/reset.ts`,
|
|
5258
5301
|
code: "BEIGNET_DB_RESET_ENTRYPOINT_MISSING",
|
|
5259
5302
|
},
|
|
5303
|
+
{
|
|
5304
|
+
script: "db:status",
|
|
5305
|
+
command: "status",
|
|
5306
|
+
file: `${infrastructurePath}/db/migration-status.ts`,
|
|
5307
|
+
code: "BEIGNET_DB_STATUS_ENTRYPOINT_MISSING",
|
|
5308
|
+
},
|
|
5260
5309
|
] as const;
|
|
5261
5310
|
|
|
5262
5311
|
for (const entrypoint of standardEntrypoints) {
|
|
@@ -6284,6 +6333,32 @@ function configuredProviderRequiredEnv(
|
|
|
6284
6333
|
return envVars.filter((envVar) => !ignored.has(envVar));
|
|
6285
6334
|
}
|
|
6286
6335
|
|
|
6336
|
+
function configuredProviderRequiredEnvAlternatives(
|
|
6337
|
+
alternatives: readonly (readonly string[])[],
|
|
6338
|
+
config: ResolvedBeignetConfig,
|
|
6339
|
+
): string[][] {
|
|
6340
|
+
return alternatives.map((alternative) =>
|
|
6341
|
+
configuredProviderRequiredEnv(alternative, config),
|
|
6342
|
+
);
|
|
6343
|
+
}
|
|
6344
|
+
|
|
6345
|
+
async function providerRequiredEnvAlternativeExists(
|
|
6346
|
+
targetDir: string,
|
|
6347
|
+
configFiles: readonly string[],
|
|
6348
|
+
alternatives: readonly (readonly string[])[],
|
|
6349
|
+
sourceCache: Map<string, string>,
|
|
6350
|
+
): Promise<boolean> {
|
|
6351
|
+
for (const alternative of alternatives) {
|
|
6352
|
+
const exists = await Promise.all(
|
|
6353
|
+
alternative.map((envVar) =>
|
|
6354
|
+
providerRequiredEnvExists(targetDir, configFiles, envVar, sourceCache),
|
|
6355
|
+
),
|
|
6356
|
+
);
|
|
6357
|
+
if (exists.every(Boolean)) return true;
|
|
6358
|
+
}
|
|
6359
|
+
return false;
|
|
6360
|
+
}
|
|
6361
|
+
|
|
6287
6362
|
function configuredProviderRequiredTable(
|
|
6288
6363
|
tableName: string,
|
|
6289
6364
|
config: ResolvedBeignetConfig,
|
package/src/lib.ts
CHANGED
|
@@ -29,14 +29,22 @@ export type { CreateOptions } from "./create.js";
|
|
|
29
29
|
export { createProject } from "./create.js";
|
|
30
30
|
export type {
|
|
31
31
|
DatabaseCommand,
|
|
32
|
+
DatabaseMigrationStatus,
|
|
32
33
|
DatabaseSchemaDialect,
|
|
33
34
|
DatabaseSchemaTable,
|
|
34
35
|
RunDatabaseCommandOptions,
|
|
35
36
|
RunDatabaseCommandResult,
|
|
37
|
+
RunDatabaseStatusOptions,
|
|
38
|
+
RunDatabaseStatusResult,
|
|
36
39
|
SyncDatabaseSchemaOptions,
|
|
37
40
|
SyncDatabaseSchemaResult,
|
|
38
41
|
} from "./db.js";
|
|
39
|
-
export {
|
|
42
|
+
export {
|
|
43
|
+
databaseMigrationsPendingExitCode,
|
|
44
|
+
runDatabaseCommand,
|
|
45
|
+
runDatabaseStatus,
|
|
46
|
+
syncDatabaseSchema,
|
|
47
|
+
} from "./db.js";
|
|
40
48
|
export type {
|
|
41
49
|
DoctorFixApplyResult,
|
|
42
50
|
DoctorFixFileChange,
|
package/src/make/inbox.ts
CHANGED
|
@@ -226,7 +226,7 @@ export async function makeInbox(
|
|
|
226
226
|
*/
|
|
227
227
|
export function makeInboxNextStepLines(): string[] {
|
|
228
228
|
return [
|
|
229
|
-
"Run beignet db generate and beignet db
|
|
229
|
+
"Run beignet db generate, beignet db migrate, and beignet db status so inbox_notifications exists and is verified.",
|
|
230
230
|
'Add an in-app channel to any feature notification: import { defineInboxNotificationChannel } from "@/features/inbox/channel" and add inApp: defineInboxNotificationChannel(({ payload }) => ({ userId: payload.userId, type: "your-type", title: "Something happened" })) to its channels.',
|
|
231
231
|
"Render the unread badge from features/inbox/components/unread-badge.tsx next to your Inbox nav link for a live unread count.",
|
|
232
232
|
"Run your app's test, lint, and typecheck commands, then beignet lint and beignet doctor.",
|
package/src/make/payments.ts
CHANGED
|
@@ -209,7 +209,7 @@ export function makePaymentsNextStepLines(
|
|
|
209
209
|
return [
|
|
210
210
|
"The free plan works out of the box; billing accounts without an active subscription resolve to it automatically.",
|
|
211
211
|
"Set BILLING_PRO_PRICE_ID in .env.local to the provider price ID for your pro plan.",
|
|
212
|
-
"Run beignet db generate and beignet db
|
|
212
|
+
"Run beignet db generate, beignet db migrate, and beignet db status so billing_accounts exists and is verified before handling webhooks.",
|
|
213
213
|
'Gate paid actions once usage passes FREE_PLAN_LIMITS: await requireEntitlement(ctx, { entitlement: "todos.create", subject: { type: "tenant", id: tenantId } });',
|
|
214
214
|
...(hasPlanUi
|
|
215
215
|
? [
|
package/src/make/tenancy.ts
CHANGED
|
@@ -249,7 +249,7 @@ export async function makeTenancy(
|
|
|
249
249
|
*/
|
|
250
250
|
export function makeTenancyNextStepLines(): string[] {
|
|
251
251
|
return [
|
|
252
|
-
"Run beignet db generate and beignet db
|
|
252
|
+
"Run beignet db generate, beignet db migrate, and beignet db status so the workspaces, workspace_members, and workspace_invites tables exist and are verified.",
|
|
253
253
|
"Requests resolve the active workspace from memberships and the beignet-workspace cookie; users without a workspace have no tenant, so point them at Settings > Workspace to create one.",
|
|
254
254
|
"Run the db:seed script for a demo workspace with a sign-in-able demo admin (demo-admin@example.com).",
|
|
255
255
|
"Invite emails send through the in-memory mailer in development; swap server/providers.ts to a real mail provider such as @beignet/provider-mail-resend for delivery.",
|
|
@@ -3857,7 +3857,7 @@ export type AppServiceContextInput =
|
|
|
3857
3857
|
*/
|
|
3858
3858
|
export const appContext = defineServerContext<AppContext, AppRuntimePorts>()({
|
|
3859
3859
|
\tgate: (ports) => ports.gate,
|
|
3860
|
-
\trequest: async ({ req, ports, requestId, trace }) => {
|
|
3860
|
+
\trequest: async ({ req, requestInfo, ports, requestId, trace }) => {
|
|
3861
3861
|
\t\tconst auth = await ports.auth.getSession(req);
|
|
3862
3862
|
\t\tconst { tenant, membership } = await resolveRequestWorkspace({
|
|
3863
3863
|
\t\t\tauth,
|
|
@@ -3876,6 +3876,7 @@ export const appContext = defineServerContext<AppContext, AppRuntimePorts>()({
|
|
|
3876
3876
|
\t\t\t\t\t})
|
|
3877
3877
|
\t\t\t\t: createAnonymousActor(),
|
|
3878
3878
|
\t\t\tauth,
|
|
3879
|
+
\t\t\trequestInfo,
|
|
3879
3880
|
\t\t\t...trace,
|
|
3880
3881
|
\t\t\tports,
|
|
3881
3882
|
\t\t\t...(tenant ? { tenant } : {}),
|
package/src/mcp.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
defaultDatabaseCommandMaxOutputBytes,
|
|
24
24
|
defaultDatabaseCommandTimeoutMs,
|
|
25
25
|
runDatabaseCommand,
|
|
26
|
+
runDatabaseStatus,
|
|
26
27
|
syncDatabaseSchema,
|
|
27
28
|
} from "./db.js";
|
|
28
29
|
import { explainApp, explainTargetKinds } from "./explain.js";
|
|
@@ -639,7 +640,7 @@ export function buildBeignetMcpServer(options: McpServerOptions): McpServer {
|
|
|
639
640
|
"check",
|
|
640
641
|
{
|
|
641
642
|
description:
|
|
642
|
-
"Run the full Beignet app validation loop: Beignet lint, strict doctor, and the app's lint, typecheck, and test scripts. Returns the same versioned JSON as beignet check --json, including every step, bounded failure output, durations, and overall ok status. Does not apply Beignet fixes, but app-owned scripts run with their normal side effects.",
|
|
643
|
+
"Run the full Beignet app validation loop: Beignet lint, strict doctor, optional disconnected or connected preflight, and the app's lint, typecheck, and test scripts. Returns the same versioned JSON as beignet check --json, including every step, bounded failure output, durations, and overall ok status. Does not apply Beignet fixes, but app-owned scripts run with their normal side effects.",
|
|
643
644
|
inputSchema: {
|
|
644
645
|
preflight: z
|
|
645
646
|
.boolean()
|
|
@@ -647,6 +648,21 @@ export function buildBeignetMcpServer(options: McpServerOptions): McpServer {
|
|
|
647
648
|
.describe(
|
|
648
649
|
"Include the environment preflight check before app package scripts. Defaults to false.",
|
|
649
650
|
),
|
|
651
|
+
preflightConnect: z
|
|
652
|
+
.boolean()
|
|
653
|
+
.optional()
|
|
654
|
+
.describe(
|
|
655
|
+
"Include connected preflight with migration status and dependency health checks. Implies preflight and defaults to false.",
|
|
656
|
+
),
|
|
657
|
+
connectTimeoutMs: z
|
|
658
|
+
.number()
|
|
659
|
+
.int()
|
|
660
|
+
.min(1)
|
|
661
|
+
.max(60 * 60 * 1_000)
|
|
662
|
+
.optional()
|
|
663
|
+
.describe(
|
|
664
|
+
"Maximum duration for migration status and each dependency health check in milliseconds. Defaults to 5000.",
|
|
665
|
+
),
|
|
650
666
|
timeoutMs: z
|
|
651
667
|
.number()
|
|
652
668
|
.int()
|
|
@@ -670,6 +686,8 @@ export function buildBeignetMcpServer(options: McpServerOptions): McpServer {
|
|
|
670
686
|
await checkApp({
|
|
671
687
|
cwd,
|
|
672
688
|
preflight: input.preflight ?? false,
|
|
689
|
+
preflightConnect: input.preflightConnect ?? false,
|
|
690
|
+
connectTimeoutMs: input.connectTimeoutMs,
|
|
673
691
|
scriptTimeoutMs: input.timeoutMs ?? defaultMcpCheckTimeoutMs,
|
|
674
692
|
signal: extra.signal,
|
|
675
693
|
}),
|
|
@@ -725,6 +743,43 @@ export function buildBeignetMcpServer(options: McpServerOptions): McpServer {
|
|
|
725
743
|
),
|
|
726
744
|
);
|
|
727
745
|
|
|
746
|
+
server.registerTool(
|
|
747
|
+
"db_status",
|
|
748
|
+
{
|
|
749
|
+
description:
|
|
750
|
+
"Inspect app-owned database migrations and return exactly the versioned beignet db status --json result. Exit state distinguishes current, pending, and failed inspection without mutating the database. Output is bounded, the complete child process tree is cancelled with the MCP request, and execution stops after the configured timeout.",
|
|
751
|
+
inputSchema: {
|
|
752
|
+
timeoutMs: z
|
|
753
|
+
.number()
|
|
754
|
+
.int()
|
|
755
|
+
.min(1_000)
|
|
756
|
+
.max(60 * 60 * 1_000)
|
|
757
|
+
.optional()
|
|
758
|
+
.describe(
|
|
759
|
+
"Maximum status duration in milliseconds. Defaults to 600000 (10 minutes).",
|
|
760
|
+
),
|
|
761
|
+
},
|
|
762
|
+
annotations: {
|
|
763
|
+
readOnlyHint: true,
|
|
764
|
+
destructiveHint: false,
|
|
765
|
+
idempotentHint: true,
|
|
766
|
+
openWorldHint: true,
|
|
767
|
+
},
|
|
768
|
+
},
|
|
769
|
+
async (input, extra) =>
|
|
770
|
+
safeToolResult(async () =>
|
|
771
|
+
jsonResult(
|
|
772
|
+
await runDatabaseStatus({
|
|
773
|
+
cwd,
|
|
774
|
+
captureOutput: true,
|
|
775
|
+
maxOutputBytes: defaultDatabaseCommandMaxOutputBytes,
|
|
776
|
+
signal: extra.signal,
|
|
777
|
+
timeoutMs: input.timeoutMs ?? defaultDatabaseCommandTimeoutMs,
|
|
778
|
+
}),
|
|
779
|
+
),
|
|
780
|
+
),
|
|
781
|
+
);
|
|
782
|
+
|
|
728
783
|
server.registerTool(
|
|
729
784
|
"db_schema_sync",
|
|
730
785
|
{
|