cotutor 0.4.2 → 0.4.4

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 (275) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +44 -2
  3. package/dist/app/cli/backup.d.ts +68 -0
  4. package/dist/app/cli/backup.js +243 -0
  5. package/dist/app/cli/doctor-fix.d.ts +18 -0
  6. package/dist/app/cli/doctor-fix.js +70 -0
  7. package/dist/app/cli/doctor.js +8 -0
  8. package/dist/app/cli/init.d.ts +2 -0
  9. package/dist/app/cli/init.js +6 -3
  10. package/dist/app/cli/main.js +103 -0
  11. package/dist/app/cli/report.d.ts +11 -0
  12. package/dist/app/cli/report.js +110 -0
  13. package/dist/app/cli/root-ca.d.ts +8 -0
  14. package/dist/app/cli/root-ca.js +33 -0
  15. package/dist/app/cli/serve.d.ts +11 -2
  16. package/dist/app/cli/serve.js +58 -3
  17. package/dist/app/cli/skeleton.d.ts +1 -1
  18. package/dist/app/cli/skeleton.js +2 -2
  19. package/dist/app/cli/usage.d.ts +1 -1
  20. package/dist/app/cli/usage.js +3 -1
  21. package/dist/app/http/access.js +1 -1
  22. package/dist/app/http/app.js +4 -0
  23. package/dist/app/http/parent-home.js +9 -0
  24. package/dist/app/http/parent-setup.d.ts +19 -0
  25. package/dist/app/http/parent-setup.js +96 -0
  26. package/dist/app/http/stage.js +2 -2
  27. package/dist/app/mock/mock.js +3 -0
  28. package/dist/memory/vault-notes.d.ts +4 -0
  29. package/dist/memory/vault-notes.js +11 -0
  30. package/dist/shared/upgrade.d.ts +2 -0
  31. package/dist/shared/upgrade.js +5 -1
  32. package/dist/stage/fonts/Assistant/Assistant-Bold.woff2 +0 -0
  33. package/dist/stage/fonts/Assistant/Assistant-Medium.woff2 +0 -0
  34. package/dist/stage/fonts/Assistant/Assistant-Regular.woff2 +0 -0
  35. package/dist/stage/fonts/Assistant/Assistant-SemiBold.woff2 +0 -0
  36. package/dist/stage/fonts/Cascadia/CascadiaCode-Regular.woff2 +0 -0
  37. package/dist/stage/fonts/ComicShanns/ComicShanns-Regular-279a7b317d12eb88de06167bd672b4b4.woff2 +0 -0
  38. package/dist/stage/fonts/ComicShanns/ComicShanns-Regular-6e066e8de2ac57ea9283adb9c24d7f0c.woff2 +0 -0
  39. package/dist/stage/fonts/ComicShanns/ComicShanns-Regular-dc6a8806fa96795d7b3be5026f989a17.woff2 +0 -0
  40. package/dist/stage/fonts/ComicShanns/ComicShanns-Regular-fcb0fc02dcbee4c9846b3e2508668039.woff2 +0 -0
  41. package/dist/stage/fonts/Excalifont/Excalifont-Regular-349fac6ca4700ffec595a7150a0d1e1d.woff2 +0 -0
  42. package/dist/stage/fonts/Excalifont/Excalifont-Regular-3f2c5db56cc93c5a6873b1361d730c16.woff2 +0 -0
  43. package/dist/stage/fonts/Excalifont/Excalifont-Regular-41b173a47b57366892116a575a43e2b6.woff2 +0 -0
  44. package/dist/stage/fonts/Excalifont/Excalifont-Regular-623ccf21b21ef6b3a0d87738f77eb071.woff2 +0 -0
  45. package/dist/stage/fonts/Excalifont/Excalifont-Regular-a88b72a24fb54c9f94e3b5fdaa7481c9.woff2 +0 -0
  46. package/dist/stage/fonts/Excalifont/Excalifont-Regular-b9dcf9d2e50a1eaf42fc664b50a3fd0d.woff2 +0 -0
  47. package/dist/stage/fonts/Excalifont/Excalifont-Regular-be310b9bcd4f1a43f571c46df7809174.woff2 +0 -0
  48. package/dist/stage/fonts/Liberation/LiberationSans-Regular.woff2 +0 -0
  49. package/dist/stage/fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYE98RXi4EwSsbg.woff2 +0 -0
  50. package/dist/stage/fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYEF8RXi4EwQ.woff2 +0 -0
  51. package/dist/stage/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTA3j6zbXWjgevT5.woff2 +0 -0
  52. package/dist/stage/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTQ3j6zbXWjgeg.woff2 +0 -0
  53. package/dist/stage/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTk3j6zbXWjgevT5.woff2 +0 -0
  54. package/dist/stage/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTo3j6zbXWjgevT5.woff2 +0 -0
  55. package/dist/stage/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTs3j6zbXWjgevT5.woff2 +0 -0
  56. package/dist/stage/fonts/Virgil/Virgil-Regular.woff2 +0 -0
  57. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-019d66dcad46dc156b162d267f981c20.woff2 +0 -0
  58. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-04b718e5623574919c8b0dea5f301444.woff2 +0 -0
  59. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-069e77aac84590e2e991d0a0176d34f2.woff2 +0 -0
  60. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-06c77b8c66e51ed6c63ccb502dd8b8af.woff2 +0 -0
  61. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-08e0dc436ad0ad61ba5558db0674d762.woff2 +0 -0
  62. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-093b9ef39a46ceae95a1df18a0a3a326.woff2 +0 -0
  63. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-095c169f3314805276f603a362766abd.woff2 +0 -0
  64. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-09850c4077f3fffe707905872e0e2460.woff2 +0 -0
  65. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-0986d134c05864f5025962eef9f994a0.woff2 +0 -0
  66. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-0b5d723fdc4e249c140f0909e87d03b4.woff2 +0 -0
  67. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-0f626226ba1272e832aea87bafd9720e.woff2 +0 -0
  68. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-0f7fb1e0d5015bb1371343153ecf7ce3.woff2 +0 -0
  69. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-0fa55a080fcd0f9dc2e0b0058b793df8.woff2 +0 -0
  70. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-0facdf1ea213ba40261022f5d5ed4493.woff2 +0 -0
  71. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-10a7ae9a371830a80c3d844acf1c02d7.woff2 +0 -0
  72. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-112c051027b2d766c19a519f6ee1f4f7.woff2 +0 -0
  73. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-11c345711937f0ba4b8f7b6b919c8440.woff2 +0 -0
  74. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-12b52b58eb3df36804b9a654ec9ee194.woff2 +0 -0
  75. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-13ae07ed2e272d26d59bc0691cd7117a.woff2 +0 -0
  76. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-13d2887ec8ee73c43acdabc52a05af7b.woff2 +0 -0
  77. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-145aa02cdd91946e67dc934e1acffe75.woff2 +0 -0
  78. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-15dc6d811c9cd078f9086a740d5a1038.woff2 +0 -0
  79. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-173945821411c09f70c95f98d590e697.woff2 +0 -0
  80. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-1b611157cd46bb184d4fa4dae2d6a2b8.woff2 +0 -0
  81. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-1e6fd68f1f3902ce48ce8c69df385622.woff2 +0 -0
  82. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-1ee544f0f1dac422545c505baa788992.woff2 +0 -0
  83. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-1fdc0c67ed57263a80fd108c1f6ccf24.woff2 +0 -0
  84. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-203b0e569e3b14aac86a003dc3fa523e.woff2 +0 -0
  85. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-20cc1bbf50e7efb442756cb605672c1f.woff2 +0 -0
  86. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-20e7bf72fa05de9adf7dbcc7bf51dde6.woff2 +0 -0
  87. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-21430ee05a1248901da8d0de08744d47.woff2 +0 -0
  88. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-23686f7f29da6e8008c36dd3a80c83d6.woff2 +0 -0
  89. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-23ad2d71b280f00b1363b95b7bea94eb.woff2 +0 -0
  90. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-23f228f3999c01983860012330e4be08.woff2 +0 -0
  91. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-24476a126f129212beb33f66853ea151.woff2 +0 -0
  92. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-24a21c1e4449222e8d1898d69ff3a404.woff2 +0 -0
  93. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-25b7f38e18f035f96cb5e547bd2bd08c.woff2 +0 -0
  94. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-29cec36cd205b211da97acabaa62f055.woff2 +0 -0
  95. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-2a26d20a23b00898ce82f09d2ee47c3f.woff2 +0 -0
  96. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-2adbc89c11e65905393d3dfc468b9d5b.woff2 +0 -0
  97. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-2b7441d46298788ac94e610ffcc709b6.woff2 +0 -0
  98. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-2b77e8ebfb2367ab2662396a60e7d320.woff2 +0 -0
  99. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-2cf96d082d35ea3d8106851223ad0d16.woff2 +0 -0
  100. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-2d43040e86ff03ba677f6f9c04cd0805.woff2 +0 -0
  101. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-2e33e8dc771ef5e1d9127d60a6b73679.woff2 +0 -0
  102. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-33432927cd87d40cfe393c7482bf221f.woff2 +0 -0
  103. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-353f33792a8f60dc69323ddf635a269e.woff2 +0 -0
  104. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-36925dfe329a45086cbb7fc5c20d45ac.woff2 +0 -0
  105. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-3717077e38f98d89eae729b6c14e56dc.woff2 +0 -0
  106. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-3756e81d3e149cf6099163ee79944fec.woff2 +0 -0
  107. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-395c35dd584b56b0789f58a0559beaf1.woff2 +0 -0
  108. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-3c9de2ae0ea4bc91a510942dfa4be8d2.woff2 +0 -0
  109. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-3cc70dbb64df5b21f1326cc24dee2195.woff2 +0 -0
  110. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-3e1f8f654357353bf0e04ba5c34b5f7f.woff2 +0 -0
  111. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-3e63ed8162808a9e425ed80a8bc79114.woff2 +0 -0
  112. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-3eaa538115d76932653c21d8dc28f207.woff2 +0 -0
  113. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4095eb84ef3874e2600247bee0b04026.woff2 +0 -0
  114. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-41521fade99856108931b4768b1b2648.woff2 +0 -0
  115. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-450da755d5bcb70906e1295e559b9602.woff2 +0 -0
  116. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-452225341522a7942f0f6aab1a5c91a3.woff2 +0 -0
  117. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4535823663ad81405188a528d8f2b1a2.woff2 +0 -0
  118. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4806e761d750087c2d734fc64596eaff.woff2 +0 -0
  119. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4a0fdb40036e87b40aa08dd30584cb85.woff2 +0 -0
  120. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4a38cc3e9cf104e69ba246d37f8cf135.woff2 +0 -0
  121. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4aca6a43e59aceee2166b0c7e4e85ef1.woff2 +0 -0
  122. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4bfaa8ffa64c5ee560aa2daba7c9cbd3.woff2 +0 -0
  123. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4dc6d5f188d5c96d44815cd1e81aa885.woff2 +0 -0
  124. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4ddc14ed3eb0c3e46364317dfc0144a3.woff2 +0 -0
  125. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4ee10ae43505e2e0bc62656ced49c0fa.woff2 +0 -0
  126. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4f50e5136e136527280bc902c5817561.woff2 +0 -0
  127. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-51502f1206be09c565f1547c406e9558.woff2 +0 -0
  128. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-51a0e808bbc8361236ac521a119758a3.woff2 +0 -0
  129. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-52a84a22fd1369bffeaf21da2d6158dc.woff2 +0 -0
  130. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-5330a2119a716e4e7224ed108b085dac.woff2 +0 -0
  131. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-543fa46ace099a7099dad69123399400.woff2 +0 -0
  132. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-544fc28abe2c5c30e62383fd4dac255f.woff2 +0 -0
  133. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-54acdfc2166ad7fcbd074f75fd4a56ba.woff2 +0 -0
  134. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-5572b3513ba8df57a3d5d7303ee6b11b.woff2 +0 -0
  135. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-56467a5c8840c4d23a60b2f935114848.woff2 +0 -0
  136. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-56a32a7689abd0326e57c10c6c069bb4.woff2 +0 -0
  137. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-57862b464a55b18c7bf234ce22907d73.woff2 +0 -0
  138. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-583d166e56ba0de4b77eabb47ef67839.woff2 +0 -0
  139. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-5882ffa04f32584d26109137e2da4352.woff2 +0 -0
  140. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-58fd02350d0bc52cf1ca3bb32ce9766e.woff2 +0 -0
  141. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-5935a5775af3d5c6307ac667bd9ae74e.woff2 +0 -0
  142. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-59e9ff77b0efaf684bc09274fb6908c9.woff2 +0 -0
  143. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-5a1ce3117cfe90c48e8fb4a9a00f694d.woff2 +0 -0
  144. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-5a45d991244d4c7140217e1e5f5ca4f4.woff2 +0 -0
  145. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-5a7fac4b8b23a6e4e5ba0c9bf1756c91.woff2 +0 -0
  146. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-5b0ed6971aaab9c8ad563230bd5471a7.woff2 +0 -0
  147. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-5d2898fbc097a7e24c6f38d80587621e.woff2 +0 -0
  148. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-603aefd23e350ba7eb124273e3c9bcf1.woff2 +0 -0
  149. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-60a3089806700d379f11827ee9843b6b.woff2 +0 -0
  150. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-60a41c7e1c68f22424e6d22df544bc82.woff2 +0 -0
  151. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-642b26e2e5f5fb780b51b593dbc8c851.woff2 +0 -0
  152. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-66493ba5a8367f2928812f446f47b56a.woff2 +0 -0
  153. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-670ba603758d94268e8606f240a42e12.woff2 +0 -0
  154. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-671a2c20b1eb9e4ef8a192833940e319.woff2 +0 -0
  155. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-684d65f1793cac449dde5d59cb3c47fb.woff2 +0 -0
  156. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-69c09cc5fa3e55c74fc4821f76909cc3.woff2 +0 -0
  157. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-6ae5b42180ad70b971c91e7eefb8eba2.woff2 +0 -0
  158. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-6e092f71c1e634059ada0e52abadce67.woff2 +0 -0
  159. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-6f3256af8454371776bc46670d33cc65.woff2 +0 -0
  160. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-6fe5c5973cc06f74b2387a631ea36b88.woff2 +0 -0
  161. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-70c2eb8d64e71a42a834eb857ea9df51.woff2 +0 -0
  162. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-70e811fd7994e61f408c923de6ddd078.woff2 +0 -0
  163. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-7197d6fda6cba7c3874c53d6381ca239.woff2 +0 -0
  164. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-72252d73220fa3cd856677888cee1635.woff2 +0 -0
  165. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-72536a3d71b694a0d53dd90ddceae41e.woff2 +0 -0
  166. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-726303e0774b4e678bff8c2deb6ca603.woff2 +0 -0
  167. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-733171b4ffcd17ea1fe1c0ba627173bf.woff2 +0 -0
  168. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-739bc1a567439c7cffcd1614644593d2.woff2 +0 -0
  169. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-73e309718fd16cea44b4d54a33581811.woff2 +0 -0
  170. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-7494dc504ae00ee9cd0505f990f88c5d.woff2 +0 -0
  171. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-74e2263a91439c25b91d5132ce9f4d62.woff2 +0 -0
  172. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-761d05e3cd968cf574166867998ef06a.woff2 +0 -0
  173. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-7718fe60986d8b42b1be9c5ace5ccf25.woff2 +0 -0
  174. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-774d4f764a1299da5d28ec2f2ffe0d69.woff2 +0 -0
  175. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-79d494361ae093b69e74ee9dbe65bfd4.woff2 +0 -0
  176. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-79f007c1c6d07557120982951ea67998.woff2 +0 -0
  177. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-7a07ddc0f0c0f5f4a9bad6ee3dda66b5.woff2 +0 -0
  178. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-7ab2bed91166a9dca83a5ebfbe2a7f38.woff2 +0 -0
  179. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-7ccce86603f80a099ddb0cb21d4ae3e3.woff2 +0 -0
  180. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-7e4bde7e9c7f84cd34d8a845e384c746.woff2 +0 -0
  181. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-7e929f262f30c8ee78bf398150b1a7cd.woff2 +0 -0
  182. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-7eb9fffd1aa890d07d0f88cc82e6cfe4.woff2 +0 -0
  183. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-7f855356ab893b0d2b9c1c83b8116f0e.woff2 +0 -0
  184. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-829615148e6357d826b9242eb7fbbd1e.woff2 +0 -0
  185. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-866fa7613df6b3fd272bcfd4530c0bb9.woff2 +0 -0
  186. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-87599f94b6cc129d505b375798d0d751.woff2 +0 -0
  187. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-8c2f33cee3993174f7e87c28e4bf42ee.woff2 +0 -0
  188. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-8d3bcabb847b56243b16afe62adaaf21.woff2 +0 -0
  189. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-8de5b863cb50dfefdd07cb11c774d579.woff2 +0 -0
  190. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-8e9f97f01034820170065b2921b4fb5e.woff2 +0 -0
  191. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-8f476c4c99813d57cbe6eca4727388ad.woff2 +0 -0
  192. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-903bb6865f3452e2fda42e3a25547bc5.woff2 +0 -0
  193. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-91ddb2969bf2d31ba02ad82998d1314c.woff2 +0 -0
  194. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-938d90c10ff8c20386af7f242c05d6b0.woff2 +0 -0
  195. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-93fc8f28a33234bcadf1527cafabd502.woff2 +0 -0
  196. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-95429962233afd82db1c27df1500a28c.woff2 +0 -0
  197. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-9544732d2e62d1a429674f8ee41b5d3a.woff2 +0 -0
  198. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-9592bfc861f07bcb8d75c196b370e548.woff2 +0 -0
  199. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-95bfd249da4902577b4b7d76ebdd0b44.woff2 +0 -0
  200. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-968cffdc8ee679da094e77ebf50f58ef.woff2 +0 -0
  201. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-97f7f48ce90c9429bf32ae51469db74d.woff2 +0 -0
  202. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-982b630266d87db93d2539affb1275c6.woff2 +0 -0
  203. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-98f2ad84457de7f3740d9920b8fa8667.woff2 +0 -0
  204. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-99a16ef6a64934d5781933dbd9c46b2e.woff2 +0 -0
  205. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-9cfb2a77a4e45025105ad29a1748b90d.woff2 +0 -0
  206. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-9d81066dd2b337c938df6e90380a00dc.woff2 +0 -0
  207. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-9eb5a99df4e76ac3363453ac9ca288b1.woff2 +0 -0
  208. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-a004ddfcb26e67bd6e678c8ed19e25ce.woff2 +0 -0
  209. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-a0ca5df4258213d7fc9fce80f65ce760.woff2 +0 -0
  210. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-a1f916d6039285c4ffb900cd654e418f.woff2 +0 -0
  211. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-a203b91dad570bf05a58c3c3ddb529bf.woff2 +0 -0
  212. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-a365e82ed54697a52f27adcea1315fe8.woff2 +0 -0
  213. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-a4c34be6d42152e64b0df90bc4607f64.woff2 +0 -0
  214. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-a7accba310e821da5505f71c03b76bdb.woff2 +0 -0
  215. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-aa0d470430e6391eca720c7cfa44446f.woff2 +0 -0
  216. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-aa5c9ca6cf4fba00433b7aa3fa10671a.woff2 +0 -0
  217. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-ac9ceb44437becc3e9c4dbfebab7fc2d.woff2 +0 -0
  218. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-b1220a3c61f85cc0408deedb4c5f57a2.woff2 +0 -0
  219. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-b358f7a51ece39a3247942b1feabdb29.woff2 +0 -0
  220. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-b57aaedfd8ebdf3931f25119dc6a5eb2.woff2 +0 -0
  221. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-b5c1596551c256e0e9cf02028595b092.woff2 +0 -0
  222. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-b6d128682ee29e471486354d486a1b90.woff2 +0 -0
  223. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-b6fd38ca30869792244804b04bc058da.woff2 +0 -0
  224. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-b7d203b051eff504ff59ddca7576b6a9.woff2 +0 -0
  225. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-b96d9226ce77ec94ceca043d712182e6.woff2 +0 -0
  226. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-ba3de316d63c7e339987b16f41a0b879.woff2 +0 -0
  227. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-bafff7a14c27403dcc6cf1432e8ea836.woff2 +0 -0
  228. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-bd77e3c7f9e0b072d96af37f73d1aa32.woff2 +0 -0
  229. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-be549ab72f0719d606a5c01e2c0219b6.woff2 +0 -0
  230. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-c16ed9740b85badf16e86ea782a3062f.woff2 +0 -0
  231. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-c1f94158256bb1f3bf665b053d895af9.woff2 +0 -0
  232. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-c40533fdf4cc57177b12803598af7e59.woff2 +0 -0
  233. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-c4a687ac4f0c2766eefc9f77ed99cddf.woff2 +0 -0
  234. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-c69f61a4ab18d0488c8d1fc12e7028e8.woff2 +0 -0
  235. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-c8b71798409ccc126ee264a00aadcf21.woff2 +0 -0
  236. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-c99eda15fc26a2941579560f76c3a5cf.woff2 +0 -0
  237. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-cb17fc3db95f6d139afc9d31a8e93293.woff2 +0 -0
  238. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-cbaaefaaf326668277aa24dfa93c4d28.woff2 +0 -0
  239. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-cd145ce4a0ea18469358df53c207bc1b.woff2 +0 -0
  240. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-cdbce89e82cc1ab53a2decbf5819278f.woff2 +0 -0
  241. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-ce4884f96f11589608b76b726a755803.woff2 +0 -0
  242. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-cf2cc71752631e579e35b0e423bf2638.woff2 +0 -0
  243. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-cf6ff4e0f491ca0cf3038187a997b9b4.woff2 +0 -0
  244. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-cfb211578629b7e8153b37240de6a9d5.woff2 +0 -0
  245. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-d0cf73942fea1c74edbdf0b3011f4656.woff2 +0 -0
  246. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-d2666cbed13462c5dc36fa2f15c202ca.woff2 +0 -0
  247. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-d3716376641d615e2995605b29bca7b6.woff2 +0 -0
  248. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-dac48066b5883d8b4551fc584f0c2a3e.woff2 +0 -0
  249. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-dbea1af6dcd9860be40c3d18254338f5.woff2 +0 -0
  250. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-e11567fd2accf9957cd0d3c2be937d87.woff2 +0 -0
  251. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-e2ead7ea7da0437f085f42ffc05f8d13.woff2 +0 -0
  252. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-e3fcf5180fd466c8915c4e8069491054.woff2 +0 -0
  253. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-e480d9c614742d05f0e78f274f1e69e6.woff2 +0 -0
  254. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-e4bca6cfa53e499cae0a6be4894a90e9.woff2 +0 -0
  255. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-e51ef413167c6e14e0c0fdcc585f2fc9.woff2 +0 -0
  256. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-e5f453bb04da18eed01675eeebd88bf8.woff2 +0 -0
  257. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-e656f091b9dc4709722c9f4b84d3c797.woff2 +0 -0
  258. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-ec181b795ac1fb5a50d700b6e996d745.woff2 +0 -0
  259. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-ee8bae97908d5147b423f77ad0d3c1bb.woff2 +0 -0
  260. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-f0f13b5c60e0af5553bd359f5513be1b.woff2 +0 -0
  261. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-f2b54d4e7be0eaefe1c2c56836fa5368.woff2 +0 -0
  262. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-f56414bf9bced67990def8660e306759.woff2 +0 -0
  263. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-f5d079153c99a25b9be5b8583c4cc8a7.woff2 +0 -0
  264. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-f6032fc06eb20480f096199713f70885.woff2 +0 -0
  265. package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-f8ee5d36068a42b51d0e4a1116cfcec1.woff2 +0 -0
  266. package/dist/ui/kid/kid-page.js +2 -0
  267. package/dist/ui/kid/offline-sw.d.ts +1 -0
  268. package/dist/ui/kid/offline-sw.js +42 -0
  269. package/dist/ui/parent/parent-home-page.js +49 -5
  270. package/dist/ui/parent/parent-settings-page.js +65 -1
  271. package/install.ps1 +66 -0
  272. package/install.sh +84 -0
  273. package/package.json +13 -10
  274. package/skills/cotutor-analyze/references//345/221/275/344/273/244/344/270/216/346/226/207/344/273/266.md +1 -1
  275. package/skills/cotutor-tune/references//345/255/227/346/256/265.md +1 -1
