swallowkit 2.0.0-alpha.1 → 2.0.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +14 -0
- package/README.md +14 -0
- package/dist/cli/commands/add-auth.js +37 -6
- package/dist/cli/commands/add-auth.js.map +1 -1
- package/dist/cli/commands/configure-mcp.d.ts +12 -0
- package/dist/cli/commands/configure-mcp.d.ts.map +1 -0
- package/dist/cli/commands/configure-mcp.js +42 -0
- package/dist/cli/commands/configure-mcp.js.map +1 -0
- package/dist/cli/commands/dev.d.ts +2 -2
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +39 -27
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/cli/commands/init.d.ts +8 -2
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +67 -132
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/migrations.d.ts.map +1 -1
- package/dist/cli/commands/migrations.js +25 -0
- package/dist/cli/commands/migrations.js.map +1 -1
- package/dist/cli/commands/provision.d.ts +5 -0
- package/dist/cli/commands/provision.d.ts.map +1 -1
- package/dist/cli/commands/provision.js +278 -55
- package/dist/cli/commands/provision.js.map +1 -1
- package/dist/cli/commands/scaffold.d.ts +4 -0
- package/dist/cli/commands/scaffold.d.ts.map +1 -1
- package/dist/cli/commands/scaffold.js +85 -3
- package/dist/cli/commands/scaffold.js.map +1 -1
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +43 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/core/operations/create-model.d.ts +2 -0
- package/dist/core/operations/create-model.d.ts.map +1 -1
- package/dist/core/operations/create-model.js +60 -8
- package/dist/core/operations/create-model.js.map +1 -1
- package/dist/core/operations/migration-generator.d.ts.map +1 -1
- package/dist/core/operations/migration-generator.js +12 -1
- package/dist/core/operations/migration-generator.js.map +1 -1
- package/dist/core/operations/model-migration.d.ts +22 -0
- package/dist/core/operations/model-migration.d.ts.map +1 -0
- package/dist/core/operations/model-migration.js +36 -0
- package/dist/core/operations/model-migration.js.map +1 -0
- package/dist/core/operations/provision-deployment.d.ts +52 -0
- package/dist/core/operations/provision-deployment.d.ts.map +1 -0
- package/dist/core/operations/provision-deployment.js +164 -0
- package/dist/core/operations/provision-deployment.js.map +1 -0
- package/dist/core/operations/provision-operations.d.ts +62 -6
- package/dist/core/operations/provision-operations.d.ts.map +1 -1
- package/dist/core/operations/provision-operations.js +653 -115
- package/dist/core/operations/provision-operations.js.map +1 -1
- package/dist/core/operations/scaffold-apply.d.ts +1 -0
- package/dist/core/operations/scaffold-apply.d.ts.map +1 -1
- package/dist/core/operations/scaffold-apply.js +1 -0
- package/dist/core/operations/scaffold-apply.js.map +1 -1
- package/dist/core/operations/scaffold-machine.d.ts +1 -0
- package/dist/core/operations/scaffold-machine.d.ts.map +1 -1
- package/dist/core/operations/scaffold-machine.js.map +1 -1
- package/dist/core/operations/scaffold-plan.d.ts +2 -0
- package/dist/core/operations/scaffold-plan.d.ts.map +1 -1
- package/dist/core/operations/scaffold-plan.js +3 -1
- package/dist/core/operations/scaffold-plan.js.map +1 -1
- package/dist/core/project/agent-instructions.d.ts.map +1 -1
- package/dist/core/project/agent-instructions.js +4 -1
- package/dist/core/project/agent-instructions.js.map +1 -1
- package/dist/core/project/boundaries.d.ts +5 -2
- package/dist/core/project/boundaries.d.ts.map +1 -1
- package/dist/core/project/boundaries.js +51 -20
- package/dist/core/project/boundaries.js.map +1 -1
- package/dist/core/project/capabilities.d.ts +10 -0
- package/dist/core/project/capabilities.d.ts.map +1 -1
- package/dist/core/project/capabilities.js +38 -6
- package/dist/core/project/capabilities.js.map +1 -1
- package/dist/core/project/home-page.d.ts +4 -0
- package/dist/core/project/home-page.d.ts.map +1 -0
- package/dist/core/project/home-page.js +113 -0
- package/dist/core/project/home-page.js.map +1 -0
- package/dist/core/project/mcp-config.d.ts +26 -0
- package/dist/core/project/mcp-config.d.ts.map +1 -0
- package/dist/core/project/mcp-config.js +117 -0
- package/dist/core/project/mcp-config.js.map +1 -0
- package/dist/core/project/react-project.d.ts +1 -1
- package/dist/core/project/react-project.d.ts.map +1 -1
- package/dist/core/project/react-project.js +46 -25
- package/dist/core/project/react-project.js.map +1 -1
- package/dist/core/project/state.d.ts +7 -0
- package/dist/core/project/state.d.ts.map +1 -1
- package/dist/core/project/state.js +86 -0
- package/dist/core/project/state.js.map +1 -1
- package/dist/core/project/workflows.d.ts.map +1 -1
- package/dist/core/project/workflows.js +72 -12
- package/dist/core/project/workflows.js.map +1 -1
- package/dist/core/scaffold/auth-generator.d.ts.map +1 -1
- package/dist/core/scaffold/auth-generator.js +26 -27
- package/dist/core/scaffold/auth-generator.js.map +1 -1
- package/dist/core/scaffold/model-parser.d.ts +23 -0
- package/dist/core/scaffold/model-parser.d.ts.map +1 -1
- package/dist/core/scaffold/model-parser.js +407 -137
- package/dist/core/scaffold/model-parser.js.map +1 -1
- package/dist/core/scaffold/native-schema-generator.d.ts +13 -0
- package/dist/core/scaffold/native-schema-generator.d.ts.map +1 -1
- package/dist/core/scaffold/native-schema-generator.js +294 -91
- package/dist/core/scaffold/native-schema-generator.js.map +1 -1
- package/dist/core/scaffold/openapi-generator.d.ts +5 -0
- package/dist/core/scaffold/openapi-generator.d.ts.map +1 -1
- package/dist/core/scaffold/openapi-generator.js +53 -3
- package/dist/core/scaffold/openapi-generator.js.map +1 -1
- package/dist/core/scaffold/ui-generator.d.ts +0 -3
- package/dist/core/scaffold/ui-generator.d.ts.map +1 -1
- package/dist/core/scaffold/ui-generator.js +68 -7
- package/dist/core/scaffold/ui-generator.js.map +1 -1
- package/dist/core/verify/index.d.ts +4 -3
- package/dist/core/verify/index.d.ts.map +1 -1
- package/dist/core/verify/index.js +122 -5
- package/dist/core/verify/index.js.map +1 -1
- package/dist/machine/contracts.d.ts +1 -0
- package/dist/machine/contracts.d.ts.map +1 -1
- package/dist/machine/errors.d.ts +3 -2
- package/dist/machine/errors.d.ts.map +1 -1
- package/dist/machine/errors.js +2 -1
- package/dist/machine/errors.js.map +1 -1
- package/dist/machine/index.d.ts.map +1 -1
- package/dist/machine/index.js +59 -28
- package/dist/machine/index.js.map +1 -1
- package/dist/mcp/index.d.ts +6 -4
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +210 -25
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/version-selection.d.ts +55 -0
- package/dist/mcp/version-selection.d.ts.map +1 -0
- package/dist/mcp/version-selection.js +152 -0
- package/dist/mcp/version-selection.js.map +1 -0
- package/dist/utils/azure-cli.d.ts +56 -0
- package/dist/utils/azure-cli.d.ts.map +1 -0
- package/dist/utils/azure-cli.js +326 -0
- package/dist/utils/azure-cli.js.map +1 -0
- package/dist/utils/azure-diagnostics.d.ts +16 -0
- package/dist/utils/azure-diagnostics.d.ts.map +1 -0
- package/dist/utils/azure-diagnostics.js +68 -0
- package/dist/utils/azure-diagnostics.js.map +1 -0
- package/dist/utils/package-manager.js +2 -2
- package/dist/utils/package-manager.js.map +1 -1
- package/dist/utils/python-uv.d.ts +5 -7
- package/dist/utils/python-uv.d.ts.map +1 -1
- package/dist/utils/python-uv.js +50 -24
- package/dist/utils/python-uv.js.map +1 -1
- package/dist/utils/react-dev.d.ts +4 -0
- package/dist/utils/react-dev.d.ts.map +1 -0
- package/dist/utils/react-dev.js +35 -0
- package/dist/utils/react-dev.js.map +1 -0
- package/dist/utils/semver.d.ts +14 -0
- package/dist/utils/semver.d.ts.map +1 -0
- package/dist/utils/semver.js +61 -0
- package/dist/utils/semver.js.map +1 -0
- package/package.json +6 -3
- package/src/__tests__/__snapshots__/boundaries.test.ts.snap +154 -0
- package/src/__tests__/agent-instructions.test.ts +93 -0
- package/src/__tests__/agent-loop-phase34.test.ts +143 -8
- package/src/__tests__/auth.test.ts +9 -0
- package/src/__tests__/azure-cli.test.ts +202 -0
- package/src/__tests__/boundaries.test.ts +42 -0
- package/src/__tests__/csharp-schema.test.ts +261 -0
- package/src/__tests__/dev.test.ts +13 -6
- package/src/__tests__/fixtures/az wrapper.cmd +2 -0
- package/src/__tests__/fixtures/azure-cli.cjs +153 -0
- package/src/__tests__/fixtures/provision-runner.cjs +28 -0
- package/src/__tests__/generated-project-matrix.test.ts +789 -0
- package/src/__tests__/home-page.test.ts +50 -0
- package/src/__tests__/init.test.ts +116 -0
- package/src/__tests__/mcp-version.test.ts +262 -0
- package/src/__tests__/mcp.test.ts +120 -3
- package/src/__tests__/multi-auth.test.ts +115 -4
- package/src/__tests__/package-manager.test.ts +17 -2
- package/src/__tests__/plan-apply.test.ts +179 -0
- package/src/__tests__/provision-runtime.test.ts +722 -0
- package/src/__tests__/python-uv.test.ts +50 -14
- package/src/__tests__/python-venv.test.ts +48 -0
- package/src/__tests__/react-dev.test.ts +72 -0
- package/src/__tests__/react.test.ts +19 -0
- package/src/__tests__/schema-analysis.test.ts +329 -0
- package/src/cli/commands/add-auth.ts +36 -6
- package/src/cli/commands/configure-mcp.ts +54 -0
- package/src/cli/commands/dev.ts +40 -31
- package/src/cli/commands/init.ts +73 -138
- package/src/cli/commands/migrations.ts +22 -0
- package/src/cli/commands/provision.ts +294 -56
- package/src/cli/commands/scaffold.ts +105 -3
- package/src/cli/index.ts +40 -7
- package/src/core/operations/create-model.ts +51 -13
- package/src/core/operations/migration-generator.ts +14 -1
- package/src/core/operations/model-migration.ts +52 -0
- package/src/core/operations/provision-deployment.ts +183 -0
- package/src/core/operations/provision-operations.ts +662 -154
- package/src/core/operations/scaffold-apply.ts +2 -0
- package/src/core/operations/scaffold-machine.ts +1 -0
- package/src/core/operations/scaffold-plan.ts +5 -1
- package/src/core/project/agent-instructions.ts +4 -1
- package/src/core/project/agent-templates/AGENTS.md +126 -6
- package/src/core/project/agent-templates/CLAUDE.md +14 -1
- package/src/core/project/agent-templates/copilot-instructions.md +15 -1
- package/src/core/project/agent-templates/shared-models.instructions.md +23 -3
- package/src/core/project/boundaries.ts +62 -20
- package/src/core/project/capabilities.ts +49 -6
- package/src/core/project/home-page.ts +114 -0
- package/src/core/project/mcp-config.ts +84 -0
- package/src/core/project/react-project.ts +50 -28
- package/src/core/project/state.ts +70 -0
- package/src/core/project/workflows.ts +72 -12
- package/src/core/scaffold/auth-generator.ts +26 -27
- package/src/core/scaffold/model-parser.ts +413 -129
- package/src/core/scaffold/native-schema-generator.ts +319 -103
- package/src/core/scaffold/openapi-generator.ts +63 -5
- package/src/core/scaffold/ui-generator.ts +70 -8
- package/src/core/verify/index.ts +118 -6
- package/src/machine/contracts.ts +1 -0
- package/src/machine/errors.ts +4 -2
- package/src/machine/index.ts +65 -34
- package/src/mcp/index.ts +221 -31
- package/src/mcp/version-selection.ts +163 -0
- package/src/utils/azure-cli.ts +315 -0
- package/src/utils/azure-diagnostics.ts +75 -0
- package/src/utils/package-manager.ts +2 -2
- package/src/utils/python-uv.ts +53 -33
- package/src/utils/react-dev.ts +31 -0
- package/src/utils/semver.ts +59 -0
|
@@ -19,6 +19,7 @@ export interface ApplyScaffoldOptions {
|
|
|
19
19
|
functionsDir?: string;
|
|
20
20
|
apiDir?: string;
|
|
21
21
|
apiOnly?: boolean;
|
|
22
|
+
skipInfra?: boolean;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export interface ApplyScaffoldResult extends MachineScaffoldOperationResult {
|
|
@@ -70,6 +71,7 @@ export async function applyScaffoldOperation(options: ApplyScaffoldOptions): Pro
|
|
|
70
71
|
functionsDir: options.functionsDir ?? basePlan?.options.functionsDir,
|
|
71
72
|
apiDir: options.apiDir ?? basePlan?.options.apiDir,
|
|
72
73
|
apiOnly: options.apiOnly ?? basePlan?.options.apiOnly,
|
|
74
|
+
skipInfra: options.skipInfra ?? basePlan?.options.skipInfra,
|
|
73
75
|
};
|
|
74
76
|
|
|
75
77
|
// 常に最新状態で collect し、競合を検出する(plan 指定時も現況を再確認)
|
|
@@ -29,6 +29,7 @@ export interface PlanScaffoldOptions {
|
|
|
29
29
|
functionsDir?: string;
|
|
30
30
|
apiDir?: string;
|
|
31
31
|
apiOnly?: boolean;
|
|
32
|
+
skipInfra?: boolean;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
export type ScaffoldPlanAction = "create" | "update" | "overwrite" | "append" | "delete" | "skip";
|
|
@@ -59,6 +60,7 @@ export interface ScaffoldPlanData {
|
|
|
59
60
|
functionsDir?: string;
|
|
60
61
|
apiDir?: string;
|
|
61
62
|
apiOnly?: boolean;
|
|
63
|
+
skipInfra?: boolean;
|
|
62
64
|
};
|
|
63
65
|
createdAt: string;
|
|
64
66
|
swallowkitVersion: string;
|
|
@@ -93,6 +95,7 @@ async function collectScaffoldOperations(options: PlanScaffoldOptions): Promise<
|
|
|
93
95
|
functionsDir: options.functionsDir,
|
|
94
96
|
apiDir: options.apiDir,
|
|
95
97
|
apiOnly: options.apiOnly,
|
|
98
|
+
skipInfra: options.skipInfra,
|
|
96
99
|
});
|
|
97
100
|
});
|
|
98
101
|
});
|
|
@@ -193,7 +196,7 @@ export async function planScaffoldOperation(options: PlanScaffoldOptions): Promi
|
|
|
193
196
|
.update(
|
|
194
197
|
JSON.stringify({
|
|
195
198
|
model: options.model,
|
|
196
|
-
options: { functionsDir: options.functionsDir, apiDir: options.apiDir, apiOnly: options.apiOnly },
|
|
199
|
+
options: { functionsDir: options.functionsDir, apiDir: options.apiDir, apiOnly: options.apiOnly, skipInfra: options.skipInfra },
|
|
197
200
|
operations: operations.map((op) => ({ path: op.path, action: op.action })),
|
|
198
201
|
fingerprints,
|
|
199
202
|
schemaAnalysis,
|
|
@@ -210,6 +213,7 @@ export async function planScaffoldOperation(options: PlanScaffoldOptions): Promi
|
|
|
210
213
|
...(options.functionsDir ? { functionsDir: options.functionsDir } : {}),
|
|
211
214
|
...(options.apiDir ? { apiDir: options.apiDir } : {}),
|
|
212
215
|
...(options.apiOnly !== undefined ? { apiOnly: options.apiOnly } : {}),
|
|
216
|
+
...(options.skipInfra ? { skipInfra: true } : {}),
|
|
213
217
|
},
|
|
214
218
|
createdAt: new Date().toISOString(),
|
|
215
219
|
swallowkitVersion: getSwallowKitVersion(),
|
|
@@ -71,6 +71,9 @@ function getBackendRules(backendLanguage: BackendLanguage): string {
|
|
|
71
71
|
"- All backend business logic and data access live in `functions/`.",
|
|
72
72
|
`- SwallowKit derives OpenAPI and native ${BACKEND_LANGUAGE_LABELS[backendLanguage]} schema assets from the Zod source of truth.`,
|
|
73
73
|
"- Keep custom business logic in ai-authored locations identified by the current boundary contract.",
|
|
74
|
+
backendLanguage === "python"
|
|
75
|
+
? "- Use uv with the user's interpreter/version settings. Local Python is not pinned to the Azure deployment runtime. Preserve functions/.venv and functions/.codegen-venv; do not clear them or weaken OS application-control policy to fix interpreter errors."
|
|
76
|
+
: "- Start the isolated Functions backend with dotnet run, not func start from the source directory, so the SDK loads extensions from the build output.",
|
|
74
77
|
].join("\n");
|
|
75
78
|
}
|
|
76
79
|
|
|
@@ -91,7 +94,7 @@ function interpolateTemplate(template: string, context: AgentInstructionContext)
|
|
|
91
94
|
? "├── src/ # React SPA (Vite + React Router)\n│ └── pages/ # generated/custom UI and route registrations\n├── bff/ # SWA managed HTTP-only Functions\n│ ├── src/ # BFF handlers and request-local helpers\n│ └── {function}/ # function.json registrations"
|
|
92
95
|
: "├── app/ # Next.js App Router\n│ ├── api/ # BFF routes\n│ └── {model}/ # generated/custom UI",
|
|
93
96
|
devGuidance: react
|
|
94
|
-
? "Use http://localhost:4280 for the app. `swallowkit dev` runs Vite (3000), the managed BFF (7073), standalone Functions (7071), and SWA CLI (4280). SWA forwards /api only to the managed BFF, never directly to standalone Functions. `--no-functions` leaves the BFF running; `--no-swa` removes same-origin routing/auth emulation. BFF local settings belong in bff/local.settings.json. Build bundles BFF dependencies and copies staticwebapp.config.json into dist/. Deploy dist/ + bff/ together, and functions/ separately."
|
|
97
|
+
? "Use http://localhost:4280 for the app. `swallowkit dev` runs Vite (3000), the managed BFF (7073), standalone Functions (7071), and SWA CLI (4280). SWA forwards /api only to the managed BFF, never directly to standalone Functions. `--no-functions` leaves the BFF running; `--no-swa` removes same-origin routing/auth emulation. BFF local settings belong in bff/local.settings.json. Build bundles BFF dependencies and copies staticwebapp.config.json into dist/. Deploy dist/ + bff/ together, and functions/ separately. Generated home, CRUD, and login pages share the Next.js presentation templates. Preserve their Tailwind styles and the light/dark defaults in src/style.css when editing them."
|
|
95
98
|
: "Use http://localhost:3000 for the app, or the SWA emulator port (4280) when testing SWA authentication. `swallowkit dev` runs Next.js and standalone Functions (7071). The BFF remains Next.js API routes.",
|
|
96
99
|
pm: context.packageManager,
|
|
97
100
|
runCmd,
|
|
@@ -41,7 +41,14 @@ When a SwallowKit capability, project structure, or ownership boundary affects
|
|
|
41
41
|
a design decision, inspect the current project and the currently available
|
|
42
42
|
SwallowKit interfaces before deciding.
|
|
43
43
|
|
|
44
|
-
Prefer the `swallowkit_*` MCP tools when available
|
|
44
|
+
Prefer the `swallowkit_*` MCP tools when available, with one exception: every
|
|
45
|
+
MCP response reports the SwallowKit version that answered in
|
|
46
|
+
`metadata.swallowkitVersion` and `metadata.mcp`. If that version is older than
|
|
47
|
+
the project's installed SwallowKit (`{{runCmd}} swallowkit --version`), or
|
|
48
|
+
`metadata.warnings` contains `mcp-older-than-project`, its capabilities,
|
|
49
|
+
boundaries, and plan/apply contracts may be outdated for this project. Use
|
|
50
|
+
`{{runCmd}} swallowkit machine ...` instead and follow the response's
|
|
51
|
+
`nextActions` (for example `{{runCmd}} swallowkit configure-mcp`).
|
|
45
52
|
|
|
46
53
|
If MCP is unavailable, use the machine interface:
|
|
47
54
|
|
|
@@ -217,6 +224,10 @@ required.
|
|
|
217
224
|
|
|
218
225
|
Never invent or implicitly grant human approval.
|
|
219
226
|
|
|
227
|
+
Humans normally invoke `swallowkit provision` directly. Its invocation requests
|
|
228
|
+
execution without an additional confirmation. Agents must still use the
|
|
229
|
+
machine/MCP approval flow and must not switch to normal CLI to bypass it.
|
|
230
|
+
|
|
220
231
|
## Model Changes
|
|
221
232
|
|
|
222
233
|
For an existing model change, the normal pattern is:
|
|
@@ -263,6 +274,55 @@ SwallowKit should generate framework-owned CRUD artifacts.
|
|
|
263
274
|
|
|
264
275
|
Do not manually recreate boilerplate that SwallowKit owns.
|
|
265
276
|
|
|
277
|
+
### Persistent models require infrastructure, even with custom APIs
|
|
278
|
+
|
|
279
|
+
Whenever adding a persistent model, execute the installed SwallowKit model
|
|
280
|
+
creation and infrastructure generation workflow, whether or not it has custom
|
|
281
|
+
APIs. A hand-written model alone is not complete.
|
|
282
|
+
|
|
283
|
+
1. Create the source-of-truth schema with
|
|
284
|
+
`{{runCmd}} swallowkit machine generate model <model> --overwrite never`
|
|
285
|
+
(the machine equivalent of `{{runCmd}} swallowkit create-model <model>`),
|
|
286
|
+
then author its domain fields in `shared/models/` and check its export from
|
|
287
|
+
`shared/index.ts`. Preserve an existing hand-written schema; do not overwrite
|
|
288
|
+
it just to run the template command. Model creation alone does **not**
|
|
289
|
+
generate a Cosmos DB container.
|
|
290
|
+
2. If generated CRUD is needed, use `machine plan scaffold <model>` →
|
|
291
|
+
`machine apply scaffold --plan <planId>` to derive Functions, BFF, UI,
|
|
292
|
+
OpenAPI/native schema assets as applicable, and the container migration.
|
|
293
|
+
`--api-only` skips UI only; it still generates CRUD Functions and BFF routes.
|
|
294
|
+
If custom APIs replace CRUD, do **not** scaffold unnecessary CRUD. Instead run
|
|
295
|
+
`{{runCmd}} swallowkit migrations add-model <model> --dry-run`, review the
|
|
296
|
+
changes, then `{{runCmd}} swallowkit migrations add-model <model>` to generate
|
|
297
|
+
only the Cosmos DB container migration and its generation records.
|
|
298
|
+
3. Inspect `machine inspect entities`, `machine inspect infra`,
|
|
299
|
+
`machine inspect artifacts`, and `machine inspect drift`, then run
|
|
300
|
+
`{{runCmd}} swallowkit machine verify project`. Check that the model's
|
|
301
|
+
container name and partition key match the generated Bicep under
|
|
302
|
+
`infra/migrations/`, its `sourceModel` entry in
|
|
303
|
+
`infra/migrations/manifest.json`, and `.swallowkit/artifacts.json`.
|
|
304
|
+
An existing baseline-owned container may need no new migration; verify its
|
|
305
|
+
tracked definition and wiring in `infra/main.bicep` instead. External
|
|
306
|
+
`connectorConfig` models use the configured connector rather than Cosmos DB;
|
|
307
|
+
verify that mapping instead of inventing a Cosmos container.
|
|
308
|
+
|
|
309
|
+
Do not hand-edit the checksum-locked baseline or an existing migration to add
|
|
310
|
+
a container; use the current migration workflow. Generation is local, not Azure
|
|
311
|
+
provisioning. Deployment still follows the provisioning approval gates below.
|
|
312
|
+
|
|
313
|
+
If infrastructure generation must be deferred, state the reason and the pending
|
|
314
|
+
container/migration work explicitly. For CRUD, pass `--skip-infra` to
|
|
315
|
+
`plan scaffold` / `apply scaffold` (MCP `skipInfra: true`). Nothing under `infra/`
|
|
316
|
+
changes and the plan reports `infra-skipped`. Generate the pending migration
|
|
317
|
+
later with `{{runCmd}} swallowkit migrations add-model <model>`. Even if
|
|
318
|
+
`verify project` passes, do not mark the persistent model complete or describe
|
|
319
|
+
the project as deployment-ready while required infrastructure is missing.
|
|
320
|
+
|
|
321
|
+
Treat plan `warnings` as decisions to make, not noise. In particular,
|
|
322
|
+
`user-scoped-data-without-auth` means the model looks per-user (for example a
|
|
323
|
+
`/userId` partition key) while authentication is not configured, so generated
|
|
324
|
+
CRUD would let any caller read and write every document.
|
|
325
|
+
|
|
266
326
|
## Authentication
|
|
267
327
|
|
|
268
328
|
Authentication is a **plan/apply operation**, not a free-form config edit.
|
|
@@ -300,6 +360,20 @@ custom endpoints that derive the scoping key (e.g. `learnerId`) from the
|
|
|
300
360
|
verified principal — never from the request body — and restrict the generated
|
|
301
361
|
write endpoints to admin roles.
|
|
302
362
|
|
|
363
|
+
Configure authentication with `plan auth` / `apply auth` **before** declaring
|
|
364
|
+
`authPolicy`. Without authentication, an explicit policy
|
|
365
|
+
blocks plan/apply/scaffold with `auth-policy-without-auth` before file writes;
|
|
366
|
+
follow `nextActions`, then re-plan. Do not remove a required policy just to pass
|
|
367
|
+
generation.
|
|
368
|
+
An empty `authPolicy = {}` means no explicit policy; it does not enable authentication.
|
|
369
|
+
|
|
370
|
+
With named `auth.schemes`, define `auth.authorization.policies` selecting the
|
|
371
|
+
required schemes and roles, then use `authPolicy = { policy: 'adminOnly' }` (or
|
|
372
|
+
read/write policy names). Role-only declarations do not select a named scheme
|
|
373
|
+
and block with `auth-policy-requires-named-policy`. Conversely, single-provider
|
|
374
|
+
`auth.provider` supports role lists only; a named policy (including a named
|
|
375
|
+
`defaultPolicy`) blocks with `auth-named-policy-requires-named-scheme`.
|
|
376
|
+
|
|
303
377
|
## Verification Is a Completion Gate
|
|
304
378
|
|
|
305
379
|
Before treating an agent-driven implementation as complete, run SwallowKit
|
|
@@ -311,8 +385,17 @@ verification:
|
|
|
311
385
|
|
|
312
386
|
or the equivalent MCP operation.
|
|
313
387
|
|
|
314
|
-
|
|
315
|
-
|
|
388
|
+
Default checks are `structure`, `drift`, `typecheck`, `backend-build`, plus
|
|
389
|
+
configured project checks. `backend-build` checks standalone `functions/`:
|
|
390
|
+
C# uses `dotnet build`, TypeScript uses the project's `tsc --noEmit`, and Python
|
|
391
|
+
uses Python 3 `compileall` (syntax only, not imports or type checking), preferring
|
|
392
|
+
`functions/.venv` over PATH. Missing toolchains are `skip` with an explanation;
|
|
393
|
+
a skipped backend check is **not** evidence that the backend works. Restore the
|
|
394
|
+
toolchain and re-run it before claiming backend validation.
|
|
395
|
+
|
|
396
|
+
Root `build` scripts do not replace standalone backend verification. To include
|
|
397
|
+
frontend production builds, use `--checks "structure,drift,typecheck,backend-build,build"`.
|
|
398
|
+
Quote comma-separated values in PowerShell.
|
|
316
399
|
|
|
317
400
|
When verification fails, use the structured failure explanation:
|
|
318
401
|
|
|
@@ -359,6 +442,24 @@ Use the `swallowkit-provision` Agent Skill or runbook and never bypass its
|
|
|
359
442
|
approval gate. A broad request to deploy does not itself grant the explicit
|
|
360
443
|
approval required by that workflow.
|
|
361
444
|
|
|
445
|
+
Provision applies Bicep once and tracks the original Azure deployment with a
|
|
446
|
+
bounded wait. A local timeout/error, output truncation, or Ctrl+C is not proof
|
|
447
|
+
that Azure failed. `in-progress` means Azure is Running/Accepted; `unknown`
|
|
448
|
+
means its result could not be read; `partial` means Azure succeeded but
|
|
449
|
+
tag/ledger completion is pending. Never re-submit Bicep, reconcile, adopt,
|
|
450
|
+
cancel, or delete just to repair waiting or migration bookkeeping.
|
|
451
|
+
|
|
452
|
+
Retain `.swallowkit/state/provision/` execution checkpoints. Use
|
|
453
|
+
`{{runCmd}} swallowkit machine inspect provision --plan <runId> --wait-seconds 300`
|
|
454
|
+
for read-only status/wait, and after explicit human approval use
|
|
455
|
+
`{{runCmd}} swallowkit machine apply provision --plan <runId> --approve`
|
|
456
|
+
to resume. `runId` equals the original `planId`; fingerprints, subscription,
|
|
457
|
+
deployment identity and migration checks remain in force. Only
|
|
458
|
+
`status: "complete"` / `outcome: "succeeded"` means Azure Succeeded plus verified
|
|
459
|
+
tags and local ledger. Do not print deployment output secrets or raw `az --debug`.
|
|
460
|
+
For older untracked baselines use `plan provision --resume-deployment <name>`
|
|
461
|
+
with original target/regions; it blocks unless ARM/parameter evidence matches.
|
|
462
|
+
|
|
362
463
|
## SwallowKit Agent Skills and Runbooks
|
|
363
464
|
|
|
364
465
|
SwallowKit installs task-specific Agent Skills under:
|
|
@@ -455,12 +556,24 @@ same generated structure.
|
|
|
455
556
|
- Model schema files use `shared/models/{kebab-case}.ts`.
|
|
456
557
|
- The Zod schema constant and inferred TypeScript type use the same PascalCase
|
|
457
558
|
name: `export const Todo = z.object(...); export type Todo = z.infer<typeof Todo>`.
|
|
458
|
-
- Re-export models from `shared/index.ts`.
|
|
559
|
+
- Re-export models from `shared/index.ts`. create-model and plan/apply scaffold
|
|
560
|
+
append missing exports, including manually authored models. Manual exports
|
|
561
|
+
are allowed; this file has no managed markers and existing content is preserved.
|
|
459
562
|
- `id` is a required `z.string()`; only `createdAt` / `updatedAt` are optional
|
|
460
563
|
backend-managed fields.
|
|
461
|
-
- Models may declare `partitionKey`, `authPolicy`, `displayName`,
|
|
462
|
-
`connectorConfig` as exported constants. Exact formats:
|
|
564
|
+
- Models may declare `partitionKey`, `authPolicy`, `displayName`,
|
|
565
|
+
`references`, and `connectorConfig` as exported constants. Exact formats:
|
|
463
566
|
`{{runCmd}} swallowkit machine inspect capabilities` (modelDeclarations).
|
|
567
|
+
- A string field named `<model>Id` is treated as a foreign key only when that
|
|
568
|
+
model exists in `shared/models`. Declare other references explicitly with
|
|
569
|
+
`export const references = { authorId: 'User' };` (map a field to `false`
|
|
570
|
+
to opt out).
|
|
571
|
+
- Native C#/Python schema types come from Zod, not field names: use
|
|
572
|
+
`z.iso.datetime()` / `z.iso.date()` for date values (`createdAt` stays a
|
|
573
|
+
string), `z.number().int()` for integers, and inline `z.object` for nested
|
|
574
|
+
classes. Length/range/regex/item constraints are enforced natively; formats
|
|
575
|
+
such as email remain Zod (BFF) validation. See `inspect capabilities`
|
|
576
|
+
(sharedModels.nativeSchemaMapping).
|
|
464
577
|
- Cosmos DB containers use PascalCase plural names and default to `/id` as the
|
|
465
578
|
partition key unless the model declares another key, e.g.
|
|
466
579
|
`export const partitionKey = '/learnerId';` (the field must exist in the
|
|
@@ -517,3 +630,10 @@ Do:
|
|
|
517
630
|
- verify before final semantic review
|
|
518
631
|
|
|
519
632
|
Use `{{pm}}`, the package manager selected for this project. Do not introduce another package manager or lockfile. Use `{{runCmd}} swallowkit` for the project-local CLI. The MCP launcher intentionally resolves `latest` independently.
|
|
633
|
+
Exception for prerelease projects: when the project's SwallowKit is newer than
|
|
634
|
+
the published `latest` (for example `2.0.0-alpha.3` while `latest` is `1.1.2`),
|
|
635
|
+
`.mcp.json` may pin `SWALLOWKIT_MCP_VERSION` to the project version, and a
|
|
636
|
+
`latest` launcher that supports it hands the session to the project-installed
|
|
637
|
+
MCP. Run `{{runCmd}} swallowkit configure-mcp` to re-select the version (it
|
|
638
|
+
returns to `latest` once `latest` is at least the project version). Until MCP
|
|
639
|
+
reports the project version, prefer `{{runCmd}} swallowkit machine ...`.
|
|
@@ -14,7 +14,9 @@ Always-on rules:
|
|
|
14
14
|
- Inspect the current project and SwallowKit capabilities before making
|
|
15
15
|
SwallowKit-dependent assumptions or asking questions the repository can answer.
|
|
16
16
|
- Prefer `swallowkit_*` MCP tools.
|
|
17
|
-
- Fall back to `{{runCmd}} swallowkit machine ...` when MCP is unavailable
|
|
17
|
+
- Fall back to `{{runCmd}} swallowkit machine ...` when MCP is unavailable, or
|
|
18
|
+
when an MCP response's `metadata.swallowkitVersion` is older than the project's
|
|
19
|
+
SwallowKit (`metadata.warnings` contains `mcp-older-than-project`).
|
|
18
20
|
- Inspect responsibility boundaries before editing framework-related files.
|
|
19
21
|
- Never hand-edit deterministic SwallowKit-managed artifacts.
|
|
20
22
|
- Add auth schemes only via plan/apply auth; never hand-write `auth.schemes`
|
|
@@ -22,7 +24,18 @@ Always-on rules:
|
|
|
22
24
|
after apply).
|
|
23
25
|
- Use plan/apply for deterministic generation.
|
|
24
26
|
- Respect all `requires-human` states and provisioning approval gates.
|
|
27
|
+
- Normal `swallowkit provision` is for humans. Agents must not use it to bypass
|
|
28
|
+
the machine/MCP approval flow.
|
|
29
|
+
- Provision timeouts/Ctrl+C do not prove Azure failed. Inspect the original
|
|
30
|
+
execution checkpoint with `machine inspect provision --plan <runId>`; resume
|
|
31
|
+
`machine apply provision --plan <runId> --approve` only after explicit human
|
|
32
|
+
approval. Preserve checkpoints; never re-submit Bicep/reconcile/cancel/delete
|
|
33
|
+
to repair waiting or tag/ledger failures. Do not print deployment output secrets.
|
|
25
34
|
- Run SwallowKit verification before considering implementation complete.
|
|
35
|
+
- Default verification includes `backend-build` for standalone Functions.
|
|
36
|
+
Skipped toolchains are not validation; Python compilation checks syntax only.
|
|
37
|
+
- Configure auth via plan/apply auth before adding `authPolicy`; otherwise
|
|
38
|
+
scaffold blocks before file writes. Scaffold appends missing shared model exports.
|
|
26
39
|
|
|
27
40
|
Task-specific SwallowKit Agent Skills are available under `.github/skills/`.
|
|
28
41
|
Equivalent agent-agnostic runbooks are available under
|
|
@@ -13,7 +13,9 @@ Key rules:
|
|
|
13
13
|
- Inspect current SwallowKit capabilities instead of assuming them.
|
|
14
14
|
- Answer repository- and SwallowKit-inspectable questions before asking the human.
|
|
15
15
|
- Prefer `swallowkit_*` MCP tools when available.
|
|
16
|
-
- Otherwise use `{{runCmd}} swallowkit machine ...`.
|
|
16
|
+
- Otherwise use `{{runCmd}} swallowkit machine ...`. Also use it when an MCP
|
|
17
|
+
response's `metadata.swallowkitVersion` is older than the project's SwallowKit
|
|
18
|
+
or `metadata.warnings` contains `mcp-older-than-project`.
|
|
17
19
|
- Inspect responsibility boundaries before editing framework-related files.
|
|
18
20
|
- Never hand-edit deterministic SwallowKit-managed artifacts.
|
|
19
21
|
- Add auth schemes only via plan/apply auth; never hand-write `auth.schemes`
|
|
@@ -21,7 +23,19 @@ Key rules:
|
|
|
21
23
|
after apply).
|
|
22
24
|
- Use plan/apply for deterministic generation.
|
|
23
25
|
- Respect `requires-human` states and other human approval gates.
|
|
26
|
+
- Normal `swallowkit provision` is a human-facing deployment command. Agents must
|
|
27
|
+
use the machine/MCP approval flow, not normal CLI as an approval bypass.
|
|
28
|
+
- Provision timeouts/Ctrl+C do not prove Azure failed. Read `status`, `outcome`,
|
|
29
|
+
and `nextActions`; inspect the original run with `machine inspect provision
|
|
30
|
+
--plan <runId>`, then resume `machine apply provision --plan <runId> --approve`
|
|
31
|
+
only after explicit human approval. Preserve execution checkpoints; never
|
|
32
|
+
re-submit Bicep or use reconcile/cancel/delete to repair waiting or tag/ledger
|
|
33
|
+
failures. Do not print deployment output secrets.
|
|
24
34
|
- Run SwallowKit verification before completion.
|
|
35
|
+
- Default verification includes `backend-build` for standalone Functions.
|
|
36
|
+
Skipped toolchains are not validation; Python compilation checks syntax only.
|
|
37
|
+
- Configure auth via plan/apply auth before adding `authPolicy`; otherwise
|
|
38
|
+
scaffold blocks before file writes. Scaffold appends missing shared model exports.
|
|
25
39
|
|
|
26
40
|
Task-specific SwallowKit Agent Skills live under `.github/skills/`.
|
|
27
41
|
Agent-agnostic equivalents live under `.swallowkit/workflows/`.
|
|
@@ -18,9 +18,22 @@ source-of-truth models, subject to the current result of
|
|
|
18
18
|
- `createdAt` and `updatedAt` are **optional** string fields
|
|
19
19
|
(`z.string().optional()`). The backend manages their values.
|
|
20
20
|
- Export a `displayName` string for UI display.
|
|
21
|
-
-
|
|
22
|
-
|
|
21
|
+
- create-model and plan/apply scaffold append missing model exports to
|
|
22
|
+
`shared/index.ts`, including manually authored models. Manual exports are
|
|
23
|
+
allowed; there are no managed markers and existing content is preserved.
|
|
23
24
|
- For relationships, use nested schemas rather than duplicating model shapes.
|
|
25
|
+
- For every new persistent model, follow the root `AGENTS.md` persistent-model
|
|
26
|
+
workflow even with custom APIs. Use `{{runCmd}} swallowkit machine generate model <model> --overwrite never`
|
|
27
|
+
(the `create-model` equivalent), preserve existing schemas, and generate the
|
|
28
|
+
required infrastructure. Model creation alone does not create a container.
|
|
29
|
+
Use plan/apply scaffold when CRUD is needed; for custom APIs replacing CRUD,
|
|
30
|
+
review `{{runCmd}} swallowkit migrations add-model <model> --dry-run`, then run
|
|
31
|
+
`{{runCmd}} swallowkit migrations add-model <model>` without unnecessary CRUD.
|
|
32
|
+
Check the model, container Bicep, migration manifest, and artifact ledger
|
|
33
|
+
correspondence, then inspect drift and verify project. For connector models,
|
|
34
|
+
verify the external connector mapping instead of generating a Cosmos container.
|
|
35
|
+
If generation is deferred, state why and what remains; do not claim completion
|
|
36
|
+
or deployment readiness while required infrastructure is missing.
|
|
24
37
|
|
|
25
38
|
## Optional model declarations (exact formats)
|
|
26
39
|
|
|
@@ -30,7 +43,7 @@ These are the only declarations SwallowKit parses from a model file:
|
|
|
30
43
|
// Cosmos DB partition key (default '/id'). Must reference a schema field.
|
|
31
44
|
export const partitionKey = '/learnerId';
|
|
32
45
|
|
|
33
|
-
// Role-based access control on generated CRUD.
|
|
46
|
+
// Role-based access control on generated CRUD (requires plan/apply auth first).
|
|
34
47
|
export const authPolicy = { roles: ['admin'] };
|
|
35
48
|
// or: { read: ['user'], write: ['admin'] } or: { policy: 'adminOnly' }
|
|
36
49
|
|
|
@@ -48,6 +61,13 @@ export const connectorConfig = {
|
|
|
48
61
|
The full machine-readable contract:
|
|
49
62
|
`{{runCmd}} swallowkit machine inspect capabilities`
|
|
50
63
|
|
|
64
|
+
An explicit `authPolicy` without authentication blocks plan/apply/scaffold with
|
|
65
|
+
`auth-policy-without-auth` before writing files. Follow `nextActions` to configure
|
|
66
|
+
auth, then re-plan. Do not drop a required guard to bypass the prerequisite.
|
|
67
|
+
For named `auth.schemes`, use named authorization policies selecting schemes
|
|
68
|
+
and roles, referenced by `policy` or read/write names. Role-only declarations
|
|
69
|
+
block with `auth-policy-requires-named-policy` rather than emitting missing helpers.
|
|
70
|
+
|
|
51
71
|
After changing a model, do not manually patch generated artifacts.
|
|
52
72
|
|
|
53
73
|
## After changing a model
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
* - shared: マーカー区切りの共有領域。マーカー内は SwallowKit、外は自由。
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
import { getBackendLanguage } from "../config";
|
|
13
14
|
import { ArtifactOwnership } from "../operations/file-session";
|
|
15
|
+
import { BackendLanguage } from "../../types";
|
|
14
16
|
import { inspectArtifacts } from "./artifacts";
|
|
15
17
|
|
|
16
18
|
export type BoundaryZone = "deterministic" | "ai-authored" | "shared";
|
|
@@ -48,6 +50,8 @@ export interface BoundaryArtifact {
|
|
|
48
50
|
export interface BoundariesContract {
|
|
49
51
|
contractVersion: number;
|
|
50
52
|
summary: string;
|
|
53
|
+
/** backend.language the convention rules were resolved for */
|
|
54
|
+
backendLanguage: BackendLanguage;
|
|
51
55
|
ownershipPolicies: OwnershipPolicy[];
|
|
52
56
|
/** 台帳に載っていないパスの既定規約 */
|
|
53
57
|
conventionRules: BoundaryPathRule[];
|
|
@@ -82,7 +86,7 @@ export const OWNERSHIP_POLICIES: OwnershipPolicy[] = [
|
|
|
82
86
|
zone: "shared",
|
|
83
87
|
editPolicy: "edit-outside-markers",
|
|
84
88
|
howToChange:
|
|
85
|
-
"SwallowKit appends
|
|
89
|
+
"SwallowKit appends at the file-specific extension point: marked sections (e.g. `# SwallowKit scaffold registrations`) or append-only files such as shared/index.ts. Follow the path rule; preserve existing generated entries and any markers.",
|
|
86
90
|
},
|
|
87
91
|
{
|
|
88
92
|
ownership: "metadata",
|
|
@@ -92,7 +96,7 @@ export const OWNERSHIP_POLICIES: OwnershipPolicy[] = [
|
|
|
92
96
|
},
|
|
93
97
|
];
|
|
94
98
|
|
|
95
|
-
|
|
99
|
+
const COMMON_LEADING_RULES: BoundaryPathRule[] = [
|
|
96
100
|
{
|
|
97
101
|
pattern: ".swallowkit/",
|
|
98
102
|
zone: "deterministic",
|
|
@@ -107,32 +111,66 @@ export const CONVENTION_RULES: BoundaryPathRule[] = [
|
|
|
107
111
|
"Zod model schemas — the single source of truth. AI/developers author these freely; deterministic generation derives everything else from them.",
|
|
108
112
|
},
|
|
109
113
|
{
|
|
110
|
-
pattern: "infra/
|
|
111
|
-
zone: "
|
|
112
|
-
editPolicy: "
|
|
113
|
-
description:
|
|
114
|
+
pattern: "infra/migrations/manifest.json",
|
|
115
|
+
zone: "deterministic",
|
|
116
|
+
editPolicy: "never-hand-edit",
|
|
117
|
+
description:
|
|
118
|
+
"Infrastructure migration ledger with baseline checksums. Updated by scaffold, `swallowkit migrations add-model`, and `swallowkit create-migration`.",
|
|
114
119
|
},
|
|
115
120
|
{
|
|
116
|
-
pattern: "
|
|
117
|
-
zone: "
|
|
118
|
-
editPolicy: "edit
|
|
119
|
-
description:
|
|
121
|
+
pattern: "infra/migrations/",
|
|
122
|
+
zone: "ai-authored",
|
|
123
|
+
editPolicy: "free-edit",
|
|
124
|
+
description:
|
|
125
|
+
"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>`.",
|
|
120
126
|
},
|
|
121
127
|
{
|
|
122
|
-
pattern: "
|
|
123
|
-
zone: "
|
|
124
|
-
editPolicy: "
|
|
125
|
-
description:
|
|
128
|
+
pattern: "infra/",
|
|
129
|
+
zone: "deterministic",
|
|
130
|
+
editPolicy: "never-hand-edit",
|
|
131
|
+
description:
|
|
132
|
+
"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.",
|
|
126
133
|
},
|
|
127
134
|
{
|
|
128
|
-
pattern: "
|
|
129
|
-
zone: "
|
|
135
|
+
pattern: "shared/index.ts",
|
|
136
|
+
zone: "shared",
|
|
130
137
|
editPolicy: "free-edit",
|
|
131
|
-
description:
|
|
132
|
-
"Any path not recorded in the artifact ledger is AI/developer-authored. Business logic, custom pages, custom Functions, and tests belong here.",
|
|
138
|
+
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.",
|
|
133
139
|
},
|
|
134
140
|
];
|
|
135
141
|
|
|
142
|
+
/** Backend files that SwallowKit appends to; C# and TypeScript discover functions without a registration file. */
|
|
143
|
+
const BACKEND_EXTENSION_RULES: Record<BackendLanguage, BoundaryPathRule[]> = {
|
|
144
|
+
python: [
|
|
145
|
+
{
|
|
146
|
+
pattern: "functions/function_app.py",
|
|
147
|
+
zone: "shared",
|
|
148
|
+
editPolicy: "edit-outside-markers",
|
|
149
|
+
description: "SwallowKit appends blueprint registrations under its marker; other edits are free.",
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
pattern: "functions/requirements.txt",
|
|
153
|
+
zone: "shared",
|
|
154
|
+
editPolicy: "free-edit",
|
|
155
|
+
description: "SwallowKit appends connector driver requirements when connector models are scaffolded; keep those lines and edit other requirements freely.",
|
|
156
|
+
},
|
|
157
|
+
],
|
|
158
|
+
csharp: [],
|
|
159
|
+
typescript: [],
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const FALLBACK_RULE: BoundaryPathRule = {
|
|
163
|
+
pattern: "*",
|
|
164
|
+
zone: "ai-authored",
|
|
165
|
+
editPolicy: "free-edit",
|
|
166
|
+
description:
|
|
167
|
+
"Any path not recorded in the artifact ledger is AI/developer-authored. Business logic, custom pages, custom Functions, and tests belong here.",
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
export function buildConventionRules(backendLanguage: BackendLanguage): BoundaryPathRule[] {
|
|
171
|
+
return [...COMMON_LEADING_RULES, ...BACKEND_EXTENSION_RULES[backendLanguage], FALLBACK_RULE];
|
|
172
|
+
}
|
|
173
|
+
|
|
136
174
|
const POLICY_BY_OWNERSHIP = new Map(OWNERSHIP_POLICIES.map((policy) => [policy.ownership, policy] as const));
|
|
137
175
|
|
|
138
176
|
export const BOUNDARY_GUIDANCE: string[] = [
|
|
@@ -143,7 +181,10 @@ export const BOUNDARY_GUIDANCE: string[] = [
|
|
|
143
181
|
"Run `swallowkit machine verify project` after applying changes; use `explain failure` to get repair evidence.",
|
|
144
182
|
];
|
|
145
183
|
|
|
146
|
-
export function inspectBoundaries(
|
|
184
|
+
export function inspectBoundaries(
|
|
185
|
+
projectRoot: string = process.cwd(),
|
|
186
|
+
backendLanguage: BackendLanguage = getBackendLanguage()
|
|
187
|
+
): BoundariesContract {
|
|
147
188
|
const inspected = inspectArtifacts(projectRoot);
|
|
148
189
|
|
|
149
190
|
const artifacts: BoundaryArtifact[] = inspected.artifacts.map((artifact) => {
|
|
@@ -162,8 +203,9 @@ export function inspectBoundaries(projectRoot: string = process.cwd()): Boundari
|
|
|
162
203
|
contractVersion: 1,
|
|
163
204
|
summary:
|
|
164
205
|
"SwallowKit separates deterministic generation (models → CRUD/BFF/UI/infra via plan/apply) from AI free-form authoring (models, business logic, custom code). This contract tells agents which files belong to which side.",
|
|
206
|
+
backendLanguage,
|
|
165
207
|
ownershipPolicies: OWNERSHIP_POLICIES,
|
|
166
|
-
conventionRules:
|
|
208
|
+
conventionRules: buildConventionRules(backendLanguage),
|
|
167
209
|
artifacts,
|
|
168
210
|
guidance: BOUNDARY_GUIDANCE,
|
|
169
211
|
};
|
|
@@ -53,6 +53,7 @@ export interface CapabilitiesContract {
|
|
|
53
53
|
sharedModels: {
|
|
54
54
|
idFieldRule: string;
|
|
55
55
|
buildNote: string;
|
|
56
|
+
nativeSchemaMapping: string[];
|
|
56
57
|
};
|
|
57
58
|
seeding: {
|
|
58
59
|
createTemplates: string;
|
|
@@ -60,10 +61,19 @@ export interface CapabilitiesContract {
|
|
|
60
61
|
notes: string[];
|
|
61
62
|
};
|
|
62
63
|
machineCommands: string[];
|
|
64
|
+
provisioning: {
|
|
65
|
+
execution: string;
|
|
66
|
+
completion: string;
|
|
67
|
+
tracking: string;
|
|
68
|
+
recovery: string;
|
|
69
|
+
diagnostics: string;
|
|
70
|
+
approval: string;
|
|
71
|
+
};
|
|
63
72
|
verifyChecks: {
|
|
64
73
|
defaultChecks: string[];
|
|
65
74
|
optInChecks: string[];
|
|
66
75
|
customChecks: string;
|
|
76
|
+
backendBuild: string;
|
|
67
77
|
};
|
|
68
78
|
}
|
|
69
79
|
|
|
@@ -108,6 +118,19 @@ export function inspectCapabilities(): CapabilitiesContract {
|
|
|
108
118
|
"Role-based access control metadata applied to the generated CRUD Functions. `roles` guards all operations; `read`/`write` guard per-operation; `policy` references a named authorization policy from swallowkit.config auth.authorization.policies.",
|
|
109
119
|
format:
|
|
110
120
|
"export const authPolicy = { roles: ['admin'] };\n// or per-operation:\nexport const authPolicy = { read: ['user'], write: ['admin'] };\n// or a named policy:\nexport const authPolicy = { policy: 'adminOnly' };",
|
|
121
|
+
notes: [
|
|
122
|
+
"An explicit authPolicy without configured authentication blocks plan/apply/generate scaffold with auth-policy-without-auth before any artifacts are written. Run plan auth, apply auth, then re-plan scaffold. An empty {} declaration keeps the existing behavior: no explicit policy.",
|
|
123
|
+
"With named auth.schemes, define auth.authorization.policies selecting schemes and roles, then reference them via policy or read/write names. A role-only declaration cannot select a named scheme and blocks with auth-policy-requires-named-policy; it is supported by legacy single-provider authentication.",
|
|
124
|
+
"Conversely, single-provider authentication (auth.provider) supports role lists only. Referencing a named policy (authPolicy.policy, read/write names, or a named auth.authorization.defaultPolicy) blocks with auth-named-policy-requires-named-scheme; add a named scheme first.",
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
name: "references",
|
|
129
|
+
required: false,
|
|
130
|
+
description:
|
|
131
|
+
"Explicit foreign keys used by generated UI lookups. Without it, a string field named <model>Id is treated as a foreign key only when shared/models contains that model (userId -> User only if user.ts exists). Map a field to false to disable inference. References to missing models are ignored with a reference-model-not-found warning.",
|
|
132
|
+
format: "export const references = { authorId: 'User', legacyId: false };",
|
|
133
|
+
notes: ["Only single string id fields can reference a model.", "No lookup UI, fetch, or OpenAPI reference is generated for fields that do not reference an existing model."],
|
|
111
134
|
},
|
|
112
135
|
{
|
|
113
136
|
name: "connectorConfig",
|
|
@@ -174,15 +197,24 @@ export function inspectCapabilities(): CapabilitiesContract {
|
|
|
174
197
|
],
|
|
175
198
|
notGuaranteed: [
|
|
176
199
|
"Owner scoping: generated CRUD does NOT restrict rows to the authenticated principal. Any authenticated caller passing the policy can read/write any document.",
|
|
200
|
+
"Without authentication, plan scaffold reports user-scoped-data-without-auth when the partition key or an owner-like field (userId, learnerId, ownerId, ...) suggests per-user data.",
|
|
177
201
|
],
|
|
178
202
|
guidance: [
|
|
179
|
-
"For multi-user data where users may only touch their own records, add ai-authored custom endpoints that derive the scoping key (e.g. learnerId) from the verified principal — never from the request body — and restrict generated write endpoints to admin roles or disable them.",
|
|
203
|
+
"Configure authentication via plan/apply auth before declaring authPolicy. For multi-user data where users may only touch their own records, add ai-authored custom endpoints that derive the scoping key (e.g. learnerId) from the verified principal — never from the request body — and restrict generated write endpoints to admin roles or disable them.",
|
|
180
204
|
],
|
|
181
205
|
},
|
|
182
206
|
sharedModels: {
|
|
183
207
|
idFieldRule: "id: z.string() (required). createdAt/updatedAt: z.string().optional(). The backend owns their values.",
|
|
208
|
+
nativeSchemaMapping: [
|
|
209
|
+
"C#/Python schema assets derive types from Zod, never from field names: z.string() -> string/str (including createdAt/updatedAt).",
|
|
210
|
+
"Date types only when declared: z.iso.datetime() -> DateTime/datetime, z.iso.date() -> DateOnly/date, z.date() -> DateTime/datetime.",
|
|
211
|
+
"z.number() -> double / float|int; z.number().int() or z.int() -> long / int.",
|
|
212
|
+
"Inline z.object({...}) fields become named classes <Model><Field> (e.g. ProbeItemNested); imported model schemas keep their own class.",
|
|
213
|
+
"min/max/length/nonempty/regex/int/gt/gte/lt/lte/positive/nonnegative and array min/max are enforced by C# IValidatableObject.Validate and Python Field bounds/validators. Regexes use search semantics like Zod.",
|
|
214
|
+
"String formats (email/uuid/url), refinements, and transforms are not re-implemented natively; the BFF Zod schemas remain the authoritative validation.",
|
|
215
|
+
],
|
|
184
216
|
buildNote:
|
|
185
|
-
"verify typecheck resolves the shared package from its built dist/. SwallowKit rebuilds shared automatically during verify; when typechecking manually, build
|
|
217
|
+
"create-model and plan/apply scaffold append missing model exports to shared/index.ts, including manually authored models. Manual exports are allowed (no markers); existing content is preserved. verify typecheck resolves the shared package from its built dist/. SwallowKit rebuilds shared automatically during verify; when typechecking manually, build shared first.",
|
|
186
218
|
},
|
|
187
219
|
seeding: {
|
|
188
220
|
createTemplates: "swallowkit create-dev-seeds <environment> — writes dev-seeds/<environment>/<model>.json templates.",
|
|
@@ -190,18 +222,29 @@ export function inspectCapabilities(): CapabilitiesContract {
|
|
|
190
222
|
notes: ["Editing dev-seeds/*.json alone does nothing; seeds are only applied via dev --seed-env."],
|
|
191
223
|
},
|
|
192
224
|
machineCommands: [
|
|
193
|
-
"inspect project | entities | routes | artifacts | boundaries | infra | drift | capabilities",
|
|
225
|
+
"inspect project | entities | routes | artifacts | boundaries | infra | drift | capabilities; inspect provision --plan <runId> [--wait-seconds <0-3600>]",
|
|
194
226
|
"validate project",
|
|
195
227
|
"generate model <names...> | generate scaffold <model>",
|
|
196
|
-
"plan scaffold <models...> | plan auth --provider <p> [--scheme <name>] [--allowed-providers <csv>] | plan provision -g <rg> --location <loc> --swa-location <loc> [--adopt-existing --baseline 0 --what-if] [--reconcile --what-if]",
|
|
197
|
-
"apply scaffold [models...] --plan <id> [--approve] | apply auth --plan <id> [--approve] | apply provision --plan <id> --approve",
|
|
228
|
+
"plan scaffold <models...> [--api-only] [--skip-infra] | plan auth --provider <p> [--scheme <name>] [--allowed-providers <csv>] | plan provision -g <rg> --location <loc> --swa-location <loc> [--adopt-existing --baseline 0 --what-if] [--reconcile --what-if] [--resume-deployment <name>]",
|
|
229
|
+
"apply scaffold [models...] --plan <id> [--approve] [--skip-infra] | apply auth --plan <id> [--approve] | apply provision --plan <id> --approve [--wait-seconds <0-3600>] (also resumes the same execution checkpoint)",
|
|
198
230
|
"verify project [--checks <ids>] [--compact]",
|
|
199
231
|
"explain failure [--check <id>]",
|
|
232
|
+
"(regular CLI) migrations add-model <model> [--dry-run] — generate only the container migration after scaffold --skip-infra",
|
|
233
|
+
"(regular CLI) configure-mcp [--version auto|latest|<semver>] — re-select the MCP launcher version in .mcp.json",
|
|
200
234
|
],
|
|
235
|
+
provisioning: {
|
|
236
|
+
execution: "Submit Bicep once with az deployment group create --no-wait, then bounded state polling (default 300 seconds, configurable 0-3600) for machine/MCP; the human `swallowkit provision` command waits until Azure reaches a terminal state. Azure CLI invocations are bounded separately. Warning-only stderr with exit 0 is not a failure; output capture limits do not terminate az.",
|
|
237
|
+
completion: "status complete/outcome succeeded requires Azure Succeeded plus verified migration tags and local ledger completion. Running/Accepted -> in-progress; unreadable/not-found state -> blocked/outcome unknown; bookkeeping interruption after Azure Succeeded -> blocked/outcome partial; Failed/Canceled -> failed with Azure causes.",
|
|
238
|
+
tracking: "Approved runs persist before Azure writes under .swallowkit/state/provision/. runId equals the original planId and preserves the subscription, RG, deployment ID/correlation, fingerprints and migration state. inspect provision is read-only; apply provision --plan resumes without re-submitting attempted deployments. Ctrl+C/termination may leave Azure running; never cancel/delete without explicit consent.",
|
|
239
|
+
recovery: "For an older untracked baseline, plan provision --resume-deployment <name> compares the existing ARM template and non-secure parameters to the local Bicep/parameters. It observes that deployment and only tags/records it after Succeeded. Mismatches, unreadable evidence, secure parameters or non-baseline migrations block; do not use reconcile just to repair bookkeeping.",
|
|
240
|
+
diagnostics: "Machine/MCP results include bounded/redacted stdout/stderr, omitted-output flags, exit code, signal, failure kind, elapsed time and deployment identity, but no deployment outputs. Normal CLI shows named resource information and CI/CD setup guidance after success. Never print --debug output, keys, tokens or connection strings.",
|
|
241
|
+
approval: "Machine/MCP initial apply and every resume require explicit human approval. A human invoking normal provision or provision --resume explicitly requests execution without another confirmation prompt. Agents must not switch to normal CLI to bypass approval. A passing local command or an ok envelope is not proof of completed Azure provisioning; inspect status, outcome and nextActions.",
|
|
242
|
+
},
|
|
201
243
|
verifyChecks: {
|
|
202
|
-
defaultChecks: ["structure", "drift", "typecheck"],
|
|
244
|
+
defaultChecks: ["structure", "drift", "typecheck", "backend-build"],
|
|
203
245
|
optInChecks: ["build", "lint", "test"],
|
|
204
246
|
customChecks: "swallowkit.config verify.checks: [{ id, command, title?, timeoutMs? }]",
|
|
247
|
+
backendBuild: "Runs dotnet build in functions/ (C#), the project tsc --noEmit (TypeScript), or Python 3 compileall (syntax only, using functions/.venv before PATH). Missing toolchains are skip with a reason, not proof of validation. Root build scripts do not replace backend-build; use --checks \"structure,drift,typecheck,backend-build,build\" for both.",
|
|
205
248
|
},
|
|
206
249
|
};
|
|
207
250
|
}
|