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
|
@@ -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
|
+
`;
|
|
@@ -57,6 +57,10 @@ describe("coding-agent instruction contract", () => {
|
|
|
57
57
|
expect(agentsMd).toContain("Verification Is a Completion Gate");
|
|
58
58
|
expect(agentsMd).toContain("semantic code review answers different questions");
|
|
59
59
|
expect(agentsMd).toContain("When the status is `requires-human`, stop");
|
|
60
|
+
expect(agentsMd).toContain("machine inspect provision --plan <runId> --wait-seconds 300");
|
|
61
|
+
expect(agentsMd).toContain("outcome: \"succeeded\"");
|
|
62
|
+
expect(agentsMd).toContain("Never re-submit Bicep");
|
|
63
|
+
expect(agentsMd).toContain("must not switch to normal CLI to bypass it");
|
|
60
64
|
expect(agentsMd).toContain("never bypass its\napproval gate");
|
|
61
65
|
});
|
|
62
66
|
|
|
@@ -88,6 +92,7 @@ describe("coding-agent instruction contract", () => {
|
|
|
88
92
|
expect(adapter).toContain("planning");
|
|
89
93
|
expect(adapter).toContain("Never hand-edit deterministic SwallowKit-managed artifacts");
|
|
90
94
|
expect(adapter).toContain("SwallowKit verification");
|
|
95
|
+
expect(adapter).toContain("approval");
|
|
91
96
|
}
|
|
92
97
|
});
|
|
93
98
|
|
|
@@ -179,7 +184,7 @@ describe("coding-agent documentation synchronization", () => {
|
|
|
179
184
|
}
|
|
180
185
|
|
|
181
186
|
expect(englishGuide).toContain("complete English templates");
|
|
182
|
-
expect(englishGuide).
|
|
187
|
+
expect(englishGuide).toMatch(/not\r?\nabridged excerpts/);
|
|
183
188
|
expect(japaneseGuide).toContain("抜粋ではありません");
|
|
184
189
|
});
|
|
185
190
|
|
|
@@ -17,6 +17,8 @@ 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";
|
|
21
|
+
import * as azureCli from "../utils/azure-cli";
|
|
20
22
|
import { createCustomMigration, initializeLegacyMigrations } from "../core/operations/migration-generator";
|
|
21
23
|
import { createMigrationManifest, encodeMigrationState, getMigrationTagKey, saveMigrationManifest } from "../core/project/migrations";
|
|
22
24
|
|
|
@@ -126,12 +128,17 @@ describe("agent loop phase 3/4", () => {
|
|
|
126
128
|
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "swallowkit-p34-"));
|
|
127
129
|
process.chdir(tempDir);
|
|
128
130
|
(childProcess.spawnSync as unknown as any).mockReturnValue({ status: 1, stdout: "", stderr: "" });
|
|
131
|
+
// Platform-independent az invocation; the Windows wrapper resolution is covered in azure-cli.test.ts.
|
|
132
|
+
setAzCliInvocationForTesting({ command: "az", prefixArgs: [], source: "az" });
|
|
133
|
+
jest.spyOn(azureCli, "runAzCliAsync").mockImplementation(async (args) => azureCli.runAzCli(args));
|
|
129
134
|
});
|
|
130
135
|
|
|
131
136
|
afterEach(() => {
|
|
137
|
+
resetAzCliInvocationCache();
|
|
132
138
|
process.chdir(originalCwd);
|
|
133
139
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
134
140
|
jest.clearAllMocks();
|
|
141
|
+
jest.restoreAllMocks();
|
|
135
142
|
});
|
|
136
143
|
|
|
137
144
|
it("returns the responsibility boundary contract via inspect boundaries", async () => {
|
|
@@ -269,6 +276,7 @@ describe("agent loop phase 3/4", () => {
|
|
|
269
276
|
createProjectFixture(tempDir);
|
|
270
277
|
writeFile(path.join(tempDir, "infra", "main.bicep"), SAMPLE_MAIN_BICEP);
|
|
271
278
|
writeFile(path.join(tempDir, "infra", "main.parameters.json"), "{}\n");
|
|
279
|
+
setAzCliInvocationForTesting(null);
|
|
272
280
|
|
|
273
281
|
const plan = await runMachine([
|
|
274
282
|
"node", "swallowkit", "machine", "plan", "provision",
|
|
@@ -312,11 +320,11 @@ describe("agent loop phase 3/4", () => {
|
|
|
312
320
|
(childProcess.spawnSync as unknown as any).mockImplementation((_file: string, args: string[]) => {
|
|
313
321
|
if (args[0] === "--version") return { status: 0, stdout: "azure-cli", stderr: "" };
|
|
314
322
|
if (args[0] === "group" && args[1] === "exists") return { status: 0, stdout: "true\n", stderr: "" };
|
|
315
|
-
if (args[0] === "group" && args[1] === "show") return { status: 0, stdout: JSON.stringify({ id: "/subscriptions/
|
|
323
|
+
if (args[0] === "group" && args[1] === "show") return { status: 0, stdout: JSON.stringify({ id: "/subscriptions/11111111-1111-1111-1111-111111111111/resourceGroups/rg-sample", tags: {} }), stderr: "" };
|
|
316
324
|
return { status: 1, stdout: "", stderr: "unexpected" };
|
|
317
325
|
});
|
|
318
326
|
|
|
319
|
-
const plan = await planProvisionOperation({ resourceGroup: "rg-sample", location: "japaneast", swaLocation: "eastasia" });
|
|
327
|
+
const plan = await planProvisionOperation({ resourceGroup: "rg-sample", location: "japaneast", swaLocation: "eastasia", subscription: "11111111-1111-1111-1111-111111111111" });
|
|
320
328
|
|
|
321
329
|
expect(plan.mode).toBe("adoption-required");
|
|
322
330
|
expect(plan.commands).toEqual([]);
|
|
@@ -331,7 +339,7 @@ describe("agent loop phase 3/4", () => {
|
|
|
331
339
|
(childProcess.spawnSync as unknown as any).mockImplementation((_file: string, args: string[]) => {
|
|
332
340
|
if (args[0] === "--version") return { status: 0, stdout: "azure-cli", stderr: "" };
|
|
333
341
|
if (args[0] === "group" && args[1] === "exists") return { status: 0, stdout: "true\n", stderr: "" };
|
|
334
|
-
if (args[0] === "group" && args[1] === "show") return { status: 0, stdout: JSON.stringify({ id: "/subscriptions/
|
|
342
|
+
if (args[0] === "group" && args[1] === "show") return { status: 0, stdout: JSON.stringify({ id: "/subscriptions/11111111-1111-1111-1111-111111111111/resourceGroups/rg-sample", tags: {} }), stderr: "" };
|
|
335
343
|
if (args[0] === "deployment" && args[2] === "what-if") {
|
|
336
344
|
return { status: 0, stdout: JSON.stringify({ changes: [{ changeType: "Modify", resourceId: "/functions/sample" }] }), stderr: "" };
|
|
337
345
|
}
|
|
@@ -345,6 +353,7 @@ describe("agent loop phase 3/4", () => {
|
|
|
345
353
|
adoptExisting: true,
|
|
346
354
|
baseline: 0,
|
|
347
355
|
whatIf: true,
|
|
356
|
+
subscription: "11111111-1111-1111-1111-111111111111",
|
|
348
357
|
});
|
|
349
358
|
|
|
350
359
|
expect(plan.mode).toBe("adopt");
|
|
@@ -362,7 +371,7 @@ describe("agent loop phase 3/4", () => {
|
|
|
362
371
|
(childProcess.spawnSync as unknown as any).mockImplementation((_file: string, args: string[]) => {
|
|
363
372
|
if (args[0] === "--version") return { status: 0, stdout: "azure-cli", stderr: "" };
|
|
364
373
|
if (args[0] === "group" && args[1] === "exists") return { status: 0, stdout: "true\n", stderr: "" };
|
|
365
|
-
if (args[0] === "group" && args[1] === "show") return { status: 0, stdout: JSON.stringify({ id: "/subscriptions/
|
|
374
|
+
if (args[0] === "group" && args[1] === "show") return { status: 0, stdout: JSON.stringify({ id: "/subscriptions/11111111-1111-1111-1111-111111111111/resourceGroups/rg-sample", tags: {} }), stderr: "" };
|
|
366
375
|
if (args[0] === "deployment" && args[2] === "what-if") return { status: 0, stdout: JSON.stringify({ changes: [] }), stderr: "" };
|
|
367
376
|
return { status: 1, stdout: "", stderr: "unexpected" };
|
|
368
377
|
});
|
|
@@ -372,6 +381,7 @@ describe("agent loop phase 3/4", () => {
|
|
|
372
381
|
location: "japaneast",
|
|
373
382
|
swaLocation: "eastasia",
|
|
374
383
|
reconcile: true,
|
|
384
|
+
subscription: "11111111-1111-1111-1111-111111111111",
|
|
375
385
|
});
|
|
376
386
|
|
|
377
387
|
expect(plan.mode).toBe("reconcile");
|
|
@@ -393,12 +403,12 @@ describe("agent loop phase 3/4", () => {
|
|
|
393
403
|
if (args[0] === "group" && args[1] === "exists") return { status: 0, stdout: "true\n", stderr: "" };
|
|
394
404
|
if (args[0] === "group" && args[1] === "show") {
|
|
395
405
|
const tagKey = getMigrationTagKey(manifest.projectId);
|
|
396
|
-
return { status: 0, stdout: JSON.stringify({ id: "/subscriptions/
|
|
406
|
+
return { status: 0, stdout: JSON.stringify({ id: "/subscriptions/11111111-1111-1111-1111-111111111111/resourceGroups/rg-sample", tags: { [tagKey]: tagValue } }), stderr: "" };
|
|
397
407
|
}
|
|
398
408
|
return { status: 1, stdout: "", stderr: "unexpected" };
|
|
399
409
|
});
|
|
400
410
|
|
|
401
|
-
const plan = await planProvisionOperation({ resourceGroup: "rg-sample", location: "japaneast", swaLocation: "eastasia" });
|
|
411
|
+
const plan = await planProvisionOperation({ resourceGroup: "rg-sample", location: "japaneast", swaLocation: "eastasia", subscription: "11111111-1111-1111-1111-111111111111" });
|
|
402
412
|
|
|
403
413
|
expect(plan.mode).toBe("migrate");
|
|
404
414
|
expect(plan.pendingMigrations.map((migration) => migration.version)).toEqual([1]);
|
|
@@ -419,7 +429,13 @@ describe("agent loop phase 3/4", () => {
|
|
|
419
429
|
(childProcess.spawnSync as unknown as any).mockImplementation((_file: string, args: string[]) => {
|
|
420
430
|
if (args[0] === "--version") return { status: 0, stdout: "azure-cli", stderr: "" };
|
|
421
431
|
if (args[0] === "group" && args[1] === "exists") return { status: 0, stdout: "true\n", stderr: "" };
|
|
422
|
-
if (args[0] === "group" && args[1] === "show") return { status: 0, stdout: JSON.stringify({ id: "/subscriptions/
|
|
432
|
+
if (args[0] === "group" && args[1] === "show") return { status: 0, stdout: JSON.stringify({ id: "/subscriptions/11111111-1111-1111-1111-111111111111/resourceGroups/rg-sample", tags: { [tagKey]: tagValue } }), stderr: "" };
|
|
433
|
+
if (args[0] === "deployment" && args[2] === "show") {
|
|
434
|
+
const name = args[args.indexOf("--name") + 1];
|
|
435
|
+
return deployedTemplates.length === 0
|
|
436
|
+
? { status: 1, stdout: "", stderr: "DeploymentNotFound" }
|
|
437
|
+
: { status: 0, stdout: JSON.stringify({ id: `/subscriptions/11111111-1111-1111-1111-111111111111/resourceGroups/rg-sample/providers/Microsoft.Resources/deployments/${name}`, state: "Succeeded", correlationId: "fixture-correlation" }), stderr: "" };
|
|
438
|
+
}
|
|
423
439
|
if (args[0] === "deployment" && args[2] === "create") {
|
|
424
440
|
deployedTemplates.push(args[args.indexOf("--template-file") + 1]);
|
|
425
441
|
return { status: 0, stdout: JSON.stringify({ properties: { outputs: {} } }), stderr: "" };
|
|
@@ -431,7 +447,7 @@ describe("agent loop phase 3/4", () => {
|
|
|
431
447
|
return { status: 1, stdout: "", stderr: `unexpected: ${args.join(" ")}` };
|
|
432
448
|
});
|
|
433
449
|
|
|
434
|
-
const plan = await planProvisionOperation({ resourceGroup: "rg-sample", location: "japaneast", swaLocation: "eastasia" });
|
|
450
|
+
const plan = await planProvisionOperation({ resourceGroup: "rg-sample", location: "japaneast", swaLocation: "eastasia", subscription: "11111111-1111-1111-1111-111111111111" });
|
|
435
451
|
const result = await applyProvisionOperation({ planId: plan.planId, approve: true });
|
|
436
452
|
|
|
437
453
|
expect(result.executedCommands).toHaveLength(2);
|
|
@@ -508,6 +524,30 @@ describe("agent loop phase 3/4", () => {
|
|
|
508
524
|
);
|
|
509
525
|
});
|
|
510
526
|
|
|
527
|
+
it.each<[string, string[]]>([
|
|
528
|
+
["pnpm", ["exec", "next", "typegen"]],
|
|
529
|
+
["npm", ["exec", "--", "next", "typegen"]],
|
|
530
|
+
])("generates Next.js route types with %s before typechecking", async (packageManager, typegenArgs) => {
|
|
531
|
+
writeFile(
|
|
532
|
+
path.join(tempDir, "package.json"),
|
|
533
|
+
JSON.stringify({ name: "sample-app", devEngines: { packageManager: { name: packageManager, version: ">=10", onFail: "error" } } })
|
|
534
|
+
);
|
|
535
|
+
writeFile(path.join(tempDir, "tsconfig.json"), JSON.stringify({ compilerOptions: { noEmit: true } }));
|
|
536
|
+
writeFile(path.join(tempDir, "next.config.ts"), "export default {};\n");
|
|
537
|
+
writeFile(path.join(tempDir, "node_modules", "next", "package.json"), JSON.stringify({ name: "next", version: "16.0.0" }));
|
|
538
|
+
const spawnSyncMock = childProcess.spawnSync as unknown as ReturnType<typeof jest.fn>;
|
|
539
|
+
spawnSyncMock.mockReset();
|
|
540
|
+
spawnSyncMock
|
|
541
|
+
.mockReturnValueOnce({ status: 1, stdout: "", stderr: "typegen failed" })
|
|
542
|
+
.mockReturnValueOnce({ status: 2, stdout: "app/layout.tsx: Cannot find name 'LayoutProps'.", stderr: "" });
|
|
543
|
+
|
|
544
|
+
const result = await runVerify(["typecheck"], tempDir);
|
|
545
|
+
|
|
546
|
+
expect(spawnSyncMock.mock.calls[0].slice(0, 2)).toEqual([packageManager, typegenArgs]);
|
|
547
|
+
expect(result.checks[0].status).toBe("fail");
|
|
548
|
+
expect(result.checks[0].evidence.logTail?.[0]).toMatch(/^next typegen did not complete \(exit 1\)/);
|
|
549
|
+
});
|
|
550
|
+
|
|
511
551
|
it("uses the existing typecheck script when present", async () => {
|
|
512
552
|
writeFile(
|
|
513
553
|
path.join(tempDir, "package.json"),
|
|
@@ -530,6 +570,101 @@ describe("agent loop phase 3/4", () => {
|
|
|
530
570
|
);
|
|
531
571
|
});
|
|
532
572
|
|
|
573
|
+
it("includes standalone C# compilation in default verification and explains source errors", async () => {
|
|
574
|
+
createProjectFixture(tempDir);
|
|
575
|
+
writeFile(path.join(tempDir, "swallowkit.config.json"), JSON.stringify({ backend: { language: "csharp" } }));
|
|
576
|
+
// The fixture's .js config otherwise takes precedence.
|
|
577
|
+
fs.unlinkSync(path.join(tempDir, "swallowkit.config.js"));
|
|
578
|
+
fs.mkdirSync(path.join(tempDir, "shared", "models"), { recursive: true });
|
|
579
|
+
fs.mkdirSync(path.join(tempDir, "app", "api"), { recursive: true });
|
|
580
|
+
writeFile(path.join(tempDir, "functions", "SwallowKit.Functions.csproj"), "<Project />\n");
|
|
581
|
+
const spawnMock = childProcess.spawnSync as unknown as ReturnType<typeof jest.fn>;
|
|
582
|
+
spawnMock.mockImplementation((command: string, args: string[]) => ({
|
|
583
|
+
status: command === "dotnet" && args[0] === "build" ? 1 : 0,
|
|
584
|
+
stdout: command === "dotnet" && args[0] === "build"
|
|
585
|
+
? `${path.join(tempDir, "functions", "Crud", "ProbeItemCrudFunctions.cs")}(8,7): error CS0246: Functions namespace not found`
|
|
586
|
+
: "",
|
|
587
|
+
stderr: "",
|
|
588
|
+
}));
|
|
589
|
+
const result = await runVerify(undefined, tempDir);
|
|
590
|
+
expect(result.summary.done).toBe(false);
|
|
591
|
+
expect(result.checks).toContainEqual(expect.objectContaining({
|
|
592
|
+
id: "backend-build", status: "fail",
|
|
593
|
+
evidence: expect.objectContaining({ logTail: expect.arrayContaining([expect.stringContaining("(8,7): error CS0246")]) }),
|
|
594
|
+
}));
|
|
595
|
+
const explanation = await runMachine(["node", "swallowkit", "machine", "explain", "failure", "--check", "backend-build"]);
|
|
596
|
+
expect(JSON.stringify(explanation.response)).toContain("(8,7): error CS0246");
|
|
597
|
+
});
|
|
598
|
+
|
|
599
|
+
it.each(["csharp", "python"] as const)("skips %s backend compilation when its toolchain is missing", async (language) => {
|
|
600
|
+
createProjectFixture(tempDir);
|
|
601
|
+
writeFile(path.join(tempDir, "swallowkit.config.js"), `module.exports = { backend: { language: '${language}' } };`);
|
|
602
|
+
const missing = Object.assign(new Error("not found"), { code: "ENOENT" });
|
|
603
|
+
(childProcess.spawnSync as unknown as ReturnType<typeof jest.fn>).mockReturnValue({ status: null, error: missing });
|
|
604
|
+
const result = await runVerify(["backend-build"], tempDir);
|
|
605
|
+
expect(result.checks[0]).toMatchObject({ id: "backend-build", status: "skip" });
|
|
606
|
+
expect(result.checks[0].evidence.diagnostics?.[0]).toMatch(/not installed|not available/);
|
|
607
|
+
expect(result.summary).toMatchObject({ skipped: 1, failed: 0 });
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
it("does not hide an installed backend toolchain execution failure as a skip", async () => {
|
|
611
|
+
createProjectFixture(tempDir);
|
|
612
|
+
writeFile(path.join(tempDir, "swallowkit.config.js"), "module.exports = { backend: { language: 'csharp' } };");
|
|
613
|
+
const denied = Object.assign(new Error("spawn EPERM"), { code: "EPERM" });
|
|
614
|
+
(childProcess.spawnSync as unknown as ReturnType<typeof jest.fn>).mockReturnValue({ status: null, error: denied });
|
|
615
|
+
const result = await runVerify(["backend-build"], tempDir);
|
|
616
|
+
expect(result.checks[0]).toMatchObject({ status: "error", evidence: { errorCode: "verification-command-unavailable" } });
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
it("uses the project's compiler and functions tsconfig for TypeScript backend verification", async () => {
|
|
620
|
+
createProjectFixture(tempDir);
|
|
621
|
+
fs.symlinkSync(path.join(repoRoot, "node_modules", "typescript"), path.join(tempDir, "node_modules", "typescript"), "junction");
|
|
622
|
+
const spawnMock = childProcess.spawnSync as unknown as ReturnType<typeof jest.fn>;
|
|
623
|
+
spawnMock.mockReturnValue({ status: 2, stdout: "src/probe-item.ts(9,3): error TS2322: Invalid type", stderr: "" });
|
|
624
|
+
const result = await runVerify(["backend-build"], tempDir);
|
|
625
|
+
expect(result.summary.done).toBe(false);
|
|
626
|
+
expect(result.checks[0].evidence.diagnostics).toContain("src/probe-item.ts(9,3): error TS2322: Invalid type");
|
|
627
|
+
expect(spawnMock).toHaveBeenCalledWith(process.execPath, [
|
|
628
|
+
expect.stringContaining(path.join("typescript", "bin", "tsc")), "--project", "tsconfig.json", "--noEmit",
|
|
629
|
+
], expect.objectContaining({ cwd: path.join(tempDir, "functions"), shell: false }));
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
it("prefers the existing Python dev virtualenv and includes source syntax errors", async () => {
|
|
633
|
+
createProjectFixture(tempDir);
|
|
634
|
+
writeFile(path.join(tempDir, "swallowkit.config.js"), "module.exports = { backend: { language: 'python' } };");
|
|
635
|
+
const python = path.join(tempDir, "functions", ".venv", ...(process.platform === "win32" ? ["Scripts", "python.exe"] : ["bin", "python"]));
|
|
636
|
+
writeFile(python, "mock interpreter");
|
|
637
|
+
const spawnMock = childProcess.spawnSync as unknown as ReturnType<typeof jest.fn>;
|
|
638
|
+
spawnMock.mockImplementation((_command: string, args: string[]) => args.includes("compileall")
|
|
639
|
+
? { status: 1, stdout: '*** Error compiling "./blueprints/probe_item.py"...\n File "./blueprints/probe_item.py", line 12\nSyntaxError: invalid syntax', stderr: "" }
|
|
640
|
+
: { status: 0, stdout: "", stderr: "" });
|
|
641
|
+
const result = await runVerify(["backend-build"], tempDir);
|
|
642
|
+
expect(result.checks[0].status).toBe("fail");
|
|
643
|
+
expect(result.checks[0].evidence.diagnostics).toContain(' File "./blueprints/probe_item.py", line 12');
|
|
644
|
+
expect(spawnMock).toHaveBeenCalledWith(python, [
|
|
645
|
+
"-m", "compileall", "-q", "-f", "-x", expect.stringContaining(".codegen-venv"), ".",
|
|
646
|
+
], expect.objectContaining({ cwd: path.join(tempDir, "functions"), shell: false }));
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
it.each([
|
|
650
|
+
["python", "python"],
|
|
651
|
+
["unsupported", "typescript"],
|
|
652
|
+
])("resolves the backend like generation when SWALLOWKIT_BACKEND_LANGUAGE=%s", async (override, expected) => {
|
|
653
|
+
createProjectFixture(tempDir); // config file says typescript
|
|
654
|
+
fs.symlinkSync(path.join(repoRoot, "node_modules", "typescript"), path.join(tempDir, "node_modules", "typescript"), "junction");
|
|
655
|
+
const spawnMock = childProcess.spawnSync as unknown as ReturnType<typeof jest.fn>;
|
|
656
|
+
spawnMock.mockReturnValue({ status: 0, stdout: "", stderr: "" });
|
|
657
|
+
const previous = process.env.SWALLOWKIT_BACKEND_LANGUAGE;
|
|
658
|
+
process.env.SWALLOWKIT_BACKEND_LANGUAGE = override;
|
|
659
|
+
try {
|
|
660
|
+
const result = await runVerify(["backend-build"], tempDir);
|
|
661
|
+
expect(result.checks[0].evidence.command).toContain(expected === "python" ? "compileall" : "tsc");
|
|
662
|
+
} finally {
|
|
663
|
+
if (previous === undefined) delete process.env.SWALLOWKIT_BACKEND_LANGUAGE;
|
|
664
|
+
else process.env.SWALLOWKIT_BACKEND_LANGUAGE = previous;
|
|
665
|
+
}
|
|
666
|
+
});
|
|
667
|
+
|
|
533
668
|
it("reports verification command startup failures as blocked", async () => {
|
|
534
669
|
createProjectFixture(tempDir);
|
|
535
670
|
writeFile(path.join(tempDir, "tsconfig.json"), JSON.stringify({ compilerOptions: { noEmit: true } }));
|
|
@@ -300,6 +300,15 @@ describe("generateLoginPage", () => {
|
|
|
300
300
|
expect(code).toContain("handleSubmit");
|
|
301
301
|
expect(code).toContain("/api/auth/login");
|
|
302
302
|
});
|
|
303
|
+
|
|
304
|
+
it("keeps the shared form legible with either global color scheme", () => {
|
|
305
|
+
const code = generateLoginPage();
|
|
306
|
+
expect(code).toContain("bg-gray-50 dark:bg-gray-900");
|
|
307
|
+
expect(code).toContain("bg-white dark:bg-gray-800");
|
|
308
|
+
expect(code).toContain("text-gray-900 dark:text-gray-100");
|
|
309
|
+
expect(code).toContain("dark:border-gray-600");
|
|
310
|
+
expect(code).toContain("dark:text-red-300");
|
|
311
|
+
});
|
|
303
312
|
});
|
|
304
313
|
|
|
305
314
|
describe("generateAuthContext", () => {
|