@beignet/cli 0.0.43 → 0.0.45

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 (81) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +61 -8
  3. package/dist/choices.d.ts +4 -0
  4. package/dist/choices.d.ts.map +1 -1
  5. package/dist/choices.js +9 -0
  6. package/dist/choices.js.map +1 -1
  7. package/dist/db.d.ts.map +1 -1
  8. package/dist/db.js +8 -4
  9. package/dist/db.js.map +1 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +13 -13
  12. package/dist/index.js.map +1 -1
  13. package/dist/inspect.js +78 -21
  14. package/dist/inspect.js.map +1 -1
  15. package/dist/lib.d.ts +4 -1
  16. package/dist/lib.d.ts.map +1 -1
  17. package/dist/lib.js +1 -1
  18. package/dist/lib.js.map +1 -1
  19. package/dist/mcp.d.ts +2 -1
  20. package/dist/mcp.d.ts.map +1 -1
  21. package/dist/mcp.js +354 -3
  22. package/dist/mcp.js.map +1 -1
  23. package/dist/operational-lifecycle.d.ts +12 -0
  24. package/dist/operational-lifecycle.d.ts.map +1 -0
  25. package/dist/operational-lifecycle.js +39 -0
  26. package/dist/operational-lifecycle.js.map +1 -0
  27. package/dist/operational-path.d.ts +3 -0
  28. package/dist/operational-path.d.ts.map +1 -0
  29. package/dist/operational-path.js +26 -0
  30. package/dist/operational-path.js.map +1 -0
  31. package/dist/operational-process.d.ts +78 -0
  32. package/dist/operational-process.d.ts.map +1 -0
  33. package/dist/operational-process.js +228 -0
  34. package/dist/operational-process.js.map +1 -0
  35. package/dist/operational-runner.d.ts +2 -0
  36. package/dist/operational-runner.d.ts.map +1 -0
  37. package/dist/operational-runner.js +168 -0
  38. package/dist/operational-runner.js.map +1 -0
  39. package/dist/outbox.d.ts +14 -6
  40. package/dist/outbox.d.ts.map +1 -1
  41. package/dist/outbox.js +140 -124
  42. package/dist/outbox.js.map +1 -1
  43. package/dist/schedule.d.ts +2 -1
  44. package/dist/schedule.d.ts.map +1 -1
  45. package/dist/schedule.js +79 -81
  46. package/dist/schedule.js.map +1 -1
  47. package/dist/task.d.ts +2 -1
  48. package/dist/task.d.ts.map +1 -1
  49. package/dist/task.js +57 -61
  50. package/dist/task.js.map +1 -1
  51. package/dist/templates/agents.d.ts.map +1 -1
  52. package/dist/templates/agents.js +21 -8
  53. package/dist/templates/agents.js.map +1 -1
  54. package/dist/templates/base.d.ts.map +1 -1
  55. package/dist/templates/base.js +2 -0
  56. package/dist/templates/base.js.map +1 -1
  57. package/dist/templates/server.d.ts.map +1 -1
  58. package/dist/templates/server.js +9 -2
  59. package/dist/templates/server.js.map +1 -1
  60. package/dist/templates/shadcn.d.ts.map +1 -1
  61. package/dist/templates/shadcn.js +3 -1
  62. package/dist/templates/shadcn.js.map +1 -1
  63. package/package.json +2 -2
  64. package/skills/app-structure/SKILL.md +19 -6
  65. package/src/choices.ts +19 -0
  66. package/src/db.ts +8 -4
  67. package/src/index.ts +19 -16
  68. package/src/inspect.ts +114 -26
  69. package/src/lib.ts +27 -1
  70. package/src/mcp.ts +457 -2
  71. package/src/operational-lifecycle.ts +56 -0
  72. package/src/operational-path.ts +35 -0
  73. package/src/operational-process.ts +454 -0
  74. package/src/operational-runner.ts +221 -0
  75. package/src/outbox.ts +154 -128
  76. package/src/schedule.ts +84 -89
  77. package/src/task.ts +58 -62
  78. package/src/templates/agents.ts +21 -8
  79. package/src/templates/base.ts +2 -0
  80. package/src/templates/server.ts +9 -2
  81. package/src/templates/shadcn.ts +3 -1
