cotutor 0.2.0 → 0.3.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 (871) hide show
  1. package/LICENSE +247 -21
  2. package/NOTICE +42 -0
  3. package/README.md +92 -20
  4. package/bin/cotutor.js +4 -4
  5. package/cards/canvas/card.css +8 -0
  6. package/cards/canvas/card.md +68 -0
  7. package/cards/choice/card.css +18 -0
  8. package/cards/choice/card.md +55 -0
  9. package/cards/code/card.css +5 -0
  10. package/cards/code/card.md +46 -0
  11. package/cards/dictation/card.css +10 -0
  12. package/cards/dictation/card.md +97 -0
  13. package/cards/image/card.css +10 -0
  14. package/cards/image/card.md +52 -0
  15. package/cards/lecture/card.css +9 -0
  16. package/cards/lecture/card.md +69 -0
  17. package/cards/paint/card.css +20 -0
  18. package/cards/paint/card.md +77 -0
  19. package/cards/photo/card.css +15 -0
  20. package/cards/photo/card.md +61 -0
  21. package/cards/read/card.css +6 -0
  22. package/cards/read/card.md +51 -0
  23. package/cards/text/card.css +3 -0
  24. package/cards/text/card.md +69 -0
  25. package/cards/tianzige/card.css +17 -0
  26. package/cards/tianzige/card.md +78 -0
  27. package/cards/tutor/card.css +66 -0
  28. package/cards/tutor/card.md +148 -0
  29. package/cards/word/card.css +24 -0
  30. package/cards/word/card.md +91 -0
  31. package/cards//346/235/277/344/271/246/346/200/216/344/271/210/345/206/231.md +159 -0
  32. package/dist/app/activity-eval-rules.d.ts +62 -0
  33. package/dist/app/activity-eval-rules.js +276 -0
  34. package/dist/app/activity-eval.d.ts +65 -0
  35. package/dist/app/activity-eval.js +158 -0
  36. package/dist/app/build.d.ts +11 -0
  37. package/dist/app/build.js +45 -0
  38. package/dist/app/cli/activities.d.ts +63 -0
  39. package/dist/app/cli/activities.js +158 -0
  40. package/dist/{cli → app/cli}/cert.js +3 -3
  41. package/dist/app/cli/chalk/bake.d.ts +10 -0
  42. package/dist/app/cli/chalk/bake.js +58 -0
  43. package/dist/app/cli/chalk/browser.d.ts +16 -0
  44. package/dist/app/cli/chalk/browser.js +142 -0
  45. package/dist/app/cli/chalk/build.d.ts +14 -0
  46. package/dist/app/cli/chalk/build.js +100 -0
  47. package/dist/app/cli/chalk/dub.d.ts +51 -0
  48. package/dist/app/cli/chalk/dub.js +106 -0
  49. package/dist/app/cli/chalk/load-scene.d.ts +34 -0
  50. package/dist/app/cli/chalk/load-scene.js +117 -0
  51. package/dist/app/cli/chalk/main.d.ts +7 -0
  52. package/dist/app/cli/chalk/main.js +198 -0
  53. package/dist/app/cli/chalk/serve.d.ts +4 -0
  54. package/dist/app/cli/chalk/serve.js +28 -0
  55. package/dist/app/cli/chalk/snap.d.ts +65 -0
  56. package/dist/app/cli/chalk/snap.js +103 -0
  57. package/dist/app/cli/chalk/typecheck.d.ts +7 -0
  58. package/dist/app/cli/chalk/typecheck.js +51 -0
  59. package/dist/{cli → app/cli}/doctor.d.ts +4 -3
  60. package/dist/app/cli/doctor.js +617 -0
  61. package/dist/app/cli/grades.d.ts +14 -0
  62. package/dist/app/cli/grades.js +44 -0
  63. package/dist/{cli → app/cli}/init.d.ts +3 -1
  64. package/dist/app/cli/init.js +155 -0
  65. package/dist/app/cli/main.js +715 -0
  66. package/dist/app/cli/migrate.d.ts +58 -0
  67. package/dist/app/cli/migrate.js +253 -0
  68. package/dist/{cli → app/cli}/serve.d.ts +12 -5
  69. package/dist/app/cli/serve.js +98 -0
  70. package/dist/app/cli/shipped.d.ts +30 -0
  71. package/dist/app/cli/shipped.js +47 -0
  72. package/dist/app/cli/skeleton.d.ts +38 -0
  73. package/dist/app/cli/skeleton.js +161 -0
  74. package/dist/app/cli/skills.d.ts +55 -0
  75. package/dist/app/cli/skills.js +189 -0
  76. package/dist/app/cli/themes.d.ts +52 -0
  77. package/dist/app/cli/themes.js +148 -0
  78. package/dist/{cli → app/cli}/tutors.d.ts +15 -26
  79. package/dist/{cli → app/cli}/tutors.js +86 -110
  80. package/dist/app/cli/usage.d.ts +2 -0
  81. package/dist/app/cli/usage.js +30 -0
  82. package/dist/app/dictation/recognize.d.ts +18 -0
  83. package/dist/app/dictation/recognize.js +6 -0
  84. package/dist/app/dictation/route.d.ts +52 -0
  85. package/dist/app/dictation/route.js +510 -0
  86. package/dist/app/diff.d.ts +11 -0
  87. package/dist/app/diff.js +71 -0
  88. package/dist/app/http/access.d.ts +62 -0
  89. package/dist/app/http/access.js +180 -0
  90. package/dist/app/http/app.d.ts +246 -0
  91. package/dist/app/http/app.js +1212 -0
  92. package/dist/app/http/dev-activities.d.ts +115 -0
  93. package/dist/app/http/dev-activities.js +193 -0
  94. package/dist/app/http/dev-overview.d.ts +108 -0
  95. package/dist/app/http/dev-overview.js +209 -0
  96. package/dist/app/http/dev-tutor-files.d.ts +80 -0
  97. package/dist/app/http/dev-tutor-files.js +151 -0
  98. package/dist/app/http/parent-home.d.ts +37 -0
  99. package/dist/app/http/parent-home.js +203 -0
  100. package/dist/app/http/range.d.ts +9 -0
  101. package/dist/app/http/range.js +19 -0
  102. package/dist/app/http/raw-view.d.ts +117 -0
  103. package/dist/app/http/raw-view.js +149 -0
  104. package/dist/app/http/send-file.d.ts +7 -0
  105. package/dist/app/http/send-file.js +29 -0
  106. package/dist/{server → app/http}/stage.d.ts +9 -0
  107. package/dist/{server → app/http}/stage.js +34 -6
  108. package/dist/app/http/theme.d.ts +13 -0
  109. package/dist/app/http/theme.js +41 -0
  110. package/dist/app/machine/bailian.d.ts +28 -0
  111. package/dist/app/machine/bailian.js +88 -0
  112. package/dist/app/mock/mock-live.d.ts +16 -0
  113. package/dist/app/mock/mock-live.js +140 -0
  114. package/dist/{server → app/mock}/mock.d.ts +36 -5
  115. package/dist/app/mock/mock.js +1117 -0
  116. package/dist/app/replay.d.ts +94 -0
  117. package/dist/app/replay.js +170 -0
  118. package/dist/app/skills/analyze-doc.d.ts +3 -0
  119. package/dist/app/skills/analyze-doc.js +47 -0
  120. package/dist/app/skills/home-doc.d.ts +5 -0
  121. package/dist/app/skills/home-doc.js +112 -0
  122. package/dist/app/skills/tune-doc.d.ts +3 -0
  123. package/dist/app/skills/tune-doc.js +80 -0
  124. package/dist/app/talk/list.d.ts +11 -0
  125. package/dist/app/talk/list.js +9 -0
  126. package/dist/app/talk/route.d.ts +16 -0
  127. package/dist/app/talk/route.js +142 -0
  128. package/dist/app/workspace.d.ts +58 -0
  129. package/dist/{cli → app}/workspace.js +77 -52
  130. package/dist/app/ws/route.d.ts +25 -0
  131. package/dist/app/ws/route.js +29 -0
  132. package/dist/app/ws/ws.d.ts +31 -0
  133. package/dist/app/ws/ws.js +169 -0
  134. package/dist/board/canvas-chat.d.ts +97 -0
  135. package/dist/board/canvas-chat.js +175 -0
  136. package/dist/board/card-guards.d.ts +15 -0
  137. package/dist/board/card-guards.js +38 -0
  138. package/dist/board/cards/canvas.d.ts +41 -0
  139. package/dist/board/cards/canvas.js +83 -0
  140. package/dist/{cards → board/cards}/choice.js +0 -12
  141. package/dist/{cards → board/cards}/code.js +0 -3
  142. package/dist/board/cards/dictation.d.ts +42 -0
  143. package/dist/board/cards/dictation.js +105 -0
  144. package/dist/board/cards/docs.d.ts +47 -0
  145. package/dist/board/cards/docs.js +152 -0
  146. package/dist/{cards → board/cards}/image.js +1 -10
  147. package/dist/board/cards/index.d.ts +62 -0
  148. package/dist/board/cards/index.js +144 -0
  149. package/dist/{cards → board/cards}/kind.d.ts +10 -4
  150. package/dist/board/cards/kind.js +9 -0
  151. package/dist/board/cards/lecture.d.ts +26 -0
  152. package/dist/board/cards/lecture.js +62 -0
  153. package/dist/board/cards/paint.d.ts +38 -0
  154. package/dist/board/cards/paint.js +85 -0
  155. package/dist/board/cards/photo.d.ts +15 -0
  156. package/dist/board/cards/photo.js +29 -0
  157. package/dist/{cards → board/cards}/read.js +1 -10
  158. package/dist/board/cards/text.d.ts +20 -0
  159. package/dist/board/cards/text.js +59 -0
  160. package/dist/board/cards/tianzige.d.ts +16 -0
  161. package/dist/board/cards/tianzige.js +64 -0
  162. package/dist/board/cards/tutor.d.ts +72 -0
  163. package/dist/board/cards/tutor.js +134 -0
  164. package/dist/board/cards/word.d.ts +20 -0
  165. package/dist/board/cards/word.js +76 -0
  166. package/dist/board/lecture.d.ts +100 -0
  167. package/dist/board/lecture.js +204 -0
  168. package/dist/board/paper.d.ts +20 -0
  169. package/dist/board/paper.js +76 -0
  170. package/dist/board/parse.d.ts +120 -0
  171. package/dist/board/parse.js +330 -0
  172. package/dist/board/presentation.d.ts +295 -0
  173. package/dist/board/presentation.js +615 -0
  174. package/dist/board/sections.d.ts +16 -0
  175. package/dist/board/sections.js +130 -0
  176. package/dist/brain/api-tools.d.ts +8 -0
  177. package/dist/brain/api-tools.js +190 -0
  178. package/dist/brain/api.d.ts +62 -0
  179. package/dist/brain/api.js +411 -0
  180. package/dist/brain/cli/adapters.d.ts +60 -0
  181. package/dist/brain/cli/adapters.js +91 -0
  182. package/dist/brain/cli/qwen.d.ts +11 -0
  183. package/dist/brain/cli/qwen.js +141 -0
  184. package/dist/brain/cli/run-plan.d.ts +59 -0
  185. package/dist/brain/cli/run-plan.js +71 -0
  186. package/dist/brain/cli/run.d.ts +35 -0
  187. package/dist/brain/cli/run.js +256 -0
  188. package/dist/brain/cli/stream-json.d.ts +18 -0
  189. package/dist/brain/cli/stream-json.js +86 -0
  190. package/dist/brain/cli/types.d.ts +144 -0
  191. package/dist/brain/cli/types.js +3 -0
  192. package/dist/brain/cli/warm.d.ts +53 -0
  193. package/dist/brain/cli/warm.js +103 -0
  194. package/dist/brain/index.d.ts +145 -0
  195. package/dist/brain/index.js +74 -0
  196. package/dist/brain/stream.d.ts +20 -0
  197. package/dist/brain/stream.js +70 -0
  198. package/dist/brain/transcript.d.ts +45 -0
  199. package/dist/brain/transcript.js +132 -0
  200. package/dist/chalk/actions.d.ts +37 -0
  201. package/dist/chalk/actions.js +69 -0
  202. package/dist/chalk/bundle.d.ts +26 -0
  203. package/dist/chalk/bundle.js +69 -0
  204. package/dist/chalk/check.d.ts +28 -0
  205. package/dist/chalk/check.js +291 -0
  206. package/dist/chalk/circle.d.ts +64 -0
  207. package/dist/chalk/circle.js +193 -0
  208. package/dist/chalk/clock.d.ts +84 -0
  209. package/dist/chalk/clock.js +84 -0
  210. package/dist/chalk/geometry.d.ts +44 -0
  211. package/dist/chalk/geometry.js +139 -0
  212. package/dist/chalk/glyphs/capitals.d.ts +12 -0
  213. package/dist/chalk/glyphs/capitals.js +264 -0
  214. package/dist/chalk/glyphs/index.d.ts +21 -0
  215. package/dist/chalk/glyphs/index.js +18 -0
  216. package/dist/chalk/glyphs/letters.d.ts +13 -0
  217. package/dist/chalk/glyphs/letters.js +280 -0
  218. package/dist/chalk/glyphs/metrics.d.ts +33 -0
  219. package/dist/chalk/glyphs/metrics.js +28 -0
  220. package/dist/chalk/glyphs/registry.d.ts +7 -0
  221. package/dist/chalk/glyphs/registry.js +8 -0
  222. package/dist/chalk/glyphs/sample.d.ts +32 -0
  223. package/dist/chalk/glyphs/sample.js +102 -0
  224. package/dist/chalk/glyphs/skeleton.d.ts +64 -0
  225. package/dist/chalk/glyphs/skeleton.js +126 -0
  226. package/dist/chalk/glyphs/types.d.ts +58 -0
  227. package/dist/chalk/glyphs/types.js +17 -0
  228. package/dist/chalk/index.d.ts +23 -0
  229. package/dist/chalk/index.js +15 -0
  230. package/dist/chalk/manifest.d.ts +41 -0
  231. package/dist/chalk/manifest.js +6 -0
  232. package/dist/chalk/paint.d.ts +180 -0
  233. package/dist/chalk/paint.js +210 -0
  234. package/dist/chalk/pointer.d.ts +8 -0
  235. package/dist/chalk/pointer.js +21 -0
  236. package/dist/chalk/prepare.d.ts +11 -0
  237. package/dist/chalk/prepare.js +15 -0
  238. package/dist/chalk/scene-schema.d.ts +199 -0
  239. package/dist/chalk/scene-schema.js +91 -0
  240. package/dist/chalk/seed.d.ts +3 -0
  241. package/dist/chalk/seed.js +10 -0
  242. package/dist/chalk/text-metrics.d.ts +8 -0
  243. package/dist/chalk/text-metrics.js +156 -0
  244. package/dist/chalk/timeline.d.ts +47 -0
  245. package/dist/chalk/timeline.js +84 -0
  246. package/dist/chalk/types.d.ts +150 -0
  247. package/dist/chalk/types.js +8 -0
  248. package/dist/lib/index.d.ts +14 -12
  249. package/dist/lib/index.js +14 -12
  250. package/dist/media/draw.d.ts +23 -0
  251. package/dist/media/draw.js +44 -0
  252. package/dist/media/mp3.d.ts +6 -0
  253. package/dist/media/mp3.js +58 -0
  254. package/dist/media/mp4.d.ts +1 -0
  255. package/dist/media/mp4.js +58 -0
  256. package/dist/media/tts-voices.d.ts +18 -0
  257. package/dist/media/tts-voices.js +606 -0
  258. package/dist/media/tts.d.ts +56 -0
  259. package/dist/media/tts.js +174 -0
  260. package/dist/media/vision.d.ts +25 -0
  261. package/dist/media/vision.js +71 -0
  262. package/dist/memory/commit.d.ts +67 -0
  263. package/dist/memory/commit.js +130 -0
  264. package/dist/memory/context.d.ts +86 -0
  265. package/dist/memory/context.js +97 -0
  266. package/dist/memory/diary.d.ts +84 -0
  267. package/dist/memory/diary.js +183 -0
  268. package/dist/memory/grade.d.ts +2 -0
  269. package/dist/memory/grade.js +7 -0
  270. package/dist/{lib → memory}/plan.d.ts +1 -1
  271. package/dist/{lib → memory}/plan.js +1 -1
  272. package/dist/memory/proposals.d.ts +11 -0
  273. package/dist/memory/proposals.js +43 -0
  274. package/dist/memory/retrieval.d.ts +44 -0
  275. package/dist/memory/retrieval.js +157 -0
  276. package/dist/{lib → memory}/timetable.d.ts +0 -3
  277. package/dist/{lib → memory}/timetable.js +0 -11
  278. package/dist/memory/vault-notes.d.ts +165 -0
  279. package/dist/memory/vault-notes.js +359 -0
  280. package/dist/memory/vault.d.ts +70 -0
  281. package/dist/memory/vault.js +169 -0
  282. package/dist/realtime/bailian.d.ts +120 -0
  283. package/dist/realtime/bailian.js +288 -0
  284. package/dist/realtime/cues.d.ts +51 -0
  285. package/dist/realtime/cues.js +94 -0
  286. package/dist/realtime/listen.d.ts +32 -0
  287. package/dist/realtime/listen.js +53 -0
  288. package/dist/realtime/preview.d.ts +23 -0
  289. package/dist/realtime/preview.js +38 -0
  290. package/dist/realtime/prompt.d.ts +8 -0
  291. package/dist/realtime/prompt.js +13 -0
  292. package/dist/realtime/voices.d.ts +19 -0
  293. package/dist/realtime/voices.js +71 -0
  294. package/dist/runtime/activities.d.ts +17 -0
  295. package/dist/runtime/activities.js +46 -0
  296. package/dist/runtime/activity-state.d.ts +22 -0
  297. package/dist/runtime/activity-state.js +83 -0
  298. package/dist/runtime/activity.d.ts +63 -0
  299. package/dist/runtime/activity.js +428 -0
  300. package/dist/runtime/agent-file.d.ts +24 -0
  301. package/dist/runtime/agent-file.js +59 -0
  302. package/dist/runtime/auto-bookkeep.d.ts +30 -0
  303. package/dist/runtime/auto-bookkeep.js +84 -0
  304. package/dist/{lib → runtime/context}/context-pack.d.ts +3 -3
  305. package/dist/runtime/context/context-pack.js +182 -0
  306. package/dist/runtime/context/thread-digest.d.ts +4 -0
  307. package/dist/runtime/context/thread-digest.js +35 -0
  308. package/dist/runtime/context/tutor-rules.d.ts +25 -0
  309. package/dist/runtime/context/tutor-rules.js +47 -0
  310. package/dist/runtime/delivery/delivery.d.ts +94 -0
  311. package/dist/runtime/delivery/delivery.js +145 -0
  312. package/dist/runtime/delivery/playback.d.ts +25 -0
  313. package/dist/runtime/delivery/playback.js +29 -0
  314. package/dist/runtime/delivery/player.d.ts +145 -0
  315. package/dist/runtime/delivery/player.js +221 -0
  316. package/dist/runtime/delivery/queue.d.ts +89 -0
  317. package/dist/runtime/delivery/queue.js +59 -0
  318. package/dist/runtime/home/edit.d.ts +39 -0
  319. package/dist/runtime/home/edit.js +132 -0
  320. package/dist/runtime/home/home.d.ts +180 -0
  321. package/dist/runtime/home/home.js +311 -0
  322. package/dist/runtime/home/store.d.ts +142 -0
  323. package/dist/runtime/home/store.js +440 -0
  324. package/dist/runtime/journal/conversation.d.ts +46 -0
  325. package/dist/runtime/journal/conversation.js +89 -0
  326. package/dist/runtime/journal/events.d.ts +27 -0
  327. package/dist/runtime/journal/events.js +136 -0
  328. package/dist/runtime/journal/kid-log.d.ts +105 -0
  329. package/dist/runtime/journal/kid-log.js +133 -0
  330. package/dist/runtime/journal/ledger.d.ts +17 -0
  331. package/dist/{lib → runtime/journal}/ledger.js +7 -40
  332. package/dist/runtime/journal/mix.d.ts +33 -0
  333. package/dist/runtime/journal/mix.js +88 -0
  334. package/dist/runtime/journal/mouth-index.d.ts +26 -0
  335. package/dist/runtime/journal/mouth-index.js +34 -0
  336. package/dist/runtime/journal/mouth.d.ts +54 -0
  337. package/dist/runtime/journal/mouth.js +102 -0
  338. package/dist/runtime/journal/recorder.d.ts +46 -0
  339. package/dist/runtime/journal/recorder.js +58 -0
  340. package/dist/runtime/journal/store.d.ts +123 -0
  341. package/dist/runtime/journal/store.js +316 -0
  342. package/dist/runtime/kid-input.d.ts +16 -0
  343. package/dist/runtime/kid-input.js +195 -0
  344. package/dist/runtime/kid-view.d.ts +124 -0
  345. package/dist/runtime/kid-view.js +157 -0
  346. package/dist/runtime/lecture.d.ts +86 -0
  347. package/dist/runtime/lecture.js +237 -0
  348. package/dist/runtime/live/call.d.ts +219 -0
  349. package/dist/runtime/live/call.js +1211 -0
  350. package/dist/runtime/live/turns.d.ts +48 -0
  351. package/dist/runtime/live/turns.js +102 -0
  352. package/dist/runtime/runner.d.ts +289 -0
  353. package/dist/runtime/runner.js +898 -0
  354. package/dist/runtime/talk-run.d.ts +21 -0
  355. package/dist/runtime/talk-run.js +34 -0
  356. package/dist/scenes/dictation/match.d.ts +57 -0
  357. package/dist/scenes/dictation/match.js +255 -0
  358. package/dist/scenes/dictation/recognize.d.ts +86 -0
  359. package/dist/scenes/dictation/recognize.js +163 -0
  360. package/dist/scenes/dictation/store.d.ts +112 -0
  361. package/dist/scenes/dictation/store.js +99 -0
  362. package/dist/scenes/look.d.ts +26 -0
  363. package/dist/scenes/look.js +1 -0
  364. package/dist/scenes/paint/painter.d.ts +84 -0
  365. package/dist/scenes/paint/painter.js +170 -0
  366. package/dist/scenes/paint/prompt.d.ts +23 -0
  367. package/dist/scenes/paint/prompt.js +36 -0
  368. package/dist/scenes/talk/en-words.d.ts +8 -0
  369. package/dist/scenes/talk/en-words.js +44 -0
  370. package/dist/scenes/talk/list.d.ts +44 -0
  371. package/dist/scenes/talk/list.js +88 -0
  372. package/dist/scenes/talk/store.d.ts +27 -0
  373. package/dist/scenes/talk/store.js +61 -0
  374. package/dist/scenes/talk/warmup.d.ts +16 -0
  375. package/dist/scenes/talk/warmup.js +39 -0
  376. package/dist/schema/activity.d.ts +149 -0
  377. package/dist/schema/activity.js +113 -0
  378. package/dist/schema/board.d.ts +143 -2
  379. package/dist/schema/board.js +15 -3
  380. package/dist/schema/config.d.ts +309 -94
  381. package/dist/schema/config.js +259 -72
  382. package/dist/schema/context-pack.d.ts +76 -14
  383. package/dist/schema/context-pack.js +91 -10
  384. package/dist/{lib/conversation.d.ts → schema/conversation-files.d.ts} +11 -33
  385. package/dist/schema/conversation-files.js +26 -0
  386. package/dist/schema/conversation.d.ts +385 -49
  387. package/dist/schema/conversation.js +135 -19
  388. package/dist/schema/events.d.ts +138 -0
  389. package/dist/schema/events.js +1 -0
  390. package/dist/schema/home.d.ts +46 -0
  391. package/dist/schema/home.js +30 -0
  392. package/dist/schema/index.d.ts +14 -3
  393. package/dist/schema/index.js +14 -3
  394. package/dist/schema/kid-device.d.ts +20 -0
  395. package/dist/schema/kid-device.js +32 -0
  396. package/dist/schema/ledger.d.ts +8 -63
  397. package/dist/schema/ledger.js +7 -31
  398. package/dist/schema/memory.d.ts +73 -0
  399. package/dist/schema/memory.js +47 -0
  400. package/dist/schema/plan.d.ts +2 -2
  401. package/dist/schema/plan.js +2 -2
  402. package/dist/schema/sections.d.ts +32 -25
  403. package/dist/schema/sections.js +21 -22
  404. package/dist/schema/theme.d.ts +25 -0
  405. package/dist/schema/theme.js +26 -0
  406. package/dist/schema/timetable.d.ts +2 -2
  407. package/dist/schema/timetable.js +2 -2
  408. package/dist/schema/workspace.d.ts +41 -0
  409. package/dist/schema/workspace.js +9 -0
  410. package/dist/shared/errors.d.ts +8 -0
  411. package/dist/shared/errors.js +13 -0
  412. package/dist/shared/home.d.ts +2 -0
  413. package/dist/shared/home.js +16 -0
  414. package/dist/shared/human-notes.d.ts +5 -0
  415. package/dist/shared/human-notes.js +7 -0
  416. package/dist/shared/qianwen.d.ts +50 -0
  417. package/dist/shared/qianwen.js +109 -0
  418. package/dist/shared/time.d.ts +9 -0
  419. package/dist/shared/time.js +22 -0
  420. package/dist/shared/tokens.d.ts +18 -0
  421. package/dist/shared/tokens.js +11 -0
  422. package/dist/shared/wav.d.ts +10 -0
  423. package/dist/shared/wav.js +50 -0
  424. package/dist/stage/chunk-226TNLQA.js +129 -0
  425. package/dist/stage/chunk-24LGQEKE.js +1 -0
  426. package/dist/stage/chunk-25XV6UY3.js +10 -0
  427. package/dist/stage/chunk-2AZI3NHJ.js +1 -0
  428. package/dist/stage/chunk-2BQZTTBE.js +1 -0
  429. package/dist/stage/chunk-2M7CGY3Y.js +11 -0
  430. package/dist/stage/chunk-2VR4WFQ7.js +10 -0
  431. package/dist/stage/chunk-2ZYXBUWG.js +9 -0
  432. package/dist/stage/chunk-32LAWMGY.js +1 -0
  433. package/dist/stage/chunk-3LEMTSOO.js +11 -0
  434. package/dist/stage/chunk-3QCKGZYE.js +32 -0
  435. package/dist/stage/chunk-44P66WFA.js +1 -0
  436. package/dist/stage/chunk-4AM6FRR6.js +7 -0
  437. package/dist/stage/chunk-4QDE4SUK.js +1 -0
  438. package/dist/stage/chunk-4QESHV3U.js +1 -0
  439. package/dist/stage/chunk-4SG5QPHB.js +2 -0
  440. package/dist/stage/chunk-4T4UVCOC.js +1 -0
  441. package/dist/stage/chunk-4WUEPPG3.js +34 -0
  442. package/dist/stage/chunk-4YCN6UZ5.js +99 -0
  443. package/dist/stage/chunk-5V7ZY2AP.js +1 -0
  444. package/dist/stage/chunk-5VS5Y2VJ.js +6 -0
  445. package/dist/stage/chunk-5W4NO2ZD.js +62 -0
  446. package/dist/stage/chunk-65CRNICM.js +1 -0
  447. package/dist/stage/chunk-66MULO7F.js +5 -0
  448. package/dist/stage/chunk-6COFQTBS.js +162 -0
  449. package/dist/stage/chunk-6VZG3M3I.js +8 -0
  450. package/dist/stage/chunk-7HVDH43T.js +1 -0
  451. package/dist/stage/chunk-7JLJN4EZ.js +8 -0
  452. package/dist/stage/chunk-7QDSP4LN.js +1 -0
  453. package/dist/stage/chunk-7R6OQAO3.js +1 -0
  454. package/dist/stage/chunk-7VTTHZKW.js +7 -0
  455. package/dist/stage/chunk-ATHR5KEN.js +10 -0
  456. package/dist/stage/chunk-B6R5LTP2.js +36 -0
  457. package/dist/stage/chunk-BD4WE264.js +1 -0
  458. package/dist/stage/chunk-BONANU47.js +206 -0
  459. package/dist/stage/chunk-BTVW7OFK.js +89 -0
  460. package/dist/stage/chunk-BUTJIDHG.js +8 -0
  461. package/dist/stage/chunk-C2IPYMML.js +84 -0
  462. package/dist/stage/chunk-C54FTPPV.js +9 -0
  463. package/dist/stage/chunk-C6LOUF2Z.js +90 -0
  464. package/dist/stage/chunk-CFF3PILO.js +339 -0
  465. package/dist/stage/chunk-CI2FQ2JY.js +9 -0
  466. package/dist/stage/chunk-CW5O4RV7.js +12 -0
  467. package/dist/stage/chunk-CYABNQYD.js +1 -0
  468. package/dist/stage/chunk-D7FFA4NS.js +15 -0
  469. package/dist/stage/chunk-DUNNXU6Z.js +8 -0
  470. package/dist/stage/chunk-E3E4Q6JF.js +6 -0
  471. package/dist/stage/chunk-EB3U3LH7.js +9 -0
  472. package/dist/stage/chunk-EGSZ736B.js +8 -0
  473. package/dist/stage/chunk-EOBXW5VQ.js +2 -0
  474. package/dist/stage/chunk-ERZC3B7Y.js +11 -0
  475. package/dist/stage/chunk-ESDOOBIH.js +11 -0
  476. package/dist/stage/chunk-EVU4QAL4.js +178 -0
  477. package/dist/stage/chunk-EVVZI2NY.js +39 -0
  478. package/dist/stage/chunk-FBKAZUKD.js +39 -0
  479. package/dist/stage/chunk-FDVKYQJN.js +1 -0
  480. package/dist/stage/chunk-FGPVYHVR.js +5 -0
  481. package/dist/stage/chunk-FHUD4AZC.js +1 -0
  482. package/dist/stage/chunk-FKUJ2DMY.js +96 -0
  483. package/dist/stage/chunk-FNZGVIJV.js +1 -0
  484. package/dist/stage/chunk-GBYSEGYM.js +78 -0
  485. package/dist/stage/chunk-GCO4TDHX.js +1 -0
  486. package/dist/stage/chunk-GKTML2LG.js +10 -0
  487. package/dist/stage/chunk-GMDIHHXQ.js +11 -0
  488. package/dist/stage/chunk-GOUNACI3.js +10 -0
  489. package/dist/stage/chunk-GXAYATPF.js +3 -0
  490. package/dist/stage/chunk-H2K2DDXV.js +8 -0
  491. package/dist/stage/chunk-H3UJI6ZY.js +13 -0
  492. package/dist/stage/chunk-H6PUGCME.js +7 -0
  493. package/dist/stage/chunk-HNBUIMIG.js +1 -0
  494. package/dist/stage/chunk-HRZY2BJQ.js +10 -0
  495. package/dist/stage/chunk-HSPJGALW.js +30 -0
  496. package/dist/stage/chunk-IBYORHIP.js +25 -0
  497. package/dist/stage/chunk-IHF4EWTY.js +1 -0
  498. package/dist/stage/chunk-ISBRPNKI.js +1 -0
  499. package/dist/stage/chunk-IZ3OI3C2.js +2 -0
  500. package/dist/stage/chunk-JEFZAC2R.js +1 -0
  501. package/dist/stage/chunk-JFIGRDPO.js +1 -0
  502. package/dist/stage/chunk-JFVYBOOC.js +9 -0
  503. package/dist/stage/chunk-JGD4TUTQ.js +1 -0
  504. package/dist/stage/chunk-JO4BEHDH.js +4 -0
  505. package/dist/stage/chunk-JOWBS42C.js +1 -0
  506. package/dist/stage/chunk-JP3TM2TG.js +1 -0
  507. package/dist/stage/chunk-JVK2C52O.js +1 -0
  508. package/dist/stage/chunk-K4I76XBX.js +14 -0
  509. package/dist/stage/chunk-KA6CZZ4M.js +1 -0
  510. package/dist/stage/chunk-KESSJ36M.js +1 -0
  511. package/dist/stage/chunk-LKATEVRU.js +1 -0
  512. package/dist/stage/chunk-LS4EJ2EI.js +1 -0
  513. package/dist/stage/chunk-LUKJQC2X.js +70 -0
  514. package/dist/stage/chunk-LWULR3SM.js +1 -0
  515. package/dist/stage/chunk-LWVRFMKX.js +2 -0
  516. package/dist/stage/chunk-LXC4ZBPZ.js +1 -0
  517. package/dist/stage/chunk-M2UP255H.js +1 -0
  518. package/dist/stage/chunk-MAPPXUZQ.js +231 -0
  519. package/dist/stage/chunk-MBMPW7Z5.js +1 -0
  520. package/dist/stage/chunk-MD3HMMTK.js +1 -0
  521. package/dist/stage/chunk-MLPCUIKR.js +17 -0
  522. package/dist/stage/chunk-MNQIRPDQ.js +8 -0
  523. package/dist/stage/chunk-MRG7MJVS.js +1 -0
  524. package/dist/stage/chunk-MU6EXW72.js +10 -0
  525. package/dist/stage/chunk-MVU2X6LU.js +4 -0
  526. package/dist/stage/chunk-N6UA5CZV.js +36 -0
  527. package/dist/stage/chunk-NLZIT2TJ.js +7 -0
  528. package/dist/stage/chunk-NOJR3J7M.js +1 -0
  529. package/dist/stage/chunk-NT7ARDOL.js +1 -0
  530. package/dist/stage/chunk-NWOGMPZH.js +1 -0
  531. package/dist/stage/chunk-NXE4KMG3.js +40 -0
  532. package/dist/stage/chunk-O4YCZXD2.js +257 -0
  533. package/dist/stage/chunk-OAJZ7HLK.js +1 -0
  534. package/dist/stage/chunk-OCFCFASO.js +1 -0
  535. package/dist/stage/chunk-ODGPG5RY.js +7 -0
  536. package/dist/stage/chunk-ODUEA52Q.js +3 -0
  537. package/dist/stage/chunk-OGDJ3FCI.js +1 -0
  538. package/dist/stage/chunk-OLDJ55TT.js +1 -0
  539. package/dist/stage/chunk-OOCL4ATI.js +2 -0
  540. package/dist/stage/chunk-OQEFDUDV.js +1 -0
  541. package/dist/stage/chunk-OQWVEWG7.js +4 -0
  542. package/dist/stage/chunk-OUIX6BGK.js +1 -0
  543. package/dist/stage/chunk-OV7OZYUO.js +7 -0
  544. package/dist/stage/chunk-PFGDY33O.js +1 -0
  545. package/dist/stage/chunk-PFJDUJB3.js +139 -0
  546. package/dist/stage/chunk-PGEW76ER.js +1 -0
  547. package/dist/stage/chunk-PP76TAQX.js +32 -0
  548. package/dist/stage/chunk-PTBOP4OT.js +2 -0
  549. package/dist/stage/chunk-PX2RVHCK.js +1 -0
  550. package/dist/stage/chunk-Q7K3PNAD.js +1 -0
  551. package/dist/stage/chunk-QDDPLZDB.js +1 -0
  552. package/dist/stage/chunk-QLGLZ77F.js +1 -0
  553. package/dist/stage/chunk-QOPFDFHI.js +1 -0
  554. package/dist/stage/chunk-QXT4KAEJ.js +1 -0
  555. package/dist/stage/chunk-R4YVZCIT.js +1 -0
  556. package/dist/stage/chunk-R6P6EHWA.js +62 -0
  557. package/dist/stage/chunk-RCH3OXBI.js +9 -0
  558. package/dist/stage/chunk-RHPE44I2.js +1 -0
  559. package/dist/stage/chunk-RJ2R4FVC.js +1 -0
  560. package/dist/stage/chunk-RJH2YVTD.js +1 -0
  561. package/dist/stage/chunk-RLWWW5OB.js +6 -0
  562. package/dist/stage/chunk-S3WO35Z7.js +120 -0
  563. package/dist/stage/chunk-S7ZGX6MW.js +1 -0
  564. package/dist/stage/chunk-SIAWX27B.js +1 -0
  565. package/dist/stage/chunk-SLG4X622.js +1 -0
  566. package/dist/stage/chunk-SLJRBC77.js +168 -0
  567. package/dist/stage/chunk-SRORWQJZ.js +1 -0
  568. package/dist/stage/chunk-STZTUIIF.js +2 -0
  569. package/dist/stage/chunk-SVQ6MWNV.js +9 -0
  570. package/dist/stage/chunk-TL3HLL2S.js +132 -0
  571. package/dist/stage/chunk-U3DOE6SF.js +24 -0
  572. package/dist/stage/chunk-UABQIZKW.js +6 -0
  573. package/dist/stage/chunk-UDK3R764.js +1 -0
  574. package/dist/stage/chunk-UFF4E54B.js +41 -0
  575. package/dist/stage/chunk-UFP5Q4AY.js +1 -0
  576. package/dist/stage/chunk-UMH2TSW2.js +72 -0
  577. package/dist/stage/chunk-UTASVNF5.js +10 -0
  578. package/dist/stage/chunk-UW7ML5ML.js +88 -0
  579. package/dist/stage/chunk-V3J7F6OP.js +1 -0
  580. package/dist/stage/chunk-VEHP5B5Q.js +5 -0
  581. package/dist/stage/chunk-VRXWB733.js +9 -0
  582. package/dist/stage/chunk-VVDHBBS5.js +5 -0
  583. package/dist/stage/chunk-VYFOH6FU.js +106 -0
  584. package/dist/stage/chunk-W3VZTLQS.js +3 -0
  585. package/dist/stage/chunk-W7WNRWTZ.js +8 -0
  586. package/dist/stage/chunk-WHUCV53C.js +1 -0
  587. package/dist/stage/chunk-WULMYHIF.js +1 -0
  588. package/dist/stage/chunk-X54EX7AW.js +9 -0
  589. package/dist/stage/chunk-X565ISZM.js +1 -0
  590. package/dist/stage/chunk-XGZMDECB.js +1 -0
  591. package/dist/stage/chunk-XHONC4RF.js +172 -0
  592. package/dist/stage/chunk-XIK4XQ6E.js +24 -0
  593. package/dist/stage/chunk-XJQQWFTE.js +1 -0
  594. package/dist/stage/chunk-XM4WOU3I.js +13 -0
  595. package/dist/stage/chunk-XM7Y5HP5.js +38 -0
  596. package/dist/stage/chunk-XNYYRGD5.js +292 -0
  597. package/dist/stage/chunk-XOYVR3SV.js +1 -0
  598. package/dist/stage/chunk-XQIW5HCE.js +1 -0
  599. package/dist/stage/chunk-YEWL7FUW.js +8 -0
  600. package/dist/stage/chunk-YI55PY3V.js +1 -0
  601. package/dist/stage/chunk-YM63HI6W.js +1 -0
  602. package/dist/stage/chunk-YNLGLU4P.js +9 -0
  603. package/dist/stage/chunk-YTNMNOWP.js +1 -0
  604. package/dist/stage/chunk-YV62XKTC.js +1 -0
  605. package/dist/stage/chunk-YVBA3QW6.js +1 -0
  606. package/dist/stage/chunk-Z2SY2HOC.js +1 -0
  607. package/dist/stage/chunk-ZBTCQEBK.js +10 -0
  608. package/dist/stage/chunk-ZCUFN74D.js +1 -0
  609. package/dist/stage/chunk-ZHOULXEJ.js +11 -0
  610. package/dist/stage/chunk-ZTRZIET2.js +1 -0
  611. package/dist/stage/index.html +1 -0
  612. package/dist/stage/stage.css +1 -1
  613. package/dist/stage/stage.js +1 -4383
  614. package/dist/ui/dev/dev-page.d.ts +1 -0
  615. package/dist/ui/dev/dev-page.js +2248 -0
  616. package/dist/ui/dev/dev-theme.d.ts +6 -0
  617. package/dist/ui/dev/dev-theme.js +67 -0
  618. package/dist/ui/dev/qr-page.d.ts +8 -0
  619. package/dist/ui/dev/qr-page.js +61 -0
  620. package/dist/ui/dev/voice-gallery-page.d.ts +1 -0
  621. package/dist/ui/dev/voice-gallery-page.js +121 -0
  622. package/dist/ui/dev/voice-scenes.d.ts +21 -0
  623. package/dist/ui/dev/voice-scenes.js +30 -0
  624. package/dist/ui/dictation/en-box.d.ts +2 -0
  625. package/dist/ui/dictation/en-box.js +86 -0
  626. package/dist/ui/dictation/en-page.d.ts +1 -0
  627. package/dist/ui/dictation/en-page.js +484 -0
  628. package/dist/ui/dictation/page.d.ts +1 -0
  629. package/dist/ui/dictation/page.js +1084 -0
  630. package/dist/ui/dictation/parent-page.d.ts +1 -0
  631. package/dist/ui/dictation/parent-page.js +234 -0
  632. package/dist/ui/dictation/reel-mode.d.ts +1 -0
  633. package/dist/ui/dictation/reel-mode.js +87 -0
  634. package/dist/ui/dictation/reel-page.d.ts +1 -0
  635. package/dist/ui/dictation/reel-page.js +62 -0
  636. package/dist/ui/dictation/reel.d.ts +163 -0
  637. package/dist/ui/dictation/reel.js +436 -0
  638. package/dist/ui/dictation/ui.d.ts +44 -0
  639. package/dist/ui/dictation/ui.js +80 -0
  640. package/dist/ui/dictation/unlock.d.ts +7 -0
  641. package/dist/ui/dictation/unlock.js +16 -0
  642. package/dist/ui/kid/audio-client.d.ts +11 -0
  643. package/dist/ui/kid/audio-client.js +74 -0
  644. package/dist/ui/kid/board-mark-art.d.ts +37 -0
  645. package/dist/ui/kid/board-mark-art.js +5 -0
  646. package/dist/ui/kid/board-mark.d.ts +24 -0
  647. package/dist/ui/kid/board-mark.js +58 -0
  648. package/dist/ui/kid/kid-log.d.ts +15 -0
  649. package/dist/ui/kid/kid-log.js +87 -0
  650. package/dist/ui/kid/kid-nav.d.ts +11 -0
  651. package/dist/ui/kid/kid-nav.js +22 -0
  652. package/dist/ui/kid/kid-page.d.ts +9 -0
  653. package/dist/ui/kid/kid-page.js +3719 -0
  654. package/dist/ui/kid/letters.d.ts +26 -0
  655. package/dist/ui/kid/letters.js +51 -0
  656. package/dist/ui/kid/photo-edit.d.ts +83 -0
  657. package/dist/ui/kid/photo-edit.js +106 -0
  658. package/dist/ui/kid/photo-ui.d.ts +23 -0
  659. package/dist/ui/kid/photo-ui.js +60 -0
  660. package/dist/ui/kid/reel.d.ts +419 -0
  661. package/dist/ui/kid/reel.js +648 -0
  662. package/dist/ui/kid/tianzige.d.ts +8 -0
  663. package/dist/ui/kid/tianzige.js +45 -0
  664. package/dist/ui/kid/tutor-face.d.ts +35 -0
  665. package/dist/ui/kid/tutor-face.js +84 -0
  666. package/dist/ui/kid/voice-ui.d.ts +70 -0
  667. package/dist/ui/kid/voice-ui.js +316 -0
  668. package/dist/ui/kid/voice-view.d.ts +71 -0
  669. package/dist/ui/kid/voice-view.js +75 -0
  670. package/dist/ui/kid/word-draw.d.ts +2 -0
  671. package/dist/ui/kid/word-draw.js +107 -0
  672. package/dist/ui/kid/word-emoji.d.ts +10 -0
  673. package/dist/ui/kid/word-emoji.js +66 -0
  674. package/dist/ui/kid/word-layout.d.ts +25 -0
  675. package/dist/ui/kid/word-layout.js +29 -0
  676. package/dist/ui/parent/parent-home-page.d.ts +1 -0
  677. package/dist/ui/parent/parent-home-page.js +414 -0
  678. package/dist/ui/parent/parent-page.d.ts +2 -0
  679. package/dist/ui/parent/parent-page.js +507 -0
  680. package/dist/ui/shared/brand.d.ts +36 -0
  681. package/dist/ui/shared/brand.js +51 -0
  682. package/dist/ui/shared/favicon.d.ts +12 -0
  683. package/dist/ui/shared/favicon.js +96 -0
  684. package/dist/ui/shared/icon.d.ts +9 -0
  685. package/dist/ui/shared/icon.js +35 -0
  686. package/dist/ui/shared/inline-lib.d.ts +1 -0
  687. package/dist/ui/shared/inline-lib.js +28 -0
  688. package/dist/ui/shared/logo.d.ts +31 -0
  689. package/dist/ui/shared/logo.js +43 -0
  690. package/dist/ui/shared/page-dom.d.ts +12 -0
  691. package/dist/ui/shared/page-dom.js +36 -0
  692. package/dist/ui/shared/png.d.ts +1 -0
  693. package/dist/ui/shared/png.js +45 -0
  694. package/dist/ui/shared/qr-svg.d.ts +3 -0
  695. package/dist/ui/shared/qr-svg.js +32 -0
  696. package/dist/ui/shared/qr.d.ts +14 -0
  697. package/dist/ui/shared/qr.js +281 -0
  698. package/dist/ui/shared/reel-dock.d.ts +22 -0
  699. package/dist/ui/shared/reel-dock.js +365 -0
  700. package/dist/ui/shared/tutor-color.d.ts +15 -0
  701. package/dist/ui/shared/tutor-color.js +47 -0
  702. package/dist/ui/talk/page.d.ts +6 -0
  703. package/dist/ui/talk/page.js +294 -0
  704. package/grades/grade-2/README.md +11 -0
  705. package/grades/grade-2/VALIDATION.md +41 -0
  706. package/grades/grade-2/agents/chinese-tutor/activities//344/275/240/350/257/264/346/210/221/347/224/273.md +157 -0
  707. package/grades/grade-2/agents/chinese-tutor/activities//344/275/240/350/257/264/346/210/221/347/224/273./344/276/213/345/255/220.md +78 -0
  708. package/grades/grade-2/agents/chinese-tutor/activities//344/276/213/345/255/220/345/233/276//345/200/237/344/274/236.jpg +0 -0
  709. package/grades/grade-2/agents/chinese-tutor/activities//344/276/213/345/255/220/345/233/276//345/260/217/347/214/264/346/221/230/346/241/203.jpg +0 -0
  710. package/grades/grade-2/agents/chinese-tutor/activities//345/206/231/350/257/235.md +64 -0
  711. package/grades/grade-2/agents/chinese-tutor/activities//345/206/231/350/257/235./344/276/213/345/255/220.md +31 -0
  712. package/grades/grade-2/agents/chinese-tutor/activities//345/220/254/345/206/231.md +48 -0
  713. package/grades/grade-2/agents/chinese-tutor/activities//345/244/215/344/271/240.md +79 -0
  714. package/grades/grade-2/agents/chinese-tutor/activities//345/244/215/344/271/240./344/276/213/345/255/220.md +35 -0
  715. package/grades/grade-2/agents/chinese-tutor/activities//345/260/217/350/257/276/345/240/202.md +53 -0
  716. package/grades/grade-2/agents/chinese-tutor/activities//346/211/271/346/224/271.md +81 -0
  717. package/grades/grade-2/agents/chinese-tutor/activities//346/211/271/346/224/271./344/276/213/345/255/220.md +35 -0
  718. package/grades/grade-2/agents/chinese-tutor/activities//347/234/213/345/233/276/350/257/264/350/257/235.md +94 -0
  719. package/grades/grade-2/agents/chinese-tutor/activities//347/234/213/345/233/276/350/257/264/350/257/235./344/276/213/345/255/220.md +63 -0
  720. package/grades/grade-2/agents/chinese-tutor/activities//351/242/204/344/271/240.md +82 -0
  721. package/grades/grade-2/agents/chinese-tutor/activities//351/242/204/344/271/240./344/276/213/345/255/220.md +35 -0
  722. package/grades/grade-2/agents/chinese-tutor.md +59 -0
  723. package/grades/grade-2/agents/english-tutor/activities//345/217/243/350/257/255/350/257/276.md +149 -0
  724. package/grades/grade-2/agents/english-tutor/activities//345/217/243/350/257/255/350/257/276./344/276/213/345/255/220.md +13 -0
  725. package/grades/grade-2/agents/english-tutor/activities//345/220/254/345/206/231.md +47 -0
  726. package/grades/grade-2/agents/english-tutor/activities//345/244/215/344/271/240.md +78 -0
  727. package/grades/grade-2/agents/english-tutor/activities//345/244/215/344/271/240./344/276/213/345/255/220.md +35 -0
  728. package/grades/grade-2/agents/english-tutor/activities//345/260/217/350/257/276/345/240/202.md +53 -0
  729. package/grades/grade-2/agents/english-tutor/activities//346/211/271/346/224/271.md +80 -0
  730. package/grades/grade-2/agents/english-tutor/activities//346/211/271/346/224/271./344/276/213/345/255/220.md +35 -0
  731. package/grades/grade-2/agents/english-tutor/activities//351/242/204/344/271/240.md +86 -0
  732. package/grades/grade-2/agents/english-tutor/activities//351/242/204/344/271/240./344/276/213/345/255/220.md +35 -0
  733. package/grades/grade-2/agents/english-tutor.md +57 -0
  734. package/grades/grade-2/agents/math-tutor/activities//345/244/215/344/271/240.md +78 -0
  735. package/grades/grade-2/agents/math-tutor/activities//345/244/215/344/271/240./344/276/213/345/255/220.md +35 -0
  736. package/grades/grade-2/agents/math-tutor/activities//345/260/217/350/257/276/345/240/202.md +56 -0
  737. package/grades/grade-2/agents/math-tutor/activities//345/260/217/350/257/276/345/240/202./344/276/213/345/255/220.md +52 -0
  738. package/grades/grade-2/agents/math-tutor/activities//346/211/271/346/224/271.md +80 -0
  739. package/grades/grade-2/agents/math-tutor/activities//346/211/271/346/224/271./344/276/213/345/255/220.md +35 -0
  740. package/grades/grade-2/agents/math-tutor/activities//351/242/204/344/271/240.md +81 -0
  741. package/grades/grade-2/agents/math-tutor/activities//351/242/204/344/271/240./344/276/213/345/255/220.md +35 -0
  742. package/grades/grade-2/agents/math-tutor.md +51 -0
  743. package/grades/grade-2/examples/2026-10-27-pingjunfen/audio/index.json +44 -0
  744. package/grades/grade-2/examples/2026-10-27-pingjunfen/audio/step-1.mp3 +0 -0
  745. package/grades/grade-2/examples/2026-10-27-pingjunfen/audio/step-2.mp3 +0 -0
  746. package/grades/grade-2/examples/2026-10-27-pingjunfen/audio/step-3.mp3 +0 -0
  747. package/grades/grade-2/examples/2026-10-27-pingjunfen/audio/step-4.mp3 +0 -0
  748. package/grades/grade-2/examples/2026-10-27-pingjunfen/audio/step-5.mp3 +0 -0
  749. package/grades/grade-2/examples/2026-10-27-pingjunfen/bake.json +1 -0
  750. package/grades/grade-2/examples/2026-10-27-pingjunfen/manifest.json +63 -0
  751. package/grades/grade-2/examples/2026-10-27-pingjunfen/scene.json +247 -0
  752. package/grades/grade-2/examples/2026-10-27-pingjunfen.md +40 -0
  753. package/grades/grade-2/examples/2026-10-27-pingjunfen.ts +26 -0
  754. package/grades/grade-2/examples//345/271/263/345/235/207/345/210/206./344/276/213/345/255/220.md +24 -0
  755. package/grades/grade-2/examples//346/225/260/345/255/246/345/271/263/345/235/207/345/210/206.md +42 -0
  756. package/grades/grade-2/validation/2026-10-27.json +4410 -0
  757. package/package.json +26 -15
  758. package/skills/chalk-cli/SKILL.md +62 -0
  759. package/skills/chalk-scene/SKILL.md +91 -0
  760. package/skills/chalk-teaching/SKILL.md +82 -0
  761. package/skills/chalk-teaching/models//344/272/244/351/224/231/346/225/260/345/210/227/345/210/206/350/241/214.md +8 -0
  762. package/skills/chalk-teaching/models//345/207/221/345/215/201.md +7 -0
  763. package/skills/chalk-teaching/models//345/221/250/346/234/237/350/247/204/345/276/213.md +6 -0
  764. package/skills/chalk-teaching/models//345/256/236/347/211/251/345/233/276-/345/242/236/345/207/217.md +6 -0
  765. package/skills/chalk-teaching/models//345/256/236/347/211/251/345/233/276-/346/257/224/345/244/232/345/260/221-/346/261/202/345/244/247/346/225/260/346/261/202/345/260/217/346/225/260.md +7 -0
  766. package/skills/chalk-teaching/models//345/256/236/347/211/251/345/233/276-/346/257/224/345/244/232/345/260/221-/346/261/202/345/267/256.md +6 -0
  767. package/skills/chalk-teaching/models//345/260/217/346/243/222/350/277/233/344/275/215/345/212/240.md +7 -0
  768. package/skills/chalk-teaching/models//345/260/217/346/243/222/351/200/200/344/275/215/345/207/217.md +6 -0
  769. package/skills/chalk-teaching/models//346/216/222/351/230/237/347/202/271/351/230/265.md +7 -0
  770. package/skills/chalk-teaching/models//346/227/266/351/227/264/346/225/260/350/275/264.md +6 -0
  771. package/skills/chalk-teaching/models//346/245/274/345/261/202/351/227/264/351/232/224/345/233/276.md +7 -0
  772. package/skills/chalk-teaching/models//347/240/264/345/215/201.md +7 -0
  773. package/skills/chalk-teaching/models//347/253/226/345/274/217/351/200/200/344/275/215.md +6 -0
  774. package/skills/chalk-teaching/models//347/272/277/346/256/265/345/233/276.md +7 -0
  775. package/skills/chalk-teaching/models-index.md +24 -0
  776. package/skills/chalk-teaching/references//350/256/262/350/247/243/346/250/241/346/235/277/344/270/211/346/241/243.md +32 -0
  777. package/skills/chalk-teaching/references//350/257/264/346/230/216/346/226/207/344/273/266.md +102 -0
  778. package/skills/chalk-verify/SKILL.md +57 -0
  779. package/skills/chalk-verify/references//350/257/204/345/210/244/346/240/207/345/207/206.md +69 -0
  780. package/skills/cotutor-analyze/SKILL.md +106 -0
  781. package/skills/cotutor-analyze/references//345/221/275/344/273/244/344/270/216/346/226/207/344/273/266.md +31 -0
  782. package/skills/cotutor-board/SKILL.md +373 -0
  783. package/skills/cotutor-board/references/README.md +38 -0
  784. package/skills/cotutor-board/references/canvas.md +68 -0
  785. package/skills/cotutor-board/references/choice.md +55 -0
  786. package/skills/cotutor-board/references/code.md +46 -0
  787. package/skills/cotutor-board/references/image.md +52 -0
  788. package/skills/cotutor-board/references/lecture.md +69 -0
  789. package/skills/cotutor-board/references/paint.md +77 -0
  790. package/skills/cotutor-board/references/photo.md +61 -0
  791. package/skills/cotutor-board/references/read.md +51 -0
  792. package/skills/cotutor-board/references/text.md +69 -0
  793. package/skills/cotutor-board/references/tianzige.md +78 -0
  794. package/skills/cotutor-board/references/word.md +91 -0
  795. package/skills/cotutor-home/SKILL.md +169 -0
  796. package/skills/cotutor-home/references/dictation.md +97 -0
  797. package/skills/cotutor-home/references/tutor.md +148 -0
  798. package/skills/cotutor-home/references//345/221/275/344/273/244.md +21 -0
  799. package/skills/cotutor-home/references//351/246/226/351/241/265/350/257/255/346/263/225.md +142 -0
  800. package/skills/cotutor-tune/SKILL.md +147 -0
  801. package/skills/cotutor-tune/references//345/255/227/346/256/265.md +50 -0
  802. package/skills/cotutor-tutor/SKILL.md +261 -0
  803. package/skills/cotutor-tutor/references//344/270/212/344/270/213/346/226/207/345/214/205.md +78 -0
  804. package/themes/default/kid.css +86 -0
  805. package/themes/default/theme.json +26 -0
  806. package/agents/chinese-tutor.md +0 -67
  807. package/agents/homework-tutor.md +0 -17
  808. package/agents/math-tutor.md +0 -68
  809. package/agents/planner.md +0 -18
  810. package/agents/reading-tutor.md +0 -65
  811. package/agents/scene-maker.md +0 -41
  812. package/dist/cards/canvas.d.ts +0 -22
  813. package/dist/cards/canvas.js +0 -65
  814. package/dist/cards/fill.d.ts +0 -14
  815. package/dist/cards/fill.js +0 -64
  816. package/dist/cards/index.d.ts +0 -48
  817. package/dist/cards/index.js +0 -115
  818. package/dist/cards/kind.js +0 -7
  819. package/dist/cards/scene.d.ts +0 -24
  820. package/dist/cards/scene.js +0 -67
  821. package/dist/cards/text.d.ts +0 -18
  822. package/dist/cards/text.js +0 -41
  823. package/dist/cli/doctor.js +0 -355
  824. package/dist/cli/init.js +0 -116
  825. package/dist/cli/main.js +0 -243
  826. package/dist/cli/serve.js +0 -56
  827. package/dist/cli/skeleton.d.ts +0 -39
  828. package/dist/cli/skeleton.js +0 -184
  829. package/dist/cli/skills.d.ts +0 -40
  830. package/dist/cli/skills.js +0 -170
  831. package/dist/cli/workspace.d.ts +0 -69
  832. package/dist/lib/agent-file.d.ts +0 -10
  833. package/dist/lib/agent-file.js +0 -16
  834. package/dist/lib/board.d.ts +0 -15
  835. package/dist/lib/board.js +0 -107
  836. package/dist/lib/context-pack.js +0 -55
  837. package/dist/lib/conversation.js +0 -88
  838. package/dist/lib/kid-board.d.ts +0 -148
  839. package/dist/lib/kid-board.js +0 -294
  840. package/dist/lib/kid-view.d.ts +0 -63
  841. package/dist/lib/kid-view.js +0 -93
  842. package/dist/lib/ledger.d.ts +0 -29
  843. package/dist/lib/run-plan.d.ts +0 -30
  844. package/dist/lib/run-plan.js +0 -32
  845. package/dist/lib/sections.d.ts +0 -12
  846. package/dist/lib/sections.js +0 -151
  847. package/dist/lib/stream.d.ts +0 -15
  848. package/dist/lib/stream.js +0 -69
  849. package/dist/lib/transcript.d.ts +0 -36
  850. package/dist/lib/transcript.js +0 -95
  851. package/dist/server/app.d.ts +0 -74
  852. package/dist/server/app.js +0 -406
  853. package/dist/server/kid-page.d.ts +0 -1
  854. package/dist/server/kid-page.js +0 -768
  855. package/dist/server/mock.js +0 -403
  856. package/dist/server/parent-page.d.ts +0 -8
  857. package/dist/server/parent-page.js +0 -393
  858. package/dist/server/runner.d.ts +0 -64
  859. package/dist/server/runner.js +0 -277
  860. package/dist/server/scene-props.d.ts +0 -16
  861. package/dist/server/scene-props.js +0 -39
  862. package/dist/server/store.d.ts +0 -43
  863. package/dist/server/store.js +0 -210
  864. package/dist/server/tts.d.ts +0 -51
  865. package/dist/server/tts.js +0 -99
  866. /package/dist/{cli → app/cli}/cert.d.ts +0 -0
  867. /package/dist/{cli → app/cli}/main.d.ts +0 -0
  868. /package/dist/{cards → board/cards}/choice.d.ts +0 -0
  869. /package/dist/{cards → board/cards}/code.d.ts +0 -0
  870. /package/dist/{cards → board/cards}/image.d.ts +0 -0
  871. /package/dist/{cards → board/cards}/read.d.ts +0 -0