@@ -3674,6 +3674,8 @@ __REEL_DOCK_JS__
3674
3674
  location.reload();
3675
3675
  };
3676
3676
  setInterval(() => { staleReload(); if (S.tutor) { if (!S.pending) loadDay(true); } else loadHome(); }, 5000);
3677
+ // 离线页(offline-sw.ts):电脑关了、睡着了时,点开主屏幕图标看到「老师们还没到」,不是浏览器的报错。只在 https(或 localhost)上有;回放、预览里不装
3678
+ if (!REEL && !PREVIEW && window.isSecureContext && 'serviceWorker' in navigator) navigator.serviceWorker.register('/sw.js').catch(() => {});
3677
3679
  document.addEventListener('visibilitychange', () => { if (!document.hidden) (S.tutor ? loadDay(true) : loadHome()); });
3678
3680
  // 孩子端刷新(手动的、Safari 自己重载的)回到手上这位老师;在首页刷新就回首页。只读回放不记(重载回来是今天的)
3679
3681
  if (!REEL && !PREVIEW) window.addEventListener('pagehide', () => { try { if (S.tutor && !S.readonly) sessionStorage.setItem('kid-resume', S.tutor.name); else sessionStorage.removeItem('kid-resume'); } catch {} });
@@ -0,0 +1 @@
1
+ export declare const KID_SW_JS: string;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * 孩子端的离线页(Service Worker,GET /sw.js):电脑关了、睡着了、服务没在跑时,平板上打开孩子端看到的不是浏览器的报错,是「老师们休息中」。
3
+ * 和页面开着时断线的样子(kid-page 的 #rest)同一句:都是「电脑那边连不上」;「老师们还没到」是百炼没配好,另一回事。
4
+ * 孩子端永远没有错误:这一页只说老师们休息、叫爸爸妈妈,不说连接、不说服务器。
5
+ * 页面开着时断线由页面自己管(灰掉、「老师们休息中」);这一页只在重新打开(iPad 把网页 App 清出内存后再点开、刷新)时出现。
6
+ *
7
+ * 只接管孩子端那几页的打开(导航);接口、静态文件、别的页面一律不碰。不缓存任何东西:平时原样走网络,孩子看不到旧页面;
8
+ * 连不上或 12 秒没回应才给离线页,它每 5 秒问一次 /api/health,通了就自己刷新回去。
9
+ * Service Worker 只在安全上下文里有(https 且平板信任了根证书,或 localhost);http 时孩子端照旧,什么都不变。
10
+ * 改了这个文件就改 VERSION:平板上的旧 worker 靠脚本内容变了才换。
11
+ */
12
+ const VERSION = '2';
13
+ /** 离线页本身:没有网可取,样式、脚本都内联 */
14
+ const OFFLINE_HTML = [
15
+ '<!doctype html><html lang="zh-CN"><head><meta charset="utf-8">',
16
+ '<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">',
17
+ '<meta name="apple-mobile-web-app-capable" content="yes"><title>老师们休息中</title>',
18
+ '<style>html,body{height:100%;margin:0}body{display:flex;align-items:center;justify-content:center;background:#f7f3ea;color:#3a352c;',
19
+ 'font:22px/1.6 -apple-system,"PingFang SC","Microsoft YaHei",sans-serif;text-align:center;-webkit-user-select:none;user-select:none}',
20
+ 'p{margin:0 24px}small{display:block;margin-top:12px;font-size:17px;color:#8a8273}</style></head>',
21
+ '<body><p id="off">老师们休息中<small>叫爸爸妈妈来看一下:家里那台电脑是不是关了、睡着了</small></p>',
22
+ '<script>setInterval(function(){fetch("/api/health",{cache:"no-store"}).then(function(r){if(r.ok)location.reload()}).catch(function(){})},5000)</script>',
23
+ '</body></html>',
24
+ ].join('');
25
+ export const KID_SW_JS = `// cotutor 孩子端的离线页 v${VERSION}(src/ui/kid/offline-sw.ts)
26
+ const KID = new Set(['/', '/dictation', '/dictation/', '/talk', '/talk/']);
27
+ const WAIT_MS = 12000;
28
+ const OFFLINE = ${JSON.stringify(OFFLINE_HTML)};
29
+ self.addEventListener('install', () => { self.skipWaiting(); });
30
+ self.addEventListener('activate', (e) => { e.waitUntil(self.clients.claim()); });
31
+ self.addEventListener('fetch', (e) => {
32
+ const r = e.request;
33
+ if (r.mode !== 'navigate' || r.method !== 'GET') return;
34
+ const u = new URL(r.url);
35
+ if (u.origin !== self.location.origin || !KID.has(u.pathname)) return;
36
+ const offline = () => new Response(OFFLINE, { status: 200, headers: { 'content-type': 'text/html; charset=utf-8', 'cache-control': 'no-store' } });
37
+ e.respondWith(Promise.race([
38
+ fetch(r).catch(() => null),
39
+ new Promise((resolve) => { setTimeout(() => resolve(null), WAIT_MS); }),
40
+ ]).then((res) => res || offline()));
41
+ });
42
+ `;
@@ -219,6 +219,19 @@ ${BRAND_CSS}
219
219
  }
