swallowkit 1.1.2 → 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 +61 -7
- package/README.md +61 -7
- package/dist/cli/commands/add-auth.d.ts.map +1 -1
- package/dist/cli/commands/add-auth.js +103 -27
- 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 +5 -2
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +143 -67
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/cli/commands/init.d.ts +14 -7
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +149 -170
- 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 +5 -1
- package/dist/cli/commands/scaffold.d.ts.map +1 -1
- package/dist/cli/commands/scaffold.js +123 -18
- 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 +49 -8
- package/dist/cli/index.js.map +1 -1
- package/dist/core/config.d.ts +2 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +19 -0
- package/dist/core/config.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 +2 -1
- package/dist/core/project/agent-instructions.d.ts.map +1 -1
- package/dist/core/project/agent-instructions.js +15 -0
- 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 +17 -0
- package/dist/core/project/capabilities.d.ts.map +1 -1
- package/dist/core/project/capabilities.js +45 -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/manifest.d.ts +3 -1
- package/dist/core/project/manifest.d.ts.map +1 -1
- package/dist/core/project/manifest.js +47 -25
- package/dist/core/project/manifest.js.map +1 -1
- 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 +26 -0
- package/dist/core/project/react-project.d.ts.map +1 -0
- package/dist/core/project/react-project.js +443 -0
- package/dist/core/project/react-project.js.map +1 -0
- 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/validation.d.ts.map +1 -1
- package/dist/core/project/validation.js +32 -10
- package/dist/core/project/validation.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/react-bff-generator.d.ts +10 -0
- package/dist/core/scaffold/react-bff-generator.d.ts.map +1 -0
- package/dist/core/scaffold/react-bff-generator.js +252 -0
- package/dist/core/scaffold/react-bff-generator.js.map +1 -0
- package/dist/core/scaffold/react-ui-generator.d.ts +6 -0
- package/dist/core/scaffold/react-ui-generator.d.ts.map +1 -0
- package/dist/core/scaffold/react-ui-generator.js +41 -0
- package/dist/core/scaffold/react-ui-generator.js.map +1 -0
- 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/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/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 +61 -30
- 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/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -1
- 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.d.ts +2 -2
- package/dist/utils/package-manager.d.ts.map +1 -1
- package/dist/utils/package-manager.js +6 -3
- 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 +7 -4
- package/src/__tests__/__snapshots__/boundaries.test.ts.snap +154 -0
- package/src/__tests__/agent-instructions.test.ts +6 -1
- 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 +145 -5
- 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 +838 -0
- package/src/__tests__/release-metadata.test.ts +121 -0
- package/src/__tests__/schema-analysis.test.ts +329 -0
- package/src/cli/commands/add-auth.ts +103 -29
- package/src/cli/commands/configure-mcp.ts +54 -0
- package/src/cli/commands/dev.ts +145 -73
- package/src/cli/commands/init.ts +147 -172
- package/src/cli/commands/migrations.ts +22 -0
- package/src/cli/commands/provision.ts +294 -56
- package/src/cli/commands/scaffold.ts +145 -22
- package/src/cli/index.ts +46 -10
- package/src/core/config.ts +21 -1
- 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 +17 -1
- package/src/core/project/agent-templates/AGENTS.md +113 -15
- package/src/core/project/agent-templates/CLAUDE.md +14 -1
- package/src/core/project/agent-templates/bff-routes.instructions.md +5 -3
- 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 +63 -6
- package/src/core/project/home-page.ts +114 -0
- package/src/core/project/manifest.ts +52 -27
- package/src/core/project/mcp-config.ts +84 -0
- package/src/core/project/react-project.ts +529 -0
- package/src/core/project/state.ts +70 -0
- package/src/core/project/validation.ts +32 -10
- 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/react-bff-generator.ts +292 -0
- package/src/core/scaffold/react-ui-generator.ts +51 -0
- package/src/core/scaffold/ui-generator.ts +70 -8
- package/src/core/verify/index.ts +118 -6
- package/src/index.ts +3 -1
- package/src/machine/contracts.ts +1 -0
- package/src/machine/errors.ts +4 -2
- package/src/machine/index.ts +67 -36
- package/src/mcp/index.ts +221 -31
- package/src/mcp/version-selection.ts +163 -0
- package/src/types/index.ts +4 -0
- package/src/utils/azure-cli.ts +315 -0
- package/src/utils/azure-diagnostics.ts +75 -0
- package/src/utils/package-manager.ts +7 -4
- 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/core/verify/index.ts
CHANGED
|
@@ -5,16 +5,17 @@
|
|
|
5
5
|
* - structure: プロジェクト構造規約 (validateProject)
|
|
6
6
|
* - drift: 生成物と現在状態の乖離 (detectDrift)
|
|
7
7
|
* - typecheck: TypeScript 型チェック (tsc --noEmit / typecheck script)
|
|
8
|
+
* - backend-build: standalone Functions のコンパイル (C#/TypeScript) または構文検証 (Python)
|
|
8
9
|
* - build/lint/test: package.json scripts に同名 script がある場合のみ実行 (なければ skip)
|
|
9
10
|
* - custom: swallowkit.config の verify.checks で定義されたプロジェクト固有チェック
|
|
10
11
|
*
|
|
11
|
-
* 既定実行セットは structure/drift/typecheck + custom。build/lint/test は --checks で明示指定。
|
|
12
|
+
* 既定実行セットは structure/drift/typecheck/backend-build + custom。build/lint/test は --checks で明示指定。
|
|
12
13
|
*/
|
|
13
14
|
|
|
14
15
|
import * as fs from "fs";
|
|
15
16
|
import * as path from "path";
|
|
16
17
|
import { spawnSync } from "child_process";
|
|
17
|
-
import { loadConfig } from "../config";
|
|
18
|
+
import { loadConfig, loadConfigFromEnv } from "../config";
|
|
18
19
|
import { detectDrift, DriftFinding } from "../project/drift";
|
|
19
20
|
import { saveLastVerifyState } from "../project/state";
|
|
20
21
|
import { ProjectViolation, validateProject } from "../project/validation";
|
|
@@ -60,11 +61,11 @@ export interface VerifyResult {
|
|
|
60
61
|
verifiedAt: string;
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
export const AVAILABLE_VERIFY_CHECKS = ["structure", "drift", "typecheck", "build", "lint", "test"] as const;
|
|
64
|
+
export const AVAILABLE_VERIFY_CHECKS = ["structure", "drift", "typecheck", "backend-build", "build", "lint", "test"] as const;
|
|
64
65
|
export type VerifyCheckId = (typeof AVAILABLE_VERIFY_CHECKS)[number];
|
|
65
66
|
|
|
66
67
|
/** 既定で実行される built-in チェック。build/lint/test は明示指定時のみ。 */
|
|
67
|
-
export const DEFAULT_VERIFY_CHECKS = ["structure", "drift", "typecheck"] as const;
|
|
68
|
+
export const DEFAULT_VERIFY_CHECKS = ["structure", "drift", "typecheck", "backend-build"] as const;
|
|
68
69
|
|
|
69
70
|
async function runStructureCheck(projectRoot: string): Promise<VerifyCheckResult> {
|
|
70
71
|
const startedAt = Date.now();
|
|
@@ -137,6 +138,7 @@ interface CommandCheckSpec {
|
|
|
137
138
|
args: string[];
|
|
138
139
|
timeoutMs?: number;
|
|
139
140
|
failAction: string;
|
|
141
|
+
shell?: boolean;
|
|
140
142
|
}
|
|
141
143
|
|
|
142
144
|
function runCommandCheck(projectRoot: string, spec: CommandCheckSpec): VerifyCheckResult {
|
|
@@ -145,9 +147,10 @@ function runCommandCheck(projectRoot: string, spec: CommandCheckSpec): VerifyChe
|
|
|
145
147
|
try {
|
|
146
148
|
const result = spawnSync(spec.command, spec.args, {
|
|
147
149
|
cwd: projectRoot,
|
|
148
|
-
shell: true,
|
|
150
|
+
shell: spec.shell ?? true,
|
|
149
151
|
encoding: "utf-8",
|
|
150
152
|
timeout: spec.timeoutMs ?? 5 * 60 * 1000,
|
|
153
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
151
154
|
});
|
|
152
155
|
|
|
153
156
|
const output = `${result.stdout ?? ""}\n${result.stderr ?? ""}`;
|
|
@@ -180,6 +183,11 @@ function runCommandCheck(projectRoot: string, spec: CommandCheckSpec): VerifyChe
|
|
|
180
183
|
command: commandLabel,
|
|
181
184
|
exitCode,
|
|
182
185
|
logTail: tailLines(output, 50),
|
|
186
|
+
...(spec.id === "backend-build" ? {
|
|
187
|
+
diagnostics: [...new Set(output.split(/\r?\n/).filter((line) =>
|
|
188
|
+
/\(\d+,\d+\):\s*error\s+\w+/.test(line) ||
|
|
189
|
+
/^\s*(File ".+", line \d+|(?:Sorry: )?(?:Syntax|Indentation|Tab)Error:|\*\*\* Error compiling)/.test(line)))],
|
|
190
|
+
} : {}),
|
|
183
191
|
},
|
|
184
192
|
suggestedActions: exitCode === 0 ? [] : [spec.failAction],
|
|
185
193
|
};
|
|
@@ -201,6 +209,86 @@ function runCommandCheck(projectRoot: string, spec: CommandCheckSpec): VerifyChe
|
|
|
201
209
|
}
|
|
202
210
|
}
|
|
203
211
|
|
|
212
|
+
function backendUnavailable(reason: string): VerifyCheckResult {
|
|
213
|
+
return {
|
|
214
|
+
id: "backend-build",
|
|
215
|
+
title: "Standalone Functions compilation",
|
|
216
|
+
status: "skip",
|
|
217
|
+
durationMs: 0,
|
|
218
|
+
fixable: false,
|
|
219
|
+
evidence: { logTail: [reason], diagnostics: [reason] },
|
|
220
|
+
suggestedActions: ["Install or restore the backend toolchain, then re-run verify with --checks \"backend-build\". A skipped check is not backend validation."],
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function runBackendBuildCheck(projectRoot: string): VerifyCheckResult {
|
|
225
|
+
const functionsRoot = path.join(projectRoot, "functions");
|
|
226
|
+
if (!fs.existsSync(functionsRoot)) return backendUnavailable("functions/ not found; no standalone backend was checked.");
|
|
227
|
+
const configPath = ["swallowkit.config.json", "swallowkit.config.js", ".swallowkitrc.json"]
|
|
228
|
+
.map((name) => path.join(projectRoot, name)).find((file) => fs.existsSync(file));
|
|
229
|
+
if (!configPath) return backendUnavailable("SwallowKit configuration not found; backend language is unknown.");
|
|
230
|
+
// Same effective language as generation (getBackendLanguage): env override, then file, invalid -> typescript.
|
|
231
|
+
const configured = loadConfigFromEnv().backend?.language ?? loadConfig(configPath, true, true).backend?.language;
|
|
232
|
+
const language = configured && ["typescript", "csharp", "python"].includes(configured) ? configured : "typescript";
|
|
233
|
+
let command: string;
|
|
234
|
+
let args: string[];
|
|
235
|
+
if (language === "csharp") {
|
|
236
|
+
command = "dotnet";
|
|
237
|
+
args = ["build", "--nologo"];
|
|
238
|
+
const probe = spawnSync(command, ["--version"], { cwd: functionsRoot, encoding: "utf-8", timeout: 30_000 });
|
|
239
|
+
if (probe.error && "code" in probe.error && probe.error.code === "ENOENT") return backendUnavailable("dotnet SDK is not installed or is not on PATH; C# compilation was skipped.");
|
|
240
|
+
} else if (language === "python") {
|
|
241
|
+
const venvPython = process.platform === "win32"
|
|
242
|
+
? path.join(functionsRoot, ".venv", "Scripts", "python.exe")
|
|
243
|
+
: path.join(functionsRoot, ".venv", "bin", "python");
|
|
244
|
+
const candidates = fs.existsSync(venvPython)
|
|
245
|
+
? [{ command: venvPython, args: [] as string[] }]
|
|
246
|
+
: process.platform === "win32"
|
|
247
|
+
? [{ command: "python", args: [] }, { command: "python3", args: [] }, { command: "py", args: ["-3"] }]
|
|
248
|
+
: [{ command: "python3", args: [] }, { command: "python", args: [] }];
|
|
249
|
+
const python = candidates.find((candidate) => {
|
|
250
|
+
const probe = spawnSync(candidate.command, [...candidate.args, "-c", "import sys; sys.exit(0 if sys.version_info.major == 3 else 1)"], {
|
|
251
|
+
cwd: functionsRoot, encoding: "utf-8", timeout: 30_000,
|
|
252
|
+
});
|
|
253
|
+
// Preserve execution errors for an installed interpreter instead of silently falling back.
|
|
254
|
+
return probe.status === 0 || (probe.error && (!("code" in probe.error) || probe.error.code !== "ENOENT"));
|
|
255
|
+
});
|
|
256
|
+
if (!python) return backendUnavailable("Python 3 is not available in functions/.venv or on PATH; Python syntax compilation was skipped.");
|
|
257
|
+
command = python.command;
|
|
258
|
+
// -f: never trust cached bytecode, which can survive same-size edits within one mtime second.
|
|
259
|
+
args = [...python.args, "-m", "compileall", "-q", "-f", "-x", "[/\\\\](?:\\.venv|\\.codegen-venv|node_modules|__pycache__)(?:[/\\\\]|$)", "."];
|
|
260
|
+
} else {
|
|
261
|
+
let tscPath: string;
|
|
262
|
+
try {
|
|
263
|
+
tscPath = require.resolve("typescript/bin/tsc", { paths: [functionsRoot] });
|
|
264
|
+
} catch (error) {
|
|
265
|
+
if (error instanceof Error && "code" in error && error.code === "MODULE_NOT_FOUND") {
|
|
266
|
+
return backendUnavailable("The project's TypeScript compiler is not installed; restore dependencies before verifying functions/.");
|
|
267
|
+
}
|
|
268
|
+
throw error;
|
|
269
|
+
}
|
|
270
|
+
const sharedBuild = runSharedBuildIfPresent(projectRoot);
|
|
271
|
+
if (sharedBuild.ran && !sharedBuild.ok) {
|
|
272
|
+
return {
|
|
273
|
+
id: "backend-build", title: "Standalone Functions compilation", status: sharedBuild.unavailable ? "error" : "fail",
|
|
274
|
+
durationMs: 0, fixable: !sharedBuild.unavailable,
|
|
275
|
+
evidence: { command: sharedBuild.command, logTail: sharedBuild.logTail,
|
|
276
|
+
...(sharedBuild.unavailable ? { errorCode: "verification-command-unavailable" as const } : {}) },
|
|
277
|
+
suggestedActions: ["Fix the shared package build before compiling the TypeScript backend."],
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
command = process.execPath;
|
|
281
|
+
args = [tscPath, "--project", "tsconfig.json", "--noEmit"];
|
|
282
|
+
}
|
|
283
|
+
const result = runCommandCheck(functionsRoot, {
|
|
284
|
+
id: "backend-build", title: "Standalone Functions compilation", command, args, shell: false,
|
|
285
|
+
timeoutMs: 10 * 60 * 1000,
|
|
286
|
+
failAction: "Fix the backend compilation errors in evidence.diagnostics / evidence.logTail, then re-run verify.",
|
|
287
|
+
});
|
|
288
|
+
result.evidence.command = `${result.evidence.command} (in functions/)`;
|
|
289
|
+
return result;
|
|
290
|
+
}
|
|
291
|
+
|
|
204
292
|
function readPackageScripts(projectRoot: string): Record<string, string> {
|
|
205
293
|
const packageJsonPath = path.join(projectRoot, "package.json");
|
|
206
294
|
if (!fs.existsSync(packageJsonPath)) return {};
|
|
@@ -253,6 +341,8 @@ function runTypecheckCheck(projectRoot: string): VerifyCheckResult {
|
|
|
253
341
|
|
|
254
342
|
const scripts = readPackageScripts(projectRoot);
|
|
255
343
|
const pm = detectFromProject(projectRoot);
|
|
344
|
+
// Next.js App Router templates use generated route types (e.g. LayoutProps); create them before tsc.
|
|
345
|
+
const typegenNotes = runNextTypegenIfPresent(projectRoot, pm);
|
|
256
346
|
let command: string;
|
|
257
347
|
let args: string[];
|
|
258
348
|
if (typeof scripts.typecheck === "string") {
|
|
@@ -263,13 +353,33 @@ function runTypecheckCheck(projectRoot: string): VerifyCheckResult {
|
|
|
263
353
|
args = pm === "pnpm" ? ["exec", "tsc", "--noEmit"] : ["exec", "tsc", "--", "--noEmit"];
|
|
264
354
|
}
|
|
265
355
|
|
|
266
|
-
|
|
356
|
+
const result = runCommandCheck(projectRoot, {
|
|
267
357
|
id: "typecheck",
|
|
268
358
|
title: "TypeScript type check",
|
|
269
359
|
command,
|
|
270
360
|
args,
|
|
271
361
|
failAction: "Fix the TypeScript errors listed in evidence.logTail, then re-run verify.",
|
|
272
362
|
});
|
|
363
|
+
if (result.status !== "pass" && typegenNotes.length > 0) {
|
|
364
|
+
result.evidence.logTail = [...typegenNotes, ...(result.evidence.logTail ?? [])];
|
|
365
|
+
}
|
|
366
|
+
return result;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const NEXT_CONFIG_FILES = ["next.config.ts", "next.config.js", "next.config.mjs", "next.config.cjs"];
|
|
370
|
+
|
|
371
|
+
function runNextTypegenIfPresent(projectRoot: string, pm: ReturnType<typeof detectFromProject>): string[] {
|
|
372
|
+
if (!NEXT_CONFIG_FILES.some((file) => fs.existsSync(path.join(projectRoot, file)))) return [];
|
|
373
|
+
if (!fs.existsSync(path.join(projectRoot, "node_modules", "next", "package.json"))) return [];
|
|
374
|
+
const args = pm === "pnpm" ? ["exec", "next", "typegen"] : ["exec", "--", "next", "typegen"];
|
|
375
|
+
const result = spawnSync(getCommands(pm).name, args, {
|
|
376
|
+
cwd: projectRoot,
|
|
377
|
+
shell: true,
|
|
378
|
+
encoding: "utf-8",
|
|
379
|
+
timeout: 2 * 60 * 1000,
|
|
380
|
+
});
|
|
381
|
+
if (!result.error && result.status === 0) return [];
|
|
382
|
+
return [`next typegen did not complete (${result.error?.message ?? `exit ${result.status}`}); route types such as LayoutProps may be missing.`];
|
|
273
383
|
}
|
|
274
384
|
|
|
275
385
|
const SCRIPT_CHECK_TITLES: Record<string, string> = {
|
|
@@ -408,6 +518,8 @@ export async function runVerify(
|
|
|
408
518
|
checks.push(await runDriftCheck(projectRoot));
|
|
409
519
|
} else if (id === "typecheck") {
|
|
410
520
|
checks.push(runTypecheckCheck(projectRoot));
|
|
521
|
+
} else if (id === "backend-build") {
|
|
522
|
+
checks.push(runBackendBuildCheck(projectRoot));
|
|
411
523
|
} else if (id === "build" || id === "lint" || id === "test") {
|
|
412
524
|
checks.push(runScriptCheck(projectRoot, id));
|
|
413
525
|
} else {
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* SwallowKit - Next.js
|
|
2
|
+
* SwallowKit - React and Next.js application scaffolding for Azure
|
|
3
3
|
* Main exports
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -9,6 +9,7 @@ export type {
|
|
|
9
9
|
UseServerFnResult,
|
|
10
10
|
ServerFnMode,
|
|
11
11
|
BackendLanguage,
|
|
12
|
+
FrontendFramework,
|
|
12
13
|
SwallowKitConfig,
|
|
13
14
|
} from "./types";
|
|
14
15
|
|
|
@@ -17,6 +18,7 @@ export {
|
|
|
17
18
|
loadConfig,
|
|
18
19
|
generateConfig,
|
|
19
20
|
getBackendLanguage,
|
|
21
|
+
getFrontendFramework,
|
|
20
22
|
getFullConfig,
|
|
21
23
|
validateConfig,
|
|
22
24
|
} from "./core/config";
|
package/src/machine/contracts.ts
CHANGED
package/src/machine/errors.ts
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import type { MachineOperationStatus } from "./contracts";
|
|
1
|
+
import type { MachineNextAction, MachineOperationStatus } from "./contracts";
|
|
2
2
|
|
|
3
3
|
export class MachineCommandError extends Error {
|
|
4
4
|
readonly code: string;
|
|
5
5
|
readonly details?: unknown;
|
|
6
6
|
readonly status?: MachineOperationStatus;
|
|
7
|
+
readonly nextActions?: MachineNextAction[];
|
|
7
8
|
|
|
8
|
-
constructor(code: string, message: string, details?: unknown, status?: MachineOperationStatus) {
|
|
9
|
+
constructor(code: string, message: string, details?: unknown, status?: MachineOperationStatus, nextActions?: MachineNextAction[]) {
|
|
9
10
|
super(message);
|
|
10
11
|
this.name = "MachineCommandError";
|
|
11
12
|
this.code = code;
|
|
12
13
|
this.details = details;
|
|
13
14
|
this.status = status;
|
|
15
|
+
this.nextActions = nextActions;
|
|
14
16
|
}
|
|
15
17
|
}
|
|
16
18
|
|
package/src/machine/index.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { isSwallowKitProject } from "../core/config";
|
|
|
3
3
|
import { createModelOperation } from "../core/operations/create-model";
|
|
4
4
|
import { applyScaffoldOperation } from "../core/operations/scaffold-apply";
|
|
5
5
|
import { applyAuthOperation, planAuthOperation } from "../core/operations/auth-operations";
|
|
6
|
-
import { applyProvisionOperation, planProvisionOperation } from "../core/operations/provision-operations";
|
|
6
|
+
import { applyProvisionOperation, inspectProvisionOperation, planProvisionOperation } from "../core/operations/provision-operations";
|
|
7
7
|
import { ProcessExitInterceptError } from "../core/operations/runtime";
|
|
8
8
|
import { inspectInfra } from "../core/project/infra";
|
|
9
9
|
import { runMachineScaffoldOperation } from "../core/operations/scaffold-machine";
|
|
@@ -58,6 +58,7 @@ function writeMachineError(command: string, error: unknown): void {
|
|
|
58
58
|
ok: false,
|
|
59
59
|
command,
|
|
60
60
|
status: resolveMachineErrorStatus(error),
|
|
61
|
+
...(error instanceof MachineCommandError && error.nextActions?.length ? { nextActions: error.nextActions } : {}),
|
|
61
62
|
error: toMachineError(error),
|
|
62
63
|
};
|
|
63
64
|
writeMachineResponse(response);
|
|
@@ -140,6 +141,17 @@ function createMachineProgram(): Command {
|
|
|
140
141
|
.showHelpAfterError(false);
|
|
141
142
|
|
|
142
143
|
const inspect = new Command("inspect");
|
|
144
|
+
inspect
|
|
145
|
+
.command("provision")
|
|
146
|
+
.description("Read/wait for an original provision deployment without writes or replay")
|
|
147
|
+
.requiredOption("--plan <runId>", "Original provision plan/execution checkpoint ID")
|
|
148
|
+
.option("--wait-seconds <seconds>", "Bounded read-only wait, 0-3600 seconds (default: 0)", Number)
|
|
149
|
+
.action(async (options: { plan: string; waitSeconds?: number }) => {
|
|
150
|
+
await handleMachineAction("inspect-provision", async () => {
|
|
151
|
+
ensureProjectForMachine();
|
|
152
|
+
return inspectProvisionOperation({ planId: options.plan, waitSeconds: options.waitSeconds });
|
|
153
|
+
}, (result) => ({ status: result.status, nextActions: result.nextActions }));
|
|
154
|
+
});
|
|
143
155
|
inspect
|
|
144
156
|
.command("project")
|
|
145
157
|
.description("Inspect SwallowKit project metadata")
|
|
@@ -272,9 +284,10 @@ function createMachineProgram(): Command {
|
|
|
272
284
|
.description("Generate scaffold artifacts with deterministic JSON output")
|
|
273
285
|
.argument("<model>", "Model file or model name")
|
|
274
286
|
.option("--functions-dir <dir>", "Functions directory", "functions")
|
|
275
|
-
.option("--api-dir <dir>", "
|
|
287
|
+
.option("--api-dir <dir>", "BFF routes directory (Next.js: app/api; React: bff)")
|
|
276
288
|
.option("--api-only", "Skip UI components; still update Functions, BFF routes, OpenAPI, and native schema assets", false)
|
|
277
|
-
.
|
|
289
|
+
.option("--skip-infra", "Do not create or update anything under infra/ (container migration is reported as pending)", false)
|
|
290
|
+
.action(async (model: string, options: { functionsDir?: string; apiDir?: string; apiOnly?: boolean; skipInfra?: boolean }) => {
|
|
278
291
|
await handleMachineAction("generate-scaffold", async () => {
|
|
279
292
|
ensureProjectForMachine();
|
|
280
293
|
return runMachineScaffoldOperation({
|
|
@@ -282,6 +295,7 @@ function createMachineProgram(): Command {
|
|
|
282
295
|
functionsDir: options.functionsDir,
|
|
283
296
|
apiDir: options.apiDir,
|
|
284
297
|
apiOnly: options.apiOnly,
|
|
298
|
+
skipInfra: options.skipInfra,
|
|
285
299
|
});
|
|
286
300
|
});
|
|
287
301
|
});
|
|
@@ -292,9 +306,10 @@ function createMachineProgram(): Command {
|
|
|
292
306
|
.description("Compute the scaffold change plan without writing any files (accepts multiple models)")
|
|
293
307
|
.argument("<models...>", "Model files or model names")
|
|
294
308
|
.option("--functions-dir <dir>", "Functions directory", "functions")
|
|
295
|
-
.option("--api-dir <dir>", "
|
|
309
|
+
.option("--api-dir <dir>", "BFF routes directory (Next.js: app/api; React: bff)")
|
|
296
310
|
.option("--api-only", "Skip UI components in the plan", false)
|
|
297
|
-
.
|
|
311
|
+
.option("--skip-infra", "Exclude all infra/ changes (container migration) from the plan", false)
|
|
312
|
+
.action(async (models: string[], options: { functionsDir?: string; apiDir?: string; apiOnly?: boolean; skipInfra?: boolean }) => {
|
|
298
313
|
await handleMachineAction(
|
|
299
314
|
"plan-scaffold",
|
|
300
315
|
async () => {
|
|
@@ -307,6 +322,7 @@ function createMachineProgram(): Command {
|
|
|
307
322
|
functionsDir: options.functionsDir,
|
|
308
323
|
apiDir: options.apiDir,
|
|
309
324
|
apiOnly: options.apiOnly,
|
|
325
|
+
skipInfra: options.skipInfra,
|
|
310
326
|
})
|
|
311
327
|
);
|
|
312
328
|
}
|
|
@@ -316,12 +332,20 @@ function createMachineProgram(): Command {
|
|
|
316
332
|
const plans = "plans" in data ? data.plans : [data];
|
|
317
333
|
return {
|
|
318
334
|
status: plans.some((planData) => planData.requiresApproval) ? "requires-human" : "complete",
|
|
319
|
-
nextActions:
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
335
|
+
nextActions: [
|
|
336
|
+
...plans.map((planData) => ({
|
|
337
|
+
command: `swallowkit machine apply scaffold --plan ${planData.planId}${planData.requiresApproval ? " --approve" : ""}`,
|
|
338
|
+
description: planData.requiresApproval
|
|
339
|
+
? `Apply the plan for ${planData.model} after reviewing the listed conflicts (requires --approve).`
|
|
340
|
+
: `Apply the plan for ${planData.model}.`,
|
|
341
|
+
})),
|
|
342
|
+
...plans
|
|
343
|
+
.filter((planData) => planData.warnings.some((warning) => warning.startsWith("infra-skipped:")))
|
|
344
|
+
.map((planData) => ({
|
|
345
|
+
command: `swallowkit migrations add-model ${planData.model}`,
|
|
346
|
+
description: `Later, when infrastructure changes are allowed, generate only the Cosmos DB container migration for ${planData.model}.`,
|
|
347
|
+
})),
|
|
348
|
+
],
|
|
325
349
|
};
|
|
326
350
|
}
|
|
327
351
|
);
|
|
@@ -360,7 +384,7 @@ function createMachineProgram(): Command {
|
|
|
360
384
|
|
|
361
385
|
plan
|
|
362
386
|
.command("provision")
|
|
363
|
-
.description("
|
|
387
|
+
.description("Review local infrastructure and current Azure state without writes (requires az login)")
|
|
364
388
|
.requiredOption("-g, --resource-group <name>", "Resource group name")
|
|
365
389
|
.requiredOption("--location <region>", "Primary location for Functions and Cosmos DB")
|
|
366
390
|
.requiredOption("--swa-location <region>", "Static Web App location")
|
|
@@ -369,7 +393,8 @@ function createMachineProgram(): Command {
|
|
|
369
393
|
.option("--adopt-existing", "Adopt an existing untagged resource group without deploying main.bicep", false)
|
|
370
394
|
.option("--baseline <version>", "Baseline version for adoption", (value) => Number(value))
|
|
371
395
|
.option("--reconcile", "Explicitly redeploy infra/main.bicep", false)
|
|
372
|
-
.
|
|
396
|
+
.option("--resume-deployment <name>", "Recover a matching older baseline deployment without re-submitting Bicep")
|
|
397
|
+
.action(async (options: { resourceGroup: string; location: string; swaLocation: string; subscription?: string; whatIf?: boolean; adoptExisting?: boolean; baseline?: number; reconcile?: boolean; resumeDeployment?: string }) => {
|
|
373
398
|
await handleMachineAction(
|
|
374
399
|
"plan-provision",
|
|
375
400
|
async () => {
|
|
@@ -383,6 +408,7 @@ function createMachineProgram(): Command {
|
|
|
383
408
|
adoptExisting: options.adoptExisting,
|
|
384
409
|
baseline: options.baseline,
|
|
385
410
|
reconcile: options.reconcile,
|
|
411
|
+
resumeDeployment: options.resumeDeployment,
|
|
386
412
|
});
|
|
387
413
|
},
|
|
388
414
|
(planData) => ({
|
|
@@ -408,10 +434,11 @@ function createMachineProgram(): Command {
|
|
|
408
434
|
.option("--functions-dir <dir>", "Functions directory")
|
|
409
435
|
.option("--api-dir <dir>", "API routes directory")
|
|
410
436
|
.option("--api-only", "Skip UI components; still update Functions, BFF routes, OpenAPI, and native schema assets")
|
|
437
|
+
.option("--skip-infra", "Do not create or update anything under infra/ (container migration is reported as pending)")
|
|
411
438
|
.action(
|
|
412
439
|
async (
|
|
413
440
|
models: string[],
|
|
414
|
-
options: { plan?: string; approve?: boolean; functionsDir?: string; apiDir?: string; apiOnly?: boolean }
|
|
441
|
+
options: { plan?: string; approve?: boolean; functionsDir?: string; apiDir?: string; apiOnly?: boolean; skipInfra?: boolean }
|
|
415
442
|
) => {
|
|
416
443
|
await handleMachineAction(
|
|
417
444
|
"apply-scaffold",
|
|
@@ -433,6 +460,7 @@ function createMachineProgram(): Command {
|
|
|
433
460
|
functionsDir: options.functionsDir,
|
|
434
461
|
apiDir: options.apiDir,
|
|
435
462
|
apiOnly: options.apiOnly,
|
|
463
|
+
skipInfra: options.skipInfra,
|
|
436
464
|
});
|
|
437
465
|
}
|
|
438
466
|
const results = [];
|
|
@@ -444,20 +472,30 @@ function createMachineProgram(): Command {
|
|
|
444
472
|
functionsDir: options.functionsDir,
|
|
445
473
|
apiDir: options.apiDir,
|
|
446
474
|
apiOnly: options.apiOnly,
|
|
475
|
+
skipInfra: options.skipInfra,
|
|
447
476
|
})
|
|
448
477
|
);
|
|
449
478
|
}
|
|
450
479
|
return { applyType: "scaffold-batch" as const, results };
|
|
451
480
|
},
|
|
452
|
-
() =>
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
481
|
+
(data) => {
|
|
482
|
+
const results = "results" in data ? data.results : [data];
|
|
483
|
+
return {
|
|
484
|
+
status: "complete",
|
|
485
|
+
nextActions: [
|
|
486
|
+
{
|
|
487
|
+
command: "swallowkit machine verify project",
|
|
488
|
+
description: "Verify the project after applying scaffold changes.",
|
|
489
|
+
},
|
|
490
|
+
...results
|
|
491
|
+
.filter((result) => result.warnings.some((warning) => warning.startsWith("infra-skipped:")))
|
|
492
|
+
.map((result) => ({
|
|
493
|
+
command: `swallowkit migrations add-model ${result.model}`,
|
|
494
|
+
description: `The Cosmos DB container migration for ${result.model} is still pending; generate it when infrastructure changes are allowed.`,
|
|
495
|
+
})),
|
|
496
|
+
],
|
|
497
|
+
};
|
|
498
|
+
}
|
|
461
499
|
);
|
|
462
500
|
}
|
|
463
501
|
);
|
|
@@ -521,32 +559,25 @@ function createMachineProgram(): Command {
|
|
|
521
559
|
.description("Apply an approved provisioning plan (always requires --approve; creates billable Azure resources)")
|
|
522
560
|
.requiredOption("--plan <planId>", "Provision plan to apply")
|
|
523
561
|
.option("--approve", "Confirm human approval of the provisioning plan", false)
|
|
524
|
-
.
|
|
562
|
+
.option("--wait-seconds <seconds>", "Bounded state wait, 0-3600 seconds (default: 300)", Number)
|
|
563
|
+
.action(async (options: { plan: string; approve?: boolean; waitSeconds?: number }) => {
|
|
525
564
|
await handleMachineAction(
|
|
526
565
|
"apply-provision",
|
|
527
566
|
async () => {
|
|
528
567
|
ensureProjectForMachine();
|
|
529
|
-
return applyProvisionOperation({ planId: options.plan, approve: options.approve });
|
|
568
|
+
return applyProvisionOperation({ planId: options.plan, approve: options.approve, waitSeconds: options.waitSeconds });
|
|
530
569
|
},
|
|
531
|
-
() => ({
|
|
532
|
-
status: "complete",
|
|
533
|
-
nextActions: [
|
|
534
|
-
{
|
|
535
|
-
command: "swallowkit machine inspect infra",
|
|
536
|
-
description: "Re-inspect infra assets after provisioning.",
|
|
537
|
-
},
|
|
538
|
-
],
|
|
539
|
-
})
|
|
570
|
+
(result) => ({ status: result.status, nextActions: result.nextActions })
|
|
540
571
|
);
|
|
541
572
|
});
|
|
542
573
|
|
|
543
574
|
const verify = new Command("verify");
|
|
544
575
|
verify
|
|
545
576
|
.command("project")
|
|
546
|
-
.description("Run verification checks (structure, drift, typecheck) with machine-readable evidence")
|
|
577
|
+
.description("Run verification checks (structure, drift, typecheck, backend-build) with machine-readable evidence")
|
|
547
578
|
.option(
|
|
548
579
|
"--checks <ids>",
|
|
549
|
-
"Comma-separated check ids to run (structure,drift,typecheck,build,lint,test, plus custom ids from swallowkit.config verify.checks)"
|
|
580
|
+
"Comma-separated check ids to run (structure,drift,typecheck,backend-build,build,lint,test, plus custom ids from swallowkit.config verify.checks); quote CSV values in PowerShell"
|
|
550
581
|
)
|
|
551
582
|
.option("--compact", "Suppress info-severity findings/violations from evidence to keep agent-facing output small", false)
|
|
552
583
|
.action(async (options: { checks?: string; compact?: boolean }) => {
|