swallowkit 1.0.0-beta.8 → 1.0.0
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 +87 -181
- package/README.md +87 -238
- package/dist/__tests__/fixtures.d.ts +12 -0
- package/dist/__tests__/fixtures.d.ts.map +1 -1
- package/dist/__tests__/fixtures.js +101 -0
- package/dist/__tests__/fixtures.js.map +1 -1
- package/dist/cli/commands/add-auth.d.ts +15 -0
- package/dist/cli/commands/add-auth.d.ts.map +1 -0
- package/dist/cli/commands/add-auth.js +790 -0
- package/dist/cli/commands/add-auth.js.map +1 -0
- package/dist/cli/commands/add-connector.d.ts +20 -0
- package/dist/cli/commands/add-connector.d.ts.map +1 -0
- package/dist/cli/commands/add-connector.js +164 -0
- package/dist/cli/commands/add-connector.js.map +1 -0
- package/dist/cli/commands/cosmos-worktree-isolation.d.ts +25 -0
- package/dist/cli/commands/cosmos-worktree-isolation.d.ts.map +1 -0
- package/dist/cli/commands/cosmos-worktree-isolation.js +124 -0
- package/dist/cli/commands/cosmos-worktree-isolation.js.map +1 -0
- package/dist/cli/commands/create-model.d.ts +1 -4
- package/dist/cli/commands/create-model.d.ts.map +1 -1
- package/dist/cli/commands/create-model.js +20 -82
- package/dist/cli/commands/create-model.js.map +1 -1
- package/dist/cli/commands/dev-seeds.d.ts +27 -0
- package/dist/cli/commands/dev-seeds.d.ts.map +1 -1
- package/dist/cli/commands/dev-seeds.js +188 -6
- package/dist/cli/commands/dev-seeds.js.map +1 -1
- package/dist/cli/commands/dev.d.ts +30 -0
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +495 -129
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/cli/commands/init.d.ts +70 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +797 -768
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/scaffold.d.ts +24 -3
- package/dist/cli/commands/scaffold.d.ts.map +1 -1
- package/dist/cli/commands/scaffold.js +408 -189
- package/dist/cli/commands/scaffold.js.map +1 -1
- package/dist/cli/index.d.ts +5 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +335 -58
- package/dist/cli/index.js.map +1 -1
- package/dist/core/config.d.ts +13 -3
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +151 -8
- package/dist/core/config.js.map +1 -1
- package/dist/core/mock/connector-mock-server.d.ts +101 -0
- package/dist/core/mock/connector-mock-server.d.ts.map +1 -0
- package/dist/core/mock/connector-mock-server.js +480 -0
- package/dist/core/mock/connector-mock-server.js.map +1 -0
- package/dist/core/mock/zod-mock-generator.d.ts +14 -0
- package/dist/core/mock/zod-mock-generator.d.ts.map +1 -0
- package/dist/core/mock/zod-mock-generator.js +163 -0
- package/dist/core/mock/zod-mock-generator.js.map +1 -0
- package/dist/core/operations/auth-operations.d.ts +61 -0
- package/dist/core/operations/auth-operations.d.ts.map +1 -0
- package/dist/core/operations/auth-operations.js +272 -0
- package/dist/core/operations/auth-operations.js.map +1 -0
- package/dist/core/operations/create-model.d.ts +15 -0
- package/dist/core/operations/create-model.d.ts.map +1 -0
- package/dist/core/operations/create-model.js +185 -0
- package/dist/core/operations/create-model.js.map +1 -0
- package/dist/core/operations/file-session.d.ts +56 -0
- package/dist/core/operations/file-session.d.ts.map +1 -0
- package/dist/core/operations/file-session.js +203 -0
- package/dist/core/operations/file-session.js.map +1 -0
- package/dist/core/operations/provision-operations.d.ts +52 -0
- package/dist/core/operations/provision-operations.d.ts.map +1 -0
- package/dist/core/operations/provision-operations.js +211 -0
- package/dist/core/operations/provision-operations.js.map +1 -0
- package/dist/core/operations/runtime.d.ts +37 -0
- package/dist/core/operations/runtime.d.ts.map +1 -0
- package/dist/core/operations/runtime.js +248 -0
- package/dist/core/operations/runtime.js.map +1 -0
- package/dist/core/operations/scaffold-apply.d.ts +21 -0
- package/dist/core/operations/scaffold-apply.d.ts.map +1 -0
- package/dist/core/operations/scaffold-apply.js +57 -0
- package/dist/core/operations/scaffold-apply.js.map +1 -0
- package/dist/core/operations/scaffold-machine.d.ts +16 -0
- package/dist/core/operations/scaffold-machine.d.ts.map +1 -0
- package/dist/core/operations/scaffold-machine.js +51 -0
- package/dist/core/operations/scaffold-machine.js.map +1 -0
- package/dist/core/operations/scaffold-plan.d.ts +43 -0
- package/dist/core/operations/scaffold-plan.d.ts.map +1 -0
- package/dist/core/operations/scaffold-plan.js +187 -0
- package/dist/core/operations/scaffold-plan.js.map +1 -0
- package/dist/core/project/agent-instructions.d.ts +29 -0
- package/dist/core/project/agent-instructions.d.ts.map +1 -0
- package/dist/core/project/agent-instructions.js +160 -0
- package/dist/core/project/agent-instructions.js.map +1 -0
- package/dist/core/project/artifacts.d.ts +58 -0
- package/dist/core/project/artifacts.d.ts.map +1 -0
- package/dist/core/project/artifacts.js +179 -0
- package/dist/core/project/artifacts.js.map +1 -0
- package/dist/core/project/boundaries.d.ts +50 -0
- package/dist/core/project/boundaries.d.ts.map +1 -0
- package/dist/core/project/boundaries.js +117 -0
- package/dist/core/project/boundaries.js.map +1 -0
- package/dist/core/project/capabilities.d.ts +58 -0
- package/dist/core/project/capabilities.d.ts.map +1 -0
- package/dist/core/project/capabilities.js +135 -0
- package/dist/core/project/capabilities.js.map +1 -0
- package/dist/core/project/drift.d.ts +29 -0
- package/dist/core/project/drift.d.ts.map +1 -0
- package/dist/core/project/drift.js +188 -0
- package/dist/core/project/drift.js.map +1 -0
- package/dist/core/project/infra.d.ts +49 -0
- package/dist/core/project/infra.d.ts.map +1 -0
- package/dist/core/project/infra.js +167 -0
- package/dist/core/project/infra.js.map +1 -0
- package/dist/core/project/manifest.d.ts +92 -0
- package/dist/core/project/manifest.d.ts.map +1 -0
- package/dist/core/project/manifest.js +321 -0
- package/dist/core/project/manifest.js.map +1 -0
- package/dist/core/project/state.d.ts +15 -0
- package/dist/core/project/state.d.ts.map +1 -0
- package/dist/core/project/state.js +106 -0
- package/dist/core/project/state.js.map +1 -0
- package/dist/core/project/validation.d.ts +20 -0
- package/dist/core/project/validation.d.ts.map +1 -0
- package/dist/core/project/validation.js +274 -0
- package/dist/core/project/validation.js.map +1 -0
- package/dist/core/project/workflows.d.ts +43 -0
- package/dist/core/project/workflows.d.ts.map +1 -0
- package/dist/core/project/workflows.js +299 -0
- package/dist/core/project/workflows.js.map +1 -0
- package/dist/core/scaffold/auth-generator.d.ts +63 -0
- package/dist/core/scaffold/auth-generator.d.ts.map +1 -0
- package/dist/core/scaffold/auth-generator.js +1774 -0
- package/dist/core/scaffold/auth-generator.js.map +1 -0
- package/dist/core/scaffold/connector-functions-generator.d.ts +41 -0
- package/dist/core/scaffold/connector-functions-generator.d.ts.map +1 -0
- package/dist/core/scaffold/connector-functions-generator.js +1029 -0
- package/dist/core/scaffold/connector-functions-generator.js.map +1 -0
- package/dist/core/scaffold/functions-generator.d.ts +4 -3
- package/dist/core/scaffold/functions-generator.d.ts.map +1 -1
- package/dist/core/scaffold/functions-generator.js +405 -134
- package/dist/core/scaffold/functions-generator.js.map +1 -1
- package/dist/core/scaffold/model-parser.d.ts +20 -0
- package/dist/core/scaffold/model-parser.d.ts.map +1 -1
- package/dist/core/scaffold/model-parser.js +229 -78
- package/dist/core/scaffold/model-parser.js.map +1 -1
- package/dist/core/scaffold/native-schema-generator.d.ts +19 -0
- package/dist/core/scaffold/native-schema-generator.d.ts.map +1 -0
- package/dist/core/scaffold/native-schema-generator.js +753 -0
- package/dist/core/scaffold/native-schema-generator.js.map +1 -0
- package/dist/core/scaffold/nextjs-generator.d.ts +8 -0
- package/dist/core/scaffold/nextjs-generator.d.ts.map +1 -1
- package/dist/core/scaffold/nextjs-generator.js +152 -8
- package/dist/core/scaffold/nextjs-generator.js.map +1 -1
- package/dist/core/scaffold/ui-generator.d.ts +17 -4
- package/dist/core/scaffold/ui-generator.d.ts.map +1 -1
- package/dist/core/scaffold/ui-generator.js +174 -34
- package/dist/core/scaffold/ui-generator.js.map +1 -1
- package/dist/core/verify/index.d.ts +69 -0
- package/dist/core/verify/index.d.ts.map +1 -0
- package/dist/core/verify/index.js +412 -0
- package/dist/core/verify/index.js.map +1 -0
- package/dist/machine/contracts.d.ts +24 -0
- package/dist/machine/contracts.d.ts.map +1 -0
- package/dist/machine/contracts.js +3 -0
- package/dist/machine/contracts.js.map +1 -0
- package/dist/machine/errors.d.ts +14 -0
- package/dist/machine/errors.d.ts.map +1 -0
- package/dist/machine/errors.js +42 -0
- package/dist/machine/errors.js.map +1 -0
- package/dist/machine/index.d.ts +3 -0
- package/dist/machine/index.d.ts.map +1 -0
- package/dist/machine/index.js +566 -0
- package/dist/machine/index.js.map +1 -0
- package/dist/mcp/index.d.ts +25 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +425 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/types/index.d.ts +105 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/package-manager.d.ts +7 -11
- package/dist/utils/package-manager.d.ts.map +1 -1
- package/dist/utils/package-manager.js +42 -17
- package/dist/utils/package-manager.js.map +1 -1
- package/dist/utils/python-uv.d.ts +21 -0
- package/dist/utils/python-uv.d.ts.map +1 -0
- package/dist/utils/python-uv.js +111 -0
- package/dist/utils/python-uv.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +49 -0
- package/dist/version.js.map +1 -0
- package/package.json +15 -17
- package/src/__tests__/__snapshots__/functions-generator.test.ts.snap +716 -22
- package/src/__tests__/__snapshots__/nextjs-generator.test.ts.snap +19 -7
- package/src/__tests__/__snapshots__/ui-generator.test.ts.snap +20 -12
- package/src/__tests__/agent-instructions.test.ts +237 -0
- package/src/__tests__/agent-loop-phase34.test.ts +513 -0
- package/src/__tests__/auth.test.ts +770 -0
- package/src/__tests__/bff-swa-auth.test.ts +275 -0
- package/src/__tests__/config.test.ts +176 -3
- package/src/__tests__/connector-functions-generator.test.ts +288 -0
- package/src/__tests__/connector-mock-server.test.ts +459 -0
- package/src/__tests__/connector-model-bff.test.ts +162 -0
- package/src/__tests__/cosmos-worktree-isolation.test.ts +149 -0
- package/src/__tests__/dev-seeds.test.ts +124 -0
- package/src/__tests__/dev.test.ts +254 -0
- package/src/__tests__/file-session.test.ts +98 -0
- package/src/__tests__/fixtures.ts +101 -0
- package/src/__tests__/functions-generator.test.ts +137 -1
- package/src/__tests__/init.test.ts +386 -1
- package/src/__tests__/jest-globals.d.ts +8 -0
- package/src/__tests__/machine.test.ts +371 -0
- package/src/__tests__/mcp.test.ts +253 -0
- package/src/__tests__/model-parser.test.ts +142 -0
- package/src/__tests__/multi-auth.test.ts +160 -0
- package/src/__tests__/nextjs-generator.test.ts +8 -0
- package/src/__tests__/package-manager.test.ts +59 -4
- package/src/__tests__/plan-apply.test.ts +499 -0
- package/src/__tests__/python-uv.test.ts +48 -0
- package/src/__tests__/scaffold.test.ts +287 -24
- package/src/__tests__/tsconfig.json +15 -0
- package/src/__tests__/ui-generator.test.ts +104 -0
- package/src/__tests__/zod-mock-generator.test.ts +132 -0
- package/src/cli/commands/add-auth.ts +853 -0
- package/src/cli/commands/add-connector.ts +159 -0
- package/src/cli/commands/cosmos-worktree-isolation.ts +130 -0
- package/src/cli/commands/create-model.ts +21 -100
- package/src/cli/commands/dev-seeds.ts +278 -7
- package/src/cli/commands/dev.ts +607 -160
- package/src/cli/commands/init.ts +880 -808
- package/src/cli/commands/scaffold.ts +531 -236
- package/src/cli/index.ts +338 -60
- package/src/core/config.ts +145 -9
- package/src/core/mock/connector-mock-server.ts +555 -0
- package/src/core/mock/zod-mock-generator.ts +205 -0
- package/src/core/operations/auth-operations.ts +360 -0
- package/src/core/operations/create-model.ts +191 -0
- package/src/core/operations/file-session.ts +222 -0
- package/src/core/operations/provision-operations.ts +297 -0
- package/src/core/operations/runtime.ts +258 -0
- package/src/core/operations/scaffold-apply.ts +106 -0
- package/src/core/operations/scaffold-machine.ts +77 -0
- package/src/core/operations/scaffold-plan.ts +215 -0
- package/src/core/project/agent-instructions.ts +167 -0
- package/src/core/project/agent-templates/AGENTS.md +504 -0
- package/src/core/project/agent-templates/CLAUDE.md +31 -0
- package/src/core/project/agent-templates/azure-functions.instructions.md +22 -0
- package/src/core/project/agent-templates/bff-routes.instructions.md +18 -0
- package/src/core/project/agent-templates/copilot-instructions.md +27 -0
- package/src/core/project/agent-templates/shared-models.instructions.md +72 -0
- package/src/core/project/artifacts.ts +205 -0
- package/src/core/project/boundaries.ts +170 -0
- package/src/core/project/capabilities.ts +193 -0
- package/src/core/project/drift.ts +202 -0
- package/src/core/project/infra.ts +196 -0
- package/src/core/project/manifest.ts +402 -0
- package/src/core/project/state.ts +77 -0
- package/src/core/project/validation.ts +295 -0
- package/src/core/project/workflows.ts +295 -0
- package/src/core/scaffold/auth-generator.ts +1824 -0
- package/src/core/scaffold/connector-functions-generator.ts +1133 -0
- package/src/core/scaffold/functions-generator.ts +432 -134
- package/src/core/scaffold/model-parser.ts +244 -90
- package/src/core/scaffold/native-schema-generator.ts +904 -0
- package/src/core/scaffold/nextjs-generator.ts +174 -9
- package/src/core/scaffold/ui-generator.ts +191 -36
- package/src/core/verify/index.ts +468 -0
- package/src/machine/contracts.ts +33 -0
- package/src/machine/errors.ts +45 -0
- package/src/machine/index.ts +690 -0
- package/src/mcp/index.ts +423 -0
- package/src/types/index.ts +137 -0
- package/src/utils/package-manager.ts +41 -19
- package/src/utils/python-uv.ts +96 -0
- package/src/version.ts +13 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
3
|
exports[`generateBFFCallFunction generates call function helper code 1`] = `
|
|
4
|
-
"import {
|
|
4
|
+
"import { NextResponse } from 'next/server';
|
|
5
5
|
import { z } from 'zod/v4';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -23,13 +23,24 @@ function getFunctionsBaseUrl(): string {
|
|
|
23
23
|
return process.env.BACKEND_FUNCTIONS_BASE_URL || process.env.FUNCTIONS_BASE_URL || 'http://localhost:7071';
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
function isLocalFunctionsUrl(url: string): boolean {
|
|
27
|
+
return url.startsWith('http://localhost:') || url.startsWith('http://127.0.0.1:');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getFunctionsKeyHeaders(functionsBaseUrl: string): Record<string, string> {
|
|
31
|
+
const key = process.env.BACKEND_FUNCTIONS_KEY;
|
|
32
|
+
if (key) return { 'x-functions-key': key };
|
|
33
|
+
if (isLocalFunctionsUrl(functionsBaseUrl)) return {};
|
|
34
|
+
throw new Error('BACKEND_FUNCTIONS_KEY is required for non-local Functions calls');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface CallFunctionConfig<TInput = unknown, TOutput = unknown> {
|
|
27
38
|
/** HTTP メソッド */
|
|
28
39
|
method: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
29
40
|
/** Azure Functions のパス (例: '/api/todo', '/api/todo/123') */
|
|
30
41
|
path: string;
|
|
31
42
|
/** リクエストボディ (POST/PUT 用) */
|
|
32
|
-
body?:
|
|
43
|
+
body?: unknown;
|
|
33
44
|
/** 入力バリデーション用 Zod スキーマ (省略時はバリデーションなし) */
|
|
34
45
|
inputSchema?: z.ZodSchema<TInput>;
|
|
35
46
|
/** 出力バリデーション用 Zod スキーマ (省略時はそのまま返す) */
|
|
@@ -38,7 +49,7 @@ interface CallFunctionConfig<TInput = any, TOutput = any> {
|
|
|
38
49
|
successStatus?: number;
|
|
39
50
|
}
|
|
40
51
|
|
|
41
|
-
export async function callFunction<TInput =
|
|
52
|
+
export async function callFunction<TInput = unknown, TOutput = unknown>(
|
|
42
53
|
config: CallFunctionConfig<TInput, TOutput>
|
|
43
54
|
): Promise<NextResponse> {
|
|
44
55
|
const { method, path, body, inputSchema, responseSchema, successStatus = 200 } = config;
|
|
@@ -61,11 +72,12 @@ export async function callFunction<TInput = any, TOutput = any>(
|
|
|
61
72
|
// Azure Functions を呼び出し
|
|
62
73
|
const functionsBaseUrl = getFunctionsBaseUrl();
|
|
63
74
|
const url = functionsBaseUrl + path;
|
|
75
|
+
const keyHeaders = getFunctionsKeyHeaders(functionsBaseUrl);
|
|
64
76
|
console.log(\`[BFF] \${method} \${url}\`);
|
|
65
77
|
|
|
66
78
|
const response = await fetch(url, {
|
|
67
79
|
method,
|
|
68
|
-
headers: { 'Content-Type': 'application/json' },
|
|
80
|
+
headers: { 'Content-Type': 'application/json', ...keyHeaders },
|
|
69
81
|
body: validatedBody !== undefined ? JSON.stringify(validatedBody) : undefined,
|
|
70
82
|
});
|
|
71
83
|
|
|
@@ -100,10 +112,10 @@ export async function callFunction<TInput = any, TOutput = any>(
|
|
|
100
112
|
}
|
|
101
113
|
|
|
102
114
|
return NextResponse.json(data, { status: successStatus });
|
|
103
|
-
} catch (error
|
|
115
|
+
} catch (error) {
|
|
104
116
|
console.error(\`[BFF] Error:\`, error);
|
|
105
117
|
return NextResponse.json(
|
|
106
|
-
{ error: error.message
|
|
118
|
+
{ error: error instanceof Error ? error.message : 'Internal server error' },
|
|
107
119
|
{ status: 500 }
|
|
108
120
|
);
|
|
109
121
|
}
|
|
@@ -9,6 +9,7 @@ import Link from 'next/link';
|
|
|
9
9
|
import { z } from 'zod/v4';
|
|
10
10
|
import { todoSchema } from '@myapp/shared';
|
|
11
11
|
|
|
12
|
+
|
|
12
13
|
type Todo = z.infer<typeof todoSchema>;
|
|
13
14
|
|
|
14
15
|
export default function TodoDetailPage() {
|
|
@@ -19,6 +20,7 @@ export default function TodoDetailPage() {
|
|
|
19
20
|
const [error, setError] = useState<string | null>(null);
|
|
20
21
|
|
|
21
22
|
|
|
23
|
+
|
|
22
24
|
useEffect(() => {
|
|
23
25
|
const id = params?.id as string;
|
|
24
26
|
if (!id) return;
|
|
@@ -51,8 +53,8 @@ export default function TodoDetailPage() {
|
|
|
51
53
|
if (!res.ok) throw new Error('Failed to delete todo');
|
|
52
54
|
|
|
53
55
|
router.push('/todo');
|
|
54
|
-
} catch (err
|
|
55
|
-
alert(\`Error: \${err.message}\`);
|
|
56
|
+
} catch (err) {
|
|
57
|
+
alert(\`Error: \${err instanceof Error ? err.message : String(err)}\`);
|
|
56
58
|
}
|
|
57
59
|
};
|
|
58
60
|
|
|
@@ -141,18 +143,22 @@ exports[`generateEditPage generates edit page (snapshot) 1`] = `
|
|
|
141
143
|
"'use client';
|
|
142
144
|
|
|
143
145
|
import { useEffect, useState } from 'react';
|
|
144
|
-
import { useParams } from 'next/navigation';
|
|
146
|
+
import { useParams, useRouter } from 'next/navigation';
|
|
145
147
|
import TodoForm from '../../_components/TodoForm';
|
|
146
148
|
import { z } from 'zod/v4';
|
|
147
149
|
import { todoSchema } from '@myapp/shared';
|
|
148
150
|
|
|
151
|
+
|
|
149
152
|
type Todo = z.infer<typeof todoSchema>;
|
|
150
153
|
|
|
151
154
|
export default function EditTodoPage() {
|
|
152
155
|
const params = useParams();
|
|
156
|
+
|
|
153
157
|
const [todo, setTodo] = useState<Todo | null>(null);
|
|
154
158
|
const [loading, setLoading] = useState(true);
|
|
155
159
|
|
|
160
|
+
|
|
161
|
+
|
|
156
162
|
useEffect(() => {
|
|
157
163
|
const id = params?.id as string;
|
|
158
164
|
if (!id) return;
|
|
@@ -235,7 +241,7 @@ export default function TodoForm({ initialData, isEdit = false }: TodoFormProps)
|
|
|
235
241
|
|
|
236
242
|
try {
|
|
237
243
|
// Array フィールドをカンマ区切りから配列に変換
|
|
238
|
-
const submitData:
|
|
244
|
+
const submitData: Record<string, unknown> = { ...formData };
|
|
239
245
|
|
|
240
246
|
|
|
241
247
|
|
|
@@ -259,17 +265,17 @@ export default function TodoForm({ initialData, isEdit = false }: TodoFormProps)
|
|
|
259
265
|
}
|
|
260
266
|
|
|
261
267
|
router.push('/todo');
|
|
262
|
-
} catch (err
|
|
263
|
-
if (err.
|
|
268
|
+
} catch (err) {
|
|
269
|
+
if (err instanceof z.ZodError) {
|
|
264
270
|
// Zod validation errors
|
|
265
271
|
const fieldErrors: Record<string, string> = {};
|
|
266
|
-
err.issues.forEach((
|
|
267
|
-
const field =
|
|
268
|
-
fieldErrors[field] =
|
|
272
|
+
err.issues.forEach((issue) => {
|
|
273
|
+
const field = String(issue.path[0]);
|
|
274
|
+
fieldErrors[field] = issue.message;
|
|
269
275
|
});
|
|
270
276
|
setErrors(fieldErrors);
|
|
271
277
|
} else {
|
|
272
|
-
alert(\`Error: \${err.message}\`);
|
|
278
|
+
alert(\`Error: \${err instanceof Error ? err.message : String(err)}\`);
|
|
273
279
|
}
|
|
274
280
|
setLoading(false);
|
|
275
281
|
}
|
|
@@ -360,6 +366,7 @@ import Link from 'next/link';
|
|
|
360
366
|
import { z } from 'zod/v4';
|
|
361
367
|
import { todoSchema } from '@myapp/shared';
|
|
362
368
|
|
|
369
|
+
|
|
363
370
|
type Todo = z.infer<typeof todoSchema>;
|
|
364
371
|
|
|
365
372
|
export default function TodoListPage() {
|
|
@@ -368,6 +375,7 @@ export default function TodoListPage() {
|
|
|
368
375
|
const [error, setError] = useState<string | null>(null);
|
|
369
376
|
|
|
370
377
|
|
|
378
|
+
|
|
371
379
|
useEffect(() => {
|
|
372
380
|
fetch('/api/todo')
|
|
373
381
|
.then((res) => {
|
|
@@ -397,8 +405,8 @@ export default function TodoListPage() {
|
|
|
397
405
|
if (!res.ok) throw new Error('Failed to delete todo');
|
|
398
406
|
|
|
399
407
|
setTodos(todos.filter((item) => item.id !== id));
|
|
400
|
-
} catch (err
|
|
401
|
-
alert(\`Error: \${err.message}\`);
|
|
408
|
+
} catch (err) {
|
|
409
|
+
alert(\`Error: \${err instanceof Error ? err.message : String(err)}\`);
|
|
402
410
|
}
|
|
403
411
|
};
|
|
404
412
|
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as os from "os";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import {
|
|
5
|
+
AGENT_TEMPLATE_FILES,
|
|
6
|
+
AgentInstructionContext,
|
|
7
|
+
buildAgentsMd,
|
|
8
|
+
buildClaudeMd,
|
|
9
|
+
buildCopilotInstructions,
|
|
10
|
+
buildPathSpecificInstructions,
|
|
11
|
+
readAgentInstructionTemplate,
|
|
12
|
+
writeAgentInstructionFiles,
|
|
13
|
+
} from "../core/project/agent-instructions";
|
|
14
|
+
|
|
15
|
+
const representativeContext: AgentInstructionContext = {
|
|
16
|
+
projectName: "sample-app",
|
|
17
|
+
backendLanguage: "typescript",
|
|
18
|
+
packageManager: "npm",
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const repositoryRoot = path.resolve(__dirname, "../..");
|
|
22
|
+
|
|
23
|
+
describe("coding-agent instruction contract", () => {
|
|
24
|
+
it("applies SwallowKit before implementation and composes with external processes", () => {
|
|
25
|
+
const agentsMd = buildAgentsMd(representativeContext);
|
|
26
|
+
|
|
27
|
+
expect(agentsMd).toContain("discovery, requirements clarification");
|
|
28
|
+
expect(agentsMd).toContain("specification, planning, ticket decomposition");
|
|
29
|
+
expect(agentsMd).toContain("not only during code generation");
|
|
30
|
+
expect(agentsMd).toContain("How SwallowKit Fits Into the Development Process");
|
|
31
|
+
expect(agentsMd).toContain("does **not** own the overall software development process");
|
|
32
|
+
expect(agentsMd).toContain("External development-process skills and SwallowKit are intended to compose");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("requires inspection before questions or design instead of remembered capabilities", () => {
|
|
36
|
+
const agentsMd = buildAgentsMd(representativeContext);
|
|
37
|
+
|
|
38
|
+
expect(agentsMd).toContain("Do Not Assume SwallowKit Capabilities From Memory");
|
|
39
|
+
expect(agentsMd).toContain("Inspect Before Asking or Designing");
|
|
40
|
+
expect(agentsMd).toContain("should be answered by the agent instead of being delegated to the human");
|
|
41
|
+
expect(agentsMd).toContain("npx swallowkit machine inspect project");
|
|
42
|
+
expect(agentsMd).toContain("npx swallowkit machine inspect entities");
|
|
43
|
+
expect(agentsMd).toContain("npx swallowkit machine inspect routes");
|
|
44
|
+
expect(agentsMd).toContain("npx swallowkit machine inspect boundaries");
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("defines ownership, vertical slices, plan/apply, verification, and approval gates", () => {
|
|
48
|
+
const agentsMd = buildAgentsMd(representativeContext);
|
|
49
|
+
|
|
50
|
+
expect(agentsMd).toContain("### ai-authored");
|
|
51
|
+
expect(agentsMd).toContain("### deterministic");
|
|
52
|
+
expect(agentsMd).toContain("### shared");
|
|
53
|
+
expect(agentsMd).toContain("vertical slices");
|
|
54
|
+
expect(agentsMd).toContain("Do not split work into horizontal tickets");
|
|
55
|
+
expect(agentsMd).toContain("Deterministic Changes: Plan → Apply → Verify");
|
|
56
|
+
expect(agentsMd).toContain("npx swallowkit machine plan scaffold <model>");
|
|
57
|
+
expect(agentsMd).toContain("Verification Is a Completion Gate");
|
|
58
|
+
expect(agentsMd).toContain("semantic code review answers different questions");
|
|
59
|
+
expect(agentsMd).toContain("When the status is `requires-human`, stop");
|
|
60
|
+
expect(agentsMd).toContain("never bypass its\napproval gate");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("uses MCP first and the package-manager-specific machine fallback", () => {
|
|
64
|
+
const npmDocument = buildAgentsMd(representativeContext);
|
|
65
|
+
const pnpmDocument = buildAgentsMd({
|
|
66
|
+
...representativeContext,
|
|
67
|
+
packageManager: "pnpm",
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
expect(npmDocument).toContain("Prefer the `swallowkit_*` MCP tools when available");
|
|
71
|
+
expect(npmDocument).toContain("npx swallowkit machine ...");
|
|
72
|
+
expect(pnpmDocument).toContain("pnpm exec swallowkit machine ...");
|
|
73
|
+
expect(pnpmDocument).not.toContain("npx swallowkit machine ...");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("keeps Claude and Copilot as self-identifying adapters to canonical AGENTS.md", () => {
|
|
77
|
+
const adapters = [
|
|
78
|
+
buildClaudeMd(representativeContext),
|
|
79
|
+
buildCopilotInstructions(representativeContext),
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
for (const adapter of adapters) {
|
|
83
|
+
expect(adapter).toContain("This is a **SwallowKit** project");
|
|
84
|
+
expect(adapter).toContain("root `AGENTS.md`");
|
|
85
|
+
expect(adapter).toContain("canonical project contract");
|
|
86
|
+
expect(adapter).toContain("discovery");
|
|
87
|
+
expect(adapter).toContain("specification");
|
|
88
|
+
expect(adapter).toContain("planning");
|
|
89
|
+
expect(adapter).toContain("Never hand-edit deterministic SwallowKit-managed artifacts");
|
|
90
|
+
expect(adapter).toContain("SwallowKit verification");
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("aligns path-specific instructions with the machine plan/apply workflow", () => {
|
|
95
|
+
const instructions = buildPathSpecificInstructions(representativeContext);
|
|
96
|
+
const sharedModels = instructions[AGENT_TEMPLATE_FILES.sharedModelsInstructions];
|
|
97
|
+
|
|
98
|
+
expect(sharedModels).toContain("swallowkit-modify-model");
|
|
99
|
+
expect(sharedModels).toContain(".swallowkit/workflows/modify-model.md");
|
|
100
|
+
expect(sharedModels).toContain("inspect drift → plan scaffold → apply scaffold → verify project");
|
|
101
|
+
expect(sharedModels).toContain("Prefer the equivalent `swallowkit_*` MCP tools");
|
|
102
|
+
|
|
103
|
+
for (const content of Object.values(instructions)) {
|
|
104
|
+
expect(content).toContain("root `AGENTS.md` is the canonical contract");
|
|
105
|
+
expect(content).toMatch(/Never|never|do not/);
|
|
106
|
+
expect(content).toContain("requires-human");
|
|
107
|
+
expect(content).not.toMatch(/run `(?:npx|pnpm )?swallowkit scaffold/);
|
|
108
|
+
expect(content).not.toContain("rerunning `swallowkit scaffold`");
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("writes the generated integration files from the builders", () => {
|
|
113
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "swallowkit-agent-docs-"));
|
|
114
|
+
try {
|
|
115
|
+
const documents = writeAgentInstructionFiles(tempDir, representativeContext);
|
|
116
|
+
expect(fs.readFileSync(path.join(tempDir, "AGENTS.md"), "utf-8")).toBe(documents.agentsMd);
|
|
117
|
+
expect(fs.readFileSync(path.join(tempDir, "CLAUDE.md"), "utf-8")).toBe(documents.claudeMd);
|
|
118
|
+
expect(
|
|
119
|
+
fs.readFileSync(path.join(tempDir, ".github", "copilot-instructions.md"), "utf-8")
|
|
120
|
+
).toBe(documents.copilotInstructions);
|
|
121
|
+
for (const [fileName, content] of Object.entries(documents.pathSpecificInstructions)) {
|
|
122
|
+
expect(
|
|
123
|
+
fs.readFileSync(path.join(tempDir, ".github", "instructions", fileName), "utf-8")
|
|
124
|
+
).toBe(content);
|
|
125
|
+
}
|
|
126
|
+
} finally {
|
|
127
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("covers the requested model-change, new-feature, BFF, and deployment scenarios", () => {
|
|
132
|
+
const agentsMd = buildAgentsMd(representativeContext);
|
|
133
|
+
const pathInstructions = buildPathSpecificInstructions(representativeContext);
|
|
134
|
+
|
|
135
|
+
// Scenario A: existing Todo field change.
|
|
136
|
+
expect(agentsMd).toContain("For an existing model change, the normal pattern is");
|
|
137
|
+
expect(agentsMd).toContain("edit source-of-truth model");
|
|
138
|
+
expect(agentsMd).toContain("inspect drift");
|
|
139
|
+
expect(agentsMd).toContain("verify before final semantic review");
|
|
140
|
+
|
|
141
|
+
// Scenario B: new Order behavior starts with discovery and the add-model capability.
|
|
142
|
+
expect(agentsMd).toContain("requirements clarification");
|
|
143
|
+
expect(agentsMd).toContain("machine inspect entities");
|
|
144
|
+
expect(agentsMd).toContain("machine inspect routes");
|
|
145
|
+
expect(agentsMd).toContain("Use the `swallowkit-add-model` Agent Skill when available");
|
|
146
|
+
|
|
147
|
+
// Scenario C: generated BFF logic is redirected to the correct ownership zone.
|
|
148
|
+
const bff = pathInstructions[AGENT_TEMPLATE_FILES.bffRoutesInstructions];
|
|
149
|
+
const functions = pathInstructions[AGENT_TEMPLATE_FILES.azureFunctionsInstructions];
|
|
150
|
+
expect(bff).toContain("Never place business logic, database access");
|
|
151
|
+
expect(bff).toContain("Never directly edit a route reported as deterministic");
|
|
152
|
+
expect(functions).toContain("Put custom behavior only in an ai-authored location");
|
|
153
|
+
|
|
154
|
+
// Scenario D: a broad deployment request never implies provisioning approval.
|
|
155
|
+
expect(agentsMd).toContain("A broad request to deploy does not itself grant the explicit");
|
|
156
|
+
expect(agentsMd).toContain("Use the `swallowkit-provision` Agent Skill or runbook");
|
|
157
|
+
expect(agentsMd).toContain("When the status is `requires-human`, stop");
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe("coding-agent documentation synchronization", () => {
|
|
162
|
+
const englishGuidePath = path.join(repositoryRoot, "docs", "en", "coding-agent-guide.md");
|
|
163
|
+
const japaneseGuidePath = path.join(repositoryRoot, "docs", "ja", "coding-agent-guide.md");
|
|
164
|
+
|
|
165
|
+
it("publishes each complete English original directly from its canonical template", () => {
|
|
166
|
+
const englishGuide = fs.readFileSync(englishGuidePath, "utf-8");
|
|
167
|
+
const japaneseGuide = fs.readFileSync(japaneseGuidePath, "utf-8");
|
|
168
|
+
|
|
169
|
+
const expectedIncludes = [
|
|
170
|
+
"AGENTS.md",
|
|
171
|
+
"CLAUDE.md",
|
|
172
|
+
"copilot-instructions.md",
|
|
173
|
+
];
|
|
174
|
+
for (const fileName of expectedIncludes) {
|
|
175
|
+
const include = `<<< ../../src/core/project/agent-templates/${fileName}{md}`;
|
|
176
|
+
expect(englishGuide).toContain(include);
|
|
177
|
+
expect(japaneseGuide).toContain(include);
|
|
178
|
+
expect(readAgentInstructionTemplate(fileName).length).toBeGreaterThan(500);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
expect(englishGuide).toContain("complete English templates");
|
|
182
|
+
expect(englishGuide).toContain("not\nabridged excerpts");
|
|
183
|
+
expect(japaneseGuide).toContain("抜粋ではありません");
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("keeps the Japanese AGENTS.md translation aligned by canonical section", () => {
|
|
187
|
+
const source = readAgentInstructionTemplate(AGENT_TEMPLATE_FILES.agentsMd);
|
|
188
|
+
const translation = fs.readFileSync(
|
|
189
|
+
path.join(repositoryRoot, "docs", "ja", "generated-agent-docs", "AGENTS.ja.md"),
|
|
190
|
+
"utf-8"
|
|
191
|
+
);
|
|
192
|
+
const sourceSections = [...source.matchAll(/^## (.+)$/gm)].map((match) => match[1]);
|
|
193
|
+
const translatedSourceSections = [
|
|
194
|
+
...translation.matchAll(/^<!-- source-section: (.+) -->$/gm),
|
|
195
|
+
].map((match) => match[1]);
|
|
196
|
+
|
|
197
|
+
expect(translatedSourceSections).toEqual(sourceSections);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it("exposes matching major EN/JA guide topics and both sidebar entries", () => {
|
|
201
|
+
const englishGuide = fs.readFileSync(englishGuidePath, "utf-8");
|
|
202
|
+
const japaneseGuide = fs.readFileSync(japaneseGuidePath, "utf-8");
|
|
203
|
+
const vitepressConfig = fs.readFileSync(
|
|
204
|
+
path.join(repositoryRoot, "docs", ".vitepress", "config.mts"),
|
|
205
|
+
"utf-8"
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
for (const topic of [
|
|
209
|
+
"Generated agent integration files",
|
|
210
|
+
"SwallowKit across the development lifecycle",
|
|
211
|
+
"Inspect before asking or designing",
|
|
212
|
+
"Responsibility boundary",
|
|
213
|
+
"Planning and ticketing",
|
|
214
|
+
"Implementation workflow",
|
|
215
|
+
"Verification versus semantic review",
|
|
216
|
+
"Human approval",
|
|
217
|
+
"Composing with external development processes",
|
|
218
|
+
]) {
|
|
219
|
+
expect(englishGuide.toLowerCase()).toContain(topic.toLowerCase());
|
|
220
|
+
}
|
|
221
|
+
for (const topic of [
|
|
222
|
+
"生成される Agent integration files",
|
|
223
|
+
"開発ライフサイクル全体での SwallowKit",
|
|
224
|
+
"質問・設計の前に inspect する",
|
|
225
|
+
"Responsibility boundary",
|
|
226
|
+
"Planning と ticketing",
|
|
227
|
+
"Implementation workflow",
|
|
228
|
+
"Verification と semantic review の違い",
|
|
229
|
+
"Human approval",
|
|
230
|
+
"外部 development process との composition",
|
|
231
|
+
]) {
|
|
232
|
+
expect(japaneseGuide).toContain(topic);
|
|
233
|
+
}
|
|
234
|
+
expect(vitepressConfig).toContain("/en/coding-agent-guide");
|
|
235
|
+
expect(vitepressConfig).toContain("/ja/coding-agent-guide");
|
|
236
|
+
});
|
|
237
|
+
});
|