@nifrajs/cli 3.5.0 → 4.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 (403) hide show
  1. package/README.md +42 -3
  2. package/dist/app-files.d.ts +11 -0
  3. package/dist/app-files.d.ts.map +1 -0
  4. package/dist/app-files.js +34 -0
  5. package/dist/app-files.js.map +1 -0
  6. package/dist/assure-hydration.d.ts +7 -1
  7. package/dist/assure-hydration.d.ts.map +1 -1
  8. package/dist/assure-hydration.js +128 -43
  9. package/dist/assure-hydration.js.map +1 -1
  10. package/dist/assure.d.ts.map +1 -1
  11. package/dist/assure.js +16 -2
  12. package/dist/assure.js.map +1 -1
  13. package/dist/capabilities-tool.d.ts +5 -1
  14. package/dist/capabilities-tool.d.ts.map +1 -1
  15. package/dist/capabilities-tool.js +32 -10
  16. package/dist/capabilities-tool.js.map +1 -1
  17. package/dist/cdn-check.d.ts +41 -0
  18. package/dist/cdn-check.d.ts.map +1 -0
  19. package/dist/cdn-check.js +207 -0
  20. package/dist/cdn-check.js.map +1 -0
  21. package/dist/check-diagnostics.d.ts +4 -0
  22. package/dist/check-diagnostics.d.ts.map +1 -1
  23. package/dist/check-diagnostics.js +13 -0
  24. package/dist/check-diagnostics.js.map +1 -1
  25. package/dist/check-scan.d.ts +49 -7
  26. package/dist/check-scan.d.ts.map +1 -1
  27. package/dist/check-scan.js +291 -62
  28. package/dist/check-scan.js.map +1 -1
  29. package/dist/check.d.ts.map +1 -1
  30. package/dist/check.js +99 -63
  31. package/dist/check.js.map +1 -1
  32. package/dist/cli.d.ts +42 -16
  33. package/dist/cli.d.ts.map +1 -1
  34. package/dist/cli.js +262 -82
  35. package/dist/cli.js.map +1 -1
  36. package/dist/command-catalog.d.ts +57 -5
  37. package/dist/command-catalog.d.ts.map +1 -1
  38. package/dist/command-catalog.js +270 -26
  39. package/dist/command-catalog.js.map +1 -1
  40. package/dist/config-target.d.ts +8 -0
  41. package/dist/config-target.d.ts.map +1 -0
  42. package/dist/config-target.js +45 -0
  43. package/dist/config-target.js.map +1 -0
  44. package/dist/contracts.d.ts.map +1 -1
  45. package/dist/contracts.js +52 -13
  46. package/dist/contracts.js.map +1 -1
  47. package/dist/db-audit.d.ts +37 -0
  48. package/dist/db-audit.d.ts.map +1 -0
  49. package/dist/db-audit.js +99 -0
  50. package/dist/db-audit.js.map +1 -0
  51. package/dist/db-child.d.ts +64 -0
  52. package/dist/db-child.d.ts.map +1 -0
  53. package/dist/db-child.js +213 -0
  54. package/dist/db-child.js.map +1 -0
  55. package/dist/db-config.d.ts +60 -0
  56. package/dist/db-config.d.ts.map +1 -0
  57. package/dist/db-config.js +176 -0
  58. package/dist/db-config.js.map +1 -0
  59. package/dist/db-tool.d.ts +84 -0
  60. package/dist/db-tool.d.ts.map +1 -0
  61. package/dist/db-tool.js +537 -0
  62. package/dist/db-tool.js.map +1 -0
  63. package/dist/dev-bun-config.d.ts +20 -13
  64. package/dist/dev-bun-config.d.ts.map +1 -1
  65. package/dist/dev-bun-config.js +98 -41
  66. package/dist/dev-bun-config.js.map +1 -1
  67. package/dist/dev-feed-tool.d.ts +106 -0
  68. package/dist/dev-feed-tool.d.ts.map +1 -0
  69. package/dist/dev-feed-tool.js +713 -0
  70. package/dist/dev-feed-tool.js.map +1 -0
  71. package/dist/dev-server-client.d.ts +67 -0
  72. package/dist/dev-server-client.d.ts.map +1 -0
  73. package/dist/dev-server-client.js +195 -0
  74. package/dist/dev-server-client.js.map +1 -0
  75. package/dist/diff-tool.d.ts +3 -3
  76. package/dist/diff-tool.d.ts.map +1 -1
  77. package/dist/diff-tool.js +6 -5
  78. package/dist/diff-tool.js.map +1 -1
  79. package/dist/docs-search.d.ts.map +1 -1
  80. package/dist/docs-search.js +12 -4
  81. package/dist/docs-search.js.map +1 -1
  82. package/dist/doctor.d.ts +17 -0
  83. package/dist/doctor.d.ts.map +1 -1
  84. package/dist/doctor.js +76 -15
  85. package/dist/doctor.js.map +1 -1
  86. package/dist/env-file.d.ts +15 -0
  87. package/dist/env-file.d.ts.map +1 -1
  88. package/dist/env-file.js +73 -1
  89. package/dist/env-file.js.map +1 -1
  90. package/dist/fix-recipes.d.ts.map +1 -1
  91. package/dist/fix-recipes.js +41 -21
  92. package/dist/fix-recipes.js.map +1 -1
  93. package/dist/frontend-guidance.js +5 -5
  94. package/dist/frontend-guidance.js.map +1 -1
  95. package/dist/i18n-check.d.ts +16 -0
  96. package/dist/i18n-check.d.ts.map +1 -0
  97. package/dist/i18n-check.js +154 -0
  98. package/dist/i18n-check.js.map +1 -0
  99. package/dist/init-agents.d.ts +49 -13
  100. package/dist/init-agents.d.ts.map +1 -1
  101. package/dist/init-agents.js +239 -34
  102. package/dist/init-agents.js.map +1 -1
  103. package/dist/internal/code-unit-order.d.ts +4 -0
  104. package/dist/internal/code-unit-order.d.ts.map +1 -0
  105. package/dist/internal/code-unit-order.js +6 -0
  106. package/dist/internal/code-unit-order.js.map +1 -0
  107. package/dist/internal/script-kind.d.ts +7 -0
  108. package/dist/internal/script-kind.d.ts.map +1 -0
  109. package/dist/internal/script-kind.js +12 -0
  110. package/dist/internal/script-kind.js.map +1 -0
  111. package/dist/internal/source-facts.d.ts +5 -0
  112. package/dist/internal/source-facts.d.ts.map +1 -1
  113. package/dist/internal/source-facts.js +61 -5
  114. package/dist/internal/source-facts.js.map +1 -1
  115. package/dist/internal/typescript-import.d.ts +49 -24
  116. package/dist/internal/typescript-import.d.ts.map +1 -1
  117. package/dist/internal/typescript-import.js +507 -67
  118. package/dist/internal/typescript-import.js.map +1 -1
  119. package/dist/introspect.d.ts +5 -1
  120. package/dist/introspect.d.ts.map +1 -1
  121. package/dist/introspect.js +92 -27
  122. package/dist/introspect.js.map +1 -1
  123. package/dist/learn.js +3 -3
  124. package/dist/learn.js.map +1 -1
  125. package/dist/levels-tool.d.ts +10 -0
  126. package/dist/levels-tool.d.ts.map +1 -1
  127. package/dist/levels-tool.js +33 -3
  128. package/dist/levels-tool.js.map +1 -1
  129. package/dist/load.d.ts +67 -17
  130. package/dist/load.d.ts.map +1 -1
  131. package/dist/load.js +78 -18
  132. package/dist/load.js.map +1 -1
  133. package/dist/manifest-tool.d.ts.map +1 -1
  134. package/dist/manifest-tool.js +3 -2
  135. package/dist/manifest-tool.js.map +1 -1
  136. package/dist/mcp-app-tool.d.ts.map +1 -1
  137. package/dist/mcp-app-tool.js +2 -0
  138. package/dist/mcp-app-tool.js.map +1 -1
  139. package/dist/mcp-context.js +1 -1
  140. package/dist/mcp-context.js.map +1 -1
  141. package/dist/mcp-delegate.d.ts +57 -0
  142. package/dist/mcp-delegate.d.ts.map +1 -0
  143. package/dist/mcp-delegate.js +130 -0
  144. package/dist/mcp-delegate.js.map +1 -0
  145. package/dist/mcp-docs-tools.d.ts.map +1 -1
  146. package/dist/mcp-docs-tools.js +23 -5
  147. package/dist/mcp-docs-tools.js.map +1 -1
  148. package/dist/mcp-exec.d.ts +2 -0
  149. package/dist/mcp-exec.d.ts.map +1 -1
  150. package/dist/mcp-exec.js +132 -108
  151. package/dist/mcp-exec.js.map +1 -1
  152. package/dist/mcp-http.d.ts.map +1 -1
  153. package/dist/mcp-http.js +17 -5
  154. package/dist/mcp-http.js.map +1 -1
  155. package/dist/mcp-io.d.ts +14 -0
  156. package/dist/mcp-io.d.ts.map +1 -1
  157. package/dist/mcp-io.js +45 -0
  158. package/dist/mcp-io.js.map +1 -1
  159. package/dist/mcp-isolate.d.ts +48 -0
  160. package/dist/mcp-isolate.d.ts.map +1 -0
  161. package/dist/mcp-isolate.js +222 -0
  162. package/dist/mcp-isolate.js.map +1 -0
  163. package/dist/mcp-project-child.d.ts +74 -0
  164. package/dist/mcp-project-child.d.ts.map +1 -0
  165. package/dist/mcp-project-child.js +130 -0
  166. package/dist/mcp-project-child.js.map +1 -0
  167. package/dist/mcp-render.js +2 -2
  168. package/dist/mcp-render.js.map +1 -1
  169. package/dist/mcp-root.d.ts +37 -9
  170. package/dist/mcp-root.d.ts.map +1 -1
  171. package/dist/mcp-root.js +110 -23
  172. package/dist/mcp-root.js.map +1 -1
  173. package/dist/mcp-run.d.ts +18 -1
  174. package/dist/mcp-run.d.ts.map +1 -1
  175. package/dist/mcp-run.js +82 -9
  176. package/dist/mcp-run.js.map +1 -1
  177. package/dist/mcp-ws.js +4 -1
  178. package/dist/mcp-ws.js.map +1 -1
  179. package/dist/mcp.d.ts +16 -3
  180. package/dist/mcp.d.ts.map +1 -1
  181. package/dist/mcp.js +81 -53
  182. package/dist/mcp.js.map +1 -1
  183. package/dist/migrate-layout.d.ts +44 -0
  184. package/dist/migrate-layout.d.ts.map +1 -0
  185. package/dist/migrate-layout.js +982 -0
  186. package/dist/migrate-layout.js.map +1 -0
  187. package/dist/openapi-tool.d.ts +2 -2
  188. package/dist/openapi-tool.d.ts.map +1 -1
  189. package/dist/openapi-tool.js.map +1 -1
  190. package/dist/openapi-types.d.ts +2 -1
  191. package/dist/openapi-types.d.ts.map +1 -1
  192. package/dist/openapi-types.js +240 -12
  193. package/dist/openapi-types.js.map +1 -1
  194. package/dist/pipeline-report.d.ts +3 -2
  195. package/dist/pipeline-report.d.ts.map +1 -1
  196. package/dist/pipeline-report.js +19 -16
  197. package/dist/pipeline-report.js.map +1 -1
  198. package/dist/port.d.ts +5 -4
  199. package/dist/port.d.ts.map +1 -1
  200. package/dist/port.js +46 -29
  201. package/dist/port.js.map +1 -1
  202. package/dist/project-facts.d.ts +5 -0
  203. package/dist/project-facts.d.ts.map +1 -1
  204. package/dist/project-facts.js.map +1 -1
  205. package/dist/recipes/4.0.0.d.ts +9 -0
  206. package/dist/recipes/4.0.0.d.ts.map +1 -0
  207. package/dist/recipes/4.0.0.js +34 -0
  208. package/dist/recipes/4.0.0.js.map +1 -0
  209. package/dist/recipes/index.d.ts.map +1 -1
  210. package/dist/recipes/index.js +2 -0
  211. package/dist/recipes/index.js.map +1 -1
  212. package/dist/release-verification.d.ts +11 -1
  213. package/dist/release-verification.d.ts.map +1 -1
  214. package/dist/release-verification.js +47 -4
  215. package/dist/release-verification.js.map +1 -1
  216. package/dist/review.d.ts.map +1 -1
  217. package/dist/review.js +12 -8
  218. package/dist/review.js.map +1 -1
  219. package/dist/route-types.d.ts +28 -0
  220. package/dist/route-types.d.ts.map +1 -0
  221. package/dist/route-types.js +106 -0
  222. package/dist/route-types.js.map +1 -0
  223. package/dist/rules/codes.d.ts +9 -0
  224. package/dist/rules/codes.d.ts.map +1 -1
  225. package/dist/rules/codes.js +9 -0
  226. package/dist/rules/codes.js.map +1 -1
  227. package/dist/rules/data-guard.d.ts +12 -0
  228. package/dist/rules/data-guard.d.ts.map +1 -0
  229. package/dist/rules/data-guard.js +213 -0
  230. package/dist/rules/data-guard.js.map +1 -0
  231. package/dist/rules/index.d.ts +3 -0
  232. package/dist/rules/index.d.ts.map +1 -1
  233. package/dist/rules/index.js +17 -5
  234. package/dist/rules/index.js.map +1 -1
  235. package/dist/rules/islands.d.ts.map +1 -1
  236. package/dist/rules/islands.js +7 -4
  237. package/dist/rules/islands.js.map +1 -1
  238. package/dist/rules/legacy.d.ts.map +1 -1
  239. package/dist/rules/legacy.js +71 -38
  240. package/dist/rules/legacy.js.map +1 -1
  241. package/dist/rules/nano.d.ts.map +1 -1
  242. package/dist/rules/nano.js +15 -6
  243. package/dist/rules/nano.js.map +1 -1
  244. package/dist/rules/pages.d.ts +15 -0
  245. package/dist/rules/pages.d.ts.map +1 -0
  246. package/dist/rules/pages.js +88 -0
  247. package/dist/rules/pages.js.map +1 -0
  248. package/dist/rules/routes.d.ts +11 -0
  249. package/dist/rules/routes.d.ts.map +1 -1
  250. package/dist/rules/routes.js +180 -2
  251. package/dist/rules/routes.js.map +1 -1
  252. package/dist/rules/secrets.d.ts +10 -0
  253. package/dist/rules/secrets.d.ts.map +1 -0
  254. package/dist/rules/secrets.js +169 -0
  255. package/dist/rules/secrets.js.map +1 -0
  256. package/dist/rules/security.d.ts +7 -0
  257. package/dist/rules/security.d.ts.map +1 -1
  258. package/dist/rules/security.js +171 -65
  259. package/dist/rules/security.js.map +1 -1
  260. package/dist/rules/typescript.d.ts +16 -0
  261. package/dist/rules/typescript.d.ts.map +1 -0
  262. package/dist/rules/typescript.js +59 -0
  263. package/dist/rules/typescript.js.map +1 -0
  264. package/dist/rules/zones.d.ts +17 -0
  265. package/dist/rules/zones.d.ts.map +1 -0
  266. package/dist/rules/zones.js +174 -0
  267. package/dist/rules/zones.js.map +1 -0
  268. package/dist/scaffold.d.ts +25 -12
  269. package/dist/scaffold.d.ts.map +1 -1
  270. package/dist/scaffold.js +132 -87
  271. package/dist/scaffold.js.map +1 -1
  272. package/dist/sdk.d.ts +17 -3
  273. package/dist/sdk.d.ts.map +1 -1
  274. package/dist/sdk.js +941 -153
  275. package/dist/sdk.js.map +1 -1
  276. package/dist/search-terms.d.ts +2 -0
  277. package/dist/search-terms.d.ts.map +1 -1
  278. package/dist/search-terms.js +23 -8
  279. package/dist/search-terms.js.map +1 -1
  280. package/dist/smoke.d.ts +79 -0
  281. package/dist/smoke.d.ts.map +1 -0
  282. package/dist/smoke.js +494 -0
  283. package/dist/smoke.js.map +1 -0
  284. package/dist/sync-manifest.d.ts.map +1 -1
  285. package/dist/sync-manifest.js +2 -1
  286. package/dist/sync-manifest.js.map +1 -1
  287. package/dist/sync-routes.d.ts +4 -3
  288. package/dist/sync-routes.d.ts.map +1 -1
  289. package/dist/sync-routes.js +4 -3
  290. package/dist/sync-routes.js.map +1 -1
  291. package/dist/test-tool.d.ts.map +1 -1
  292. package/dist/test-tool.js +30 -11
  293. package/dist/test-tool.js.map +1 -1
  294. package/dist/types-search.d.ts.map +1 -1
  295. package/dist/types-search.js +11 -5
  296. package/dist/types-search.js.map +1 -1
  297. package/dist/upgrade.d.ts +36 -6
  298. package/dist/upgrade.d.ts.map +1 -1
  299. package/dist/upgrade.js +167 -29
  300. package/dist/upgrade.js.map +1 -1
  301. package/dist/verification-plan.d.ts.map +1 -1
  302. package/dist/verification-plan.js +4 -0
  303. package/dist/verification-plan.js.map +1 -1
  304. package/dist/verification.d.ts.map +1 -1
  305. package/dist/verification.js +45 -12
  306. package/dist/verification.js.map +1 -1
  307. package/dist/web-app-options.d.ts +19 -0
  308. package/dist/web-app-options.d.ts.map +1 -0
  309. package/dist/web-app-options.js +49 -0
  310. package/dist/web-app-options.js.map +1 -0
  311. package/dist/work-graph.d.ts.map +1 -1
  312. package/dist/work-graph.js +29 -13
  313. package/dist/work-graph.js.map +1 -1
  314. package/docs/examples.json +185 -29
  315. package/docs/llms-full.txt +3807 -580
  316. package/docs/types.json +14229 -10939
  317. package/package.json +19 -12
  318. package/src/app-files.ts +40 -0
  319. package/src/assure-hydration.ts +139 -46
  320. package/src/assure.ts +17 -2
  321. package/src/capabilities-tool.ts +35 -9
  322. package/src/cdn-check.ts +268 -0
  323. package/src/check-diagnostics.ts +17 -0
  324. package/src/check-scan.ts +358 -63
  325. package/src/check.ts +97 -62
  326. package/src/cli.ts +296 -87
  327. package/src/command-catalog.ts +374 -38
  328. package/src/config-target.ts +47 -0
  329. package/src/contracts.ts +54 -12
  330. package/src/db-audit.ts +128 -0
  331. package/src/db-child.ts +285 -0
  332. package/src/db-config.ts +224 -0
  333. package/src/db-tool.ts +690 -0
  334. package/src/dev-bun-config.ts +116 -40
  335. package/src/dev-feed-tool.ts +912 -0
  336. package/src/dev-server-client.ts +267 -0
  337. package/src/diff-tool.ts +6 -5
  338. package/src/docs-search.ts +10 -3
  339. package/src/doctor.ts +98 -15
  340. package/src/env-file.ts +78 -1
  341. package/src/fix-recipes.ts +44 -31
  342. package/src/frontend-guidance.ts +5 -5
  343. package/src/i18n-check.ts +179 -0
  344. package/src/init-agents.ts +301 -38
  345. package/src/internal/code-unit-order.ts +5 -0
  346. package/src/internal/script-kind.ts +11 -0
  347. package/src/internal/source-facts.ts +96 -22
  348. package/src/internal/typescript-import.ts +663 -68
  349. package/src/introspect.ts +90 -27
  350. package/src/learn.ts +3 -3
  351. package/src/levels-tool.ts +47 -2
  352. package/src/load.ts +140 -33
  353. package/src/manifest-tool.ts +3 -2
  354. package/src/mcp-app-tool.ts +2 -0
  355. package/src/mcp-context.ts +1 -1
  356. package/src/mcp-delegate.ts +162 -0
  357. package/src/mcp-docs-tools.ts +23 -5
  358. package/src/mcp-exec.ts +160 -132
  359. package/src/mcp-http.ts +19 -5
  360. package/src/mcp-io.ts +57 -0
  361. package/src/mcp-isolate.ts +287 -0
  362. package/src/mcp-project-child.ts +182 -0
  363. package/src/mcp-render.ts +2 -2
  364. package/src/mcp-root.ts +117 -22
  365. package/src/mcp-run.ts +104 -10
  366. package/src/mcp-ws.ts +4 -1
  367. package/src/mcp.ts +106 -64
  368. package/src/migrate-layout.ts +1121 -0
  369. package/src/openapi-tool.ts +7 -3
  370. package/src/openapi-types.ts +315 -13
  371. package/src/pipeline-report.ts +22 -18
  372. package/src/port.ts +53 -30
  373. package/src/project-facts.ts +5 -0
  374. package/src/recipes/4.0.0.ts +35 -0
  375. package/src/recipes/index.ts +2 -0
  376. package/src/release-verification.ts +74 -5
  377. package/src/review.ts +13 -8
  378. package/src/route-types.ts +133 -0
  379. package/src/rules/codes.ts +9 -0
  380. package/src/rules/data-guard.ts +230 -0
  381. package/src/rules/index.ts +18 -5
  382. package/src/rules/islands.ts +12 -4
  383. package/src/rules/legacy.ts +71 -39
  384. package/src/rules/nano.ts +18 -6
  385. package/src/rules/pages.ts +99 -0
  386. package/src/rules/routes.ts +181 -2
  387. package/src/rules/secrets.ts +174 -0
  388. package/src/rules/security.ts +198 -70
  389. package/src/rules/typescript.ts +77 -0
  390. package/src/rules/zones.ts +195 -0
  391. package/src/scaffold.ts +147 -95
  392. package/src/sdk.ts +1215 -158
  393. package/src/search-terms.ts +24 -7
  394. package/src/smoke.ts +607 -0
  395. package/src/sync-manifest.ts +2 -1
  396. package/src/sync-routes.ts +4 -3
  397. package/src/test-tool.ts +32 -11
  398. package/src/types-search.ts +11 -4
  399. package/src/upgrade.ts +205 -25
  400. package/src/verification-plan.ts +13 -0
  401. package/src/verification.ts +50 -12
  402. package/src/web-app-options.ts +57 -0
  403. package/src/work-graph.ts +27 -13