package/src/inspect.ts CHANGED
@@ -2347,6 +2347,10 @@ async function inspectProductionReadiness(
2347
2347
  packageJson,
2348
2348
  );
2349
2349
  const configFiles = operationalConfigFiles(files, config);
2350
+ const cronDirectory = path.posix.join(
2351
+ directoryPath(config.paths.routes),
2352
+ "cron",
2353
+ );
2350
2354
  const infrastructurePath = directoryPath(
2351
2355
  path.dirname(config.paths.portWiring),
2352
2356
  );
@@ -2380,16 +2384,17 @@ async function inspectProductionReadiness(
2380
2384
  }
2381
2385
 
2382
2386
  if (
2383
- file.startsWith("app/api/cron/") &&
2387
+ fileWithinDirectory(file, cronDirectory) &&
2384
2388
  file.endsWith("/route.ts") &&
2385
2389
  !/\bCRON_SECRET\b/.test(source) &&
2386
- !/\bcreateOutboxDrainRoute\s*\(/.test(source)
2390
+ !/\bcreateOutboxDrainRoute\s*\(/.test(source) &&
2391
+ !/\bcreateScheduleRoute\s*\(/.test(source)
2387
2392
  ) {
2388
2393
  diagnostics.push({
2389
2394
  severity: "warning",
2390
2395
  code: "BEIGNET_CRON_SECRET_MISSING",
2391
2396
  file,
2392
- message: `${file} looks like a cron route that does not reference CRON_SECRET. Protect cron entrypoints with a shared secret or a framework helper such as createOutboxDrainRoute(...).`,
2397
+ message: `${file} looks like a cron route that does not reference CRON_SECRET. Protect cron entrypoints with a shared secret or a framework helper such as createOutboxDrainRoute(...) or createScheduleRoute(...).`,
2393
2398
  });
2394
2399
  }
2395
2400
 
@@ -3882,9 +3887,15 @@ function isInfraOrServerFile(
3882
3887
  }
3883
3888
 
3884
3889
  function containsCallExpression(source: string, name: string): boolean {
3885
- return new RegExp(
3890
+ const codeIndexes = new Set(codeCharacterIndexes(source));
3891
+ const pattern = new RegExp(
3886
3892
  `\\b${escapeRegExp(name)}\\s*(?:<[^;=(){}]*>\\s*)?\\(`,
3887
- ).test(source);
3893
+ "g",
3894
+ );
3895
+
3896
+ return [...source.matchAll(pattern)].some(
3897
+ (match) => match.index !== undefined && codeIndexes.has(match.index),
3898
+ );
3888
3899
  }
3889
3900
 
3890
3901
  type WorkflowRegistryKind =
@@ -4607,6 +4618,8 @@ async function inspectServerlessFootguns(
4607
4618
  convention: InspectConvention,
4608
4619
  ): Promise<InspectDiagnostic[]> {
4609
4620
  const diagnostics: InspectDiagnostic[] = [];
4621
+ const routeDirectory = directoryPath(config.paths.routes);
4622
+ const cronDirectory = path.posix.join(routeDirectory, "cron");
4610
4623
 
4611
4624
  for (const file of files) {
4612
4625
  if (
@@ -4617,12 +4630,9 @@ async function inspectServerlessFootguns(
4617
4630
  continue;
4618
4631
  }
4619
4632
 
4620
- const isInfraOrServerFile =
4621
- file.startsWith("infra/") || file.startsWith("server/");
4622
- const isProviderFile =
4623
- /(^|\/)provider(s)?\.ts$/.test(file) ||
4624
- /(^|\/)[^/]*provider[^/]*\.ts$/.test(file);
4625
4633
  const source = await readFile(path.join(targetDir, file), "utf8");
4634
+ const isInfraOrServerFile = isRuntimeFile(file, config);
4635
+ const isProviderFile = isProviderLifecycleFile(file, source);
4626
4636
 
4627
4637
  if (
4628
4638
  config.framework === "next" &&
@@ -4666,7 +4676,7 @@ async function inspectServerlessFootguns(
4666
4676
  }
4667
4677
 
4668
4678
  if (
4669
- file.startsWith("app/api/cron/") &&
4679
+ fileWithinDirectory(file, cronDirectory) &&
4670
4680
  file.endsWith("/route.ts") &&
4671
4681
  !/\bauthorization\b/i.test(source) &&
4672
4682
  !/\bcreateOutboxDrainRoute\s*\(/.test(source) &&
@@ -4682,8 +4692,8 @@ async function inspectServerlessFootguns(
4682
4692
  }
4683
4693
 
4684
4694
  if (
4685
- hasOutboxRegistry(files) &&
4686
- !(await appHasOutboxDrainEntrypoint(targetDir, files))
4695
+ hasOutboxRegistry(files, config) &&
4696
+ !(await appHasOutboxDrainEntrypoint(targetDir, files, config))
4687
4697
  ) {
4688
4698
  diagnostics.push({
4689
4699
  severity: "warning",
@@ -4696,6 +4706,82 @@ async function inspectServerlessFootguns(
4696
4706
  return diagnostics;
4697
4707
  }
4698
4708
 
4709
+ function configuredRuntimeFiles(config: ResolvedBeignetConfig): string[] {
4710
+ return [
4711
+ config.paths.server,
4712
+ config.paths.listeners,
4713
+ config.paths.tasks,
4714
+ config.paths.outbox,
4715
+ config.paths.schedules,
4716
+ config.paths.portWiring,
4717
+ ];
4718
+ }
4719
+
4720
+ function configuredRuntimeDirectories(config: ResolvedBeignetConfig): string[] {
4721
+ const applicationDirectories = configuredApplicationDirectories(config);
4722
+
4723
+ return configuredRuntimeFiles(config)
4724
+ .map((file) => directoryPath(path.posix.dirname(file)))
4725
+ .filter((directory) => directory !== ".")
4726
+ .filter(
4727
+ (directory) =>
4728
+ !applicationDirectories.some(
4729
+ (applicationDirectory) =>
4730
+ applicationDirectory !== directory &&
4731
+ fileWithinDirectory(applicationDirectory, directory),
4732
+ ),
4733
+ )
4734
+ .filter((directory, index, all) => all.indexOf(directory) === index);
4735
+ }
4736
+
4737
+ function configuredApplicationDirectories(
4738
+ config: ResolvedBeignetConfig,
4739
+ ): string[] {
4740
+ return [
4741
+ config.paths.contracts,
4742
+ config.paths.routes,
4743
+ config.paths.features,
4744
+ config.paths.policies,
4745
+ config.paths.useCases,
4746
+ config.paths.tests,
4747
+ ]
4748
+ .map(directoryPath)
4749
+ .filter((directory) => directory !== ".")
4750
+ .filter((directory, index, all) => all.indexOf(directory) === index);
4751
+ }
4752
+
4753
+ function isRuntimeFile(file: string, config: ResolvedBeignetConfig): boolean {
4754
+ if (configuredRuntimeFiles(config).includes(file)) return true;
4755
+ if (
4756
+ configuredApplicationDirectories(config).some((directory) =>
4757
+ fileWithinDirectory(file, directory),
4758
+ )
4759
+ ) {
4760
+ return false;
4761
+ }
4762
+
4763
+ return (
4764
+ fileWithinDirectory(file, "infra") ||
4765
+ fileWithinDirectory(file, "server") ||
4766
+ configuredRuntimeDirectories(config).some((directory) =>
4767
+ fileWithinDirectory(file, directory),
4768
+ )
4769
+ );
4770
+ }
4771
+
4772
+ function fileWithinDirectory(file: string, directory: string): boolean {
4773
+ return directory === "." || file.startsWith(`${directory}/`);
4774
+ }
4775
+
4776
+ function isProviderLifecycleFile(file: string, source?: string): boolean {
4777
+ return (
4778
+ /(^|\/)provider(s)?\.ts$/.test(file) ||
4779
+ /(^|\/)[^/]*provider[^/]*\.ts$/.test(file) ||
4780
+ /(^|\/)providers?\//.test(file) ||
4781
+ (source !== undefined && containsCallExpression(source, "createProvider"))
4782
+ );
4783
+ }
4784
+
4699
4785
  function isNextRouteFile(file: string, config: ResolvedBeignetConfig): boolean {
4700
4786
  const routesPath = directoryPath(config.paths.routes);
4701
4787
 
@@ -4727,33 +4813,35 @@ function importsEagerServer(
4727
4813
  return false;
4728
4814
  }
4729
4815
 
4730
- function hasOutboxRegistry(files: string[]): boolean {
4731
- return files.some(isOutboxRegistryFile);
4732
- }
4733
-
4734
- function isOutboxRegistryFile(file: string): boolean {
4735
- return file === "server/outbox.ts";
4816
+ function hasOutboxRegistry(
4817
+ files: string[],
4818
+ config: ResolvedBeignetConfig,
4819
+ ): boolean {
4820
+ return files.includes(config.paths.outbox);
4736
4821
  }
4737
4822
 
4738
4823
  async function appHasOutboxDrainEntrypoint(
4739
4824
  targetDir: string,
4740
4825
  files: string[],
4826
+ config: ResolvedBeignetConfig,
4741
4827
  ): Promise<boolean> {
4828
+ const routesDirectory = directoryPath(config.paths.routes);
4829
+
4742
4830
  for (const file of files) {
4743
4831
  if (!file.endsWith(".ts") || file.endsWith(".test.ts")) continue;
4744
4832
  if (
4745
- !file.startsWith("app/api/") &&
4746
- !file.startsWith("server/") &&
4747
- !file.startsWith("infra/")
4833
+ !fileWithinDirectory(file, routesDirectory) &&
4834
+ !isRuntimeFile(file, config)
4748
4835
  ) {
4749
4836
  continue;
4750
4837
  }
4751
4838
 
4752
4839
  const source = await readFile(path.join(targetDir, file), "utf8");
4753
- if (
4754
- /\bcreateOutboxDrainRoute\s*\(/.test(source) ||
4755
- /\bdrainOutbox\s*\(/.test(source)
4756
- ) {
4840
+ if (containsCallExpression(source, "createOutboxDrainRoute")) {
4841
+ return true;
4842
+ }
4843
+ if (isProviderLifecycleFile(file, source)) continue;
4844
+ if (containsCallExpression(source, "drainOutbox")) {
4757
4845
  return true;
4758
4846
  }
4759
4847
  }
package/src/lib.ts CHANGED
@@ -103,7 +103,33 @@ export {
103
103
  makeUpload,
104
104
  makeUseCase,
105
105
  } from "./make.js";
106
- export { runOutboxDrain } from "./outbox.js";
106
+ export type {
107
+ RunOutboxDrainOptions,
108
+ RunOutboxDrainResult,
109
+ RunOutboxListOptions,
110
+ RunOutboxListResult,
111
+ RunOutboxPruneOptions,
112
+ RunOutboxPruneResult,
113
+ RunOutboxPurgeOptions,
114
+ RunOutboxPurgeResult,
115
+ RunOutboxRequeueOptions,
116
+ RunOutboxRequeueResult,
117
+ RunOutboxShowOptions,
118
+ RunOutboxShowResult,
119
+ } from "./outbox.js";
120
+ export {
121
+ runOutboxDrain,
122
+ runOutboxList,
123
+ runOutboxPrune,
124
+ runOutboxPurge,
125
+ runOutboxRequeue,
126
+ runOutboxShow,
127
+ } from "./outbox.js";
128
+ export type {
129
+ RunAppScheduleOptions,
130
+ RunAppScheduleResult,
131
+ } from "./schedule.js";
107
132
  export { runAppSchedule } from "./schedule.js";
133
+ export type { RunAppTaskOptions, RunAppTaskResult } from "./task.js";
108
134
  export { runAppTask } from "./task.js";
109
135
  export type { StarterProviderName } from "./templates/index.js";