swallowkit 2.0.0-alpha.3 → 2.0.0-alpha.5
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/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/init.d.ts +6 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +19 -5
- 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 +2 -0
- package/dist/cli/commands/provision.d.ts.map +1 -1
- package/dist/cli/commands/provision.js +45 -16
- 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 +29 -4
- 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/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-operations.d.ts +19 -1
- package/dist/core/operations/provision-operations.d.ts.map +1 -1
- package/dist/core/operations/provision-operations.js +62 -35
- 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/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 +2 -0
- package/dist/core/project/capabilities.d.ts.map +1 -1
- package/dist/core/project/capabilities.js +29 -5
- package/dist/core/project/capabilities.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.js +1 -1
- package/dist/core/project/workflows.d.ts.map +1 -1
- package/dist/core/project/workflows.js +23 -5
- 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 +18 -19
- 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 +289 -76
- 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 +42 -17
- package/dist/machine/index.js.map +1 -1
- package/dist/mcp/index.d.ts +4 -2
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +154 -15
- 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 +44 -0
- package/dist/utils/azure-cli.d.ts.map +1 -0
- package/dist/utils/azure-cli.js +164 -0
- package/dist/utils/azure-cli.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-loop-phase34.test.ts +124 -0
- package/src/__tests__/azure-cli.test.ts +199 -0
- package/src/__tests__/boundaries.test.ts +42 -0
- package/src/__tests__/csharp-schema.test.ts +261 -0
- package/src/__tests__/generated-project-matrix.test.ts +789 -0
- package/src/__tests__/mcp-version.test.ts +262 -0
- package/src/__tests__/mcp.test.ts +64 -3
- package/src/__tests__/multi-auth.test.ts +115 -4
- package/src/__tests__/plan-apply.test.ts +170 -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/init.ts +23 -8
- package/src/cli/commands/migrations.ts +22 -0
- package/src/cli/commands/provision.ts +53 -17
- package/src/cli/commands/scaffold.ts +105 -3
- package/src/cli/index.ts +28 -5
- package/src/core/operations/create-model.ts +51 -13
- package/src/core/operations/model-migration.ts +52 -0
- package/src/core/operations/provision-operations.ts +86 -42
- 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-templates/AGENTS.md +67 -6
- package/src/core/project/agent-templates/CLAUDE.md +7 -1
- package/src/core/project/agent-templates/copilot-instructions.md +7 -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 +32 -5
- package/src/core/project/mcp-config.ts +84 -0
- package/src/core/project/react-project.ts +1 -1
- package/src/core/project/workflows.ts +23 -5
- package/src/core/scaffold/auth-generator.ts +18 -19
- package/src/core/scaffold/model-parser.ts +413 -129
- package/src/core/scaffold/native-schema-generator.ts +313 -78
- 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 +45 -20
- package/src/mcp/index.ts +173 -18
- package/src/mcp/version-selection.ts +163 -0
- package/src/utils/azure-cli.ts +154 -0
- package/src/utils/semver.ts +59 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Azure CLI invocation that works without a shell on every platform.
|
|
4
|
+
*
|
|
5
|
+
* On Windows `az` is a batch wrapper (az.cmd). Node cannot spawn it with `shell: false`
|
|
6
|
+
* (ENOENT for "az", EINVAL for "az.cmd"), so the wrapper is resolved explicitly:
|
|
7
|
+
* the MSI layout runs its bundled Python exactly like az.cmd does, and other wrappers
|
|
8
|
+
* run through cmd.exe with every argument quoted.
|
|
9
|
+
*/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
+
}) : function(o, v) {
|
|
24
|
+
o["default"] = v;
|
|
25
|
+
});
|
|
26
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
27
|
+
var ownKeys = function(o) {
|
|
28
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
29
|
+
var ar = [];
|
|
30
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
31
|
+
return ar;
|
|
32
|
+
};
|
|
33
|
+
return ownKeys(o);
|
|
34
|
+
};
|
|
35
|
+
return function (mod) {
|
|
36
|
+
if (mod && mod.__esModule) return mod;
|
|
37
|
+
var result = {};
|
|
38
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
39
|
+
__setModuleDefault(result, mod);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
})();
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.resolveAzCliInvocation = resolveAzCliInvocation;
|
|
45
|
+
exports.buildBatchCommandLine = buildBatchCommandLine;
|
|
46
|
+
exports.getAzCliInvocation = getAzCliInvocation;
|
|
47
|
+
exports.resetAzCliInvocationCache = resetAzCliInvocationCache;
|
|
48
|
+
exports.setAzCliInvocationForTesting = setAzCliInvocationForTesting;
|
|
49
|
+
exports.runAzCli = runAzCli;
|
|
50
|
+
exports.checkAzCliAvailability = checkAzCliAvailability;
|
|
51
|
+
const child_process_1 = require("child_process");
|
|
52
|
+
const fs = __importStar(require("fs"));
|
|
53
|
+
const path = __importStar(require("path"));
|
|
54
|
+
function findOnWindowsPath(name, env) {
|
|
55
|
+
const pathValue = env.PATH ?? env.Path ?? "";
|
|
56
|
+
const extensions = (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean).map((ext) => ext.toLowerCase());
|
|
57
|
+
for (const directory of pathValue.split(";").filter(Boolean)) {
|
|
58
|
+
for (const extension of extensions) {
|
|
59
|
+
const candidate = path.join(directory.replace(/^"|"$/g, ""), `${name}${extension}`);
|
|
60
|
+
try {
|
|
61
|
+
if (fs.statSync(candidate).isFile())
|
|
62
|
+
return candidate;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// Keep searching PATH.
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
function resolveAzCliInvocation(env = process.env, platform = process.platform) {
|
|
72
|
+
if (platform !== "win32")
|
|
73
|
+
return { command: "az", prefixArgs: [], source: "az" };
|
|
74
|
+
const resolved = findOnWindowsPath("az", env);
|
|
75
|
+
if (!resolved)
|
|
76
|
+
return null;
|
|
77
|
+
const extension = path.extname(resolved).toLowerCase();
|
|
78
|
+
if (extension === ".exe" || extension === ".com") {
|
|
79
|
+
return { command: resolved, prefixArgs: [], source: resolved };
|
|
80
|
+
}
|
|
81
|
+
// MSI install: wbin\az.cmd runs "..\python.exe -IBm azure.cli %*" with AZ_INSTALLER=MSI.
|
|
82
|
+
const bundledPython = path.join(path.dirname(resolved), "..", "python.exe");
|
|
83
|
+
if (path.basename(path.dirname(resolved)).toLowerCase() === "wbin" && fs.existsSync(bundledPython)) {
|
|
84
|
+
return {
|
|
85
|
+
command: path.resolve(bundledPython),
|
|
86
|
+
prefixArgs: ["-IBm", "azure.cli"],
|
|
87
|
+
env: { AZ_INSTALLER: "MSI" },
|
|
88
|
+
source: resolved,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return { command: env.ComSpec ?? "cmd.exe", prefixArgs: [], batchScript: resolved, source: resolved };
|
|
92
|
+
}
|
|
93
|
+
/** Builds the cmd.exe /s /c payload. Rejects characters cmd.exe would reinterpret even inside quotes. */
|
|
94
|
+
function buildBatchCommandLine(script, args) {
|
|
95
|
+
for (const value of [script, ...args]) {
|
|
96
|
+
if (/["%\r\n]/.test(value)) {
|
|
97
|
+
throw new Error(`Azure CLI argument cannot be passed safely through ${path.basename(script)}: ${JSON.stringify(value)}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return `"${[script, ...args].map((value) => `"${value}"`).join(" ")}"`;
|
|
101
|
+
}
|
|
102
|
+
let cachedInvocation;
|
|
103
|
+
function getAzCliInvocation() {
|
|
104
|
+
if (cachedInvocation === undefined)
|
|
105
|
+
cachedInvocation = resolveAzCliInvocation();
|
|
106
|
+
return cachedInvocation;
|
|
107
|
+
}
|
|
108
|
+
function resetAzCliInvocationCache() {
|
|
109
|
+
cachedInvocation = undefined;
|
|
110
|
+
}
|
|
111
|
+
/** Test hook: pin the resolved invocation (null = not found). */
|
|
112
|
+
function setAzCliInvocationForTesting(invocation) {
|
|
113
|
+
cachedInvocation = invocation;
|
|
114
|
+
}
|
|
115
|
+
function runAzCli(args, options = {}) {
|
|
116
|
+
const invocation = options.invocation === undefined ? getAzCliInvocation() : options.invocation;
|
|
117
|
+
if (!invocation) {
|
|
118
|
+
return { status: null, stdout: "", stderr: "", error: Object.assign(new Error("az was not found on PATH"), { code: "ENOENT" }) };
|
|
119
|
+
}
|
|
120
|
+
const spawnOptions = {
|
|
121
|
+
shell: false,
|
|
122
|
+
encoding: "utf-8",
|
|
123
|
+
timeout: options.timeout ?? 300000,
|
|
124
|
+
env: invocation.env ? { ...process.env, ...invocation.env } : process.env,
|
|
125
|
+
};
|
|
126
|
+
let result;
|
|
127
|
+
try {
|
|
128
|
+
result = invocation.batchScript
|
|
129
|
+
? (0, child_process_1.spawnSync)(invocation.command, ["/d", "/s", "/v:off", "/c", buildBatchCommandLine(invocation.batchScript, args)], {
|
|
130
|
+
...spawnOptions,
|
|
131
|
+
windowsVerbatimArguments: true,
|
|
132
|
+
})
|
|
133
|
+
: (0, child_process_1.spawnSync)(invocation.command, [...invocation.prefixArgs, ...args], spawnOptions);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
return { status: null, stdout: "", stderr: "", error: error instanceof Error ? error : new Error(String(error)) };
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
status: result.status,
|
|
140
|
+
stdout: String(result.stdout ?? ""),
|
|
141
|
+
stderr: String(result.stderr ?? ""),
|
|
142
|
+
...(result.error ? { error: result.error } : {}),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function checkAzCliAvailability() {
|
|
146
|
+
const invocation = getAzCliInvocation();
|
|
147
|
+
if (!invocation) {
|
|
148
|
+
return { available: false, reason: "not-found", detail: "az was not found on PATH." };
|
|
149
|
+
}
|
|
150
|
+
const result = runAzCli(["--version"], { timeout: 60000, invocation });
|
|
151
|
+
if (result.status === 0)
|
|
152
|
+
return { available: true, invocation };
|
|
153
|
+
const errorCode = result.error?.code;
|
|
154
|
+
if (errorCode === "ENOENT") {
|
|
155
|
+
return { available: false, reason: "not-found", detail: "az was not found on PATH." };
|
|
156
|
+
}
|
|
157
|
+
const output = `${result.stderr || result.stdout}`.trim().split(/\r?\n/).slice(-3).join(" ");
|
|
158
|
+
return {
|
|
159
|
+
available: false,
|
|
160
|
+
reason: "not-runnable",
|
|
161
|
+
detail: `${invocation.source} could not run "az --version" (${result.error?.message ?? `exit ${result.status}`})${output ? `: ${output}` : ""}`,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=azure-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"azure-cli.js","sourceRoot":"","sources":["../../src/utils/azure-cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface ParsedSemver {
|
|
2
|
+
major: number;
|
|
3
|
+
minor: number;
|
|
4
|
+
patch: number;
|
|
5
|
+
prerelease: Array<string | number>;
|
|
6
|
+
}
|
|
7
|
+
export declare function parseSemver(value: string | null | undefined): ParsedSemver | null;
|
|
8
|
+
export declare function isPrerelease(value: string): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Compares versions by SemVer 2.0 precedence. Build metadata is ignored.
|
|
11
|
+
* Returns null when either value is not a valid version.
|
|
12
|
+
*/
|
|
13
|
+
export declare function compareSemver(left: string, right: string): number | null;
|
|
14
|
+
//# sourceMappingURL=semver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semver.d.ts","sourceRoot":"","sources":["../../src/utils/semver.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;CACpC;AAKD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,YAAY,GAAG,IAAI,CAWjF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA2BxE"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseSemver = parseSemver;
|
|
4
|
+
exports.isPrerelease = isPrerelease;
|
|
5
|
+
exports.compareSemver = compareSemver;
|
|
6
|
+
const SEMVER_PATTERN = /^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
7
|
+
function parseSemver(value) {
|
|
8
|
+
const match = typeof value === "string" ? SEMVER_PATTERN.exec(value.trim()) : null;
|
|
9
|
+
if (!match)
|
|
10
|
+
return null;
|
|
11
|
+
return {
|
|
12
|
+
major: Number(match[1]),
|
|
13
|
+
minor: Number(match[2]),
|
|
14
|
+
patch: Number(match[3]),
|
|
15
|
+
prerelease: match[4]
|
|
16
|
+
? match[4].split(".").map((identifier) => (/^\d+$/.test(identifier) ? Number(identifier) : identifier))
|
|
17
|
+
: [],
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function isPrerelease(value) {
|
|
21
|
+
return (parseSemver(value)?.prerelease.length ?? 0) > 0;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Compares versions by SemVer 2.0 precedence. Build metadata is ignored.
|
|
25
|
+
* Returns null when either value is not a valid version.
|
|
26
|
+
*/
|
|
27
|
+
function compareSemver(left, right) {
|
|
28
|
+
const a = parseSemver(left);
|
|
29
|
+
const b = parseSemver(right);
|
|
30
|
+
if (!a || !b)
|
|
31
|
+
return null;
|
|
32
|
+
for (const key of ["major", "minor", "patch"]) {
|
|
33
|
+
if (a[key] !== b[key])
|
|
34
|
+
return a[key] < b[key] ? -1 : 1;
|
|
35
|
+
}
|
|
36
|
+
if (a.prerelease.length === 0 || b.prerelease.length === 0) {
|
|
37
|
+
if (a.prerelease.length === b.prerelease.length)
|
|
38
|
+
return 0;
|
|
39
|
+
return a.prerelease.length === 0 ? 1 : -1;
|
|
40
|
+
}
|
|
41
|
+
const length = Math.max(a.prerelease.length, b.prerelease.length);
|
|
42
|
+
for (let index = 0; index < length; index++) {
|
|
43
|
+
const leftId = a.prerelease[index];
|
|
44
|
+
const rightId = b.prerelease[index];
|
|
45
|
+
if (leftId === undefined)
|
|
46
|
+
return -1;
|
|
47
|
+
if (rightId === undefined)
|
|
48
|
+
return 1;
|
|
49
|
+
if (leftId === rightId)
|
|
50
|
+
continue;
|
|
51
|
+
if (typeof leftId === "number" && typeof rightId === "number")
|
|
52
|
+
return leftId < rightId ? -1 : 1;
|
|
53
|
+
if (typeof leftId === "number")
|
|
54
|
+
return -1;
|
|
55
|
+
if (typeof rightId === "number")
|
|
56
|
+
return 1;
|
|
57
|
+
return leftId < rightId ? -1 : 1;
|
|
58
|
+
}
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=semver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semver.js","sourceRoot":"","sources":["../../src/utils/semver.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "swallowkit",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.5",
|
|
4
4
|
"description": "Type-safe schema-driven development toolkit for Next.js and React applications on Azure",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -46,21 +46,24 @@
|
|
|
46
46
|
"zod": "^3.25.76"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
+
"@azure/functions": "~4.5.0",
|
|
49
50
|
"@types/jest": "^29.0.0",
|
|
50
51
|
"@types/jsonwebtoken": "^9.0.0",
|
|
51
52
|
"@types/node": "^20.0.0",
|
|
52
53
|
"@types/prompts": "^2.4.9",
|
|
53
54
|
"@types/react": "^18.0.0",
|
|
55
|
+
"@types/react-dom": "^18.3.7",
|
|
54
56
|
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
55
57
|
"@typescript-eslint/parser": "^6.0.0",
|
|
58
|
+
"azure-functions-v3": "npm:@azure/functions@^3.6.0",
|
|
56
59
|
"eslint": "^8.0.0",
|
|
57
60
|
"jest": "^29.0.0",
|
|
61
|
+
"next": "^16.2.6",
|
|
58
62
|
"prettier": "^3.0.0",
|
|
59
63
|
"react": "^18.3.1",
|
|
60
64
|
"react-dom": "^18.3.1",
|
|
61
65
|
"ts-jest": "^29.0.0",
|
|
62
|
-
"vitepress": "^1.6.4"
|
|
63
|
-
"next": "^16.2.6"
|
|
66
|
+
"vitepress": "^1.6.4"
|
|
64
67
|
},
|
|
65
68
|
"engines": {
|
|
66
69
|
"node": ">=22.14.0"
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`inspect boundaries convention rules matches the csharp backend 1`] = `
|
|
4
|
+
[
|
|
5
|
+
{
|
|
6
|
+
"description": "SwallowKit metadata (manifest, artifact ledger, plan state). Managed by tooling only.",
|
|
7
|
+
"editPolicy": "never-hand-edit",
|
|
8
|
+
"pattern": ".swallowkit/",
|
|
9
|
+
"zone": "deterministic",
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"description": "Zod model schemas — the single source of truth. AI/developers author these freely; deterministic generation derives everything else from them.",
|
|
13
|
+
"editPolicy": "free-edit",
|
|
14
|
+
"pattern": "shared/models/",
|
|
15
|
+
"zone": "ai-authored",
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"description": "Infrastructure migration ledger with baseline checksums. Updated by scaffold, \`swallowkit migrations add-model\`, and \`swallowkit create-migration\`.",
|
|
19
|
+
"editPolicy": "never-hand-edit",
|
|
20
|
+
"pattern": "infra/migrations/manifest.json",
|
|
21
|
+
"zone": "deterministic",
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"description": "Versioned Bicep migrations. Edit a migration only before it is provisioned; never change an applied migration — add a new one with \`swallowkit create-migration <slug>\`.",
|
|
25
|
+
"editPolicy": "free-edit",
|
|
26
|
+
"pattern": "infra/migrations/",
|
|
27
|
+
"zone": "ai-authored",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"description": "Baseline infrastructure (main.bicep and modules) whose checksums are recorded in infra/migrations/manifest.json. Hand edits block scaffold with baseline-drift; add resources through a new migration instead.",
|
|
31
|
+
"editPolicy": "never-hand-edit",
|
|
32
|
+
"pattern": "infra/",
|
|
33
|
+
"zone": "deterministic",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"description": "create-model and scaffold append missing model exports while preserving existing content. No managed markers; manual exports are allowed. Keep exports needed by generated code.",
|
|
37
|
+
"editPolicy": "free-edit",
|
|
38
|
+
"pattern": "shared/index.ts",
|
|
39
|
+
"zone": "shared",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"description": "Any path not recorded in the artifact ledger is AI/developer-authored. Business logic, custom pages, custom Functions, and tests belong here.",
|
|
43
|
+
"editPolicy": "free-edit",
|
|
44
|
+
"pattern": "*",
|
|
45
|
+
"zone": "ai-authored",
|
|
46
|
+
},
|
|
47
|
+
]
|
|
48
|
+
`;
|
|
49
|
+
|
|
50
|
+
exports[`inspect boundaries convention rules matches the python backend 1`] = `
|
|
51
|
+
[
|
|
52
|
+
{
|
|
53
|
+
"description": "SwallowKit metadata (manifest, artifact ledger, plan state). Managed by tooling only.",
|
|
54
|
+
"editPolicy": "never-hand-edit",
|
|
55
|
+
"pattern": ".swallowkit/",
|
|
56
|
+
"zone": "deterministic",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"description": "Zod model schemas — the single source of truth. AI/developers author these freely; deterministic generation derives everything else from them.",
|
|
60
|
+
"editPolicy": "free-edit",
|
|
61
|
+
"pattern": "shared/models/",
|
|
62
|
+
"zone": "ai-authored",
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"description": "Infrastructure migration ledger with baseline checksums. Updated by scaffold, \`swallowkit migrations add-model\`, and \`swallowkit create-migration\`.",
|
|
66
|
+
"editPolicy": "never-hand-edit",
|
|
67
|
+
"pattern": "infra/migrations/manifest.json",
|
|
68
|
+
"zone": "deterministic",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"description": "Versioned Bicep migrations. Edit a migration only before it is provisioned; never change an applied migration — add a new one with \`swallowkit create-migration <slug>\`.",
|
|
72
|
+
"editPolicy": "free-edit",
|
|
73
|
+
"pattern": "infra/migrations/",
|
|
74
|
+
"zone": "ai-authored",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"description": "Baseline infrastructure (main.bicep and modules) whose checksums are recorded in infra/migrations/manifest.json. Hand edits block scaffold with baseline-drift; add resources through a new migration instead.",
|
|
78
|
+
"editPolicy": "never-hand-edit",
|
|
79
|
+
"pattern": "infra/",
|
|
80
|
+
"zone": "deterministic",
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"description": "create-model and scaffold append missing model exports while preserving existing content. No managed markers; manual exports are allowed. Keep exports needed by generated code.",
|
|
84
|
+
"editPolicy": "free-edit",
|
|
85
|
+
"pattern": "shared/index.ts",
|
|
86
|
+
"zone": "shared",
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"description": "SwallowKit appends blueprint registrations under its marker; other edits are free.",
|
|
90
|
+
"editPolicy": "edit-outside-markers",
|
|
91
|
+
"pattern": "functions/function_app.py",
|
|
92
|
+
"zone": "shared",
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"description": "SwallowKit appends connector driver requirements when connector models are scaffolded; keep those lines and edit other requirements freely.",
|
|
96
|
+
"editPolicy": "free-edit",
|
|
97
|
+
"pattern": "functions/requirements.txt",
|
|
98
|
+
"zone": "shared",
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"description": "Any path not recorded in the artifact ledger is AI/developer-authored. Business logic, custom pages, custom Functions, and tests belong here.",
|
|
102
|
+
"editPolicy": "free-edit",
|
|
103
|
+
"pattern": "*",
|
|
104
|
+
"zone": "ai-authored",
|
|
105
|
+
},
|
|
106
|
+
]
|
|
107
|
+
`;
|
|
108
|
+
|
|
109
|
+
exports[`inspect boundaries convention rules matches the typescript backend 1`] = `
|
|
110
|
+
[
|
|
111
|
+
{
|
|
112
|
+
"description": "SwallowKit metadata (manifest, artifact ledger, plan state). Managed by tooling only.",
|
|
113
|
+
"editPolicy": "never-hand-edit",
|
|
114
|
+
"pattern": ".swallowkit/",
|
|
115
|
+
"zone": "deterministic",
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"description": "Zod model schemas — the single source of truth. AI/developers author these freely; deterministic generation derives everything else from them.",
|
|
119
|
+
"editPolicy": "free-edit",
|
|
120
|
+
"pattern": "shared/models/",
|
|
121
|
+
"zone": "ai-authored",
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"description": "Infrastructure migration ledger with baseline checksums. Updated by scaffold, \`swallowkit migrations add-model\`, and \`swallowkit create-migration\`.",
|
|
125
|
+
"editPolicy": "never-hand-edit",
|
|
126
|
+
"pattern": "infra/migrations/manifest.json",
|
|
127
|
+
"zone": "deterministic",
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"description": "Versioned Bicep migrations. Edit a migration only before it is provisioned; never change an applied migration — add a new one with \`swallowkit create-migration <slug>\`.",
|
|
131
|
+
"editPolicy": "free-edit",
|
|
132
|
+
"pattern": "infra/migrations/",
|
|
133
|
+
"zone": "ai-authored",
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"description": "Baseline infrastructure (main.bicep and modules) whose checksums are recorded in infra/migrations/manifest.json. Hand edits block scaffold with baseline-drift; add resources through a new migration instead.",
|
|
137
|
+
"editPolicy": "never-hand-edit",
|
|
138
|
+
"pattern": "infra/",
|
|
139
|
+
"zone": "deterministic",
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"description": "create-model and scaffold append missing model exports while preserving existing content. No managed markers; manual exports are allowed. Keep exports needed by generated code.",
|
|
143
|
+
"editPolicy": "free-edit",
|
|
144
|
+
"pattern": "shared/index.ts",
|
|
145
|
+
"zone": "shared",
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"description": "Any path not recorded in the artifact ledger is AI/developer-authored. Business logic, custom pages, custom Functions, and tests belong here.",
|
|
149
|
+
"editPolicy": "free-edit",
|
|
150
|
+
"pattern": "*",
|
|
151
|
+
"zone": "ai-authored",
|
|
152
|
+
},
|
|
153
|
+
]
|
|
154
|
+
`;
|
|
@@ -17,6 +17,7 @@ import { inspectInfra } from "../core/project/infra";
|
|
|
17
17
|
import { loadCustomVerifyChecks, compactVerifyResult, runVerify, VerifyResult } from "../core/verify";
|
|
18
18
|
import { buildAgentSkills, buildWorkflowDocs, writeAgentSkills, writeWorkflowDocs } from "../core/project/workflows";
|
|
19
19
|
import { applyProvisionOperation, planProvisionOperation } from "../core/operations/provision-operations";
|
|
20
|
+
import { resetAzCliInvocationCache, setAzCliInvocationForTesting } from "../utils/azure-cli";
|
|
20
21
|
import { createCustomMigration, initializeLegacyMigrations } from "../core/operations/migration-generator";
|
|
21
22
|
import { createMigrationManifest, encodeMigrationState, getMigrationTagKey, saveMigrationManifest } from "../core/project/migrations";
|
|
22
23
|
|
|
@@ -126,9 +127,12 @@ describe("agent loop phase 3/4", () => {
|
|
|
126
127
|
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "swallowkit-p34-"));
|
|
127
128
|
process.chdir(tempDir);
|
|
128
129
|
(childProcess.spawnSync as unknown as any).mockReturnValue({ status: 1, stdout: "", stderr: "" });
|
|
130
|
+
// Platform-independent az invocation; the Windows wrapper resolution is covered in azure-cli.test.ts.
|
|
131
|
+
setAzCliInvocationForTesting({ command: "az", prefixArgs: [], source: "az" });
|
|
129
132
|
});
|
|
130
133
|
|
|
131
134
|
afterEach(() => {
|
|
135
|
+
resetAzCliInvocationCache();
|
|
132
136
|
process.chdir(originalCwd);
|
|
133
137
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
134
138
|
jest.clearAllMocks();
|
|
@@ -269,6 +273,7 @@ describe("agent loop phase 3/4", () => {
|
|
|
269
273
|
createProjectFixture(tempDir);
|
|
270
274
|
writeFile(path.join(tempDir, "infra", "main.bicep"), SAMPLE_MAIN_BICEP);
|
|
271
275
|
writeFile(path.join(tempDir, "infra", "main.parameters.json"), "{}\n");
|
|
276
|
+
setAzCliInvocationForTesting(null);
|
|
272
277
|
|
|
273
278
|
const plan = await runMachine([
|
|
274
279
|
"node", "swallowkit", "machine", "plan", "provision",
|
|
@@ -508,6 +513,30 @@ describe("agent loop phase 3/4", () => {
|
|
|
508
513
|
);
|
|
509
514
|
});
|
|
510
515
|
|
|
516
|
+
it.each<[string, string[]]>([
|
|
517
|
+
["pnpm", ["exec", "next", "typegen"]],
|
|
518
|
+
["npm", ["exec", "--", "next", "typegen"]],
|
|
519
|
+
])("generates Next.js route types with %s before typechecking", async (packageManager, typegenArgs) => {
|
|
520
|
+
writeFile(
|
|
521
|
+
path.join(tempDir, "package.json"),
|
|
522
|
+
JSON.stringify({ name: "sample-app", devEngines: { packageManager: { name: packageManager, version: ">=10", onFail: "error" } } })
|
|
523
|
+
);
|
|
524
|
+
writeFile(path.join(tempDir, "tsconfig.json"), JSON.stringify({ compilerOptions: { noEmit: true } }));
|
|
525
|
+
writeFile(path.join(tempDir, "next.config.ts"), "export default {};\n");
|
|
526
|
+
writeFile(path.join(tempDir, "node_modules", "next", "package.json"), JSON.stringify({ name: "next", version: "16.0.0" }));
|
|
527
|
+
const spawnSyncMock = childProcess.spawnSync as unknown as ReturnType<typeof jest.fn>;
|
|
528
|
+
spawnSyncMock.mockReset();
|
|
529
|
+
spawnSyncMock
|
|
530
|
+
.mockReturnValueOnce({ status: 1, stdout: "", stderr: "typegen failed" })
|
|
531
|
+
.mockReturnValueOnce({ status: 2, stdout: "app/layout.tsx: Cannot find name 'LayoutProps'.", stderr: "" });
|
|
532
|
+
|
|
533
|
+
const result = await runVerify(["typecheck"], tempDir);
|
|
534
|
+
|
|
535
|
+
expect(spawnSyncMock.mock.calls[0].slice(0, 2)).toEqual([packageManager, typegenArgs]);
|
|
536
|
+
expect(result.checks[0].status).toBe("fail");
|
|
537
|
+
expect(result.checks[0].evidence.logTail?.[0]).toMatch(/^next typegen did not complete \(exit 1\)/);
|
|
538
|
+
});
|
|
539
|
+
|
|
511
540
|
it("uses the existing typecheck script when present", async () => {
|
|
512
541
|
writeFile(
|
|
513
542
|
path.join(tempDir, "package.json"),
|
|
@@ -530,6 +559,101 @@ describe("agent loop phase 3/4", () => {
|
|
|
530
559
|
);
|
|
531
560
|
});
|
|
532
561
|
|
|
562
|
+
it("includes standalone C# compilation in default verification and explains source errors", async () => {
|
|
563
|
+
createProjectFixture(tempDir);
|
|
564
|
+
writeFile(path.join(tempDir, "swallowkit.config.json"), JSON.stringify({ backend: { language: "csharp" } }));
|
|
565
|
+
// The fixture's .js config otherwise takes precedence.
|
|
566
|
+
fs.unlinkSync(path.join(tempDir, "swallowkit.config.js"));
|
|
567
|
+
fs.mkdirSync(path.join(tempDir, "shared", "models"), { recursive: true });
|
|
568
|
+
fs.mkdirSync(path.join(tempDir, "app", "api"), { recursive: true });
|
|
569
|
+
writeFile(path.join(tempDir, "functions", "SwallowKit.Functions.csproj"), "<Project />\n");
|
|
570
|
+
const spawnMock = childProcess.spawnSync as unknown as ReturnType<typeof jest.fn>;
|
|
571
|
+
spawnMock.mockImplementation((command: string, args: string[]) => ({
|
|
572
|
+
status: command === "dotnet" && args[0] === "build" ? 1 : 0,
|
|
573
|
+
stdout: command === "dotnet" && args[0] === "build"
|
|
574
|
+
? `${path.join(tempDir, "functions", "Crud", "ProbeItemCrudFunctions.cs")}(8,7): error CS0246: Functions namespace not found`
|
|
575
|
+
: "",
|
|
576
|
+
stderr: "",
|
|
577
|
+
}));
|
|
578
|
+
const result = await runVerify(undefined, tempDir);
|
|
579
|
+
expect(result.summary.done).toBe(false);
|
|
580
|
+
expect(result.checks).toContainEqual(expect.objectContaining({
|
|
581
|
+
id: "backend-build", status: "fail",
|
|
582
|
+
evidence: expect.objectContaining({ logTail: expect.arrayContaining([expect.stringContaining("(8,7): error CS0246")]) }),
|
|
583
|
+
}));
|
|
584
|
+
const explanation = await runMachine(["node", "swallowkit", "machine", "explain", "failure", "--check", "backend-build"]);
|
|
585
|
+
expect(JSON.stringify(explanation.response)).toContain("(8,7): error CS0246");
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
it.each(["csharp", "python"] as const)("skips %s backend compilation when its toolchain is missing", async (language) => {
|
|
589
|
+
createProjectFixture(tempDir);
|
|
590
|
+
writeFile(path.join(tempDir, "swallowkit.config.js"), `module.exports = { backend: { language: '${language}' } };`);
|
|
591
|
+
const missing = Object.assign(new Error("not found"), { code: "ENOENT" });
|
|
592
|
+
(childProcess.spawnSync as unknown as ReturnType<typeof jest.fn>).mockReturnValue({ status: null, error: missing });
|
|
593
|
+
const result = await runVerify(["backend-build"], tempDir);
|
|
594
|
+
expect(result.checks[0]).toMatchObject({ id: "backend-build", status: "skip" });
|
|
595
|
+
expect(result.checks[0].evidence.diagnostics?.[0]).toMatch(/not installed|not available/);
|
|
596
|
+
expect(result.summary).toMatchObject({ skipped: 1, failed: 0 });
|
|
597
|
+
});
|
|
598
|
+
|
|
599
|
+
it("does not hide an installed backend toolchain execution failure as a skip", async () => {
|
|
600
|
+
createProjectFixture(tempDir);
|
|
601
|
+
writeFile(path.join(tempDir, "swallowkit.config.js"), "module.exports = { backend: { language: 'csharp' } };");
|
|
602
|
+
const denied = Object.assign(new Error("spawn EPERM"), { code: "EPERM" });
|
|
603
|
+
(childProcess.spawnSync as unknown as ReturnType<typeof jest.fn>).mockReturnValue({ status: null, error: denied });
|
|
604
|
+
const result = await runVerify(["backend-build"], tempDir);
|
|
605
|
+
expect(result.checks[0]).toMatchObject({ status: "error", evidence: { errorCode: "verification-command-unavailable" } });
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
it("uses the project's compiler and functions tsconfig for TypeScript backend verification", async () => {
|
|
609
|
+
createProjectFixture(tempDir);
|
|
610
|
+
fs.symlinkSync(path.join(repoRoot, "node_modules", "typescript"), path.join(tempDir, "node_modules", "typescript"), "junction");
|
|
611
|
+
const spawnMock = childProcess.spawnSync as unknown as ReturnType<typeof jest.fn>;
|
|
612
|
+
spawnMock.mockReturnValue({ status: 2, stdout: "src/probe-item.ts(9,3): error TS2322: Invalid type", stderr: "" });
|
|
613
|
+
const result = await runVerify(["backend-build"], tempDir);
|
|
614
|
+
expect(result.summary.done).toBe(false);
|
|
615
|
+
expect(result.checks[0].evidence.diagnostics).toContain("src/probe-item.ts(9,3): error TS2322: Invalid type");
|
|
616
|
+
expect(spawnMock).toHaveBeenCalledWith(process.execPath, [
|
|
617
|
+
expect.stringContaining(path.join("typescript", "bin", "tsc")), "--project", "tsconfig.json", "--noEmit",
|
|
618
|
+
], expect.objectContaining({ cwd: path.join(tempDir, "functions"), shell: false }));
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
it("prefers the existing Python dev virtualenv and includes source syntax errors", async () => {
|
|
622
|
+
createProjectFixture(tempDir);
|
|
623
|
+
writeFile(path.join(tempDir, "swallowkit.config.js"), "module.exports = { backend: { language: 'python' } };");
|
|
624
|
+
const python = path.join(tempDir, "functions", ".venv", ...(process.platform === "win32" ? ["Scripts", "python.exe"] : ["bin", "python"]));
|
|
625
|
+
writeFile(python, "mock interpreter");
|
|
626
|
+
const spawnMock = childProcess.spawnSync as unknown as ReturnType<typeof jest.fn>;
|
|
627
|
+
spawnMock.mockImplementation((_command: string, args: string[]) => args.includes("compileall")
|
|
628
|
+
? { status: 1, stdout: '*** Error compiling "./blueprints/probe_item.py"...\n File "./blueprints/probe_item.py", line 12\nSyntaxError: invalid syntax', stderr: "" }
|
|
629
|
+
: { status: 0, stdout: "", stderr: "" });
|
|
630
|
+
const result = await runVerify(["backend-build"], tempDir);
|
|
631
|
+
expect(result.checks[0].status).toBe("fail");
|
|
632
|
+
expect(result.checks[0].evidence.diagnostics).toContain(' File "./blueprints/probe_item.py", line 12');
|
|
633
|
+
expect(spawnMock).toHaveBeenCalledWith(python, [
|
|
634
|
+
"-m", "compileall", "-q", "-f", "-x", expect.stringContaining(".codegen-venv"), ".",
|
|
635
|
+
], expect.objectContaining({ cwd: path.join(tempDir, "functions"), shell: false }));
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
it.each([
|
|
639
|
+
["python", "python"],
|
|
640
|
+
["unsupported", "typescript"],
|
|
641
|
+
])("resolves the backend like generation when SWALLOWKIT_BACKEND_LANGUAGE=%s", async (override, expected) => {
|
|
642
|
+
createProjectFixture(tempDir); // config file says typescript
|
|
643
|
+
fs.symlinkSync(path.join(repoRoot, "node_modules", "typescript"), path.join(tempDir, "node_modules", "typescript"), "junction");
|
|
644
|
+
const spawnMock = childProcess.spawnSync as unknown as ReturnType<typeof jest.fn>;
|
|
645
|
+
spawnMock.mockReturnValue({ status: 0, stdout: "", stderr: "" });
|
|
646
|
+
const previous = process.env.SWALLOWKIT_BACKEND_LANGUAGE;
|
|
647
|
+
process.env.SWALLOWKIT_BACKEND_LANGUAGE = override;
|
|
648
|
+
try {
|
|
649
|
+
const result = await runVerify(["backend-build"], tempDir);
|
|
650
|
+
expect(result.checks[0].evidence.command).toContain(expected === "python" ? "compileall" : "tsc");
|
|
651
|
+
} finally {
|
|
652
|
+
if (previous === undefined) delete process.env.SWALLOWKIT_BACKEND_LANGUAGE;
|
|
653
|
+
else process.env.SWALLOWKIT_BACKEND_LANGUAGE = previous;
|
|
654
|
+
}
|
|
655
|
+
});
|
|
656
|
+
|
|
533
657
|
it("reports verification command startup failures as blocked", async () => {
|
|
534
658
|
createProjectFixture(tempDir);
|
|
535
659
|
writeFile(path.join(tempDir, "tsconfig.json"), JSON.stringify({ compilerOptions: { noEmit: true } }));
|