@@ -7,8 +7,12 @@
7
7
  */
8
8
  import { resolve } from "node:path";
9
9
  import { formatAssuranceReport } from "./assure.js";
10
+ import { cdnCheckSpec } from "./cdn-check.js";
10
11
  import { renderCheckReport } from "./check.js";
12
+ import { dbAuditSpec, dbQuerySpec, dbRoleSpec, dbSchemaSpec } from "./db-tool.js";
13
+ import { errorsSpec, logsSpec } from "./dev-feed-tool.js";
11
14
  import { diagnostic, normalizeSeverity, toSarifLog } from "./diagnostics.js";
15
+ import { i18nCheckPassed, renderI18nCheck } from "./i18n-check.js";
12
16
  import { collectPortResult, renderReport } from "./port.js";
13
17
  import { reviewSpec } from "./review.js";
14
18
  import { collectProjectWorkGraph, renderWorkGraphText, } from "./work-graph.js";
@@ -29,6 +33,17 @@ export function toCommandCatalogEntry(spec) {
29
33
  outputVersion: spec.output.version,
30
34
  transports: Object.freeze([...spec.transports]),
31
35
  stability: spec.stability,
36
+ cliOnlyFields: Object.freeze([...(spec.cliOnlyFields ?? [])]),
37
+ });
38
+ }
39
+ /** The input schema a command's MCP tool advertises: its catalog schema without CLI-only fields. */
40
+ export function commandMcpInputSchema(entry) {
41
+ const properties = entry.inputSchema.properties;
42
+ if (entry.cliOnlyFields.length === 0 || typeof properties !== "object" || properties === null)
43
+ return entry.inputSchema;
44
+ return freezeJson({
45
+ ...entry.inputSchema,
46
+ properties: Object.fromEntries(Object.entries(properties).filter(([key]) => !entry.cliOnlyFields.includes(key))),
32
47
  });
33
48
  }
