@gtkx/cli 0.21.0 → 1.0.0-rc.2

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 (358) hide show
  1. package/README.md +173 -0
  2. package/bin/gtkx-dev-runner.js +9 -0
  3. package/dist/builder.d.ts +5 -52
  4. package/dist/builder.d.ts.map +1 -1
  5. package/dist/builder.js +24 -57
  6. package/dist/builder.js.map +1 -1
  7. package/dist/cli.d.ts +1 -2
  8. package/dist/cli.d.ts.map +1 -1
  9. package/dist/cli.js +24 -122
  10. package/dist/cli.js.map +1 -1
  11. package/dist/codegen/freshness.d.ts +11 -0
  12. package/dist/codegen/freshness.d.ts.map +1 -0
  13. package/dist/codegen/freshness.js +45 -0
  14. package/dist/codegen/freshness.js.map +1 -0
  15. package/dist/codegen/report.d.ts +4 -0
  16. package/dist/codegen/report.d.ts.map +1 -0
  17. package/dist/codegen/report.js +18 -0
  18. package/dist/codegen/report.js.map +1 -0
  19. package/dist/codegen/run-codegen.d.ts +35 -0
  20. package/dist/codegen/run-codegen.d.ts.map +1 -0
  21. package/dist/codegen/run-codegen.js +162 -0
  22. package/dist/codegen/run-codegen.js.map +1 -0
  23. package/dist/codegen/store-resolver.d.ts +24 -0
  24. package/dist/codegen/store-resolver.d.ts.map +1 -0
  25. package/dist/codegen/store-resolver.js +72 -0
  26. package/dist/codegen/store-resolver.js.map +1 -0
  27. package/dist/commands/build.d.ts +10 -0
  28. package/dist/commands/build.d.ts.map +1 -0
  29. package/dist/commands/build.js +34 -0
  30. package/dist/commands/build.js.map +1 -0
  31. package/dist/commands/codegen.d.ts +10 -0
  32. package/dist/commands/codegen.d.ts.map +1 -0
  33. package/dist/commands/codegen.js +42 -0
  34. package/dist/commands/codegen.js.map +1 -0
  35. package/dist/commands/dev.d.ts +6 -0
  36. package/dist/commands/dev.d.ts.map +1 -0
  37. package/dist/commands/dev.js +22 -0
  38. package/dist/commands/dev.js.map +1 -0
  39. package/dist/commands/docs.d.ts +20 -0
  40. package/dist/commands/docs.d.ts.map +1 -0
  41. package/dist/commands/docs.js +74 -0
  42. package/dist/commands/docs.js.map +1 -0
  43. package/dist/dev/icon-dir.d.ts +3 -0
  44. package/dist/dev/icon-dir.d.ts.map +1 -0
  45. package/dist/dev/icon-dir.js +16 -0
  46. package/dist/dev/icon-dir.js.map +1 -0
  47. package/dist/dev/refresh-tracker.d.ts +7 -0
  48. package/dist/dev/refresh-tracker.d.ts.map +1 -0
  49. package/dist/dev/refresh-tracker.js +19 -0
  50. package/dist/dev/refresh-tracker.js.map +1 -0
  51. package/dist/dev/runner-deps.d.ts +4 -0
  52. package/dist/dev/runner-deps.d.ts.map +1 -0
  53. package/dist/dev/runner-deps.js +55 -0
  54. package/dist/dev/runner-deps.js.map +1 -0
  55. package/dist/dev/runner-main.d.ts +3 -0
  56. package/dist/dev/runner-main.d.ts.map +1 -0
  57. package/dist/dev/runner-main.js +29 -0
  58. package/dist/dev/runner-main.js.map +1 -0
  59. package/dist/dev/runner.d.ts +24 -0
  60. package/dist/dev/runner.d.ts.map +1 -0
  61. package/dist/dev/runner.js +119 -0
  62. package/dist/dev/runner.js.map +1 -0
  63. package/dist/dev/schema-dir.d.ts +3 -0
  64. package/dist/dev/schema-dir.d.ts.map +1 -0
  65. package/dist/dev/schema-dir.js +12 -0
  66. package/dist/dev/schema-dir.js.map +1 -0
  67. package/dist/dev/supervisor.d.ts +18 -0
  68. package/dist/dev/supervisor.d.ts.map +1 -0
  69. package/dist/dev/supervisor.js +182 -0
  70. package/dist/dev/supervisor.js.map +1 -0
  71. package/dist/dev/vite-dev-server.d.ts +21 -0
  72. package/dist/dev/vite-dev-server.d.ts.map +1 -0
  73. package/dist/dev/vite-dev-server.js +13 -0
  74. package/dist/dev/vite-dev-server.js.map +1 -0
  75. package/dist/internal/banner.d.ts +4 -0
  76. package/dist/internal/banner.d.ts.map +1 -0
  77. package/dist/internal/banner.js +9 -0
  78. package/dist/internal/banner.js.map +1 -0
  79. package/dist/internal/data-dir.d.ts +4 -0
  80. package/dist/internal/data-dir.d.ts.map +1 -0
  81. package/dist/internal/data-dir.js +52 -0
  82. package/dist/internal/data-dir.js.map +1 -0
  83. package/dist/internal/entry-arg.d.ts +20 -0
  84. package/dist/internal/entry-arg.d.ts.map +1 -0
  85. package/dist/internal/entry-arg.js +36 -0
  86. package/dist/internal/entry-arg.js.map +1 -0
  87. package/dist/internal/errors.d.ts +5 -0
  88. package/dist/internal/errors.d.ts.map +1 -0
  89. package/dist/internal/errors.js +29 -0
  90. package/dist/internal/errors.js.map +1 -0
  91. package/dist/internal/list-files.d.ts +7 -0
  92. package/dist/internal/list-files.d.ts.map +1 -0
  93. package/dist/internal/list-files.js +15 -0
  94. package/dist/internal/list-files.js.map +1 -0
  95. package/dist/internal/resolve-cli-tool.d.ts +3 -0
  96. package/dist/internal/resolve-cli-tool.d.ts.map +1 -0
  97. package/dist/internal/resolve-cli-tool.js +27 -0
  98. package/dist/internal/resolve-cli-tool.js.map +1 -0
  99. package/dist/internal/staging-dir.d.ts +4 -0
  100. package/dist/internal/staging-dir.d.ts.map +1 -0
  101. package/dist/internal/staging-dir.js +17 -0
  102. package/dist/internal/staging-dir.js.map +1 -0
  103. package/dist/internal/xdg-data-dirs.d.ts +3 -0
  104. package/dist/internal/xdg-data-dirs.d.ts.map +1 -0
  105. package/dist/internal/xdg-data-dirs.js +10 -0
  106. package/dist/internal/xdg-data-dirs.js.map +1 -0
  107. package/dist/mcp/client.d.ts +28 -0
  108. package/dist/mcp/client.d.ts.map +1 -0
  109. package/dist/mcp/client.js +182 -0
  110. package/dist/mcp/client.js.map +1 -0
  111. package/dist/mcp/handlers.d.ts +9 -0
  112. package/dist/mcp/handlers.d.ts.map +1 -0
  113. package/dist/mcp/handlers.js +147 -0
  114. package/dist/mcp/handlers.js.map +1 -0
  115. package/dist/mcp/index.d.ts +4 -0
  116. package/dist/mcp/index.d.ts.map +1 -0
  117. package/dist/mcp/index.js +34 -0
  118. package/dist/mcp/index.js.map +1 -0
  119. package/dist/mcp/serialize-widget.d.ts +10 -0
  120. package/dist/mcp/serialize-widget.d.ts.map +1 -0
  121. package/dist/mcp/serialize-widget.js +23 -0
  122. package/dist/mcp/serialize-widget.js.map +1 -0
  123. package/dist/mcp/testing-loader.d.ts +5 -0
  124. package/dist/mcp/testing-loader.d.ts.map +1 -0
  125. package/dist/mcp/testing-loader.js +47 -0
  126. package/dist/mcp/testing-loader.js.map +1 -0
  127. package/dist/mcp/widget-registry.d.ts +14 -0
  128. package/dist/mcp/widget-registry.d.ts.map +1 -0
  129. package/dist/mcp/widget-registry.js +39 -0
  130. package/dist/mcp/widget-registry.js.map +1 -0
  131. package/dist/refresh-globals.d.ts +2 -0
  132. package/dist/refresh-globals.d.ts.map +1 -0
  133. package/dist/refresh-globals.js +8 -0
  134. package/dist/refresh-globals.js.map +1 -0
  135. package/dist/refresh-runtime.d.ts +10 -26
  136. package/dist/refresh-runtime.d.ts.map +1 -1
  137. package/dist/refresh-runtime.js +26 -48
  138. package/dist/refresh-runtime.js.map +1 -1
  139. package/dist/settings/compile.d.ts +3 -0
  140. package/dist/settings/compile.d.ts.map +1 -0
  141. package/dist/settings/compile.js +21 -0
  142. package/dist/settings/compile.js.map +1 -0
  143. package/dist/settings/parser.d.ts +24 -0
  144. package/dist/settings/parser.d.ts.map +1 -0
  145. package/dist/settings/parser.js +121 -0
  146. package/dist/settings/parser.js.map +1 -0
  147. package/dist/settings/render.d.ts +5 -0
  148. package/dist/settings/render.d.ts.map +1 -0
  149. package/dist/settings/render.js +122 -0
  150. package/dist/settings/render.js.map +1 -0
  151. package/dist/settings/schema.d.ts +13 -0
  152. package/dist/settings/schema.d.ts.map +1 -0
  153. package/dist/settings/schema.js +121 -0
  154. package/dist/settings/schema.js.map +1 -0
  155. package/dist/vite-plugins/asset-extensions.d.ts +5 -0
  156. package/dist/vite-plugins/asset-extensions.d.ts.map +1 -0
  157. package/dist/vite-plugins/asset-extensions.js +28 -0
  158. package/dist/vite-plugins/asset-extensions.js.map +1 -0
  159. package/dist/vite-plugins/built-url.d.ts +4 -0
  160. package/dist/vite-plugins/built-url.d.ts.map +1 -0
  161. package/dist/vite-plugins/built-url.js +36 -0
  162. package/dist/vite-plugins/built-url.js.map +1 -0
  163. package/dist/vite-plugins/css.d.ts +4 -0
  164. package/dist/vite-plugins/css.d.ts.map +1 -0
  165. package/dist/vite-plugins/css.js +38 -0
  166. package/dist/vite-plugins/css.js.map +1 -0
  167. package/dist/vite-plugins/fast-refresh/refresh-filter.d.ts +8 -0
  168. package/dist/vite-plugins/fast-refresh/refresh-filter.d.ts.map +1 -0
  169. package/dist/vite-plugins/fast-refresh/refresh-filter.js +19 -0
  170. package/dist/vite-plugins/fast-refresh/refresh-filter.js.map +1 -0
  171. package/dist/vite-plugins/fast-refresh/swc-refresh.d.ts +6 -0
  172. package/dist/vite-plugins/fast-refresh/swc-refresh.d.ts.map +1 -0
  173. package/dist/vite-plugins/fast-refresh/swc-refresh.js +70 -0
  174. package/dist/vite-plugins/fast-refresh/swc-refresh.js.map +1 -0
  175. package/dist/vite-plugins/icons.d.ts +4 -0
  176. package/dist/vite-plugins/icons.d.ts.map +1 -0
  177. package/dist/vite-plugins/icons.js +51 -0
  178. package/dist/vite-plugins/icons.js.map +1 -0
  179. package/dist/vite-plugins/index.d.ts +4 -0
  180. package/dist/vite-plugins/index.d.ts.map +1 -0
  181. package/dist/vite-plugins/index.js +22 -0
  182. package/dist/vite-plugins/index.js.map +1 -0
  183. package/dist/vite-plugins/native.d.ts +4 -0
  184. package/dist/vite-plugins/native.d.ts.map +1 -0
  185. package/dist/vite-plugins/native.js +62 -0
  186. package/dist/vite-plugins/native.js.map +1 -0
  187. package/dist/vite-plugins/react-compiler.d.ts +5 -0
  188. package/dist/vite-plugins/react-compiler.d.ts.map +1 -0
  189. package/dist/vite-plugins/react-compiler.js +62 -0
  190. package/dist/vite-plugins/react-compiler.js.map +1 -0
  191. package/dist/vite-plugins/react-dom-prebundle.d.ts +4 -0
  192. package/dist/vite-plugins/react-dom-prebundle.d.ts.map +1 -0
  193. package/dist/vite-plugins/react-dom-prebundle.js +12 -0
  194. package/dist/vite-plugins/react-dom-prebundle.js.map +1 -0
  195. package/dist/vite-plugins/resource-init-module.d.ts +6 -0
  196. package/dist/vite-plugins/resource-init-module.d.ts.map +1 -0
  197. package/dist/vite-plugins/resource-init-module.js +51 -0
  198. package/dist/vite-plugins/resource-init-module.js.map +1 -0
  199. package/dist/vite-plugins/resource-shared.d.ts +8 -0
  200. package/dist/vite-plugins/resource-shared.d.ts.map +1 -0
  201. package/dist/vite-plugins/resource-shared.js +28 -0
  202. package/dist/vite-plugins/resource-shared.js.map +1 -0
  203. package/dist/vite-plugins/resources.d.ts +5 -0
  204. package/dist/vite-plugins/resources.d.ts.map +1 -0
  205. package/dist/vite-plugins/resources.js +260 -0
  206. package/dist/vite-plugins/resources.js.map +1 -0
  207. package/dist/vite-plugins/settings-worker-env.d.ts +4 -0
  208. package/dist/vite-plugins/settings-worker-env.d.ts.map +1 -0
  209. package/dist/vite-plugins/settings-worker-env.js +23 -0
  210. package/dist/vite-plugins/settings-worker-env.js.map +1 -0
  211. package/dist/vite-plugins/settings.d.ts +4 -0
  212. package/dist/vite-plugins/settings.d.ts.map +1 -0
  213. package/dist/vite-plugins/settings.js +214 -0
  214. package/dist/vite-plugins/settings.js.map +1 -0
  215. package/dist/vite-plugins/strip-query.d.ts +3 -0
  216. package/dist/vite-plugins/strip-query.d.ts.map +1 -0
  217. package/dist/vite-plugins/strip-query.js +6 -0
  218. package/dist/vite-plugins/strip-query.js.map +1 -0
  219. package/dist/vite-plugins/undeclared-library.d.ts +4 -0
  220. package/dist/vite-plugins/undeclared-library.d.ts.map +1 -0
  221. package/dist/vite-plugins/undeclared-library.js +50 -0
  222. package/dist/vite-plugins/undeclared-library.js.map +1 -0
  223. package/dist/vite-plugins/virtual-module.d.ts +22 -0
  224. package/dist/vite-plugins/virtual-module.d.ts.map +1 -0
  225. package/dist/vite-plugins/virtual-module.js +20 -0
  226. package/dist/vite-plugins/virtual-module.js.map +1 -0
  227. package/dist/vitest-plugin.d.ts +10 -0
  228. package/dist/vitest-plugin.d.ts.map +1 -0
  229. package/dist/vitest-plugin.js +12 -0
  230. package/dist/vitest-plugin.js.map +1 -0
  231. package/env.d.ts +91 -8
  232. package/package.json +30 -38
  233. package/src/babel-modules.d.ts +11 -0
  234. package/src/builder.ts +31 -86
  235. package/src/cli.ts +42 -0
  236. package/src/codegen/freshness.ts +65 -0
  237. package/src/codegen/report.ts +28 -0
  238. package/src/codegen/run-codegen.ts +260 -0
  239. package/src/codegen/store-resolver.ts +116 -0
  240. package/src/commands/build.ts +38 -0
  241. package/src/commands/codegen.ts +49 -0
  242. package/src/commands/dev.ts +24 -0
  243. package/src/commands/docs.ts +95 -0
  244. package/src/dev/icon-dir.ts +21 -0
  245. package/src/dev/refresh-tracker.ts +25 -0
  246. package/src/dev/runner-deps.ts +65 -0
  247. package/src/dev/runner-main.ts +34 -0
  248. package/src/dev/runner.ts +185 -0
  249. package/src/dev/schema-dir.ts +16 -0
  250. package/src/dev/supervisor.ts +276 -0
  251. package/src/dev/vite-dev-server.ts +36 -0
  252. package/src/internal/banner.ts +13 -0
  253. package/src/internal/data-dir.ts +70 -0
  254. package/src/internal/entry-arg.ts +46 -0
  255. package/src/internal/errors.ts +36 -0
  256. package/src/internal/list-files.ts +23 -0
  257. package/src/internal/resolve-cli-tool.ts +37 -0
  258. package/src/internal/staging-dir.ts +19 -0
  259. package/src/internal/xdg-data-dirs.ts +13 -0
  260. package/src/mcp/client.ts +235 -0
  261. package/src/mcp/handlers.ts +213 -0
  262. package/src/mcp/index.ts +46 -0
  263. package/src/mcp/serialize-widget.ts +41 -0
  264. package/src/mcp/testing-loader.ts +73 -0
  265. package/src/mcp/widget-registry.ts +49 -0
  266. package/src/refresh-globals.ts +10 -0
  267. package/src/refresh-runtime.ts +30 -55
  268. package/src/settings/compile.ts +22 -0
  269. package/src/settings/parser.ts +193 -0
  270. package/src/settings/render.ts +167 -0
  271. package/src/settings/schema.ts +169 -0
  272. package/src/vite-plugins/asset-extensions.ts +29 -0
  273. package/src/vite-plugins/built-url.ts +50 -0
  274. package/src/vite-plugins/css.ts +53 -0
  275. package/src/vite-plugins/fast-refresh/refresh-filter.ts +26 -0
  276. package/src/vite-plugins/fast-refresh/swc-refresh.ts +92 -0
  277. package/src/vite-plugins/icons.ts +74 -0
  278. package/src/vite-plugins/index.ts +25 -0
  279. package/src/vite-plugins/native.ts +83 -0
  280. package/src/vite-plugins/react-compiler.ts +84 -0
  281. package/src/vite-plugins/react-dom-prebundle.ts +17 -0
  282. package/src/vite-plugins/resource-init-module.ts +57 -0
  283. package/src/vite-plugins/resource-shared.ts +40 -0
  284. package/src/vite-plugins/resources.ts +366 -0
  285. package/src/vite-plugins/settings-worker-env.ts +30 -0
  286. package/src/vite-plugins/settings.ts +286 -0
  287. package/src/vite-plugins/strip-query.ts +7 -0
  288. package/src/vite-plugins/undeclared-library.ts +78 -0
  289. package/src/vite-plugins/virtual-module.ts +44 -0
  290. package/src/vitest-plugin.ts +13 -0
  291. package/dist/create.d.ts +0 -55
  292. package/dist/create.d.ts.map +0 -1
  293. package/dist/create.js +0 -236
  294. package/dist/create.js.map +0 -1
  295. package/dist/dev-server.d.ts +0 -37
  296. package/dist/dev-server.d.ts.map +0 -1
  297. package/dist/dev-server.js +0 -130
  298. package/dist/dev-server.js.map +0 -1
  299. package/dist/index.d.ts +0 -4
  300. package/dist/index.d.ts.map +0 -1
  301. package/dist/index.js +0 -4
  302. package/dist/index.js.map +0 -1
  303. package/dist/mcp-client.d.ts +0 -31
  304. package/dist/mcp-client.d.ts.map +0 -1
  305. package/dist/mcp-client.js +0 -430
  306. package/dist/mcp-client.js.map +0 -1
  307. package/dist/templates.d.ts +0 -9
  308. package/dist/templates.d.ts.map +0 -1
  309. package/dist/templates.js +0 -16
  310. package/dist/templates.js.map +0 -1
  311. package/dist/vite-plugin-gtkx-assets.d.ts +0 -20
  312. package/dist/vite-plugin-gtkx-assets.d.ts.map +0 -1
  313. package/dist/vite-plugin-gtkx-assets.js +0 -57
  314. package/dist/vite-plugin-gtkx-assets.js.map +0 -1
  315. package/dist/vite-plugin-gtkx-built-url.d.ts +0 -18
  316. package/dist/vite-plugin-gtkx-built-url.d.ts.map +0 -1
  317. package/dist/vite-plugin-gtkx-built-url.js +0 -43
  318. package/dist/vite-plugin-gtkx-built-url.js.map +0 -1
  319. package/dist/vite-plugin-gtkx-gsettings.d.ts +0 -28
  320. package/dist/vite-plugin-gtkx-gsettings.d.ts.map +0 -1
  321. package/dist/vite-plugin-gtkx-gsettings.js +0 -147
  322. package/dist/vite-plugin-gtkx-gsettings.js.map +0 -1
  323. package/dist/vite-plugin-gtkx-native.d.ts +0 -14
  324. package/dist/vite-plugin-gtkx-native.d.ts.map +0 -1
  325. package/dist/vite-plugin-gtkx-native.js +0 -53
  326. package/dist/vite-plugin-gtkx-native.js.map +0 -1
  327. package/dist/vite-plugin-gtkx-refresh.d.ts +0 -8
  328. package/dist/vite-plugin-gtkx-refresh.d.ts.map +0 -1
  329. package/dist/vite-plugin-gtkx-refresh.js +0 -37
  330. package/dist/vite-plugin-gtkx-refresh.js.map +0 -1
  331. package/dist/vite-plugin-swc-ssr-refresh.d.ts +0 -8
  332. package/dist/vite-plugin-swc-ssr-refresh.d.ts.map +0 -1
  333. package/dist/vite-plugin-swc-ssr-refresh.js +0 -46
  334. package/dist/vite-plugin-swc-ssr-refresh.js.map +0 -1
  335. package/src/cli.tsx +0 -154
  336. package/src/create.ts +0 -326
  337. package/src/dev-server.tsx +0 -162
  338. package/src/index.ts +0 -3
  339. package/src/mcp-client.ts +0 -518
  340. package/src/templates.ts +0 -26
  341. package/src/vite-plugin-gtkx-assets.ts +0 -69
  342. package/src/vite-plugin-gtkx-built-url.ts +0 -48
  343. package/src/vite-plugin-gtkx-gsettings.ts +0 -168
  344. package/src/vite-plugin-gtkx-native.ts +0 -64
  345. package/src/vite-plugin-gtkx-refresh.ts +0 -54
  346. package/src/vite-plugin-swc-ssr-refresh.ts +0 -61
  347. package/templates/claude/EXAMPLES.md.ejs +0 -744
  348. package/templates/claude/SKILL.md.ejs +0 -93
  349. package/templates/claude/WIDGETS.md.ejs +0 -820
  350. package/templates/config/vitest.config.ts.ejs +0 -11
  351. package/templates/gitignore.ejs +0 -4
  352. package/templates/package.json.ejs +0 -16
  353. package/templates/src/app.tsx.ejs +0 -32
  354. package/templates/src/dev.tsx.ejs +0 -5
  355. package/templates/src/gtkx-env.d.ts.ejs +0 -1
  356. package/templates/src/index.tsx.ejs +0 -5
  357. package/templates/tests/app.test.tsx.ejs +0 -16
  358. package/templates/tsconfig.json.ejs +0 -14
