swallowkit 2.0.0-alpha.1 → 2.0.0-alpha.10
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/README.ja.md +14 -0
- package/README.md +14 -0
- package/dist/cli/commands/add-auth.js +37 -6
- package/dist/cli/commands/add-auth.js.map +1 -1
- package/dist/cli/commands/configure-mcp.d.ts +12 -0
- package/dist/cli/commands/configure-mcp.d.ts.map +1 -0
- package/dist/cli/commands/configure-mcp.js +42 -0
- package/dist/cli/commands/configure-mcp.js.map +1 -0
- package/dist/cli/commands/dev.d.ts +2 -2
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +39 -27
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/cli/commands/init.d.ts +8 -2
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +67 -132
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/migrations.d.ts.map +1 -1
- package/dist/cli/commands/migrations.js +25 -0
- package/dist/cli/commands/migrations.js.map +1 -1
- package/dist/cli/commands/provision.d.ts +5 -0
- package/dist/cli/commands/provision.d.ts.map +1 -1
- package/dist/cli/commands/provision.js +278 -55
- package/dist/cli/commands/provision.js.map +1 -1
- package/dist/cli/commands/scaffold.d.ts +4 -0
- package/dist/cli/commands/scaffold.d.ts.map +1 -1
- package/dist/cli/commands/scaffold.js +85 -3
- package/dist/cli/commands/scaffold.js.map +1 -1
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +43 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/core/operations/create-model.d.ts +2 -0
- package/dist/core/operations/create-model.d.ts.map +1 -1
- package/dist/core/operations/create-model.js +60 -8
- package/dist/core/operations/create-model.js.map +1 -1
- package/dist/core/operations/migration-generator.d.ts.map +1 -1
- package/dist/core/operations/migration-generator.js +12 -1
- package/dist/core/operations/migration-generator.js.map +1 -1
- package/dist/core/operations/model-migration.d.ts +22 -0
- package/dist/core/operations/model-migration.d.ts.map +1 -0
- package/dist/core/operations/model-migration.js +36 -0
- package/dist/core/operations/model-migration.js.map +1 -0
- package/dist/core/operations/provision-deployment.d.ts +52 -0
- package/dist/core/operations/provision-deployment.d.ts.map +1 -0
- package/dist/core/operations/provision-deployment.js +164 -0
- package/dist/core/operations/provision-deployment.js.map +1 -0
- package/dist/core/operations/provision-operations.d.ts +62 -6
- package/dist/core/operations/provision-operations.d.ts.map +1 -1
- package/dist/core/operations/provision-operations.js +653 -115
- package/dist/core/operations/provision-operations.js.map +1 -1
- package/dist/core/operations/scaffold-apply.d.ts +1 -0
- package/dist/core/operations/scaffold-apply.d.ts.map +1 -1
- package/dist/core/operations/scaffold-apply.js +1 -0
- package/dist/core/operations/scaffold-apply.js.map +1 -1
- package/dist/core/operations/scaffold-machine.d.ts +1 -0
- package/dist/core/operations/scaffold-machine.d.ts.map +1 -1
- package/dist/core/operations/scaffold-machine.js.map +1 -1
- package/dist/core/operations/scaffold-plan.d.ts +2 -0
- package/dist/core/operations/scaffold-plan.d.ts.map +1 -1
- package/dist/core/operations/scaffold-plan.js +3 -1
- package/dist/core/operations/scaffold-plan.js.map +1 -1
- package/dist/core/project/agent-instructions.d.ts.map +1 -1
- package/dist/core/project/agent-instructions.js +4 -1
- package/dist/core/project/agent-instructions.js.map +1 -1
- package/dist/core/project/boundaries.d.ts +5 -2
- package/dist/core/project/boundaries.d.ts.map +1 -1
- package/dist/core/project/boundaries.js +51 -20
- package/dist/core/project/boundaries.js.map +1 -1
- package/dist/core/project/capabilities.d.ts +10 -0
- package/dist/core/project/capabilities.d.ts.map +1 -1
- package/dist/core/project/capabilities.js +38 -6
- package/dist/core/project/capabilities.js.map +1 -1
- package/dist/core/project/home-page.d.ts +4 -0
- package/dist/core/project/home-page.d.ts.map +1 -0
- package/dist/core/project/home-page.js +113 -0
- package/dist/core/project/home-page.js.map +1 -0
- package/dist/core/project/mcp-config.d.ts +26 -0
- package/dist/core/project/mcp-config.d.ts.map +1 -0
- package/dist/core/project/mcp-config.js +117 -0
- package/dist/core/project/mcp-config.js.map +1 -0
- package/dist/core/project/react-project.d.ts +1 -1
- package/dist/core/project/react-project.d.ts.map +1 -1
- package/dist/core/project/react-project.js +46 -25
- package/dist/core/project/react-project.js.map +1 -1
- package/dist/core/project/state.d.ts +7 -0
- package/dist/core/project/state.d.ts.map +1 -1
- package/dist/core/project/state.js +86 -0
- package/dist/core/project/state.js.map +1 -1
- package/dist/core/project/workflows.d.ts.map +1 -1
- package/dist/core/project/workflows.js +53 -7
- package/dist/core/project/workflows.js.map +1 -1
- package/dist/core/scaffold/auth-generator.d.ts.map +1 -1
- package/dist/core/scaffold/auth-generator.js +26 -27
- package/dist/core/scaffold/auth-generator.js.map +1 -1
- package/dist/core/scaffold/model-parser.d.ts +23 -0
- package/dist/core/scaffold/model-parser.d.ts.map +1 -1
- package/dist/core/scaffold/model-parser.js +407 -137
- package/dist/core/scaffold/model-parser.js.map +1 -1
- package/dist/core/scaffold/native-schema-generator.d.ts +13 -0
- package/dist/core/scaffold/native-schema-generator.d.ts.map +1 -1
- package/dist/core/scaffold/native-schema-generator.js +294 -91
- package/dist/core/scaffold/native-schema-generator.js.map +1 -1
- package/dist/core/scaffold/openapi-generator.d.ts +5 -0
- package/dist/core/scaffold/openapi-generator.d.ts.map +1 -1
- package/dist/core/scaffold/openapi-generator.js +53 -3
- package/dist/core/scaffold/openapi-generator.js.map +1 -1
- package/dist/core/scaffold/ui-generator.d.ts +0 -3
- package/dist/core/scaffold/ui-generator.d.ts.map +1 -1
- package/dist/core/scaffold/ui-generator.js +68 -7
- package/dist/core/scaffold/ui-generator.js.map +1 -1
- package/dist/core/verify/index.d.ts +4 -3
- package/dist/core/verify/index.d.ts.map +1 -1
- package/dist/core/verify/index.js +122 -5
- package/dist/core/verify/index.js.map +1 -1
- package/dist/machine/contracts.d.ts +1 -0
- package/dist/machine/contracts.d.ts.map +1 -1
- package/dist/machine/errors.d.ts +3 -2
- package/dist/machine/errors.d.ts.map +1 -1
- package/dist/machine/errors.js +2 -1
- package/dist/machine/errors.js.map +1 -1
- package/dist/machine/index.d.ts.map +1 -1
- package/dist/machine/index.js +59 -28
- package/dist/machine/index.js.map +1 -1
- package/dist/mcp/index.d.ts +6 -4
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +210 -25
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/version-selection.d.ts +55 -0
- package/dist/mcp/version-selection.d.ts.map +1 -0
- package/dist/mcp/version-selection.js +152 -0
- package/dist/mcp/version-selection.js.map +1 -0
- package/dist/utils/azure-cli.d.ts +56 -0
- package/dist/utils/azure-cli.d.ts.map +1 -0
- package/dist/utils/azure-cli.js +326 -0
- package/dist/utils/azure-cli.js.map +1 -0
- package/dist/utils/azure-diagnostics.d.ts +16 -0
- package/dist/utils/azure-diagnostics.d.ts.map +1 -0
- package/dist/utils/azure-diagnostics.js +68 -0
- package/dist/utils/azure-diagnostics.js.map +1 -0
- package/dist/utils/package-manager.js +2 -2
- package/dist/utils/package-manager.js.map +1 -1
- package/dist/utils/python-uv.d.ts +5 -7
- package/dist/utils/python-uv.d.ts.map +1 -1
- package/dist/utils/python-uv.js +50 -24
- package/dist/utils/python-uv.js.map +1 -1
- package/dist/utils/react-dev.d.ts +4 -0
- package/dist/utils/react-dev.d.ts.map +1 -0
- package/dist/utils/react-dev.js +35 -0
- package/dist/utils/react-dev.js.map +1 -0
- package/dist/utils/semver.d.ts +14 -0
- package/dist/utils/semver.d.ts.map +1 -0
- package/dist/utils/semver.js +61 -0
- package/dist/utils/semver.js.map +1 -0
- package/package.json +6 -3
- package/src/__tests__/__snapshots__/boundaries.test.ts.snap +154 -0
- package/src/__tests__/agent-instructions.test.ts +5 -0
- package/src/__tests__/agent-loop-phase34.test.ts +143 -8
- package/src/__tests__/auth.test.ts +9 -0
- package/src/__tests__/azure-cli.test.ts +202 -0
- package/src/__tests__/boundaries.test.ts +42 -0
- package/src/__tests__/csharp-schema.test.ts +261 -0
- package/src/__tests__/dev.test.ts +13 -6
- package/src/__tests__/fixtures/az wrapper.cmd +2 -0
- package/src/__tests__/fixtures/azure-cli.cjs +153 -0
- package/src/__tests__/fixtures/provision-runner.cjs +28 -0
- package/src/__tests__/generated-project-matrix.test.ts +789 -0
- package/src/__tests__/home-page.test.ts +50 -0
- package/src/__tests__/init.test.ts +116 -0
- package/src/__tests__/mcp-version.test.ts +262 -0
- package/src/__tests__/mcp.test.ts +120 -3
- package/src/__tests__/multi-auth.test.ts +115 -4
- package/src/__tests__/package-manager.test.ts +17 -2
- package/src/__tests__/plan-apply.test.ts +179 -0
- package/src/__tests__/provision-runtime.test.ts +722 -0
- package/src/__tests__/python-uv.test.ts +50 -14
- package/src/__tests__/python-venv.test.ts +48 -0
- package/src/__tests__/react-dev.test.ts +72 -0
- package/src/__tests__/react.test.ts +19 -0
- package/src/__tests__/schema-analysis.test.ts +329 -0
- package/src/cli/commands/add-auth.ts +36 -6
- package/src/cli/commands/configure-mcp.ts +54 -0
- package/src/cli/commands/dev.ts +40 -31
- package/src/cli/commands/init.ts +73 -138
- package/src/cli/commands/migrations.ts +22 -0
- package/src/cli/commands/provision.ts +294 -56
- package/src/cli/commands/scaffold.ts +105 -3
- package/src/cli/index.ts +40 -7
- package/src/core/operations/create-model.ts +51 -13
- package/src/core/operations/migration-generator.ts +14 -1
- package/src/core/operations/model-migration.ts +52 -0
- package/src/core/operations/provision-deployment.ts +183 -0
- package/src/core/operations/provision-operations.ts +662 -154
- package/src/core/operations/scaffold-apply.ts +2 -0
- package/src/core/operations/scaffold-machine.ts +1 -0
- package/src/core/operations/scaffold-plan.ts +5 -1
- package/src/core/project/agent-instructions.ts +4 -1
- package/src/core/project/agent-templates/AGENTS.md +89 -6
- package/src/core/project/agent-templates/CLAUDE.md +14 -1
- package/src/core/project/agent-templates/copilot-instructions.md +15 -1
- package/src/core/project/agent-templates/shared-models.instructions.md +11 -3
- package/src/core/project/boundaries.ts +62 -20
- package/src/core/project/capabilities.ts +49 -6
- package/src/core/project/home-page.ts +114 -0
- package/src/core/project/mcp-config.ts +84 -0
- package/src/core/project/react-project.ts +50 -28
- package/src/core/project/state.ts +70 -0
- package/src/core/project/workflows.ts +53 -7
- package/src/core/scaffold/auth-generator.ts +26 -27
- package/src/core/scaffold/model-parser.ts +413 -129
- package/src/core/scaffold/native-schema-generator.ts +319 -103
- package/src/core/scaffold/openapi-generator.ts +63 -5
- package/src/core/scaffold/ui-generator.ts +70 -8
- package/src/core/verify/index.ts +118 -6
- package/src/machine/contracts.ts +1 -0
- package/src/machine/errors.ts +4 -2
- package/src/machine/index.ts +65 -34
- package/src/mcp/index.ts +221 -31
- package/src/mcp/version-selection.ts +163 -0
- package/src/utils/azure-cli.ts +315 -0
- package/src/utils/azure-diagnostics.ts +75 -0
- package/src/utils/package-manager.ts +2 -2
- package/src/utils/python-uv.ts +53 -33
- package/src/utils/react-dev.ts +31 -0
- package/src/utils/semver.ts +59 -0
package/src/cli/commands/init.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
3
|
import { spawn, execSync } from "child_process";
|
|
4
4
|
import prompts from "prompts";
|
|
@@ -25,7 +25,9 @@ import {
|
|
|
25
25
|
buildCSharpCodegenToolManifestSource,
|
|
26
26
|
buildPythonCodegenRequirementsSource,
|
|
27
27
|
} from "../../core/scaffold/native-schema-generator";
|
|
28
|
-
import {
|
|
28
|
+
import { DEFAULT_AZURE_PYTHON_VERSION } from "../../utils/python-uv";
|
|
29
|
+
import { buildHomePage } from "../../core/project/home-page";
|
|
30
|
+
import { MCP_LATEST, McpPinDecision, lookupPublishedLatestVersion, resolveMcpPinVersion } from "../../core/project/mcp-config";
|
|
29
31
|
|
|
30
32
|
interface InitOptions {
|
|
31
33
|
name: string;
|
|
@@ -144,7 +146,7 @@ function getFunctionsRuntimeConfig(backendLanguage: BackendLanguage): { name: st
|
|
|
144
146
|
return { name: "dotnet-isolated", version: "10.0" };
|
|
145
147
|
}
|
|
146
148
|
if (backendLanguage === "python") {
|
|
147
|
-
return { name: "python", version:
|
|
149
|
+
return { name: "python", version: DEFAULT_AZURE_PYTHON_VERSION };
|
|
148
150
|
}
|
|
149
151
|
return { name: "node", version: "22" };
|
|
150
152
|
}
|
|
@@ -344,7 +346,7 @@ export async function initCommand(options: InitOptions) {
|
|
|
344
346
|
const azureConfig = await promptAzureConfig(options);
|
|
345
347
|
|
|
346
348
|
if (frontend === "react") {
|
|
347
|
-
createReactProject(projectDir, options.name);
|
|
349
|
+
createReactProject(projectDir, options.name, pm);
|
|
348
350
|
} else {
|
|
349
351
|
await createNextJsProject(options.name, pm);
|
|
350
352
|
await upgradeNextJs(projectDir, options.nextVersion || 'latest', pm);
|
|
@@ -711,7 +713,7 @@ export function buildCSharpFunctionsProjectSource(): string {
|
|
|
711
713
|
<None Remove="generated\\**\\bin\\**;generated\\**\\obj\\**" />
|
|
712
714
|
</ItemGroup>
|
|
713
715
|
<ItemGroup>
|
|
714
|
-
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.
|
|
716
|
+
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.63.2" />
|
|
715
717
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
|
716
718
|
<PackageReference Include="Azure.Identity" Version="1.17.0" />
|
|
717
719
|
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="2.52.0" />
|
|
@@ -778,14 +780,30 @@ function getSwallowKitPackageMetadata(): { name: string; version: string } {
|
|
|
778
780
|
};
|
|
779
781
|
}
|
|
780
782
|
|
|
781
|
-
export function buildGeneratedProjectDevDependencies(): Record<string, string> {
|
|
783
|
+
export function buildGeneratedProjectDevDependencies(frontend: FrontendFramework = "nextjs"): Record<string, string> {
|
|
782
784
|
const { name, version } = getSwallowKitPackageMetadata();
|
|
783
785
|
return {
|
|
784
786
|
[name]: version,
|
|
787
|
+
...(frontend === "nextjs" ? { "@tailwindcss/postcss": "^4.0.0" } : {}),
|
|
785
788
|
};
|
|
786
789
|
}
|
|
787
790
|
|
|
788
|
-
export function
|
|
791
|
+
export function ensureNextTailwindPostcssConfig(projectDir: string): void {
|
|
792
|
+
if (["postcss.config.mjs", "postcss.config.js", "postcss.config.cjs", "postcss.config.json"]
|
|
793
|
+
.some(file => fs.existsSync(path.join(projectDir, file)))) {
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
// New create-next-app templates can configure Tailwind for Turbopack only.
|
|
798
|
+
fs.writeFileSync(path.join(projectDir, "postcss.config.mjs"), `export default {
|
|
799
|
+
plugins: {
|
|
800
|
+
"@tailwindcss/postcss": {},
|
|
801
|
+
},
|
|
802
|
+
};
|
|
803
|
+
`);
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
export function buildSwallowKitMcpProjectConfigSource(pm: PackageManager = 'pnpm', mcpVersion: string = MCP_LATEST): string {
|
|
789
807
|
const { name } = getSwallowKitPackageMetadata();
|
|
790
808
|
return JSON.stringify(
|
|
791
809
|
{
|
|
@@ -797,7 +815,7 @@ export function buildSwallowKitMcpProjectConfigSource(pm: PackageManager = 'pnpm
|
|
|
797
815
|
: ["--yes", "--package", `${name}@\${SWALLOWKIT_MCP_VERSION}`, "swallowkit-mcp"],
|
|
798
816
|
cwd: ".",
|
|
799
817
|
env: {
|
|
800
|
-
SWALLOWKIT_MCP_VERSION:
|
|
818
|
+
SWALLOWKIT_MCP_VERSION: mcpVersion,
|
|
801
819
|
},
|
|
802
820
|
},
|
|
803
821
|
},
|
|
@@ -807,6 +825,15 @@ export function buildSwallowKitMcpProjectConfigSource(pm: PackageManager = 'pnpm
|
|
|
807
825
|
);
|
|
808
826
|
}
|
|
809
827
|
|
|
828
|
+
/** latest by default; pinned to this CLI version only when it is newer than published latest. */
|
|
829
|
+
export function selectInitialMcpVersion(
|
|
830
|
+
lookupLatest: (packageName: string) => string | null = lookupPublishedLatestVersion
|
|
831
|
+
): McpPinDecision {
|
|
832
|
+
const { name, version } = getSwallowKitPackageMetadata();
|
|
833
|
+
if (version === MCP_LATEST) return { version: MCP_LATEST, reason: "SwallowKit package metadata is unavailable." };
|
|
834
|
+
return resolveMcpPinVersion(version, lookupLatest(name));
|
|
835
|
+
}
|
|
836
|
+
|
|
810
837
|
async function addSwallowKitFiles(
|
|
811
838
|
projectDir: string,
|
|
812
839
|
options: InitOptions,
|
|
@@ -831,7 +858,7 @@ async function addSwallowKitFiles(
|
|
|
831
858
|
};
|
|
832
859
|
packageJson.devDependencies = {
|
|
833
860
|
...packageJson.devDependencies,
|
|
834
|
-
...buildGeneratedProjectDevDependencies(),
|
|
861
|
+
...buildGeneratedProjectDevDependencies(frontend),
|
|
835
862
|
};
|
|
836
863
|
|
|
837
864
|
packageJson.scripts = {
|
|
@@ -865,6 +892,8 @@ async function addSwallowKitFiles(
|
|
|
865
892
|
|
|
866
893
|
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
867
894
|
|
|
895
|
+
if (frontend === "nextjs") ensureNextTailwindPostcssConfig(projectDir);
|
|
896
|
+
|
|
868
897
|
// Create pnpm-workspace.yaml for local pnpm development when needed.
|
|
869
898
|
if (wsConfig.type === 'file') {
|
|
870
899
|
fs.writeFileSync(path.join(projectDir, wsConfig.filename), wsConfig.content + (frontend === "react" ? " esbuild: true\n" : ""));
|
|
@@ -1185,7 +1214,7 @@ export async function register() {
|
|
|
1185
1214
|
createAiAgentFiles(projectDir, projectName, backendLanguage, pm, frontend);
|
|
1186
1215
|
}
|
|
1187
1216
|
|
|
1188
|
-
async function createSharedPackage(projectDir: string, projectName: string) {
|
|
1217
|
+
export async function createSharedPackage(projectDir: string, projectName: string) {
|
|
1189
1218
|
console.log('📦 Creating shared workspace package for Zod models...\n');
|
|
1190
1219
|
|
|
1191
1220
|
const sharedDir = path.join(projectDir, 'shared');
|
|
@@ -1225,7 +1254,7 @@ async function createSharedPackage(projectDir: string, projectName: string) {
|
|
|
1225
1254
|
// shared/index.ts (empty re-export file, scaffold will add entries)
|
|
1226
1255
|
fs.writeFileSync(
|
|
1227
1256
|
path.join(sharedDir, 'index.ts'),
|
|
1228
|
-
`// Shared Zod models
|
|
1257
|
+
`// Shared Zod models. SwallowKit create-model/scaffold append missing model exports.\n// You may add exports manually; existing exports and comments are preserved. No managed markers.\n`
|
|
1229
1258
|
);
|
|
1230
1259
|
|
|
1231
1260
|
// shared/.gitignore
|
|
@@ -1237,7 +1266,7 @@ async function createSharedPackage(projectDir: string, projectName: string) {
|
|
|
1237
1266
|
console.log('✅ Shared package created\n');
|
|
1238
1267
|
}
|
|
1239
1268
|
|
|
1240
|
-
async function createAzureFunctionsProject(
|
|
1269
|
+
export async function createAzureFunctionsProject(
|
|
1241
1270
|
projectDir: string,
|
|
1242
1271
|
pm: PackageManager = 'pnpm',
|
|
1243
1272
|
backendLanguage: BackendLanguage = 'typescript'
|
|
@@ -1492,7 +1521,6 @@ public sealed class GreetFunction
|
|
|
1492
1521
|
}
|
|
1493
1522
|
|
|
1494
1523
|
function createPythonFunctionsProject(projectDir: string, functionsDir: string): void {
|
|
1495
|
-
fs.writeFileSync(path.join(projectDir, '.python-version'), '3.11\n');
|
|
1496
1524
|
ensureProjectGitignoreEntry(projectDir, '.uv');
|
|
1497
1525
|
|
|
1498
1526
|
fs.writeFileSync(path.join(functionsDir, 'requirements.txt'), `azure-functions>=1.20.0
|
|
@@ -1632,117 +1660,8 @@ export async function POST(request: NextRequest) {
|
|
|
1632
1660
|
|
|
1633
1661
|
async function createHomePage(projectDir: string, pm: PackageManager = 'pnpm') {
|
|
1634
1662
|
console.log('📦 Creating home page...\n');
|
|
1635
|
-
|
|
1636
|
-
const pmCmd = getCommands(pm);
|
|
1637
|
-
|
|
1638
|
-
const pageContent = `'use client'
|
|
1639
|
-
|
|
1640
|
-
export const dynamic = 'force-dynamic';
|
|
1641
|
-
|
|
1642
|
-
import { useState } from 'react';
|
|
1643
|
-
import { scaffoldConfig } from '@/lib/scaffold-config';
|
|
1644
1663
|
|
|
1645
|
-
|
|
1646
|
-
const [greetingStatus, setGreetingStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
|
|
1647
|
-
const [message, setMessage] = useState('');
|
|
1648
|
-
|
|
1649
|
-
const testConnection = async () => {
|
|
1650
|
-
setGreetingStatus('loading');
|
|
1651
|
-
try {
|
|
1652
|
-
const response = await fetch('/api/greet?name=SwallowKit');
|
|
1653
|
-
const data = await response.json();
|
|
1654
|
-
if (!response.ok) {
|
|
1655
|
-
throw new Error(data.error || \`Server error: \${response.status}\`);
|
|
1656
|
-
}
|
|
1657
|
-
setMessage(data.message);
|
|
1658
|
-
setGreetingStatus('success');
|
|
1659
|
-
} catch (error) {
|
|
1660
|
-
setMessage(error instanceof Error ? error.message : 'Failed to connect to Azure Functions');
|
|
1661
|
-
setGreetingStatus('error');
|
|
1662
|
-
}
|
|
1663
|
-
};
|
|
1664
|
-
|
|
1665
|
-
return (
|
|
1666
|
-
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-50 dark:from-gray-900 dark:to-gray-800">
|
|
1667
|
-
<div className="container mx-auto px-4 py-12">
|
|
1668
|
-
<header className="text-center mb-16">
|
|
1669
|
-
<h1 className="text-5xl font-bold text-gray-800 dark:text-white mb-4">
|
|
1670
|
-
Welcome to SwallowKit
|
|
1671
|
-
</h1>
|
|
1672
|
-
<p className="text-xl text-gray-600 dark:text-gray-400">
|
|
1673
|
-
Next.js on Azure Static Web Apps + Functions + Cosmos DB — Zod schema sharing
|
|
1674
|
-
</p>
|
|
1675
|
-
</header>
|
|
1676
|
-
|
|
1677
|
-
{/* Connection Test */}
|
|
1678
|
-
<section className="max-w-2xl mx-auto mb-12">
|
|
1679
|
-
<div className="bg-white dark:bg-gray-800 rounded-xl p-8 border border-gray-200 dark:border-gray-700">
|
|
1680
|
-
<h2 className="text-2xl font-semibold mb-4 text-gray-900 dark:text-gray-100">
|
|
1681
|
-
Test BFF → Functions Connection
|
|
1682
|
-
</h2>
|
|
1683
|
-
<button
|
|
1684
|
-
onClick={testConnection}
|
|
1685
|
-
disabled={greetingStatus === 'loading'}
|
|
1686
|
-
className="px-6 py-3 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 text-white rounded-lg font-medium transition-colors"
|
|
1687
|
-
>
|
|
1688
|
-
{greetingStatus === 'loading' ? 'Testing...' : 'Test Connection'}
|
|
1689
|
-
</button>
|
|
1690
|
-
{greetingStatus === 'success' && (
|
|
1691
|
-
<div className="mt-4 p-4 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg">
|
|
1692
|
-
<p className="text-green-800 dark:text-green-200 font-medium">✅ Connection successful!</p>
|
|
1693
|
-
<p className="text-green-700 dark:text-green-300 text-sm mt-1">{message}</p>
|
|
1694
|
-
</div>
|
|
1695
|
-
)}
|
|
1696
|
-
{greetingStatus === 'error' && (
|
|
1697
|
-
<div className="mt-4 p-4 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg">
|
|
1698
|
-
<p className="text-red-800 dark:text-red-200 font-medium">❌ Connection failed</p>
|
|
1699
|
-
<p className="text-red-700 dark:text-red-300 text-sm mt-1">{message}</p>
|
|
1700
|
-
</div>
|
|
1701
|
-
)}
|
|
1702
|
-
</div>
|
|
1703
|
-
</section>
|
|
1704
|
-
|
|
1705
|
-
{/* Scaffolded Models Menu */}
|
|
1706
|
-
{scaffoldConfig.models.length > 0 ? (
|
|
1707
|
-
<section className="max-w-6xl mx-auto">
|
|
1708
|
-
<h2 className="text-3xl font-bold mb-8 text-gray-900 dark:text-gray-100">Your Models</h2>
|
|
1709
|
-
<div className="grid gap-6 grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
|
|
1710
|
-
{scaffoldConfig.models.map((model) => (
|
|
1711
|
-
<a
|
|
1712
|
-
key={model.name}
|
|
1713
|
-
href={model.path}
|
|
1714
|
-
className="block p-8 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl hover:shadow-lg hover:border-blue-400 dark:hover:border-blue-600 transition-all"
|
|
1715
|
-
>
|
|
1716
|
-
<h3 className="text-2xl font-semibold mb-2 text-gray-900 dark:text-gray-100">{model.label}</h3>
|
|
1717
|
-
<p className="text-gray-600 dark:text-gray-400">Manage {model.label.toLowerCase()}</p>
|
|
1718
|
-
</a>
|
|
1719
|
-
))}
|
|
1720
|
-
</div>
|
|
1721
|
-
</section>
|
|
1722
|
-
) : (
|
|
1723
|
-
<section className="max-w-2xl mx-auto text-center">
|
|
1724
|
-
<div className="bg-white dark:bg-gray-800 rounded-xl p-12 border border-gray-200 dark:border-gray-700">
|
|
1725
|
-
<h2 className="text-2xl font-semibold mb-4 text-gray-900 dark:text-gray-100">Get Started</h2>
|
|
1726
|
-
<p className="text-gray-600 dark:text-gray-400 mb-6">
|
|
1727
|
-
Create your first model with Zod and generate CRUD operations automatically.
|
|
1728
|
-
</p>
|
|
1729
|
-
<code className="block bg-gray-100 dark:bg-gray-900 p-4 rounded text-left text-sm">
|
|
1730
|
-
${pmCmd.exec} swallowkit scaffold shared/models/your-model.ts
|
|
1731
|
-
</code>
|
|
1732
|
-
</div>
|
|
1733
|
-
</section>
|
|
1734
|
-
)}
|
|
1735
|
-
|
|
1736
|
-
<footer className="mt-16 text-center text-gray-600 dark:text-gray-400 text-sm">
|
|
1737
|
-
<p>Built with SwallowKit</p>
|
|
1738
|
-
</footer>
|
|
1739
|
-
</div>
|
|
1740
|
-
</div>
|
|
1741
|
-
);
|
|
1742
|
-
}
|
|
1743
|
-
`;
|
|
1744
|
-
|
|
1745
|
-
fs.writeFileSync(path.join(projectDir, 'app', 'page.tsx'), pageContent);
|
|
1664
|
+
fs.writeFileSync(path.join(projectDir, 'app', 'page.tsx'), buildHomePage("nextjs", pm));
|
|
1746
1665
|
|
|
1747
1666
|
console.log('✅ Home page created\n');
|
|
1748
1667
|
|
|
@@ -1796,9 +1715,8 @@ function createReadme(
|
|
|
1796
1715
|
const backendScaffoldNote = backendLanguage === 'typescript'
|
|
1797
1716
|
? '- Azure Functions CRUD endpoints'
|
|
1798
1717
|
: `- Azure Functions ${backendLanguageLabel} CRUD handlers\n- OpenAPI export + native-generated ${backendLanguageLabel} schema assets`;
|
|
1799
|
-
const pythonUvPaths = getProjectLocalUvPaths(projectDir);
|
|
1800
1718
|
const pythonLocalDevNote = backendLanguage === 'python'
|
|
1801
|
-
? `\n**Python local dev note**: SwallowKit uses \`uv\`
|
|
1719
|
+
? `\n**Python local dev note**: SwallowKit uses normal \`uv\` interpreter discovery and settings, including installed Python, \`.python-version\`, and \`UV_PYTHON\`. It does not pin local Python to the Azure deployment version (${DEFAULT_AZURE_PYTHON_VERSION}). Local Functions uses \`functions/.venv\` and schema generation uses \`functions/.codegen-venv\`. Existing environments are preserved; explicitly recreate them with uv when switching interpreters. A missing uv binary is bootstrapped under \`.uv/bin\` without changing PATH. Keep \`functions/requirements.txt\` and \`functions/requirements.codegen.txt\` as the dependency sources of truth.\n`
|
|
1802
1720
|
: '';
|
|
1803
1721
|
|
|
1804
1722
|
const readme = `# ${projectName}
|
|
@@ -1907,10 +1825,12 @@ ${pmCmd.exec} swallowkit provision --resource-group <rg-name>
|
|
|
1907
1825
|
|
|
1908
1826
|
This creates:
|
|
1909
1827
|
- Static Web App (\`swa-${projectName}\`)
|
|
1910
|
-
- Azure Functions (\`func-${projectName}
|
|
1911
|
-
- Cosmos DB (\`cosmos-${projectName}
|
|
1828
|
+
- Azure Functions (\`func-${projectName}-<suffix>\`)
|
|
1829
|
+
- Cosmos DB (\`cosmos-${projectName}-<suffix>\`)
|
|
1912
1830
|
- Storage Account
|
|
1913
1831
|
|
|
1832
|
+
Cosmos DB and Function App names must be globally unique, so they include a short suffix derived from the resource group. When provisioning completes, the command prints the actual resource names and the CI/CD settings to use.
|
|
1833
|
+
|
|
1914
1834
|
You will be prompted to select Azure regions:
|
|
1915
1835
|
1. **Primary location**: For Functions and Cosmos DB (default: Japan East)
|
|
1916
1836
|
2. **Static Web App location**: Limited availability (default: East Asia)
|
|
@@ -1926,12 +1846,12 @@ ${cicdChoice === 'github' ? `#### GitHub Actions
|
|
|
1926
1846
|
|
|
1927
1847
|
2. Get Function App publish profile:
|
|
1928
1848
|
\`\`\`bash
|
|
1929
|
-
az webapp deployment list-publishing-profiles --name
|
|
1849
|
+
az webapp deployment list-publishing-profiles --name <functions-app-name> --resource-group <rg-name> --xml
|
|
1930
1850
|
\`\`\`
|
|
1931
1851
|
|
|
1932
1852
|
3. Add secrets to GitHub repository:
|
|
1933
1853
|
- \`AZURE_STATIC_WEB_APPS_API_TOKEN\`: SWA deployment token (from step 1)
|
|
1934
|
-
- \`AZURE_FUNCTIONAPP_NAME\`: \`func-${projectName}
|
|
1854
|
+
- \`AZURE_FUNCTIONAPP_NAME\`: Functions app name printed by \`swallowkit provision\` (\`func-${projectName}-<suffix>\`)
|
|
1935
1855
|
- \`AZURE_FUNCTIONAPP_PUBLISH_PROFILE\`: Functions publish profile (from step 2)
|
|
1936
1856
|
|
|
1937
1857
|
4. Push to \`main\` branch to trigger deployment (or use **Actions** → **Run workflow** for manual deployment)` : cicdChoice === 'azure' ? `#### Azure Pipelines
|
|
@@ -1953,8 +1873,10 @@ az staticwebapp deploy --name swa-${projectName} --resource-group <rg-name> --ap
|
|
|
1953
1873
|
\`\`\`bash
|
|
1954
1874
|
cd functions
|
|
1955
1875
|
${pmCmd.run} build
|
|
1956
|
-
func azure functionapp publish
|
|
1957
|
-
|
|
1876
|
+
func azure functionapp publish <functions-app-name>
|
|
1877
|
+
\`\`\`
|
|
1878
|
+
|
|
1879
|
+
Use the Functions app name printed by \`swallowkit provision\`.`}
|
|
1958
1880
|
|
|
1959
1881
|
## 🔧 Available Commands
|
|
1960
1882
|
|
|
@@ -2031,11 +1953,16 @@ function createAiAgentFiles(
|
|
|
2031
1953
|
console.log(' ✅ .github/copilot-instructions.md (GitHub Copilot adapter)');
|
|
2032
1954
|
console.log(' ✅ .github/instructions/ (path-specific instructions)');
|
|
2033
1955
|
|
|
1956
|
+
const mcpVersion = selectInitialMcpVersion();
|
|
2034
1957
|
fs.writeFileSync(
|
|
2035
1958
|
path.join(projectDir, '.mcp.json'),
|
|
2036
|
-
buildSwallowKitMcpProjectConfigSource(pm)
|
|
1959
|
+
buildSwallowKitMcpProjectConfigSource(pm, mcpVersion.version)
|
|
1960
|
+
);
|
|
1961
|
+
console.log(
|
|
1962
|
+
mcpVersion.version === MCP_LATEST
|
|
1963
|
+
? ' ✅ .mcp.json (project-scoped MCP bootstrap, resolves latest)'
|
|
1964
|
+
: ` ✅ .mcp.json (project-scoped MCP bootstrap, pinned to ${mcpVersion.version}: ${mcpVersion.reason} Run "${runCmd} swallowkit configure-mcp" to re-select later.)`
|
|
2037
1965
|
);
|
|
2038
|
-
console.log(' ✅ .mcp.json (project-scoped MCP bootstrap)');
|
|
2039
1966
|
|
|
2040
1967
|
writeWorkflowDocs(projectDir, runCmd);
|
|
2041
1968
|
console.log(' ✅ .swallowkit/workflows/ (agent-agnostic autonomous-loop runbooks)');
|
|
@@ -2126,6 +2053,14 @@ param cosmosDbMode string = '${azureConfig.cosmosDbMode}'
|
|
|
2126
2053
|
@description('Enable VNet integration')
|
|
2127
2054
|
param enableVNet bool = ${enableVNet}
|
|
2128
2055
|
|
|
2056
|
+
// Cosmos DB account and Function App names are globally unique across Azure.
|
|
2057
|
+
// A suffix derived from the resource group keeps names stable for redeployments
|
|
2058
|
+
// to the same resource group while avoiding collisions with other environments
|
|
2059
|
+
// and with names Azure still reserves after a previous resource group is deleted.
|
|
2060
|
+
var resourceSuffix = take(uniqueString(resourceGroup().id, projectName), 6)
|
|
2061
|
+
var cosmosAccountName = 'cosmos-\${take(toLower(projectName), 30)}-\${resourceSuffix}'
|
|
2062
|
+
var functionsAppName = 'func-\${take(projectName, 40)}-\${resourceSuffix}'
|
|
2063
|
+
|
|
2129
2064
|
// Shared Log Analytics Workspace (in Functions region for data residency)
|
|
2130
2065
|
module logAnalytics 'modules/loganalytics.bicep' = {
|
|
2131
2066
|
name: 'logAnalytics'
|
|
@@ -2179,7 +2114,7 @@ module vnet 'modules/vnet.bicep' = if (enableVNet) {
|
|
|
2179
2114
|
module cosmosDbFreeTier 'modules/cosmosdb-freetier.bicep' = if (cosmosDbMode == 'freetier') {
|
|
2180
2115
|
name: 'cosmosDb'
|
|
2181
2116
|
params: {
|
|
2182
|
-
accountName:
|
|
2117
|
+
accountName: cosmosAccountName
|
|
2183
2118
|
databaseName: '\${projectName}Database'
|
|
2184
2119
|
location: location
|
|
2185
2120
|
publicNetworkAccess: enableVNet ? 'Disabled' : 'Enabled'
|
|
@@ -2189,7 +2124,7 @@ module cosmosDbFreeTier 'modules/cosmosdb-freetier.bicep' = if (cosmosDbMode ==
|
|
|
2189
2124
|
module cosmosDbServerless 'modules/cosmosdb-serverless.bicep' = if (cosmosDbMode == 'serverless') {
|
|
2190
2125
|
name: 'cosmosDb'
|
|
2191
2126
|
params: {
|
|
2192
|
-
accountName:
|
|
2127
|
+
accountName: cosmosAccountName
|
|
2193
2128
|
databaseName: '\${projectName}Database'
|
|
2194
2129
|
location: location
|
|
2195
2130
|
publicNetworkAccess: enableVNet ? 'Disabled' : 'Enabled'
|
|
@@ -2213,7 +2148,7 @@ module cosmosPrivateEndpoint 'modules/private-endpoint-cosmos.bicep' = if (enabl
|
|
|
2213
2148
|
module functionsFlex 'modules/functions-flex.bicep' = {
|
|
2214
2149
|
name: 'functionsApp'
|
|
2215
2150
|
params: {
|
|
2216
|
-
name:
|
|
2151
|
+
name: functionsAppName
|
|
2217
2152
|
location: location
|
|
2218
2153
|
storageAccountName: 'stg\${uniqueString(resourceGroup().id, projectName)}'
|
|
2219
2154
|
appInsightsConnectionString: appInsightsFunctions.outputs.connectionString
|
|
@@ -2949,7 +2884,7 @@ jobs:
|
|
|
2949
2884
|
${commonSetup} - name: Setup Python
|
|
2950
2885
|
uses: actions/setup-python@v5
|
|
2951
2886
|
with:
|
|
2952
|
-
python-version: '
|
|
2887
|
+
python-version: '${DEFAULT_AZURE_PYTHON_VERSION}'
|
|
2953
2888
|
|
|
2954
2889
|
- name: Install Functions dependencies
|
|
2955
2890
|
run: |
|
|
@@ -3138,7 +3073,7 @@ variables:
|
|
|
3138
3073
|
steps:
|
|
3139
3074
|
${commonSetup} - task: UsePythonVersion@0
|
|
3140
3075
|
inputs:
|
|
3141
|
-
versionSpec: '
|
|
3076
|
+
versionSpec: '${DEFAULT_AZURE_PYTHON_VERSION}'
|
|
3142
3077
|
displayName: 'Install Python'
|
|
3143
3078
|
|
|
3144
3079
|
- script: |
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import { ensureSwallowKitProject } from "../../core/config";
|
|
3
3
|
import { initializeLegacyMigrations } from "../../core/operations/migration-generator";
|
|
4
|
+
import { addModelContainerMigration } from "../../core/operations/model-migration";
|
|
4
5
|
|
|
5
6
|
export const migrationsCommand = new Command("migrations")
|
|
6
7
|
.description("Manage versioned Azure infrastructure migrations");
|
|
@@ -18,3 +19,24 @@ migrationsCommand
|
|
|
18
19
|
console.log(`Migration baseline 0 created for project ${manifest.projectId}.`);
|
|
19
20
|
console.log("Commit infra/migrations/manifest.json, then run provision with --adopt-existing --baseline 0.");
|
|
20
21
|
});
|
|
22
|
+
|
|
23
|
+
migrationsCommand
|
|
24
|
+
.command("add-model")
|
|
25
|
+
.description("Generate only the Cosmos DB container migration for a model (e.g. after scaffold --skip-infra)")
|
|
26
|
+
.argument("<model>", "Model file or model name")
|
|
27
|
+
.option("--dry-run", "Show the planned infra changes without writing anything", false)
|
|
28
|
+
.action(async (model: string, options: { dryRun?: boolean }) => {
|
|
29
|
+
ensureSwallowKitProject("migrations add-model");
|
|
30
|
+
const result = await addModelContainerMigration(model, { dryRun: options.dryRun });
|
|
31
|
+
for (const operation of result.operations) {
|
|
32
|
+
if (operation.action !== "skip") console.log(` ${operation.action.padEnd(7)} ${operation.path}`);
|
|
33
|
+
}
|
|
34
|
+
if (!result.migration) {
|
|
35
|
+
console.log(`No migration needed for ${result.model}: ${result.reason}`);
|
|
36
|
+
} else if (result.operations.every((operation) => operation.action === "skip")) {
|
|
37
|
+
console.log(`Migration ${result.migration.version} for ${result.model} already exists: ${result.migration.template}`);
|
|
38
|
+
} else {
|
|
39
|
+
console.log(`${result.dryRun ? "Would create" : "Created"} migration ${result.migration.version} for ${result.model}: ${result.migration.template}`);
|
|
40
|
+
if (!result.dryRun) console.log("Commit the migration, then run provision to plan and apply it.");
|
|
41
|
+
}
|
|
42
|
+
});
|