swallowkit 1.0.0-beta.9 → 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.
Files changed (272) hide show
  1. package/README.ja.md +87 -181
  2. package/README.md +87 -238
  3. package/dist/__tests__/fixtures.d.ts +12 -0
  4. package/dist/__tests__/fixtures.d.ts.map +1 -1
  5. package/dist/__tests__/fixtures.js +101 -0
  6. package/dist/__tests__/fixtures.js.map +1 -1
  7. package/dist/cli/commands/add-auth.d.ts +15 -0
  8. package/dist/cli/commands/add-auth.d.ts.map +1 -0
  9. package/dist/cli/commands/add-auth.js +790 -0
  10. package/dist/cli/commands/add-auth.js.map +1 -0
  11. package/dist/cli/commands/add-connector.d.ts +20 -0
  12. package/dist/cli/commands/add-connector.d.ts.map +1 -0
  13. package/dist/cli/commands/add-connector.js +164 -0
  14. package/dist/cli/commands/add-connector.js.map +1 -0
  15. package/dist/cli/commands/cosmos-worktree-isolation.d.ts +25 -0
  16. package/dist/cli/commands/cosmos-worktree-isolation.d.ts.map +1 -0
  17. package/dist/cli/commands/cosmos-worktree-isolation.js +124 -0
  18. package/dist/cli/commands/cosmos-worktree-isolation.js.map +1 -0
  19. package/dist/cli/commands/create-model.d.ts +1 -4
  20. package/dist/cli/commands/create-model.d.ts.map +1 -1
  21. package/dist/cli/commands/create-model.js +20 -82
  22. package/dist/cli/commands/create-model.js.map +1 -1
  23. package/dist/cli/commands/dev-seeds.d.ts +27 -0
  24. package/dist/cli/commands/dev-seeds.d.ts.map +1 -1
  25. package/dist/cli/commands/dev-seeds.js +188 -6
  26. package/dist/cli/commands/dev-seeds.js.map +1 -1
  27. package/dist/cli/commands/dev.d.ts +30 -0
  28. package/dist/cli/commands/dev.d.ts.map +1 -1
  29. package/dist/cli/commands/dev.js +495 -129
  30. package/dist/cli/commands/dev.js.map +1 -1
  31. package/dist/cli/commands/init.d.ts +69 -1
  32. package/dist/cli/commands/init.d.ts.map +1 -1
  33. package/dist/cli/commands/init.js +788 -766
  34. package/dist/cli/commands/init.js.map +1 -1
  35. package/dist/cli/commands/scaffold.d.ts +24 -3
  36. package/dist/cli/commands/scaffold.d.ts.map +1 -1
  37. package/dist/cli/commands/scaffold.js +408 -189
  38. package/dist/cli/commands/scaffold.js.map +1 -1
  39. package/dist/cli/index.d.ts +5 -1
  40. package/dist/cli/index.d.ts.map +1 -1
  41. package/dist/cli/index.js +335 -58
  42. package/dist/cli/index.js.map +1 -1
  43. package/dist/core/config.d.ts +13 -3
  44. package/dist/core/config.d.ts.map +1 -1
  45. package/dist/core/config.js +151 -8
  46. package/dist/core/config.js.map +1 -1
  47. package/dist/core/mock/connector-mock-server.d.ts +101 -0
  48. package/dist/core/mock/connector-mock-server.d.ts.map +1 -0
  49. package/dist/core/mock/connector-mock-server.js +480 -0
  50. package/dist/core/mock/connector-mock-server.js.map +1 -0
  51. package/dist/core/mock/zod-mock-generator.d.ts +14 -0
  52. package/dist/core/mock/zod-mock-generator.d.ts.map +1 -0
  53. package/dist/core/mock/zod-mock-generator.js +163 -0
  54. package/dist/core/mock/zod-mock-generator.js.map +1 -0
  55. package/dist/core/operations/auth-operations.d.ts +61 -0
  56. package/dist/core/operations/auth-operations.d.ts.map +1 -0
  57. package/dist/core/operations/auth-operations.js +272 -0
  58. package/dist/core/operations/auth-operations.js.map +1 -0
  59. package/dist/core/operations/create-model.d.ts +15 -0
  60. package/dist/core/operations/create-model.d.ts.map +1 -0
  61. package/dist/core/operations/create-model.js +185 -0
  62. package/dist/core/operations/create-model.js.map +1 -0
  63. package/dist/core/operations/file-session.d.ts +56 -0
  64. package/dist/core/operations/file-session.d.ts.map +1 -0
  65. package/dist/core/operations/file-session.js +203 -0
  66. package/dist/core/operations/file-session.js.map +1 -0
  67. package/dist/core/operations/provision-operations.d.ts +52 -0
  68. package/dist/core/operations/provision-operations.d.ts.map +1 -0
  69. package/dist/core/operations/provision-operations.js +211 -0
  70. package/dist/core/operations/provision-operations.js.map +1 -0
  71. package/dist/core/operations/runtime.d.ts +37 -0
  72. package/dist/core/operations/runtime.d.ts.map +1 -0
  73. package/dist/core/operations/runtime.js +248 -0
  74. package/dist/core/operations/runtime.js.map +1 -0
  75. package/dist/core/operations/scaffold-apply.d.ts +21 -0
  76. package/dist/core/operations/scaffold-apply.d.ts.map +1 -0
  77. package/dist/core/operations/scaffold-apply.js +57 -0
  78. package/dist/core/operations/scaffold-apply.js.map +1 -0
  79. package/dist/core/operations/scaffold-machine.d.ts +16 -0
  80. package/dist/core/operations/scaffold-machine.d.ts.map +1 -0
  81. package/dist/core/operations/scaffold-machine.js +51 -0
  82. package/dist/core/operations/scaffold-machine.js.map +1 -0
  83. package/dist/core/operations/scaffold-plan.d.ts +43 -0
  84. package/dist/core/operations/scaffold-plan.d.ts.map +1 -0
  85. package/dist/core/operations/scaffold-plan.js +187 -0
  86. package/dist/core/operations/scaffold-plan.js.map +1 -0
  87. package/dist/core/project/agent-instructions.d.ts +29 -0
  88. package/dist/core/project/agent-instructions.d.ts.map +1 -0
  89. package/dist/core/project/agent-instructions.js +160 -0
  90. package/dist/core/project/agent-instructions.js.map +1 -0
  91. package/dist/core/project/artifacts.d.ts +58 -0
  92. package/dist/core/project/artifacts.d.ts.map +1 -0
  93. package/dist/core/project/artifacts.js +179 -0
  94. package/dist/core/project/artifacts.js.map +1 -0
  95. package/dist/core/project/boundaries.d.ts +50 -0
  96. package/dist/core/project/boundaries.d.ts.map +1 -0
  97. package/dist/core/project/boundaries.js +117 -0
  98. package/dist/core/project/boundaries.js.map +1 -0
  99. package/dist/core/project/capabilities.d.ts +58 -0
  100. package/dist/core/project/capabilities.d.ts.map +1 -0
  101. package/dist/core/project/capabilities.js +135 -0
  102. package/dist/core/project/capabilities.js.map +1 -0
  103. package/dist/core/project/drift.d.ts +29 -0
  104. package/dist/core/project/drift.d.ts.map +1 -0
  105. package/dist/core/project/drift.js +188 -0
  106. package/dist/core/project/drift.js.map +1 -0
  107. package/dist/core/project/infra.d.ts +49 -0
  108. package/dist/core/project/infra.d.ts.map +1 -0
  109. package/dist/core/project/infra.js +167 -0
  110. package/dist/core/project/infra.js.map +1 -0
  111. package/dist/core/project/manifest.d.ts +92 -0
  112. package/dist/core/project/manifest.d.ts.map +1 -0
  113. package/dist/core/project/manifest.js +321 -0
  114. package/dist/core/project/manifest.js.map +1 -0
  115. package/dist/core/project/state.d.ts +15 -0
  116. package/dist/core/project/state.d.ts.map +1 -0
  117. package/dist/core/project/state.js +106 -0
  118. package/dist/core/project/state.js.map +1 -0
  119. package/dist/core/project/validation.d.ts +20 -0
  120. package/dist/core/project/validation.d.ts.map +1 -0
  121. package/dist/core/project/validation.js +274 -0
  122. package/dist/core/project/validation.js.map +1 -0
  123. package/dist/core/project/workflows.d.ts +43 -0
  124. package/dist/core/project/workflows.d.ts.map +1 -0
  125. package/dist/core/project/workflows.js +299 -0
  126. package/dist/core/project/workflows.js.map +1 -0
  127. package/dist/core/scaffold/auth-generator.d.ts +63 -0
  128. package/dist/core/scaffold/auth-generator.d.ts.map +1 -0
  129. package/dist/core/scaffold/auth-generator.js +1774 -0
  130. package/dist/core/scaffold/auth-generator.js.map +1 -0
  131. package/dist/core/scaffold/connector-functions-generator.d.ts +41 -0
  132. package/dist/core/scaffold/connector-functions-generator.d.ts.map +1 -0
  133. package/dist/core/scaffold/connector-functions-generator.js +1029 -0
  134. package/dist/core/scaffold/connector-functions-generator.js.map +1 -0
  135. package/dist/core/scaffold/functions-generator.d.ts +4 -3
  136. package/dist/core/scaffold/functions-generator.d.ts.map +1 -1
  137. package/dist/core/scaffold/functions-generator.js +405 -134
  138. package/dist/core/scaffold/functions-generator.js.map +1 -1
  139. package/dist/core/scaffold/model-parser.d.ts +20 -0
  140. package/dist/core/scaffold/model-parser.d.ts.map +1 -1
  141. package/dist/core/scaffold/model-parser.js +229 -78
  142. package/dist/core/scaffold/model-parser.js.map +1 -1
  143. package/dist/core/scaffold/native-schema-generator.d.ts +19 -0
  144. package/dist/core/scaffold/native-schema-generator.d.ts.map +1 -0
  145. package/dist/core/scaffold/native-schema-generator.js +753 -0
  146. package/dist/core/scaffold/native-schema-generator.js.map +1 -0
  147. package/dist/core/scaffold/nextjs-generator.d.ts +8 -0
  148. package/dist/core/scaffold/nextjs-generator.d.ts.map +1 -1
  149. package/dist/core/scaffold/nextjs-generator.js +152 -8
  150. package/dist/core/scaffold/nextjs-generator.js.map +1 -1
  151. package/dist/core/scaffold/ui-generator.d.ts +17 -4
  152. package/dist/core/scaffold/ui-generator.d.ts.map +1 -1
  153. package/dist/core/scaffold/ui-generator.js +174 -34
  154. package/dist/core/scaffold/ui-generator.js.map +1 -1
  155. package/dist/core/verify/index.d.ts +69 -0
  156. package/dist/core/verify/index.d.ts.map +1 -0
  157. package/dist/core/verify/index.js +412 -0
  158. package/dist/core/verify/index.js.map +1 -0
  159. package/dist/machine/contracts.d.ts +24 -0
  160. package/dist/machine/contracts.d.ts.map +1 -0
  161. package/dist/machine/contracts.js +3 -0
  162. package/dist/machine/contracts.js.map +1 -0
  163. package/dist/machine/errors.d.ts +14 -0
  164. package/dist/machine/errors.d.ts.map +1 -0
  165. package/dist/machine/errors.js +42 -0
  166. package/dist/machine/errors.js.map +1 -0
  167. package/dist/machine/index.d.ts +3 -0
  168. package/dist/machine/index.d.ts.map +1 -0
  169. package/dist/machine/index.js +566 -0
  170. package/dist/machine/index.js.map +1 -0
  171. package/dist/mcp/index.d.ts +25 -0
  172. package/dist/mcp/index.d.ts.map +1 -0
  173. package/dist/mcp/index.js +425 -0
  174. package/dist/mcp/index.js.map +1 -0
  175. package/dist/types/index.d.ts +105 -0
  176. package/dist/types/index.d.ts.map +1 -1
  177. package/dist/utils/package-manager.d.ts +7 -11
  178. package/dist/utils/package-manager.d.ts.map +1 -1
  179. package/dist/utils/package-manager.js +42 -17
  180. package/dist/utils/package-manager.js.map +1 -1
  181. package/dist/utils/python-uv.d.ts +21 -0
  182. package/dist/utils/python-uv.d.ts.map +1 -0
  183. package/dist/utils/python-uv.js +111 -0
  184. package/dist/utils/python-uv.js.map +1 -0
  185. package/dist/version.d.ts +2 -0
  186. package/dist/version.d.ts.map +1 -0
  187. package/dist/version.js +49 -0
  188. package/dist/version.js.map +1 -0
  189. package/package.json +15 -17
  190. package/src/__tests__/__snapshots__/functions-generator.test.ts.snap +716 -22
  191. package/src/__tests__/__snapshots__/nextjs-generator.test.ts.snap +19 -7
  192. package/src/__tests__/__snapshots__/ui-generator.test.ts.snap +20 -12
  193. package/src/__tests__/agent-instructions.test.ts +237 -0
  194. package/src/__tests__/agent-loop-phase34.test.ts +513 -0
  195. package/src/__tests__/auth.test.ts +770 -0
  196. package/src/__tests__/bff-swa-auth.test.ts +275 -0
  197. package/src/__tests__/config.test.ts +176 -3
  198. package/src/__tests__/connector-functions-generator.test.ts +288 -0
  199. package/src/__tests__/connector-mock-server.test.ts +459 -0
  200. package/src/__tests__/connector-model-bff.test.ts +162 -0
  201. package/src/__tests__/cosmos-worktree-isolation.test.ts +149 -0
  202. package/src/__tests__/dev-seeds.test.ts +124 -0
  203. package/src/__tests__/dev.test.ts +254 -0
  204. package/src/__tests__/file-session.test.ts +98 -0
  205. package/src/__tests__/fixtures.ts +101 -0
  206. package/src/__tests__/functions-generator.test.ts +137 -1
  207. package/src/__tests__/init.test.ts +366 -2
  208. package/src/__tests__/jest-globals.d.ts +8 -0
  209. package/src/__tests__/machine.test.ts +371 -0
  210. package/src/__tests__/mcp.test.ts +253 -0
  211. package/src/__tests__/model-parser.test.ts +142 -0
  212. package/src/__tests__/multi-auth.test.ts +160 -0
  213. package/src/__tests__/nextjs-generator.test.ts +8 -0
  214. package/src/__tests__/package-manager.test.ts +59 -4
  215. package/src/__tests__/plan-apply.test.ts +499 -0
  216. package/src/__tests__/python-uv.test.ts +48 -0
  217. package/src/__tests__/scaffold.test.ts +287 -24
  218. package/src/__tests__/tsconfig.json +15 -0
  219. package/src/__tests__/ui-generator.test.ts +104 -0
  220. package/src/__tests__/zod-mock-generator.test.ts +132 -0
  221. package/src/cli/commands/add-auth.ts +853 -0
  222. package/src/cli/commands/add-connector.ts +159 -0
  223. package/src/cli/commands/cosmos-worktree-isolation.ts +130 -0
  224. package/src/cli/commands/create-model.ts +21 -100
  225. package/src/cli/commands/dev-seeds.ts +278 -7
  226. package/src/cli/commands/dev.ts +607 -160
  227. package/src/cli/commands/init.ts +851 -786
  228. package/src/cli/commands/scaffold.ts +531 -236
  229. package/src/cli/index.ts +338 -60
  230. package/src/core/config.ts +145 -9
  231. package/src/core/mock/connector-mock-server.ts +555 -0
  232. package/src/core/mock/zod-mock-generator.ts +205 -0
  233. package/src/core/operations/auth-operations.ts +360 -0
  234. package/src/core/operations/create-model.ts +191 -0
  235. package/src/core/operations/file-session.ts +222 -0
  236. package/src/core/operations/provision-operations.ts +297 -0
  237. package/src/core/operations/runtime.ts +258 -0
  238. package/src/core/operations/scaffold-apply.ts +106 -0
  239. package/src/core/operations/scaffold-machine.ts +77 -0
  240. package/src/core/operations/scaffold-plan.ts +215 -0
  241. package/src/core/project/agent-instructions.ts +167 -0
  242. package/src/core/project/agent-templates/AGENTS.md +504 -0
  243. package/src/core/project/agent-templates/CLAUDE.md +31 -0
  244. package/src/core/project/agent-templates/azure-functions.instructions.md +22 -0
  245. package/src/core/project/agent-templates/bff-routes.instructions.md +18 -0
  246. package/src/core/project/agent-templates/copilot-instructions.md +27 -0
  247. package/src/core/project/agent-templates/shared-models.instructions.md +72 -0
  248. package/src/core/project/artifacts.ts +205 -0
  249. package/src/core/project/boundaries.ts +170 -0
  250. package/src/core/project/capabilities.ts +193 -0
  251. package/src/core/project/drift.ts +202 -0
  252. package/src/core/project/infra.ts +196 -0
  253. package/src/core/project/manifest.ts +402 -0
  254. package/src/core/project/state.ts +77 -0
  255. package/src/core/project/validation.ts +295 -0
  256. package/src/core/project/workflows.ts +295 -0
  257. package/src/core/scaffold/auth-generator.ts +1824 -0
  258. package/src/core/scaffold/connector-functions-generator.ts +1133 -0
  259. package/src/core/scaffold/functions-generator.ts +432 -134
  260. package/src/core/scaffold/model-parser.ts +244 -90
  261. package/src/core/scaffold/native-schema-generator.ts +904 -0
  262. package/src/core/scaffold/nextjs-generator.ts +174 -9
  263. package/src/core/scaffold/ui-generator.ts +191 -36
  264. package/src/core/verify/index.ts +468 -0
  265. package/src/machine/contracts.ts +33 -0
  266. package/src/machine/errors.ts +45 -0
  267. package/src/machine/index.ts +690 -0
  268. package/src/mcp/index.ts +423 -0
  269. package/src/types/index.ts +137 -0
  270. package/src/utils/package-manager.ts +41 -19
  271. package/src/utils/python-uv.ts +96 -0
  272. 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 { NextRequest, NextResponse } from 'next/server';
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
- interface CallFunctionConfig<TInput = any, TOutput = any> {
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?: any;
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 = any, TOutput = any>(
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: any) {
115
+ } catch (error) {
104
116
  console.error(\`[BFF] Error:\`, error);
105
117
  return NextResponse.json(
106
- { error: error.message || 'Internal server error' },
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: any) {
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: any = { ...formData };
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: any) {
263
- if (err.issues) {
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((error: any) => {
267
- const field = error.path[0];
268
- fieldErrors[field] = error.message;
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: any) {
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
+ });