@nifrajs/cli 3.5.0 → 4.0.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 (404) 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 +62 -5
  37. package/dist/command-catalog.d.ts.map +1 -1
  38. package/dist/command-catalog.js +275 -35
  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 +48 -22
  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 +1155 -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 +36 -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 +10 -2
  285. package/dist/sync-manifest.d.ts.map +1 -1
  286. package/dist/sync-manifest.js +44 -19
  287. package/dist/sync-manifest.js.map +1 -1
  288. package/dist/sync-routes.d.ts +4 -3
  289. package/dist/sync-routes.d.ts.map +1 -1
  290. package/dist/sync-routes.js +4 -3
  291. package/dist/sync-routes.js.map +1 -1
  292. package/dist/test-tool.d.ts.map +1 -1
  293. package/dist/test-tool.js +30 -11
  294. package/dist/test-tool.js.map +1 -1
  295. package/dist/types-search.d.ts.map +1 -1
  296. package/dist/types-search.js +11 -5
  297. package/dist/types-search.js.map +1 -1
  298. package/dist/upgrade.d.ts +36 -6
  299. package/dist/upgrade.d.ts.map +1 -1
  300. package/dist/upgrade.js +167 -29
  301. package/dist/upgrade.js.map +1 -1
  302. package/dist/verification-plan.d.ts.map +1 -1
  303. package/dist/verification-plan.js +4 -0
  304. package/dist/verification-plan.js.map +1 -1
  305. package/dist/verification.d.ts.map +1 -1
  306. package/dist/verification.js +45 -12
  307. package/dist/verification.js.map +1 -1
  308. package/dist/web-app-options.d.ts +19 -0
  309. package/dist/web-app-options.d.ts.map +1 -0
  310. package/dist/web-app-options.js +49 -0
  311. package/dist/web-app-options.js.map +1 -0
  312. package/dist/work-graph.d.ts.map +1 -1
  313. package/dist/work-graph.js +29 -13
  314. package/dist/work-graph.js.map +1 -1
  315. package/docs/examples.json +185 -29
  316. package/docs/llms-full.txt +3807 -580
  317. package/docs/types.json +14229 -10939
  318. package/package.json +19 -12
  319. package/src/app-files.ts +40 -0
  320. package/src/assure-hydration.ts +139 -46
  321. package/src/assure.ts +17 -2
  322. package/src/capabilities-tool.ts +35 -9
  323. package/src/cdn-check.ts +268 -0
  324. package/src/check-diagnostics.ts +17 -0
  325. package/src/check-scan.ts +358 -63
  326. package/src/check.ts +97 -62
  327. package/src/cli.ts +296 -87
  328. package/src/command-catalog.ts +389 -48
  329. package/src/config-target.ts +47 -0
  330. package/src/contracts.ts +54 -12
  331. package/src/db-audit.ts +128 -0
  332. package/src/db-child.ts +285 -0
  333. package/src/db-config.ts +224 -0
  334. package/src/db-tool.ts +690 -0
  335. package/src/dev-bun-config.ts +116 -40
  336. package/src/dev-feed-tool.ts +912 -0
  337. package/src/dev-server-client.ts +267 -0
  338. package/src/diff-tool.ts +6 -5
  339. package/src/docs-search.ts +10 -3
  340. package/src/doctor.ts +98 -15
  341. package/src/env-file.ts +78 -1
  342. package/src/fix-recipes.ts +53 -32
  343. package/src/frontend-guidance.ts +5 -5
  344. package/src/i18n-check.ts +179 -0
  345. package/src/init-agents.ts +301 -38
  346. package/src/internal/code-unit-order.ts +5 -0
  347. package/src/internal/script-kind.ts +11 -0
  348. package/src/internal/source-facts.ts +96 -22
  349. package/src/internal/typescript-import.ts +663 -68
  350. package/src/introspect.ts +90 -27
  351. package/src/learn.ts +3 -3
  352. package/src/levels-tool.ts +47 -2
  353. package/src/load.ts +140 -33
  354. package/src/manifest-tool.ts +3 -2
  355. package/src/mcp-app-tool.ts +2 -0
  356. package/src/mcp-context.ts +1 -1
  357. package/src/mcp-delegate.ts +162 -0
  358. package/src/mcp-docs-tools.ts +23 -5
  359. package/src/mcp-exec.ts +160 -132
  360. package/src/mcp-http.ts +19 -5
  361. package/src/mcp-io.ts +57 -0
  362. package/src/mcp-isolate.ts +287 -0
  363. package/src/mcp-project-child.ts +182 -0
  364. package/src/mcp-render.ts +2 -2
  365. package/src/mcp-root.ts +117 -22
  366. package/src/mcp-run.ts +104 -10
  367. package/src/mcp-ws.ts +4 -1
  368. package/src/mcp.ts +106 -64
  369. package/src/migrate-layout.ts +1338 -0
  370. package/src/openapi-tool.ts +7 -3
  371. package/src/openapi-types.ts +315 -13
  372. package/src/pipeline-report.ts +22 -18
  373. package/src/port.ts +53 -30
  374. package/src/project-facts.ts +5 -0
  375. package/src/recipes/4.0.0.ts +37 -0
  376. package/src/recipes/index.ts +2 -0
  377. package/src/release-verification.ts +74 -5
  378. package/src/review.ts +13 -8
  379. package/src/route-types.ts +133 -0
  380. package/src/rules/codes.ts +9 -0
  381. package/src/rules/data-guard.ts +230 -0
  382. package/src/rules/index.ts +18 -5
  383. package/src/rules/islands.ts +12 -4
  384. package/src/rules/legacy.ts +71 -39
  385. package/src/rules/nano.ts +18 -6
  386. package/src/rules/pages.ts +99 -0
  387. package/src/rules/routes.ts +181 -2
  388. package/src/rules/secrets.ts +174 -0
  389. package/src/rules/security.ts +198 -70
  390. package/src/rules/typescript.ts +77 -0
  391. package/src/rules/zones.ts +195 -0
  392. package/src/scaffold.ts +147 -95
  393. package/src/sdk.ts +1215 -158
  394. package/src/search-terms.ts +24 -7
  395. package/src/smoke.ts +607 -0
  396. package/src/sync-manifest.ts +50 -19
  397. package/src/sync-routes.ts +4 -3
  398. package/src/test-tool.ts +32 -11
  399. package/src/types-search.ts +11 -4
  400. package/src/upgrade.ts +205 -25
  401. package/src/verification-plan.ts +13 -0
  402. package/src/verification.ts +50 -12
  403. package/src/web-app-options.ts +57 -0
  404. package/src/work-graph.ts +27 -13
