@beignet/cli 0.0.48 → 0.0.50
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 +54 -0
- package/README.md +117 -22
- package/dist/analysis/contract-factories.d.ts +17 -0
- package/dist/analysis/contract-factories.d.ts.map +1 -0
- package/dist/analysis/contract-factories.js +176 -0
- package/dist/analysis/contract-factories.js.map +1 -0
- package/dist/analysis/layers.d.ts +5 -0
- package/dist/analysis/layers.d.ts.map +1 -0
- package/dist/analysis/layers.js +172 -0
- package/dist/analysis/layers.js.map +1 -0
- package/dist/analysis/port-wiring.d.ts +23 -0
- package/dist/analysis/port-wiring.d.ts.map +1 -0
- package/dist/analysis/port-wiring.js +379 -0
- package/dist/analysis/port-wiring.js.map +1 -0
- package/dist/analysis/source-index.d.ts +5 -0
- package/dist/analysis/source-index.d.ts.map +1 -1
- package/dist/analysis/source-index.js +171 -42
- package/dist/analysis/source-index.js.map +1 -1
- package/dist/analysis/workspace.d.ts +11 -4
- package/dist/analysis/workspace.d.ts.map +1 -1
- package/dist/analysis/workspace.js +78 -8
- package/dist/analysis/workspace.js.map +1 -1
- package/dist/app-map-changes.d.ts +103 -0
- package/dist/app-map-changes.d.ts.map +1 -0
- package/dist/app-map-changes.js +949 -0
- package/dist/app-map-changes.js.map +1 -0
- package/dist/app-map.d.ts.map +1 -1
- package/dist/app-map.js +311 -92
- package/dist/app-map.js.map +1 -1
- package/dist/check.js +37 -3
- package/dist/check.js.map +1 -1
- package/dist/explain.js +4 -4
- package/dist/explain.js.map +1 -1
- package/dist/git-changes.d.ts +30 -0
- package/dist/git-changes.d.ts.map +1 -0
- package/dist/git-changes.js +367 -0
- package/dist/git-changes.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -1
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.ts.map +1 -1
- package/dist/inspect.js +706 -186
- package/dist/inspect.js.map +1 -1
- package/dist/lib.d.ts +3 -0
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +1 -0
- package/dist/lib.js.map +1 -1
- package/dist/lint.d.ts.map +1 -1
- package/dist/lint.js +309 -487
- package/dist/lint.js.map +1 -1
- package/dist/make/inbox.d.ts.map +1 -1
- package/dist/make/inbox.js +11 -4
- package/dist/make/inbox.js.map +1 -1
- package/dist/make/payments.js +2 -2
- package/dist/make/shared.d.ts.map +1 -1
- package/dist/make/shared.js +31 -27
- package/dist/make/shared.js.map +1 -1
- package/dist/make.d.ts.map +1 -1
- package/dist/make.js +144 -8
- package/dist/make.js.map +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +43 -21
- package/dist/mcp.js.map +1 -1
- package/dist/provider-add.d.ts.map +1 -1
- package/dist/provider-add.js +142 -7
- package/dist/provider-add.js.map +1 -1
- package/dist/registry-edits.d.ts +7 -0
- package/dist/registry-edits.d.ts.map +1 -1
- package/dist/registry-edits.js +237 -53
- package/dist/registry-edits.js.map +1 -1
- package/dist/templates/agents.d.ts.map +1 -1
- package/dist/templates/agents.js +37 -1
- package/dist/templates/agents.js.map +1 -1
- package/dist/templates/base.d.ts.map +1 -1
- package/dist/templates/base.js +13 -2
- package/dist/templates/base.js.map +1 -1
- package/dist/templates/server.d.ts.map +1 -1
- package/dist/templates/server.js +2 -0
- package/dist/templates/server.js.map +1 -1
- package/dist/templates/shared.d.ts +1 -0
- package/dist/templates/shared.d.ts.map +1 -1
- package/dist/templates/shared.js +3 -2
- package/dist/templates/shared.js.map +1 -1
- package/package.json +7 -6
- package/skills/app-structure/SKILL.md +71 -7
- package/src/analysis/contract-factories.ts +256 -0
- package/src/analysis/layers.ts +266 -0
- package/src/analysis/port-wiring.ts +506 -0
- package/src/analysis/source-index.ts +225 -57
- package/src/analysis/workspace.ts +134 -9
- package/src/app-map-changes.ts +1462 -0
- package/src/app-map.ts +418 -109
- package/src/check.ts +51 -3
- package/src/explain.ts +4 -4
- package/src/git-changes.ts +511 -0
- package/src/index.ts +39 -1
- package/src/inspect.ts +1005 -238
- package/src/lib.ts +21 -0
- package/src/lint.ts +393 -643
- package/src/make/inbox.ts +11 -4
- package/src/make/payments.ts +2 -2
- package/src/make/shared.ts +31 -27
- package/src/make.ts +225 -8
- package/src/mcp.ts +51 -24
- package/src/provider-add.ts +186 -7
- package/src/registry-edits.ts +313 -63
- package/src/templates/agents.ts +37 -1
- package/src/templates/base.ts +13 -2
- package/src/templates/server.ts +2 -0
- package/src/templates/shared.ts +3 -2
package/dist/make.js
CHANGED
|
@@ -2,6 +2,8 @@ import { randomBytes } from "node:crypto";
|
|
|
2
2
|
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import ts from "typescript";
|
|
5
|
+
import { analyzePortWiringFiles } from "./analysis/port-wiring.js";
|
|
6
|
+
import { listProjectFiles } from "./analysis/workspace.js";
|
|
5
7
|
import { clientFormsPath, clientIndexPath, loadBeignetConfig, resolveConfig, } from "./config.js";
|
|
6
8
|
import { assertNextFramework } from "./framework.js";
|
|
7
9
|
import { adapterFilePath, addNamedImport, addNamedTypeImport, aliasModule, appendDeferredPortKey, appendPickStringLiteralMember, applyPortProviderWiring, assertAdapterApp, assertFeatureArtifactApp, assertFeatureUiApp, assertGeneratedIdentifiers, assertPersistenceArtifactApp, assertPolicyApp, assertPortApp, assertServerRuntimeApp, assertStandardApp, assertTestApp, assertUseCaseApp, beignetDependencyVersion, constantCase, createListenersRegistrySource, defineUploadsInitializerInfo, detectResourceDatabase, detectResourcePersistence, drizzleDialects, drizzleRepositoriesPath, drizzleResourceRepositoryFilePath, drizzleSchemaIndexPath, eventBusPortWiring, eventFilePath, factoryFilePath, featureArtifactDir, featureArtifactIndexFile, featureArtifactNames, featureResourceNames, featureUiClientQueriesFilePath, featureUiComponentFilePath, featureUiIndexFilePath, featureUiNames, fileExists, hasTopLevelObjectProperty, identifierNames, infrastructureDir, insertTypeProperty, jobFilePath, listenerFilePath, listenersFilePath, mergeMakeResultInto, mergeMakeResults, missingCapabilityBuilderFiles, notificationFilePath, notificationPortWirings, planGeneratedFile, planGeneratedFiles, portFilePath, portNames, providersFilePath, readOptionalFile, relativeModule, resourceContractFilePath, resourceFeatureDir, resourceNames, resourcePortFilePath, resourceSharedErrorsPath, scheduleFilePath, seedEntrypointPath, seedFilePath, seedNames, singularize, storagePortWiring, tanstackReactQueryDependencyVersion, taskFilePath, typeBodySource, uniqueStrings, updateDrizzleRepositories, updateDrizzleSchemaIndex, updateFeatureArtifactIndex, updateInfrastructureAdapterWiring, updateInfrastructureDeferredPorts, updateInfrastructureGatePolicies, updateInfrastructurePortStub, updateInfrastructurePorts, updateListenersRegistrySource, updateOpenApiRoute, updatePackageDependencies, updatePackageJson, updatePackageScripts, updatePortIndex, updatePortsIndex, updateSeedEntrypoint, updateServerRoutes, updateServerTransactionPorts, updateSharedErrors, uploadFilePath, useCaseFeatureDir, useCaseFilePath, usesFeatureOwnedPolicies, usesFeatureOwnedTests, wireListenersProviderSource, wirePortProviders, writeGeneratedFile, writePlannedGeneratedFile, } from "./make/shared.js";
|
|
@@ -552,6 +554,7 @@ export async function makeJob(options) {
|
|
|
552
554
|
await assertFeatureArtifactApp(targetDir, config, "job");
|
|
553
555
|
await assertServerRuntimeApp(targetDir, config, "job");
|
|
554
556
|
await updateOutboxPortWiring(targetDir, config, { dryRun: true });
|
|
557
|
+
const jobDispatcherPlan = await planInlineJobDispatcherWiring(targetDir, config);
|
|
555
558
|
const outboxDrainPlan = await planOutboxDrainWiring(targetDir, config, {
|
|
556
559
|
force: Boolean(options.force),
|
|
557
560
|
});
|
|
@@ -580,6 +583,9 @@ export async function makeJob(options) {
|
|
|
580
583
|
await applyOutboxDrainWiring(result, targetDir, outboxDrainPlan, {
|
|
581
584
|
dryRun: Boolean(options.dryRun),
|
|
582
585
|
});
|
|
586
|
+
await applyInlineJobDispatcherWiring(result, targetDir, jobDispatcherPlan, {
|
|
587
|
+
dryRun: Boolean(options.dryRun),
|
|
588
|
+
});
|
|
583
589
|
await applyOutboxPortWiring(result, targetDir, config, {
|
|
584
590
|
dryRun: Boolean(options.dryRun),
|
|
585
591
|
});
|
|
@@ -588,6 +594,123 @@ export async function makeJob(options) {
|
|
|
588
594
|
});
|
|
589
595
|
return result;
|
|
590
596
|
}
|
|
597
|
+
async function planInlineJobDispatcherWiring(targetDir, config) {
|
|
598
|
+
const portsFile = config.paths.ports;
|
|
599
|
+
const portWiringFile = config.paths.portWiring;
|
|
600
|
+
const providersFile = providersFilePath(config);
|
|
601
|
+
const ports = await readFile(path.join(targetDir, portsFile), "utf8");
|
|
602
|
+
const portWiring = await readFile(path.join(targetDir, portWiringFile), "utf8");
|
|
603
|
+
const analysis = await analyzePortWiringFiles({
|
|
604
|
+
targetDir,
|
|
605
|
+
files: await listProjectFiles(targetDir),
|
|
606
|
+
config,
|
|
607
|
+
});
|
|
608
|
+
const declaresJobs = analysis.declared.has("jobs");
|
|
609
|
+
const wiresJobs = analysis.bound.has("jobs") || analysis.deferred.has("jobs");
|
|
610
|
+
if (declaresJobs && wiresJobs) {
|
|
611
|
+
return { changes: [] };
|
|
612
|
+
}
|
|
613
|
+
if (!declaresJobs && analysis.declarationIndeterminate) {
|
|
614
|
+
throw new Error(`Could not prove whether AppPorts in ${portsFile} declares the jobs port. Preserve the app's custom port type and add jobs: JobDispatcherPort manually before running make job.`);
|
|
615
|
+
}
|
|
616
|
+
if (!wiresJobs && analysis.indeterminate) {
|
|
617
|
+
throw new Error(`Could not prove how the jobs port is wired in ${portWiringFile}. Preserve the app's custom dispatcher by binding or deferring "jobs" in a statically inspectable definePorts(...) object before running make job.`);
|
|
618
|
+
}
|
|
619
|
+
let nextPorts = ports;
|
|
620
|
+
if (!declaresJobs && !analysis.appPortsInferredFromWiring) {
|
|
621
|
+
nextPorts = addNamedTypeImport(nextPorts, "JobDispatcherPort", "@beignet/core/ports");
|
|
622
|
+
nextPorts = insertTypeProperty(nextPorts, "AppPorts", "jobs: JobDispatcherPort;", `Could not find AppPorts in ${portsFile}. Add jobs: JobDispatcherPort manually and wire a dispatcher, or restore the generated ports file before running make job.`);
|
|
623
|
+
}
|
|
624
|
+
if (wiresJobs) {
|
|
625
|
+
return {
|
|
626
|
+
changes: ports === nextPorts
|
|
627
|
+
? []
|
|
628
|
+
: [{ path: portsFile, before: ports, after: nextPorts }],
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
const nextPortWiring = appendDeferredPortKey(portWiring, "jobs");
|
|
632
|
+
if (nextPortWiring === portWiring) {
|
|
633
|
+
throw new Error(`Could not find the deferred port list in ${portWiringFile}. Add "jobs" manually and wire a dispatcher, or restore the generated port wiring file before running make job.`);
|
|
634
|
+
}
|
|
635
|
+
const providersPath = path.join(targetDir, providersFile);
|
|
636
|
+
const providers = await readOptionalFile(providersPath);
|
|
637
|
+
if (providers === undefined) {
|
|
638
|
+
throw new Error(`Could not find ${providersFile}. Register an inline or provider-backed jobs dispatcher manually, or restore the generated providers file before running make job.`);
|
|
639
|
+
}
|
|
640
|
+
let nextProviders = addNamedImport(providers, "createInlineJobDispatcher", "@beignet/core/jobs");
|
|
641
|
+
nextProviders = addNamedImport(nextProviders, "createProvider", "@beignet/core/providers");
|
|
642
|
+
nextProviders = addNamedTypeImport(nextProviders, "AppContext", aliasModule(config.paths.appContext));
|
|
643
|
+
nextProviders = addNamedTypeImport(nextProviders, "AppPorts", aliasModule(config.paths.ports));
|
|
644
|
+
nextProviders = addNamedTypeImport(nextProviders, "AppServiceContextInput", aliasModule(path.join(path.dirname(config.paths.server), "context.ts")));
|
|
645
|
+
const providerName = "inlineJobsProvider";
|
|
646
|
+
const generatedProviderMarker = "// beignet:generated-inline-jobs-provider";
|
|
647
|
+
const providersSourceFile = ts.createSourceFile(providersFile, nextProviders, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
648
|
+
const providerDeclaration = providersSourceFile.statements
|
|
649
|
+
.filter(ts.isVariableStatement)
|
|
650
|
+
.flatMap((statement) => [...statement.declarationList.declarations])
|
|
651
|
+
.find((declaration) => ts.isIdentifier(declaration.name) &&
|
|
652
|
+
declaration.name.text === providerName);
|
|
653
|
+
const providerDeclarationExists = providerDeclaration !== undefined;
|
|
654
|
+
const providerIsGenerated = providerDeclaration
|
|
655
|
+
? nextProviders
|
|
656
|
+
.slice(0, providerDeclaration.getStart(providersSourceFile))
|
|
657
|
+
.trimEnd()
|
|
658
|
+
.endsWith(generatedProviderMarker)
|
|
659
|
+
: false;
|
|
660
|
+
if (providerDeclarationExists && !providerIsGenerated) {
|
|
661
|
+
throw new Error(`Could not install the generated inline jobs dispatcher because ${providerName} already exists in ${providersFile}. Rename the app-owned declaration or wire its jobs port explicitly before running make job.`);
|
|
662
|
+
}
|
|
663
|
+
if (!providerDeclarationExists) {
|
|
664
|
+
const definition = `// beignet:generated-inline-jobs-provider
|
|
665
|
+
const ${providerName} = createProvider<
|
|
666
|
+
{},
|
|
667
|
+
AppContext,
|
|
668
|
+
AppServiceContextInput
|
|
669
|
+
>()({
|
|
670
|
+
name: "inline-jobs",
|
|
671
|
+
setup({ createServiceContext }): { ports: Pick<AppPorts, "jobs"> } {
|
|
672
|
+
return {
|
|
673
|
+
ports: {
|
|
674
|
+
jobs: createInlineJobDispatcher<AppContext>({
|
|
675
|
+
ctx: () => createServiceContext(undefined),
|
|
676
|
+
}),
|
|
677
|
+
},
|
|
678
|
+
};
|
|
679
|
+
},
|
|
680
|
+
});
|
|
681
|
+
`;
|
|
682
|
+
const inserted = nextProviders.replace(/\nexport const providers = \[/, `\n${definition}\nexport const providers = [`);
|
|
683
|
+
if (inserted === nextProviders) {
|
|
684
|
+
throw new Error(`Could not find the exported providers array in ${providersFile}. Register an inline or provider-backed jobs dispatcher manually, or restore the generated providers file before running make job.`);
|
|
685
|
+
}
|
|
686
|
+
nextProviders = inserted;
|
|
687
|
+
}
|
|
688
|
+
const appended = appendToNamedArray(nextProviders, "providers", providerName);
|
|
689
|
+
if (appended.kind === "missing") {
|
|
690
|
+
throw new Error(`Could not find the exported providers array in ${providersFile}. Register ${providerName} manually, or restore the generated providers file before running make job.`);
|
|
691
|
+
}
|
|
692
|
+
if (appended.kind === "updated")
|
|
693
|
+
nextProviders = appended.source;
|
|
694
|
+
return {
|
|
695
|
+
changes: [
|
|
696
|
+
{ path: portsFile, before: ports, after: nextPorts },
|
|
697
|
+
{ path: portWiringFile, before: portWiring, after: nextPortWiring },
|
|
698
|
+
{ path: providersFile, before: providers, after: nextProviders },
|
|
699
|
+
].filter((change) => change.before !== change.after),
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
async function applyInlineJobDispatcherWiring(result, targetDir, plan, options) {
|
|
703
|
+
for (const change of plan.changes) {
|
|
704
|
+
if (!options.dryRun) {
|
|
705
|
+
await writeFile(path.join(targetDir, change.path), change.after);
|
|
706
|
+
}
|
|
707
|
+
if (!result.updatedFiles.includes(change.path)) {
|
|
708
|
+
result.updatedFiles.push(change.path);
|
|
709
|
+
}
|
|
710
|
+
if (!result.files.includes(change.path))
|
|
711
|
+
result.files.push(change.path);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
591
714
|
export async function makeTask(options) {
|
|
592
715
|
const targetDir = path.resolve(options.cwd ?? process.cwd());
|
|
593
716
|
const names = taskNames(options.name);
|
|
@@ -2552,8 +2675,8 @@ export function decode${names.singularPascal}Cursor(cursor: string): ${names.sin
|
|
|
2552
2675
|
|
|
2553
2676
|
export const List${names.pluralPascal}InputSchema = z
|
|
2554
2677
|
.object({
|
|
2555
|
-
limit: z.
|
|
2556
|
-
cursor: z.string().
|
|
2678
|
+
limit: z.number().int().min(1).max(100).default(20),
|
|
2679
|
+
cursor: z.string().optional().transform((value) => value ?? null),
|
|
2557
2680
|
name: z.string().trim().min(1).max(120).optional(),
|
|
2558
2681
|
sortBy: ${names.singularPascal}SortBySchema.default("createdAt"),
|
|
2559
2682
|
sortDirection: ${names.singularPascal}SortDirectionSchema.default("desc"),
|
|
@@ -3316,7 +3439,7 @@ ${createMethod}${resourceMethods}
|
|
|
3316
3439
|
`;
|
|
3317
3440
|
}
|
|
3318
3441
|
function contractFile(names, config, mode, options) {
|
|
3319
|
-
return `import { defineContractGroup } from "@beignet/core/contracts";
|
|
3442
|
+
return `import { defineContractGroup, defineQueryTransport, query } from "@beignet/core/contracts";
|
|
3320
3443
|
import { z } from "zod";
|
|
3321
3444
|
${mode === "resource" ? `import { errors } from "${aliasModule(resourceSharedErrorsPath(config))}";\n` : ""}import {
|
|
3322
3445
|
Create${names.singularPascal}InputSchema,
|
|
@@ -3339,7 +3462,16 @@ const ${names.pluralCamel} = defineContractGroup()
|
|
|
3339
3462
|
|
|
3340
3463
|
export const list${names.pluralPascal} = ${names.pluralCamel}
|
|
3341
3464
|
.get("/api/${names.pluralKebab}")
|
|
3342
|
-
.query(
|
|
3465
|
+
.query(
|
|
3466
|
+
List${names.pluralPascal}InputSchema,
|
|
3467
|
+
defineQueryTransport({
|
|
3468
|
+
limit: query.integer(),
|
|
3469
|
+
cursor: query.string(),
|
|
3470
|
+
name: query.string(),
|
|
3471
|
+
sortBy: query.string(),
|
|
3472
|
+
sortDirection: query.string(),
|
|
3473
|
+
}),
|
|
3474
|
+
)
|
|
3343
3475
|
.responses({
|
|
3344
3476
|
200: List${names.pluralPascal}OutputSchema,
|
|
3345
3477
|
});
|
|
@@ -3381,7 +3513,7 @@ ${options.authorization ? `\t.meta({\n\t\tauth: "required",\n\t\tauthorization:
|
|
|
3381
3513
|
`;
|
|
3382
3514
|
}
|
|
3383
3515
|
function standaloneContractFile(names) {
|
|
3384
|
-
return `import { defineContractGroup } from "@beignet/core/contracts";
|
|
3516
|
+
return `import { defineContractGroup, defineQueryTransport, query } from "@beignet/core/contracts";
|
|
3385
3517
|
import { z } from "zod";
|
|
3386
3518
|
|
|
3387
3519
|
const ErrorResponseSchema = z.object({
|
|
@@ -3405,8 +3537,12 @@ export const list${names.pluralPascal} = ${names.pluralCamel}
|
|
|
3405
3537
|
.get("/api/${names.pluralKebab}")
|
|
3406
3538
|
.query(
|
|
3407
3539
|
z.object({
|
|
3408
|
-
limit: z.
|
|
3409
|
-
offset: z.
|
|
3540
|
+
limit: z.number().int().min(1).max(100).default(20),
|
|
3541
|
+
offset: z.number().int().min(0).default(0),
|
|
3542
|
+
}),
|
|
3543
|
+
defineQueryTransport({
|
|
3544
|
+
limit: query.integer(),
|
|
3545
|
+
offset: query.integer(),
|
|
3410
3546
|
}),
|
|
3411
3547
|
)
|
|
3412
3548
|
.responses({
|
|
@@ -4372,7 +4508,7 @@ ${options.authorization ? `\t\t\t\tgate: initialPorts.gate,\n` : ""}
|
|
|
4372
4508
|
);
|
|
4373
4509
|
const secondPage = await tester.run(
|
|
4374
4510
|
list${names.pluralPascal}UseCase,
|
|
4375
|
-
{ limit: 2, cursor: firstPage.page.nextCursor },
|
|
4511
|
+
{ limit: 2, cursor: firstPage.page.nextCursor! },
|
|
4376
4512
|
{ ctx },
|
|
4377
4513
|
);
|
|
4378
4514
|
const nameAscendingPage = await tester.run(
|