220
220
  .upd { position:relative; display:flex; flex-direction:column; gap:6px; margin:0 0 12px; padding:12px 14px; border-radius:14px; background:var(--card); box-shadow:0 0 0 1px var(--line); font-size:15px; }
221
221
  .upd.bad { box-shadow:0 0 0 1px var(--accent); }
222
+ .setup { position:relative; display:flex; flex-direction:column; gap:2px; margin:0 0 12px; padding:12px 14px; border-radius:14px; background:var(--card); box-shadow:0 0 0 1px var(--line); font-size:15px; }
223
+ .setup > b { padding-right:64px; }
224
+ .setup .sp { display:flex; gap:10px; padding:8px 0; border-top:1px solid var(--line); }
225
+ .setup .sp:first-of-type { border-top:0; }
226
+ .setup .mk { flex:none; width:20px; text-align:center; color:var(--dim); }
227
+ .setup .sp.on .mk { color:var(--accent); }
228
+ .setup .sp.on b { font-weight:500; color:var(--dim); }
229
+ .setup .tx { display:flex; flex-direction:column; gap:4px; min-width:0; flex:1; }
230
+ .setup small { color:var(--dim); font-size:14px; line-height:1.5; }
231
+ .setup pre { margin:2px 0 0; padding:10px 12px; border-radius:10px; background:var(--paper); font:13px/1.6 ui-monospace,Menlo,Consolas,monospace; white-space:pre-wrap; overflow-wrap:anywhere; user-select:all; -webkit-user-select:all; }
232
+ .setup .gr { display:flex; flex-wrap:wrap; gap:6px; margin-top:2px; }
233
+ .setup .gr button { min-height:44px; padding:0 12px; border:0; border-radius:10px; background:var(--paper); box-shadow:0 0 0 1px var(--line); color:inherit; font-size:15px; cursor:pointer; }
234
+ .setup .hide { position:absolute; top:6px; right:6px; min-height:44px; padding:0 10px; border:0; background:transparent; color:var(--accent); font-size:15px; cursor:pointer; }
222
235
  .upd ul { margin:0; padding-left:18px; font-size:14px; }