package/src/create.ts DELETED
@@ -1,326 +0,0 @@
1
- import { execFileSync, spawn } from "node:child_process";
2
- import { existsSync, mkdirSync, writeFileSync } from "node:fs";
3
- import { join, resolve } from "node:path";
4
- import * as p from "@clack/prompts";
5
- import { renderFile, type TemplateContext } from "./templates.js";
6
-
7
- /**
8
- * Supported package managers for GTKX projects.
9
- */
10
- type PackageManager = "pnpm" | "npm" | "yarn";
11
-
12
- /**
13
- * Whether to include testing setup in GTKX projects.
14
- */
15
- export type TestingOption = "vitest" | "none";
16
-
17
- /**
18
- * Options for creating a new GTKX project.
19
- *
20
- * All options are optional; missing values will be prompted interactively.
21
- */
22
- type CreateOptions = {
23
- name?: string;
24
- appId?: string;
25
- packageManager?: PackageManager;
26
- testing?: TestingOption;
27
- claudeSkills?: boolean;
28
- };
29
-
30
- const DEPENDENCIES = ["@gtkx/css", "@gtkx/ffi", "@gtkx/react", "react"];
31
-
32
- const DEV_DEPENDENCIES = ["@gtkx/cli", "@types/react", "typescript", "vite"];
33
-
34
- const TESTING_DEV_DEPENDENCIES = ["@gtkx/testing", "@gtkx/vitest", "vitest"];
35
-
36
- const createTemplateContext = (name: string, appId: string, testing: TestingOption): TemplateContext => {
37
- const title = name
38
- .split("-")
39
- .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
40
- .join(" ");
41
-
42
- return { name, appId, title, testing };
43
- };
44
-
45
- export const getAddCommand = (pm: PackageManager, deps: string[], dev: boolean): string => {
46
- const devFlag = dev ? (pm === "npm" ? "--save-dev" : "-D") : "";
47
- const parts = [devFlag, ...deps].filter(Boolean).join(" ");
48
-
49
- switch (pm) {
50
- case "npm":
51
- return `npm install ${parts}`;
52
- case "yarn":
53
- return `yarn add ${parts}`;
54
- case "pnpm":
55
- return `pnpm add ${parts}`;
56
- }
57
- };
58
-
59
- export const getRunCommand = (pm: PackageManager): string => {
60
- switch (pm) {
61
- case "npm":
62
- return "npm run dev";
63
- case "yarn":
64
- return "yarn dev";
65
- case "pnpm":
66
- return "pnpm dev";
67
- }
68
- };
69
-
70
- export const isValidProjectName = (name: string): boolean => {
71
- return /^[a-z0-9-]+$/.test(name);
72
- };
73
-
74
- export const isValidAppId = (appId: string): boolean => {
75
- return /^[a-zA-Z][a-zA-Z0-9]*(\.[a-zA-Z][a-zA-Z0-9]*)+$/.test(appId);
76
- };
77
-
78
- const runCommand = (command: string, cwd: string): Promise<void> => {
79
- return new Promise((resolve, reject) => {
80
- const proc = spawn(command, { cwd, stdio: "pipe", shell: true });
81
- proc.on("close", (code) =>
82
- code === 0 ? resolve() : reject(new Error(`Command failed with exit code ${code}`)),
83
- );
84
- proc.on("error", reject);
85
- });
86
- };
87
-
88
- const suggestAppId = (name: string): string => {
89
- const sanitized = name.replace(/-/g, "");
90
- return `com.${sanitized}.app`;
91
- };
92
-
93
- type ResolvedOptions = {
94
- name: string;
95
- appId: string;
96
- packageManager: PackageManager;
97
- testing: TestingOption;
98
- claudeSkills: boolean;
99
- };
100
-
101
- const checkCancelled = <T>(value: T | symbol): T => {
102
- if (p.isCancel(value)) {
103
- p.cancel("Operation cancelled");
104
- process.exit(0);
105
- }
106
- return value as T;
107
- };
108
-
109
- const promptForOptions = async (options: CreateOptions): Promise<ResolvedOptions> => {
110
- const name =
111
- options.name ??
112
- checkCancelled(
113
- await p.text({
114
- message: "Project name",
115
- placeholder: "my-app",
116
- validate: (value) => {
117
- if (!value) return "Project name is required";
118
- if (!isValidProjectName(value)) {
119
- return "Project name must be lowercase letters, numbers, and hyphens only";
120
- }
121
- if (existsSync(resolve(process.cwd(), value))) {
122
- return `Directory "${value}" already exists`;
123
- }
124
- },
125
- }),
126
- );
127
-
128
- const defaultAppId = suggestAppId(name);
129
-
130
- const appId =
131
- options.appId ??
132
- checkCancelled(
133
- await p.text({
134
- message: "App ID",
135
- placeholder: defaultAppId,
136
- initialValue: defaultAppId,
137
- validate: (value) => {
138
- if (!value) return "App ID is required";
139
- if (!isValidAppId(value)) {
140
- return "App ID must be reverse domain notation (e.g., com.example.myapp)";
141
- }
142
- },
143
- }),
144
- );
145
-
146
- const packageManager =
147
- options.packageManager ??
148
- checkCancelled(
149
- await p.select({
150
- message: "Package manager",
151
- options: [
152
- { value: "pnpm", label: "pnpm", hint: "recommended" },
153
- { value: "npm", label: "npm" },
154
- { value: "yarn", label: "yarn" },
155
- ],
156
- initialValue: "pnpm",
157
- }),
158
- );
159
-
160
- const testing: TestingOption =
161
- options.testing ??
162
- (checkCancelled(
163
- await p.confirm({
164
- message: "Include testing setup (Vitest)?",
165
- initialValue: true,
166
- }),
167
- )
168
- ? "vitest"
169
- : "none");
170
-
171
- const claudeSkills =
172
- options.claudeSkills ??
173
- checkCancelled(
174
- await p.confirm({
175
- message: "Include Claude Code skills?",
176
- initialValue: true,
177
- }),
178
- );
179
-
180
- return { name, appId, packageManager, testing, claudeSkills };
181
- };
182
-
183
- const scaffoldProject = (projectPath: string, resolved: ResolvedOptions): void => {
184
- const { name, appId, testing, claudeSkills } = resolved;
185
- const context = createTemplateContext(name, appId, testing);
186
-
187
- mkdirSync(projectPath, { recursive: true });
188
- mkdirSync(join(projectPath, "src"), { recursive: true });
189
-
190
- if (testing !== "none") {
191
- mkdirSync(join(projectPath, "tests"), { recursive: true });
192
- }
193
-
194
- writeFileSync(join(projectPath, "package.json"), renderFile("package.json.ejs", context));
195
- writeFileSync(join(projectPath, "tsconfig.json"), renderFile("tsconfig.json.ejs", context));
196
- writeFileSync(join(projectPath, "src", "app.tsx"), renderFile("src/app.tsx.ejs", context));
197
- writeFileSync(join(projectPath, "src", "dev.tsx"), renderFile("src/dev.tsx.ejs", context));
198
- writeFileSync(join(projectPath, "src", "index.tsx"), renderFile("src/index.tsx.ejs", context));
199
- writeFileSync(join(projectPath, "src", "gtkx-env.d.ts"), renderFile("src/gtkx-env.d.ts.ejs", context));
200
- writeFileSync(join(projectPath, ".gitignore"), renderFile("gitignore.ejs", context));
201
-
202
- if (claudeSkills) {
203
- const skillsDir = join(projectPath, ".claude", "skills", "developing-gtkx-apps");
204
- mkdirSync(skillsDir, { recursive: true });
205
- writeFileSync(join(skillsDir, "SKILL.md"), renderFile("claude/SKILL.md.ejs", context));
206
- writeFileSync(join(skillsDir, "WIDGETS.md"), renderFile("claude/WIDGETS.md.ejs", context));
207
- writeFileSync(join(skillsDir, "EXAMPLES.md"), renderFile("claude/EXAMPLES.md.ejs", context));
208
- }
209
-
210
- if (testing === "vitest") {
211
- writeFileSync(join(projectPath, "vitest.config.ts"), renderFile("config/vitest.config.ts.ejs", context));
212
- writeFileSync(join(projectPath, "tests", "app.test.tsx"), renderFile("tests/app.test.tsx.ejs", context));
213
- }
214
- };
215
-
216
- const getDevDependencies = (testing: TestingOption): string[] => {
217
- const devDeps = [...DEV_DEPENDENCIES];
218
- if (testing === "vitest") {
219
- devDeps.push(...TESTING_DEV_DEPENDENCIES);
220
- }
221
- return devDeps;
222
- };
223
-
224
- const installDependencies = async (
225
- projectPath: string,
226
- name: string,
227
- packageManager: PackageManager,
228
- devDeps: string[],
229
- ): Promise<void> => {
230
- const installSpinner = p.spinner();
231
- installSpinner.start("Installing dependencies...");
232
-
233
- try {
234
- const addCmd = getAddCommand(packageManager, DEPENDENCIES, false);
235
- await runCommand(addCmd, projectPath);
236
-
237
- const addDevCmd = getAddCommand(packageManager, devDeps, true);
238
- await runCommand(addDevCmd, projectPath);
239
-
240
- installSpinner.stop("Dependencies installed!");
241
- } catch (error) {
242
- installSpinner.stop("Failed to install dependencies");
243
- p.log.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
244
- p.log.info("You can install dependencies manually by running:");
245
- p.log.info(` cd ${name}`);
246
- p.log.info(` ${getAddCommand(packageManager, DEPENDENCIES, false)}`);
247
- p.log.info(` ${getAddCommand(packageManager, devDeps, true)}`);
248
- }
249
- };
250
-
251
- const initializeGitRepo = (projectPath: string): void => {
252
- const opts = { cwd: projectPath, stdio: "pipe" as const };
253
- execFileSync("git", ["init"], opts);
254
- execFileSync("git", ["add", "-A"], opts);
255
- execFileSync("git", ["commit", "-m", "Initial commit"], opts);
256
- };
257
-
258
- const printNextSteps = (name: string, packageManager: PackageManager, testing: TestingOption): void => {
259
- const runCmd = getRunCommand(packageManager);
260
- const nextSteps = `cd ${name}\n${runCmd}`;
261
-
262
- const testingNote =
263
- testing !== "none"
264
- ? `
265
-
266
- To run tests, you need xvfb installed:
267
- Fedora: sudo dnf install xorg-x11-server-Xvfb
268
- Ubuntu: sudo apt install xvfb`
269
- : "";
270
-
271
- p.note(`${nextSteps}${testingNote}`, "Next steps");
272
- };
273
-
274
- /**
275
- * Creates a new GTKX project with interactive prompts.
276
- *
277
- * Scaffolds a complete project structure including:
278
- * - TypeScript configuration
279
- * - React component template
280
- * - Development server entry point
281
- * - Optional testing setup
282
- * - Optional Claude Code skills
283
- *
284
- * @param options - Pre-filled options to skip prompts
285
- *
286
- * @example
287
- * ```tsx
288
- * import { createApp } from "@gtkx/cli";
289
- *
290
- * // Interactive mode
291
- * await createApp();
292
- *
293
- * // With pre-filled options
294
- * await createApp({
295
- * name: "my-app",
296
- * appId: "com.example.myapp",
297
- * packageManager: "pnpm",
298
- * testing: "vitest",
299
- * });
300
- * ```
301
- */
302
- export const createApp = async (options: CreateOptions = {}): Promise<void> => {
303
- p.intro("Create GTKX App");
304
-
305
- const resolved = await promptForOptions(options);
306
- const projectPath = resolve(process.cwd(), resolved.name);
307
-
308
- const s = p.spinner();
309
- s.start("Creating project structure...");
310
- scaffoldProject(projectPath, resolved);
311
- s.stop("Project structure created!");
312
-
313
- const devDeps = getDevDependencies(resolved.testing);
314
- await installDependencies(projectPath, resolved.name, resolved.packageManager, devDeps);
315
-
316
- const gitSpinner = p.spinner();
317
- gitSpinner.start("Initializing git repository...");
318
- try {
319
- initializeGitRepo(projectPath);
320
- gitSpinner.stop("Git repository initialized!");
321
- } catch {
322
- gitSpinner.stop("Failed to initialize git repository");
323
- }
324
-
325
- printNextSteps(resolved.name, resolved.packageManager, resolved.testing);
326
- };
@@ -1,162 +0,0 @@
1
- import { events } from "@gtkx/ffi";
2
- import { setHotReloading, update } from "@gtkx/react";
3
- import { createServer, type InlineConfig, type ViteDevServer } from "vite";
4
- import { isReactRefreshBoundary, performRefresh } from "./refresh-runtime.js";
5
- import { gtkxAssets } from "./vite-plugin-gtkx-assets.js";
6
- import { gtkxGSettings } from "./vite-plugin-gtkx-gsettings.js";
7
- import { gtkxRefresh } from "./vite-plugin-gtkx-refresh.js";
8
- import { swcSsrRefresh } from "./vite-plugin-swc-ssr-refresh.js";
9
-
10
- /**
11
- * Options for the GTKX development server.
12
- */
13
- export type DevServerOptions = {
14
- /** Path to the entry file (e.g., "src/dev.tsx") */
15
- entry: string;
16
- /** Additional Vite configuration */
17
- vite?: InlineConfig;
18
- };
19
-
20
- type AppModule = {
21
- default: () => React.ReactNode;
22
- };
23
-
24
- /**
25
- * Creates a Vite-based development server with hot module replacement.
26
- *
27
- * Provides fast refresh for React components and full reload for other changes.
28
- * The server watches for file changes and automatically updates the running
29
- * GTK application.
30
- *
31
- * @param options - Server configuration including entry point and Vite options
32
- * @returns A Vite development server instance
33
- *
34
- * @example
35
- * ```tsx
36
- * import { createDevServer } from "@gtkx/cli";
37
- * import { render } from "@gtkx/react";
38
- *
39
- * const server = await createDevServer({
40
- * entry: "./src/dev.tsx",
41
- * });
42
- *
43
- * const mod = await server.ssrLoadModule("./src/dev.tsx");
44
- * render(<mod.default />, mod.appId);
45
- * ```
46
- *
47
- * @see {@link DevServerOptions} for configuration options
48
- */
49
- export const createDevServer = async (options: DevServerOptions): Promise<ViteDevServer> => {
50
- const { entry, vite: viteConfig } = options;
51
-
52
- const moduleExports = new Map<string, Record<string, unknown>>();
53
-
54
- const server = await createServer({
55
- ...viteConfig,
56
- appType: "custom",
57
- plugins: [
58
- gtkxGSettings(),
59
- gtkxAssets(),
60
- swcSsrRefresh(),
61
- gtkxRefresh(),
62
- {
63
- name: "gtkx:remove-react-dom-optimized",
64
- enforce: "post",
65
- config(config) {
66
- config.optimizeDeps ??= {};
67
- config.optimizeDeps.include = config.optimizeDeps.include?.filter(
68
- (dep) => dep !== "react-dom" && !dep.startsWith("react-dom/"),
69
- );
70
- },
71
- },
72
- ],
73
- server: {
74
- ...viteConfig?.server,
75
- middlewareMode: true,
76
- },
77
- optimizeDeps: {
78
- ...viteConfig?.optimizeDeps,
79
- noDiscovery: true,
80
- include: [],
81
- },
82
- ssr: {
83
- ...viteConfig?.ssr,
84
- external: true,
85
- },
86
- });
87
-
88
- const loadModule = async (): Promise<AppModule> => {
89
- const mod = (await server.ssrLoadModule(entry)) as AppModule;
90
- moduleExports.set(entry, { ...mod });
91
- return mod;
92
- };
93
-
94
- const invalidateAllModules = (): void => {
95
- for (const module of server.moduleGraph.idToModuleMap.values()) {
96
- server.moduleGraph.invalidateModule(module);
97
- }
98
- };
99
-
100
- const invalidateModuleAndImporters = (filePath: string): void => {
101
- const module = server.moduleGraph.getModuleById(filePath);
102
-
103
- if (module) {
104
- server.moduleGraph.invalidateModule(module);
105
-
106
- for (const importer of module.importers) {
107
- server.moduleGraph.invalidateModule(importer);
108
- }
109
- }
110
- };
111
-
112
- events.on("stop", () => {
113
- server.close();
114
- });
115
-
116
- server.watcher.on("change", async (changedPath) => {
117
- try {
118
- const module = server.moduleGraph.getModuleById(changedPath);
119
-
120
- if (!module) {
121
- return;
122
- }
123
-
124
- console.log(`[gtkx] File changed: ${changedPath}`);
125
-
126
- invalidateModuleAndImporters(changedPath);
127
-
128
- const newMod = (await server.ssrLoadModule(changedPath)) as Record<string, unknown>;
129
- moduleExports.set(changedPath, { ...newMod });
130
-
131
- if (isReactRefreshBoundary(newMod)) {
132
- console.log("[gtkx] Fast refreshing...");
133
- performRefresh();
134
- console.log("[gtkx] Fast refresh complete");
135
- return;
136
- }
137
-
138
- console.log("[gtkx] Full reload...");
139
- invalidateAllModules();
140
-
141
- const mod = await loadModule();
142
- const App = mod.default;
143
-
144
- if (typeof App !== "function") {
145
- console.error("[gtkx] Entry file must export a default function component");
146
- return;
147
- }
148
-
149
- setHotReloading(true);
150
- try {
151
- await update(<App />);
152
- } finally {
153
- setHotReloading(false);
154
- }
155
- console.log("[gtkx] Full reload complete");
156
- } catch (error) {
157
- console.error("[gtkx] Hot reload failed:", error);
158
- }
159
- });
160
-
161
- return server;
162
- };
package/src/index.ts DELETED
@@ -1,3 +0,0 @@
1
- export { type BuildOptions, build } from "./builder.js";
2
- export { createApp } from "./create.js";
3
- export { createDevServer, type DevServerOptions } from "./dev-server.js";