cotutor 0.1.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.
- package/LICENSE +247 -21
- package/NOTICE +42 -0
- package/README.md +107 -24
- package/bin/cotutor.js +4 -4
- package/cards/canvas/card.css +8 -0
- package/cards/canvas/card.md +68 -0
- package/cards/choice/card.css +18 -0
- package/cards/choice/card.md +55 -0
- package/cards/code/card.css +5 -0
- package/cards/code/card.md +46 -0
- package/cards/dictation/card.css +10 -0
- package/cards/dictation/card.md +97 -0
- package/cards/image/card.css +10 -0
- package/cards/image/card.md +52 -0
- package/cards/lecture/card.css +9 -0
- package/cards/lecture/card.md +69 -0
- package/cards/paint/card.css +20 -0
- package/cards/paint/card.md +77 -0
- package/cards/photo/card.css +15 -0
- package/cards/photo/card.md +61 -0
- package/cards/read/card.css +6 -0
- package/cards/read/card.md +51 -0
- package/cards/text/card.css +3 -0
- package/cards/text/card.md +69 -0
- package/cards/tianzige/card.css +17 -0
- package/cards/tianzige/card.md +78 -0
- package/cards/tutor/card.css +66 -0
- package/cards/tutor/card.md +148 -0
- package/cards/word/card.css +24 -0
- package/cards/word/card.md +91 -0
- package/cards//346/235/277/344/271/246/346/200/216/344/271/210/345/206/231.md +159 -0
- package/dist/app/activity-eval-rules.d.ts +62 -0
- package/dist/app/activity-eval-rules.js +276 -0
- package/dist/app/activity-eval.d.ts +65 -0
- package/dist/app/activity-eval.js +158 -0
- package/dist/app/build.d.ts +11 -0
- package/dist/app/build.js +45 -0
- package/dist/app/cli/activities.d.ts +63 -0
- package/dist/app/cli/activities.js +158 -0
- package/dist/app/cli/cert.d.ts +7 -0
- package/dist/app/cli/cert.js +36 -0
- package/dist/app/cli/chalk/bake.d.ts +10 -0
- package/dist/app/cli/chalk/bake.js +58 -0
- package/dist/app/cli/chalk/browser.d.ts +16 -0
- package/dist/app/cli/chalk/browser.js +142 -0
- package/dist/app/cli/chalk/build.d.ts +14 -0
- package/dist/app/cli/chalk/build.js +100 -0
- package/dist/app/cli/chalk/dub.d.ts +51 -0
- package/dist/app/cli/chalk/dub.js +106 -0
- package/dist/app/cli/chalk/load-scene.d.ts +34 -0
- package/dist/app/cli/chalk/load-scene.js +117 -0
- package/dist/app/cli/chalk/main.d.ts +7 -0
- package/dist/app/cli/chalk/main.js +198 -0
- package/dist/app/cli/chalk/serve.d.ts +4 -0
- package/dist/app/cli/chalk/serve.js +28 -0
- package/dist/app/cli/chalk/snap.d.ts +65 -0
- package/dist/app/cli/chalk/snap.js +103 -0
- package/dist/app/cli/chalk/typecheck.d.ts +7 -0
- package/dist/app/cli/chalk/typecheck.js +51 -0
- package/dist/app/cli/doctor.d.ts +23 -0
- package/dist/app/cli/doctor.js +617 -0
- package/dist/app/cli/grades.d.ts +14 -0
- package/dist/app/cli/grades.js +44 -0
- package/dist/{cli → app/cli}/init.d.ts +3 -1
- package/dist/app/cli/init.js +155 -0
- package/dist/app/cli/main.js +715 -0
- package/dist/app/cli/migrate.d.ts +58 -0
- package/dist/app/cli/migrate.js +253 -0
- package/dist/app/cli/serve.d.ts +37 -0
- package/dist/app/cli/serve.js +98 -0
- package/dist/app/cli/shipped.d.ts +30 -0
- package/dist/app/cli/shipped.js +47 -0
- package/dist/app/cli/skeleton.d.ts +38 -0
- package/dist/app/cli/skeleton.js +161 -0
- package/dist/app/cli/skills.d.ts +55 -0
- package/dist/app/cli/skills.js +189 -0
- package/dist/app/cli/themes.d.ts +52 -0
- package/dist/app/cli/themes.js +148 -0
- package/dist/app/cli/tutors.d.ts +73 -0
- package/dist/app/cli/tutors.js +250 -0
- package/dist/app/cli/usage.d.ts +2 -0
- package/dist/app/cli/usage.js +30 -0
- package/dist/app/dictation/recognize.d.ts +18 -0
- package/dist/app/dictation/recognize.js +6 -0
- package/dist/app/dictation/route.d.ts +52 -0
- package/dist/app/dictation/route.js +510 -0
- package/dist/app/diff.d.ts +11 -0
- package/dist/app/diff.js +71 -0
- package/dist/app/http/access.d.ts +62 -0
- package/dist/app/http/access.js +180 -0
- package/dist/app/http/app.d.ts +246 -0
- package/dist/app/http/app.js +1212 -0
- package/dist/app/http/dev-activities.d.ts +115 -0
- package/dist/app/http/dev-activities.js +193 -0
- package/dist/app/http/dev-overview.d.ts +108 -0
- package/dist/app/http/dev-overview.js +209 -0
- package/dist/app/http/dev-tutor-files.d.ts +80 -0
- package/dist/app/http/dev-tutor-files.js +151 -0
- package/dist/app/http/parent-home.d.ts +37 -0
- package/dist/app/http/parent-home.js +203 -0
- package/dist/app/http/range.d.ts +9 -0
- package/dist/app/http/range.js +19 -0
- package/dist/app/http/raw-view.d.ts +117 -0
- package/dist/app/http/raw-view.js +149 -0
- package/dist/app/http/send-file.d.ts +7 -0
- package/dist/app/http/send-file.js +29 -0
- package/dist/app/http/stage.d.ts +24 -0
- package/dist/app/http/stage.js +97 -0
- package/dist/app/http/theme.d.ts +13 -0
- package/dist/app/http/theme.js +41 -0
- package/dist/app/machine/bailian.d.ts +28 -0
- package/dist/app/machine/bailian.js +88 -0
- package/dist/app/mock/mock-live.d.ts +16 -0
- package/dist/app/mock/mock-live.js +140 -0
- package/dist/app/mock/mock.d.ts +89 -0
- package/dist/app/mock/mock.js +1117 -0
- package/dist/app/replay.d.ts +94 -0
- package/dist/app/replay.js +170 -0
- package/dist/app/skills/analyze-doc.d.ts +3 -0
- package/dist/app/skills/analyze-doc.js +47 -0
- package/dist/app/skills/home-doc.d.ts +5 -0
- package/dist/app/skills/home-doc.js +112 -0
- package/dist/app/skills/tune-doc.d.ts +3 -0
- package/dist/app/skills/tune-doc.js +80 -0
- package/dist/app/talk/list.d.ts +11 -0
- package/dist/app/talk/list.js +9 -0
- package/dist/app/talk/route.d.ts +16 -0
- package/dist/app/talk/route.js +142 -0
- package/dist/app/workspace.d.ts +58 -0
- package/dist/{cli → app}/workspace.js +82 -36
- package/dist/app/ws/route.d.ts +25 -0
- package/dist/app/ws/route.js +29 -0
- package/dist/app/ws/ws.d.ts +31 -0
- package/dist/app/ws/ws.js +169 -0
- package/dist/board/canvas-chat.d.ts +97 -0
- package/dist/board/canvas-chat.js +175 -0
- package/dist/board/card-guards.d.ts +15 -0
- package/dist/board/card-guards.js +38 -0
- package/dist/board/cards/canvas.d.ts +41 -0
- package/dist/board/cards/canvas.js +83 -0
- package/dist/board/cards/choice.d.ts +20 -0
- package/dist/board/cards/choice.js +64 -0
- package/dist/board/cards/code.d.ts +9 -0
- package/dist/board/cards/code.js +10 -0
- package/dist/board/cards/dictation.d.ts +42 -0
- package/dist/board/cards/dictation.js +105 -0
- package/dist/board/cards/docs.d.ts +47 -0
- package/dist/board/cards/docs.js +152 -0
- package/dist/board/cards/image.d.ts +13 -0
- package/dist/board/cards/image.js +26 -0
- package/dist/board/cards/index.d.ts +62 -0
- package/dist/board/cards/index.js +144 -0
- package/dist/board/cards/kind.d.ts +33 -0
- package/dist/board/cards/kind.js +9 -0
- package/dist/board/cards/lecture.d.ts +26 -0
- package/dist/board/cards/lecture.js +62 -0
- package/dist/board/cards/paint.d.ts +38 -0
- package/dist/board/cards/paint.js +85 -0
- package/dist/board/cards/photo.d.ts +15 -0
- package/dist/board/cards/photo.js +29 -0
- package/dist/board/cards/read.d.ts +8 -0
- package/dist/board/cards/read.js +18 -0
- package/dist/board/cards/text.d.ts +20 -0
- package/dist/board/cards/text.js +59 -0
- package/dist/board/cards/tianzige.d.ts +16 -0
- package/dist/board/cards/tianzige.js +64 -0
- package/dist/board/cards/tutor.d.ts +72 -0
- package/dist/board/cards/tutor.js +134 -0
- package/dist/board/cards/word.d.ts +20 -0
- package/dist/board/cards/word.js +76 -0
- package/dist/board/lecture.d.ts +100 -0
- package/dist/board/lecture.js +204 -0
- package/dist/board/paper.d.ts +20 -0
- package/dist/board/paper.js +76 -0
- package/dist/board/parse.d.ts +120 -0
- package/dist/board/parse.js +330 -0
- package/dist/board/presentation.d.ts +295 -0
- package/dist/board/presentation.js +615 -0
- package/dist/board/sections.d.ts +16 -0
- package/dist/board/sections.js +130 -0
- package/dist/brain/api-tools.d.ts +8 -0
- package/dist/brain/api-tools.js +190 -0
- package/dist/brain/api.d.ts +62 -0
- package/dist/brain/api.js +411 -0
- package/dist/brain/cli/adapters.d.ts +60 -0
- package/dist/brain/cli/adapters.js +91 -0
- package/dist/brain/cli/qwen.d.ts +11 -0
- package/dist/brain/cli/qwen.js +141 -0
- package/dist/brain/cli/run-plan.d.ts +59 -0
- package/dist/brain/cli/run-plan.js +71 -0
- package/dist/brain/cli/run.d.ts +35 -0
- package/dist/brain/cli/run.js +256 -0
- package/dist/brain/cli/stream-json.d.ts +18 -0
- package/dist/brain/cli/stream-json.js +86 -0
- package/dist/brain/cli/types.d.ts +144 -0
- package/dist/brain/cli/types.js +3 -0
- package/dist/brain/cli/warm.d.ts +53 -0
- package/dist/brain/cli/warm.js +103 -0
- package/dist/brain/index.d.ts +145 -0
- package/dist/brain/index.js +74 -0
- package/dist/brain/stream.d.ts +20 -0
- package/dist/brain/stream.js +70 -0
- package/dist/brain/transcript.d.ts +45 -0
- package/dist/brain/transcript.js +132 -0
- package/dist/chalk/actions.d.ts +37 -0
- package/dist/chalk/actions.js +69 -0
- package/dist/chalk/bundle.d.ts +26 -0
- package/dist/chalk/bundle.js +69 -0
- package/dist/chalk/check.d.ts +28 -0
- package/dist/chalk/check.js +291 -0
- package/dist/chalk/circle.d.ts +64 -0
- package/dist/chalk/circle.js +193 -0
- package/dist/chalk/clock.d.ts +84 -0
- package/dist/chalk/clock.js +84 -0
- package/dist/chalk/geometry.d.ts +44 -0
- package/dist/chalk/geometry.js +139 -0
- package/dist/chalk/glyphs/capitals.d.ts +12 -0
- package/dist/chalk/glyphs/capitals.js +264 -0
- package/dist/chalk/glyphs/index.d.ts +21 -0
- package/dist/chalk/glyphs/index.js +18 -0
- package/dist/chalk/glyphs/letters.d.ts +13 -0
- package/dist/chalk/glyphs/letters.js +280 -0
- package/dist/chalk/glyphs/metrics.d.ts +33 -0
- package/dist/chalk/glyphs/metrics.js +28 -0
- package/dist/chalk/glyphs/registry.d.ts +7 -0
- package/dist/chalk/glyphs/registry.js +8 -0
- package/dist/chalk/glyphs/sample.d.ts +32 -0
- package/dist/chalk/glyphs/sample.js +102 -0
- package/dist/chalk/glyphs/skeleton.d.ts +64 -0
- package/dist/chalk/glyphs/skeleton.js +126 -0
- package/dist/chalk/glyphs/types.d.ts +58 -0
- package/dist/chalk/glyphs/types.js +17 -0
- package/dist/chalk/index.d.ts +23 -0
- package/dist/chalk/index.js +15 -0
- package/dist/chalk/manifest.d.ts +41 -0
- package/dist/chalk/manifest.js +6 -0
- package/dist/chalk/paint.d.ts +180 -0
- package/dist/chalk/paint.js +210 -0
- package/dist/chalk/pointer.d.ts +8 -0
- package/dist/chalk/pointer.js +21 -0
- package/dist/chalk/prepare.d.ts +11 -0
- package/dist/chalk/prepare.js +15 -0
- package/dist/chalk/scene-schema.d.ts +199 -0
- package/dist/chalk/scene-schema.js +91 -0
- package/dist/chalk/seed.d.ts +3 -0
- package/dist/chalk/seed.js +10 -0
- package/dist/chalk/text-metrics.d.ts +8 -0
- package/dist/chalk/text-metrics.js +156 -0
- package/dist/chalk/timeline.d.ts +47 -0
- package/dist/chalk/timeline.js +84 -0
- package/dist/chalk/types.d.ts +150 -0
- package/dist/chalk/types.js +8 -0
- package/dist/lib/index.d.ts +14 -8
- package/dist/lib/index.js +14 -8
- package/dist/media/draw.d.ts +23 -0
- package/dist/media/draw.js +44 -0
- package/dist/media/mp3.d.ts +6 -0
- package/dist/media/mp3.js +58 -0
- package/dist/media/mp4.d.ts +1 -0
- package/dist/media/mp4.js +58 -0
- package/dist/media/tts-voices.d.ts +18 -0
- package/dist/media/tts-voices.js +606 -0
- package/dist/media/tts.d.ts +56 -0
- package/dist/media/tts.js +174 -0
- package/dist/media/vision.d.ts +25 -0
- package/dist/media/vision.js +71 -0
- package/dist/memory/commit.d.ts +67 -0
- package/dist/memory/commit.js +130 -0
- package/dist/memory/context.d.ts +86 -0
- package/dist/memory/context.js +97 -0
- package/dist/memory/diary.d.ts +84 -0
- package/dist/memory/diary.js +183 -0
- package/dist/memory/grade.d.ts +2 -0
- package/dist/memory/grade.js +7 -0
- package/dist/{lib → memory}/plan.d.ts +3 -1
- package/dist/{lib → memory}/plan.js +10 -1
- package/dist/memory/proposals.d.ts +11 -0
- package/dist/memory/proposals.js +43 -0
- package/dist/memory/retrieval.d.ts +44 -0
- package/dist/memory/retrieval.js +157 -0
- package/dist/memory/timetable.d.ts +19 -0
- package/dist/memory/timetable.js +95 -0
- package/dist/memory/vault-notes.d.ts +165 -0
- package/dist/memory/vault-notes.js +359 -0
- package/dist/memory/vault.d.ts +70 -0
- package/dist/memory/vault.js +169 -0
- package/dist/realtime/bailian.d.ts +120 -0
- package/dist/realtime/bailian.js +288 -0
- package/dist/realtime/cues.d.ts +51 -0
- package/dist/realtime/cues.js +94 -0
- package/dist/realtime/listen.d.ts +32 -0
- package/dist/realtime/listen.js +53 -0
- package/dist/realtime/preview.d.ts +23 -0
- package/dist/realtime/preview.js +38 -0
- package/dist/realtime/prompt.d.ts +8 -0
- package/dist/realtime/prompt.js +13 -0
- package/dist/realtime/voices.d.ts +19 -0
- package/dist/realtime/voices.js +71 -0
- package/dist/runtime/activities.d.ts +17 -0
- package/dist/runtime/activities.js +46 -0
- package/dist/runtime/activity-state.d.ts +22 -0
- package/dist/runtime/activity-state.js +83 -0
- package/dist/runtime/activity.d.ts +63 -0
- package/dist/runtime/activity.js +428 -0
- package/dist/runtime/agent-file.d.ts +24 -0
- package/dist/runtime/agent-file.js +59 -0
- package/dist/runtime/auto-bookkeep.d.ts +30 -0
- package/dist/runtime/auto-bookkeep.js +84 -0
- package/dist/{lib → runtime/context}/context-pack.d.ts +3 -3
- package/dist/runtime/context/context-pack.js +182 -0
- package/dist/runtime/context/thread-digest.d.ts +4 -0
- package/dist/runtime/context/thread-digest.js +35 -0
- package/dist/runtime/context/tutor-rules.d.ts +25 -0
- package/dist/runtime/context/tutor-rules.js +47 -0
- package/dist/runtime/delivery/delivery.d.ts +94 -0
- package/dist/runtime/delivery/delivery.js +145 -0
- package/dist/runtime/delivery/playback.d.ts +25 -0
- package/dist/runtime/delivery/playback.js +29 -0
- package/dist/runtime/delivery/player.d.ts +145 -0
- package/dist/runtime/delivery/player.js +221 -0
- package/dist/runtime/delivery/queue.d.ts +89 -0
- package/dist/runtime/delivery/queue.js +59 -0
- package/dist/runtime/home/edit.d.ts +39 -0
- package/dist/runtime/home/edit.js +132 -0
- package/dist/runtime/home/home.d.ts +180 -0
- package/dist/runtime/home/home.js +311 -0
- package/dist/runtime/home/store.d.ts +142 -0
- package/dist/runtime/home/store.js +440 -0
- package/dist/runtime/journal/conversation.d.ts +46 -0
- package/dist/runtime/journal/conversation.js +89 -0
- package/dist/runtime/journal/events.d.ts +27 -0
- package/dist/runtime/journal/events.js +136 -0
- package/dist/runtime/journal/kid-log.d.ts +105 -0
- package/dist/runtime/journal/kid-log.js +133 -0
- package/dist/runtime/journal/ledger.d.ts +17 -0
- package/dist/{lib → runtime/journal}/ledger.js +7 -32
- package/dist/runtime/journal/mix.d.ts +33 -0
- package/dist/runtime/journal/mix.js +88 -0
- package/dist/runtime/journal/mouth-index.d.ts +26 -0
- package/dist/runtime/journal/mouth-index.js +34 -0
- package/dist/runtime/journal/mouth.d.ts +54 -0
- package/dist/runtime/journal/mouth.js +102 -0
- package/dist/runtime/journal/recorder.d.ts +46 -0
- package/dist/runtime/journal/recorder.js +58 -0
- package/dist/runtime/journal/store.d.ts +123 -0
- package/dist/runtime/journal/store.js +316 -0
- package/dist/runtime/kid-input.d.ts +16 -0
- package/dist/runtime/kid-input.js +195 -0
- package/dist/runtime/kid-view.d.ts +124 -0
- package/dist/runtime/kid-view.js +157 -0
- package/dist/runtime/lecture.d.ts +86 -0
- package/dist/runtime/lecture.js +237 -0
- package/dist/runtime/live/call.d.ts +219 -0
- package/dist/runtime/live/call.js +1211 -0
- package/dist/runtime/live/turns.d.ts +48 -0
- package/dist/runtime/live/turns.js +102 -0
- package/dist/runtime/runner.d.ts +289 -0
- package/dist/runtime/runner.js +898 -0
- package/dist/runtime/talk-run.d.ts +21 -0
- package/dist/runtime/talk-run.js +34 -0
- package/dist/scenes/dictation/match.d.ts +57 -0
- package/dist/scenes/dictation/match.js +255 -0
- package/dist/scenes/dictation/recognize.d.ts +86 -0
- package/dist/scenes/dictation/recognize.js +163 -0
- package/dist/scenes/dictation/store.d.ts +112 -0
- package/dist/scenes/dictation/store.js +99 -0
- package/dist/scenes/look.d.ts +26 -0
- package/dist/scenes/look.js +1 -0
- package/dist/scenes/paint/painter.d.ts +84 -0
- package/dist/scenes/paint/painter.js +170 -0
- package/dist/scenes/paint/prompt.d.ts +23 -0
- package/dist/scenes/paint/prompt.js +36 -0
- package/dist/scenes/talk/en-words.d.ts +8 -0
- package/dist/scenes/talk/en-words.js +44 -0
- package/dist/scenes/talk/list.d.ts +44 -0
- package/dist/scenes/talk/list.js +88 -0
- package/dist/scenes/talk/store.d.ts +27 -0
- package/dist/scenes/talk/store.js +61 -0
- package/dist/scenes/talk/warmup.d.ts +16 -0
- package/dist/scenes/talk/warmup.js +39 -0
- package/dist/schema/activity.d.ts +149 -0
- package/dist/schema/activity.js +113 -0
- package/dist/schema/board.d.ts +200 -0
- package/dist/schema/board.js +42 -0
- package/dist/schema/config.d.ts +353 -80
- package/dist/schema/config.js +293 -76
- package/dist/schema/context-pack.d.ts +82 -13
- package/dist/schema/context-pack.js +97 -10
- package/dist/schema/conversation-files.d.ts +43 -0
- package/dist/schema/conversation-files.js +26 -0
- package/dist/schema/conversation.d.ts +459 -13
- package/dist/schema/conversation.js +148 -8
- package/dist/schema/events.d.ts +138 -0
- package/dist/schema/events.js +1 -0
- package/dist/schema/home.d.ts +46 -0
- package/dist/schema/home.js +30 -0
- package/dist/schema/index.d.ts +19 -4
- package/dist/schema/index.js +19 -4
- package/dist/schema/json-schema.d.ts +2 -0
- package/dist/schema/json-schema.js +23 -0
- package/dist/schema/kid-device.d.ts +20 -0
- package/dist/schema/kid-device.js +32 -0
- package/dist/schema/ledger.d.ts +9 -64
- package/dist/schema/ledger.js +7 -31
- package/dist/schema/memory.d.ts +73 -0
- package/dist/schema/memory.js +47 -0
- package/dist/schema/plan.d.ts +2 -2
- package/dist/schema/plan.js +2 -2
- package/dist/schema/sections.d.ts +32 -25
- package/dist/schema/sections.js +21 -22
- package/dist/schema/theme.d.ts +25 -0
- package/dist/schema/theme.js +26 -0
- package/dist/schema/timetable.d.ts +26 -0
- package/dist/schema/timetable.js +18 -0
- package/dist/schema/workspace.d.ts +41 -0
- package/dist/schema/workspace.js +9 -0
- package/dist/shared/errors.d.ts +8 -0
- package/dist/shared/errors.js +13 -0
- package/dist/shared/home.d.ts +2 -0
- package/dist/shared/home.js +16 -0
- package/dist/shared/human-notes.d.ts +5 -0
- package/dist/shared/human-notes.js +7 -0
- package/dist/shared/qianwen.d.ts +50 -0
- package/dist/shared/qianwen.js +109 -0
- package/dist/shared/time.d.ts +9 -0
- package/dist/shared/time.js +22 -0
- package/dist/shared/tokens.d.ts +18 -0
- package/dist/shared/tokens.js +11 -0
- package/dist/shared/wav.d.ts +10 -0
- package/dist/shared/wav.js +50 -0
- package/dist/stage/Assistant-Bold-ZDZZ6JHA.woff2 +0 -0
- package/dist/stage/Assistant-Medium-DZ25RZU3.woff2 +0 -0
- package/dist/stage/Assistant-Regular-PLF2XOGW.woff2 +0 -0
- package/dist/stage/Assistant-SemiBold-CZ5MX6FK.woff2 +0 -0
- package/dist/stage/chunk-226TNLQA.js +129 -0
- package/dist/stage/chunk-24LGQEKE.js +1 -0
- package/dist/stage/chunk-25XV6UY3.js +10 -0
- package/dist/stage/chunk-2AZI3NHJ.js +1 -0
- package/dist/stage/chunk-2BQZTTBE.js +1 -0
- package/dist/stage/chunk-2M7CGY3Y.js +11 -0
- package/dist/stage/chunk-2VR4WFQ7.js +10 -0
- package/dist/stage/chunk-2ZYXBUWG.js +9 -0
- package/dist/stage/chunk-32LAWMGY.js +1 -0
- package/dist/stage/chunk-3LEMTSOO.js +11 -0
- package/dist/stage/chunk-3QCKGZYE.js +32 -0
- package/dist/stage/chunk-44P66WFA.js +1 -0
- package/dist/stage/chunk-4AM6FRR6.js +7 -0
- package/dist/stage/chunk-4QDE4SUK.js +1 -0
- package/dist/stage/chunk-4QESHV3U.js +1 -0
- package/dist/stage/chunk-4SG5QPHB.js +2 -0
- package/dist/stage/chunk-4T4UVCOC.js +1 -0
- package/dist/stage/chunk-4WUEPPG3.js +34 -0
- package/dist/stage/chunk-4YCN6UZ5.js +99 -0
- package/dist/stage/chunk-5V7ZY2AP.js +1 -0
- package/dist/stage/chunk-5VS5Y2VJ.js +6 -0
- package/dist/stage/chunk-5W4NO2ZD.js +62 -0
- package/dist/stage/chunk-65CRNICM.js +1 -0
- package/dist/stage/chunk-66MULO7F.js +5 -0
- package/dist/stage/chunk-6COFQTBS.js +162 -0
- package/dist/stage/chunk-6VZG3M3I.js +8 -0
- package/dist/stage/chunk-7HVDH43T.js +1 -0
- package/dist/stage/chunk-7JLJN4EZ.js +8 -0
- package/dist/stage/chunk-7QDSP4LN.js +1 -0
- package/dist/stage/chunk-7R6OQAO3.js +1 -0
- package/dist/stage/chunk-7VTTHZKW.js +7 -0
- package/dist/stage/chunk-ATHR5KEN.js +10 -0
- package/dist/stage/chunk-B6R5LTP2.js +36 -0
- package/dist/stage/chunk-BD4WE264.js +1 -0
- package/dist/stage/chunk-BONANU47.js +206 -0
- package/dist/stage/chunk-BTVW7OFK.js +89 -0
- package/dist/stage/chunk-BUTJIDHG.js +8 -0
- package/dist/stage/chunk-C2IPYMML.js +84 -0
- package/dist/stage/chunk-C54FTPPV.js +9 -0
- package/dist/stage/chunk-C6LOUF2Z.js +90 -0
- package/dist/stage/chunk-CFF3PILO.js +339 -0
- package/dist/stage/chunk-CI2FQ2JY.js +9 -0
- package/dist/stage/chunk-CW5O4RV7.js +12 -0
- package/dist/stage/chunk-CYABNQYD.js +1 -0
- package/dist/stage/chunk-D7FFA4NS.js +15 -0
- package/dist/stage/chunk-DUNNXU6Z.js +8 -0
- package/dist/stage/chunk-E3E4Q6JF.js +6 -0
- package/dist/stage/chunk-EB3U3LH7.js +9 -0
- package/dist/stage/chunk-EGSZ736B.js +8 -0
- package/dist/stage/chunk-EOBXW5VQ.js +2 -0
- package/dist/stage/chunk-ERZC3B7Y.js +11 -0
- package/dist/stage/chunk-ESDOOBIH.js +11 -0
- package/dist/stage/chunk-EVU4QAL4.js +178 -0
- package/dist/stage/chunk-EVVZI2NY.js +39 -0
- package/dist/stage/chunk-FBKAZUKD.js +39 -0
- package/dist/stage/chunk-FDVKYQJN.js +1 -0
- package/dist/stage/chunk-FGPVYHVR.js +5 -0
- package/dist/stage/chunk-FHUD4AZC.js +1 -0
- package/dist/stage/chunk-FKUJ2DMY.js +96 -0
- package/dist/stage/chunk-FNZGVIJV.js +1 -0
- package/dist/stage/chunk-GBYSEGYM.js +78 -0
- package/dist/stage/chunk-GCO4TDHX.js +1 -0
- package/dist/stage/chunk-GKTML2LG.js +10 -0
- package/dist/stage/chunk-GMDIHHXQ.js +11 -0
- package/dist/stage/chunk-GOUNACI3.js +10 -0
- package/dist/stage/chunk-GXAYATPF.js +3 -0
- package/dist/stage/chunk-H2K2DDXV.js +8 -0
- package/dist/stage/chunk-H3UJI6ZY.js +13 -0
- package/dist/stage/chunk-H6PUGCME.js +7 -0
- package/dist/stage/chunk-HNBUIMIG.js +1 -0
- package/dist/stage/chunk-HRZY2BJQ.js +10 -0
- package/dist/stage/chunk-HSPJGALW.js +30 -0
- package/dist/stage/chunk-IBYORHIP.js +25 -0
- package/dist/stage/chunk-IHF4EWTY.js +1 -0
- package/dist/stage/chunk-ISBRPNKI.js +1 -0
- package/dist/stage/chunk-IZ3OI3C2.js +2 -0
- package/dist/stage/chunk-JEFZAC2R.js +1 -0
- package/dist/stage/chunk-JFIGRDPO.js +1 -0
- package/dist/stage/chunk-JFVYBOOC.js +9 -0
- package/dist/stage/chunk-JGD4TUTQ.js +1 -0
- package/dist/stage/chunk-JO4BEHDH.js +4 -0
- package/dist/stage/chunk-JOWBS42C.js +1 -0
- package/dist/stage/chunk-JP3TM2TG.js +1 -0
- package/dist/stage/chunk-JVK2C52O.js +1 -0
- package/dist/stage/chunk-K4I76XBX.js +14 -0
- package/dist/stage/chunk-KA6CZZ4M.js +1 -0
- package/dist/stage/chunk-KESSJ36M.js +1 -0
- package/dist/stage/chunk-LKATEVRU.js +1 -0
- package/dist/stage/chunk-LS4EJ2EI.js +1 -0
- package/dist/stage/chunk-LUKJQC2X.js +70 -0
- package/dist/stage/chunk-LWULR3SM.js +1 -0
- package/dist/stage/chunk-LWVRFMKX.js +2 -0
- package/dist/stage/chunk-LXC4ZBPZ.js +1 -0
- package/dist/stage/chunk-M2UP255H.js +1 -0
- package/dist/stage/chunk-MAPPXUZQ.js +231 -0
- package/dist/stage/chunk-MBMPW7Z5.js +1 -0
- package/dist/stage/chunk-MD3HMMTK.js +1 -0
- package/dist/stage/chunk-MLPCUIKR.js +17 -0
- package/dist/stage/chunk-MNQIRPDQ.js +8 -0
- package/dist/stage/chunk-MRG7MJVS.js +1 -0
- package/dist/stage/chunk-MU6EXW72.js +10 -0
- package/dist/stage/chunk-MVU2X6LU.js +4 -0
- package/dist/stage/chunk-N6UA5CZV.js +36 -0
- package/dist/stage/chunk-NLZIT2TJ.js +7 -0
- package/dist/stage/chunk-NOJR3J7M.js +1 -0
- package/dist/stage/chunk-NT7ARDOL.js +1 -0
- package/dist/stage/chunk-NWOGMPZH.js +1 -0
- package/dist/stage/chunk-NXE4KMG3.js +40 -0
- package/dist/stage/chunk-O4YCZXD2.js +257 -0
- package/dist/stage/chunk-OAJZ7HLK.js +1 -0
- package/dist/stage/chunk-OCFCFASO.js +1 -0
- package/dist/stage/chunk-ODGPG5RY.js +7 -0
- package/dist/stage/chunk-ODUEA52Q.js +3 -0
- package/dist/stage/chunk-OGDJ3FCI.js +1 -0
- package/dist/stage/chunk-OLDJ55TT.js +1 -0
- package/dist/stage/chunk-OOCL4ATI.js +2 -0
- package/dist/stage/chunk-OQEFDUDV.js +1 -0
- package/dist/stage/chunk-OQWVEWG7.js +4 -0
- package/dist/stage/chunk-OUIX6BGK.js +1 -0
- package/dist/stage/chunk-OV7OZYUO.js +7 -0
- package/dist/stage/chunk-PFGDY33O.js +1 -0
- package/dist/stage/chunk-PFJDUJB3.js +139 -0
- package/dist/stage/chunk-PGEW76ER.js +1 -0
- package/dist/stage/chunk-PP76TAQX.js +32 -0
- package/dist/stage/chunk-PTBOP4OT.js +2 -0
- package/dist/stage/chunk-PX2RVHCK.js +1 -0
- package/dist/stage/chunk-Q7K3PNAD.js +1 -0
- package/dist/stage/chunk-QDDPLZDB.js +1 -0
- package/dist/stage/chunk-QLGLZ77F.js +1 -0
- package/dist/stage/chunk-QOPFDFHI.js +1 -0
- package/dist/stage/chunk-QXT4KAEJ.js +1 -0
- package/dist/stage/chunk-R4YVZCIT.js +1 -0
- package/dist/stage/chunk-R6P6EHWA.js +62 -0
- package/dist/stage/chunk-RCH3OXBI.js +9 -0
- package/dist/stage/chunk-RHPE44I2.js +1 -0
- package/dist/stage/chunk-RJ2R4FVC.js +1 -0
- package/dist/stage/chunk-RJH2YVTD.js +1 -0
- package/dist/stage/chunk-RLWWW5OB.js +6 -0
- package/dist/stage/chunk-S3WO35Z7.js +120 -0
- package/dist/stage/chunk-S7ZGX6MW.js +1 -0
- package/dist/stage/chunk-SIAWX27B.js +1 -0
- package/dist/stage/chunk-SLG4X622.js +1 -0
- package/dist/stage/chunk-SLJRBC77.js +168 -0
- package/dist/stage/chunk-SRORWQJZ.js +1 -0
- package/dist/stage/chunk-STZTUIIF.js +2 -0
- package/dist/stage/chunk-SVQ6MWNV.js +9 -0
- package/dist/stage/chunk-TL3HLL2S.js +132 -0
- package/dist/stage/chunk-U3DOE6SF.js +24 -0
- package/dist/stage/chunk-UABQIZKW.js +6 -0
- package/dist/stage/chunk-UDK3R764.js +1 -0
- package/dist/stage/chunk-UFF4E54B.js +41 -0
- package/dist/stage/chunk-UFP5Q4AY.js +1 -0
- package/dist/stage/chunk-UMH2TSW2.js +72 -0
- package/dist/stage/chunk-UTASVNF5.js +10 -0
- package/dist/stage/chunk-UW7ML5ML.js +88 -0
- package/dist/stage/chunk-V3J7F6OP.js +1 -0
- package/dist/stage/chunk-VEHP5B5Q.js +5 -0
- package/dist/stage/chunk-VRXWB733.js +9 -0
- package/dist/stage/chunk-VVDHBBS5.js +5 -0
- package/dist/stage/chunk-VYFOH6FU.js +106 -0
- package/dist/stage/chunk-W3VZTLQS.js +3 -0
- package/dist/stage/chunk-W7WNRWTZ.js +8 -0
- package/dist/stage/chunk-WHUCV53C.js +1 -0
- package/dist/stage/chunk-WULMYHIF.js +1 -0
- package/dist/stage/chunk-X54EX7AW.js +9 -0
- package/dist/stage/chunk-X565ISZM.js +1 -0
- package/dist/stage/chunk-XGZMDECB.js +1 -0
- package/dist/stage/chunk-XHONC4RF.js +172 -0
- package/dist/stage/chunk-XIK4XQ6E.js +24 -0
- package/dist/stage/chunk-XJQQWFTE.js +1 -0
- package/dist/stage/chunk-XM4WOU3I.js +13 -0
- package/dist/stage/chunk-XM7Y5HP5.js +38 -0
- package/dist/stage/chunk-XNYYRGD5.js +292 -0
- package/dist/stage/chunk-XOYVR3SV.js +1 -0
- package/dist/stage/chunk-XQIW5HCE.js +1 -0
- package/dist/stage/chunk-YEWL7FUW.js +8 -0
- package/dist/stage/chunk-YI55PY3V.js +1 -0
- package/dist/stage/chunk-YM63HI6W.js +1 -0
- package/dist/stage/chunk-YNLGLU4P.js +9 -0
- package/dist/stage/chunk-YTNMNOWP.js +1 -0
- package/dist/stage/chunk-YV62XKTC.js +1 -0
- package/dist/stage/chunk-YVBA3QW6.js +1 -0
- package/dist/stage/chunk-Z2SY2HOC.js +1 -0
- package/dist/stage/chunk-ZBTCQEBK.js +10 -0
- package/dist/stage/chunk-ZCUFN74D.js +1 -0
- package/dist/stage/chunk-ZHOULXEJ.js +11 -0
- package/dist/stage/chunk-ZTRZIET2.js +1 -0
- package/dist/stage/index.html +11 -0
- package/dist/stage/stage.css +1 -0
- package/dist/stage/stage.js +1 -0
- package/dist/ui/dev/dev-page.d.ts +1 -0
- package/dist/ui/dev/dev-page.js +2248 -0
- package/dist/ui/dev/dev-theme.d.ts +6 -0
- package/dist/ui/dev/dev-theme.js +67 -0
- package/dist/ui/dev/qr-page.d.ts +8 -0
- package/dist/ui/dev/qr-page.js +61 -0
- package/dist/ui/dev/voice-gallery-page.d.ts +1 -0
- package/dist/ui/dev/voice-gallery-page.js +121 -0
- package/dist/ui/dev/voice-scenes.d.ts +21 -0
- package/dist/ui/dev/voice-scenes.js +30 -0
- package/dist/ui/dictation/en-box.d.ts +2 -0
- package/dist/ui/dictation/en-box.js +86 -0
- package/dist/ui/dictation/en-page.d.ts +1 -0
- package/dist/ui/dictation/en-page.js +484 -0
- package/dist/ui/dictation/page.d.ts +1 -0
- package/dist/ui/dictation/page.js +1084 -0
- package/dist/ui/dictation/parent-page.d.ts +1 -0
- package/dist/ui/dictation/parent-page.js +234 -0
- package/dist/ui/dictation/reel-mode.d.ts +1 -0
- package/dist/ui/dictation/reel-mode.js +87 -0
- package/dist/ui/dictation/reel-page.d.ts +1 -0
- package/dist/ui/dictation/reel-page.js +62 -0
- package/dist/ui/dictation/reel.d.ts +163 -0
- package/dist/ui/dictation/reel.js +436 -0
- package/dist/ui/dictation/ui.d.ts +44 -0
- package/dist/ui/dictation/ui.js +80 -0
- package/dist/ui/dictation/unlock.d.ts +7 -0
- package/dist/ui/dictation/unlock.js +16 -0
- package/dist/ui/kid/audio-client.d.ts +11 -0
- package/dist/ui/kid/audio-client.js +74 -0
- package/dist/ui/kid/board-mark-art.d.ts +37 -0
- package/dist/ui/kid/board-mark-art.js +5 -0
- package/dist/ui/kid/board-mark.d.ts +24 -0
- package/dist/ui/kid/board-mark.js +58 -0
- package/dist/ui/kid/kid-log.d.ts +15 -0
- package/dist/ui/kid/kid-log.js +87 -0
- package/dist/ui/kid/kid-nav.d.ts +11 -0
- package/dist/ui/kid/kid-nav.js +22 -0
- package/dist/ui/kid/kid-page.d.ts +9 -0
- package/dist/ui/kid/kid-page.js +3719 -0
- package/dist/ui/kid/letters.d.ts +26 -0
- package/dist/ui/kid/letters.js +51 -0
- package/dist/ui/kid/photo-edit.d.ts +83 -0
- package/dist/ui/kid/photo-edit.js +106 -0
- package/dist/ui/kid/photo-ui.d.ts +23 -0
- package/dist/ui/kid/photo-ui.js +60 -0
- package/dist/ui/kid/reel.d.ts +419 -0
- package/dist/ui/kid/reel.js +648 -0
- package/dist/ui/kid/tianzige.d.ts +8 -0
- package/dist/ui/kid/tianzige.js +45 -0
- package/dist/ui/kid/tutor-face.d.ts +35 -0
- package/dist/ui/kid/tutor-face.js +84 -0
- package/dist/ui/kid/voice-ui.d.ts +70 -0
- package/dist/ui/kid/voice-ui.js +316 -0
- package/dist/ui/kid/voice-view.d.ts +71 -0
- package/dist/ui/kid/voice-view.js +75 -0
- package/dist/ui/kid/word-draw.d.ts +2 -0
- package/dist/ui/kid/word-draw.js +107 -0
- package/dist/ui/kid/word-emoji.d.ts +10 -0
- package/dist/ui/kid/word-emoji.js +66 -0
- package/dist/ui/kid/word-layout.d.ts +25 -0
- package/dist/ui/kid/word-layout.js +29 -0
- package/dist/ui/parent/parent-home-page.d.ts +1 -0
- package/dist/ui/parent/parent-home-page.js +414 -0
- package/dist/ui/parent/parent-page.d.ts +2 -0
- package/dist/ui/parent/parent-page.js +507 -0
- package/dist/ui/shared/brand.d.ts +36 -0
- package/dist/ui/shared/brand.js +51 -0
- package/dist/ui/shared/favicon.d.ts +12 -0
- package/dist/ui/shared/favicon.js +96 -0
- package/dist/ui/shared/icon.d.ts +9 -0
- package/dist/ui/shared/icon.js +35 -0
- package/dist/ui/shared/inline-lib.d.ts +1 -0
- package/dist/ui/shared/inline-lib.js +28 -0
- package/dist/ui/shared/logo.d.ts +31 -0
- package/dist/ui/shared/logo.js +43 -0
- package/dist/ui/shared/page-dom.d.ts +12 -0
- package/dist/ui/shared/page-dom.js +36 -0
- package/dist/ui/shared/png.d.ts +1 -0
- package/dist/ui/shared/png.js +45 -0
- package/dist/ui/shared/qr-svg.d.ts +3 -0
- package/dist/ui/shared/qr-svg.js +32 -0
- package/dist/ui/shared/qr.d.ts +14 -0
- package/dist/ui/shared/qr.js +281 -0
- package/dist/ui/shared/reel-dock.d.ts +22 -0
- package/dist/ui/shared/reel-dock.js +365 -0
- package/dist/ui/shared/tutor-color.d.ts +15 -0
- package/dist/ui/shared/tutor-color.js +47 -0
- package/dist/ui/talk/page.d.ts +6 -0
- package/dist/ui/talk/page.js +294 -0
- package/grades/grade-2/README.md +11 -0
- package/grades/grade-2/VALIDATION.md +41 -0
- package/grades/grade-2/agents/chinese-tutor/activities//344/275/240/350/257/264/346/210/221/347/224/273.md +157 -0
- 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
- 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
- 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
- package/grades/grade-2/agents/chinese-tutor/activities//345/206/231/350/257/235.md +64 -0
- package/grades/grade-2/agents/chinese-tutor/activities//345/206/231/350/257/235./344/276/213/345/255/220.md +31 -0
- package/grades/grade-2/agents/chinese-tutor/activities//345/220/254/345/206/231.md +48 -0
- package/grades/grade-2/agents/chinese-tutor/activities//345/244/215/344/271/240.md +79 -0
- package/grades/grade-2/agents/chinese-tutor/activities//345/244/215/344/271/240./344/276/213/345/255/220.md +35 -0
- package/grades/grade-2/agents/chinese-tutor/activities//345/260/217/350/257/276/345/240/202.md +53 -0
- package/grades/grade-2/agents/chinese-tutor/activities//346/211/271/346/224/271.md +81 -0
- package/grades/grade-2/agents/chinese-tutor/activities//346/211/271/346/224/271./344/276/213/345/255/220.md +35 -0
- package/grades/grade-2/agents/chinese-tutor/activities//347/234/213/345/233/276/350/257/264/350/257/235.md +94 -0
- 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
- package/grades/grade-2/agents/chinese-tutor/activities//351/242/204/344/271/240.md +82 -0
- package/grades/grade-2/agents/chinese-tutor/activities//351/242/204/344/271/240./344/276/213/345/255/220.md +35 -0
- package/grades/grade-2/agents/chinese-tutor.md +59 -0
- package/grades/grade-2/agents/english-tutor/activities//345/217/243/350/257/255/350/257/276.md +149 -0
- 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
- package/grades/grade-2/agents/english-tutor/activities//345/220/254/345/206/231.md +47 -0
- package/grades/grade-2/agents/english-tutor/activities//345/244/215/344/271/240.md +78 -0
- package/grades/grade-2/agents/english-tutor/activities//345/244/215/344/271/240./344/276/213/345/255/220.md +35 -0
- package/grades/grade-2/agents/english-tutor/activities//345/260/217/350/257/276/345/240/202.md +53 -0
- package/grades/grade-2/agents/english-tutor/activities//346/211/271/346/224/271.md +80 -0
- package/grades/grade-2/agents/english-tutor/activities//346/211/271/346/224/271./344/276/213/345/255/220.md +35 -0
- package/grades/grade-2/agents/english-tutor/activities//351/242/204/344/271/240.md +86 -0
- package/grades/grade-2/agents/english-tutor/activities//351/242/204/344/271/240./344/276/213/345/255/220.md +35 -0
- package/grades/grade-2/agents/english-tutor.md +57 -0
- package/grades/grade-2/agents/math-tutor/activities//345/244/215/344/271/240.md +78 -0
- package/grades/grade-2/agents/math-tutor/activities//345/244/215/344/271/240./344/276/213/345/255/220.md +35 -0
- package/grades/grade-2/agents/math-tutor/activities//345/260/217/350/257/276/345/240/202.md +56 -0
- 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
- package/grades/grade-2/agents/math-tutor/activities//346/211/271/346/224/271.md +80 -0
- package/grades/grade-2/agents/math-tutor/activities//346/211/271/346/224/271./344/276/213/345/255/220.md +35 -0
- package/grades/grade-2/agents/math-tutor/activities//351/242/204/344/271/240.md +81 -0
- package/grades/grade-2/agents/math-tutor/activities//351/242/204/344/271/240./344/276/213/345/255/220.md +35 -0
- package/grades/grade-2/agents/math-tutor.md +51 -0
- package/grades/grade-2/examples/2026-10-27-pingjunfen/audio/index.json +44 -0
- package/grades/grade-2/examples/2026-10-27-pingjunfen/audio/step-1.mp3 +0 -0
- package/grades/grade-2/examples/2026-10-27-pingjunfen/audio/step-2.mp3 +0 -0
- package/grades/grade-2/examples/2026-10-27-pingjunfen/audio/step-3.mp3 +0 -0
- package/grades/grade-2/examples/2026-10-27-pingjunfen/audio/step-4.mp3 +0 -0
- package/grades/grade-2/examples/2026-10-27-pingjunfen/audio/step-5.mp3 +0 -0
- package/grades/grade-2/examples/2026-10-27-pingjunfen/bake.json +1 -0
- package/grades/grade-2/examples/2026-10-27-pingjunfen/manifest.json +63 -0
- package/grades/grade-2/examples/2026-10-27-pingjunfen/scene.json +247 -0
- package/grades/grade-2/examples/2026-10-27-pingjunfen.md +40 -0
- package/grades/grade-2/examples/2026-10-27-pingjunfen.ts +26 -0
- package/grades/grade-2/examples//345/271/263/345/235/207/345/210/206./344/276/213/345/255/220.md +24 -0
- package/grades/grade-2/examples//346/225/260/345/255/246/345/271/263/345/235/207/345/210/206.md +42 -0
- package/grades/grade-2/validation/2026-10-27.json +4410 -0
- package/package.json +32 -12
- package/skills/chalk-cli/SKILL.md +62 -0
- package/skills/chalk-scene/SKILL.md +91 -0
- package/skills/chalk-teaching/SKILL.md +82 -0
- 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
- package/skills/chalk-teaching/models//345/207/221/345/215/201.md +7 -0
- package/skills/chalk-teaching/models//345/221/250/346/234/237/350/247/204/345/276/213.md +6 -0
- package/skills/chalk-teaching/models//345/256/236/347/211/251/345/233/276-/345/242/236/345/207/217.md +6 -0
- 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
- 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
- package/skills/chalk-teaching/models//345/260/217/346/243/222/350/277/233/344/275/215/345/212/240.md +7 -0
- package/skills/chalk-teaching/models//345/260/217/346/243/222/351/200/200/344/275/215/345/207/217.md +6 -0
- package/skills/chalk-teaching/models//346/216/222/351/230/237/347/202/271/351/230/265.md +7 -0
- package/skills/chalk-teaching/models//346/227/266/351/227/264/346/225/260/350/275/264.md +6 -0
- package/skills/chalk-teaching/models//346/245/274/345/261/202/351/227/264/351/232/224/345/233/276.md +7 -0
- package/skills/chalk-teaching/models//347/240/264/345/215/201.md +7 -0
- package/skills/chalk-teaching/models//347/253/226/345/274/217/351/200/200/344/275/215.md +6 -0
- package/skills/chalk-teaching/models//347/272/277/346/256/265/345/233/276.md +7 -0
- package/skills/chalk-teaching/models-index.md +24 -0
- 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
- package/skills/chalk-teaching/references//350/257/264/346/230/216/346/226/207/344/273/266.md +102 -0
- package/skills/chalk-verify/SKILL.md +57 -0
- package/skills/chalk-verify/references//350/257/204/345/210/244/346/240/207/345/207/206.md +69 -0
- package/skills/cotutor-analyze/SKILL.md +106 -0
- package/skills/cotutor-analyze/references//345/221/275/344/273/244/344/270/216/346/226/207/344/273/266.md +31 -0
- package/skills/cotutor-board/SKILL.md +373 -0
- package/skills/cotutor-board/references/README.md +38 -0
- package/skills/cotutor-board/references/canvas.md +68 -0
- package/skills/cotutor-board/references/choice.md +55 -0
- package/skills/cotutor-board/references/code.md +46 -0
- package/skills/cotutor-board/references/image.md +52 -0
- package/skills/cotutor-board/references/lecture.md +69 -0
- package/skills/cotutor-board/references/paint.md +77 -0
- package/skills/cotutor-board/references/photo.md +61 -0
- package/skills/cotutor-board/references/read.md +51 -0
- package/skills/cotutor-board/references/text.md +69 -0
- package/skills/cotutor-board/references/tianzige.md +78 -0
- package/skills/cotutor-board/references/word.md +91 -0
- package/skills/cotutor-home/SKILL.md +169 -0
- package/skills/cotutor-home/references/dictation.md +97 -0
- package/skills/cotutor-home/references/tutor.md +148 -0
- package/skills/cotutor-home/references//345/221/275/344/273/244.md +21 -0
- package/skills/cotutor-home/references//351/246/226/351/241/265/350/257/255/346/263/225.md +142 -0
- package/skills/cotutor-tune/SKILL.md +147 -0
- package/skills/cotutor-tune/references//345/255/227/346/256/265.md +50 -0
- package/skills/cotutor-tutor/SKILL.md +261 -0
- package/skills/cotutor-tutor/references//344/270/212/344/270/213/346/226/207/345/214/205.md +78 -0
- package/themes/default/kid.css +86 -0
- package/themes/default/theme.json +26 -0
- package/agents/chinese-teacher.md +0 -19
- package/agents/homework-aide.md +0 -17
- package/agents/math-teacher.md +0 -19
- package/agents/planner.md +0 -18
- package/agents/reading-teacher.md +0 -19
- package/dist/cli/doctor.d.ts +0 -19
- package/dist/cli/doctor.js +0 -190
- package/dist/cli/init.js +0 -114
- package/dist/cli/main.js +0 -123
- package/dist/cli/serve.d.ts +0 -19
- package/dist/cli/serve.js +0 -22
- package/dist/cli/skeleton.d.ts +0 -21
- package/dist/cli/skeleton.js +0 -82
- package/dist/cli/workspace.d.ts +0 -61
- package/dist/lib/agent-file.d.ts +0 -10
- package/dist/lib/agent-file.js +0 -16
- package/dist/lib/context-pack.js +0 -46
- package/dist/lib/conversation.d.ts +0 -28
- package/dist/lib/conversation.js +0 -44
- package/dist/lib/kid-view.d.ts +0 -26
- package/dist/lib/kid-view.js +0 -38
- package/dist/lib/ledger.d.ts +0 -21
- package/dist/lib/sections.d.ts +0 -12
- package/dist/lib/sections.js +0 -151
- package/dist/lib/transcript.d.ts +0 -36
- package/dist/lib/transcript.js +0 -95
- package/dist/server/app.d.ts +0 -13
- package/dist/server/app.js +0 -45
- /package/dist/{cli → app/cli}/main.d.ts +0 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 听写卡(kind 名 dictation,只用在首页):家长写一串词,孩子在首页点开,老师一个一个念、孩子在田字格里写,写完自己对。
|
|
3
|
+
* 英文单词也行:词都是英文单词时 props.lang = 'en',孩子在四线三格里写整个单词。
|
|
4
|
+
* 标签修饰 = 念的老师(cotutor.json 的键,用他的音色;不写用语文老师或第一位配了音色的);正文一行一个词,词后面空一格可以跟「怎么念」。
|
|
5
|
+
* 英文单词前面可以配一个 emoji:只在孩子写完对一对时出,写的时候看不到。
|
|
6
|
+
* 词就是答案:strip 只留几个词,孩子端首页 JSON 里没有字;听写页写完交了才拿到(src/app/dictation/route.ts)。
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import { HAN } from "./tianzige.js";
|
|
10
|
+
import { bodyLines } from "./kind.js";
|
|
11
|
+
/** 一个词最多几个字(一个字一个田字格,同田字格卡) */
|
|
12
|
+
export const DICTATION_WORD_MAX = 4;
|
|
13
|
+
/** 英文单词最多几个字母(一个单词一个四线三格) */
|
|
14
|
+
export const DICTATION_EN_MAX = 20;
|
|
15
|
+
/** 英文单词:字母开头,可以带连字符与撇号(ice-cream、don't);不带空格,一行一个单词 */
|
|
16
|
+
export const EN_WORD_RE = /^[A-Za-z][A-Za-z'-]*$/;
|
|
17
|
+
/** 能不能听写、是哪种:一到四个汉字 = zh;一个英文单词(≤ 20 个字母)= en;都不是 null */
|
|
18
|
+
export function dictationWordLang(text) {
|
|
19
|
+
const cs = Array.from(text);
|
|
20
|
+
if (cs.length && cs.length <= DICTATION_WORD_MAX && cs.every((c) => HAN.test(c)))
|
|
21
|
+
return 'zh';
|
|
22
|
+
if (EN_WORD_RE.test(text) && text.length <= DICTATION_EN_MAX)
|
|
23
|
+
return 'en';
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
/** 一张卡最多几个词 */
|
|
27
|
+
export const DICTATION_WORDS_MAX = 20;
|
|
28
|
+
/** 念法最多几个字 */
|
|
29
|
+
export const DICTATION_SAY_MAX = 40;
|
|
30
|
+
const NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
31
|
+
/** 一个 emoji:图形字符开头,后面只跟修饰符、连接符(👨👩👧、👍🏽、🇨🇳) */
|
|
32
|
+
const EMOJI_RE = /^(?:\p{Extended_Pictographic}|\p{Regional_Indicator})(?:\p{Extended_Pictographic}|\p{Regional_Indicator}|\p{Emoji_Modifier}|\u200d|\ufe0f)*$/u;
|
|
33
|
+
/** 是一个 emoji 就回它(去掉两头空白),不是 undefined;英文单词配的图 */
|
|
34
|
+
export function dictationEmoji(v) {
|
|
35
|
+
const t = typeof v === 'string' ? v.trim() : '';
|
|
36
|
+
return t && t.length <= 16 && EMOJI_RE.test(t) ? t : undefined;
|
|
37
|
+
}
|
|
38
|
+
const LIST_PREFIX = /^(?:[-*+]|\d+[.)、])\s*/;
|
|
39
|
+
export const DictationWordSchema = z.object({
|
|
40
|
+
/** 要写的字,1–4 个汉字 */
|
|
41
|
+
chars: z.string().min(1),
|
|
42
|
+
/** 老师怎么念(「鼓励,老师鼓励我的鼓励」);没写就念词本身 */
|
|
43
|
+
say: z.string().min(1).optional(),
|
|
44
|
+
/** 英文单词配的 emoji(能画出来的东西才有);只在对一对时出 */
|
|
45
|
+
emoji: z.string().min(1).max(16).optional(),
|
|
46
|
+
});
|
|
47
|
+
export const DictationPropsSchema = z.object({
|
|
48
|
+
/** 念的老师(cotutor.json 的键) */
|
|
49
|
+
tutor: z.string().regex(NAME_RE).optional(),
|
|
50
|
+
/** 英文单词听写(词都是英文单词);汉字的不写 */
|
|
51
|
+
lang: z.literal('en').optional(),
|
|
52
|
+
/** 词;孩子端剥成空的 */
|
|
53
|
+
words: z.array(DictationWordSchema).max(DICTATION_WORDS_MAX),
|
|
54
|
+
/** 几个词(strip 时补,孩子端首页卡上显示) */
|
|
55
|
+
count: z.number().int().nonnegative().optional(),
|
|
56
|
+
});
|
|
57
|
+
export const dictation = {
|
|
58
|
+
name: 'dictation',
|
|
59
|
+
where: ['home'],
|
|
60
|
+
props: DictationPropsSchema,
|
|
61
|
+
parse(body, mods) {
|
|
62
|
+
const who = mods[0];
|
|
63
|
+
if (who !== undefined && !NAME_RE.test(who))
|
|
64
|
+
throw new Error(`「${who}」不像老师的键(cotutor.json tutors 里的英文名)`);
|
|
65
|
+
if (mods.length > 1)
|
|
66
|
+
throw new Error('标签后面只写一位老师');
|
|
67
|
+
const words = [];
|
|
68
|
+
for (const raw of bodyLines(body)) {
|
|
69
|
+
let line = raw.replace(LIST_PREFIX, '');
|
|
70
|
+
// 前面可以配一个 emoji(同单词卡的「🍎 apple」)
|
|
71
|
+
const lead = /^(\S+)\s+(.+)$/.exec(line);
|
|
72
|
+
const emoji = lead ? dictationEmoji(lead[1]) : undefined;
|
|
73
|
+
if (emoji && lead)
|
|
74
|
+
line = lead[2];
|
|
75
|
+
const m = /^(\S+)(?:\s+(.+))?$/.exec(line);
|
|
76
|
+
if (!m)
|
|
77
|
+
continue;
|
|
78
|
+
const lang = dictationWordLang(m[1]);
|
|
79
|
+
if (!lang) {
|
|
80
|
+
const chars = Array.from(m[1]);
|
|
81
|
+
if (/^[A-Za-z]/.test(m[1]))
|
|
82
|
+
throw new Error(`「${m[1]}」不像一个英文单词(只要字母,最多 ${DICTATION_EN_MAX} 个;一行一个单词,念法空一格写在后面)`);
|
|
83
|
+
const bad = chars.find((c) => !HAN.test(c));
|
|
84
|
+
if (bad)
|
|
85
|
+
throw new Error(`「${m[1]}」里的「${bad}」不是汉字;一行一个词,念法空一格写在后面`);
|
|
86
|
+
throw new Error(`「${m[1]}」超过 ${DICTATION_WORD_MAX} 个字,拆开写`);
|
|
87
|
+
}
|
|
88
|
+
if (words.length && (dictationWordLang(words[0].chars) ?? 'zh') !== lang)
|
|
89
|
+
throw new Error(`「${m[1]}」:一张听写卡只写一种,汉字的词和英文单词分两张`);
|
|
90
|
+
const say = m[2]?.trim();
|
|
91
|
+
if (say && Array.from(say).length > DICTATION_SAY_MAX)
|
|
92
|
+
throw new Error(`「${m[1]}」的念法超过 ${DICTATION_SAY_MAX} 个字`);
|
|
93
|
+
words.push({ chars: m[1], ...(say ? { say } : {}), ...(emoji ? { emoji } : {}) });
|
|
94
|
+
}
|
|
95
|
+
if (!words.length)
|
|
96
|
+
throw new Error('要听写的词呢(一行一个)');
|
|
97
|
+
if (words.length > DICTATION_WORDS_MAX)
|
|
98
|
+
throw new Error(`一张卡最多 ${DICTATION_WORDS_MAX} 个词(给了 ${words.length} 个),拆成两张`);
|
|
99
|
+
const en = dictationWordLang(words[0].chars) === 'en';
|
|
100
|
+
return { ...(who ? { tutor: who } : {}), ...(en ? { lang: 'en' } : {}), words };
|
|
101
|
+
},
|
|
102
|
+
strip(p) {
|
|
103
|
+
return { ...(p.tutor ? { tutor: p.tutor } : {}), ...(p.lang ? { lang: p.lang } : {}), words: [], count: p.count ?? p.words.length };
|
|
104
|
+
},
|
|
105
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type CardPlace } from './index.ts';
|
|
2
|
+
/** 本包自带的卡协议目录(仓库检出与 npm 安装都在包根 cards/) */
|
|
3
|
+
export declare const PACKAGE_CARDS_DIR: string;
|
|
4
|
+
export interface CardDoc {
|
|
5
|
+
kind: string;
|
|
6
|
+
/** 整份 card.md */
|
|
7
|
+
md: string;
|
|
8
|
+
/** 各栏目正文(按 ## 标题切;没有的栏目是空串) */
|
|
9
|
+
sections: Record<string, string>;
|
|
10
|
+
/** 标题行后面那句(「text — 一段字」) */
|
|
11
|
+
headline: string;
|
|
12
|
+
}
|
|
13
|
+
/** md 按 `## ` 切栏目;`# ` 标题行单独取 */
|
|
14
|
+
export declare function splitSections(md: string): {
|
|
15
|
+
headline: string;
|
|
16
|
+
sections: Record<string, string>;
|
|
17
|
+
};
|
|
18
|
+
export declare function readCardDoc(kind: string, dir?: string): CardDoc;
|
|
19
|
+
/** 能用在某处的种类的协议(按注册表的顺序);缺省板书——cotutor-board 技能只列这些;给了 only 就只要这几种(按老师裁,boardGuideFor) */
|
|
20
|
+
export declare function cardDocs(dir?: string, place?: CardPlace, only?: readonly string[]): CardDoc[];
|
|
21
|
+
/** 板书写法的手写部分(开头的规矩、一节的例子、作业照片),人改的就是这一篇;`{{卡的种类}}` 那一行由下面拼的各种卡替换 */
|
|
22
|
+
export declare const BOARD_GUIDE_SOURCE = "\u677F\u4E66\u600E\u4E48\u5199.md";
|
|
23
|
+
/**
|
|
24
|
+
* 给老师看的语法表(SKILL.md 的正文):cards/板书怎么写.md(剥掉给人看的注释,按卡裁段落)+ 各 card.md 的「是什么 / 写法 / 例子」。
|
|
25
|
+
* kinds 不给 = 板书的全部种类(出厂的 SKILL.md);给了就只拼这几种(按老师裁,boardGuideFor)。
|
|
26
|
+
*/
|
|
27
|
+
export declare function boardSyntaxDoc(dir?: string, kinds?: readonly string[]): string;
|
|
28
|
+
/** 板书写法以外多带的几种卡(activity 要用、老师的清单里没有的),同板书写法里那一段的样子;递给老师前剥掉给人看的注释 */
|
|
29
|
+
export declare function cardGuidesFor(kinds: readonly string[], dir?: string): string;
|
|
30
|
+
/** 按老师裁的板书写法(递给老师的正文,同 boardGuideBody(SKILL.md) 的形状:没有 frontmatter、没有给人看的注释) */
|
|
31
|
+
export declare function boardGuideFor(kinds: readonly string[], dir?: string): string;
|
|
32
|
+
/** references/README.md:一行一种——名字、一句是什么、何时用;老师按需 @ 单张 */
|
|
33
|
+
export declare function cardsIndexDoc(dir?: string): string;
|
|
34
|
+
/** 技能名;目录 .agents/skills/cotutor-board/ */
|
|
35
|
+
export declare const BOARD_SKILL = "cotutor-board";
|
|
36
|
+
/** SKILL.md:frontmatter(name / description)+ 语法表;description 列出卡的种类,让模型不读正文也知道有哪几种 */
|
|
37
|
+
export declare function boardSkillDoc(dir?: string): string;
|
|
38
|
+
/** 技能目录的全部文件(相对技能根):SKILL.md + references/README.md + references/<kind>.md;scripts/gen-skills.ts 写进包根 skills/cotutor-board/,tests/skills.test.ts 断言入库的和它一致 */
|
|
39
|
+
export declare function boardSkillFiles(dir?: string): Record<string, string>;
|
|
40
|
+
/** 各种卡的结构样式(cards/<kind>/card.css)拼成一段,放在主题 css 前面(主题能盖) */
|
|
41
|
+
export declare function cardsCss(dir?: string): string;
|
|
42
|
+
/** 例子即测试用:md 里每个围栏 + 它前面的 expect 注释 */
|
|
43
|
+
export declare function docExamples(md: string): {
|
|
44
|
+
tag: string;
|
|
45
|
+
body: string;
|
|
46
|
+
expect: Record<string, unknown> | null;
|
|
47
|
+
}[];
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 卡的协议文件:每种能力型卡在包根 cards/<kind>/ 下有 card.md(协议:是什么 / 何时用 / 写法 / 例子 / 反例 /
|
|
3
|
+
* 孩子看到什么 / 你会收回什么 / 状态的形状)与 card.css(这种卡的结构样式,只用主题变量)。
|
|
4
|
+
* md 是可以单独 @ 的文件:init / upgrade 出厂成 workspace 里的**一个技能** .agents/skills/cotutor-board/:SKILL.md = 语法表(frontmatter + 各 md 的「是什么 / 写法 / 例子」拼),references/<kind>.md 逐张协议,
|
|
5
|
+
* references/README.md 索引;老师按需 @ 单张。写盘的在 app/cli/skills.ts `writeBoardSkill`。
|
|
6
|
+
* 例子即测试:tests/cards-doc.test.ts 把每个 card.md 里的围栏喂 parseCard,`<!-- expect {…} -->` 注释是期望。
|
|
7
|
+
*/
|
|
8
|
+
import { readFileSync } from 'node:fs';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
import { CARD_KINDS, kindsFor } from "./index.js";
|
|
12
|
+
import { stripHumanNotes } from "../../shared/human-notes.js";
|
|
13
|
+
import { applyCardGuards } from "../card-guards.js";
|
|
14
|
+
/** 本包自带的卡协议目录(仓库检出与 npm 安装都在包根 cards/) */
|
|
15
|
+
export const PACKAGE_CARDS_DIR = fileURLToPath(new URL('../../../cards/', import.meta.url));
|
|
16
|
+
/** md 按 `## ` 切栏目;`# ` 标题行单独取 */
|
|
17
|
+
export function splitSections(md) {
|
|
18
|
+
const lines = md.split('\n');
|
|
19
|
+
// 标题行 = 第一个 ## 之前的那行 `# …`;栏目里的 `# 认边`(例子围栏里的)照收
|
|
20
|
+
let headline = '';
|
|
21
|
+
const sections = {};
|
|
22
|
+
let cur = null;
|
|
23
|
+
const buf = [];
|
|
24
|
+
const flush = () => {
|
|
25
|
+
if (cur !== null)
|
|
26
|
+
sections[cur] = buf.join('\n').trim();
|
|
27
|
+
buf.length = 0;
|
|
28
|
+
};
|
|
29
|
+
for (const l of lines) {
|
|
30
|
+
if (l.startsWith('## ')) {
|
|
31
|
+
flush();
|
|
32
|
+
cur = l.slice(3).trim();
|
|
33
|
+
}
|
|
34
|
+
else if (cur === null) {
|
|
35
|
+
if (!headline && l.startsWith('# '))
|
|
36
|
+
headline = l.slice(2).trim();
|
|
37
|
+
}
|
|
38
|
+
else
|
|
39
|
+
buf.push(l);
|
|
40
|
+
}
|
|
41
|
+
flush();
|
|
42
|
+
return { headline, sections };
|
|
43
|
+
}
|
|
44
|
+
export function readCardDoc(kind, dir = PACKAGE_CARDS_DIR) {
|
|
45
|
+
const md = readFileSync(join(dir, kind, 'card.md'), 'utf8');
|
|
46
|
+
const { headline, sections } = splitSections(md);
|
|
47
|
+
return { kind, md, sections, headline };
|
|
48
|
+
}
|
|
49
|
+
/** 能用在某处的种类的协议(按注册表的顺序);缺省板书——cotutor-board 技能只列这些;给了 only 就只要这几种(按老师裁,boardGuideFor) */
|
|
50
|
+
export function cardDocs(dir = PACKAGE_CARDS_DIR, place = 'board', only) {
|
|
51
|
+
return kindsFor(place)
|
|
52
|
+
.filter((k) => !only || only.includes(k.name))
|
|
53
|
+
.map((k) => readCardDoc(k.name, dir));
|
|
54
|
+
}
|
|
55
|
+
/** 例子里的 `<!-- expect {…} -->` 注释:给老师看的版本要去掉 */
|
|
56
|
+
const EXPECT_RE = /^\s*<!--\s*expect\b.*?-->\s*\n?/gm;
|
|
57
|
+
/** 板书写法的手写部分(开头的规矩、一节的例子、作业照片),人改的就是这一篇;`{{卡的种类}}` 那一行由下面拼的各种卡替换 */
|
|
58
|
+
export const BOARD_GUIDE_SOURCE = '板书怎么写.md';
|
|
59
|
+
const KINDS_SLOT = /^\{\{卡的种类\}\}$/m;
|
|
60
|
+
/**
|
|
61
|
+
* 给老师看的语法表(SKILL.md 的正文):cards/板书怎么写.md(剥掉给人看的注释,按卡裁段落)+ 各 card.md 的「是什么 / 写法 / 例子」。
|
|
62
|
+
* kinds 不给 = 板书的全部种类(出厂的 SKILL.md);给了就只拼这几种(按老师裁,boardGuideFor)。
|
|
63
|
+
*/
|
|
64
|
+
export function boardSyntaxDoc(dir = PACKAGE_CARDS_DIR, kinds) {
|
|
65
|
+
const all = kindsFor('board').map((k) => k.name);
|
|
66
|
+
const want = kinds ? all.filter((k) => kinds.includes(k)) : all;
|
|
67
|
+
const docs = cardDocs(dir, 'board', want).map(cardGuide).join('\n\n');
|
|
68
|
+
const guide = applyCardGuards(stripHumanNotes(readFileSync(join(dir, BOARD_GUIDE_SOURCE), 'utf8')), want);
|
|
69
|
+
if (!KINDS_SLOT.test(guide))
|
|
70
|
+
throw new Error(`cards/${BOARD_GUIDE_SOURCE} 里没有「{{卡的种类}}」那一行`);
|
|
71
|
+
return `${guide.replace(KINDS_SLOT, () => docs)}\n`;
|
|
72
|
+
}
|
|
73
|
+
/** 一种卡给老师看的那段:标题 + 是什么 / 写法 / 例子(去掉 expect);板书写法里「卡的种类」一节就是一张张拼的它 */
|
|
74
|
+
function cardGuide(d) {
|
|
75
|
+
const parts = [`### ${d.headline}`, d.sections['是什么'], d.sections['写法'], d.sections['例子']?.replace(EXPECT_RE, '')].filter((x) => x && x.trim());
|
|
76
|
+
return parts.join('\n\n').trim();
|
|
77
|
+
}
|
|
78
|
+
/** 板书写法以外多带的几种卡(activity 要用、老师的清单里没有的),同板书写法里那一段的样子;递给老师前剥掉给人看的注释 */
|
|
79
|
+
export function cardGuidesFor(kinds, dir = PACKAGE_CARDS_DIR) {
|
|
80
|
+
return stripHumanNotes(cardDocs(dir, 'board', kinds).map(cardGuide).join('\n\n'));
|
|
81
|
+
}
|
|
82
|
+
/** 按老师裁的板书写法(递给老师的正文,同 boardGuideBody(SKILL.md) 的形状:没有 frontmatter、没有给人看的注释) */
|
|
83
|
+
export function boardGuideFor(kinds, dir = PACKAGE_CARDS_DIR) {
|
|
84
|
+
return stripHumanNotes(boardSyntaxDoc(dir, kinds));
|
|
85
|
+
}
|
|
86
|
+
/** references/README.md:一行一种——名字、一句是什么、何时用;老师按需 @ 单张 */
|
|
87
|
+
export function cardsIndexDoc(dir = PACKAGE_CARDS_DIR) {
|
|
88
|
+
const rows = cardDocs(dir).map((d) => {
|
|
89
|
+
const what = (d.sections['是什么'] ?? '').split('\n').find((l) => l.trim()) ?? '';
|
|
90
|
+
const when = (d.sections['什么时候用 / 别用'] ?? '').split('\n').filter((l) => l.startsWith('- 用:')).map((l) => `\n - 用在:${l.slice(4).trim()}`).join('');
|
|
91
|
+
return `- **${d.kind}**(${d.kind}.md)—— ${what}${when}`;
|
|
92
|
+
});
|
|
93
|
+
return `# 卡的种类(索引)
|
|
94
|
+
|
|
95
|
+
每种卡一份协议:是什么、什么时候用 / 别用、写法、例子、反例、孩子看到什么、你会收回什么、状态的形状。讲解前只读需要的那一两张;总表在 ../SKILL.md。机器文件,init / upgrade 刷新。
|
|
96
|
+
|
|
97
|
+
${rows.join('\n')}
|
|
98
|
+
`;
|
|
99
|
+
}
|
|
100
|
+
/** 技能名;目录 .agents/skills/cotutor-board/ */
|
|
101
|
+
export const BOARD_SKILL = 'cotutor-board';
|
|
102
|
+
/** SKILL.md:frontmatter(name / description)+ 语法表;description 列出卡的种类,让模型不读正文也知道有哪几种 */
|
|
103
|
+
export function boardSkillDoc(dir = PACKAGE_CARDS_DIR) {
|
|
104
|
+
const kinds = kindsFor('board').map((k) => k.name).join(' / ');
|
|
105
|
+
const description = `cotutor 的板书怎么写:讲稿一行一句,围栏是卡(种类:${kinds})。应用已经递给老师,老师不用读;家长查阅用。每种卡完整的协议在 references/<种类>.md。机器生成,源在 cotutor 仓的 cards/,别在这里改。`;
|
|
106
|
+
return `---\nname: ${BOARD_SKILL}\ndescription: ${description}\n---\n\n${boardSyntaxDoc(dir)}`;
|
|
107
|
+
}
|
|
108
|
+
/** 技能目录的全部文件(相对技能根):SKILL.md + references/README.md + references/<kind>.md;scripts/gen-skills.ts 写进包根 skills/cotutor-board/,tests/skills.test.ts 断言入库的和它一致 */
|
|
109
|
+
export function boardSkillFiles(dir = PACKAGE_CARDS_DIR) {
|
|
110
|
+
const out = { 'SKILL.md': boardSkillDoc(dir), 'references/README.md': cardsIndexDoc(dir) };
|
|
111
|
+
for (const d of cardDocs(dir))
|
|
112
|
+
out[`references/${d.kind}.md`] = d.md;
|
|
113
|
+
return out;
|
|
114
|
+
}
|
|
115
|
+
/** 各种卡的结构样式(cards/<kind>/card.css)拼成一段,放在主题 css 前面(主题能盖) */
|
|
116
|
+
export function cardsCss(dir = PACKAGE_CARDS_DIR) {
|
|
117
|
+
return CARD_KINDS.map((k) => {
|
|
118
|
+
try {
|
|
119
|
+
return `/* ---- ${k.name}(cards/${k.name}/card.css)---- */\n${readFileSync(join(dir, k.name, 'card.css'), 'utf8').trim()}`;
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return '';
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
.filter(Boolean)
|
|
126
|
+
.join('\n\n');
|
|
127
|
+
}
|
|
128
|
+
/** 例子即测试用:md 里每个围栏 + 它前面的 expect 注释 */
|
|
129
|
+
export function docExamples(md) {
|
|
130
|
+
const out = [];
|
|
131
|
+
const lines = md.split('\n');
|
|
132
|
+
let expect = null;
|
|
133
|
+
for (let i = 0; i < lines.length; i++) {
|
|
134
|
+
const l = lines[i];
|
|
135
|
+
const ex = /^<!--\s*expect\s+(\{.*\})\s*-->$/.exec(l.trim());
|
|
136
|
+
if (ex) {
|
|
137
|
+
expect = JSON.parse(ex[1]);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
const open = /^```(.*)$/.exec(l);
|
|
141
|
+
if (open && !l.startsWith('````')) {
|
|
142
|
+
const body = [];
|
|
143
|
+
let j = i + 1;
|
|
144
|
+
for (; j < lines.length && !/^```\s*$/.test(lines[j]); j++)
|
|
145
|
+
body.push(lines[j]);
|
|
146
|
+
out.push({ tag: open[1].trim(), body: body.join('\n'), expect });
|
|
147
|
+
expect = null;
|
|
148
|
+
i = j;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return out;
|
|
152
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 图片卡:第一行是图(workspace 里的相对路径——产物、孩子拍的照片;或 http(s) 地址),后面几行是图注。
|
|
3
|
+
* 路径由 /api/kid/image?p= 供图,只认 workspace 根以内的图片文件;舞台里双指缩放。
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { type CardKind } from './kind.ts';
|
|
7
|
+
export declare const ImagePropsSchema: z.ZodObject<{
|
|
8
|
+
src: z.ZodString;
|
|
9
|
+
caption: z.ZodOptional<z.ZodString>;
|
|
10
|
+
}, z.core.$strip>;
|
|
11
|
+
export type ImageProps = z.infer<typeof ImagePropsSchema>;
|
|
12
|
+
export declare const IMAGE_EXT: RegExp;
|
|
13
|
+
export declare const image: CardKind<ImageProps>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 图片卡:第一行是图(workspace 里的相对路径——产物、孩子拍的照片;或 http(s) 地址),后面几行是图注。
|
|
3
|
+
* 路径由 /api/kid/image?p= 供图,只认 workspace 根以内的图片文件;舞台里双指缩放。
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { bodyLines } from "./kind.js";
|
|
7
|
+
export const ImagePropsSchema = z.object({
|
|
8
|
+
/** 相对 workspace 根的路径,或 http(s):// 地址 */
|
|
9
|
+
src: z.string().min(1),
|
|
10
|
+
caption: z.string().optional(),
|
|
11
|
+
});
|
|
12
|
+
export const IMAGE_EXT = /\.(png|jpe?g|webp|gif|svg)$/i;
|
|
13
|
+
export const image = {
|
|
14
|
+
name: 'image',
|
|
15
|
+
where: ['board', 'home'],
|
|
16
|
+
props: ImagePropsSchema,
|
|
17
|
+
parse(body) {
|
|
18
|
+
const [src, ...rest] = bodyLines(body);
|
|
19
|
+
if (!src)
|
|
20
|
+
throw new Error('第一行要是图片路径或地址');
|
|
21
|
+
if (!/^https?:\/\//.test(src) && !IMAGE_EXT.test(src))
|
|
22
|
+
throw new Error('要是 png / jpg / webp / gif / svg 图片');
|
|
23
|
+
const caption = rest.join('\n');
|
|
24
|
+
return { src, ...(caption ? { caption } : {}) };
|
|
25
|
+
},
|
|
26
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { BoardCard, BoardSection } from '../presentation.ts';
|
|
2
|
+
import type { CardKind, CardPlace } from './kind.ts';
|
|
3
|
+
export { BUNDLE_ID_RE, type CardKind, type CardPlace } from './kind.ts';
|
|
4
|
+
export { text, TEXT_STYLES, type TextProps, type TextStyle } from './text.ts';
|
|
5
|
+
export { read, type ReadProps } from './read.ts';
|
|
6
|
+
export { choice, type ChoiceProps } from './choice.ts';
|
|
7
|
+
export { code, type CodeProps } from './code.ts';
|
|
8
|
+
export { image, IMAGE_EXT, type ImageProps } from './image.ts';
|
|
9
|
+
export { lecture, type LectureProps, type LectureState } from './lecture.ts';
|
|
10
|
+
export { canvas, type CanvasProps, type CanvasState } from './canvas.ts';
|
|
11
|
+
export { paint, PaintPropsSchema, PAINT_PANELS_MAX, type PaintCast, type PaintProps } from './paint.ts';
|
|
12
|
+
export { tianzige, HAN, TIANZIGE_MAX, type TianzigeProps } from './tianzige.ts';
|
|
13
|
+
export { word, wordChunks, WORD_MAX, WORD_MAX_WORDS, WORD_RE, type WordProps } from './word.ts';
|
|
14
|
+
export { tutor, BUTTON_LABEL_MAX, TUTOR_BUTTONS_MAX, TutorButtonSchema, type TutorButton, type TutorProps } from './tutor.ts';
|
|
15
|
+
export { dictation, dictationEmoji, dictationWordLang, DictationPropsSchema, DICTATION_EN_MAX, DICTATION_SAY_MAX, DICTATION_WORD_MAX, DICTATION_WORDS_MAX, EN_WORD_RE, type DictationLang, type DictationProps, type DictationWord } from './dictation.ts';
|
|
16
|
+
/** 全部种类:先板书的十一种(注册表顺序即技能里的顺序),再首页专属的 */
|
|
17
|
+
export declare const CARD_KINDS: readonly CardKind<any>[];
|
|
18
|
+
export declare function cardKind(name: string): CardKind | undefined;
|
|
19
|
+
/** 这种卡能不能用在这里(没写 where 的只板书) */
|
|
20
|
+
export declare function usableIn(kind: Pick<CardKind, 'where'>, place: CardPlace): boolean;
|
|
21
|
+
/** 能用在某处的种类(注册表顺序) */
|
|
22
|
+
export declare function kindsFor(place: CardPlace): readonly CardKind<any>[];
|
|
23
|
+
/**
|
|
24
|
+
* 这位老师的板书写法里讲哪几种卡(cotutor.json tutors.<老师>.cards,《卡片协议.md》「谁拿到哪些卡」):
|
|
25
|
+
* 没写 = null(全部,递出厂的 cotutor-board SKILL.md);写了 = 板书能用的、按注册表顺序,text 总在(写坏的卡退成它)。
|
|
26
|
+
*/
|
|
27
|
+
export declare function tutorCardKinds(cards: readonly string[] | undefined): string[] | null;
|
|
28
|
+
export interface ParsedCard {
|
|
29
|
+
card: BoardCard;
|
|
30
|
+
/** 没解析成时的一句(家长视图转录里显示);孩子端什么也不报 */
|
|
31
|
+
warning?: string;
|
|
32
|
+
/** 没照标签解析成(退成了文字卡 / 代码卡);首页检查据此判「要改」 */
|
|
33
|
+
fallback?: boolean;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 围栏 → 卡。标签第一个词是 kind,其余是修饰;不认识的标签:板书里当代码卡原样显示,首页里退文字卡;
|
|
37
|
+
* 认识但正文解析不出、或这种卡不能用在这里(place)→ 文字卡显示原文 + warning。永不抛错。
|
|
38
|
+
*/
|
|
39
|
+
export declare function parseCard(tag: string, body: string, place?: CardPlace): ParsedCard;
|
|
40
|
+
/** 孩子端的一节:每张卡过本种卡的 strip(答案不下发);不认识的 kind 原样;孩子自己的状态与已生成的资产照给 */
|
|
41
|
+
export declare function stripSecrets(section: BoardSection): BoardSection;
|
|
42
|
+
/** 一张卡的标题(舞台顶栏、给老师的描述里用):文字卡的 title / text,选择题的问题,其余第一段有字的,田字格的字,单词卡的词,听写卡的词表 */
|
|
43
|
+
export declare function cardLabel(card: BoardCard): string;
|
|
44
|
+
/** 这张卡要后台预生成的配音(文件名相对它的资产目录);没有的种类 → [] */
|
|
45
|
+
export declare function cardAssets(card: BoardCard): {
|
|
46
|
+
file: string;
|
|
47
|
+
text: string;
|
|
48
|
+
}[];
|
|
49
|
+
export type CardStateResult = {
|
|
50
|
+
ok: true;
|
|
51
|
+
state: unknown;
|
|
52
|
+
} | {
|
|
53
|
+
ok: false;
|
|
54
|
+
why: string;
|
|
55
|
+
};
|
|
56
|
+
/** 孩子端 PUT 上来的状态过本种卡的契约;这种卡没有状态、或不认识的 kind → 不收 */
|
|
57
|
+
export declare function parseCardState(card: BoardCard, raw: unknown): CardStateResult;
|
|
58
|
+
/**
|
|
59
|
+
* 给老师的一句:「choice「问题」 选了「B …」(答案:「…」)」。props 用索引里的(带答案),状态是孩子的;
|
|
60
|
+
* 没有 describe 的种类把状态原样 JSON。id 由调用方拼在前面(<job>/<n>)。
|
|
61
|
+
*/
|
|
62
|
+
export declare function describeCard(card: BoardCard, state: unknown): string;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 卡的注册表:加一种卡 = 加一个文件 + 这里一行;解析器、语法表、孩子端剥秘密都从这里走。
|
|
3
|
+
* 页面那一半在 kid-page.ts(渲染)与 board/presentation.ts(标注落点),按 kind 名对上。协议文档与结构样式在包根 cards/<kind>/(src/board/cards/docs.ts)。
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { canvas } from "./canvas.js";
|
|
7
|
+
import { choice } from "./choice.js";
|
|
8
|
+
import { code } from "./code.js";
|
|
9
|
+
import { tianzige } from "./tianzige.js";
|
|
10
|
+
import { word } from "./word.js";
|
|
11
|
+
import { image } from "./image.js";
|
|
12
|
+
import { read } from "./read.js";
|
|
13
|
+
import { paint } from "./paint.js";
|
|
14
|
+
import { photo } from "./photo.js";
|
|
15
|
+
import { lecture } from "./lecture.js";
|
|
16
|
+
import { text } from "./text.js";
|
|
17
|
+
import { tutor } from "./tutor.js";
|
|
18
|
+
import { dictation } from "./dictation.js";
|
|
19
|
+
export { BUNDLE_ID_RE } from "./kind.js";
|
|
20
|
+
export { text, TEXT_STYLES } from "./text.js";
|
|
21
|
+
export { read } from "./read.js";
|
|
22
|
+
export { choice } from "./choice.js";
|
|
23
|
+
export { code } from "./code.js";
|
|
24
|
+
export { image, IMAGE_EXT } from "./image.js";
|
|
25
|
+
export { lecture } from "./lecture.js";
|
|
26
|
+
export { canvas } from "./canvas.js";
|
|
27
|
+
export { paint, PaintPropsSchema, PAINT_PANELS_MAX } from "./paint.js";
|
|
28
|
+
export { tianzige, HAN, TIANZIGE_MAX } from "./tianzige.js";
|
|
29
|
+
export { word, wordChunks, WORD_MAX, WORD_MAX_WORDS, WORD_RE } from "./word.js";
|
|
30
|
+
export { tutor, BUTTON_LABEL_MAX, TUTOR_BUTTONS_MAX, TutorButtonSchema } from "./tutor.js";
|
|
31
|
+
export { dictation, dictationEmoji, dictationWordLang, DictationPropsSchema, DICTATION_EN_MAX, DICTATION_SAY_MAX, DICTATION_WORD_MAX, DICTATION_WORDS_MAX, EN_WORD_RE } from "./dictation.js";
|
|
32
|
+
/** 全部种类:先板书的十一种(注册表顺序即技能里的顺序),再首页专属的 */
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
34
|
+
export const CARD_KINDS = [text, read, choice, image, tianzige, word, lecture, canvas, paint, photo, code, tutor, dictation];
|
|
35
|
+
export function cardKind(name) {
|
|
36
|
+
return CARD_KINDS.find((k) => k.name === name);
|
|
37
|
+
}
|
|
38
|
+
/** 这种卡能不能用在这里(没写 where 的只板书) */
|
|
39
|
+
export function usableIn(kind, place) {
|
|
40
|
+
return (kind.where ?? ['board']).includes(place);
|
|
41
|
+
}
|
|
42
|
+
/** 能用在某处的种类(注册表顺序) */
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
|
+
export function kindsFor(place) {
|
|
45
|
+
return CARD_KINDS.filter((k) => usableIn(k, place));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 这位老师的板书写法里讲哪几种卡(cotutor.json tutors.<老师>.cards,《卡片协议.md》「谁拿到哪些卡」):
|
|
49
|
+
* 没写 = null(全部,递出厂的 cotutor-board SKILL.md);写了 = 板书能用的、按注册表顺序,text 总在(写坏的卡退成它)。
|
|
50
|
+
*/
|
|
51
|
+
export function tutorCardKinds(cards) {
|
|
52
|
+
if (!cards)
|
|
53
|
+
return null;
|
|
54
|
+
return kindsFor('board').map((k) => k.name).filter((k) => k === 'text' || cards.includes(k));
|
|
55
|
+
}
|
|
56
|
+
/** 正文是「字」的卡:老师把讲稿的 [词] 标注语法写进这些卡时,把括号剥掉(2026-09-11 真跑:孩子看到了「[直角边]」);choice 的 - [ ] / - [x] 不动 */
|
|
57
|
+
const TEXTUAL = new Set(['text', 'read', 'choice', 'image', 'word', 'paint']);
|
|
58
|
+
const MARK_IN_CARD = /\[([^\[\]\n]+)\]/g;
|
|
59
|
+
function unmark(body) {
|
|
60
|
+
let had = false;
|
|
61
|
+
const out = body.replace(MARK_IN_CARD, (m, inner) => {
|
|
62
|
+
if (/^[ xX]$/.test(inner))
|
|
63
|
+
return m;
|
|
64
|
+
had = true;
|
|
65
|
+
return inner;
|
|
66
|
+
});
|
|
67
|
+
return { body: out, had };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 围栏 → 卡。标签第一个词是 kind,其余是修饰;不认识的标签:板书里当代码卡原样显示,首页里退文字卡;
|
|
71
|
+
* 认识但正文解析不出、或这种卡不能用在这里(place)→ 文字卡显示原文 + warning。永不抛错。
|
|
72
|
+
*/
|
|
73
|
+
export function parseCard(tag, body, place = 'board') {
|
|
74
|
+
const [name, ...mods] = tag.trim().split(/\s+/).filter(Boolean);
|
|
75
|
+
const asText = (why) => ({ card: { kind: 'text', props: { text: body.trim() || name || '…' } }, warning: why, fallback: true });
|
|
76
|
+
if (!name)
|
|
77
|
+
return place === 'board' ? { card: { kind: 'code', props: code.parse(body, []) } } : asText('围栏没写种类');
|
|
78
|
+
const kind = cardKind(name.toLowerCase());
|
|
79
|
+
if (!kind)
|
|
80
|
+
return place === 'board' ? { card: { kind: 'code', props: code.parse(body, [name]) } } : asText(`不认识的卡:${name}`);
|
|
81
|
+
if (!usableIn(kind, place))
|
|
82
|
+
return asText(place === 'board' ? `${name} 是首页的卡,板书里不能用` : `首页放不了 ${name} 卡(它要交给某位老师,只能在板书里)`);
|
|
83
|
+
const um = TEXTUAL.has(kind.name) ? unmark(body) : { body, had: false };
|
|
84
|
+
try {
|
|
85
|
+
const props = kind.props.parse(kind.parse(um.body, mods));
|
|
86
|
+
const notes = [um.had ? `卡里的方括号去掉了:${name} — [词] 标注只写在讲稿句里,不写在卡里` : null, kind.note?.(um.body, props) ?? null].filter((x) => Boolean(x));
|
|
87
|
+
return { card: { kind: kind.name, props }, ...(notes.length ? { warning: notes.join(';') } : {}) };
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
const why = err instanceof z.ZodError ? err.issues.map((i) => `${i.path.join('.')}:${i.message}`).join(';') : err instanceof Error ? err.message : String(err);
|
|
91
|
+
return asText(`卡片没解析成:${name} — ${why}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/** 孩子端的一节:每张卡过本种卡的 strip(答案不下发);不认识的 kind 原样;孩子自己的状态与已生成的资产照给 */
|
|
95
|
+
export function stripSecrets(section) {
|
|
96
|
+
return {
|
|
97
|
+
...section,
|
|
98
|
+
cards: section.cards.map((c) => {
|
|
99
|
+
// 认不出的种类(删掉的卡:场景 10-07、填空 10-22):老对话里存下的退成一段字,只留它的那句,别的字段(答案、题面)不下发
|
|
100
|
+
const k = cardKind(c.kind);
|
|
101
|
+
if (!k)
|
|
102
|
+
return { ...c, kind: 'text', props: { text: typeof c.props.text === 'string' ? c.props.text : cardLabel(c) } };
|
|
103
|
+
return k.strip ? { ...c, props: k.strip(c.props) } : c;
|
|
104
|
+
}),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/** 一张卡的标题(舞台顶栏、给老师的描述里用):文字卡的 title / text,选择题的问题,其余第一段有字的,田字格的字,单词卡的词,听写卡的词表 */
|
|
108
|
+
export function cardLabel(card) {
|
|
109
|
+
const p = card.props;
|
|
110
|
+
const s = (v) => (typeof v === 'string' ? v.trim() : '');
|
|
111
|
+
const first = s(p.title) || s(p.question) || s(p.show) || s(p.text) || s(p.caption) || s(p.prompt) || (Array.isArray(p.segments) ? s(p.segments[0]) : '') || s(p.chars) || s(p.word) || (Array.isArray(p.words) ? p.words.map((w) => s(w?.chars)).filter(Boolean).join('、') : '');
|
|
112
|
+
const cps = Array.from(first.replace(/\s+/g, ' '));
|
|
113
|
+
return cps.length > 40 ? `${cps.slice(0, 40).join('')}…` : cps.join('');
|
|
114
|
+
}
|
|
115
|
+
/** 这张卡要后台预生成的配音(文件名相对它的资产目录);没有的种类 → [] */
|
|
116
|
+
export function cardAssets(card) {
|
|
117
|
+
const k = cardKind(card.kind);
|
|
118
|
+
if (!k?.assets)
|
|
119
|
+
return [];
|
|
120
|
+
const r = k.props.safeParse(card.props);
|
|
121
|
+
return r.success ? k.assets(r.data) : [];
|
|
122
|
+
}
|
|
123
|
+
/** 孩子端 PUT 上来的状态过本种卡的契约;这种卡没有状态、或不认识的 kind → 不收 */
|
|
124
|
+
export function parseCardState(card, raw) {
|
|
125
|
+
const k = cardKind(card.kind);
|
|
126
|
+
if (!k?.state)
|
|
127
|
+
return { ok: false, why: `${card.kind} 卡没有状态` };
|
|
128
|
+
const r = k.state.safeParse(raw);
|
|
129
|
+
if (!r.success)
|
|
130
|
+
return { ok: false, why: r.error.issues.map((i) => `${i.path.join('.')}:${i.message}`).join(';') };
|
|
131
|
+
return { ok: true, state: r.data };
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* 给老师的一句:「choice「问题」 选了「B …」(答案:「…」)」。props 用索引里的(带答案),状态是孩子的;
|
|
135
|
+
* 没有 describe 的种类把状态原样 JSON。id 由调用方拼在前面(<job>/<n>)。
|
|
136
|
+
*/
|
|
137
|
+
export function describeCard(card, state) {
|
|
138
|
+
const k = cardKind(card.kind);
|
|
139
|
+
const head = `${card.kind}「${cardLabel(card)}」`;
|
|
140
|
+
if (!k?.describe || !k.state)
|
|
141
|
+
return `${head} ${JSON.stringify(state)}`;
|
|
142
|
+
const r = k.state.safeParse(state);
|
|
143
|
+
return `${head} ${r.success ? k.describe(card.props, r.data) : JSON.stringify(state)}`;
|
|
144
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 一种卡的服务端定义(见 docs/卡片协议.md):props 契约、围栏正文怎么解析、哪些字段不下发孩子端;给老师看的写法在包根 cards/<kind>/card.md(src/board/cards/docs.ts 读它);
|
|
3
|
+
* 有交互的卡再加 state 契约(孩子在卡上做的事,PUT 进来先过它)与 describe(把 props + state 说成给老师看的一句,进上下文包)。
|
|
4
|
+
* 页面那一半(紧凑态怎么画、舞台里怎么交互、标注落在哪些字上)在 kid-page.ts / board/presentation.ts;两边靠 kind 名对上。
|
|
5
|
+
*/
|
|
6
|
+
import type { z } from 'zod';
|
|
7
|
+
/** 卡用在哪:板书(老师的回复)/ 首页(家长批准的那页) */
|
|
8
|
+
export type CardPlace = 'board' | 'home';
|
|
9
|
+
export interface CardKind<P = Record<string, unknown>, S = unknown> {
|
|
10
|
+
name: string;
|
|
11
|
+
/** 能用在哪;缺省只板书。首页专属的卡(tutor 等)不进 cotutor-board 技能,老师写了退文字卡 */
|
|
12
|
+
where?: readonly CardPlace[];
|
|
13
|
+
props: z.ZodType<P>;
|
|
14
|
+
/** 围栏正文 + 标签后的修饰词 → props;抛错 = 没解析成(退成文字卡显示原文,家长视图报一行) */
|
|
15
|
+
parse(body: string, mods: readonly string[]): P;
|
|
16
|
+
/** 解析成了、但正文有一部分没用上(田字格的拼音对不上字数):给家长视图的一句;没有 / null = 不报 */
|
|
17
|
+
note?(body: string, props: P): string | null;
|
|
18
|
+
/** 剥掉不下发孩子端的字段(答案);没有 = 全给 */
|
|
19
|
+
strip?(props: P): P;
|
|
20
|
+
/** 孩子在卡上做的事的形状;没有 = 这种卡没有状态,PUT 一律 400 */
|
|
21
|
+
state?: z.ZodType<S>;
|
|
22
|
+
/** props + state → 给老师看的一句(不含卡的标题,那句由注册表拼);没有 = 状态原样 JSON */
|
|
23
|
+
describe?(props: P, state: S): string;
|
|
24
|
+
/** 这张卡要在后台预生成的配音资产(点读的段):文件名相对这张卡的资产目录 <日期>.<job>.cards/<n>/,text 是要念的字 */
|
|
25
|
+
assets?(props: P): {
|
|
26
|
+
file: string;
|
|
27
|
+
text: string;
|
|
28
|
+
}[];
|
|
29
|
+
}
|
|
30
|
+
/** 课包 / 视频小课堂的 id(bundles/<id>/、lectures/<id>/):lecture 卡、画板的底、首页的小课堂按钮共用 */
|
|
31
|
+
export declare const BUNDLE_ID_RE: RegExp;
|
|
32
|
+
/** 围栏正文 → 非空行(各自 trim) */
|
|
33
|
+
export declare function bodyLines(body: string): string[];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** 课包 / 视频小课堂的 id(bundles/<id>/、lectures/<id>/):lecture 卡、画板的底、首页的小课堂按钮共用 */
|
|
2
|
+
export const BUNDLE_ID_RE = /^[a-z0-9][a-z0-9-]{0,80}$/;
|
|
3
|
+
/** 围栏正文 → 非空行(各自 trim) */
|
|
4
|
+
export function bodyLines(body) {
|
|
5
|
+
return body
|
|
6
|
+
.split('\n')
|
|
7
|
+
.map((l) => l.trim())
|
|
8
|
+
.filter(Boolean);
|
|
9
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 小课堂卡:老师答孩子时放课里的一段,不另讲一遍。正文第一行「<课包或视频的 id> 0:19-0:30」,第二行可以写一句给孩子的话。
|
|
3
|
+
* 拿现成的课包或视频(家长做的);时间照上下文包 lecture.lines 抄。
|
|
4
|
+
* 课名、真放的起止(对齐到段界,board/lecture.ts lectureRange)、能不能放(ready)、末帧停在 SVG 的哪一刻,都是服务端下发时从课包现算的快照(src/runtime/lecture.ts 的 enrichLectures)。
|
|
5
|
+
* 状态 = 那一段看完没;讲稿 [[play]] 锚到它:念到那句,铺满放那一段(课里原来的声音),放完停在末帧接着念。
|
|
6
|
+
*/
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { type CardKind } from './kind.ts';
|
|
9
|
+
export declare const LecturePropsSchema: z.ZodObject<{
|
|
10
|
+
bundle: z.ZodString;
|
|
11
|
+
from: z.ZodOptional<z.ZodNumber>;
|
|
12
|
+
to: z.ZodOptional<z.ZodNumber>;
|
|
13
|
+
text: z.ZodOptional<z.ZodString>;
|
|
14
|
+
title: z.ZodOptional<z.ZodString>;
|
|
15
|
+
start: z.ZodOptional<z.ZodNumber>;
|
|
16
|
+
end: z.ZodOptional<z.ZodNumber>;
|
|
17
|
+
still: z.ZodOptional<z.ZodNumber>;
|
|
18
|
+
ready: z.ZodOptional<z.ZodBoolean>;
|
|
19
|
+
video: z.ZodOptional<z.ZodBoolean>;
|
|
20
|
+
}, z.core.$strip>;
|
|
21
|
+
export type LectureProps = z.infer<typeof LecturePropsSchema>;
|
|
22
|
+
export declare const LectureStateSchema: z.ZodObject<{
|
|
23
|
+
done: z.ZodBoolean;
|
|
24
|
+
}, z.core.$strip>;
|
|
25
|
+
export type LectureState = z.infer<typeof LectureStateSchema>;
|
|
26
|
+
export declare const lecture: CardKind<LectureProps, LectureState>;
|