@@ -7,10 +7,15 @@
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";
18
+ import { renderSyncManifestResults, syncManifestsOk, syncServerManifests, } from "./sync-manifest.js";
14
19
  import { collectProjectWorkGraph, renderWorkGraphText, } from "./work-graph.js";
15
20
  function freezeJson(value) {
16
21
  if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
@@ -29,6 +34,17 @@ export function toCommandCatalogEntry(spec) {
29
34
  outputVersion: spec.output.version,
30
35
  transports: Object.freeze([...spec.transports]),
31
36
  stability: spec.stability,
37
+ cliOnlyFields: Object.freeze([...(spec.cliOnlyFields ?? [])]),
38
+ });
39
+ }
40
+ /** The input schema a command's MCP tool advertises: its catalog schema without CLI-only fields. */
41
+ export function commandMcpInputSchema(entry) {
42
+ const properties = entry.inputSchema.properties;
43
+ if (entry.cliOnlyFields.length === 0 || typeof properties !== "object" || properties === null)
44
+ return entry.inputSchema;
45
+ return freezeJson({
46
+ ...entry.inputSchema,
47
+ properties: Object.fromEntries(Object.entries(properties).filter(([key]) => !entry.cliOnlyFields.includes(key))),
32
48
  });
33
49
  }
34
50
  function record(value) {
@@ -314,23 +330,45 @@ const FIX_SCHEMA = input(objectSchema({ code: { type: "string" }, json: { type:
314
330
  };
315
331
  });
316
332
  const MIGRATE_SCHEMA = input(objectSchema({
333
+ kind: { type: "string", enum: ["layout"] },
317
334
  from: { type: "string", enum: ["tailwind"] },
318
335
  to: { type: "string", enum: ["stylex"] },
319
336
  write: { type: "boolean" },
320
337
  json: { type: "boolean" },
321
338
  dir: { type: "string" },
322
- }, ["from", "to"]), (value) => {
339
+ }), (value) => {
323
340
  const raw = withDir(record(value));
341
+ const flags = {
342
+ ...parseBooleanFlags(raw, ["write", "json"]),
343
+ ...(raw.dir === undefined ? {} : { dir: raw.dir }),
344
+ };
345
+ const kind = optionalString(raw.kind, "kind");
346
+ if (kind !== undefined) {
347
+ if (kind !== "layout")
348
+ throw new TypeError("the migration must be `layout` (or --from tailwind --to stylex)");
349
+ return { kind, ...flags };
350
+ }
324
351
  const from = optionalString(raw.from, "from");
325
352
  const to = optionalString(raw.to, "to");
326
353
  if (from !== "tailwind")
327
354
  throw new TypeError("from must be tailwind");
328
355
  if (to !== "stylex")
329
356
  throw new TypeError("to must be stylex");
357
+ return { from, to, ...flags };
358
+ });
359
+ const TARGET_SCHEMA = input(objectSchema({ target: { type: "string" }, json: { type: "boolean" }, dir: { type: "string" } }), (value) => {
360
+ const raw = withDir(record(value));
361
+ const target = optionalString(raw.target, "target");
330
362
  return {
331
- from,
332
- to,
333
- ...parseBooleanFlags(raw, ["write", "json"]),
363
+ ...parseBooleanFlags(raw, ["json"]),
364
+ ...(raw.dir === undefined ? {} : { dir: raw.dir }),
365
+ ...(target === undefined ? {} : { target }),
366
+ };
367
+ });
368
+ const TYPES_SCHEMA = input(objectSchema({ check: { type: "boolean" }, json: { type: "boolean" }, dir: { type: "string" } }), (value) => {
369
+ const raw = withDir(record(value));
370
+ return {
371
+ ...parseBooleanFlags(raw, ["check", "json"]),
334
372
  ...(raw.dir === undefined ? {} : { dir: raw.dir }),
335
373
  };
336
374
  });
@@ -421,6 +459,39 @@ const PORT_SCHEMA = input(objectSchema({
421
459
  ...(raw.dir === undefined ? {} : { dir: raw.dir }),
422
460
  };
423
461
  });
462
+ const SMOKE_SCHEMA = input(objectSchema({
463
+ fixture: { type: "string" },
464
+ inProcess: { type: "boolean" },
465
+ json: { type: "boolean" },
466
+ dir: { type: "string" },
467
+ }), (value) => {
468
+ const raw = withDir(record(value));
469
+ return {
470
+ fixture: optionalString(raw.fixture, "fixture"),
471
+ ...parseBooleanFlags(raw, ["inProcess", "json"]),
472
+ ...(raw.dir === undefined ? {} : { dir: raw.dir }),
473
+ };
474
+ });
475
+ const I18N_SCHEMA = input(objectSchema({
476
+ action: { type: "string", enum: ["check"] },
477
+ entry: { type: "string" },
478
+ json: { type: "boolean" },
479
+ strict: { type: "boolean" },
480
+ dir: { type: "string" },
481
+ }, ["action"]), (value) => {
482
+ const raw = withDir(record(value));
483
+ if (raw.action !== "check") {
484
+ throw new TypeError(raw.action === undefined
485
+ ? "i18n needs an action: nifra i18n check [entry]"
486
+ : `unknown i18n action: ${String(raw.action)} (the one action is check)`);
487
+ }
488
+ return {
489
+ action: "check",
490
+ entry: optionalString(raw.entry, "entry"),
491
+ ...parseBooleanFlags(raw, ["json", "strict"]),
492
+ ...(raw.dir === undefined ? {} : { dir: raw.dir }),
493
+ };
494
+ });
424
495
  function loadAppFor(ctx) {
425
496
  if (ctx.loadApp !== undefined)
426
497
  return ctx.loadApp();
@@ -600,6 +671,8 @@ const manifestSpec = {
600
671
  output: output({ type: "object" }),
601
672
  transports: ["cli", "mcp"],
602
673
  stability: "stable",
674
+ // The signer is the operator's KMS/HSM callback; an agent signing its own manifest defeats it.
675
+ cliOnlyFields: ["sign"],
603
676
  argv: {
604
677
  positionals: ["action", "before", "after"],
605
678
  flags: [
@@ -724,7 +797,9 @@ const openApiSpec = {
724
797
  ],
725
798
  },
726
799
  async run(value, ctx) {
727
- const app = await loadAppFor(ctx);
800
+ const app = ctx.loadApp !== undefined
801
+ ? await ctx.loadApp()
802
+ : await import("./load.js").then(({ loadBackendApp }) => loadBackendApp(ctx.cwd));
728
803
  const { renderOpenApiWithTypes } = await import("./openapi-tool.js");
729
804
  const format = value.format ?? "json";
730
805
  return {
@@ -838,12 +913,13 @@ const fixSpec = {
838
913
  };
839
914
  const migrateSpec = {
840
915
  name: "migrate",
841
- summary: "Migrate safe static Tailwind className utilities to native StyleX props.",
916
+ summary: "Move an app onto the frontend/backend split (`migrate layout`), or migrate static Tailwind utilities to StyleX.",
842
917
  input: MIGRATE_SCHEMA,
843
918
  output: output({
844
919
  type: "object",
845
920
  properties: {
846
921
  ok: { type: "boolean" },
922
+ kind: { type: "string" },
847
923
  from: { type: "string" },
848
924
  to: { type: "string" },
849
925
  write: { type: "boolean" },
@@ -852,12 +928,16 @@ const migrateSpec = {
852
928
  written: { type: "array" },
853
929
  issues: { type: "array" },
854
930
  files: { type: "array" },
931
+ splits: { type: "array" },
932
+ moves: { type: "array" },
933
+ rewritten: { type: "array" },
855
934
  },
856
- required: ["ok", "from", "to", "write", "scanned", "changed", "written", "issues", "files"],
935
+ required: ["ok", "write", "issues"],
857
936
  }),
858
937
  transports: ["cli"],
859
938
  stability: "stable",
860
939
  argv: {
940
+ positionals: ["kind"],
861
941
  flags: [
862
942
  { name: "from", field: "from", type: "string" },
863
943
  { name: "to", field: "to", type: "string" },
@@ -867,27 +947,134 @@ const migrateSpec = {
867
947
  ],
868
948
  },
869
949
  async run(value, ctx) {
950
+ const dir = resolve(ctx.cwd, value.dir ?? ".");
951
+ const write = value.write === undefined ? {} : { write: value.write };
952
+ if (value.kind === "layout") {
953
+ const { migrateLayout } = await import("./migrate-layout.js");
954
+ return { kind: "layout", ...(await migrateLayout(dir, write)) };
955
+ }
870
956
  const { migrateTailwindToStylex } = await import("./stylex-migrate.js");
871
- return migrateTailwindToStylex(resolve(ctx.cwd, value.dir ?? "."), {
872
- ...(value.write === undefined ? {} : { write: value.write }),
873
- });
957
+ return migrateTailwindToStylex(dir, write);
874
958
  },
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"]
959
+ render: (out) => {
960
+ if (out.kind === "layout") {
961
+ return [
962
+ out.ok
963
+ ? `✓ ${out.splits.length} route file${out.splits.length === 1 ? "" : "s"} split, ${out.moves.length} file${out.moves.length === 1 ? "" : "s"} moved`
964
+ : `⚠ ${out.issues.length} issue${out.issues.length === 1 ? "" : "s"} need a decision; everything else is planned`,
965
+ ...out.splits.map((split) => ` split ${split.file} → ${split.backend} (${split.moved.join(", ")})`),
966
+ ...out.moves.map((move) => ` move ${move.from} → ${move.to}`),
967
+ ...out.rewritten.map((file) => ` edit ${file} (imports)`),
968
+ ...out.issues.map((issue) => ` ⚠ ${issue.file}: ${issue.reason}`),
969
+ ...(out.write ? [] : [" dry run: pass --write to apply"]),
970
+ ];
971
+ }
972
+ return [
973
+ out.ok
974
+ ? `✓ migrated ${out.changed.length} file${out.changed.length === 1 ? "" : "s"}`
975
+ : `⚠ migrated ${out.changed.length} safe file${out.changed.length === 1 ? "" : "s"}; ${out.issues.length} manual issue${out.issues.length === 1 ? "" : "s"} remain`,
976
+ ` scanned ${out.scanned} source file${out.scanned === 1 ? "" : "s"}`,
977
+ ...(out.write
978
+ ? [` wrote ${out.written.length} file${out.written.length === 1 ? "" : "s"}`]
979
+ : out.changed.length > 0
980
+ ? [" dry run: pass --write to apply the safe changes"]
981
+ : []),
982
+ ...out.issues
983
+ .slice(0, 30)
984
+ .map((issue) => ` ${issue.file}:${issue.line} ${issue.token} — ${issue.reason}`),
985
+ ...(out.issues.length > 30
986
+ ? [` … ${out.issues.length - 30} more issue${out.issues.length - 30 === 1 ? "" : "s"}`]
884
987
  : []),
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
- : []),
988
+ ];
989
+ },
990
+ success: (out) => out.ok,
991
+ };
992
+ const targetSpec = {
993
+ name: "target",
994
+ summary: "Show the app's deploy target, or switch it (`nifra target cloudflare`): the `target` `nifra build` emits, kept in nifra.config.ts.",
995
+ input: TARGET_SCHEMA,
996
+ output: output({
997
+ type: "object",
998
+ properties: {
999
+ ok: { type: "boolean" },
1000
+ target: { type: "string" },
1001
+ previous: { type: "string" },
1002
+ changed: { type: "boolean" },
1003
+ run: { type: "string" },
1004
+ },
1005
+ required: ["ok", "target", "changed", "run"],
1006
+ }),
1007
+ transports: ["cli"],
1008
+ stability: "stable",
1009
+ argv: {
1010
+ positionals: ["target"],
1011
+ flags: [
1012
+ { name: "json", field: "json", type: "boolean" },
1013
+ { name: "dir", field: "dir", type: "string" },
1014
+ ],
1015
+ },
1016
+ async run(value, ctx) {
1017
+ const dir = resolve(ctx.cwd, value.dir ?? ".");
1018
+ const { parseBuildTarget, planBuildTarget } = await import("@nifrajs/web/build");
1019
+ const { readConfigTarget, writeConfigTarget } = await import("./config-target.js");
1020
+ const current = readConfigTarget(dir);
1021
+ const target = parseBuildTarget(value.target ?? current ?? "bun", value.target === undefined ? "target in nifra.config.ts" : "target");
1022
+ const changed = value.target !== undefined && value.target !== current;
1023
+ if (changed)
1024
+ writeConfigTarget(dir, target);
1025
+ return {
1026
+ ok: true,
1027
+ target,
1028
+ ...(changed && current !== undefined ? { previous: current } : {}),
1029
+ changed,
1030
+ run: planBuildTarget(target, "dist").run,
1031
+ };
1032
+ },
1033
+ render: (out) => [
1034
+ out.changed
1035
+ ? `✓ target: ${out.target}${out.previous === undefined ? "" : ` (was ${out.previous})`}`
1036
+ : `target: ${out.target}`,
1037
+ ` nifra build → ${out.run}`,
1038
+ ],
1039
+ success: (out) => out.ok,
1040
+ };
1041
+ const typesSpec = {
1042
+ name: "types",
1043
+ summary: "Generate each route's `./+types` module (params, schema-typed data, typed `api`); `--check` fails when one is stale.",
1044
+ input: TYPES_SCHEMA,
1045
+ output: output({
1046
+ type: "object",
1047
+ properties: {
1048
+ ok: { type: "boolean" },
1049
+ check: { type: "boolean" },
1050
+ written: { type: "array" },
1051
+ removed: { type: "array" },
1052
+ stale: { type: "array" },
1053
+ tsconfig: { type: "string" },
1054
+ },
1055
+ required: ["ok", "check", "written", "removed", "stale"],
1056
+ }),
1057
+ transports: ["cli"],
1058
+ stability: "stable",
1059
+ argv: {
1060
+ flags: [
1061
+ { name: "check", field: "check", type: "boolean" },
1062
+ { name: "json", field: "json", type: "boolean" },
1063
+ { name: "dir", field: "dir", type: "string" },
1064
+ ],
1065
+ },
1066
+ async run(value, ctx) {
1067
+ const { routeTypes } = await import("./route-types.js");
1068
+ return routeTypes(resolve(ctx.cwd, value.dir ?? "."), { check: value.check === true });
1069
+ },
1070
+ render: (out) => [
1071
+ out.check
1072
+ ? out.ok
1073
+ ? "✓ route types are up to date"
1074
+ : `✖ ${out.stale.length} route type file${out.stale.length === 1 ? " is" : "s are"} stale - run \`nifra types\``
1075
+ : `✓ route types: ${out.written.length} written, ${out.removed.length} removed`,
1076
+ ...out.stale.map((file) => ` stale ${file}`),
1077
+ ...(out.tsconfig === undefined ? [] : [` ⚠ ${out.tsconfig}`]),
891
1078
  ],
892
1079
  success: (out) => out.ok,
893
1080
  };
@@ -997,16 +1184,11 @@ const syncManifestSpec = {
997
1184
  stability: "stable",
998
1185
  argv: { flags: [{ name: "json", field: "json", type: "boolean" }] },
999
1186
  async run(_value, ctx) {
1000
- return {
1001
- ok: true,
1002
- results: await (await import("./sync-manifest.js")).syncServerManifests(ctx.cwd),
1003
- };
1187
+ const results = await syncServerManifests(ctx.cwd);
1188
+ return { ok: syncManifestsOk(results), results };
1004
1189
  },
1005
- render: (out) => [
1006
- out.results.length === 0
1007
- ? "nifra sync-manifest: no generated server-manifest.ts found under this directory."
1008
- : `✓ checked ${out.results.length} generated server manifest${out.results.length === 1 ? "" : "s"}`,
1009
- ],
1190
+ render: (out) => renderSyncManifestResults(out.results),
1191
+ success: (out) => out.ok,
1010
1192
  };
1011
1193
  const syncRoutesSpec = {
1012
1194
  name: "sync-routes",
@@ -1068,6 +1250,28 @@ const replaySpec = {
1068
1250
  render: (out) => [JSON.stringify(out, null, 2)],
1069
1251
  success: (out) => out.ok,
1070
1252
  };
1253
+ const smokeSpec = {
1254
+ name: "smoke",
1255
+ summary: "Run the declared production SSR, mounted-API, 404, header, auth, contract, and hydration smoke checks.",
1256
+ input: SMOKE_SCHEMA,
1257
+ output: output({ type: "object" }),
1258
+ transports: ["cli", "mcp"],
1259
+ stability: "stable",
1260
+ argv: {
1261
+ flags: [
1262
+ { name: "fixture", field: "fixture", type: "string" },
1263
+ { name: "in-process", field: "inProcess", type: "boolean" },
1264
+ { name: "json", field: "json", type: "boolean" },
1265
+ ],
1266
+ },
1267
+ async run(value, ctx) {
1268
+ const { loadSmokeFixture, runSmoke } = await import("./smoke.js");
1269
+ const fixture = await loadSmokeFixture(ctx.cwd, value.fixture);
1270
+ return runSmoke(fixture, { inProcess: value.inProcess === true });
1271
+ },
1272
+ render: (out) => out.checks.map((check) => `${check.status === "pass" ? "✓" : check.status === "skip" ? "•" : "✖"} ${check.id}${check.message === undefined ? "" : ` - ${check.message}`}`),
1273
+ success: (out) => out.ok,
1274
+ };
1071
1275
  const portSpec = {
1072
1276
  name: "port",
1073
1277
  summary: "Print a feature by deploy-target portability matrix with file:line evidence and gate against an unsupported target.",
@@ -1096,7 +1300,7 @@ const portSpec = {
1096
1300
  return [
1097
1301
  report,
1098
1302
  "",
1099
- "[nifra] --ci needs a deploy target to gate against, and none was detected. Pass --target <bun|node|deno|cf-pages|vercel>.",
1303
+ "[nifra] --ci needs a deploy target to gate against, and none was detected. Pass --target <bun|node|deno|cloudflare|vercel>.",
1100
1304
  ];
1101
1305
  return [report];
1102
1306
  },
@@ -1110,6 +1314,31 @@ const portSpec = {
1110
1314
  },
1111
1315
  json: (out) => out.json,
1112
1316
  };
1317
+ // CLI only: it imports app code (the catalogs), which a long-lived MCP server process would cache.
1318
+ const i18nSpec = {
1319
+ name: "i18n",
1320
+ 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.",
1321
+ input: I18N_SCHEMA,
1322
+ output: output({ type: "object" }),
1323
+ transports: ["cli"],
1324
+ stability: "stable",
1325
+ argv: {
1326
+ positionals: ["action", "entry"],
1327
+ flags: [
1328
+ { name: "json", field: "json", type: "boolean" },
1329
+ { name: "strict", field: "strict", type: "boolean" },
1330
+ ],
1331
+ },
1332
+ async run(value, ctx) {
1333
+ const { runI18nCheck } = await import("./i18n-check.js");
1334
+ return runI18nCheck(value.dir === undefined ? ctx.cwd : resolve(ctx.cwd, value.dir), {
1335
+ entry: value.entry,
1336
+ });
1337
+ },
1338
+ render: (out) => renderI18nCheck(out),
1339
+ success: (out, input) => i18nCheckPassed(out, input.strict === true),
1340
+ json: (out) => out,
1341
+ };
1113
1342
  export const commandSpecs = Object.freeze([
1114
1343
  checkSpec,
1115
1344
  reviewSpec,
@@ -1123,6 +1352,8 @@ export const commandSpecs = Object.freeze([
1123
1352
  doctorSpec,
1124
1353
  fixSpec,
1125
1354
  migrateSpec,
1355
+ targetSpec,
1356
+ typesSpec,
1126
1357
  snapshotSpec,
1127
1358
  diffSpec,
1128
1359
  contractsSpec,
@@ -1130,7 +1361,16 @@ export const commandSpecs = Object.freeze([
1130
1361
  syncRoutesSpec,
1131
1362
  proveSpec,
1132
1363
  replaySpec,
1364
+ smokeSpec,
1133
1365
  portSpec,
1366
+ i18nSpec,
1367
+ errorsSpec,
1368
+ logsSpec,
1369
+ cdnCheckSpec,
1370
+ dbSchemaSpec,
1371
+ dbQuerySpec,
1372
+ dbRoleSpec,
1373
+ dbAuditSpec,
1134
1374
  ]);
1135
1375
  const commandByName = new Map(commandSpecs.map((spec) => [spec.name, spec]));
1136
1376
  export function findCommandSpec(name) {