34
49
  function record(value) {
@@ -314,23 +329,45 @@ const FIX_SCHEMA = input(objectSchema({ code: { type: "string" }, json: { type:
314
329
  };
315
330
  });
316
331
  const MIGRATE_SCHEMA = input(objectSchema({
332
+ kind: { type: "string", enum: ["layout"] },
317
333
  from: { type: "string", enum: ["tailwind"] },
318
334
  to: { type: "string", enum: ["stylex"] },
319
335
  write: { type: "boolean" },
320
336
  json: { type: "boolean" },
321
337
  dir: { type: "string" },
322
- }, ["from", "to"]), (value) => {
338
+ }), (value) => {
323
339
  const raw = withDir(record(value));
340
+ const flags = {
341
+ ...parseBooleanFlags(raw, ["write", "json"]),
342
+ ...(raw.dir === undefined ? {} : { dir: raw.dir }),
343
+ };
344
+ const kind = optionalString(raw.kind, "kind");
345
+ if (kind !== undefined) {
346
+ if (kind !== "layout")
347
+ throw new TypeError("the migration must be `layout` (or --from tailwind --to stylex)");
348
+ return { kind, ...flags };
349
+ }
324
350
  const from = optionalString(raw.from, "from");
325
351
  const to = optionalString(raw.to, "to");
326
352
  if (from !== "tailwind")
327
353
  throw new TypeError("from must be tailwind");
328
354
  if (to !== "stylex")
329
355
  throw new TypeError("to must be stylex");
356
+ return { from, to, ...flags };
357
+ });
358
+ const TARGET_SCHEMA = input(objectSchema({ target: { type: "string" }, json: { type: "boolean" }, dir: { type: "string" } }), (value) => {
359
+ const raw = withDir(record(value));
360
+ const target = optionalString(raw.target, "target");
330
361
  return {
331
- from,
332
- to,
333
- ...parseBooleanFlags(raw, ["write", "json"]),
362
+ ...parseBooleanFlags(raw, ["json"]),
363
+ ...(raw.dir === undefined ? {} : { dir: raw.dir }),
364
+ ...(target === undefined ? {} : { target }),
365
+ };
366
+ });
367
+ const TYPES_SCHEMA = input(objectSchema({ check: { type: "boolean" }, json: { type: "boolean" }, dir: { type: "string" } }), (value) => {
368
+ const raw = withDir(record(value));
369
+ return {
370
+ ...parseBooleanFlags(raw, ["check", "json"]),
334
371
  ...(raw.dir === undefined ? {} : { dir: raw.dir }),
335
372
  };
336
373
  });
@@ -421,6 +458,39 @@ const PORT_SCHEMA = input(objectSchema({
421
458
  ...(raw.dir === undefined ? {} : { dir: raw.dir }),
422
459
  };
423
460
  });
461
+ const SMOKE_SCHEMA = input(objectSchema({
462
+ fixture: { type: "string" },
463
+ inProcess: { type: "boolean" },
464
+ json: { type: "boolean" },
465
+ dir: { type: "string" },
466
+ }), (value) => {
467
+ const raw = withDir(record(value));
468
+ return {
469
+ fixture: optionalString(raw.fixture, "fixture"),
470
+ ...parseBooleanFlags(raw, ["inProcess", "json"]),
471
+ ...(raw.dir === undefined ? {} : { dir: raw.dir }),
472
+ };
473
+ });
474
+ const I18N_SCHEMA = input(objectSchema({
475
+ action: { type: "string", enum: ["check"] },
476
+ entry: { type: "string" },
477
+ json: { type: "boolean" },
478
+ strict: { type: "boolean" },
479
+ dir: { type: "string" },
480
+ }, ["action"]), (value) => {
481
+ const raw = withDir(record(value));
482
+ if (raw.action !== "check") {
483
+ throw new TypeError(raw.action === undefined
484
+ ? "i18n needs an action: nifra i18n check [entry]"
485
+ : `unknown i18n action: ${String(raw.action)} (the one action is check)`);
486
+ }
487
+ return {
488
+ action: "check",
489
+ entry: optionalString(raw.entry, "entry"),
490
+ ...parseBooleanFlags(raw, ["json", "strict"]),
491
+ ...(raw.dir === undefined ? {} : { dir: raw.dir }),
492
+ };
493
+ });
424
494
  function loadAppFor(ctx) {
425
495
  if (ctx.loadApp !== undefined)
426
496
  return ctx.loadApp();
@@ -600,6 +670,8 @@ const manifestSpec = {
600
670
  output: output({ type: "object" }),
601
671
  transports: ["cli", "mcp"],
602
672
  stability: "stable",
673
+ // The signer is the operator's KMS/HSM callback; an agent signing its own manifest defeats it.
674
+ cliOnlyFields: ["sign"],
603
675
  argv: {
604
676
  positionals: ["action", "before", "after"],
605
677
  flags: [
@@ -724,7 +796,9 @@ const openApiSpec = {
724
796
  ],
725
797
  },
726
798
  async run(value, ctx) {
727
- const app = await loadAppFor(ctx);
799
+ const app = ctx.loadApp !== undefined
800
+ ? await ctx.loadApp()
801
+ : await import("./load.js").then(({ loadBackendApp }) => loadBackendApp(ctx.cwd));
728
802
  const { renderOpenApiWithTypes } = await import("./openapi-tool.js");
729
803
  const format = value.format ?? "json";
730
804
  return {
@@ -838,12 +912,13 @@ const fixSpec = {
838
912
  };
839
913
  const migrateSpec = {
840
914
  name: "migrate",
841
- summary: "Migrate safe static Tailwind className utilities to native StyleX props.",
915
+ summary: "Move an app onto the frontend/backend split (`migrate layout`), or migrate static Tailwind utilities to StyleX.",
842
916
  input: MIGRATE_SCHEMA,
843
917
  output: output({
844
918
  type: "object",
845
919
  properties: {
846
920
  ok: { type: "boolean" },
921
+ kind: { type: "string" },
847
922
  from: { type: "string" },
848
923
  to: { type: "string" },
849
924
  write: { type: "boolean" },
@@ -852,12 +927,16 @@ const migrateSpec = {
852
927
  written: { type: "array" },
853
928
  issues: { type: "array" },
854
929
  files: { type: "array" },
930
+ splits: { type: "array" },
931
+ moves: { type: "array" },
932
+ rewritten: { type: "array" },
855
933
  },
856
- required: ["ok", "from", "to", "write", "scanned", "changed", "written", "issues", "files"],
934
+ required: ["ok", "write", "issues"],
857
935
  }),
858
936
  transports: ["cli"],
859
937
  stability: "stable",
860
938
  argv: {
939
+ positionals: ["kind"],
861
940
  flags: [
862
941
  { name: "from", field: "from", type: "string" },
863
942
  { name: "to", field: "to", type: "string" },
@@ -867,27 +946,134 @@ const migrateSpec = {
867
946
  ],
868
947
  },
869
948
  async run(value, ctx) {
949
+ const dir = resolve(ctx.cwd, value.dir ?? ".");
950
+ const write = value.write === undefined ? {} : { write: value.write };
951
+ if (value.kind === "layout") {
952
+ const { migrateLayout } = await import("./migrate-layout.js");
953
+ return { kind: "layout", ...(await migrateLayout(dir, write)) };
954
+ }
870
955
  const { migrateTailwindToStylex } = await import("./stylex-migrate.js");
871
- return migrateTailwindToStylex(resolve(ctx.cwd, value.dir ?? "."), {
872
- ...(value.write === undefined ? {} : { write: value.write }),
873
- });
956
+ return migrateTailwindToStylex(dir, write);
874
957
  },
875
- render: (out) => [
876
- out.ok
877
- ? `✓ migrated ${out.changed.length} file${out.changed.length === 1 ? "" : "s"}`
878
- : `⚠ migrated ${out.changed.length} safe file${out.changed.length === 1 ? "" : "s"}; ${out.issues.length} manual issue${out.issues.length === 1 ? "" : "s"} remain`,
879
- ` scanned ${out.scanned} source file${out.scanned === 1 ? "" : "s"}`,
880
- ...(out.write
881
- ? [` wrote ${out.written.length} file${out.written.length === 1 ? "" : "s"}`]
882
- : out.changed.length > 0
883
- ? [" dry run: pass --write to apply the safe changes"]
958
+ render: (out) => {
959
+ if (out.kind === "layout") {
960
+ return [
961
+ out.ok
962
+ ? `✓ ${out.splits.length} route file${out.splits.length === 1 ? "" : "s"} split, ${out.moves.length} file${out.moves.length === 1 ? "" : "s"} moved`
963
+ : `⚠ ${out.issues.length} issue${out.issues.length === 1 ? "" : "s"} need a decision; everything else is planned`,
964
+ ...out.splits.map((split) => ` split ${split.file} → ${split.backend} (${split.moved.join(", ")})`),
965
+ ...out.moves.map((move) => ` move ${move.from} → ${move.to}`),
966
+ ...out.rewritten.map((file) => ` edit ${file} (imports)`),
967
+ ...out.issues.map((issue) => ` ⚠ ${issue.file}: ${issue.reason}`),
968
+ ...(out.write ? [] : [" dry run: pass --write to apply"]),
969
+ ];
970
+ }
971
+ return [
972
+ out.ok
973
+ ? `✓ migrated ${out.changed.length} file${out.changed.length === 1 ? "" : "s"}`
974
+ : `⚠ migrated ${out.changed.length} safe file${out.changed.length === 1 ? "" : "s"}; ${out.issues.length} manual issue${out.issues.length === 1 ? "" : "s"} remain`,
975
+ ` scanned ${out.scanned} source file${out.scanned === 1 ? "" : "s"}`,
976
+ ...(out.write
977
+ ? [` wrote ${out.written.length} file${out.written.length === 1 ? "" : "s"}`]
978
+ : out.changed.length > 0
979
+ ? [" dry run: pass --write to apply the safe changes"]
980
+ : []),
981
+ ...out.issues
982
+ .slice(0, 30)
983
+ .map((issue) => ` ${issue.file}:${issue.line} ${issue.token} — ${issue.reason}`),
984
+ ...(out.issues.length > 30
985
+ ? [` … ${out.issues.length - 30} more issue${out.issues.length - 30 === 1 ? "" : "s"}`]
884
986
  : []),
885
- ...out.issues
886
- .slice(0, 30)
887
- .map((issue) => ` ${issue.file}:${issue.line} ${issue.token} — ${issue.reason}`),
888
- ...(out.issues.length > 30
889
- ? [` … ${out.issues.length - 30} more issue${out.issues.length - 30 === 1 ? "" : "s"}`]
890
- : []),
987
+ ];
988
+ },
989
+ success: (out) => out.ok,
990
+ };
991
+ const targetSpec = {
992
+ name: "target",
993
+ summary: "Show the app's deploy target, or switch it (`nifra target cloudflare`): the `target` `nifra build` emits, kept in nifra.config.ts.",
994
+ input: TARGET_SCHEMA,
995
+ output: output({
996
+ type: "object",
997
+ properties: {
998
+ ok: { type: "boolean" },
999
+ target: { type: "string" },
1000
+ previous: { type: "string" },
1001
+ changed: { type: "boolean" },
1002
+ run: { type: "string" },
1003
+ },
1004
+ required: ["ok", "target", "changed", "run"],
1005
+ }),
1006
+ transports: ["cli"],
1007
+ stability: "stable",
1008
+ argv: {
1009
+ positionals: ["target"],
1010
+ flags: [
1011
+ { name: "json", field: "json", type: "boolean" },
1012
+ { name: "dir", field: "dir", type: "string" },
1013
+ ],
1014
+ },
1015
+ async run(value, ctx) {
1016
+ const dir = resolve(ctx.cwd, value.dir ?? ".");
1017
+ const { parseBuildTarget, planBuildTarget } = await import("@nifrajs/web/build");
1018
+ const { readConfigTarget, writeConfigTarget } = await import("./config-target.js");
1019
+ const current = readConfigTarget(dir);
1020
+ const target = parseBuildTarget(value.target ?? current ?? "bun", value.target === undefined ? "target in nifra.config.ts" : "target");
1021
+ const changed = value.target !== undefined && value.target !== current;
1022
+ if (changed)
1023
+ writeConfigTarget(dir, target);
1024
+ return {
1025
+ ok: true,
1026
+ target,
1027
+ ...(changed && current !== undefined ? { previous: current } : {}),
1028
+ changed,
1029
+ run: planBuildTarget(target, "dist").run,
1030
+ };
1031
+ },
1032
+ render: (out) => [
1033
+ out.changed
1034
+ ? `✓ target: ${out.target}${out.previous === undefined ? "" : ` (was ${out.previous})`}`
1035
+ : `target: ${out.target}`,
1036
+ ` nifra build → ${out.run}`,
1037
+ ],
1038
+ success: (out) => out.ok,
1039
+ };
1040
+ const typesSpec = {
1041
+ name: "types",
1042
+ summary: "Generate each route's `./+types` module (params, schema-typed data, typed `api`); `--check` fails when one is stale.",
1043
+ input: TYPES_SCHEMA,
1044
+ output: output({
1045
+ type: "object",
1046
+ properties: {
1047
+ ok: { type: "boolean" },
1048
+ check: { type: "boolean" },
1049
+ written: { type: "array" },
1050
+ removed: { type: "array" },
1051
+ stale: { type: "array" },
1052
+ tsconfig: { type: "string" },
1053
+ },
1054
+ required: ["ok", "check", "written", "removed", "stale"],
1055
+ }),
1056
+ transports: ["cli"],
1057
+ stability: "stable",
1058
+ argv: {
1059
+ flags: [
1060
+ { name: "check", field: "check", type: "boolean" },
1061
+ { name: "json", field: "json", type: "boolean" },
1062
+ { name: "dir", field: "dir", type: "string" },
1063
+ ],
1064
+ },
1065
+ async run(value, ctx) {
1066
+ const { routeTypes } = await import("./route-types.js");
1067
+ return routeTypes(resolve(ctx.cwd, value.dir ?? "."), { check: value.check === true });
1068
+ },
1069
+ render: (out) => [
1070
+ out.check
1071
+ ? out.ok
1072
+ ? "✓ route types are up to date"
1073
+ : `✖ ${out.stale.length} route type file${out.stale.length === 1 ? " is" : "s are"} stale - run \`nifra types\``
1074
+ : `✓ route types: ${out.written.length} written, ${out.removed.length} removed`,
1075
+ ...out.stale.map((file) => ` stale ${file}`),
1076
+ ...(out.tsconfig === undefined ? [] : [` ⚠ ${out.tsconfig}`]),
891
1077
  ],
892
1078
  success: (out) => out.ok,
893
1079
  };
@@ -1068,6 +1254,28 @@ const replaySpec = {
1068
1254
  render: (out) => [JSON.stringify(out, null, 2)],
1069
1255
  success: (out) => out.ok,
1070
1256
  };
1257
+ const smokeSpec = {
1258
+ name: "smoke",
1259
+ summary: "Run the declared production SSR, mounted-API, 404, header, auth, contract, and hydration smoke checks.",
1260
+ input: SMOKE_SCHEMA,
1261
+ output: output({ type: "object" }),
1262
+ transports: ["cli", "mcp"],
1263
+ stability: "stable",
1264
+ argv: {
1265
+ flags: [
1266
+ { name: "fixture", field: "fixture", type: "string" },
1267
+ { name: "in-process", field: "inProcess", type: "boolean" },
1268
+ { name: "json", field: "json", type: "boolean" },
1269
+ ],
1270
+ },
1271
+ async run(value, ctx) {
1272
+ const { loadSmokeFixture, runSmoke } = await import("./smoke.js");
1273
+ const fixture = await loadSmokeFixture(ctx.cwd, value.fixture);
1274
+ return runSmoke(fixture, { inProcess: value.inProcess === true });
1275
+ },
1276
+ render: (out) => out.checks.map((check) => `${check.status === "pass" ? "✓" : check.status === "skip" ? "•" : "✖"} ${check.id}${check.message === undefined ? "" : ` - ${check.message}`}`),
1277
+ success: (out) => out.ok,
1278
+ };
1071
1279
  const portSpec = {
1072
1280
  name: "port",
1073
1281
  summary: "Print a feature by deploy-target portability matrix with file:line evidence and gate against an unsupported target.",
@@ -1096,7 +1304,7 @@ const portSpec = {
1096
1304
  return [
1097
1305
  report,
1098
1306
  "",
1099
- "[nifra] --ci needs a deploy target to gate against, and none was detected. Pass --target <bun|node|deno|cf-pages|vercel>.",
1307
+ "[nifra] --ci needs a deploy target to gate against, and none was detected. Pass --target <bun|node|deno|cloudflare|vercel>.",
1100
1308
  ];
1101
1309
  return [report];
1102
1310
  },
@@ -1110,6 +1318,31 @@ const portSpec = {
1110
1318
  },
1111
1319
  json: (out) => out.json,
1112
1320
  };
1321
+ // CLI only: it imports app code (the catalogs), which a long-lived MCP server process would cache.
1322
+ const i18nSpec = {
1323
+ name: "i18n",
1324
+ summary: "Check i18n catalogs (imports the module exporting `locales` and `catalogs`): coverage, missing and unused keys, ICU syntax, placeholder and tag parity, plural cases, script purity, untranslated messages.",
1325
+ input: I18N_SCHEMA,
1326
+ output: output({ type: "object" }),
1327
+ transports: ["cli"],
1328
+ stability: "stable",
1329
+ argv: {
1330
+ positionals: ["action", "entry"],
1331
+ flags: [
1332
+ { name: "json", field: "json", type: "boolean" },
1333
+ { name: "strict", field: "strict", type: "boolean" },
1334
+ ],
1335
+ },
1336
+ async run(value, ctx) {
1337
+ const { runI18nCheck } = await import("./i18n-check.js");
1338
+ return runI18nCheck(value.dir === undefined ? ctx.cwd : resolve(ctx.cwd, value.dir), {
1339
+ entry: value.entry,
1340
+ });
1341
+ },
1342
+ render: (out) => renderI18nCheck(out),
1343
+ success: (out, input) => i18nCheckPassed(out, input.strict === true),
1344
+ json: (out) => out,
1345
+ };
1113
1346
  export const commandSpecs = Object.freeze([
1114
1347
  checkSpec,
1115
1348
  reviewSpec,
@@ -1123,6 +1356,8 @@ export const commandSpecs = Object.freeze([
1123
1356
  doctorSpec,
1124
1357
  fixSpec,
1125
1358
  migrateSpec,
1359
+ targetSpec,
1360
+ typesSpec,
1126
1361
  snapshotSpec,
1127
1362
  diffSpec,
1128
1363
  contractsSpec,
@@ -1130,7 +1365,16 @@ export const commandSpecs = Object.freeze([
1130
1365
  syncRoutesSpec,
1131
1366
  proveSpec,
1132
1367
  replaySpec,
1368
+ smokeSpec,
1133
1369
  portSpec,
1370
+ i18nSpec,
1371
+ errorsSpec,
1372
+ logsSpec,
1373
+ cdnCheckSpec,
1374
+ dbSchemaSpec,
1375
+ dbQuerySpec,
1376
+ dbRoleSpec,
1377
+ dbAuditSpec,
1134
1378
  ]);
1135
1379
  const commandByName = new Map(commandSpecs.map((spec) => [spec.name, spec]));
1136
1380
  export function findCommandSpec(name) {