@beignet/cli 0.0.47 → 0.0.49

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 (144) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +126 -42
  3. package/dist/analysis/contract-factories.d.ts +17 -0
  4. package/dist/analysis/contract-factories.d.ts.map +1 -0
  5. package/dist/analysis/contract-factories.js +176 -0
  6. package/dist/analysis/contract-factories.js.map +1 -0
  7. package/dist/analysis/layers.d.ts +5 -0
  8. package/dist/analysis/layers.d.ts.map +1 -0
  9. package/dist/analysis/layers.js +172 -0
  10. package/dist/analysis/layers.js.map +1 -0
  11. package/dist/analysis/port-wiring.d.ts +23 -0
  12. package/dist/analysis/port-wiring.d.ts.map +1 -0
  13. package/dist/analysis/port-wiring.js +379 -0
  14. package/dist/analysis/port-wiring.js.map +1 -0
  15. package/dist/analysis/source-index.d.ts +5 -0
  16. package/dist/analysis/source-index.d.ts.map +1 -1
  17. package/dist/analysis/source-index.js +171 -42
  18. package/dist/analysis/source-index.js.map +1 -1
  19. package/dist/analysis/workspace.d.ts +10 -4
  20. package/dist/analysis/workspace.d.ts.map +1 -1
  21. package/dist/analysis/workspace.js +66 -6
  22. package/dist/analysis/workspace.js.map +1 -1
  23. package/dist/app-map.d.ts.map +1 -1
  24. package/dist/app-map.js +311 -92
  25. package/dist/app-map.js.map +1 -1
  26. package/dist/check.d.ts +8 -1
  27. package/dist/check.d.ts.map +1 -1
  28. package/dist/check.js +55 -9
  29. package/dist/check.js.map +1 -1
  30. package/dist/db.d.ts +38 -0
  31. package/dist/db.d.ts.map +1 -1
  32. package/dist/db.js +52 -0
  33. package/dist/db.js.map +1 -1
  34. package/dist/explain.js +4 -4
  35. package/dist/explain.js.map +1 -1
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +73 -6
  38. package/dist/index.js.map +1 -1
  39. package/dist/inspect.d.ts.map +1 -1
  40. package/dist/inspect.js +454 -170
  41. package/dist/inspect.js.map +1 -1
  42. package/dist/lib.d.ts +2 -2
  43. package/dist/lib.d.ts.map +1 -1
  44. package/dist/lib.js +1 -1
  45. package/dist/lib.js.map +1 -1
  46. package/dist/lint.d.ts.map +1 -1
  47. package/dist/lint.js +309 -487
  48. package/dist/lint.js.map +1 -1
  49. package/dist/make/inbox.d.ts.map +1 -1
  50. package/dist/make/inbox.js +12 -5
  51. package/dist/make/inbox.js.map +1 -1
  52. package/dist/make/payments.js +3 -3
  53. package/dist/make/payments.js.map +1 -1
  54. package/dist/make/tenancy.js +1 -1
  55. package/dist/make/tenancy.js.map +1 -1
  56. package/dist/make.d.ts.map +1 -1
  57. package/dist/make.js +144 -8
  58. package/dist/make.js.map +1 -1
  59. package/dist/mcp.d.ts +1 -1
  60. package/dist/mcp.d.ts.map +1 -1
  61. package/dist/mcp.js +56 -19
  62. package/dist/mcp.js.map +1 -1
  63. package/dist/preflight.d.ts +11 -3
  64. package/dist/preflight.d.ts.map +1 -1
  65. package/dist/preflight.js +139 -16
  66. package/dist/preflight.js.map +1 -1
  67. package/dist/provider-add.d.ts.map +1 -1
  68. package/dist/provider-add.js +149 -9
  69. package/dist/provider-add.js.map +1 -1
  70. package/dist/provider-audit.d.ts +13 -0
  71. package/dist/provider-audit.d.ts.map +1 -1
  72. package/dist/provider-audit.js +122 -8
  73. package/dist/provider-audit.js.map +1 -1
  74. package/dist/registry-edits.d.ts +7 -0
  75. package/dist/registry-edits.d.ts.map +1 -1
  76. package/dist/registry-edits.js +237 -53
  77. package/dist/registry-edits.js.map +1 -1
  78. package/dist/templates/agents.d.ts.map +1 -1
  79. package/dist/templates/agents.js +29 -7
  80. package/dist/templates/agents.js.map +1 -1
  81. package/dist/templates/base.d.ts +1 -0
  82. package/dist/templates/base.d.ts.map +1 -1
  83. package/dist/templates/base.js +20 -6
  84. package/dist/templates/base.js.map +1 -1
  85. package/dist/templates/db/index.d.ts +1 -0
  86. package/dist/templates/db/index.d.ts.map +1 -1
  87. package/dist/templates/db/index.js.map +1 -1
  88. package/dist/templates/db/migration-status.d.ts +9 -0
  89. package/dist/templates/db/migration-status.d.ts.map +1 -0
  90. package/dist/templates/db/migration-status.js +117 -0
  91. package/dist/templates/db/migration-status.js.map +1 -0
  92. package/dist/templates/db/mysql.d.ts.map +1 -1
  93. package/dist/templates/db/mysql.js +23 -0
  94. package/dist/templates/db/mysql.js.map +1 -1
  95. package/dist/templates/db/postgres.d.ts.map +1 -1
  96. package/dist/templates/db/postgres.js +21 -0
  97. package/dist/templates/db/postgres.js.map +1 -1
  98. package/dist/templates/db/sqlite.d.ts.map +1 -1
  99. package/dist/templates/db/sqlite.js +53 -0
  100. package/dist/templates/db/sqlite.js.map +1 -1
  101. package/dist/templates/index.d.ts.map +1 -1
  102. package/dist/templates/index.js +5 -0
  103. package/dist/templates/index.js.map +1 -1
  104. package/dist/templates/server.d.ts.map +1 -1
  105. package/dist/templates/server.js +2 -0
  106. package/dist/templates/server.js.map +1 -1
  107. package/dist/templates/shared.d.ts +1 -0
  108. package/dist/templates/shared.d.ts.map +1 -1
  109. package/dist/templates/shared.js +4 -2
  110. package/dist/templates/shared.js.map +1 -1
  111. package/package.json +7 -6
  112. package/skills/app-structure/SKILL.md +56 -11
  113. package/src/analysis/contract-factories.ts +256 -0
  114. package/src/analysis/layers.ts +266 -0
  115. package/src/analysis/port-wiring.ts +506 -0
  116. package/src/analysis/source-index.ts +225 -57
  117. package/src/analysis/workspace.ts +115 -6
  118. package/src/app-map.ts +418 -109
  119. package/src/check.ts +86 -10
  120. package/src/db.ts +97 -0
  121. package/src/explain.ts +4 -4
  122. package/src/index.ts +108 -7
  123. package/src/inspect.ts +659 -216
  124. package/src/lib.ts +9 -1
  125. package/src/lint.ts +393 -643
  126. package/src/make/inbox.ts +12 -5
  127. package/src/make/payments.ts +3 -3
  128. package/src/make/tenancy.ts +1 -1
  129. package/src/make.ts +225 -8
  130. package/src/mcp.ts +73 -21
  131. package/src/preflight.ts +195 -16
  132. package/src/provider-add.ts +193 -9
  133. package/src/provider-audit.ts +210 -18
  134. package/src/registry-edits.ts +313 -63
  135. package/src/templates/agents.ts +29 -7
  136. package/src/templates/base.ts +21 -4
  137. package/src/templates/db/index.ts +1 -0
  138. package/src/templates/db/migration-status.ts +126 -0
  139. package/src/templates/db/mysql.ts +23 -0
  140. package/src/templates/db/postgres.ts +21 -0
  141. package/src/templates/db/sqlite.ts +53 -0
  142. package/src/templates/index.ts +5 -0
  143. package/src/templates/server.ts +2 -0
  144. package/src/templates/shared.ts +4 -2
