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
@@ -0,0 +1,159 @@
1
+ /**
2
+ * SwallowKit Add-Connector コマンド
3
+ * swallowkit.config.js にコネクタ設定を追加する
4
+ */
5
+
6
+ import * as fs from "fs";
7
+ import { detectFromProject, getCommands } from "../../utils/package-manager";
8
+ import * as path from "path";
9
+ import { ensureSwallowKitProject } from "../../core/config";
10
+ import { ApiConnectorConfig, ConnectorDefinition } from "../../types";
11
+ import { syncProjectManifest } from "../../core/project/manifest";
12
+
13
+ interface AddConnectorOptions {
14
+ name: string;
15
+ type: "rdb" | "api";
16
+ provider?: "mysql" | "postgres" | "sqlserver";
17
+ }
18
+
19
+ /**
20
+ * add-connector コマンド
21
+ */
22
+ export async function addConnectorCommand(options: AddConnectorOptions) {
23
+ ensureSwallowKitProject("add-connector");
24
+
25
+ console.log(`🔌 SwallowKit Add-Connector: Adding '${options.name}' connector...\n`);
26
+
27
+ const configPath = findConfigFile();
28
+ if (!configPath) {
29
+ console.error("❌ swallowkit.config.js not found. Run 'swallowkit init' first.");
30
+ process.exit(1);
31
+ }
32
+
33
+ // Build connector definition
34
+ const connectorDef = buildConnectorDefinition(options);
35
+
36
+ // Update config file
37
+ updateConfigWithConnector(configPath, options.name, connectorDef);
38
+ await syncProjectManifest();
39
+
40
+ console.log(`\n✅ Connector '${options.name}' added successfully!`);
41
+ console.log("\n📝 Next steps:");
42
+ console.log(` 1. Review the connector settings in ${configPath}`);
43
+ console.log(` 2. Set the required environment variables in functions/local.settings.json`);
44
+ console.log(` 3. Create models with: ${getCommands(detectFromProject()).exec} swallowkit create-model <name> --connector=${options.name}`);
45
+ }
46
+
47
+ function findConfigFile(): string | null {
48
+ const candidates = ["swallowkit.config.js", "swallowkit.config.json", ".swallowkitrc.json"];
49
+ for (const candidate of candidates) {
50
+ const fullPath = path.resolve(process.cwd(), candidate);
51
+ if (fs.existsSync(fullPath)) {
52
+ return fullPath;
53
+ }
54
+ }
55
+ return null;
56
+ }
57
+
58
+ function buildConnectorDefinition(options: AddConnectorOptions): ConnectorDefinition {
59
+ const name = options.name.toUpperCase().replace(/[^A-Z0-9]/g, "_");
60
+
61
+ if (options.type === "rdb") {
62
+ return {
63
+ type: "rdb",
64
+ provider: options.provider || "mysql",
65
+ connectionEnvVar: `${name}_CONNECTION_STRING`,
66
+ };
67
+ }
68
+
69
+ return {
70
+ type: "api",
71
+ baseUrlEnvVar: `${name}_API_BASE_URL`,
72
+ auth: {
73
+ type: "apiKey",
74
+ envVar: `${name}_API_KEY`,
75
+ placement: "query",
76
+ paramName: "apiKey",
77
+ },
78
+ };
79
+ }
80
+
81
+ /**
82
+ * swallowkit.config.js にコネクタ設定を追加
83
+ */
84
+ export function updateConfigWithConnector(
85
+ configPath: string,
86
+ connectorName: string,
87
+ connectorDef: ConnectorDefinition
88
+ ): void {
89
+ const content = fs.readFileSync(configPath, "utf-8");
90
+
91
+ if (configPath.endsWith(".json")) {
92
+ // JSON config
93
+ const config = JSON.parse(content);
94
+ if (!config.connectors) {
95
+ config.connectors = {};
96
+ }
97
+ config.connectors[connectorName] = connectorDef;
98
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
99
+ console.log(`✅ Updated: ${configPath}`);
100
+ return;
101
+ }
102
+
103
+ // JS config — append connectors section
104
+ if (content.includes("connectors:") || content.includes("connectors :")) {
105
+ console.log(`⚠️ 'connectors' section already exists in ${configPath}. Please add the connector manually:`);
106
+ console.log(formatConnectorSnippet(connectorName, connectorDef));
107
+ return;
108
+ }
109
+
110
+ // Find the last property before the closing of module.exports
111
+ const closingBraceIdx = content.lastIndexOf("}");
112
+ if (closingBraceIdx === -1) {
113
+ console.error("❌ Could not parse config file structure. Please add the connector manually:");
114
+ console.log(formatConnectorSnippet(connectorName, connectorDef));
115
+ return;
116
+ }
117
+
118
+ // Check if we need a comma before inserting
119
+ const beforeClosing = content.substring(0, closingBraceIdx).trimEnd();
120
+ const needsComma = !beforeClosing.endsWith(",") && !beforeClosing.endsWith("{");
121
+
122
+ const connectorBlock = generateConnectorJSBlock(connectorName, connectorDef);
123
+ const insertion = `${needsComma ? "," : ""}\n // コネクタ定義\n connectors: {\n${connectorBlock}\n },\n`;
124
+
125
+ const newContent = content.substring(0, closingBraceIdx) + insertion + content.substring(closingBraceIdx);
126
+ fs.writeFileSync(configPath, newContent, "utf-8");
127
+ console.log(`✅ Updated: ${configPath}`);
128
+ }
129
+
130
+ function generateConnectorJSBlock(name: string, def: ConnectorDefinition): string {
131
+ if (def.type === "rdb") {
132
+ return ` ${name}: {
133
+ type: 'rdb',
134
+ provider: '${def.provider}',
135
+ connectionEnvVar: '${def.connectionEnvVar}',
136
+ },`;
137
+ }
138
+
139
+ const apiDef: ApiConnectorConfig = def;
140
+ let authBlock = "";
141
+ if (apiDef.auth) {
142
+ authBlock = `
143
+ auth: {
144
+ type: '${apiDef.auth.type}',
145
+ envVar: '${apiDef.auth.envVar}',
146
+ placement: '${apiDef.auth.placement || "query"}',
147
+ paramName: '${apiDef.auth.paramName || "apiKey"}',
148
+ },`;
149
+ }
150
+
151
+ return ` ${name}: {
152
+ type: 'api',
153
+ baseUrlEnvVar: '${apiDef.baseUrlEnvVar}',${authBlock}
154
+ },`;
155
+ }
156
+
157
+ function formatConnectorSnippet(name: string, def: ConnectorDefinition): string {
158
+ return `\n ${name}: ${JSON.stringify(def, null, 4)}\n`;
159
+ }
@@ -0,0 +1,130 @@
1
+ import { execFileSync } from "child_process";
2
+ import { createHash } from "crypto";
3
+ import * as fs from "fs";
4
+ import * as path from "path";
5
+
6
+ const WORKTREE_HASH_LENGTH = 8;
7
+
8
+ export interface GitWorktreeInfo {
9
+ worktreeRoot: string;
10
+ gitDir: string;
11
+ gitCommonDir: string;
12
+ isLinkedWorktree: boolean;
13
+ }
14
+
15
+ export interface CosmosDatabaseNameResolution {
16
+ databaseName: string;
17
+ worktreeIsolationEnabled: boolean;
18
+ worktreeRoot?: string;
19
+ }
20
+
21
+ export type GitCommandRunner = (args: string[], cwd: string) => string;
22
+
23
+ const runGitCommand: GitCommandRunner = (args, cwd) =>
24
+ execFileSync("git", args, {
25
+ cwd,
26
+ encoding: "utf-8",
27
+ stdio: ["ignore", "pipe", "ignore"],
28
+ windowsHide: true,
29
+ });
30
+
31
+ /**
32
+ * Resolve Git's worktree metadata without relying on whether .git is a file or
33
+ * directory. A linked worktree has a per-worktree Git directory that differs
34
+ * from the repository's common Git directory.
35
+ */
36
+ export function resolveGitWorktreeInfo(
37
+ cwd: string = process.cwd(),
38
+ runGit: GitCommandRunner = runGitCommand
39
+ ): GitWorktreeInfo | null {
40
+ try {
41
+ const output = runGit(
42
+ [
43
+ "rev-parse",
44
+ "--show-toplevel",
45
+ "--absolute-git-dir",
46
+ "--git-common-dir",
47
+ ],
48
+ cwd
49
+ );
50
+ const lines = output.split(/\r?\n/).map((line) => line.trim());
51
+ const [worktreeRootOutput, gitDirOutput, gitCommonDirOutput] = lines;
52
+
53
+ if (!worktreeRootOutput || !gitDirOutput || !gitCommonDirOutput) {
54
+ return null;
55
+ }
56
+
57
+ const worktreeRoot = canonicalizePath(worktreeRootOutput, cwd);
58
+ const gitDir = canonicalizePath(gitDirOutput, cwd);
59
+ const gitCommonDir = canonicalizePath(gitCommonDirOutput, cwd);
60
+
61
+ return {
62
+ worktreeRoot,
63
+ gitDir,
64
+ gitCommonDir,
65
+ isLinkedWorktree: gitDir !== gitCommonDir,
66
+ };
67
+ } catch {
68
+ return null;
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Produce a stable, database-safe identifier for a canonical worktree path.
74
+ */
75
+ export function createWorktreePathHash(worktreeRoot: string): string {
76
+ return createHash("sha256")
77
+ .update(canonicalizePath(worktreeRoot), "utf-8")
78
+ .digest("hex")
79
+ .slice(0, WORKTREE_HASH_LENGTH);
80
+ }
81
+
82
+ export function applyCosmosDatabaseWorktreeIsolation(
83
+ baseDatabaseName: string,
84
+ worktreeInfo: GitWorktreeInfo | null
85
+ ): CosmosDatabaseNameResolution {
86
+ if (!worktreeInfo?.isLinkedWorktree) {
87
+ return {
88
+ databaseName: baseDatabaseName,
89
+ worktreeIsolationEnabled: false,
90
+ };
91
+ }
92
+
93
+ const suffix = createWorktreePathHash(worktreeInfo.worktreeRoot);
94
+ return {
95
+ databaseName: `${baseDatabaseName}_${suffix}`,
96
+ worktreeIsolationEnabled: true,
97
+ worktreeRoot: worktreeInfo.worktreeRoot,
98
+ };
99
+ }
100
+
101
+ export function resolveCosmosDatabaseNameForWorktree(
102
+ baseDatabaseName: string,
103
+ cwd: string = process.cwd(),
104
+ runGit: GitCommandRunner = runGitCommand
105
+ ): CosmosDatabaseNameResolution {
106
+ return applyCosmosDatabaseWorktreeIsolation(
107
+ baseDatabaseName,
108
+ resolveGitWorktreeInfo(cwd, runGit)
109
+ );
110
+ }
111
+
112
+ function canonicalizePath(
113
+ value: string,
114
+ basePath: string = process.cwd()
115
+ ): string {
116
+ const absolutePath = path.resolve(basePath, value);
117
+ let canonicalPath = absolutePath;
118
+
119
+ try {
120
+ canonicalPath = fs.realpathSync.native(absolutePath);
121
+ } catch {
122
+ // Git metadata can disappear between discovery and normalization. The
123
+ // normalized absolute path remains a stable fallback for this invocation.
124
+ }
125
+
126
+ const normalizedPath = path.normalize(canonicalPath).normalize("NFC");
127
+ return process.platform === "win32"
128
+ ? normalizedPath.toLowerCase()
129
+ : normalizedPath;
130
+ }
@@ -1,41 +1,11 @@
1
- /**
2
- * SwallowKit Create-Model コマンド
3
- * Zod モデルの雛形を生成
4
- */
5
-
6
- import * as fs from "fs";
7
- import * as path from "path";
8
1
  import * as readline from "readline";
9
- import { toPascalCase } from "../../core/scaffold/model-parser";
10
- import { ensureSwallowKitProject } from "../../core/config";
2
+ import { createModelOperation } from "../../core/operations/create-model";
11
3
  import { detectFromProject, getCommands } from "../../utils/package-manager";
12
4
 
13
5
  interface CreateModelOptions {
14
6
  names: string[]; // モデル名のリスト(例: ["todo", "user", "post"])
15
7
  modelsDir?: string; // モデルディレクトリ(デフォルト: "shared/models")
16
- }
17
-
18
- /**
19
- * モデルテンプレートを生成
20
- */
21
- function generateModelTemplate(modelName: string): string {
22
- const pascalName = toPascalCase(modelName);
23
-
24
- return `import { z } from 'zod/v4';
25
-
26
- // ${pascalName} model (Zod official pattern: same name for value and type)
27
- export const ${pascalName} = z.object({
28
- id: z.string(),
29
- name: z.string().min(1),
30
- createdAt: z.string().optional(),
31
- updatedAt: z.string().optional(),
32
- });
33
-
34
- export type ${pascalName} = z.infer<typeof ${pascalName}>;
35
-
36
- // Display name for UI
37
- export const displayName = '${pascalName}';
38
- `;
8
+ connector?: string; // コネクタ名(例: "mysql", "backlog")
39
9
  }
40
10
 
41
11
  /**
@@ -59,83 +29,34 @@ function askConfirmation(question: string): Promise<boolean> {
59
29
  * create-model コマンド
60
30
  */
61
31
  export async function createModelCommand(options: CreateModelOptions) {
62
- // SwallowKit プロジェクトディレクトリかどうかを検証
63
- ensureSwallowKitProject("create-model");
64
-
65
32
  console.log("🏗️ SwallowKit Create-Model: Generating model templates...\n");
66
33
 
67
- const modelsDir = options.modelsDir || "shared/models";
68
-
69
- // shared/models ディレクトリが存在しなければ作成
70
- if (!fs.existsSync(modelsDir)) {
71
- console.log(`📁 Creating directory: ${modelsDir}`);
72
- fs.mkdirSync(modelsDir, { recursive: true });
73
- }
74
-
75
- const created: string[] = [];
76
- const skipped: string[] = [];
77
-
78
- for (const name of options.names) {
79
- const kebabName = name.toLowerCase().replace(/[^a-z0-9]+/g, '-');
80
- const filePath = path.join(modelsDir, `${kebabName}.ts`);
81
- const pascalName = toPascalCase(name);
82
-
83
- // 既存ファイルチェック
84
- if (fs.existsSync(filePath)) {
85
- const shouldOverwrite = await askConfirmation(
86
- `⚠️ File ${filePath} already exists. Overwrite? (y/N): `
87
- );
88
-
89
- if (!shouldOverwrite) {
90
- console.log(`⏭️ Skipped: ${kebabName}.ts`);
91
- skipped.push(kebabName);
92
- continue;
93
- }
94
- }
95
-
96
- // モデルファイルを生成
97
- const content = generateModelTemplate(name);
98
- fs.writeFileSync(filePath, content);
99
- console.log(`✅ Created: ${filePath}`);
100
- created.push(kebabName);
101
-
102
- // shared/index.ts に re-export を追加
103
- updateSharedIndex(kebabName, pascalName);
104
- }
34
+ const result = await createModelOperation({
35
+ names: options.names,
36
+ modelsDir: options.modelsDir,
37
+ connector: options.connector,
38
+ overwriteMode: "prompt",
39
+ confirmOverwrite: async (filePath) => askConfirmation(`⚠️ File ${filePath} already exists. Overwrite? (y/N): `),
40
+ });
105
41
 
106
42
  // サマリー表示
107
43
  console.log("\n📋 Summary:");
108
- if (created.length > 0) {
109
- console.log(` ✅ Created ${created.length} model(s): ${created.join(', ')}.ts`);
44
+ if (result.connectorType && options.connector) {
45
+ console.log(` 🔌 Connector: ${options.connector} (${result.connectorType})`);
46
+ }
47
+ if (result.createdFiles.length > 0) {
48
+ console.log(` ✅ Created ${result.createdFiles.length} model(s): ${result.createdFiles.join(", ")}`);
49
+ }
50
+ if (result.skippedFiles.length > 0) {
51
+ console.log(` ⏭️ Skipped ${result.skippedFiles.length} model(s): ${result.skippedFiles.join(", ")}`);
110
52
  }
111
- if (skipped.length > 0) {
112
- console.log(` ⏭️ Skipped ${skipped.length} model(s): ${skipped.join(', ')}.ts`);
53
+ if (result.updatedIndex) {
54
+ console.log(" 📦 Updated shared/index.ts");
113
55
  }
114
56
 
115
- if (created.length > 0) {
57
+ if (result.createdFiles.length > 0) {
116
58
  console.log("\n📝 Next steps:");
117
59
  console.log(" 1. Customize the generated model fields in shared/models/");
118
- console.log(` 2. Run '${getCommands(detectFromProject()).dlx} swallowkit scaffold <model>' to generate CRUD code`);
119
- }
120
- }
121
-
122
- /**
123
- * shared/index.ts に re-export エントリを追加
124
- */
125
- function updateSharedIndex(kebabName: string, pascalName: string): void {
126
- const indexPath = path.join("shared", "index.ts");
127
-
128
- if (!fs.existsSync(indexPath)) {
129
- return;
130
- }
131
-
132
- const content = fs.readFileSync(indexPath, "utf-8");
133
- const exportLine = `export { ${pascalName} } from './models/${kebabName}';`;
134
-
135
- // 既に存在する場合はスキップ
136
- if (content.includes(exportLine)) {
137
- return;
60
+ console.log(` 2. Run '${getCommands(detectFromProject()).exec} swallowkit scaffold <model>' to generate CRUD code`);
138
61
  }
139
-
140
- fs.appendFileSync(indexPath, exportLine + "\n");
141
62
  }