@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
@@ -0,0 +1,49 @@
1
+ import { info } from "@gtkx/utils";
2
+ import { defineCommand } from "citty";
3
+ import { formatCodegenResult } from "../codegen/report.js";
4
+ import { ensureGenerated, isCodegenDisabled, runCodegen, syncSchemaEnv } from "../codegen/run-codegen.js";
5
+ import { cwdArg, resolveCwd } from "../internal/entry-arg.js";
6
+
7
+ const codegen = defineCommand({
8
+ meta: {
9
+ name: "codegen",
10
+ description: "Generate TypeScript bindings for the GIR libraries declared in gtkx.config.ts",
11
+ },
12
+ args: {
13
+ force: {
14
+ type: "boolean",
15
+ description: "Wipe the generated store and regenerate unconditionally (recover a corrupted store)",
16
+ default: false,
17
+ },
18
+ ...cwdArg,
19
+ },
20
+ async run({ args }) {
21
+ const cwd = resolveCwd(args);
22
+
23
+ if (await isCodegenDisabled(cwd)) {
24
+ await runCodegen({ cwd });
25
+ syncSchemaEnv(cwd);
26
+ info("codegen: disabled for this project; reusing an installed binding store");
27
+
28
+ return;
29
+ }
30
+
31
+ if (!args.force) {
32
+ const isRan = await ensureGenerated(cwd);
33
+ info(isRan ? "codegen: regenerated stale bindings" : "codegen: bindings up to date");
34
+
35
+ return;
36
+ }
37
+
38
+ const startedAt = Date.now();
39
+ const result = await runCodegen({ cwd, force: true });
40
+ syncSchemaEnv(cwd);
41
+ const lines = formatCodegenResult(result, Date.now() - startedAt);
42
+
43
+ for (const line of lines) {
44
+ info(line);
45
+ }
46
+ },
47
+ });
48
+
49
+ export { codegen };
@@ -0,0 +1,24 @@
1
+ import { defineCommand } from "citty";
2
+ import { ensureGenerated, resolveConfigWatch } from "../codegen/run-codegen.js";
3
+ import { type DevWatch, runDevSupervisor } from "../dev/supervisor.js";
4
+ import { entryArg, resolveEntry } from "../internal/entry-arg.js";
5
+
6
+ const DEV_MODE = "development";
7
+
8
+ const dev = defineCommand({
9
+ meta: {
10
+ name: "dev",
11
+ description: "Start development server with HMR",
12
+ },
13
+ args: {
14
+ ...entryArg,
15
+ },
16
+ async run({ args }) {
17
+ const { cwd, entry: entryPath } = resolveEntry(args);
18
+ await ensureGenerated(cwd, { announce: true, mode: DEV_MODE });
19
+ const watch: DevWatch | undefined = await resolveConfigWatch(cwd, DEV_MODE);
20
+ await runDevSupervisor(entryPath, cwd, watch);
21
+ },
22
+ });
23
+
24
+ export { dev };
@@ -0,0 +1,95 @@
1
+ import { type ElementProps, readBuiltinElements, resolveGirPath, resolveLibraries, writeDocs } from "@gtkx/codegen";
2
+ import { loadConfig } from "@gtkx/config";
3
+ import { info } from "@gtkx/utils";
4
+ import { defineCommand } from "citty";
5
+ import { existsSync } from "node:fs";
6
+ import { join, resolve } from "node:path";
7
+ import { resolveReactSubexports } from "../codegen/store-resolver.js";
8
+ import { cwdArg, resolveCwd } from "../internal/entry-arg.js";
9
+
10
+ const docs = defineCommand({
11
+ meta: {
12
+ name: "docs",
13
+ description:
14
+ "Generate markdown reference pages for the JSX elements of the GIR libraries declared in gtkx.config.ts",
15
+ },
16
+ args: {
17
+ out: {
18
+ type: "string",
19
+ description: "Output directory for the generated markdown pages, relative to the project root",
20
+ default: "docs/reference",
21
+ },
22
+ "base-path": {
23
+ type: "string",
24
+ description: "URL base path used for links between generated pages",
25
+ default: "/reference",
26
+ },
27
+ force: {
28
+ type: "boolean",
29
+ description: "Regenerate even when the pages are up to date with the GIR libraries",
30
+ default: false,
31
+ },
32
+ ...cwdArg,
33
+ },
34
+ async run({ args }) {
35
+ const cwd = resolveCwd(args);
36
+ const { config } = await loadConfig(cwd);
37
+
38
+ if (config.codegen === false) {
39
+ throw new Error(
40
+ "codegen is disabled for this project, so there are no GIR libraries to document. " +
41
+ "Remove `codegen: false` from gtkx.config.ts to use `gtkx docs`.",
42
+ );
43
+ }
44
+
45
+ const girPath = resolveGirPath(config.girPath);
46
+
47
+ if (girPath.length === 0) {
48
+ throw new Error(
49
+ "No GIR search paths available. Install gobject-introspection " +
50
+ "(Linux: `sudo dnf install gobject-introspection-devel` or " +
51
+ "`sudo apt install libgirepository1.0-dev`), or set `girPath` in gtkx.config.ts.",
52
+ );
53
+ }
54
+
55
+ const libraries = resolveLibraries(config.libraries, girPath);
56
+ const startedAt = Date.now();
57
+ const outDir = resolve(cwd, args.out);
58
+
59
+ const { regenerated, namespaces } = writeDocs({
60
+ libraries,
61
+ girPath,
62
+ outDir,
63
+ basePath: args["base-path"],
64
+ props: await resolveDocsProps(cwd),
65
+ force: args.force,
66
+ });
67
+
68
+ if (!regenerated) {
69
+ info(`docs: pages in ${outDir} are up to date`);
70
+
71
+ return;
72
+ }
73
+
74
+ const count = namespaces.reduce((total, namespace) => total + namespace.elements.length, 0);
75
+
76
+ info(
77
+ `docs: wrote ${String(count)} element pages across ${String(namespaces.length)} namespaces ` +
78
+ `to ${outDir} in ${String(Date.now() - startedAt)}ms`,
79
+ );
80
+ },
81
+ });
82
+
83
+ const resolveDocsProps = async (cwd: string): Promise<ElementProps> => {
84
+ const giStoreDir = join(cwd, "node_modules", ".gtkx", "gi");
85
+
86
+ if (!existsSync(giStoreDir)) {
87
+ return {};
88
+ }
89
+
90
+ const { props } = await readBuiltinElements(resolveReactSubexports(cwd), giStoreDir);
91
+
92
+ return props;
93
+ };
94
+
95
+ export { docs };
@@ -0,0 +1,21 @@
1
+ import { existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { prependXdgDataDir } from "../internal/xdg-data-dirs.js";
4
+
5
+ const prepareDevIconDir = (root: string, dataDir: string | null): string | null => {
6
+ if (dataDir === null) {
7
+ return null;
8
+ }
9
+
10
+ const shareDir = join(root, dataDir);
11
+
12
+ if (!existsSync(join(shareDir, "icons"))) {
13
+ return null;
14
+ }
15
+
16
+ process.env.XDG_DATA_DIRS = prependXdgDataDir(shareDir, process.env.XDG_DATA_DIRS);
17
+
18
+ return shareDir;
19
+ };
20
+
21
+ export { prepareDevIconDir };
@@ -0,0 +1,25 @@
1
+ type RefreshTracker = {
2
+ performRefresh: () => void;
3
+ isRefreshing: () => boolean;
4
+ };
5
+
6
+ const createRefreshTracker = (performRefresh: () => void): RefreshTracker => {
7
+ let isRefreshing = false;
8
+
9
+ return {
10
+ performRefresh: () => {
11
+ isRefreshing = true;
12
+
13
+ try {
14
+ performRefresh();
15
+ } finally {
16
+ setTimeout(() => {
17
+ isRefreshing = false;
18
+ }, 0);
19
+ }
20
+ },
21
+ isRefreshing: () => isRefreshing,
22
+ };
23
+ };
24
+
25
+ export { createRefreshTracker, type RefreshTracker };
@@ -0,0 +1,65 @@
1
+ import { loadConfig } from "@gtkx/config";
2
+ import * as Gio from "@gtkx/gi/gio";
3
+ import { quitApplication } from "@gtkx/runtime";
4
+ import { info, installGracefulShutdown } from "@gtkx/utils";
5
+ import { createServer } from "vite";
6
+ import type { DevRunnerDeps } from "./runner.js";
7
+ import { startMcpClient, stopMcpClient } from "../mcp/index.js";
8
+ import { setTestingModuleLoader } from "../mcp/testing-loader.js";
9
+ import { isRefreshBoundary, performRefresh } from "../refresh-runtime.js";
10
+ import { gtkxFastRefresh } from "../vite-plugins/fast-refresh/swc-refresh.js";
11
+ import { gtkxVitePlugins } from "../vite-plugins/index.js";
12
+ import { gtkxReactDomPrebundle } from "../vite-plugins/react-dom-prebundle.js";
13
+
14
+ const DEV_MODE = "development";
15
+ const APPLICATION_POLL_INTERVAL_MS = 50;
16
+
17
+ const currentApplicationId = (): string | null => Gio.Application.getDefault()?.applicationId ?? null;
18
+
19
+ const waitForApplicationId = async (timeoutMs: number): Promise<string | null> => {
20
+ const deadline = Date.now() + timeoutMs;
21
+ let applicationId = currentApplicationId();
22
+
23
+ while (applicationId === null && Date.now() < deadline) {
24
+ await new Promise((resolve) => setTimeout(resolve, APPLICATION_POLL_INTERVAL_MS));
25
+ applicationId = currentApplicationId();
26
+ }
27
+
28
+ return applicationId;
29
+ };
30
+
31
+ const defaultDevRunnerDeps = (): DevRunnerDeps => ({
32
+ createServer,
33
+ waitForApplicationId,
34
+ getConfiguredApplicationId: async (root: string) => {
35
+ const loaded = await loadConfig(root, { mode: DEV_MODE });
36
+
37
+ return loaded.config.applicationId;
38
+ },
39
+ startMcpClient: (applicationId, loadAppModule) => {
40
+ setTestingModuleLoader(() => loadAppModule("@gtkx/testing") as Promise<typeof import("@gtkx/testing")>);
41
+
42
+ return startMcpClient(applicationId);
43
+ },
44
+ stopMcpClient,
45
+ watchApplicationShutdown: (onShutdown) => {
46
+ Gio.Application.getDefault()?.on("shutdown", onShutdown);
47
+ },
48
+ installShutdownHandlers: (onSignal) => {
49
+ installGracefulShutdown({ onSignal });
50
+ },
51
+ quitDefaultApplication: () => {
52
+ const application = Gio.Application.getDefault();
53
+
54
+ if (application) {
55
+ quitApplication(application);
56
+ }
57
+ },
58
+ performRefresh,
59
+ isRefreshBoundary,
60
+ plugins: () => [...gtkxVitePlugins(DEV_MODE), ...gtkxFastRefresh(), gtkxReactDomPrebundle()],
61
+ log: info,
62
+ exit: (code: number): never => process.exit(code),
63
+ });
64
+
65
+ export { defaultDevRunnerDeps };
@@ -0,0 +1,34 @@
1
+ import { error } from "@gtkx/utils";
2
+ import { resolve } from "node:path";
3
+ import { resolveDataDir } from "../internal/data-dir.js";
4
+ import { prepareDevIconDir } from "./icon-dir.js";
5
+ import { createDevRunner } from "./runner.js";
6
+ import { prepareDevSchemaDir } from "./schema-dir.js";
7
+
8
+ const ENTRY_ARG_INDEX = 2;
9
+
10
+ const main = async (): Promise<void> => {
11
+ if (process.channel) {
12
+ process.once("disconnect", () => {
13
+ process.exit(0);
14
+ });
15
+ }
16
+
17
+ const cwd = process.cwd();
18
+ const entryArg = process.argv[ENTRY_ARG_INDEX];
19
+
20
+ if (!entryArg) {
21
+ error("Missing entry argument");
22
+ process.exit(1);
23
+ }
24
+
25
+ const dataDir = resolveDataDir(cwd);
26
+ prepareDevSchemaDir(cwd, dataDir);
27
+ prepareDevIconDir(cwd, dataDir);
28
+ const entryPath = resolve(cwd, entryArg);
29
+ const { defaultDevRunnerDeps } = await import("./runner-deps.js");
30
+ const runner = createDevRunner(defaultDevRunnerDeps());
31
+ await runner.run(entryPath);
32
+ };
33
+
34
+ export { main };
@@ -0,0 +1,185 @@
1
+ import type { InlineConfig, Plugin } from "vite";
2
+ import { error } from "@gtkx/utils";
3
+ import { createRefreshTracker, type RefreshTracker } from "./refresh-tracker.js";
4
+ import { RESTART_EXIT_CODE } from "./supervisor.js";
5
+ import { createDevServerConfig, type DevServer } from "./vite-dev-server.js";
6
+
7
+ type DevRunnerDeps = {
8
+ createServer(config: InlineConfig): Promise<DevServer>;
9
+ waitForApplicationId(timeoutMs: number): Promise<string | null>;
10
+ getConfiguredApplicationId(root: string): Promise<string | undefined>;
11
+ startMcpClient(
12
+ applicationId: string,
13
+ loadAppModule: (id: string) => Promise<Record<string, unknown>>,
14
+ ): Promise<unknown>;
15
+ stopMcpClient(): void;
16
+ watchApplicationShutdown(onShutdown: () => void): void;
17
+ installShutdownHandlers(onSignal: () => void | Promise<void>): void;
18
+ quitDefaultApplication(): void;
19
+ performRefresh: () => void;
20
+ isRefreshBoundary(module: Record<string, unknown>): boolean;
21
+ plugins(): Plugin[];
22
+ log(message: string): void;
23
+ exit(code: number): never;
24
+ };
25
+
26
+ type DevRunner = {
27
+ run(entryPath: string): Promise<void>;
28
+ };
29
+
30
+ type ShutdownController = {
31
+ isShuttingDown: () => boolean;
32
+ shutdown: (quitApplication: () => void) => Promise<void>;
33
+ };
34
+
35
+ const APPLICATION_MOUNT_TIMEOUT_MS = 10_000;
36
+
37
+ const requestRestart = async (server: DevServer, deps: DevRunnerDeps): Promise<never> => {
38
+ deps.log("Full restart (process restart)");
39
+ await server.close();
40
+
41
+ return deps.exit(RESTART_EXIT_CODE);
42
+ };
43
+
44
+ const handleFileChange = async (server: DevServer, deps: DevRunnerDeps, changedPath: string): Promise<void> => {
45
+ const module = server.moduleGraph.getModuleById(changedPath);
46
+
47
+ if (!module) {
48
+ return;
49
+ }
50
+
51
+ deps.log(`File changed: ${changedPath}`);
52
+ const loadedExports = module.ssrModule;
53
+
54
+ if (loadedExports && !deps.isRefreshBoundary(loadedExports)) {
55
+ await requestRestart(server, deps);
56
+
57
+ return;
58
+ }
59
+
60
+ server.moduleGraph.invalidateModule(module);
61
+
62
+ for (const importer of module.importers) {
63
+ server.moduleGraph.invalidateModule(importer);
64
+ }
65
+
66
+ const newMod = await server.ssrLoadModule(changedPath);
67
+
68
+ if (deps.isRefreshBoundary(newMod)) {
69
+ deps.log("Running Fast Refresh...");
70
+ deps.performRefresh();
71
+ deps.log("Fast Refresh complete");
72
+
73
+ return;
74
+ }
75
+
76
+ await requestRestart(server, deps);
77
+ };
78
+
79
+ const createShutdownController = (server: DevServer, deps: DevRunnerDeps): ShutdownController => {
80
+ let isShuttingDown = false;
81
+
82
+ return {
83
+ isShuttingDown: () => isShuttingDown,
84
+ shutdown: async (quitApplication: () => void): Promise<void> => {
85
+ if (isShuttingDown) {
86
+ return;
87
+ }
88
+
89
+ isShuttingDown = true;
90
+ quitApplication();
91
+ deps.stopMcpClient();
92
+ await server.close();
93
+ },
94
+ };
95
+ };
96
+
97
+ const reloadChangedFile = async (server: DevServer, deps: DevRunnerDeps, changedPath: string): Promise<void> => {
98
+ try {
99
+ await handleFileChange(server, deps, changedPath);
100
+ } catch (error_) {
101
+ error("Hot reload failed:", error_);
102
+ }
103
+ };
104
+
105
+ const onFileChange =
106
+ (server: DevServer, deps: DevRunnerDeps, controller: ShutdownController): ((changedPath: string) => void) =>
107
+ (changedPath) => {
108
+ if (controller.isShuttingDown()) {
109
+ return;
110
+ }
111
+
112
+ void reloadChangedFile(server, deps, changedPath);
113
+ };
114
+
115
+ const onShutdownSignal =
116
+ (deps: DevRunnerDeps, controller: ShutdownController): (() => Promise<void>) =>
117
+ async () => {
118
+ if (controller.isShuttingDown()) {
119
+ return;
120
+ }
121
+
122
+ deps.log("Received shutdown signal - stopping dev runner...");
123
+
124
+ await controller.shutdown(() => {
125
+ deps.quitDefaultApplication();
126
+ });
127
+ };
128
+
129
+ const closeAndExit = async (deps: DevRunnerDeps, controller: ShutdownController): Promise<never> => {
130
+ try {
131
+ await controller.shutdown((): void => undefined);
132
+ } catch (error_) {
133
+ error("Error closing server:", error_);
134
+
135
+ return deps.exit(1);
136
+ }
137
+
138
+ return deps.exit(0);
139
+ };
140
+
141
+ const onApplicationShutdown =
142
+ (deps: DevRunnerDeps, refreshTracker: RefreshTracker, controller: ShutdownController): (() => void) =>
143
+ () => {
144
+ if (controller.isShuttingDown()) {
145
+ return;
146
+ }
147
+
148
+ if (refreshTracker.isRefreshing()) {
149
+ deps.log("Application unmounted during Fast Refresh - restarting dev runner...");
150
+
151
+ return deps.exit(RESTART_EXIT_CODE);
152
+ }
153
+
154
+ deps.log("Application quit - stopping dev runner...");
155
+ void closeAndExit(deps, controller);
156
+ };
157
+
158
+ const createDevRunner = (deps: DevRunnerDeps): DevRunner => ({
159
+ async run(entryPath: string): Promise<void> {
160
+ const root = process.cwd();
161
+ const server = await deps.createServer(createDevServerConfig(root, deps.plugins()));
162
+ const refreshTracker = createRefreshTracker(deps.performRefresh);
163
+ const refreshTrackingDeps: DevRunnerDeps = { ...deps, performRefresh: refreshTracker.performRefresh };
164
+ const controller = createShutdownController(server, deps);
165
+ deps.installShutdownHandlers(onShutdownSignal(deps, controller));
166
+ server.watcher.on("change", onFileChange(server, refreshTrackingDeps, controller));
167
+ deps.log(`Loading entry: ${entryPath}`);
168
+ await server.ssrLoadModule(entryPath);
169
+ const liveApplicationId = await deps.waitForApplicationId(APPLICATION_MOUNT_TIMEOUT_MS);
170
+
171
+ if (liveApplicationId) {
172
+ deps.watchApplicationShutdown(onApplicationShutdown(deps, refreshTracker, controller));
173
+ const applicationId = (await deps.getConfiguredApplicationId(root)) ?? liveApplicationId;
174
+ deps.log(`Connected application ID: ${applicationId}`);
175
+ await deps.startMcpClient(applicationId, (id) => server.ssrLoadModule(id));
176
+ } else {
177
+ deps.log("Entry did not mount an application - MCP client not started.");
178
+ }
179
+
180
+ deps.log("HMR enabled - watching for changes...");
181
+ },
182
+ });
183
+
184
+ export type { DevServer } from "./vite-dev-server.js";
185
+ export { createDevRunner, type DevRunnerDeps };
@@ -0,0 +1,16 @@
1
+ import { prependSchemaDir, stageAndCompileProjectSchemas } from "../settings/schema.js";
2
+
3
+ const prepareDevSchemaDir = (root: string, dataDir: string | null): string | null => {
4
+ const dir = stageAndCompileProjectSchemas(root, dataDir);
5
+
6
+ if (dir === null) {
7
+ return null;
8
+ }
9
+
10
+ process.env.GTKX_DEV_SCHEMA_DIR = dir;
11
+ process.env.GSETTINGS_SCHEMA_DIR = prependSchemaDir(dir, process.env.GSETTINGS_SCHEMA_DIR);
12
+
13
+ return dir;
14
+ };
15
+
16
+ export { prepareDevSchemaDir };