223
236
  .upd .sub { color:var(--dim); font-size:14px; padding-right:64px; }
224
237
  .upd pre { margin:2px 0 0; padding:10px 12px; border-radius:10px; background:var(--paper); font:13px/1.6 ui-monospace,Menlo,Consolas,monospace; white-space:pre-wrap; overflow-wrap:anywhere; user-select:all; -webkit-user-select:all; }
@@ -227,6 +240,7 @@ ${BRAND_CSS}
227
240
  <div class="wrap" id="main">
228
241
  <div class="top"><span class="ttl"><span id="ct-mark" class="ct-draw ct-hover">${titleLogo(true)}</span><b id="title">家长</b></span><nav class="seg"><a class="on" href="/parent/home">首页</a><a href="/parent">记录</a><a href="/parent/settings">设置</a></nav><small id="pub"></small><a class="devl" href="/dev" target="_blank" title="工作台:细调老师文件、activity(新窗口)">工作台<svg width="11" height="11" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="M4 2h6v6"/><path d="M10 2 3 9"/></svg></a></div>
229
242
  <div id="troublebar"></div>
243
+ <div id="setupbar"></div>
230
244
  <div id="updatebar"></div>
231
245
  <div id="qrtop"></div>
232
246
  <div class="main">
@@ -351,29 +365,58 @@ ${pageDomJs(3200)}
351
365
  h('span', { style: 'flex:none;display:flex', html: QR_ICON }), h('span', { class: 'tx' }, h('b', {}, '扫码打开'), h('small', {}, seen)), h('span', { class: 'lnk', style: 'font-size:14px' }, '展开'))));