@@ -18,6 +18,7 @@ export type ProviderPackageJson = {
18
18
  dependencies?: Record<string, string>;
19
19
  devDependencies?: Record<string, string>;
20
20
  peerDependencies?: Record<string, string>;
21
+ scripts?: Record<string, string>;
21
22
  };
22
23
 
23
24
  export type ProviderDoctorVariantRule = {
@@ -25,6 +26,7 @@ export type ProviderDoctorVariantRule = {
25
26
  displayName: string;
26
27
  tokens: readonly string[];
27
28
  requiredEnv: readonly string[];
29
+ requiredEnvAlternatives: readonly (readonly string[])[];
28
30
  requiredTables: readonly string[];
29
31
  registrationSeverity?: "warning" | "hint";
30
32
  };
@@ -35,6 +37,7 @@ export type ProviderDoctorRule = {
35
37
  tokens: readonly string[];
36
38
  appPorts?: readonly { name: string; type: string }[];
37
39
  requiredEnv?: readonly string[];
40
+ requiredEnvAlternatives?: readonly (readonly string[])[];
38
41
  requiredTables?: readonly string[];
39
42
  watchers?: readonly string[];
40
43
  registrationSeverity?: "warning" | "hint";
@@ -94,6 +97,14 @@ export type ProviderRequirementAudit = {
94
97
  status: ProviderAuditStatus;
95
98
  required: string[];
96
99
  missing: string[];
100
+ alternatives?: string[][];
101
+ alternativeGroups?: Array<{
102
+ name: string;
103
+ displayName: string;
104
+ status: "present" | "missing";
105
+ alternatives: string[][];
106
+ missing: string[];
107
+ }>;
97
108
  };
98
109
 
99
110
  export type ProviderAppPortsAudit = {
@@ -282,6 +293,36 @@ export async function providerDoctorRulesForInstalledPackages(
282
293
  return rules.filter((rule): rule is ProviderDoctorRule => Boolean(rule));
283
294
  }
284
295
 
296
+ export async function detectedProviderVariantsForRules(
297
+ targetDir: string,
298
+ rules: readonly ProviderDoctorRule[],
299
+ ): Promise<Map<string, ProviderDoctorVariantRule[]>> {
300
+ const variantRules = rules.filter(
301
+ (
302
+ rule,
303
+ ): rule is ProviderDoctorRule & {
304
+ variants: readonly ProviderDoctorVariantRule[];
305
+ } => rule.variants !== undefined,
306
+ );
307
+ if (variantRules.length === 0) return new Map();
308
+
309
+ const files = await listFiles(targetDir);
310
+ const config = await loadBeignetConfig(targetDir, files);
311
+ const providerEntries = await readProviderListEntries(
312
+ targetDir,
313
+ files,
314
+ config,
315
+ new Map(),
316
+ );
317
+
318
+ return new Map(
319
+ variantRules.map((rule) => [
320
+ rule.packageName,
321
+ detectedProviderVariants(rule.variants, providerEntries),
322
+ ]),
323
+ );
324
+ }
325
+
285
326
  export async function readProviderPackageMetadataSource(
286
327
  targetDir: string,
287
328
  packageName: string,
@@ -314,6 +355,7 @@ export function providerDoctorRuleFromMetadata(
314
355
  tokens: registration?.tokens ?? [],
315
356
  appPorts: metadata.appPorts ?? [],
316
357
  requiredEnv: metadata.requiredEnv ?? [],
358
+ requiredEnvAlternatives: metadata.requiredEnvAlternatives ?? [],
317
359
  requiredTables: metadata.requiredTables ?? [],
318
360
  watchers: metadata.watchers ?? [],
319
361
  registrationSeverity: registrationSeverityFromMetadata(registration),
@@ -322,6 +364,7 @@ export function providerDoctorRuleFromMetadata(
322
364
  displayName: variant.displayName ?? variant.name,
323
365
  tokens: variant.registration?.tokens ?? [],
324
366
  requiredEnv: variant.requiredEnv ?? [],
367
+ requiredEnvAlternatives: variant.requiredEnvAlternatives ?? [],
325
368
  requiredTables: variant.requiredTables ?? [],
326
369
  registrationSeverity: registrationSeverityFromMetadata(
327
370
  variant.registration,
@@ -1061,6 +1104,15 @@ function configuredProviderRequiredEnv(
1061
1104
  return envVars.filter((envVar) => !ignored.has(envVar));
1062
1105
  }
1063
1106
 
1107
+ function configuredProviderRequiredEnvAlternatives(
1108
+ alternatives: readonly (readonly string[])[],
1109
+ config: ResolvedBeignetConfig,
1110
+ ): string[][] {
1111
+ return alternatives.map((alternative) =>
1112
+ configuredProviderRequiredEnv(alternative, config),
1113
+ );
1114
+ }
1115
+
1064
1116
  function configuredProviderRequiredTables(
1065
1117
  tableNames: readonly string[],
1066
1118
  config: ResolvedBeignetConfig,
@@ -1187,19 +1239,23 @@ async function providerAuditEntryForRule(options: {
1187
1239
  const requiredEnv =
1188
1240
  options.rule.variants !== undefined
1189
1241
  ? aggregateVariantRequirement(variants, "requiredEnv")
1190
- : await requirementAudit(
1191
- configuredProviderRequiredEnv(
1242
+ : await providerEnvRequirementAudit({
1243
+ required: configuredProviderRequiredEnv(
1192
1244
  options.rule.requiredEnv ?? [],
1193
1245
  options.config,
1194
1246
  ),
1195
- (envVar) =>
1247
+ alternatives: configuredProviderRequiredEnvAlternatives(
1248
+ options.rule.requiredEnvAlternatives ?? [],
1249
+ options.config,
1250
+ ),
1251
+ exists: (envVar) =>
1196
1252
  providerRequiredEnvExists(
1197
1253
  options.targetDir,
1198
1254
  options.configFiles,
1199
1255
  envVar,
1200
1256
  options.sourceCache,
1201
1257
  ),
1202
- );
1258
+ });
1203
1259
 
1204
1260
  const requiredTables =
1205
1261
  options.rule.variants !== undefined
@@ -1288,12 +1344,19 @@ async function providerVariantAudit(options: {
1288
1344
  options.variant.requiredEnv,
1289
1345
  options.config,
1290
1346
  );
1347
+ const requiredEnvAlternatives = configuredProviderRequiredEnvAlternatives(
1348
+ options.variant.requiredEnvAlternatives,
1349
+ options.config,
1350
+ );
1291
1351
  if (!options.registered) {
1292
1352
  return {
1293
1353
  name: options.variant.name,
1294
1354
  displayName: options.variant.displayName,
1295
1355
  registration: "inactive",
1296
- requiredEnv: inactiveRequirement(requiredEnv),
1356
+ requiredEnv:
1357
+ requiredEnvAlternatives.length > 0
1358
+ ? inactiveAlternativeRequirement(requiredEnvAlternatives)
1359
+ : inactiveRequirement(requiredEnv),
1297
1360
  requiredTables: inactiveRequirement(options.variant.requiredTables),
1298
1361
  };
1299
1362
  }
@@ -1306,14 +1369,17 @@ async function providerVariantAudit(options: {
1306
1369
  options.variant.registrationSeverity,
1307
1370
  options.providerEntries,
1308
1371
  ),
1309
- requiredEnv: await requirementAudit(requiredEnv, (envVar) =>
1310
- providerRequiredEnvExists(
1311
- options.targetDir,
1312
- options.configFiles,
1313
- envVar,
1314
- options.sourceCache,
1315
- ),
1316
- ),
1372
+ requiredEnv: await providerEnvRequirementAudit({
1373
+ required: requiredEnv,
1374
+ alternatives: requiredEnvAlternatives,
1375
+ exists: (envVar) =>
1376
+ providerRequiredEnvExists(
1377
+ options.targetDir,
1378
+ options.configFiles,
1379
+ envVar,
1380
+ options.sourceCache,
1381
+ ),
1382
+ }),
1317
1383
  requiredTables: await requirementAudit(
1318
1384
  configuredProviderRequiredTables(
1319
1385
  options.variant.requiredTables,
@@ -1448,6 +1514,34 @@ async function requirementAudit(
1448
1514
  };
1449
1515
  }
1450
1516
 
1517
+ async function providerEnvRequirementAudit(options: {
1518
+ required: readonly string[];
1519
+ alternatives: readonly (readonly string[])[];
1520
+ exists: (requirement: string) => Promise<boolean>;
1521
+ }): Promise<ProviderRequirementAudit> {
1522
+ if (options.alternatives.length === 0) {
1523
+ return requirementAudit(options.required, options.exists);
1524
+ }
1525
+
1526
+ const missingAlternatives: string[][] = [];
1527
+ for (const alternative of options.alternatives) {
1528
+ const missing: string[] = [];
1529
+ for (const requirement of alternative) {
1530
+ if (await options.exists(requirement)) continue;
1531
+ missing.push(requirement);
1532
+ }
1533
+ missingAlternatives.push(missing);
1534
+ }
1535
+
1536
+ const present = missingAlternatives.some((missing) => missing.length === 0);
1537
+ return {
1538
+ status: present ? "present" : "missing",
1539
+ required: unique(options.alternatives.flat()),
1540
+ missing: present ? [] : unique(missingAlternatives.flat()),
1541
+ alternatives: options.alternatives.map((alternative) => [...alternative]),
1542
+ };
1543
+ }
1544
+
1451
1545
  function inactiveRequirement(
1452
1546
  required: readonly string[],
1453
1547
  ): ProviderRequirementAudit {
@@ -1458,6 +1552,17 @@ function inactiveRequirement(
1458
1552
  };
1459
1553
  }
1460
1554
 
1555
+ function inactiveAlternativeRequirement(
1556
+ alternatives: readonly (readonly string[])[],
1557
+ ): ProviderRequirementAudit {
1558
+ return {
1559
+ status: "inactive",
1560
+ required: unique(alternatives.flat()),
1561
+ missing: [],
1562
+ alternatives: alternatives.map((alternative) => [...alternative]),
1563
+ };
1564
+ }
1565
+
1461
1566
  function emptyRequirement(): ProviderRequirementAudit {
1462
1567
  return { status: "none", required: [], missing: [] };
1463
1568
  }
@@ -1467,21 +1572,57 @@ function aggregateVariantRequirement(
1467
1572
  key: "requiredEnv" | "requiredTables",
1468
1573
  ): ProviderRequirementAudit {
1469
1574
  const active = variants
1470
- .map((variant) => variant[key])
1471
- .filter((requirement) => requirement.status !== "inactive");
1575
+ .map((variant) => ({ variant, requirement: variant[key] }))
1576
+ .filter(({ requirement }) => requirement.status !== "inactive");
1472
1577
  if (active.length === 0)
1473
1578
  return { status: "inactive", required: [], missing: [] };
1474
1579
 
1475
1580
  const required = unique(
1476
- active.flatMap((requirement) => requirement.required),
1581
+ active.flatMap(({ requirement }) => requirement.required),
1582
+ );
1583
+ const missing = unique(
1584
+ active.flatMap(({ requirement }) => requirement.missing),
1477
1585
  );
1478
- const missing = unique(active.flatMap((requirement) => requirement.missing));
1479
1586
  if (required.length === 0) return emptyRequirement();
1480
1587
 
1588
+ const hasAlternativeRequirements = active.some(
1589
+ ({ requirement }) =>
1590
+ requirement.alternatives !== undefined ||
1591
+ requirement.alternativeGroups !== undefined,
1592
+ );
1593
+ const alternativeGroups = hasAlternativeRequirements
1594
+ ? active.flatMap(({ variant, requirement }) => {
1595
+ if (requirement.status === "none") return [];
1596
+ if (
1597
+ requirement.status !== "present" &&
1598
+ requirement.status !== "missing"
1599
+ ) {
1600
+ return [];
1601
+ }
1602
+
1603
+ return [
1604
+ {
1605
+ name: variant.name,
1606
+ displayName: variant.displayName,
1607
+ status: requirement.status,
1608
+ alternatives: (
1609
+ requirement.alternatives ?? [requirement.required]
1610
+ ).map((alternative) => [...alternative]),
1611
+ missing: [...requirement.missing],
1612
+ },
1613
+ ];
1614
+ })
1615
+ : [];
1616
+
1481
1617
  return {
1482
1618
  status: missing.length === 0 ? "present" : "missing",
1483
1619
  required,
1484
1620
  missing,
1621
+ ...(alternativeGroups.length === 1
1622
+ ? { alternatives: alternativeGroups[0]?.alternatives ?? [] }
1623
+ : alternativeGroups.length > 0
1624
+ ? { alternativeGroups }
1625
+ : {}),
1485
1626
  };
1486
1627
  }
1487
1628
 
@@ -1520,7 +1661,17 @@ function providerAuditNotes(input: {
1520
1661
  notes.push("optional provider not registered");
1521
1662
  }
1522
1663
  if (input.requiredEnv.missing.length > 0) {
1523
- notes.push(`missing env: ${input.requiredEnv.missing.join(", ")}`);
1664
+ notes.push(
1665
+ input.requiredEnv.alternativeGroups
1666
+ ? `missing env configuration groups: ${formatProviderEnvAlternativeGroups(
1667
+ input.requiredEnv.alternativeGroups,
1668
+ )}`
1669
+ : input.requiredEnv.alternatives
1670
+ ? `missing env alternative: ${formatProviderEnvAlternatives(
1671
+ input.requiredEnv.alternatives,
1672
+ )}`
1673
+ : `missing env: ${input.requiredEnv.missing.join(", ")}`,
1674
+ );
1524
1675
  }
1525
1676
  if (input.requiredTables.missing.length > 0) {
1526
1677
  notes.push(`missing tables: ${input.requiredTables.missing.join(", ")}`);
@@ -1863,6 +2014,21 @@ function escapeRegExp(value: string): string {
1863
2014
  function requirementSummary(requirement: ProviderRequirementAudit): string {
1864
2015
  if (requirement.status === "none") return "none";
1865
2016
  if (requirement.status === "inactive") return "inactive";
2017
+ if (requirement.alternativeGroups) {
2018
+ const count = requirement.alternativeGroups.length;
2019
+ const missing = requirement.alternativeGroups.filter(
2020
+ (group) => group.status === "missing",
2021
+ ).length;
2022
+ return requirement.status === "present"
2023
+ ? `${count} variant groups ok`
2024
+ : `${missing}/${count} variant groups incomplete`;
2025
+ }
2026
+ if (requirement.alternatives) {
2027
+ if (requirement.status === "present") {
2028
+ return "alternative ok";
2029
+ }
2030
+ return `${requirement.alternatives.length} alternatives missing`;
2031
+ }
1866
2032
  if (requirement.status === "present") {
1867
2033
  return `${requirement.required.length} ok`;
1868
2034
  }
@@ -1879,6 +2045,32 @@ function unique(values: readonly string[]): string[] {
1879
2045
  return [...new Set(values)];
1880
2046
  }
1881
2047
 
2048
+ export function formatProviderEnvAlternatives(
2049
+ alternatives: readonly (readonly string[])[],
2050
+ ): string {
2051
+ return alternatives
2052
+ .map((alternative) =>
2053
+ alternative.length === 1
2054
+ ? alternative[0]
2055
+ : `(${alternative.join(" + ")})`,
2056
+ )
2057
+ .join(" or ");
2058
+ }
2059
+
2060
+ function formatProviderEnvAlternativeGroups(
2061
+ groups: NonNullable<ProviderRequirementAudit["alternativeGroups"]>,
2062
+ ): string {
2063
+ return groups
2064
+ .filter((group) => group.status === "missing")
2065
+ .map(
2066
+ (group) =>
2067
+ `${group.displayName}: ${formatProviderEnvAlternatives(
2068
+ group.alternatives,
2069
+ )}`,
2070
+ )
2071
+ .join(" and ");
2072
+ }
2073
+
1882
2074
  function table(rows: string[][]): string {
1883
2075
  const widths = rows[0].map((_, columnIndex) =>
1884
2076
  Math.max(...rows.map((row) => row[columnIndex].length)),