@beignet/cli 0.0.41 → 0.0.43
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 +23 -0
- package/README.md +96 -25
- package/dist/analysis/source-index.d.ts +1 -1
- package/dist/analysis/source-index.d.ts.map +1 -1
- package/dist/analysis/source-index.js +4 -2
- package/dist/analysis/source-index.js.map +1 -1
- package/dist/analysis/workspace.d.ts +3 -2
- package/dist/analysis/workspace.d.ts.map +1 -1
- package/dist/analysis/workspace.js +51 -39
- package/dist/analysis/workspace.js.map +1 -1
- package/dist/app-map.d.ts.map +1 -1
- package/dist/app-map.js +65 -4
- package/dist/app-map.js.map +1 -1
- package/dist/choices.d.ts +18 -0
- package/dist/choices.d.ts.map +1 -1
- package/dist/choices.js +35 -0
- package/dist/choices.js.map +1 -1
- package/dist/db.d.ts +18 -7
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +20 -7
- package/dist/db.js.map +1 -1
- package/dist/doctor-fixes.d.ts +64 -0
- package/dist/doctor-fixes.d.ts.map +1 -0
- package/dist/doctor-fixes.js +142 -0
- package/dist/doctor-fixes.js.map +1 -0
- package/dist/explain.d.ts +3 -1
- package/dist/explain.d.ts.map +1 -1
- package/dist/explain.js +136 -42
- package/dist/explain.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +92 -25
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.ts +38 -9
- package/dist/inspect.d.ts.map +1 -1
- package/dist/inspect.js +385 -251
- package/dist/inspect.js.map +1 -1
- package/dist/lib.d.ts +6 -2
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +3 -2
- package/dist/lib.js.map +1 -1
- package/dist/make/inbox.js +4 -4
- package/dist/make/payments.js +6 -6
- package/dist/make/shared.js +3 -3
- package/dist/make/shared.js.map +1 -1
- package/dist/make/tenancy.d.ts.map +1 -1
- package/dist/make/tenancy.js +12 -14
- package/dist/make/tenancy.js.map +1 -1
- package/dist/make.d.ts.map +1 -1
- package/dist/make.js +33 -23
- package/dist/make.js.map +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +121 -13
- package/dist/mcp.js.map +1 -1
- package/dist/registry-edits.d.ts +7 -1
- package/dist/registry-edits.d.ts.map +1 -1
- package/dist/registry-edits.js +61 -43
- package/dist/registry-edits.js.map +1 -1
- package/dist/templates/agents.d.ts.map +1 -1
- package/dist/templates/agents.js +34 -11
- package/dist/templates/agents.js.map +1 -1
- package/dist/templates/base.d.ts.map +1 -1
- package/dist/templates/base.js +5 -5
- package/dist/templates/base.js.map +1 -1
- package/dist/templates/db/mysql.js +3 -3
- package/dist/templates/db/postgres.js +3 -3
- package/dist/templates/db/sqlite.js +3 -3
- package/dist/templates/server.js +4 -4
- package/dist/templates/server.js.map +1 -1
- package/dist/templates/shared.d.ts +2 -1
- package/dist/templates/shared.d.ts.map +1 -1
- package/dist/templates/shared.js +7 -4
- package/dist/templates/shared.js.map +1 -1
- package/dist/templates/todos.js +2 -2
- package/package.json +3 -2
- package/skills/app-structure/SKILL.md +43 -10
- package/src/analysis/source-index.ts +12 -3
- package/src/analysis/workspace.ts +94 -52
- package/src/app-map.ts +82 -4
- package/src/choices.ts +57 -0
- package/src/db.ts +45 -15
- package/src/doctor-fixes.ts +252 -0
- package/src/explain.ts +151 -43
- package/src/index.ts +130 -35
- package/src/inspect.ts +537 -295
- package/src/lib.ts +28 -1
- package/src/make/inbox.ts +4 -4
- package/src/make/payments.ts +6 -6
- package/src/make/shared.ts +3 -3
- package/src/make/tenancy.ts +12 -14
- package/src/make.ts +36 -24
- package/src/mcp.ts +187 -13
- package/src/registry-edits.ts +81 -39
- package/src/templates/agents.ts +34 -11
- package/src/templates/base.ts +5 -4
- package/src/templates/db/mysql.ts +3 -3
- package/src/templates/db/postgres.ts +3 -3
- package/src/templates/db/sqlite.ts +3 -3
- package/src/templates/server.ts +4 -4
- package/src/templates/shared.ts +14 -6
- package/src/templates/todos.ts +2 -2
package/src/lib.ts
CHANGED
|
@@ -27,7 +27,25 @@ export {
|
|
|
27
27
|
} from "./app-map.js";
|
|
28
28
|
export type { CreateOptions } from "./create.js";
|
|
29
29
|
export { createProject } from "./create.js";
|
|
30
|
-
export {
|
|
30
|
+
export type {
|
|
31
|
+
DatabaseCommand,
|
|
32
|
+
DatabaseSchemaDialect,
|
|
33
|
+
DatabaseSchemaTable,
|
|
34
|
+
RunDatabaseCommandOptions,
|
|
35
|
+
RunDatabaseCommandResult,
|
|
36
|
+
SyncDatabaseSchemaOptions,
|
|
37
|
+
SyncDatabaseSchemaResult,
|
|
38
|
+
} from "./db.js";
|
|
39
|
+
export { runDatabaseCommand, syncDatabaseSchema } from "./db.js";
|
|
40
|
+
export type {
|
|
41
|
+
DoctorFixApplyResult,
|
|
42
|
+
DoctorFixFileChange,
|
|
43
|
+
DoctorFixOperation,
|
|
44
|
+
DoctorFixOperationId,
|
|
45
|
+
DoctorFixPlan,
|
|
46
|
+
InspectFix,
|
|
47
|
+
} from "./doctor-fixes.js";
|
|
48
|
+
export { doctorFixOperationIds } from "./doctor-fixes.js";
|
|
31
49
|
export type {
|
|
32
50
|
ExplainAppOptions,
|
|
33
51
|
ExplainAppResult,
|
|
@@ -46,12 +64,21 @@ export {
|
|
|
46
64
|
formatExplain,
|
|
47
65
|
} from "./explain.js";
|
|
48
66
|
export { main } from "./index.js";
|
|
67
|
+
export type {
|
|
68
|
+
ApplyDoctorFixPlanOptions,
|
|
69
|
+
DoctorFixInspectionResult,
|
|
70
|
+
DoctorFixPlanResult,
|
|
71
|
+
} from "./inspect.js";
|
|
49
72
|
export {
|
|
50
73
|
applyDoctorFixes,
|
|
74
|
+
applyDoctorFixPlan,
|
|
51
75
|
formatDoctor,
|
|
76
|
+
formatDoctorFixPlan,
|
|
77
|
+
formatDoctorFixPlanGithub,
|
|
52
78
|
formatDoctorGithub,
|
|
53
79
|
formatRoutes,
|
|
54
80
|
inspectApp,
|
|
81
|
+
planDoctorFixes,
|
|
55
82
|
} from "./inspect.js";
|
|
56
83
|
export { formatLint, formatLintGithub, lintApp } from "./lint.js";
|
|
57
84
|
export type { MakeFeatureAddon, MakeFeatureRecipe } from "./make.js";
|
package/src/make/inbox.ts
CHANGED
|
@@ -1437,17 +1437,17 @@ export const inboxNotifications = ${dialect.tableFunction}(
|
|
|
1437
1437
|
\t\treadAt: ${column("read_at")},
|
|
1438
1438
|
\t\tcreatedAt: ${column("created_at")}.notNull(),
|
|
1439
1439
|
\t},
|
|
1440
|
-
\t(table) =>
|
|
1441
|
-
\t\
|
|
1440
|
+
\t(table) => [
|
|
1441
|
+
\t\tindex("inbox_notifications_unread_idx").on(
|
|
1442
1442
|
\t\t\ttable.userId,
|
|
1443
1443
|
\t\t\ttable.readAt,
|
|
1444
1444
|
\t\t),
|
|
1445
|
-
\t\
|
|
1445
|
+
\t\tindex("inbox_notifications_cursor_idx").on(
|
|
1446
1446
|
\t\t\ttable.userId,
|
|
1447
1447
|
\t\t\ttable.createdAt,
|
|
1448
1448
|
\t\t\ttable.id,
|
|
1449
1449
|
\t\t),
|
|
1450
|
-
\t
|
|
1450
|
+
\t],
|
|
1451
1451
|
);
|
|
1452
1452
|
`;
|
|
1453
1453
|
}
|
package/src/make/payments.ts
CHANGED
|
@@ -680,11 +680,11 @@ export const createCheckoutSessionInputSchema = z.object({
|
|
|
680
680
|
|
|
681
681
|
export const createCheckoutSessionOutputSchema = z.object({
|
|
682
682
|
\tsessionId: z.string(),
|
|
683
|
-
\turl: z.
|
|
683
|
+
\turl: z.url(),
|
|
684
684
|
});
|
|
685
685
|
|
|
686
686
|
export const createBillingPortalSessionOutputSchema = z.object({
|
|
687
|
-
\turl: z.
|
|
687
|
+
\turl: z.url(),
|
|
688
688
|
});
|
|
689
689
|
|
|
690
690
|
export const billingStatusOutputSchema = z.object({
|
|
@@ -1800,14 +1800,14 @@ export const billingAccounts = ${dialect.tableFunction}(
|
|
|
1800
1800
|
\t\tlastEventId: ${idColumn("last_event_id")},
|
|
1801
1801
|
\t\tupdatedAt: ${idColumn("updated_at")}.notNull(),
|
|
1802
1802
|
\t},
|
|
1803
|
-
\t(table) =>
|
|
1804
|
-
\t\
|
|
1803
|
+
\t(table) => [
|
|
1804
|
+
\t\tuniqueIndex(
|
|
1805
1805
|
\t\t\t"billing_accounts_provider_customer_unique",
|
|
1806
1806
|
\t\t).on(table.provider, table.customerId),
|
|
1807
|
-
\t\
|
|
1807
|
+
\t\tuniqueIndex(
|
|
1808
1808
|
\t\t\t"billing_accounts_provider_subscription_unique",
|
|
1809
1809
|
\t\t).on(table.provider, table.subscriptionId),
|
|
1810
|
-
\t
|
|
1810
|
+
\t],
|
|
1811
1811
|
);
|
|
1812
1812
|
`;
|
|
1813
1813
|
}
|
package/src/make/shared.ts
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
import {
|
|
19
19
|
currentGeneratedPackageScripts,
|
|
20
20
|
externalVersions,
|
|
21
|
-
|
|
21
|
+
isLegacyGeneratedPackageScript,
|
|
22
22
|
} from "../templates/shared.js";
|
|
23
23
|
|
|
24
24
|
export type MakeResult = {
|
|
@@ -1096,7 +1096,7 @@ export async function updatePackageScripts(
|
|
|
1096
1096
|
for (const [name, command] of Object.entries(scripts)) {
|
|
1097
1097
|
if (
|
|
1098
1098
|
!packageJson.scripts[name] ||
|
|
1099
|
-
packageJson.scripts[name]
|
|
1099
|
+
isLegacyGeneratedPackageScript(name, packageJson.scripts[name])
|
|
1100
1100
|
) {
|
|
1101
1101
|
packageJson.scripts[name] = command;
|
|
1102
1102
|
}
|
|
@@ -1162,7 +1162,7 @@ function updateGeneratedPackageScripts(scripts: Record<string, string>): void {
|
|
|
1162
1162
|
currentGeneratedPackageScripts,
|
|
1163
1163
|
)) {
|
|
1164
1164
|
if (
|
|
1165
|
-
|
|
1165
|
+
isLegacyGeneratedPackageScript(name, scripts[name]) ||
|
|
1166
1166
|
(name === "test" && !scripts[name])
|
|
1167
1167
|
) {
|
|
1168
1168
|
scripts[name] = command;
|
package/src/make/tenancy.ts
CHANGED
|
@@ -952,7 +952,7 @@ export const workspaceMemberWithUserSchema = workspaceMemberSchema.extend({
|
|
|
952
952
|
export const workspaceInviteSchema = z.object({
|
|
953
953
|
\tid: z.string().min(1),
|
|
954
954
|
\tworkspaceId: z.string().min(1),
|
|
955
|
-
\temail: z.
|
|
955
|
+
\temail: z.email(),
|
|
956
956
|
\trole: workspaceRoleSchema,
|
|
957
957
|
\ttoken: z.string().min(1),
|
|
958
958
|
\tinvitedByUserId: z.string().min(1),
|
|
@@ -1019,7 +1019,7 @@ export const listInvitesOutputSchema = z.object({
|
|
|
1019
1019
|
});
|
|
1020
1020
|
|
|
1021
1021
|
export const createInviteInputSchema = z.object({
|
|
1022
|
-
\temail: z.
|
|
1022
|
+
\temail: z.email(),
|
|
1023
1023
|
\trole: workspaceRoleSchema.default("member"),
|
|
1024
1024
|
});
|
|
1025
1025
|
|
|
@@ -2005,7 +2005,7 @@ const invitePayloadSchema = z.object({
|
|
|
2005
2005
|
\tinviteId: z.string().min(1),
|
|
2006
2006
|
\tworkspaceId: z.string().min(1),
|
|
2007
2007
|
\tworkspaceName: z.string().min(1),
|
|
2008
|
-
\temail: z.
|
|
2008
|
+
\temail: z.email(),
|
|
2009
2009
|
\trole: z.enum(["admin", "member"]),
|
|
2010
2010
|
\ttoken: z.string().min(1),
|
|
2011
2011
|
\tinvitedByName: z.string().optional(),
|
|
@@ -3242,9 +3242,7 @@ export const workspaces = ${dialect.tableFunction}(
|
|
|
3242
3242
|
\t\tcreatedAt: ${column("created_at")}.notNull(),
|
|
3243
3243
|
\t\tupdatedAt: ${column("updated_at")}.notNull(),
|
|
3244
3244
|
\t},
|
|
3245
|
-
\t(table) => (
|
|
3246
|
-
\t\tslugUnique: uniqueIndex("workspaces_slug_unique").on(table.slug),
|
|
3247
|
-
\t}),
|
|
3245
|
+
\t(table) => [uniqueIndex("workspaces_slug_unique").on(table.slug)],
|
|
3248
3246
|
);
|
|
3249
3247
|
|
|
3250
3248
|
export const workspaceMembers = ${dialect.tableFunction}(
|
|
@@ -3256,12 +3254,12 @@ export const workspaceMembers = ${dialect.tableFunction}(
|
|
|
3256
3254
|
\t\trole: ${column("role")}.$type<WorkspaceRole>().notNull(),
|
|
3257
3255
|
\t\tjoinedAt: ${column("joined_at")}.notNull(),
|
|
3258
3256
|
\t},
|
|
3259
|
-
\t(table) =>
|
|
3260
|
-
\t\
|
|
3257
|
+
\t(table) => [
|
|
3258
|
+
\t\tuniqueIndex(
|
|
3261
3259
|
\t\t\t"workspace_members_workspace_user_unique",
|
|
3262
3260
|
\t\t).on(table.workspaceId, table.userId),
|
|
3263
|
-
\t\
|
|
3264
|
-
\t
|
|
3261
|
+
\t\tindex("workspace_members_user_idx").on(table.userId),
|
|
3262
|
+
\t],
|
|
3265
3263
|
);
|
|
3266
3264
|
|
|
3267
3265
|
export const workspaceInvites = ${dialect.tableFunction}(
|
|
@@ -3278,15 +3276,15 @@ export const workspaceInvites = ${dialect.tableFunction}(
|
|
|
3278
3276
|
\t\tacceptedAt: ${column("accepted_at")},
|
|
3279
3277
|
\t\tcreatedAt: ${column("created_at")}.notNull(),
|
|
3280
3278
|
\t},
|
|
3281
|
-
\t(table) =>
|
|
3282
|
-
\t\
|
|
3279
|
+
\t(table) => [
|
|
3280
|
+
\t\tuniqueIndex("workspace_invites_token_unique").on(
|
|
3283
3281
|
\t\t\ttable.token,
|
|
3284
3282
|
\t\t),
|
|
3285
|
-
\t\
|
|
3283
|
+
\t\tindex("workspace_invites_workspace_status_idx").on(
|
|
3286
3284
|
\t\t\ttable.workspaceId,
|
|
3287
3285
|
\t\t\ttable.status,
|
|
3288
3286
|
\t\t),
|
|
3289
|
-
\t
|
|
3287
|
+
\t],
|
|
3290
3288
|
);
|
|
3291
3289
|
`;
|
|
3292
3290
|
}
|
package/src/make.ts
CHANGED
|
@@ -1575,7 +1575,8 @@ const cronSecretEnvEntry = `\t\tCRON_SECRET: z.string().min(1).optional(),`;
|
|
|
1575
1575
|
|
|
1576
1576
|
// The literal APP_URL line every generated lib/env.ts ships with. CRON_SECRET
|
|
1577
1577
|
// slots in directly below it, matching the documented env shape.
|
|
1578
|
-
const cronSecretEnvAnchor = `\t\tAPP_URL: z.
|
|
1578
|
+
const cronSecretEnvAnchor = `\t\tAPP_URL: z.url().default("http://localhost:3000"),`;
|
|
1579
|
+
const legacyCronSecretEnvAnchor = `\t\tAPP_URL: z.string().url().default("http://localhost:3000"),`;
|
|
1579
1580
|
|
|
1580
1581
|
type CronSecretWiringPlan = {
|
|
1581
1582
|
files: Array<GeneratedFile & { result: "created" | "updated" }>;
|
|
@@ -1596,10 +1597,15 @@ async function planCronSecretWiring(
|
|
|
1596
1597
|
`Could not find the generated env file ${cronSecretEnvFile}. ${manualInstruction}`,
|
|
1597
1598
|
);
|
|
1598
1599
|
}
|
|
1600
|
+
const envAnchor = envSource.includes(cronSecretEnvAnchor)
|
|
1601
|
+
? cronSecretEnvAnchor
|
|
1602
|
+
: envSource.includes(legacyCronSecretEnvAnchor)
|
|
1603
|
+
? legacyCronSecretEnvAnchor
|
|
1604
|
+
: undefined;
|
|
1599
1605
|
|
|
1600
1606
|
if (/\bCRON_SECRET\b/.test(envSource)) {
|
|
1601
1607
|
plan.skippedFiles.push(cronSecretEnvFile);
|
|
1602
|
-
} else if (
|
|
1608
|
+
} else if (envAnchor === undefined) {
|
|
1603
1609
|
throw new Error(
|
|
1604
1610
|
`Could not find the generated APP_URL server entry in ${cronSecretEnvFile}. ${manualInstruction}`,
|
|
1605
1611
|
);
|
|
@@ -1607,8 +1613,8 @@ async function planCronSecretWiring(
|
|
|
1607
1613
|
plan.files.push({
|
|
1608
1614
|
path: cronSecretEnvFile,
|
|
1609
1615
|
content: envSource.replace(
|
|
1610
|
-
|
|
1611
|
-
`${
|
|
1616
|
+
envAnchor,
|
|
1617
|
+
`${envAnchor}\n${cronSecretEnvEntry}`,
|
|
1612
1618
|
),
|
|
1613
1619
|
result: "updated",
|
|
1614
1620
|
});
|
|
@@ -2218,6 +2224,10 @@ export async function makeUpload(
|
|
|
2218
2224
|
dryRun: true,
|
|
2219
2225
|
},
|
|
2220
2226
|
);
|
|
2227
|
+
// Validate central registration before generating feature files or applying
|
|
2228
|
+
// provider wiring. Customized routes require an explicit manual edit rather
|
|
2229
|
+
// than a successful-looking partial generation.
|
|
2230
|
+
await updateUploadRoute(targetDir, names, config, { dryRun: true });
|
|
2221
2231
|
|
|
2222
2232
|
const result = await makeFeatureArtifact({
|
|
2223
2233
|
targetDir,
|
|
@@ -3716,7 +3726,9 @@ async function updateUploadRoute(
|
|
|
3716
3726
|
|
|
3717
3727
|
const registry = defineUploadsInitializerInfo(next, "uploadRegistry");
|
|
3718
3728
|
if (!registry) {
|
|
3719
|
-
|
|
3729
|
+
throw new Error(
|
|
3730
|
+
`Cannot register ${registryName} in ${file}: expected an uploadRegistry initialized with defineUploads({ ... }). Restore that registry shape or add ${registryKey}: ${registryName} manually before rerunning beignet make upload.`,
|
|
3731
|
+
);
|
|
3720
3732
|
}
|
|
3721
3733
|
if (!new RegExp(`\\b${registryKey}\\s*:`).test(registry.text)) {
|
|
3722
3734
|
next = `${next.slice(0, registry.end)}\t${registryKey}: ${registryName},\n${next.slice(
|
|
@@ -3912,7 +3924,7 @@ function schemasFile(
|
|
|
3912
3924
|
return `import { z } from "zod";
|
|
3913
3925
|
|
|
3914
3926
|
export const ${names.singularPascal}Schema = z.object({
|
|
3915
|
-
id: z.
|
|
3927
|
+
id: z.uuid(),
|
|
3916
3928
|
${options.tenantScoped ? `\ttenantId: z.string().min(1),\n` : ""} name: z.string().min(1),
|
|
3917
3929
|
version: z.number().int().min(1),
|
|
3918
3930
|
createdAt: z.string().datetime(),
|
|
@@ -3926,7 +3938,7 @@ const ${names.singularPascal}CursorPayloadSchema = z.object({
|
|
|
3926
3938
|
sortBy: ${names.singularPascal}SortBySchema,
|
|
3927
3939
|
sortDirection: ${names.singularPascal}SortDirectionSchema,
|
|
3928
3940
|
sortValue: z.string(),
|
|
3929
|
-
id: z.
|
|
3941
|
+
id: z.uuid(),
|
|
3930
3942
|
});
|
|
3931
3943
|
|
|
3932
3944
|
export type ${names.singularPascal}SortBy = z.infer<
|
|
@@ -4019,7 +4031,7 @@ ${
|
|
|
4019
4031
|
mode === "resource"
|
|
4020
4032
|
? `
|
|
4021
4033
|
export const ${names.singularPascal}IdInputSchema = z.object({
|
|
4022
|
-
id: z.
|
|
4034
|
+
id: z.uuid(),
|
|
4023
4035
|
});
|
|
4024
4036
|
|
|
4025
4037
|
export const Update${names.singularPascal}BodySchema = z.object({
|
|
@@ -4479,16 +4491,16 @@ export const outboxMessages = mysqlTable(
|
|
|
4479
4491
|
\t\tcreatedAt: varchar("created_at", { length: 32 }).notNull(),
|
|
4480
4492
|
\t\tupdatedAt: varchar("updated_at", { length: 32 }).notNull(),
|
|
4481
4493
|
\t},
|
|
4482
|
-
\t(table) =>
|
|
4483
|
-
\t\
|
|
4494
|
+
\t(table) => [
|
|
4495
|
+
\t\tindex("outbox_messages_available_idx").on(
|
|
4484
4496
|
\t\t\ttable.status,
|
|
4485
4497
|
\t\t\ttable.availableAt,
|
|
4486
4498
|
\t\t),
|
|
4487
|
-
\t\
|
|
4499
|
+
\t\tindex("outbox_messages_locked_idx").on(
|
|
4488
4500
|
\t\t\ttable.status,
|
|
4489
4501
|
\t\t\ttable.lockedUntil,
|
|
4490
4502
|
\t\t),
|
|
4491
|
-
\t
|
|
4503
|
+
\t],
|
|
4492
4504
|
);
|
|
4493
4505
|
`;
|
|
4494
4506
|
}
|
|
@@ -4515,16 +4527,16 @@ export const outboxMessages = ${dialect.tableFunction}(
|
|
|
4515
4527
|
\t\tcreatedAt: text("created_at").notNull(),
|
|
4516
4528
|
\t\tupdatedAt: text("updated_at").notNull(),
|
|
4517
4529
|
\t},
|
|
4518
|
-
\t(table) =>
|
|
4519
|
-
\t\
|
|
4530
|
+
\t(table) => [
|
|
4531
|
+
\t\tindex("outbox_messages_available_idx").on(
|
|
4520
4532
|
\t\t\ttable.status,
|
|
4521
4533
|
\t\t\ttable.availableAt,
|
|
4522
4534
|
\t\t),
|
|
4523
|
-
\t\
|
|
4535
|
+
\t\tindex("outbox_messages_locked_idx").on(
|
|
4524
4536
|
\t\t\ttable.status,
|
|
4525
4537
|
\t\t\ttable.lockedUntil,
|
|
4526
4538
|
\t\t),
|
|
4527
|
-
\t
|
|
4539
|
+
\t],
|
|
4528
4540
|
);
|
|
4529
4541
|
`;
|
|
4530
4542
|
}
|
|
@@ -4912,7 +4924,7 @@ const ${names.pluralCamel} = defineContractGroup()
|
|
|
4912
4924
|
});
|
|
4913
4925
|
|
|
4914
4926
|
export const ${names.singularCamel}Schema = z.object({
|
|
4915
|
-
id: z.
|
|
4927
|
+
id: z.uuid(),
|
|
4916
4928
|
name: z.string().min(1),
|
|
4917
4929
|
});
|
|
4918
4930
|
|
|
@@ -5121,19 +5133,19 @@ import { z } from "zod";
|
|
|
5121
5133
|
|
|
5122
5134
|
export const ${names.singularPascal}Created = defineEvent("${names.pluralCamel}.created", {
|
|
5123
5135
|
payload: z.object({
|
|
5124
|
-
id: z.
|
|
5136
|
+
id: z.uuid(),
|
|
5125
5137
|
}),
|
|
5126
5138
|
});
|
|
5127
5139
|
|
|
5128
5140
|
export const ${names.singularPascal}Updated = defineEvent("${names.pluralCamel}.updated", {
|
|
5129
5141
|
payload: z.object({
|
|
5130
|
-
id: z.
|
|
5142
|
+
id: z.uuid(),
|
|
5131
5143
|
}),
|
|
5132
5144
|
});
|
|
5133
5145
|
|
|
5134
5146
|
export const ${names.singularPascal}Deleted = defineEvent("${names.pluralCamel}.deleted", {
|
|
5135
5147
|
payload: z.object({
|
|
5136
|
-
id: z.
|
|
5148
|
+
id: z.uuid(),
|
|
5137
5149
|
}),
|
|
5138
5150
|
});
|
|
5139
5151
|
|
|
@@ -5209,7 +5221,7 @@ function eventFile(names: EventNames): string {
|
|
|
5209
5221
|
import { z } from "zod";
|
|
5210
5222
|
|
|
5211
5223
|
export const ${names.payloadSchemaName} = z.object({
|
|
5212
|
-
\tid: z.
|
|
5224
|
+
\tid: z.uuid(),
|
|
5213
5225
|
});
|
|
5214
5226
|
|
|
5215
5227
|
export type ${names.payloadTypeName} = z.infer<typeof ${names.payloadSchemaName}>;
|
|
@@ -5226,7 +5238,7 @@ import { z } from "zod";
|
|
|
5226
5238
|
import { defineJob } from "${aliasModule(config.paths.jobsBuilder)}";
|
|
5227
5239
|
|
|
5228
5240
|
export const ${names.payloadSchemaName} = z.object({
|
|
5229
|
-
\tid: z.
|
|
5241
|
+
\tid: z.uuid(),
|
|
5230
5242
|
});
|
|
5231
5243
|
|
|
5232
5244
|
export type ${names.payloadTypeName} = z.infer<typeof ${names.payloadSchemaName}>;
|
|
@@ -5317,9 +5329,9 @@ import { z } from "zod";
|
|
|
5317
5329
|
import { defineNotification } from "${aliasModule(config.paths.notificationsBuilder)}";
|
|
5318
5330
|
|
|
5319
5331
|
export const ${names.payloadSchemaName} = z.object({
|
|
5320
|
-
\tid: z.
|
|
5332
|
+
\tid: z.uuid(),
|
|
5321
5333
|
\tsubject: z.string(),
|
|
5322
|
-
\trecipientEmail: z.
|
|
5334
|
+
\trecipientEmail: z.email(),
|
|
5323
5335
|
});
|
|
5324
5336
|
|
|
5325
5337
|
export type ${names.payloadTypeName} = z.infer<typeof ${names.payloadSchemaName}>;
|
package/src/mcp.ts
CHANGED
|
@@ -5,9 +5,28 @@ import { z } from "zod";
|
|
|
5
5
|
import { mapApp, projectAppMap } from "./app-map.js";
|
|
6
6
|
import { appMapNodeKinds } from "./app-map-schema.js";
|
|
7
7
|
import { checkApp } from "./check.js";
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
databaseCommandChoices,
|
|
10
|
+
databaseSchemaDialectChoices,
|
|
11
|
+
databaseSchemaTableChoices,
|
|
12
|
+
doctorFixOperationIds,
|
|
13
|
+
type ProviderPresetName,
|
|
14
|
+
providerPresetChoices,
|
|
15
|
+
} from "./choices.js";
|
|
16
|
+
import {
|
|
17
|
+
defaultDatabaseCommandMaxOutputBytes,
|
|
18
|
+
defaultDatabaseCommandTimeoutMs,
|
|
19
|
+
runDatabaseCommand,
|
|
20
|
+
syncDatabaseSchema,
|
|
21
|
+
} from "./db.js";
|
|
9
22
|
import { explainApp, explainTargetKinds } from "./explain.js";
|
|
10
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
applyDoctorFixesWithResult,
|
|
25
|
+
applyDoctorFixPlan,
|
|
26
|
+
createDoctorFixInspectionResult,
|
|
27
|
+
inspectApp,
|
|
28
|
+
planDoctorFixes,
|
|
29
|
+
} from "./inspect.js";
|
|
11
30
|
import { lintApp } from "./lint.js";
|
|
12
31
|
import {
|
|
13
32
|
type MakeResourceResult,
|
|
@@ -379,14 +398,14 @@ export function buildBeignetMcpServer(options: McpServerOptions): McpServer {
|
|
|
379
398
|
"explain",
|
|
380
399
|
{
|
|
381
400
|
description:
|
|
382
|
-
"Explain one mapped Beignet
|
|
401
|
+
"Explain one mapped Beignet concept or diagnostic using deterministic source evidence. Supports every app-map node kind and returns relationships, relevant conventions, findings, suggested files, and follow-up commands without changing the app.",
|
|
383
402
|
inputSchema: {
|
|
384
403
|
kind: z.enum(explainTargetKinds).describe("Mapped concept to explain."),
|
|
385
404
|
target: z
|
|
386
405
|
.string()
|
|
387
406
|
.min(1)
|
|
388
407
|
.describe(
|
|
389
|
-
"
|
|
408
|
+
"Stable ID, runtime name, declaration name, source selector, applicable concept alias, or diagnostic code.",
|
|
390
409
|
),
|
|
391
410
|
},
|
|
392
411
|
annotations: { readOnlyHint: true },
|
|
@@ -441,6 +460,107 @@ export function buildBeignetMcpServer(options: McpServerOptions): McpServer {
|
|
|
441
460
|
),
|
|
442
461
|
);
|
|
443
462
|
|
|
463
|
+
server.registerTool(
|
|
464
|
+
"db",
|
|
465
|
+
{
|
|
466
|
+
description:
|
|
467
|
+
"Run one app-owned database lifecycle command and return exactly the versioned beignet db <command> --json result. Supports generate, migrate, seed, and reset; captures a bounded output tail, stops after the configured timeout, and cancels the complete child process tree with the MCP request. Dry runs validate prerequisites and report the command without executing it.",
|
|
468
|
+
inputSchema: {
|
|
469
|
+
command: z
|
|
470
|
+
.enum(databaseCommandChoices)
|
|
471
|
+
.describe("Database lifecycle command to run."),
|
|
472
|
+
dryRun: z
|
|
473
|
+
.boolean()
|
|
474
|
+
.optional()
|
|
475
|
+
.describe(
|
|
476
|
+
"Validate prerequisites and report the app-owned script without executing it. This does not simulate SQL or data changes.",
|
|
477
|
+
),
|
|
478
|
+
timeoutMs: z
|
|
479
|
+
.number()
|
|
480
|
+
.int()
|
|
481
|
+
.min(1_000)
|
|
482
|
+
.max(60 * 60 * 1_000)
|
|
483
|
+
.optional()
|
|
484
|
+
.describe(
|
|
485
|
+
"Maximum command duration in milliseconds. Defaults to 600000 (10 minutes).",
|
|
486
|
+
),
|
|
487
|
+
},
|
|
488
|
+
annotations: {
|
|
489
|
+
readOnlyHint: false,
|
|
490
|
+
destructiveHint: true,
|
|
491
|
+
idempotentHint: false,
|
|
492
|
+
openWorldHint: true,
|
|
493
|
+
},
|
|
494
|
+
},
|
|
495
|
+
async (input, extra) =>
|
|
496
|
+
safeToolResult(async () =>
|
|
497
|
+
jsonResult(
|
|
498
|
+
await runDatabaseCommand({
|
|
499
|
+
command: input.command,
|
|
500
|
+
cwd,
|
|
501
|
+
captureOutput: true,
|
|
502
|
+
maxOutputBytes: defaultDatabaseCommandMaxOutputBytes,
|
|
503
|
+
signal: extra.signal,
|
|
504
|
+
timeoutMs: input.timeoutMs ?? defaultDatabaseCommandTimeoutMs,
|
|
505
|
+
dryRun: input.dryRun,
|
|
506
|
+
}),
|
|
507
|
+
),
|
|
508
|
+
),
|
|
509
|
+
);
|
|
510
|
+
|
|
511
|
+
server.registerTool(
|
|
512
|
+
"db_schema_sync",
|
|
513
|
+
{
|
|
514
|
+
description:
|
|
515
|
+
"Idempotently sync app-owned Drizzle schema re-exports for Beignet provider tables and return exactly the versioned beignet db schema sync --json result. Supports dry-run planning and never generates or applies SQL migrations.",
|
|
516
|
+
inputSchema: {
|
|
517
|
+
dialect: z
|
|
518
|
+
.enum(databaseSchemaDialectChoices)
|
|
519
|
+
.optional()
|
|
520
|
+
.describe(
|
|
521
|
+
"Drizzle dialect. Inferred from registered providers or drizzle.config.* when omitted.",
|
|
522
|
+
),
|
|
523
|
+
tables: z
|
|
524
|
+
.array(z.enum(databaseSchemaTableChoices))
|
|
525
|
+
.min(1)
|
|
526
|
+
.optional()
|
|
527
|
+
.describe(
|
|
528
|
+
"Beignet provider tables to re-export. Defaults to audit, idempotency, and outbox.",
|
|
529
|
+
),
|
|
530
|
+
output: z
|
|
531
|
+
.string()
|
|
532
|
+
.min(1)
|
|
533
|
+
.optional()
|
|
534
|
+
.describe(
|
|
535
|
+
"App-relative schema output. Defaults to infra/db/schema/beignet.ts.",
|
|
536
|
+
),
|
|
537
|
+
dryRun: z
|
|
538
|
+
.boolean()
|
|
539
|
+
.optional()
|
|
540
|
+
.describe("Preview schema source changes without writing files."),
|
|
541
|
+
},
|
|
542
|
+
annotations: {
|
|
543
|
+
readOnlyHint: false,
|
|
544
|
+
destructiveHint: true,
|
|
545
|
+
idempotentHint: true,
|
|
546
|
+
openWorldHint: false,
|
|
547
|
+
},
|
|
548
|
+
},
|
|
549
|
+
async (input, extra) =>
|
|
550
|
+
safeToolResult(async () =>
|
|
551
|
+
jsonResult(
|
|
552
|
+
await syncDatabaseSchema({
|
|
553
|
+
cwd,
|
|
554
|
+
dialect: input.dialect,
|
|
555
|
+
tables: input.tables,
|
|
556
|
+
output: input.output,
|
|
557
|
+
dryRun: input.dryRun,
|
|
558
|
+
signal: extra.signal,
|
|
559
|
+
}),
|
|
560
|
+
),
|
|
561
|
+
),
|
|
562
|
+
);
|
|
563
|
+
|
|
444
564
|
server.registerTool(
|
|
445
565
|
"routes",
|
|
446
566
|
{
|
|
@@ -469,7 +589,7 @@ export function buildBeignetMcpServer(options: McpServerOptions): McpServer {
|
|
|
469
589
|
"doctor",
|
|
470
590
|
{
|
|
471
591
|
description:
|
|
472
|
-
"Check app wiring and Beignet conventions, returning diagnostics
|
|
592
|
+
"Check app wiring and Beignet conventions, returning diagnostics and the detected convention as JSON. Strict mode (the default) is the CI bar and includes CI-oriented warnings. Read-only; use doctor_fix_plan before a guarded doctor_fix repair.",
|
|
473
593
|
inputSchema: {
|
|
474
594
|
strict: z
|
|
475
595
|
.boolean()
|
|
@@ -489,28 +609,82 @@ export function buildBeignetMcpServer(options: McpServerOptions): McpServer {
|
|
|
489
609
|
}),
|
|
490
610
|
);
|
|
491
611
|
|
|
612
|
+
server.registerTool(
|
|
613
|
+
"doctor_fix_plan",
|
|
614
|
+
{
|
|
615
|
+
description:
|
|
616
|
+
"Plan every currently available low-risk doctor repair without changing files. Returns stable operation IDs, exact unified patches, file hashes, and a plan ID for guarded doctor_fix application.",
|
|
617
|
+
inputSchema: {
|
|
618
|
+
strict: z
|
|
619
|
+
.boolean()
|
|
620
|
+
.optional()
|
|
621
|
+
.describe("Include CI-oriented warnings. Defaults to true."),
|
|
622
|
+
},
|
|
623
|
+
annotations: {
|
|
624
|
+
readOnlyHint: true,
|
|
625
|
+
destructiveHint: false,
|
|
626
|
+
idempotentHint: true,
|
|
627
|
+
openWorldHint: false,
|
|
628
|
+
},
|
|
629
|
+
},
|
|
630
|
+
async (input) =>
|
|
631
|
+
safeToolResult(async () => {
|
|
632
|
+
return jsonResult(
|
|
633
|
+
await planDoctorFixes({ cwd, strict: input.strict ?? true }),
|
|
634
|
+
);
|
|
635
|
+
}),
|
|
636
|
+
);
|
|
637
|
+
|
|
492
638
|
server.registerTool(
|
|
493
639
|
"doctor_fix",
|
|
494
640
|
{
|
|
495
641
|
description:
|
|
496
|
-
"Apply low-risk doctor
|
|
642
|
+
"Apply low-risk doctor repairs, then re-check the app. With no planId, preserves the legacy apply-all behavior. Pass the planId returned by doctor_fix_plan for stale-file protection, optionally with fixIds to select repair operations.",
|
|
497
643
|
inputSchema: {
|
|
498
644
|
strict: z
|
|
499
645
|
.boolean()
|
|
500
646
|
.optional()
|
|
501
647
|
.describe("Include CI-oriented warnings. Defaults to true."),
|
|
648
|
+
planId: z
|
|
649
|
+
.string()
|
|
650
|
+
.min(1)
|
|
651
|
+
.optional()
|
|
652
|
+
.describe("Plan ID returned by doctor_fix_plan."),
|
|
653
|
+
fixIds: z
|
|
654
|
+
.array(z.enum(doctorFixOperationIds))
|
|
655
|
+
.min(1)
|
|
656
|
+
.optional()
|
|
657
|
+
.describe("Repair operation IDs to apply. Requires planId."),
|
|
658
|
+
},
|
|
659
|
+
annotations: {
|
|
660
|
+
readOnlyHint: false,
|
|
661
|
+
destructiveHint: true,
|
|
662
|
+
idempotentHint: true,
|
|
663
|
+
openWorldHint: false,
|
|
502
664
|
},
|
|
503
665
|
},
|
|
504
666
|
async (input) =>
|
|
505
667
|
safeToolResult(async () => {
|
|
506
668
|
const strict = input.strict ?? true;
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
669
|
+
if (input.fixIds && !input.planId) {
|
|
670
|
+
throw new Error(
|
|
671
|
+
"doctor_fix fixIds require planId from doctor_fix_plan.",
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
const applied = input.planId
|
|
675
|
+
? await applyDoctorFixPlan({
|
|
676
|
+
cwd,
|
|
677
|
+
strict,
|
|
678
|
+
planId: input.planId,
|
|
679
|
+
...(input.fixIds ? { fixIds: input.fixIds } : {}),
|
|
680
|
+
})
|
|
681
|
+
: await applyDoctorFixesWithResult({ cwd, strict });
|
|
682
|
+
return jsonResult(
|
|
683
|
+
createDoctorFixInspectionResult(
|
|
684
|
+
await inspectApp({ cwd, strict }),
|
|
685
|
+
applied,
|
|
686
|
+
),
|
|
687
|
+
);
|
|
514
688
|
}),
|
|
515
689
|
);
|
|
516
690
|
|