352
366
  return;
353
367
  }
354
- const kid = QR.to === 'kid', c = kid ? d : (d.parent || d);
368
+ if (QR.to === 'ca' && !d.ca) QR.to = 'kid';
369
+ const kid = QR.to === 'kid', ca = QR.to === 'ca', c = kid ? d : ca ? d.ca : (d.parent || d);
355
370
  const useIp = QR.ip && c.ip;
356
- const seg = h('div', { class: 'seg', role: 'group', 'aria-label': '给谁扫' }, ...[['kid', '孩子的平板'], ['parent', '我的手机']].map(([k, l]) =>
371
+ // 装证书(serve.ts 的 http 那一面给根证书):平板第一次用之前扫一次;有证书、找得到根证书才有这一格
372
+ const tabs = [['kid', '孩子的平板'], ['parent', '我的手机']].concat(d.ca ? [['ca', '装证书']] : []);
373
+ const seg = h('div', { class: 'seg', role: 'group', 'aria-label': '给谁扫' }, ...tabs.map(([k, l]) =>
357
374
  h('button', { type: 'button', class: QR.to === k ? 'on' : '', 'aria-pressed': QR.to === k ? 'true' : 'false', on: { click: () => { QR.to = k; qrDraw(); } } }, l)));
358
375
  const print = '/parent/qr?' + new URLSearchParams(Object.assign({}, useIp ? { via: 'ip' } : {}, kid ? {} : { to: 'parent' })).toString();
359
376
  qrEl.replaceChildren(
360
377
  h('div', { class: 'gh' }, h('span', {}, '扫码打开'), h('button', { type: 'button', class: 'x', 'aria-expanded': 'true', on: { click: () => qrToggle(false) } }, '收起')),
361
378
  h('div', { class: 'grp' }, h('div', { class: 'box' }, seg,
362
379
  h('div', { class: 'qrrow' }, h('div', { class: 'qrimg', html: (useIp ? c.svgIp : c.svg) || '' }),
363
- h('b', { style: 'font-weight:600' }, kid ? '用孩子平板的相机扫一下' : '用你自己的手机扫一下'),
364
- h('span', { class: 'lbl', style: 'line-height:1.5' }, kid ? '打开的就是孩子的首页。在 Safari 里「添加到主屏幕」,以后点图标就进来。' : '打开的是家长端:看记录、排首页。也可以添加到主屏幕。')),
380
+ h('b', { style: 'font-weight:600' }, kid ? '用孩子平板的相机扫一下' : ca ? '平板第一次用:先扫这张装证书' : '用你自己的手机扫一下'),
381
+ h('span', { class: 'lbl', style: 'line-height:1.5' }, kid ? '打开的就是孩子的首页。在 Safari 里「添加到主屏幕」,以后点图标就进来。' : ca ? '扫了点「允许」下载描述文件;到「设置」最上面点「已下载描述文件」装上;再到「设置 › 通用 › 关于本机 › 证书信任设置」把开关打开。装好再扫「孩子的平板」那张。每台平板做一次。' : '打开的是家长端:看记录、排首页。也可以添加到主屏幕。')),
365
382
  h('div', { class: 'qrurl' }, useIp ? c.ip : c.url),
366
383
  d.https ? null : h('div', { class: 'qrwarn' }, d.notes[0] || ''),
367
384
  h('div', { class: 'row2', style: 'font-size:14px' },
368
385
  c.ip ? h('button', { type: 'button', class: 'x', style: 'height:auto;padding:0;font-size:14px;text-align:left', on: { click: () => { QR.ip = !QR.ip; qrDraw(); } } }, useIp ? '换回 ' + host(c.url) : '扫了打不开?换成 ' + host(c.ip)) : h('span'),
369
386
  h('span', { style: 'display:flex;gap:14px;flex:none' },
370
387
  h('a', { class: 'lnk kidl', style: 'font-size:14px', href: '/', target: '_blank' }, '孩子端 ↗'),
371
- h('a', { class: 'lnk', style: 'font-size:14px', href: print, target: '_blank' }, '打印 ›'))))),
388
+ ca ? null : h('a', { class: 'lnk', style: 'font-size:14px', href: print, target: '_blank' }, '打印 ›'))))),
372
389
  h('div', { class: 'note' }, d.https ? (d.notes[0] || '') : '', d.devices ? '' : (d.https ? ' ' : '') + '还没有平板连进来过,所以这块先开着;连过以后自动收起。'));
