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,63 @@
|
|
|
1
|
+
import { type ActivityIssue } from '../../runtime/activity.ts';
|
|
2
|
+
import type { Activity } from '../../schema/index.ts';
|
|
3
|
+
import { type TutorState } from './tutors.ts';
|
|
4
|
+
import { ACTIVITIES_DIR, EXAMPLES_SUFFIX, activityFile, activityRunFor, listActivities, type ActivityRef } from '../../runtime/activities.ts';
|
|
5
|
+
export { ACTIVITIES_DIR, EXAMPLES_SUFFIX, activityFile, activityRunFor, listActivities, type ActivityRef };
|
|
6
|
+
/** 出厂的 activity 与它们的例子文件 */
|
|
7
|
+
export declare const shippedActivities: (root?: string) => Promise<ActivityRef[]>;
|
|
8
|
+
export interface ActivityStatus {
|
|
9
|
+
key: string;
|
|
10
|
+
state: TutorState;
|
|
11
|
+
file: string;
|
|
12
|
+
basedOn?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function activityStatuses(root: string): Promise<ActivityStatus[]>;
|
|
15
|
+
export interface ActivityInstallStep {
|
|
16
|
+
item: string;
|
|
17
|
+
action: 'created' | 'exists' | 'kept' | 'replaced';
|
|
18
|
+
note?: string;
|
|
19
|
+
}
|
|
20
|
+
/** init 用:缺的拷,有的不动(家长的) */
|
|
21
|
+
export declare function installActivities(root: string): Promise<ActivityInstallStep[]>;
|
|
22
|
+
export interface ActivityUpgradeStep {
|
|
23
|
+
key: string;
|
|
24
|
+
action: 'upgraded' | 'latest' | 'kept-custom' | 'forced' | 'installed';
|
|
25
|
+
basedOn?: string;
|
|
26
|
+
diff?: string[];
|
|
27
|
+
}
|
|
28
|
+
/** upgrade 用:同 upgradeTutors;force 里写「老师/名」才覆盖(原文留 .bak) */
|
|
29
|
+
export declare function upgradeActivities(root: string, opts?: {
|
|
30
|
+
force?: string[];
|
|
31
|
+
}): Promise<ActivityUpgradeStep[]>;
|
|
32
|
+
/**
|
|
33
|
+
* 只把一个出厂 activity 换回出厂那份(工作台「恢复出厂」,与 upgrade --force 老师/名 同一条路,但不碰别的):
|
|
34
|
+
* 现在那份和出厂不一样就先存 .bak。不是出厂的 → UsageError。返回 .bak 的路径(没存就是 null)
|
|
35
|
+
*/
|
|
36
|
+
export declare function restoreActivity(root: string, tutor: string, name: string): Promise<{
|
|
37
|
+
bak: string | null;
|
|
38
|
+
}>;
|
|
39
|
+
/** 出厂那份的原文;不是出厂的 → null */
|
|
40
|
+
export declare function shippedActivityText(tutor: string, name: string, root?: string): Promise<string | null>;
|
|
41
|
+
/** workspace 里一个 activity 现在的状态(出厂的看新旧;自家加的是 untracked) */
|
|
42
|
+
export declare function activityStatusOf(root: string, tutor: string, name: string): Promise<ActivityStatus>;
|
|
43
|
+
export interface ActivityCheck {
|
|
44
|
+
tutor: string;
|
|
45
|
+
name: string;
|
|
46
|
+
file: string;
|
|
47
|
+
activity: Activity | null;
|
|
48
|
+
issues: ActivityIssue[];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* cotutor activity check:workspace 里每个(或某位老师的、某一个)activity 文件解析 + 检查。
|
|
52
|
+
* tutors 是 cotutor.json 的老师表(键 → 这位老师的 cards;没写 cards 是 undefined = 全部);老师不在表里也报一条。
|
|
53
|
+
*/
|
|
54
|
+
export declare function checkActivities(root: string, tutors: Readonly<Record<string, {
|
|
55
|
+
cards?: readonly string[];
|
|
56
|
+
}>>, opts?: {
|
|
57
|
+
tutor?: string;
|
|
58
|
+
name?: string;
|
|
59
|
+
}): Promise<ActivityCheck[]>;
|
|
60
|
+
/**
|
|
61
|
+
* 终端里起一个 activity 话题(cotutor send / pack --activity):读 workspace 里那份,参数照首页按钮的写法给(`名=值`,几个用 ; 隔开),
|
|
62
|
+
* 和孩子点按钮同一条解析(补缺省、按类型转)。不在、参数不对 → UsageError。
|
|
63
|
+
*/
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* activity 文件的安装、升级与检查。和老师文件同一套:**拷贝,不链**。
|
|
3
|
+
* 包里的 grades/grade-<n>/agents/<老师>/activities/<名>.md 是出厂件;init 拷进 workspace 同一个位置(老师的家里,会话 cwd 下),这份是家长的;
|
|
4
|
+
* 出厂 hash 记 .cotutor/shipped.json 的 activities(键「老师/名」),据此分 latest / upgradable / custom / untracked / missing,意思同 tutors.ts。
|
|
5
|
+
*/
|
|
6
|
+
import { readFile, mkdir, writeFile, lstat } from 'node:fs/promises';
|
|
7
|
+
import { dirname, join } from 'node:path';
|
|
8
|
+
import { lintActivity } from "../../runtime/activity.js";
|
|
9
|
+
import { PACKAGE_AGENTS_DIR, PACKAGE_VERSION } from "./skeleton.js";
|
|
10
|
+
import { lineDiff, readManifest, sha256, writeManifest } from "./tutors.js";
|
|
11
|
+
import { UsageError } from "../workspace.js";
|
|
12
|
+
import { workspaceGradePack } from "./grades.js";
|
|
13
|
+
import { ACTIVITIES_DIR, EXAMPLES_SUFFIX, activityFile, activityRunFor, listActivities } from "../../runtime/activities.js";
|
|
14
|
+
// 读的那一半在 src/runtime/activities.ts;照旧从这里转出
|
|
15
|
+
export { ACTIVITIES_DIR, EXAMPLES_SUFFIX, activityFile, activityRunFor, listActivities };
|
|
16
|
+
/** 出厂的 activity 与它们的例子文件 */
|
|
17
|
+
export const shippedActivities = async (root) => listActivities(root ? (await workspaceGradePack(root)).agentsDir : PACKAGE_AGENTS_DIR, undefined, { examples: true });
|
|
18
|
+
const keyOf = (a) => `${a.tutor}/${a.name}`;
|
|
19
|
+
async function readState(root, a, manifest) {
|
|
20
|
+
const key = keyOf(a);
|
|
21
|
+
const file = activityFile(root, a.tutor, a.name);
|
|
22
|
+
if (!(await lstat(file).catch(() => null)))
|
|
23
|
+
return { key, state: 'missing', file };
|
|
24
|
+
let text;
|
|
25
|
+
try {
|
|
26
|
+
text = await readFile(file, 'utf8');
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return { key, state: 'broken', file };
|
|
30
|
+
}
|
|
31
|
+
const h = sha256(text);
|
|
32
|
+
const rec = manifest.activities?.[key];
|
|
33
|
+
if (h === sha256(await readFile(a.file, 'utf8')))
|
|
34
|
+
return { key, state: 'latest', file, basedOn: rec?.version };
|
|
35
|
+
if (rec && rec.hash === h)
|
|
36
|
+
return { key, state: 'upgradable', file, basedOn: rec.version };
|
|
37
|
+
return { key, state: rec ? 'custom' : 'untracked', file, basedOn: rec?.version };
|
|
38
|
+
}
|
|
39
|
+
export async function activityStatuses(root) {
|
|
40
|
+
const manifest = await readManifest(root);
|
|
41
|
+
return Promise.all((await shippedActivities(root)).map((a) => readState(root, a, manifest)));
|
|
42
|
+
}
|
|
43
|
+
async function installOne(root, a, manifest) {
|
|
44
|
+
const file = activityFile(root, a.tutor, a.name);
|
|
45
|
+
await mkdir(dirname(file), { recursive: true });
|
|
46
|
+
const text = await readFile(a.file, 'utf8');
|
|
47
|
+
await writeFile(file, text);
|
|
48
|
+
manifest.teachingPack ??= { grade: (await workspaceGradePack(root)).grade };
|
|
49
|
+
manifest.activities ??= {};
|
|
50
|
+
manifest.activities[keyOf(a)] = { hash: sha256(text), version: PACKAGE_VERSION };
|
|
51
|
+
}
|
|
52
|
+
/** init 用:缺的拷,有的不动(家长的) */
|
|
53
|
+
export async function installActivities(root) {
|
|
54
|
+
const steps = [];
|
|
55
|
+
const manifest = await readManifest(root);
|
|
56
|
+
let touched = !manifest.teachingPack;
|
|
57
|
+
manifest.teachingPack ??= { grade: (await workspaceGradePack(root)).grade };
|
|
58
|
+
for (const a of await shippedActivities(root)) {
|
|
59
|
+
const s = await readState(root, a, manifest);
|
|
60
|
+
const item = `agents/${a.tutor}/${ACTIVITIES_DIR}/${a.name}.md`;
|
|
61
|
+
if (s.state === 'missing' || s.state === 'broken') {
|
|
62
|
+
await installOne(root, a, manifest);
|
|
63
|
+
touched = true;
|
|
64
|
+
steps.push({ item, action: s.state === 'missing' ? 'created' : 'replaced', note: s.state === 'broken' ? '读不到,重新拷贝' : `拷自本包 ${PACKAGE_VERSION}` });
|
|
65
|
+
}
|
|
66
|
+
else
|
|
67
|
+
steps.push({ item, action: s.state === 'untracked' ? 'kept' : 'exists', note: s.state === 'custom' ? `自定义(基于 ${s.basedOn})` : s.state === 'upgradable' ? '可升级(cotutor upgrade)' : s.state === 'untracked' ? '已有(没有出厂记录);升级时当自定义对待' : undefined });
|
|
68
|
+
}
|
|
69
|
+
if (touched)
|
|
70
|
+
await writeManifest(root, { ...manifest, version: PACKAGE_VERSION });
|
|
71
|
+
return steps;
|
|
72
|
+
}
|
|
73
|
+
/** upgrade 用:同 upgradeTutors;force 里写「老师/名」才覆盖(原文留 .bak) */
|
|
74
|
+
export async function upgradeActivities(root, opts = {}) {
|
|
75
|
+
const manifest = await readManifest(root);
|
|
76
|
+
manifest.teachingPack ??= { grade: (await workspaceGradePack(root)).grade };
|
|
77
|
+
const steps = [];
|
|
78
|
+
for (const a of await shippedActivities(root)) {
|
|
79
|
+
const s = await readState(root, a, manifest);
|
|
80
|
+
if (s.state === 'latest')
|
|
81
|
+
steps.push({ key: s.key, action: 'latest', basedOn: s.basedOn });
|
|
82
|
+
else if (s.state === 'missing' || s.state === 'broken') {
|
|
83
|
+
await installOne(root, a, manifest);
|
|
84
|
+
steps.push({ key: s.key, action: 'installed' });
|
|
85
|
+
}
|
|
86
|
+
else if (s.state === 'upgradable') {
|
|
87
|
+
await installOne(root, a, manifest);
|
|
88
|
+
steps.push({ key: s.key, action: 'upgraded', basedOn: s.basedOn });
|
|
89
|
+
}
|
|
90
|
+
else if (opts.force?.includes(s.key)) {
|
|
91
|
+
await writeFile(`${s.file}.bak`, await readFile(s.file, 'utf8'));
|
|
92
|
+
await installOne(root, a, manifest);
|
|
93
|
+
steps.push({ key: s.key, action: 'forced', basedOn: s.basedOn });
|
|
94
|
+
}
|
|
95
|
+
else
|
|
96
|
+
steps.push({ key: s.key, action: 'kept-custom', basedOn: s.basedOn, diff: lineDiff(await readFile(s.file, 'utf8'), await readFile(a.file, 'utf8')) });
|
|
97
|
+
}
|
|
98
|
+
await writeManifest(root, { ...manifest, version: PACKAGE_VERSION });
|
|
99
|
+
return steps;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* 只把一个出厂 activity 换回出厂那份(工作台「恢复出厂」,与 upgrade --force 老师/名 同一条路,但不碰别的):
|
|
103
|
+
* 现在那份和出厂不一样就先存 .bak。不是出厂的 → UsageError。返回 .bak 的路径(没存就是 null)
|
|
104
|
+
*/
|
|
105
|
+
export async function restoreActivity(root, tutor, name) {
|
|
106
|
+
const ref = (await shippedActivities(root)).find((a) => a.tutor === tutor && a.name === name);
|
|
107
|
+
if (!ref)
|
|
108
|
+
throw new UsageError(`${tutor}/${name} 不是出厂的 activity,没有出厂那份可换`);
|
|
109
|
+
const manifest = await readManifest(root);
|
|
110
|
+
const file = activityFile(root, tutor, name);
|
|
111
|
+
const cur = await readFile(file, 'utf8').catch(() => null);
|
|
112
|
+
let bak = null;
|
|
113
|
+
if (cur !== null && cur !== (await readFile(ref.file, 'utf8'))) {
|
|
114
|
+
bak = `${file}.bak`;
|
|
115
|
+
await writeFile(bak, cur);
|
|
116
|
+
}
|
|
117
|
+
await installOne(root, ref, manifest);
|
|
118
|
+
await writeManifest(root, manifest);
|
|
119
|
+
return { bak };
|
|
120
|
+
}
|
|
121
|
+
/** 出厂那份的原文;不是出厂的 → null */
|
|
122
|
+
export async function shippedActivityText(tutor, name, root) {
|
|
123
|
+
const ref = (await shippedActivities(root)).find((a) => a.tutor === tutor && a.name === name);
|
|
124
|
+
return ref ? readFile(ref.file, 'utf8') : null;
|
|
125
|
+
}
|
|
126
|
+
/** workspace 里一个 activity 现在的状态(出厂的看新旧;自家加的是 untracked) */
|
|
127
|
+
export async function activityStatusOf(root, tutor, name) {
|
|
128
|
+
const ref = (await shippedActivities(root)).find((a) => a.tutor === tutor && a.name === name);
|
|
129
|
+
if (ref)
|
|
130
|
+
return readState(root, ref, await readManifest(root));
|
|
131
|
+
const file = activityFile(root, tutor, name);
|
|
132
|
+
return { key: `${tutor}/${name}`, state: (await lstat(file).catch(() => null)) ? 'untracked' : 'missing', file };
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* cotutor activity check:workspace 里每个(或某位老师的、某一个)activity 文件解析 + 检查。
|
|
136
|
+
* tutors 是 cotutor.json 的老师表(键 → 这位老师的 cards;没写 cards 是 undefined = 全部);老师不在表里也报一条。
|
|
137
|
+
*/
|
|
138
|
+
export async function checkActivities(root, tutors, opts = {}) {
|
|
139
|
+
const refs = (await listActivities(join(root, 'agents'), opts.tutor)).filter((r) => !opts.name || r.name === opts.name);
|
|
140
|
+
const out = [];
|
|
141
|
+
for (const r of refs) {
|
|
142
|
+
const text = await readFile(r.file, 'utf8').catch(() => null);
|
|
143
|
+
if (text === null) {
|
|
144
|
+
out.push({ ...r, activity: null, issues: [{ level: 'fix', text: '读不到' }] });
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const t = tutors[r.tutor];
|
|
148
|
+
const { activity, issues } = lintActivity(text, { fileName: r.name, tutorCards: t?.cards });
|
|
149
|
+
if (!t)
|
|
150
|
+
issues.unshift({ level: 'fix', text: `cotutor.json 里没有 ${r.tutor} 这位老师,这个 activity 没人带` });
|
|
151
|
+
out.push({ ...r, activity, issues });
|
|
152
|
+
}
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* 终端里起一个 activity 话题(cotutor send / pack --activity):读 workspace 里那份,参数照首页按钮的写法给(`名=值`,几个用 ; 隔开),
|
|
157
|
+
* 和孩子点按钮同一条解析(补缺省、按类型转)。不在、参数不对 → UsageError。
|
|
158
|
+
*/
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cotutor cert:用 mkcert 给这台机器签一张证书到 ~/.config/cotutor/certs/(cert.pem + key.pem),serve 看到就走 HTTPS。
|
|
3
|
+
* 为什么要:iPad Safari 的录音 / 语音识别只在安全上下文里给;局域网 IP 不是 localhost,得自签。
|
|
4
|
+
* 为什么放机器级而不是 workspace:签的是本机名与局域网 IP,与孩子无关;多个 workspace 共用一张,IP 变了只重签一次。
|
|
5
|
+
* 主机名 = 本机名、本机名.local、所有局域网 IPv4、localhost、127.0.0.1,再加 --host 给的。已有证书就覆盖(证书可再生)。不需要 workspace。
|
|
6
|
+
*/
|
|
7
|
+
import { execFile } from 'node:child_process';
|
|
8
|
+
import { mkdir } from 'node:fs/promises';
|
|
9
|
+
import { hostname } from 'node:os';
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
import { promisify } from 'node:util';
|
|
12
|
+
import { lanAddresses } from "./serve.js";
|
|
13
|
+
import { USER_CERT_DIR, UsageError } from "../workspace.js";
|
|
14
|
+
const execFileP = promisify(execFile);
|
|
15
|
+
export async function makeCert(extraHosts = []) {
|
|
16
|
+
let caRoot;
|
|
17
|
+
try {
|
|
18
|
+
caRoot = (await execFileP('mkcert', ['-CAROOT'], { timeout: 8000 })).stdout.trim();
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
throw new UsageError('PATH 里没有 mkcert。装:brew install mkcert && mkcert -install(在 Mac 上信任一次根证书);iPad / iPhone 端见 cert 命令输出的提示与 docs/iPad与iPhone.md。');
|
|
22
|
+
}
|
|
23
|
+
const host = hostname();
|
|
24
|
+
const hosts = [...new Set([host, host.endsWith('.local') ? host : `${host}.local`, ...lanAddresses(), 'localhost', '127.0.0.1', ...extraHosts])];
|
|
25
|
+
const dir = USER_CERT_DIR;
|
|
26
|
+
await mkdir(dir, { recursive: true });
|
|
27
|
+
const cert = join(dir, 'cert.pem');
|
|
28
|
+
const key = join(dir, 'key.pem');
|
|
29
|
+
try {
|
|
30
|
+
await execFileP('mkcert', ['-cert-file', cert, '-key-file', key, ...hosts], { timeout: 60_000 });
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
throw new UsageError(`mkcert 签证书失败:${err instanceof Error ? err.message : String(err)}\n先跑 mkcert -install,再重试。`);
|
|
34
|
+
}
|
|
35
|
+
return { cert, key, hosts, caRoot };
|
|
36
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const BAKE_FILE = "bake.json";
|
|
2
|
+
/** 课包有没有烤过、烤的是不是现在这幅画面 */
|
|
3
|
+
export declare function bakeIsFresh(bundleDir: string): Promise<boolean>;
|
|
4
|
+
/** 烤一个或几个课包(同一个浏览器);返回每个写到哪 */
|
|
5
|
+
export declare function bakeBundles(bundlesDir: string, ids: readonly string[]): Promise<{
|
|
6
|
+
id: string;
|
|
7
|
+
file: string;
|
|
8
|
+
elements: number;
|
|
9
|
+
bytes: number;
|
|
10
|
+
}[]>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bake:课包 → bake.json(格式在 src/chalk/paint.ts)。起临时页面服务(./serve.ts)与本机 Chrome(./browser.ts),开舞台的 ?chalk=bake,
|
|
3
|
+
* 在浏览器里用 excalidraw 静态导出一次、量好路径;孩子端播放(src/ui/stage/chalk/render.ts)与服务端出图(renderFrameSvg)就不用 excalidraw 了。
|
|
4
|
+
* source.hash 是画面的指纹(skeletons + background):scene.json 的画面变了 bakeIsFresh 就是 false,要重烤;配音与时长不算画面。
|
|
5
|
+
* 服务端(src/runtime/lecture.ts 的 ensureBaked)遇到没烤过的课包,起 cotutor chalk bake 补烤。
|
|
6
|
+
*/
|
|
7
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
8
|
+
import { createRequire } from 'node:module';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { bakeMatches, pictureHash } from "../../../chalk/paint.js";
|
|
11
|
+
import { withBrowser } from "./browser.js";
|
|
12
|
+
import { startPageServer } from "./serve.js";
|
|
13
|
+
export const BAKE_FILE = 'bake.json';
|
|
14
|
+
function excalidrawVersion() {
|
|
15
|
+
try {
|
|
16
|
+
return createRequire(import.meta.url)('@excalidraw/excalidraw/package.json').version;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return 'unknown';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** 课包有没有烤过、烤的是不是现在这幅画面 */
|
|
23
|
+
export async function bakeIsFresh(bundleDir) {
|
|
24
|
+
try {
|
|
25
|
+
const scene = JSON.parse(await readFile(join(bundleDir, 'scene.json'), 'utf8'));
|
|
26
|
+
return bakeMatches(JSON.parse(await readFile(join(bundleDir, BAKE_FILE), 'utf8')), scene);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** 烤一个或几个课包(同一个浏览器);返回每个写到哪 */
|
|
33
|
+
export async function bakeBundles(bundlesDir, ids) {
|
|
34
|
+
const server = await startPageServer(bundlesDir);
|
|
35
|
+
try {
|
|
36
|
+
return await withBrowser(async (page) => {
|
|
37
|
+
const out = [];
|
|
38
|
+
for (const id of ids) {
|
|
39
|
+
await page.goto(`${server.origin}/stage/?chalk=bake&bundle=${encodeURIComponent(`/api/bundles/${id}/`)}`);
|
|
40
|
+
await page.waitFor(`document.body.dataset.chalkDone === '1'`, 120_000);
|
|
41
|
+
const err = await page.evaluate('window.__chalkError ?? null');
|
|
42
|
+
if (err)
|
|
43
|
+
throw new Error(`课包 '${id}' 烤不了:${err}`);
|
|
44
|
+
const picture = JSON.parse(await page.evaluate('JSON.stringify(window.__chalkBake)'));
|
|
45
|
+
const scene = JSON.parse(await readFile(join(bundlesDir, id, 'scene.json'), 'utf8'));
|
|
46
|
+
const baked = { ...picture, source: { excalidraw: excalidrawVersion(), hash: pictureHash(scene) } };
|
|
47
|
+
const file = join(bundlesDir, id, BAKE_FILE);
|
|
48
|
+
const text = `${JSON.stringify(baked)}\n`;
|
|
49
|
+
await writeFile(file, text);
|
|
50
|
+
out.push({ id, file, elements: baked.elements.length, bytes: Buffer.byteLength(text) });
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
await server.close();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** 本机 Chrome 的可执行文件;找不到 null */
|
|
2
|
+
export declare function chromePath(env?: NodeJS.ProcessEnv): string | null;
|
|
3
|
+
export interface Page {
|
|
4
|
+
goto(url: string): Promise<void>;
|
|
5
|
+
/** 轮询到页面里这个表达式为真;超时报错 */
|
|
6
|
+
waitFor(expr: string, timeoutMs?: number): Promise<void>;
|
|
7
|
+
evaluate<T>(expr: string): Promise<T>;
|
|
8
|
+
/** 截一个元素(CSS 选择器)那一块,png */
|
|
9
|
+
screenshot(selector: string): Promise<Buffer>;
|
|
10
|
+
}
|
|
11
|
+
/** 起一个 Chrome、开一页交给 fn;不论成败都收干净 */
|
|
12
|
+
export declare function withBrowser<T>(fn: (page: Page) => Promise<T>, opts?: {
|
|
13
|
+
width?: number;
|
|
14
|
+
height?: number;
|
|
15
|
+
env?: NodeJS.ProcessEnv;
|
|
16
|
+
}): Promise<T>;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 做课包用的浏览器(2026-10-31 替掉 drawtell 的 playwright):起本机的 Chrome(无头、自己的临时 profile,不碰平时用的那个),
|
|
3
|
+
* 走 DevTools 协议(CDP)开页面、等、取值、截图。不另装浏览器:烤画面、截图与孩子端是同一种渲染就够。
|
|
4
|
+
* 每条命令都有超时(回包不来就报错,不挂着);收尾杀进程、删临时 profile,出错也在 finally 里收(scripts/_guard.mjs 那次的教训:无头 Chrome 挂了两天)。
|
|
5
|
+
* Chrome 在哪:环境变量 CHROME > macOS 的 /Applications/Google Chrome.app > PATH 里的 google-chrome / chromium。
|
|
6
|
+
*/
|
|
7
|
+
import { spawn } from 'node:child_process';
|
|
8
|
+
import { existsSync } from 'node:fs';
|
|
9
|
+
import { mkdtemp, rm } from 'node:fs/promises';
|
|
10
|
+
import { tmpdir } from 'node:os';
|
|
11
|
+
import { delimiter, join } from 'node:path';
|
|
12
|
+
const MAC_CHROME = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
|
|
13
|
+
const PATH_NAMES = ['google-chrome', 'google-chrome-stable', 'chromium', 'chromium-browser'];
|
|
14
|
+
/** 一条 CDP 命令最多等多久 */
|
|
15
|
+
const SEND_MS = 60_000;
|
|
16
|
+
/** 本机 Chrome 的可执行文件;找不到 null */
|
|
17
|
+
export function chromePath(env = process.env) {
|
|
18
|
+
const set = env.CHROME?.trim();
|
|
19
|
+
if (set)
|
|
20
|
+
return existsSync(set) ? set : null;
|
|
21
|
+
if (process.platform === 'darwin' && existsSync(MAC_CHROME))
|
|
22
|
+
return MAC_CHROME;
|
|
23
|
+
for (const dir of (env.PATH ?? '').split(delimiter)) {
|
|
24
|
+
for (const name of PATH_NAMES)
|
|
25
|
+
if (dir && existsSync(join(dir, name)))
|
|
26
|
+
return join(dir, name);
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
/** Chrome 起来时在 stderr 报 DevTools 的地址 */
|
|
31
|
+
function devtoolsUrl(chrome) {
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
let err = '';
|
|
34
|
+
const timer = setTimeout(() => reject(new Error(`Chrome 15 秒没起来:${err.trim().slice(-300)}`)), 15_000);
|
|
35
|
+
chrome.stderr?.on('data', (d) => {
|
|
36
|
+
err += d.toString();
|
|
37
|
+
const m = /DevTools listening on (ws:\/\/\S+)/.exec(err);
|
|
38
|
+
if (m) {
|
|
39
|
+
clearTimeout(timer);
|
|
40
|
+
resolve(m[1]);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
chrome.once('error', (e) => { clearTimeout(timer); reject(e); });
|
|
44
|
+
chrome.once('exit', (code) => { clearTimeout(timer); reject(new Error(`Chrome 退出了(${code}):${err.trim().slice(-300)}`)); });
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
async function connect(url) {
|
|
48
|
+
const ws = new WebSocket(url);
|
|
49
|
+
await new Promise((resolve, reject) => {
|
|
50
|
+
ws.addEventListener('open', () => resolve(), { once: true });
|
|
51
|
+
ws.addEventListener('error', () => reject(new Error('连不上 Chrome 的 DevTools')), { once: true });
|
|
52
|
+
});
|
|
53
|
+
let seq = 0;
|
|
54
|
+
const pending = new Map();
|
|
55
|
+
ws.addEventListener('message', (e) => {
|
|
56
|
+
const m = JSON.parse(String(e.data));
|
|
57
|
+
const p = m.id === undefined ? undefined : pending.get(m.id);
|
|
58
|
+
if (!p)
|
|
59
|
+
return;
|
|
60
|
+
pending.delete(m.id);
|
|
61
|
+
clearTimeout(p.timer);
|
|
62
|
+
if (m.error)
|
|
63
|
+
p.reject(new Error(m.error.message));
|
|
64
|
+
else
|
|
65
|
+
p.resolve(m.result ?? {});
|
|
66
|
+
});
|
|
67
|
+
const send = (method, params = {}, sessionId) => new Promise((resolve, reject) => {
|
|
68
|
+
const id = ++seq;
|
|
69
|
+
const timer = setTimeout(() => { pending.delete(id); reject(new Error(`Chrome 没回 ${method}(${SEND_MS / 1000} 秒)`)); }, SEND_MS);
|
|
70
|
+
pending.set(id, { resolve, reject, timer });
|
|
71
|
+
ws.send(JSON.stringify({ id, method, params, ...(sessionId ? { sessionId } : {}) }));
|
|
72
|
+
});
|
|
73
|
+
return {
|
|
74
|
+
send,
|
|
75
|
+
close() {
|
|
76
|
+
for (const p of pending.values()) {
|
|
77
|
+
clearTimeout(p.timer);
|
|
78
|
+
p.reject(new Error('关了'));
|
|
79
|
+
}
|
|
80
|
+
pending.clear();
|
|
81
|
+
ws.close();
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/** 起一个 Chrome、开一页交给 fn;不论成败都收干净 */
|
|
86
|
+
export async function withBrowser(fn, opts = {}) {
|
|
87
|
+
const bin = chromePath(opts.env);
|
|
88
|
+
if (!bin)
|
|
89
|
+
throw new Error('找不到 Chrome:装 Google Chrome,或环境变量 CHROME 指到 Chrome / Chromium 的可执行文件');
|
|
90
|
+
const width = opts.width ?? 1280;
|
|
91
|
+
const height = opts.height ?? 960;
|
|
92
|
+
const profile = await mkdtemp(join(tmpdir(), 'cotutor-chalk-'));
|
|
93
|
+
const chrome = spawn(bin, ['--headless=new', '--disable-gpu', '--no-first-run', '--no-default-browser-check', '--mute-audio', '--hide-scrollbars', `--user-data-dir=${profile}`, '--remote-debugging-port=0', `--window-size=${width},${height}`, 'about:blank'], { stdio: ['ignore', 'ignore', 'pipe'] });
|
|
94
|
+
try {
|
|
95
|
+
const cdp = await connect(await devtoolsUrl(chrome));
|
|
96
|
+
try {
|
|
97
|
+
const { targetId } = await cdp.send('Target.createTarget', { url: 'about:blank' });
|
|
98
|
+
const { sessionId } = await cdp.send('Target.attachToTarget', { targetId, flatten: true });
|
|
99
|
+
const s = (method, params) => cdp.send(method, params, String(sessionId));
|
|
100
|
+
await s('Page.enable');
|
|
101
|
+
await s('Emulation.setDeviceMetricsOverride', { width, height, deviceScaleFactor: 1, mobile: false });
|
|
102
|
+
const evaluate = async (expression) => {
|
|
103
|
+
const r = (await s('Runtime.evaluate', { expression, returnByValue: true, awaitPromise: true }));
|
|
104
|
+
if (r.exceptionDetails)
|
|
105
|
+
throw new Error(`页面里出错:${r.exceptionDetails.exception?.description ?? r.exceptionDetails.text ?? '?'}`);
|
|
106
|
+
return r.result?.value;
|
|
107
|
+
};
|
|
108
|
+
const page = {
|
|
109
|
+
async goto(url) {
|
|
110
|
+
const r = await s('Page.navigate', { url });
|
|
111
|
+
if (typeof r.errorText === 'string' && r.errorText)
|
|
112
|
+
throw new Error(`打不开 ${url}:${r.errorText}`);
|
|
113
|
+
},
|
|
114
|
+
async waitFor(expr, timeoutMs = 30_000) {
|
|
115
|
+
const until = Date.now() + timeoutMs;
|
|
116
|
+
while (!(await evaluate(`Boolean(${expr})`).catch(() => false))) {
|
|
117
|
+
if (Date.now() > until)
|
|
118
|
+
throw new Error(`页面 ${timeoutMs / 1000} 秒没好(${expr})`);
|
|
119
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
evaluate,
|
|
123
|
+
async screenshot(selector) {
|
|
124
|
+
const box = await evaluate(`(() => { const el = document.querySelector(${JSON.stringify(selector)}); if (!el) return null; const r = el.getBoundingClientRect(); return { x: r.x, y: r.y, width: r.width, height: r.height }; })()`);
|
|
125
|
+
if (!box || box.width < 1 || box.height < 1)
|
|
126
|
+
throw new Error(`页面里没有 ${selector}`);
|
|
127
|
+
const r = await s('Page.captureScreenshot', { format: 'png', clip: { ...box, scale: 1 } });
|
|
128
|
+
return Buffer.from(String(r.data), 'base64');
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
return await fn(page);
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
cdp.close();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
finally {
|
|
138
|
+
chrome.kill();
|
|
139
|
+
await Promise.race([new Promise((r) => (chrome.exitCode !== null || chrome.signalCode !== null ? r(null) : chrome.once('exit', r))), new Promise((r) => setTimeout(r, 3000))]);
|
|
140
|
+
await rm(profile, { recursive: true, force: true }).catch(() => { });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* build:场景(已过 check)→ 课包目录。幂等:同输入产出相同字节。
|
|
3
|
+
* 课包 = 自包含目录:scene.json + manifest.json(+ audio/,由 cotutor chalk dub 落进来;build 不动 audio/)。
|
|
4
|
+
* audio/index.json 里讲稿 hash 仍匹配的步,build 会把 audioSrc 回填进 manifest——
|
|
5
|
+
* 讲稿改了的步自动失去音频(等重新 dub),不会拿旧音配新词。
|
|
6
|
+
*/
|
|
7
|
+
import type { ChalkScene } from '../../../chalk/types.ts';
|
|
8
|
+
/**
|
|
9
|
+
* sourceDir:场景源所在目录,background.src 相对它解析;build 把图拷进课包(background.<ext>)并改写 src。
|
|
10
|
+
* 不给 sourceDir = 场景已是课包形态(src 相对课包目录),原样保留。
|
|
11
|
+
*/
|
|
12
|
+
export declare function buildBundle(scene: ChalkScene, outDir: string, sourceDir?: string): Promise<string[]>;
|
|
13
|
+
/** 课包 → 场景(拼法与校验在 src/chalk 的 parseBundle):bake / snap / dub 直接吃课包 id 时用 */
|
|
14
|
+
export declare function readBundle(bundlesDir: string, id: string): Promise<ChalkScene>;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* build:场景(已过 check)→ 课包目录。幂等:同输入产出相同字节。
|
|
3
|
+
* 课包 = 自包含目录:scene.json + manifest.json(+ audio/,由 cotutor chalk dub 落进来;build 不动 audio/)。
|
|
4
|
+
* audio/index.json 里讲稿 hash 仍匹配的步,build 会把 audioSrc 回填进 manifest——
|
|
5
|
+
* 讲稿改了的步自动失去音频(等重新 dub),不会拿旧音配新词。
|
|
6
|
+
*/
|
|
7
|
+
import { copyFile, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
8
|
+
import { extname, join, resolve } from 'node:path';
|
|
9
|
+
import { attachAudio } from "./dub.js";
|
|
10
|
+
import { sceneBounds } from "../../../chalk/geometry.js";
|
|
11
|
+
import { parseBundle } from "../../../chalk/bundle.js";
|
|
12
|
+
import { LoadError, NotFoundError } from "./load-scene.js";
|
|
13
|
+
/**
|
|
14
|
+
* sourceDir:场景源所在目录,background.src 相对它解析;build 把图拷进课包(background.<ext>)并改写 src。
|
|
15
|
+
* 不给 sourceDir = 场景已是课包形态(src 相对课包目录),原样保留。
|
|
16
|
+
*/
|
|
17
|
+
export async function buildBundle(scene, outDir, sourceDir) {
|
|
18
|
+
await mkdir(outDir, { recursive: true });
|
|
19
|
+
const files = [];
|
|
20
|
+
// 背景图拷进课包、改写 src:第一块画板 background.<ext>,换画板的 background-<board id>.<ext>
|
|
21
|
+
const copyBackground = async (bg, stem, where) => {
|
|
22
|
+
const from = resolve(sourceDir, bg.src);
|
|
23
|
+
const name = `${stem}${extname(bg.src).toLowerCase()}`;
|
|
24
|
+
try {
|
|
25
|
+
await copyFile(from, join(outDir, name));
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
throw new LoadError(`背景图读不到:${from}(${where} '${bg.src}' 相对场景文件所在目录解析);检查路径`);
|
|
29
|
+
}
|
|
30
|
+
files.push(join(outDir, name));
|
|
31
|
+
return { ...bg, src: name };
|
|
32
|
+
};
|
|
33
|
+
let background = scene.background;
|
|
34
|
+
let skeletons = scene.skeletons;
|
|
35
|
+
if (sourceDir) {
|
|
36
|
+
if (background)
|
|
37
|
+
background = await copyBackground(background, 'background', 'background.src');
|
|
38
|
+
skeletons = [];
|
|
39
|
+
for (const e of scene.skeletons) {
|
|
40
|
+
const bg = e.type === 'board' ? e.background : undefined;
|
|
41
|
+
skeletons.push(bg ? { ...e, background: await copyBackground(bg, `background-${e.id}`, `换画板 '${e.id}' 的 background.src`) } : e);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const sceneJson = {
|
|
45
|
+
schema: 'chalk-scene',
|
|
46
|
+
version: 1,
|
|
47
|
+
id: scene.id,
|
|
48
|
+
title: scene.title,
|
|
49
|
+
problem: scene.problem,
|
|
50
|
+
model: scene.model,
|
|
51
|
+
template: scene.template,
|
|
52
|
+
...(scene.subject ? { subject: scene.subject } : {}),
|
|
53
|
+
...(background ? { background } : {}),
|
|
54
|
+
skeletons,
|
|
55
|
+
...(scene.groups?.length ? { groups: scene.groups } : {}),
|
|
56
|
+
bounds: sceneBounds(skeletons),
|
|
57
|
+
};
|
|
58
|
+
const manifest = {
|
|
59
|
+
schema: 'lesson-manifest',
|
|
60
|
+
version: 2,
|
|
61
|
+
steps: scene.steps.map((s) => ({
|
|
62
|
+
step: s.step,
|
|
63
|
+
elementIds: s.elementIds,
|
|
64
|
+
line: s.line,
|
|
65
|
+
pauseAfter: s.pauseAfter,
|
|
66
|
+
...(s.audioSrc ? { audioSrc: s.audioSrc } : {}),
|
|
67
|
+
...(s.audioSrc && s.audioDurationMs ? { audioDurationMs: s.audioDurationMs } : {}),
|
|
68
|
+
})),
|
|
69
|
+
...(scene.blocks?.length ? { blocks: scene.blocks } : {}),
|
|
70
|
+
...(scene.subscenes?.length ? { subscenes: scene.subscenes } : {}),
|
|
71
|
+
};
|
|
72
|
+
await attachAudio(outDir, manifest);
|
|
73
|
+
for (const [name, data] of [
|
|
74
|
+
['scene.json', sceneJson],
|
|
75
|
+
['manifest.json', manifest],
|
|
76
|
+
]) {
|
|
77
|
+
const p = join(outDir, name);
|
|
78
|
+
await writeFile(p, `${JSON.stringify(data, null, 2)}\n`);
|
|
79
|
+
files.push(p);
|
|
80
|
+
}
|
|
81
|
+
return files;
|
|
82
|
+
}
|
|
83
|
+
/** 课包 → 场景(拼法与校验在 src/chalk 的 parseBundle):bake / snap / dub 直接吃课包 id 时用 */
|
|
84
|
+
export async function readBundle(bundlesDir, id) {
|
|
85
|
+
let sceneJson;
|
|
86
|
+
let manifest;
|
|
87
|
+
try {
|
|
88
|
+
sceneJson = JSON.parse(await readFile(join(bundlesDir, id, 'scene.json'), 'utf8'));
|
|
89
|
+
manifest = JSON.parse(await readFile(join(bundlesDir, id, 'manifest.json'), 'utf8'));
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
throw new NotFoundError(`课包 '${id}' 不存在或不完整(${join(bundlesDir, id)}/ 要有 scene.json + manifest.json);先 cotutor chalk build <scene.ts>`);
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
return parseBundle(sceneJson, manifest).scene;
|
|
96
|
+
}
|
|
97
|
+
catch (e) {
|
|
98
|
+
throw new LoadError(`课包 '${id}' ${e.message}。用源 TS 重新 cotutor chalk build`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ChalkScene } from '../../../chalk/types.ts';
|
|
2
|
+
import type { LessonManifest } from '../../../chalk/manifest.ts';
|
|
3
|
+
import { type StretchInfo } from '../../../chalk/timeline.ts';
|
|
4
|
+
/** 讲稿 hash:build 用它判断 audio/ 里的音频是否仍对应当前讲稿(讲稿改了 = 音频失效,不回填) */
|
|
5
|
+
export declare function lineHash(line: string): string;
|
|
6
|
+
export interface AudioIndex {
|
|
7
|
+
schema: 'drawtell-audio';
|
|
8
|
+
version: 1;
|
|
9
|
+
voice: string;
|
|
10
|
+
model: string | null;
|
|
11
|
+
instruction: string | null;
|
|
12
|
+
steps: Array<{
|
|
13
|
+
step: number;
|
|
14
|
+
file: string;
|
|
15
|
+
textHash: string;
|
|
16
|
+
characters: number;
|
|
17
|
+
durationMs: number | null;
|
|
18
|
+
}>;
|
|
19
|
+
}
|
|
20
|
+
export interface DubOptions {
|
|
21
|
+
scene: ChalkScene;
|
|
22
|
+
bundleDir: string;
|
|
23
|
+
voice: string;
|
|
24
|
+
instruction?: string;
|
|
25
|
+
/** 只算账:哪几步要合成、约多少计费字符,不花钱 */
|
|
26
|
+
dryRun?: boolean;
|
|
27
|
+
/** 配音缓存(workspace 的 dirs.tts) */
|
|
28
|
+
cacheDir: string;
|
|
29
|
+
env?: NodeJS.ProcessEnv;
|
|
30
|
+
}
|
|
31
|
+
export interface DubResult {
|
|
32
|
+
ok: boolean;
|
|
33
|
+
dryRun: boolean;
|
|
34
|
+
/** 约多少计费字符(汉字算 2、别的算 1;voxtell 实测和账单差 ±5%) */
|
|
35
|
+
characters: number;
|
|
36
|
+
/** kept = 讲稿与音色都没变,沿用课包里那份 */
|
|
37
|
+
steps: Array<{
|
|
38
|
+
step: number;
|
|
39
|
+
file: string | null;
|
|
40
|
+
kept: boolean;
|
|
41
|
+
characters: number;
|
|
42
|
+
durationMs: number | null;
|
|
43
|
+
error?: string;
|
|
44
|
+
}>;
|
|
45
|
+
/** 每步 画多久 / 音多久 / 播放器会拉伸几倍(只拉不缩,封顶 5) */
|
|
46
|
+
pacing: StretchInfo[];
|
|
47
|
+
manifestUpdated: boolean;
|
|
48
|
+
}
|
|
49
|
+
export declare function dubBundle(o: DubOptions): Promise<DubResult>;
|
|
50
|
+
/** build 用:audio/index.json 里讲稿 hash 仍匹配的步,回填 audioSrc;讲稿改了的步不回填(等重新 dub) */
|
|
51
|
+
export declare function attachAudio(bundleDir: string, manifest: LessonManifest): Promise<number>;
|