@@ -0,0 +1,142 @@
1
+ /**
2
+ * /talk 与 /api/talk/*:口语课的页面与接口。孩子在这里拍一页、改好口语单,交给英语老师的实时页上课
3
+ * (src/runtime/talk-run.ts,activity「口语课」);这一页自己不打电话。
4
+ * cotutor 只在 app.ts 的 route() 里接一行;这里引用 cotutor 的东西,cotutor 别处不引用这里。拆掉 = 删 src/{app,ui,scenes}/talk/ 和那一行(实时页里口语课热身那几处另算)。
5
+ *
6
+ * GET /talk 孩子端的页面:拍照、看口语单(按 hash 切;家长端没有这一页)
7
+ * GET /api/talk 开关、全部口语单(新的在前)
8
+ * POST /api/talk {photo?: dataURL} 开一次;有照片就交给 omni 读口语单(孩子拍的,读完才回)
9
+ * {from: 'latest'} 拍照屏的「接着上」:最近那份改好了的口语单(404 = 还没有)
10
+ * GET /api/talk/<id> 一次的全部({meta})
11
+ * PUT /api/talk/<id>/list {words, sentences, ready?} 改过的口语单;ready = 交给老师
12
+ * DELETE /api/talk/<id>
13
+ * GET /api/talk/<id>/photo 那页照片
14
+ */
15
+ import { join } from 'node:path';
16
+ import { readList, wordCardOf } from "./list.js";
17
+ import { talkPage } from "../../ui/talk/page.js";
18
+ import { backTutorOf } from "../../ui/kid/tutor-face.js";
19
+ import { ID_RE, createTalk, deleteTalk, dirOf, listTalks, readMeta, writeMeta } from "../../scenes/talk/store.js";
20
+ const isObj = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
21
+ const bad = (message) => ({ status: 400, json: { error: 'bad_request', message } });
22
+ const PHOTO_MIME = { jpeg: 'image/jpeg', jpg: 'image/jpeg', png: 'image/png', webp: 'image/webp' };
23
+ const PHOTO_B64_MAX = 5_600_000;
24
+ /** data:image/…;base64,… → 字节;不是图、太大 → undefined */
25
+ export function photoData(v) {
26
+ if (typeof v !== 'string')
27
+ return undefined;
28
+ const m = /^data:image\/([a-z]+)(?:;[^,]*)?;base64,([A-Za-z0-9+/=]+)$/.exec(v);
29
+ const mime = m ? PHOTO_MIME[m[1]] : undefined;
30
+ if (!m || !mime || m[2].length > PHOTO_B64_MAX)
31
+ return undefined;
32
+ return { data: Buffer.from(m[2], 'base64'), mime };
33
+ }
34
+ /** 改过的口语单:两组各最多 12 / 8 条,去空去重;词带回来的 emoji 与分段再过一遍单词卡的 parse(改了词,旧分段拼不回就丢) */
35
+ export function parseItems(v, max, card = false) {
36
+ if (!Array.isArray(v) || v.length > 50)
37
+ return null;
38
+ const out = [];
39
+ for (const x of v) {
40
+ if (!isObj(x) || typeof x.en !== 'string')
41
+ return null;
42
+ const en = x.en.replace(/\s+/g, ' ').trim();
43
+ const zh = typeof x.zh === 'string' ? x.zh.replace(/\s+/g, ' ').trim() : '';
44
+ if (!en || en.length > 120 || zh.length > 120)
45
+ continue;
46
+ if (out.some((o) => o.en.toLowerCase() === en.toLowerCase()))
47
+ continue;
48
+ const ch = x.chunks;
49
+ out.push(card ? { en, zh, ...wordCardOf(en, x.emoji, Array.isArray(ch) ? ch.join('-') : undefined) } : { en, zh });
50
+ if (out.length >= max)
51
+ break;
52
+ }
53
+ return out;
54
+ }
55
+ export function makeTalkRoute(deps = { readList }) {
56
+ return async function talkRoute(method, url, ctx, body) {
57
+ const p = url.pathname;
58
+ if (p === '/talk' || p === '/talk/')
59
+ return method === 'GET' ? { status: 200, html: talkPage(backTutorOf(ctx.ws.config.tutors, url.searchParams.get('tutor'))) } : { status: 405, json: { error: 'method_not_allowed' } };
60
+ if (p !== '/api/talk' && !p.startsWith('/api/talk/'))
61
+ return null;
62
+ const ws = ctx.ws;
63
+ const cfg = ws.config.talk;
64
+ const root = ws.root;
65
+ const env = deps.env ?? process.env;
66
+ if (p === '/api/talk') {
67
+ if (method === 'GET')
68
+ return { status: 200, json: { enabled: cfg.enabled, talks: await listTalks(root) } };
69
+ if (method !== 'POST')
70
+ return { status: 405, json: { error: 'method_not_allowed' } };
71
+ if (!cfg.enabled)
72
+ return { status: 404, json: { error: 'talk_disabled', message: 'cotutor.json 的 talk.enabled 还是 false' } };
73
+ const b = isObj(body) ? body : {};
74
+ if (b.from !== undefined) {
75
+ if (b.from !== 'latest')
76
+ return bad("from 只认 'latest'");
77
+ const last = (await listTalks(root)).find((t) => t.status === 'ready' && t.list.words.length + t.list.sentences.length > 0);
78
+ if (!last)
79
+ return { status: 404, json: { error: 'no_list', message: '还没有给孩子的口语单' } };
80
+ return { status: 200, json: last };
81
+ }
82
+ const photo = b.photo === undefined ? null : photoData(b.photo);
83
+ if (photo === undefined)
84
+ return bad('photo 要是 data:image/…;base64,…,不超过 4MB');
85
+ const meta = await createTalk(root, ctx.now(), photo?.data ?? null);
86
+ if (photo) {
87
+ const r = await deps.readList(photo, { env, model: cfg.listModel });
88
+ if (r.ok) {
89
+ meta.list = r.list;
90
+ meta.listBy = 'omni';
91
+ meta.listMs = r.ms;
92
+ }
93
+ else {
94
+ meta.listError = r.error;
95
+ meta.listMs = r.ms;
96
+ }
97
+ await writeMeta(root, meta);
98
+ }
99
+ return { status: 201, json: meta };
100
+ }
101
+ const m = /^\/api\/talk\/([^/]+)(?:\/(.*))?$/.exec(p);
102
+ if (!m)
103
+ return null;
104
+ const id = m[1];
105
+ const rest = m[2] ?? '';
106
+ if (!ID_RE.test(id))
107
+ return { status: 404, json: { error: 'not_found' } };
108
+ const meta = await readMeta(root, id);
109
+ if (!meta)
110
+ return { status: 404, json: { error: 'not_found' } };
111
+ const dir = dirOf(root, id);
112
+ if (rest === '' && method === 'GET')
113
+ return { status: 200, json: { meta } };
114
+ if (rest === '' && method === 'DELETE') {
115
+ await deleteTalk(root, id);
116
+ return { status: 200, json: { ok: true } };
117
+ }
118
+ if (rest === 'list' && method === 'PUT') {
119
+ const b = isObj(body) ? body : {};
120
+ const words = parseItems(b.words ?? [], 12, true);
121
+ const sentences = parseItems(b.sentences ?? [], 8);
122
+ if (!words || !sentences)
123
+ return bad('words / sentences 要是 [{en, zh}]');
124
+ const changed = JSON.stringify({ words, sentences }) !== JSON.stringify(meta.list);
125
+ meta.list = { words, sentences };
126
+ if (changed)
127
+ meta.listBy = 'parent';
128
+ meta.status = b.ready === true && words.length + sentences.length ? 'ready' : 'draft';
129
+ await writeMeta(root, meta);
130
+ return { status: 200, json: meta };
131
+ }
132
+ if (rest === 'photo' && method === 'GET')
133
+ return meta.photo ? { status: 200, file: join(dir, meta.photo), contentType: 'image/jpeg', cacheControl: 'private, max-age=3600' } : { status: 404, json: { error: 'no_photo' } };
134
+ return { status: 404, json: { error: 'not_found' } };
135
+ };
136
+ }
137
+ /** 探针用的假读口语单(COTUTOR_TALK_FAKE_LIST=1):不看照片,0.8 秒后回一个词一句 */
138
+ const fakeReadList = async () => {
139
+ await new Promise((r) => setTimeout(r, 800));
140
+ return { ok: true, list: { words: [{ en: 'red', zh: '红色', emoji: '🔴' }], sentences: [{ en: 'It is a red car.', zh: '这是一辆红色的车。' }] }, model: 'fake', ms: 800 };
141
+ };
142
+ export const talkRoute = makeTalkRoute({ readList: process.env.COTUTOR_TALK_FAKE_LIST ? fakeReadList : readList });
@@ -0,0 +1,58 @@
1
+ import { ConfigError, UsageError } from '../shared/errors.ts';
2
+ import { redactDeep, redactHome } from '../shared/home.ts';
3
+ import { type RootSource, type Workspace } from '../schema/workspace.ts';
4
+ import { type CotutorConfig } from '../schema/index.ts';
5
+ export { ConfigError, UsageError, redactDeep, redactHome };
6
+ export type { RootSource, Workspace };
7
+ export declare const CONFIG_FILE = "cotutor.json";
8
+ export declare const USER_CONFIG: string;
9
+ /** 机器级自签证书目录(cotutor cert 写 cert.pem + key.pem):证书签的是本机名与局域网 IP,与孩子无关,所以不在 workspace 里 */
10
+ export declare const USER_CERT_DIR: string;
11
+ export declare const HOME_ROOT: string;
12
+ export interface ResolvedRoot {
13
+ root: string;
14
+ source: RootSource;
15
+ }
16
+ export declare function expandPath(p: string, base: string): string;
17
+ /** 读 JSON:不存在 → null;坏 → ConfigError */
18
+ export declare function readJson(file: string): unknown | null;
19
+ /** 从 dir 向上找 cotutor.json,找到返回目录 */
20
+ export declare function findUp(dir: string): string | null;
21
+ /** ~/cotutor/ 下带 cotutor.json 的子目录 */
22
+ export declare function homeWorkspaces(homeRoot?: string): string[];
23
+ export interface ResolveOptions {
24
+ env?: NodeJS.ProcessEnv;
25
+ cwd?: string;
26
+ homeRoot?: string;
27
+ }
28
+ export declare function resolveRoot(override?: string, opts?: ResolveOptions): ResolvedRoot;
29
+ /** 校验 cotutor.json 的形状;失败 → ConfigError,信息是逐条修复指南 */
30
+ export declare function parseConfig(raw: unknown, file: string): CotutorConfig;
31
+ export declare function resolvePaths(root: string, paths: Record<string, string>): Workspace['paths'];
32
+ export declare function assembleWorkspace(root: string, source: RootSource, config: CotutorConfig): Workspace;
33
+ /** 定根 + 读配置 + 校验 + 展开角色。cotutor.json 缺失也是错(它是必需的)。 */
34
+ export declare function loadWorkspace(override?: string, opts?: ResolveOptions): Workspace;
35
+ /** --json / 启动日志里回报workspace(脱敏) */
36
+ export declare function workspaceReport(ws: Workspace): Record<string, unknown>;
37
+ /** PATCH 允许改的顶层键(老师团页与设置页);kid / version / 运行时模板走编辑器 */
38
+ export declare const CONFIG_PATCH_KEYS: readonly ["title", "policyDefaults", "tutors", "agents", "paths", "server", "vault", "live"];
39
+ /**
40
+ * 深合并:对象递归、其余覆盖、null 删键(老师条目可整体删:tutors.x = null)。
41
+ * 底下没有这个对象时也要**先剥掉 null 再放**——页面上留空的字段发的就是 null,
42
+ * 直接把补丁原样放进去会写出 `policy: {replyMaxChars: null, …}`,整份过不了契约、一保存就报错
43
+ * (2026-09-11:老师条目本来没有 policy 键时必然撞上,出厂六位都是这样)。
44
+ */
45
+ export declare function deepMerge(base: unknown, patch: unknown): unknown;
46
+ /**
47
+ * 补丁合到原始 JSON 上(保留 _note 等机器不认识的键),整份过契约再写;写坏了不落盘。
48
+ * 返回新配置;agents 只允许改 default(运行时模板走编辑器,页面上改错一个引号就把老师全弄哑)。
49
+ */
50
+ /** also:除了工作台能改的,这次还放行哪几个顶层键(家长端设置自己拼好补丁,只放 talk 的几项) */
51
+ export declare function patchConfig(ws: Workspace, patch: Record<string, unknown>, opts?: {
52
+ also?: readonly string[];
53
+ }): Promise<CotutorConfig>;
54
+ /** 文件改了(页面写的、或家长在编辑器改的)就重读;坏了抛 ConfigError,调用方决定是留旧的还是响 */
55
+ export declare function reloadIfChanged(ws: Workspace, lastMtime: number): Promise<{
56
+ ws: Workspace;
57
+ mtime: number;
58
+ }>;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * workspace解析:一孩一 workspace(`~/cotutor/<slug>/`,2026-09-08 拍板)。
2
+ * workspace解析:一孩一 workspace(`~/cotutor/<slug>/`)。
3
3
  * 解析链(定根):`--workspace <dir>` → 环境变量 COTUTOR_WORKSPACE → cwd 或其祖先有 cotutor.json