373
390
  };
374
391
 
375
392
  // 有新版本(服务每天问一次 npm,machine/update.ts):只在家长端说,孩子端不说;点「知道了」这个版本不再提,读不了 localStorage 就每次都说
376
393
  const UPGRADE_STEPS = ${JSON.stringify(upgradeSteps())};
394
+ // 还差几步(parent-setup.ts):第一次打开家长端,告诉家长接下来做什么。必需的都好了就只剩建议,「知道了」以后不再提
395
+ const showSetup = async () => {
396
+ const box = $('#setupbar');
397
+ const d = await api('GET', '/api/parent/setup').catch(() => null);
398
+ if (!d) { box.replaceChildren(); return; }
399
+ let hidden = false;
400
+ try { hidden = localStorage.getItem('cotutor.setupHidden') === '1'; } catch {}
401
+ const must = d.steps.filter((s) => s.required);
402
+ const left = must.filter((s) => !s.done);
403
+ const extra = d.steps.filter((s) => !s.required && !s.done);
404
+ if (!left.length && (hidden || !extra.length)) { box.replaceChildren(); return; }
405
+ const pickGrade = async (g) => {
406
+ try { await api('POST', '/api/parent/setup/grade', { grade: g }); toast('记下了:' + g + ' 年级'); } catch (e) { toast(e.message); }
407
+ showSetup();
408
+ };
409
+ const row = (s) => h('div', { class: 'sp' + (s.done ? ' on' : '') },
410
+ h('span', { class: 'mk' }, s.done ? '✓' : '○'),
411
+ h('span', { class: 'tx' }, h('b', {}, s.title),
412
+ s.done ? null : h('small', {}, s.detail, s.link ? ' ' : null, s.link ? h('a', { class: 'lnk', href: s.link.href, target: '_blank', rel: 'noopener' }, s.link.text) : null),
413
+ !s.done && s.commands ? h('pre', {}, s.commands.map((c) => h('div', {}, c))) : null,
414
+ !s.done && s.grades ? h('span', { class: 'gr' }, [1, 2, 3, 4, 5, 6].map((g) => h('button', { type: 'button', on: { click: () => pickGrade(g) } }, g + ' 年级'))) : null));
415
+ box.replaceChildren(h('div', { class: 'setup' },
416
+ h('b', {}, left.length ? '还差 ' + left.length + ' 步,孩子就能用了' : '都好了,还有几件可以做的'),
417
+ ...(left.length ? must.concat(extra) : extra).map(row),
418
+ left.length ? null : h('button', { type: 'button', class: 'hide', on: { click: () => { try { localStorage.setItem('cotutor.setupHidden', '1'); } catch {} box.replaceChildren(); } } }, '知道了')));
419
+ };
377
420
  // 跑起来以后百炼出的问题(欠费、key 失效、连不上,machine/bailian.ts):配好了不等于用得了。试连通了就没了