4
4
  * (老师的 cwd 是 <ws>/agents/<name>/,从那里跑 doctor 也要找得到根)→ 用户配置
5
5
  * ~/.config/cotutor/config.json 的 workspace → ~/cotutor/ 下**唯一**的一个孩子目录 → 都没有就报错附修复指南。
@@ -7,23 +7,18 @@
7
7
  * 配置"在但解析不了"响亮报错,不静默走缺省(沿 drawtell 的教训)。
8
8
  */
9
9
  import { readFileSync, readdirSync, statSync } from 'node:fs';
10
+ import { writeFile, rename, stat } from 'node:fs/promises';
11
+ import { ConfigError, UsageError } from "../shared/errors.js";
12
+ import { redactDeep, redactHome } from "../shared/home.js";
13
+ import { SKILLS_DIR } from "../schema/workspace.js";
10
14
  import { homedir } from 'node:os';
11
15
  import { dirname, isAbsolute, join, resolve } from 'node:path';
12
- import { CotutorConfigSchema, PATH_ROLES, ROLE_DEFAULTS, explainIssues, } from "../schema/index.js";
13
- /** 用法错误:main 捕获后 exit 2,错误信息即修复指南。 */
14
- export class UsageError extends Error {
15
- }
16
- /** 配置文件损坏或形状不对:文件在,但用不了。 */
17
- export class ConfigError extends UsageError {
18
- file;
19
- constructor(file, cause) {
20
- super(`配置文件用不了:${redactHome(file)}\n${cause}\n修好它;文件在 git 里就 git diff 看改动、git checkout 回退。cotutor doctor 可逐项体检。`);
21
- this.file = file;
22
- }
23
- }
16
+ import { CotutorConfigSchema, PATH_ROLES, ROLE_DEFAULTS, WORKSPACE_ROLES, explainIssues, } from "../schema/index.js";
17
+ // 挪走了的几样照旧从这里转出(旧的引法不用改)
18
+ export { ConfigError, UsageError, redactDeep, redactHome };
24
19
  export const CONFIG_FILE = 'cotutor.json';
25
20
  export const USER_CONFIG = join(homedir(), '.config', 'cotutor', 'config.json');
26
- /** 机器级自签证书目录(cotutor cert 写 cert.pem + key.pem):证书签的是本机名与局域网 IP,与孩子无关,所以不在 workspace 里(2026-09-09 拍板) */
21
+ /** 机器级自签证书目录(cotutor cert 写 cert.pem + key.pem):证书签的是本机名与局域网 IP,与孩子无关,所以不在 workspace 里 */
27
22
  export const USER_CERT_DIR = join(homedir(), '.config', 'cotutor', 'certs');
28
23
  export const HOME_ROOT = join(homedir(), 'cotutor');
29
24
  export function expandPath(p, base) {
@@ -33,20 +28,6 @@ export function expandPath(p, base) {
33
28
  return join(homedir(), p.slice(2));
34
29
  return isAbsolute(p) ? p : resolve(base, p);
35
30
  }
36
- export function redactHome(value) {
37
- const home = homedir();
38
- return home && value.startsWith(home) ? '$HOME' + value.slice(home.length) : value;
39
- }
40
- export function redactDeep(value) {
41
- if (typeof value === 'string')
42
- return redactHome(value);
43
- if (Array.isArray(value))
44
- return value.map(redactDeep);
45
- if (value && typeof value === 'object') {
46
- return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, redactDeep(v)]));
47
- }
48
- return value;
49
- }
50
31
  const isDir = (p) => {
51
32
  try {
52
33
  return statSync(p).isDirectory();
@@ -137,22 +118,6 @@ export function resolveRoot(override, opts = {}) {
137
118
  }
138
119
  /** 校验 cotutor.json 的形状;失败 → ConfigError,信息是逐条修复指南 */
139
120
  export function parseConfig(raw, file) {
140
- // 2026-09-09 术语统一(teacher → tutor,homework-aide → homework-tutor):旧键旧名响亮报,不静默变成零位老师
141
- if (raw && typeof raw === 'object') {
142
- const o = raw;
143
- if ('teachers' in o && !('tutors' in o)) {
144
- throw new ConfigError(file, ' - teachers:这个键 2026-09-09 起叫 tutors(术语统一为 tutor / 老师);把 "teachers" 改成 "tutors",老师名 *-teacher 改成 *-tutor、homework-aide 改成 homework-tutor,.claude/agents/ 下的文件同名改,然后 cotutor init 补齐');
145
- }
146
- if ('agents' in o && !('runtimes' in o)) {
147
- throw new ConfigError(file, ' - agents:这个键 2026-09-09 起叫 runtimes(它是跑老师的运行时,与 .claude/agents/ 的 agent 文件、agents/<老师>/ 的老师目录是三回事);把 "agents" 改成 "runtimes" 即可,模板内容与占位 {agent} {agentBody} 不变');
148
- }
149
- const tutors = o.tutors;
150
- if (tutors && typeof tutors === 'object') {
151
- const old = Object.keys(tutors).filter((k) => k.endsWith('-teacher') || k === 'homework-aide');
152
- if (old.length)
153
- throw new ConfigError(file, ` - tutors:${old.join('、')} 是旧名;2026-09-09 起叫 ${old.map((k) => (k === 'homework-aide' ? 'homework-tutor' : k.replace(/-teacher$/, '-tutor'))).join('、')}(文件名与 frontmatter name 一起改),然后 cotutor init 补齐`);
154
- }
155
- }
156
121
  const r = CotutorConfigSchema.safeParse(raw);
157
122
  if (r.success)
158
123
  return r.data;
@@ -164,7 +129,7 @@ export function resolvePaths(root, paths) {
164
129
  for (const role of PATH_ROLES) {
165
130
  if (role === 'vault')
166
131
  continue;
167
- out[role] = expandPath(paths[role] ?? ROLE_DEFAULTS[role], vault);
132
+ out[role] = expandPath(paths[role] ?? ROLE_DEFAULTS[role], WORKSPACE_ROLES.includes(role) ? root : vault);
168
133
  }
169
134
  for (const [role, value] of Object.entries(paths))
170
135
  if (!(role in out))
@@ -181,18 +146,15 @@ export function assembleWorkspace(root, source, config) {
181
146
  agents: join(root, 'agents'),
182
147
  ledger: join(root, 'ledger'),
183
148
  conversations: join(root, 'conversations'),
184
- claudeAgents: join(root, '.claude', 'agents'),
185
- qwenAgents: join(root, '.qwen', 'agents'),
186
- scenes: join(root, 'scenes'),
149
+ skills: join(root, SKILLS_DIR),
187
150
  bundles: join(root, 'bundles'),
188
- snaps: join(root, 'snaps'),
151
+ home: join(root, 'home'),
152
+ lectures: join(root, 'lectures'),
153
+ tts: join(root, '.cotutor', 'tts'),
189
154
  },
190
155
  files: {
191
156
  config: join(root, CONFIG_FILE),
192
- observations: join(root, 'ledger', 'observations.jsonl'),
193
157
  artifacts: join(root, 'ledger', 'artifacts.jsonl'),
194
- rulesClaude: join(root, 'CLAUDE.md'),
195
- rulesQwen: join(root, 'QWEN.md'),
196
158
  },
197
159
  };
198
160
  }
@@ -218,3 +180,66 @@ export function workspaceReport(ws) {
218
180
  runtime: ws.config.runtimes.default,
219
181
  });
220
182
  }