378
421
  const showTrouble = (hh) => {
379
422
  const box = $('#troublebar');
@@ -406,6 +449,7 @@ ${pageDomJs(3200)}
406
449
  };
407
450
  const load = async () => {
408
451
  showUpdate();
452
+ showSetup();
409
453
  try { D = await api('GET', '/api/parent/home'); } catch (e) { toast('读不到:' + e.message); return; }
410
454
  BL.st = await api('GET', '/api/parent/bailian').catch(() => null);
411
455
  QR.d = await api('GET', '/api/parent/qr').catch(() => null);
@@ -1,5 +1,5 @@
1
1
  /**
2
- * 家长端「设置」(/parent/settings):设一次就不常动的。现在只有一项——孩子的平板上,按住说话那一栏放哪边(cotutor.json 的 kid.hand)。
2
+ * 家长端「设置」(/parent/settings):设一次就不常动的。备份和诊断信息也放这(parent-setup.ts)。孩子的平板上,按住说话那一栏放哪边(cotutor.json 的 kid.hand)。
3
3
  * 两张示意图(不是截图,页面现画的 SVG):横着的平板,窄的一栏是老师头像 + 按住说话,宽的一边是写字的白纸;点一张就存。
4
4
  * 孩子端首页的接口带着它(/api/kid/home 的 hand),孩子下次进老师页就换过来;画板那一列工具跟着一起挪。
5
5
  * 零依赖内联脚本,只走 /api/parent/settings(GET 读,PATCH {kid: {hand}} 改)。
@@ -32,6 +32,10 @@ ${BRAND_CSS}
32
32
  .seg > * { flex:1; height:36px; border-radius:9px; font-size:15px; color:var(--dim); display:flex; align-items:center; justify-content:center; text-decoration:none; }
33
33
  .seg > .on { background:#fff; color:var(--ink); font-weight:600; box-shadow:0 1px 2px rgba(0,0,0,.08); }
34
34
  .gh { font-size:13px; color:var(--mute); padding:8px 16px 6px; }
35
+ .acts { display:flex; flex-wrap:wrap; gap:8px; padding:0 3px 12px; }
36
+ .act { display:inline-flex; align-items:center; min-height:44px; padding:0 14px; border:0; border-radius:10px; background:var(--paper, transparent); box-shadow:0 0 0 1px var(--line); color:inherit; font-size:15px; text-decoration:none; cursor:pointer; }
37
+ .act[disabled] { opacity:.5; }
38
+ #rep-text { margin:0 3px 12px; padding:10px 12px; max-height:320px; overflow:auto; border-radius:10px; box-shadow:0 0 0 1px var(--line); font:12px/1.55 ui-monospace,Menlo,Consolas,monospace; white-space:pre-wrap; overflow-wrap:anywhere; }
35
39
  .grp { background:var(--card); border-radius:14px; padding:14px; display:flex; flex-direction:column; gap:12px; }
36
40
  .q { font-size:16px; font-weight:500; padding:0 2px; }
37
41
  .hands { display:grid; grid-template-columns:1fr 1fr; gap:12px; }
@@ -63,6 +67,22 @@ ${BRAND_CSS}
63
67
  <div class="note">平板横着用的时候,老师页上那一栏(老师的头像、按住说话)放在这边,另一边留给写字;画板上那一列工具也跟着放这边。孩子下次进老师页就换过来。</div>
64
68
  </div>
65
69
  </div>
70
+ <div>
71
+ <div class="gh">备份</div>
72
+ <div class="grp">
73
+ <div class="note" id="bk-note">读取中……</div>
74
+ <div class="acts"><button type="button" class="act" id="bk-go">现在备份一份</button></div>
75
+ </div>
76
+ </div>
77
+ <div>
78
+ <div class="gh">遇到问题</div>
79
+ <div class="grp">
80
+ <div class="note">生成一份诊断信息,发给开发者或帮你的 AI 助手,不用来回问。里面没有孩子的对话、照片、录音、档案和 key,名字和 IP 已经抹掉。不会自动发出去,你可以先看一遍。</div>
81
+ <div class="acts"><button type="button" class="act" id="rep-go">生成诊断信息</button></div>
82
+ <pre id="rep-text" hidden></pre>
83
+ <div class="acts" id="rep-acts" hidden><button type="button" class="act" id="rep-copy">复制</button><a class="act" href="https://github.com/TarsLab/cotutor/issues/new?template=bug.yml" target="_blank" rel="noopener">到 GitHub 反馈</a></div>
84
+ </div>
85
+ </div>
66
86
  ${BRAND_FOOTER}
67
87
  </div>
68
88
  <div id="toast"></div>
@@ -125,8 +145,52 @@ ${pageDomJs(3200)}
125
145
  if (S) { document.title = S.title + ' · 家长 · 设置'; $('#title').textContent = S.title; }
126
146
  draw();
127
147
  };
148
+ // 备份:只读和「现在备一份」;恢复要停服务,在终端里做,这里说怎么做
149
+ const bkLoad = async () => {
150
+ const d = await api('GET', '/api/parent/backups').catch(() => null);
151
+ const note = $('#bk-note');
152
+ if (!d) { note.textContent = '读不到备份的情况'; return; }
153
+ const last = d.list[0];
154
+ const mb = (n) => (n / 1024 / 1024).toFixed(1) + ' MB';
155
+ note.textContent = (last ? '最近一份 ' + new Date(last.at).toLocaleString() + ',' + last.files + ' 个文件,' + mb(last.bytes) + ';一共留着 ' + d.list.length + ' 份。' : '还没有备份。') + '放在 ' + d.dir + '。服务开着时每天自动备一份,升级前也备一份;录音占地方,不在备份里。要恢复:在这台电脑的终端里跑 ' + d.commands.list + ' 看有哪些,再 ' + d.commands.restore + '。';
156
+ };
157
+ $('#bk-go').addEventListener('click', async () => {
158
+ const b = $('#bk-go');
159
+ b.disabled = true;
160
+ try { await api('POST', '/api/parent/backups', {}); toast('备份好了'); } catch (e) { toast('没备份成:' + e.message); }
161
+ b.disabled = false;
162
+ bkLoad();
163
+ });
164
+ // 诊断信息:先给人看,复制是人点的;不自动发
165
+ $('#rep-go').addEventListener('click', async () => {
166
+ const b = $('#rep-go');
167
+ b.disabled = true;
168
+ try {
169
+ const r = await api('GET', '/api/parent/report');
170
+ $('#rep-text').textContent = r.text;
171
+ $('#rep-text').hidden = false;
172
+ $('#rep-acts').hidden = false;
173
+ } catch (e) { toast('没生成成:' + e.message); }
174
+ b.disabled = false;
175
+ });
176
+ $('#rep-copy').addEventListener('click', async () => {
177
+ const text = $('#rep-text').textContent;
178
+ try {
179
+ await navigator.clipboard.writeText(text);
180
+ toast('复制好了');
181
+ } catch {
182
+ // 不是 https 的地址没有剪贴板接口:选中,让人自己复制
183
+ const range = document.createRange();
184
+ range.selectNodeContents($('#rep-text'));
185
+ const sel = getSelection();
186
+ sel.removeAllRanges();
187
+ sel.addRange(range);
188
+ toast('已选中,按复制');
189
+ }
190
+ });
128
191
  draw();
129
192
  load();
193
+ bkLoad();
130
194
  })();
131
195
  </script>
132
196
  </body></html>
package/install.ps1 ADDED
@@ -0,0 +1,66 @@
1
+ # cotutor 一行安装(Windows,在 PowerShell 里粘贴):
2
+ # irm https://raw.githubusercontent.com/TarsLab/cotutor/main/install.ps1 | iex
3
+ # 连不上 GitHub 就换这个:
4
+ # irm https://cdn.jsdelivr.net/npm/cotutor@latest/install.ps1 | iex
5
+ # 顺手建好孩子的文件夹、装好后台服务(短名 称呼 年级):
6
+ # & ([scriptblock]::Create((irm https://raw.githubusercontent.com/TarsLab/cotutor/main/install.ps1))) ming 小明 2
7
+ #
8
+ # 只做这几件事:查 Node 的版本;npm 连不上就用国内镜像;装 cotutor。
9
+ # 不要管理员,不改执行策略:npm、cotutor 都用 .cmd 跑(PowerShell 缺省策略会拦 .ps1)。Node 没装或太旧时只说怎么装,不替你装。
10
+ $ErrorActionPreference = 'Stop'
11
+
12
+ function Say($text) { Write-Host $text }
13
+ function Stop-Here($text) { Write-Host $text; throw 'cotutor-install-stopped' }
14
+
15
+ $needMajor = 22
16
+ $needMinor = 18
17
+
18
+ try {
19
+ # ---- 1. Node ----
20
+ if (-not (Get-Command node -ErrorAction SilentlyContinue)) {
21
+ Stop-Here "这台电脑还没有 Node.js:到 https://nodejs.org 下载 LTS 版(Windows 安装程序)装上,或者跑 winget install OpenJS.NodeJS.LTS;装完重开 PowerShell 再跑这一行。"
22
+ }
23
+ $v = (& node -p 'process.versions.node').Trim()
24
+ $parts = $v.Split('.')
25
+ if ([int]$parts[0] -lt $needMajor -or ([int]$parts[0] -eq $needMajor -and [int]$parts[1] -lt $needMinor)) {
26
+ Stop-Here "Node.js 是 $v,cotutor 要 $needMajor.$needMinor 以上:到 https://nodejs.org 装新的 LTS 版,重开 PowerShell 再跑这一行。"
27
+ }
28
+ if (-not (Get-Command npm.cmd -ErrorAction SilentlyContinue)) { Stop-Here '有 Node.js 但找不到 npm:到 https://nodejs.org 重新装一次 LTS 版。' }
29
+ Say "Node.js $v"
30
+
31
+ # ---- 2. npm 连得上吗(国内常连不上,换镜像) ----
32
+ $registry = $null
33
+ try { Invoke-WebRequest -UseBasicParsing -TimeoutSec 8 'https://registry.npmjs.org/cotutor/latest' | Out-Null }
34
+ catch { $registry = 'https://registry.npmmirror.com'; Say "npm 连不上或太慢,用国内镜像 $registry" }
35
+
36
+ # ---- 3. 装 ----
37
+ Say '正在下载 cotutor,要一会儿……'
38
+ $npmArgs = @('i', '-g', 'cotutor', '--no-audit', '--no-fund')
39
+ if ($registry) { $npmArgs += "--registry=$registry" }
40
+ & npm.cmd @npmArgs
41
+ if ($LASTEXITCODE -ne 0) { Stop-Here 'npm 没装成:看上面的报错;连不上就过一会儿再试。' }
42
+ # 刚装上的 cotutor.cmd 在 npm 的全局目录里;这个窗口的 PATH 可能还没有它
43
+ $globalDir = (& npm.cmd prefix -g).Trim()
44
+ if (-not (Get-Command cotutor.cmd -ErrorAction SilentlyContinue)) { $env:Path = "$globalDir;$env:Path" }
45
+ if (-not (Get-Command cotutor.cmd -ErrorAction SilentlyContinue)) { Stop-Here "装好了但找不到 cotutor:重开 PowerShell 再试;还不行,把 $globalDir 加进 PATH。" }
46
+ Say ('cotutor ' + (& cotutor.cmd --version).Trim() + ' 装好了')
47
+
48
+ # ---- 4. 带了孩子的信息就接着建文件夹、装后台服务 ----
49
+ if ($args.Count -ge 1) {
50
+ $initArgs = @('init', $args[0])
51
+ if ($args.Count -ge 2 -and $args[1]) { $initArgs += @('--name', $args[1]) }
52
+ if ($args.Count -ge 3 -and $args[2]) { $initArgs += @('--grade', [string]$args[2]) }
53
+ & cotutor.cmd @initArgs
54
+ if ($LASTEXITCODE -ne 0) { Stop-Here '建孩子的文件夹没成:看上面的报错。' }
55
+ & cotutor.cmd service install
56
+ Say ''
57
+ Say '好了。家长端已经在浏览器里打开;以后点任务栏右下角 ^ 里的 cotutor 图标,或者跑 cotutor.cmd open。'
58
+ } else {
59
+ Say ''
60
+ Say '接下来(短名用小写字母,不用真名;年级 1 到 6):'
61
+ Say ' cotutor.cmd init ming --name 小明 --grade 2'
62
+ Say ' cotutor.cmd service install'
63
+ }
64
+ } catch {
65
+ if ($_.Exception.Message -ne 'cotutor-install-stopped') { Write-Host ('出错了:' + $_.Exception.Message) }
66
+ }