183
+ // ---- cotutor.json 的补丁写回与热重载(从 runtime/journal/store.ts 搬来,2026-10-29) ----
184
+ /** PATCH 允许改的顶层键(老师团页与设置页);kid / version / 运行时模板走编辑器 */
185
+ export const CONFIG_PATCH_KEYS = ['title', 'policyDefaults', 'tutors', 'agents', 'paths', 'server', 'vault', 'live'];
186
+ const isPlainObj = (v) => Boolean(v) && typeof v === 'object' && !Array.isArray(v);
187
+ /**
188
+ * 深合并:对象递归、其余覆盖、null 删键(老师条目可整体删:tutors.x = null)。
189
+ * 底下没有这个对象时也要**先剥掉 null 再放**——页面上留空的字段发的就是 null,
190
+ * 直接把补丁原样放进去会写出 `policy: {replyMaxChars: null, …}`,整份过不了契约、一保存就报错
191
+ * (2026-09-11:老师条目本来没有 policy 键时必然撞上,出厂六位都是这样)。
192
+ */
193
+ export function deepMerge(base, patch) {
194
+ if (!isPlainObj(patch))
195
+ return patch;
196
+ const out = isPlainObj(base) ? { ...base } : {};
197
+ for (const [k, v] of Object.entries(patch)) {
198
+ if (v === null) {
199
+ delete out[k];
200
+ continue;
201
+ }
202
+ const had = k in out;
203
+ const merged = deepMerge(out[k], v);
204
+ // 补丁里一组字段全留空(全是 null)时别凭空造个空对象出来:policy: {contextPack: {}} 这种噪音不该进政策文件
205
+ if (!had && isPlainObj(merged) && !Object.keys(merged).length)
206
+ continue;
207
+ out[k] = merged;
208
+ }
209
+ return out;
210
+ }
211
+ /**
212
+ * 补丁合到原始 JSON 上(保留 _note 等机器不认识的键),整份过契约再写;写坏了不落盘。
213
+ * 返回新配置;agents 只允许改 default(运行时模板走编辑器,页面上改错一个引号就把老师全弄哑)。
214
+ */
215
+ /** also:除了工作台能改的,这次还放行哪几个顶层键(家长端设置自己拼好补丁,只放 talk 的几项) */
216
+ export async function patchConfig(ws, patch, opts = {}) {
217
+ const allowed = [...CONFIG_PATCH_KEYS, ...(opts.also ?? [])];
218
+ const unknown = Object.keys(patch).filter((k) => !allowed.includes(k));
219
+ if (unknown.length)
220
+ throw new ConfigError(ws.files.config, `页面只能改 ${CONFIG_PATCH_KEYS.join(' / ')},不认识:${unknown.join(', ')};其余字段请直接编辑文件`);
221
+ if (isPlainObj(patch.agents) && Object.keys(patch.agents).some((k) => k !== 'default')) {
222
+ throw new ConfigError(ws.files.config, 'agents 只能在页面上改 default;运行时模板请直接编辑文件');
223
+ }
224
+ const raw = readJson(ws.files.config);
225
+ if (raw === null)
226
+ throw new ConfigError(ws.files.config, '不存在');
227
+ const merged = deepMerge(raw, patch);
228
+ const r = CotutorConfigSchema.safeParse(merged);
229
+ if (!r.success)
230
+ throw new ConfigError(ws.files.config, `补丁应用后不合契约,未写入:\n${explainIssues(r.error.issues).map((l) => ` - ${l}`).join('\n')}`);
231
+ const tmp = `${ws.files.config}.tmp`;
232
+ await writeFile(tmp, `${JSON.stringify(merged, null, 2)}\n`);
233
+ await rename(tmp, ws.files.config);
234
+ return r.data;
235
+ }
236
+ /** 文件改了(页面写的、或家长在编辑器改的)就重读;坏了抛 ConfigError,调用方决定是留旧的还是响 */
237
+ export async function reloadIfChanged(ws, lastMtime) {
238
+ const st = await stat(ws.files.config);
239
+ if (st.mtimeMs === lastMtime)
240
+ return { ws, mtime: lastMtime };
241
+ const raw = readJson(ws.files.config);
242
+ if (raw === null)
243
+ throw new ConfigError(ws.files.config, '不存在了');
244
+ return { ws: assembleWorkspace(ws.root, ws.source, parseConfig(raw, ws.files.config)), mtime: st.mtimeMs };
245
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * 实时老师的那条 WebSocket:WS /api/live/<老师>/ws,一次连接一个 LiveCall(call.ts)。
3
+ * serve.ts 的 upgrade 里接一行;有脸的老师都走这里,不是有脸的、关着的、藏着的回 404。
4
+ * ?listen=open = 一直听(孩子不用按);缺省按住说。
5
+ */
6
+ import type { IncomingMessage } from 'node:http';
7
+ import type { Duplex } from 'node:stream';
8
+ import { type LiveApp } from '../../runtime/live/call.ts';
9
+ export interface LiveRouteDeps {
10
+ /** realtime 端点(测试、探针换假的);不给用真的 */
11
+ endpoint?: string;
12
+ env?: NodeJS.ProcessEnv;
13
+ /** 测试:心跳间隔、多久没动静停跳、输入多少 token 换连接 */
14
+ heartbeatMs?: number;
15
+ keepAliveMs?: number;
16
+ swapTokens?: number;
17
+ idleSwapMs?: number;
18
+ echoWaitMs?: number;
19
+ ringMs?: number;
20
+ stallMs?: number;
21
+ onFinished?(tutor: string, why: string): void;
22
+ }
23
+ export declare function makeLiveUpgrade(deps?: LiveRouteDeps): (req: IncomingMessage, socket: Duplex, head: Buffer, ctx: LiveApp) => Promise<boolean>;
24
+ /** 探针:COTUTOR_LIVE_ENDPOINT 指到假百炼 */
25
+ export declare const liveUpgrade: (req: IncomingMessage, socket: Duplex, head: Buffer, ctx: LiveApp) => Promise<boolean>;
@@ -0,0 +1,29 @@
1
+ import { LiveCall } from "../../runtime/live/call.js";
2
+ import { acceptWebSocket, isUpgrade } from "./ws.js";
3
+ import { cookieOf } from "../http/access.js";
4
+ import { DEVICE_COOKIE } from "../../schema/kid-device.js";
5
+ export function makeLiveUpgrade(deps = {}) {
6
+ return async function liveUpgrade(req, socket, head, ctx) {
7
+ const m = /^\/api\/live\/([a-z0-9][a-z0-9-]*)\/ws(?:\?.*)?$/.exec(req.url ?? '');
8
+ if (!m || !isUpgrade(req))
9
+ return false;
10
+ const tutor = m[1];
11
+ const cfg = ctx.runner.ws.config;
12
+ const refuse = (status, why) => { socket.end(`HTTP/1.1 ${status} ${why}\r\nConnection: close\r\nContent-Length: 0\r\n\r\n`); return true; };
13
+ const t = cfg.tutors[tutor];
14
+ if (!tutor.endsWith('-tutor') || !t || !t.enabled || t.hidden)
15
+ return refuse(404, 'not live');
16
+ let call = null;
17
+ const sock = acceptWebSocket(req, socket, head, {
18
+ onText: (x) => call?.onText(x),
19
+ onBinary: (b) => call?.onAudio(b),
20
+ onClose: () => call?.onSocketClose(),
21
+ });
22
+ const listen = new URL(req.url ?? '', 'http://x').searchParams.get('listen') === 'open' ? 'open' : 'hold';
23
+ call = new LiveCall(sock, { ctx, tutor, deviceId: cookieOf(req.headers.cookie, DEVICE_COOKIE), listen, endpoint: deps.endpoint, env: deps.env, heartbeatMs: deps.heartbeatMs, keepAliveMs: deps.keepAliveMs, swapTokens: deps.swapTokens, idleSwapMs: deps.idleSwapMs, echoWaitMs: deps.echoWaitMs, ringMs: deps.ringMs, stallMs: deps.stallMs, onFinished: (why) => deps.onFinished?.(tutor, why) });
24
+ void call.start();
25
+ return true;
26
+ };
27
+ }
28
+ /** 探针:COTUTOR_LIVE_ENDPOINT 指到假百炼 */
29
+ export const liveUpgrade = makeLiveUpgrade(process.env.COTUTOR_LIVE_ENDPOINT ? { endpoint: process.env.COTUTOR_LIVE_ENDPOINT, env: { ...process.env, DASHSCOPE_API_KEY: process.env.DASHSCOPE_API_KEY ?? 'sk-probe' } } : {});
@@ -0,0 +1,31 @@
1
+ import type { IncomingMessage } from 'node:http';
2
+ import type { Duplex } from 'node:stream';
3
+ export interface SocketEvents {
4
+ onText?(text: string): void;
5
+ onBinary?(data: Buffer): void;
6
+ onClose?(code: number, reason: string): void;
7
+ }
8
+ export interface ServerSocket {
9
+ sendText(text: string): boolean;
10
+ sendBinary(data: Buffer | Uint8Array): boolean;
11
+ close(code?: number, reason?: string): void;
12
+ readonly open: boolean;
13
+ }
14
+ /** 是不是 WebSocket 升级请求 */
15
+ export declare function isUpgrade(req: IncomingMessage): boolean;
16
+ export declare function acceptKey(key: string): string;
17
+ /** 把一帧编出来(服务端不打掩码) */
18
+ export declare function encodeFrame(opcode: number, payload: Buffer): Buffer;
19
+ export interface Frame {
20
+ fin: boolean;
21
+ opcode: number;
22
+ payload: Buffer;
23
+ size: number;
24
+ }
25
+ /** 从缓冲区头上解一帧;不够一帧回 null;坏帧抛 */
26
+ export declare function decodeFrame(buf: Buffer): Frame | null;
27
+ /**
28
+ * 接受一条升级请求:写握手响应,之后 socket 归这里管。
29
+ * 回的对象发消息;事件在 ev 里。只在 isUpgrade(req) 为真时调。
30
+ */
31
+ export declare function acceptWebSocket(req: IncomingMessage, socket: Duplex, head: Buffer, ev: SocketEvents): ServerSocket;
@@ -0,0 +1,169 @@
1
+ /**
2
+ * 最小的 WebSocket 服务端(RFC 6455),零依赖:孩子端 ↔ 本服务那条线用它(口语课、实时老师),测试里也拿它假扮百炼。
3
+ * 只做用得上的:握手、文本 / 二进制帧、分片拼接、ping/pong、close;不做扩展(permessage-deflate 不协商就不会来)。
4
+ * 客户端发来的帧必须带掩码(浏览器、Node 都带);服务端发出去的不带。
5
+ */
6
+ import { createHash } from 'node:crypto';
7
+ const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
8
+ /** 一帧最多收这么大(一块音频 100 毫秒 3200 字节;JSON 控制消息更小) */
9
+ const MAX_FRAME = 4 * 1024 * 1024;
10
+ /** 是不是 WebSocket 升级请求 */
11
+ export function isUpgrade(req) {
12
+ return (req.headers.upgrade ?? '').toLowerCase() === 'websocket' && typeof req.headers['sec-websocket-key'] === 'string';
13
+ }
14
+ export function acceptKey(key) {
15
+ return createHash('sha1').update(key + GUID).digest('base64');
16
+ }
17
+ /** 把一帧编出来(服务端不打掩码) */
18
+ export function encodeFrame(opcode, payload) {
19
+ const len = payload.length;
20
+ let head;
21
+ if (len < 126) {
22
+ head = Buffer.alloc(2);
23
+ head[1] = len;
24
+ }
25
+ else if (len < 65536) {
26
+ head = Buffer.alloc(4);
27
+ head[1] = 126;
28
+ head.writeUInt16BE(len, 2);
29
+ }
30
+ else {
31
+ head = Buffer.alloc(10);
32
+ head[1] = 127;
33
+ head.writeBigUInt64BE(BigInt(len), 2);
34
+ }
35
+ head[0] = 0x80 | opcode;
36
+ return Buffer.concat([head, payload]);
37
+ }
38
+ /** 从缓冲区头上解一帧;不够一帧回 null;坏帧抛 */
39
+ export function decodeFrame(buf) {
40
+ if (buf.length < 2)
41
+ return null;
42
+ const fin = (buf[0] & 0x80) !== 0;
43
+ const opcode = buf[0] & 0x0f;
44
+ const masked = (buf[1] & 0x80) !== 0;
45
+ let len = buf[1] & 0x7f;
46
+ let p = 2;
47
+ if (len === 126) {
48
+ if (buf.length < 4)
49
+ return null;
50
+ len = buf.readUInt16BE(2);
51
+ p = 4;
52
+ }
53
+ else if (len === 127) {
54
+ if (buf.length < 10)
55
+ return null;
56
+ const big = buf.readBigUInt64BE(2);
57
+ if (big > BigInt(MAX_FRAME))
58
+ throw new Error('frame too large');
59
+ len = Number(big);
60
+ p = 10;
61
+ }
62
+ if (len > MAX_FRAME)
63
+ throw new Error('frame too large');
64
+ if (!masked)
65
+ throw new Error('client frame without mask');
66
+ if (buf.length < p + 4 + len)
67
+ return null;
68
+ const mask = buf.subarray(p, p + 4);
69
+ p += 4;
70
+ const payload = Buffer.allocUnsafe(len);
71
+ for (let i = 0; i < len; i++)
72
+ payload[i] = buf[p + i] ^ mask[i & 3];
73
+ return { fin, opcode, payload, size: p + len };
74
+ }
75
+ /**
76
+ * 接受一条升级请求:写握手响应,之后 socket 归这里管。
77
+ * 回的对象发消息;事件在 ev 里。只在 isUpgrade(req) 为真时调。
78
+ */
79
+ export function acceptWebSocket(req, socket, head, ev) {
80
+ const key = String(req.headers['sec-websocket-key']);
81
+ socket.write(`HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: ${acceptKey(key)}\r\n\r\n`);
82
+ let buf = head.length ? Buffer.from(head) : Buffer.alloc(0);
83
+ let open = true;
84
+ let partial = null;
85
+ const closeWith = (code, reason) => {
86
+ if (!open)
87
+ return;
88
+ open = false;
89
+ try {
90
+ socket.end();
91
+ }
92
+ catch { /* 已经断了 */ }
93
+ ev.onClose?.(code, reason);
94
+ };
95
+ const raw = (opcode, payload) => {
96
+ if (!open || socket.destroyed)
97
+ return false;
98
+ socket.write(encodeFrame(opcode, payload));
99
+ return true;
100
+ };
101
+ const deliver = (opcode, payload) => {
102
+ if (opcode === 0x1)
103
+ ev.onText?.(payload.toString('utf8'));
104
+ else if (opcode === 0x2)
105
+ ev.onBinary?.(payload);
106
+ };
107
+ socket.on('data', (chunk) => {
108
+ buf = buf.length ? Buffer.concat([buf, chunk]) : chunk;
109
+ try {
110
+ for (;;) {
111
+ const f = decodeFrame(buf);
112
+ if (!f)
113
+ break;
114
+ buf = buf.subarray(f.size);
115
+ if (f.opcode === 0x8) {
116
+ const code = f.payload.length >= 2 ? f.payload.readUInt16BE(0) : 1005;
117
+ raw(0x8, f.payload.subarray(0, 2));
118
+ closeWith(code, f.payload.length > 2 ? f.payload.subarray(2).toString('utf8') : '');
119
+ return;
120
+ }
121
+ if (f.opcode === 0x9) {
122
+ raw(0xa, f.payload);
123
+ continue;
124
+ }
125
+ if (f.opcode === 0xa)
126
+ continue;
127
+ if (f.opcode === 0x0) {
128
+ if (!partial)
129
+ throw new Error('continuation without start');
130
+ partial.chunks.push(f.payload);
131
+ if (f.fin) {
132
+ const whole = Buffer.concat(partial.chunks);
133
+ const op = partial.opcode;
134
+ partial = null;
135
+ deliver(op, whole);
136
+ }
137
+ continue;
138
+ }
139
+ if (!f.fin) {
140
+ partial = { opcode: f.opcode, chunks: [f.payload] };
141
+ continue;
142
+ }
143
+ deliver(f.opcode, f.payload);
144
+ }
145
+ }
146
+ catch (err) {
147
+ raw(0x8, Buffer.from([0x03, 0xea]));
148
+ closeWith(1002, err instanceof Error ? err.message : 'protocol error');
149
+ }
150
+ });
151
+ socket.on('error', () => closeWith(1006, 'socket error'));
152
+ socket.on('close', () => closeWith(1006, 'socket closed'));
153
+ socket.on('end', () => closeWith(1006, 'socket ended'));
154
+ return {
155
+ get open() { return open; },
156
+ sendText: (text) => raw(0x1, Buffer.from(text, 'utf8')),
157
+ sendBinary: (data) => raw(0x2, Buffer.isBuffer(data) ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength)),
158
+ close: (code = 1000, reason = '') => {
159
+ if (!open)
160
+ return;
161
+ const r = Buffer.from(reason, 'utf8');
162
+ const p = Buffer.alloc(2 + r.length);
163
+ p.writeUInt16BE(code, 0);
164
+ r.copy(p, 2);
165
+ raw(0x8, p);
166
+ closeWith(code, reason);
167
+ },
168
+ };
169
+ }