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,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Qwen Code(`qwen`,0.25 起)的适配器。输出读法在 stream-json.ts,运行约定:
|
|
3
|
+
* - **隔离的家**:不用 `--bare`(它不读任何配置、不认 `--core-tools`、自带 read_file / edit / run_shell_command 一套)。
|
|
4
|
+
* `QWEN_HOME` 指 workspace 的 `.cotutor/qwen/home/`(不改 HOME),里面的 settings.json 由这里生成:模型供应商(key 只写环境变量名)、
|
|
5
|
+
* 关掉它自己的记忆整理(不然一轮跑完在后台用 write_file 写文件)、使用统计、遥测、防休眠。会话落在 `.cotutor/qwen/runtime/`。
|
|
6
|
+
* - **工具**:`{toolArgs}` 展开成 `--core-tools` + `--exclude-tools`;不带 = 工具表为空,只读 = read_file / glob / grep_search。
|
|
7
|
+
* 模板带 `--approval-mode default`:shell、写、读 workspace 外都被拒(`--yolo` 会放行 workspace 外的读)。
|
|
8
|
+
* - **思考量**:没有旗标;按 effort 指一份系统配置(`QWEN_CODE_SYSTEM_SETTINGS_PATH`,`model.reasoningEffort`)。
|
|
9
|
+
* - **key 与端点**:settings.json 只写 `${COTUTOR_QWEN_BASE_URL}` 与环境变量名 `COTUTOR_QWEN_API_KEY`(qwen 读配置时展开);起进程时按 `src/shared/qianwen.ts`
|
|
10
|
+
* 定走 Token Plan 还是百炼按量,把这两个填进子进程的环境,不落盘。出厂的几个模型 Token Plan 都有,有它的 key 就走它。
|
|
11
|
+
* - 没有钱数,只报 token;超时(退出码 55)不吐 result;每轮一条 goal_state 事件(读法里不出事件)。
|
|
12
|
+
*/
|
|
13
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
14
|
+
import { dirname, join } from 'node:path';
|
|
15
|
+
import { compatibleBase, qianwenKeys, qianwenLine } from "../../shared/qianwen.js";
|
|
16
|
+
import { parseStreamJson, streamJsonUserMessage } from "./stream-json.js";
|
|
17
|
+
const KINDS = {
|
|
18
|
+
read_file: 'read',
|
|
19
|
+
read_many_files: 'read',
|
|
20
|
+
zoom_image: 'read',
|
|
21
|
+
list_directory: 'read',
|
|
22
|
+
run_shell_command: 'shell',
|
|
23
|
+
glob: 'search',
|
|
24
|
+
grep_search: 'search',
|
|
25
|
+
edit: 'edit',
|
|
26
|
+
write_file: 'edit',
|
|
27
|
+
notebook_edit: 'edit',
|
|
28
|
+
skill: 'skill',
|
|
29
|
+
};
|
|
30
|
+
/** 只读那轮给的核心工具(读文件含图片、按名找、按内容找) */
|
|
31
|
+
const READ_TOOLS = ['read_file', 'glob', 'grep_search'];
|
|
32
|
+
/** `--core-tools` 管不到的非核心工具,要一个个排除(0.25 的 system/init 里出现过的;ask_user_question 与计划模式那两个是不加 --bare 时才有的,2026-10-09 真跑里核对出来) */
|
|
33
|
+
const NON_CORE = ['agent', 'skill', 'list_agents', 'task_stop', 'send_message', 'record_artifact', 'get_goal', 'update_goal', 'tool_call', 'tool_search', 'report_findings', 'enter_worktree', 'exit_worktree', 'ask_user_question', 'enter_plan_mode', 'exit_plan_mode'];
|
|
34
|
+
/** workspace 里归 qwen 的目录(机器文件,prepare 每次对一遍) */
|
|
35
|
+
export const QWEN_DIR = '.cotutor/qwen';
|
|
36
|
+
const homeOf = (root) => join(root, QWEN_DIR, 'home');
|
|
37
|
+
const effortFile = (root, level) => join(root, QWEN_DIR, `effort-${level}.json`);
|
|
38
|
+
/** 政策 effort → 模型的思考档:low 不想(孩子在等);qwen3.7 系列只有开关,none 以外都是开 */
|
|
39
|
+
const EFFORT = { low: 'none', medium: 'low', high: 'xhigh' };
|
|
40
|
+
/**
|
|
41
|
+
* 带工具的轮次(作业照片、记账)至少想一点:2026-10-09 真跑,同一道照片题 none 那次 read_file 都没调、请孩子说是哪页;
|
|
42
|
+
* low 那次读了图、认出题目(11 秒)。孩子随口的话不带工具,不想照旧(3–6 秒)
|
|
43
|
+
*/
|
|
44
|
+
const levelOf = (effort, tools) => (tools !== 'off' && EFFORT[effort] === 'none' ? 'low' : EFFORT[effort]);
|
|
45
|
+
/** settings.json 里写的占位;qwen 读配置时拿子进程环境展开 */
|
|
46
|
+
const BASE_ENV = 'COTUTOR_QWEN_BASE_URL';
|
|
47
|
+
const KEY_ENV = 'COTUTOR_QWEN_API_KEY';
|
|
48
|
+
const toggle = { thinking: true, toggleOnly: true, disableField: 'enable_thinking' };
|
|
49
|
+
const tiers = { thinking: true, efforts: ['low', 'medium', 'xhigh'], defaultEffort: 'xhigh', disableField: 'reasoning_effort' };
|
|
50
|
+
/** 出厂模型(2026-10-09 五个模型 7 道真题对比:不想时 2–8 秒,讲得准也细;3.7-plus 快但浅,3.8-flash 不想时把盘算写进讲稿——
|
|
51
|
+
* 2026-10-13 英语老师三问没再见到,出厂 qwen-flash 运行时给英语老师) */
|
|
52
|
+
export const QWEN_DEFAULT_MODEL = 'qwen3.8-max';
|
|
53
|
+
/** 千问上能用的几个(Token Plan 与百炼按量都有);运行时模板的 -m 选其中一个 */
|
|
54
|
+
const MODELS = [
|
|
55
|
+
{ id: 'qwen3.7-plus', capabilities: { reasoning: toggle }, generationConfig: { contextWindowSize: 1_000_000, modalities: { image: true } } },
|
|
56
|
+
{ id: 'qwen3.7-max', capabilities: { reasoning: toggle }, generationConfig: { contextWindowSize: 1_000_000 } },
|
|
57
|
+
{ id: 'qwen3.8-flash', capabilities: { reasoning: tiers }, generationConfig: { contextWindowSize: 1_000_000, modalities: { image: true, video: true } } },
|
|
58
|
+
{ id: 'qwen3.8-max', capabilities: { reasoning: tiers }, generationConfig: { contextWindowSize: 1_000_000, modalities: { image: true, video: true } } },
|
|
59
|
+
];
|
|
60
|
+
/** 隔离的家里那份 settings.json(没有 key,只写环境变量名) */
|
|
61
|
+
export function qwenHomeSettings() {
|
|
62
|
+
return {
|
|
63
|
+
$version: 4,
|
|
64
|
+
security: { auth: { selectedType: 'openai' } },
|
|
65
|
+
model: { name: QWEN_DEFAULT_MODEL },
|
|
66
|
+
modelProviders: { openai: MODELS.map((m) => ({ ...m, baseUrl: `\${${BASE_ENV}}`, envKey: KEY_ENV })) },
|
|
67
|
+
memory: { enableManagedAutoMemory: false, enableManagedAutoDream: false },
|
|
68
|
+
privacy: { usageStatisticsEnabled: false },
|
|
69
|
+
telemetry: { enabled: false },
|
|
70
|
+
general: { disableAutoUpdate: true, disableUpdateNag: true, preventSystemSleep: false },
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/** 这几份机器文件:绝对路径 → 内容 */
|
|
74
|
+
export function qwenFiles(root) {
|
|
75
|
+
const files = {
|
|
76
|
+
// 整个目录不进 git:会话记录(runtime/)是对话原文,同 conversations/ 只留本机;其余都是这里每次重新生成的
|
|
77
|
+
[join(root, QWEN_DIR, '.gitignore')]: '# qwen 的隔离家目录与会话记录(cotutor 生成,对话原文只留本机)\n*\n',
|
|
78
|
+
[join(homeOf(root), 'settings.json')]: `${JSON.stringify(qwenHomeSettings(), null, 2)}\n`,
|
|
79
|
+
};
|
|
80
|
+
for (const level of new Set(Object.values(EFFORT)))
|
|
81
|
+
files[effortFile(root, level)] = `${JSON.stringify({ $version: 4, model: { reasoningEffort: level } }, null, 2)}\n`;
|
|
82
|
+
return files;
|
|
83
|
+
}
|
|
84
|
+
/** 别处的设置会盖掉家里选的模型与供应商,起进程时去掉 */
|
|
85
|
+
const FOREIGN = ['OPENAI_API_KEY', 'OPENAI_BASE_URL', 'OPENAI_MODEL', 'QWEN_MODEL'];
|
|
86
|
+
export const qwen = {
|
|
87
|
+
name: 'qwen',
|
|
88
|
+
parse: parseStreamJson,
|
|
89
|
+
stdinMessage: streamJsonUserMessage,
|
|
90
|
+
// qwen 的带工具只有只读一档(read / on 一样):shell 与写本来就不给
|
|
91
|
+
toolList: (set) => (set !== 'off' ? READ_TOOLS.join(',') : ''),
|
|
92
|
+
// --core-tools 是白名单,不带时也要给一个(给空等于不限),再把它排除掉;非核心工具不归 --core-tools 管,总要排除。
|
|
93
|
+
// 只读那轮把 workspace 根与 vault 加进可读范围:会话 cwd 是老师目录,作业照片(captures/)与教材在它外面,读外面要征得同意——
|
|
94
|
+
// 消息走 stdin 时它就停在那儿等,一直等到 --max-wall-time(2026-10-09 真跑,开了思考的那次读照片挂住)
|
|
95
|
+
toolArgs: (set, { readDirs }) => set !== 'off'
|
|
96
|
+
? ['--core-tools', READ_TOOLS.join(','), '--exclude-tools', NON_CORE.join(','), ...readDirs.flatMap((d) => ['--include-directories', d])]
|
|
97
|
+
: ['--core-tools', 'read_file', '--exclude-tools', ['read_file', ...NON_CORE].join(',')],
|
|
98
|
+
toolKind: (name) => KINDS[name] ?? 'other',
|
|
99
|
+
expectedTools: (set) => (set !== 'off' ? READ_TOOLS : []),
|
|
100
|
+
planEnv: ({ root, effort, tools }) => root ? { QWEN_HOME: homeOf(root), QWEN_RUNTIME_DIR: join(root, QWEN_DIR, 'runtime'), QWEN_CODE_SYSTEM_SETTINGS_PATH: effortFile(root, levelOf(effort, tools)) } : {},
|
|
101
|
+
async prepare(root) {
|
|
102
|
+
for (const [file, text] of Object.entries(qwenFiles(root))) {
|
|
103
|
+
if ((await readFile(file, 'utf8').catch(() => null)) === text)
|
|
104
|
+
continue;
|
|
105
|
+
await mkdir(dirname(file), { recursive: true });
|
|
106
|
+
await writeFile(file, text);
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
env: (env) => {
|
|
110
|
+
const out = { ...env, QWEN_USAGE_STATISTICS_ENABLED: 'false', QWEN_CODE_MODELS_DEV: 'off', QWEN_CODE_SUPPRESS_YOLO_WARNING: '1' };
|
|
111
|
+
for (const k of FOREIGN)
|
|
112
|
+
delete out[k];
|
|
113
|
+
const line = qianwenLine(QWEN_DEFAULT_MODEL, qianwenKeys(out));
|
|
114
|
+
if (line) {
|
|
115
|
+
out[BASE_ENV] = compatibleBase(line.host);
|
|
116
|
+
out[KEY_ENV] = line.key;
|
|
117
|
+
}
|
|
118
|
+
return out;
|
|
119
|
+
},
|
|
120
|
+
check: ({ version, env }) => {
|
|
121
|
+
const v = /(\d+)\.(\d+)\.(\d+)/.exec(version);
|
|
122
|
+
const old = !v || Number(v[1]) === 0 && Number(v[2]) < 25;
|
|
123
|
+
const line = qianwenLine(QWEN_DEFAULT_MODEL, qianwenKeys(env));
|
|
124
|
+
return [
|
|
125
|
+
{ name: 'version', ok: !old, detail: old ? `qwen ${version || '?'}:要 0.25 起(关工具的旗标、隔离的家、思考量配置都按 0.25 定的)` : `qwen ${version}`, fix: old ? 'qwen update(或 brew upgrade qwen-code)' : undefined },
|
|
126
|
+
line
|
|
127
|
+
? { name: 'key', ok: true, detail: line.plan ? '走千问 Token Plan(QWENCLOUD_TOKEN_PLAN_API_KEY)' : '走百炼按量(DASHSCOPE_API_KEY,或本机 qwen / voxtell 的配置)' }
|
|
128
|
+
: { name: 'key', ok: false, detail: '千问的 key 一把都拿不到:老师进程起来就会 401', fix: '在起 serve 的 shell 里 export QWENCLOUD_TOKEN_PLAN_API_KEY(Token Plan,sk-sp-)或 DASHSCOPE_API_KEY(百炼按量)' },
|
|
129
|
+
];
|
|
130
|
+
},
|
|
131
|
+
runtimes: () => {
|
|
132
|
+
// 消息走 stdin(预热能用;数组旗标 --core-tools 之类会吞掉跟在后面的消息,不进 argv 正好避开);-m 选模型(家里那份 settings.json 列着的);
|
|
133
|
+
// {systemBody} = 老师正文 + 板书写法,整份换掉 qwen 自己的系统提示;{toolArgs} 由适配器展开;--approval-mode default:shell、写、读 workspace 外都拒
|
|
134
|
+
// qwen-flash 只差模型(2026-10-13 英语老师出厂走它:Token Plan 上便宜、开口 2.5–4 秒)
|
|
135
|
+
const of = (model) => {
|
|
136
|
+
const flags = ['-m', model, '--system-prompt', '{systemBody}', '--input-format', 'stream-json', '--output-format', 'stream-json', '--include-partial-messages', '--approval-mode', 'default', '{toolArgs}', '--max-wall-time', '10m'];
|
|
137
|
+
return { stdin: 'stream-json', run: ['qwen', ...flags], resume: ['qwen', '--resume', '{session}', ...flags] };
|
|
138
|
+
};
|
|
139
|
+
return { qwen: of(QWEN_DEFAULT_MODEL), 'qwen-flash': of('qwen3.8-flash') };
|
|
140
|
+
},
|
|
141
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { streamJsonUserMessage } from './stream-json.ts';
|
|
2
|
+
import type { ToolSet } from './types.ts';
|
|
3
|
+
import { type ConversationIndex, type CotutorConfig, type Policy, type Runtime } from '../../schema/index.ts';
|
|
4
|
+
export interface RunPlan {
|
|
5
|
+
/** 运行时名(runtimes 里的键) */
|
|
6
|
+
runtime: string;
|
|
7
|
+
/** 适配器名(src/brain/cli/;认不出的是 stream-json) */
|
|
8
|
+
cli: string;
|
|
9
|
+
/** 这轮带不带工具(模板管不了工具的运行时也照记,只是没用上) */
|
|
10
|
+
tools: ToolSet;
|
|
11
|
+
/** 完整命令行,argv[0] 是可执行文件 */
|
|
12
|
+
argv: string[];
|
|
13
|
+
/** 这次是 resume 还是新开 */
|
|
14
|
+
resume: boolean;
|
|
15
|
+
/** resume 的会话 id */
|
|
16
|
+
session: string | null;
|
|
17
|
+
/** 运行时 stdin: "stream-json":要写进 stdin 的那一行(用户消息,带换行);消息不在 argv 里 */
|
|
18
|
+
stdin?: string;
|
|
19
|
+
/** 适配器按这轮的计划定的环境变量(qwen 的思考量配置之类);和 argv 一起进预热的比对 */
|
|
20
|
+
env: Record<string, string>;
|
|
21
|
+
}
|
|
22
|
+
export declare class RuntimeError extends Error {
|
|
23
|
+
}
|
|
24
|
+
export declare function getRuntime(config: CotutorConfig, name?: string): {
|
|
25
|
+
name: string;
|
|
26
|
+
runtime: Runtime;
|
|
27
|
+
};
|
|
28
|
+
/** 模板里有没有用到某个占位符(决定要不要去读老师正文)。API 运行时没有模板:系统提示由应用给,算用了 {systemBody} */
|
|
29
|
+
export declare function runtimeUses(runtime: Runtime, placeholder: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* 这个运行时把板书写法预载进系统提示了吗:模板用了 {boardFile} / {systemBody},或者(2026-09-19 头一版)写死了 cotutor-board/SKILL.md 的路径。
|
|
32
|
+
* 没有 → 应用在话题第一条注入 <cotutor-board>。
|
|
33
|
+
*/
|
|
34
|
+
export declare function boardPreloaded(runtime: Runtime): boolean;
|
|
35
|
+
export declare function planRun(config: CotutorConfig, index: Pick<ConversationIndex, 'session'>, vars: {
|
|
36
|
+
agent: string;
|
|
37
|
+
prompt: string;
|
|
38
|
+
agentBody?: string;
|
|
39
|
+
systemBody?: string;
|
|
40
|
+
boardFile?: string;
|
|
41
|
+
runtime?: string;
|
|
42
|
+
effort?: Policy['effort'];
|
|
43
|
+
tools?: ToolSet;
|
|
44
|
+
root?: string;
|
|
45
|
+
readDirs?: readonly string[];
|
|
46
|
+
}): RunPlan;
|
|
47
|
+
/** stream-json 输入的一条用户消息(Qwen 的 `--input-format stream-json` 一行一条;别的 CLI 看它的适配器) */
|
|
48
|
+
export declare const stdinMessage: typeof streamJsonUserMessage;
|
|
49
|
+
/**
|
|
50
|
+
* 断流后接着跑的那条消息(policy.stall):resume 同一个会话发给老师。被杀的那段回复只流到了 stdout,没进会话,
|
|
51
|
+
* 所以断在半截的正文(open)原样递回去,让它从断处接着写;应用把 open 拼在这次的收尾正文前面。
|
|
52
|
+
* open 为空 = 这一段一个字没出来,已经做完的工具调用与整段都在会话里,接着把这一轮做完。
|
|
53
|
+
*/
|
|
54
|
+
export declare function stallPrompt(open: string): string;
|
|
55
|
+
/**
|
|
56
|
+
* 老师把工具调用写成了正文、停在那里等结果(这轮没给它那个工具,qwen 照自己的格式写出来;板书解析器把那块剥掉了):
|
|
57
|
+
* resume 同一个会话,告诉它不会有结果,接着直接回孩子。那块前面写的话已经进了会话,应用拼在这次的前面
|
|
58
|
+
*/
|
|
59
|
+
export declare function toolLeakPrompt(): string;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 一次运行的命令规划(纯函数):按运行时选 run 还是 resume、填占位符、定 cwd 相对路径。
|
|
3
|
+
* 规则:当天索引里已有会话**且**是同一运行时跑出来的 → resume;否则新开(跨天索引本来就是新的,零点后第一条自然不带 --resume;
|
|
4
|
+
* 换了运行时也新开——不同运行时的会话不混用)。{agentBody} 只给模板里真用到它的运行时读老师正文。
|
|
5
|
+
*/
|
|
6
|
+
import { adapterFor, fillArgs } from "./adapters.js";
|
|
7
|
+
import { streamJsonUserMessage } from "./stream-json.js";
|
|
8
|
+
import { POLICY_DEFAULTS, isApiRuntime } from "../../schema/index.js";
|
|
9
|
+
export class RuntimeError extends Error {
|
|
10
|
+
}
|
|
11
|
+
export function getRuntime(config, name) {
|
|
12
|
+
const n = name ?? config.runtimes.default;
|
|
13
|
+
const p = config.runtimes[n];
|
|
14
|
+
if (n === 'default' || !p || typeof p === 'string') {
|
|
15
|
+
const known = Object.keys(config.runtimes).filter((k) => k !== 'default');
|
|
16
|
+
throw new RuntimeError(`运行时 "${n}" 不存在;cotutor.json 的 runtimes 里有:${known.join('、')}`);
|
|
17
|
+
}
|
|
18
|
+
return { name: n, runtime: p };
|
|
19
|
+
}
|
|
20
|
+
/** 模板里有没有用到某个占位符(决定要不要去读老师正文)。API 运行时没有模板:系统提示由应用给,算用了 {systemBody} */
|
|
21
|
+
export function runtimeUses(runtime, placeholder) {
|
|
22
|
+
if (isApiRuntime(runtime))
|
|
23
|
+
return placeholder === '{systemBody}';
|
|
24
|
+
return [...runtime.run, ...runtime.resume].some((a) => a.includes(placeholder));
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 这个运行时把板书写法预载进系统提示了吗:模板用了 {boardFile} / {systemBody},或者(2026-09-19 头一版)写死了 cotutor-board/SKILL.md 的路径。
|
|
28
|
+
* 没有 → 应用在话题第一条注入 <cotutor-board>。
|
|
29
|
+
*/
|
|
30
|
+
export function boardPreloaded(runtime) {
|
|
31
|
+
return runtimeUses(runtime, '{boardFile}') || runtimeUses(runtime, '{systemBody}') || runtimeUses(runtime, 'cotutor-board/SKILL.md');
|
|
32
|
+
}
|
|
33
|
+
export function planRun(config, index, vars) {
|
|
34
|
+
const { name, runtime } = getRuntime(config, vars.runtime);
|
|
35
|
+
if (isApiRuntime(runtime))
|
|
36
|
+
throw new RuntimeError(`运行时 "${name}" 是 API 运行时,不起命令行(src/brain/api.ts)`);
|
|
37
|
+
const adapter = adapterFor(runtime);
|
|
38
|
+
const session = index.session && index.session.runtime === name ? index.session.id : null;
|
|
39
|
+
const template = session ? runtime.resume : runtime.run;
|
|
40
|
+
const effort = vars.effort ?? POLICY_DEFAULTS.effort;
|
|
41
|
+
return {
|
|
42
|
+
runtime: name,
|
|
43
|
+
cli: adapter.name,
|
|
44
|
+
tools: vars.tools ?? 'on',
|
|
45
|
+
argv: fillArgs(adapter, template, { agent: vars.agent, prompt: vars.prompt, session: session ?? undefined, agentBody: vars.agentBody, systemBody: vars.systemBody, boardFile: vars.boardFile, effort: vars.effort, tools: vars.tools, readDirs: vars.readDirs }),
|
|
46
|
+
resume: session !== null,
|
|
47
|
+
session,
|
|
48
|
+
...(runtime.stdin ? { stdin: adapter.stdinMessage(vars.prompt) } : {}),
|
|
49
|
+
env: adapter.planEnv?.({ root: vars.root, effort, tools: vars.tools ?? 'on' }) ?? {},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** stream-json 输入的一条用户消息(Qwen 的 `--input-format stream-json` 一行一条;别的 CLI 看它的适配器) */
|
|
53
|
+
export const stdinMessage = streamJsonUserMessage;
|
|
54
|
+
/**
|
|
55
|
+
* 断流后接着跑的那条消息(policy.stall):resume 同一个会话发给老师。被杀的那段回复只流到了 stdout,没进会话,
|
|
56
|
+
* 所以断在半截的正文(open)原样递回去,让它从断处接着写;应用把 open 拼在这次的收尾正文前面。
|
|
57
|
+
* open 为空 = 这一段一个字没出来,已经做完的工具调用与整段都在会话里,接着把这一轮做完。
|
|
58
|
+
*/
|
|
59
|
+
export function stallPrompt(open) {
|
|
60
|
+
const rule = '不道歉,不提断了,不重复前面的。';
|
|
61
|
+
return open
|
|
62
|
+
? `(应用注)你刚才那段回复传到一半网络断了。孩子那边已经看到、听到的就是下面 <<< 与 >>> 之间这些:\n<<<\n${open}\n>>>\n从断的地方直接接着写,字要接得上;${rule}`
|
|
63
|
+
: `(应用注)你刚才那段回复网络断了,一个字没传出来。已经做完的工具调用和写完的段都还在,接着把这一轮做完;${rule}`;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 老师把工具调用写成了正文、停在那里等结果(这轮没给它那个工具,qwen 照自己的格式写出来;板书解析器把那块剥掉了):
|
|
67
|
+
* resume 同一个会话,告诉它不会有结果,接着直接回孩子。那块前面写的话已经进了会话,应用拼在这次的前面
|
|
68
|
+
*/
|
|
69
|
+
export function toolLeakPrompt() {
|
|
70
|
+
return '(应用注)你刚才写的工具调用没有执行,孩子也看不到。这一轮不用工具,接着直接回孩子;不提工具,不道歉,不重复前面的。';
|
|
71
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type RunPlan } from './run-plan.ts';
|
|
2
|
+
import type { CliRuntime, CotutorConfig, Policy } from '../../schema/index.ts';
|
|
3
|
+
import type { BrainExecutor, BrainHooks, BrainRequest, BrainRun, WarmKey } from '../index.ts';
|
|
4
|
+
import { type Slot } from './warm.ts';
|
|
5
|
+
export declare class CliBrain implements BrainExecutor {
|
|
6
|
+
private readonly spares;
|
|
7
|
+
private readonly workspace;
|
|
8
|
+
/** 起子进程用的环境(测试注入);缺省 process.env */
|
|
9
|
+
private readonly env;
|
|
10
|
+
constructor(opts: {
|
|
11
|
+
workspace: () => {
|
|
12
|
+
config: CotutorConfig;
|
|
13
|
+
root: string;
|
|
14
|
+
};
|
|
15
|
+
env?: NodeJS.ProcessEnv;
|
|
16
|
+
warmIdleMs?: number;
|
|
17
|
+
});
|
|
18
|
+
plan(req: BrainRequest): RunPlan;
|
|
19
|
+
prepare(plan: RunPlan): Promise<void>;
|
|
20
|
+
canWarm(runtime: CliRuntime): boolean;
|
|
21
|
+
warm(tutor: string, slot: Slot, plan: RunPlan, key: WarmKey): void;
|
|
22
|
+
warmed(tutor: string, slot?: Slot): boolean;
|
|
23
|
+
dropWarm(tutor: string, slot?: Slot): void;
|
|
24
|
+
close(): void;
|
|
25
|
+
private processEnv;
|
|
26
|
+
start(req: BrainRequest, plan: RunPlan, ctx: {
|
|
27
|
+
tutor: string;
|
|
28
|
+
key: WarmKey;
|
|
29
|
+
files: {
|
|
30
|
+
log: string;
|
|
31
|
+
err: string;
|
|
32
|
+
};
|
|
33
|
+
stall: Policy['stall'];
|
|
34
|
+
}, hooks: BrainHooks): BrainRun;
|
|
35
|
+
}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 脑执行的 CLI 实现:按 cotutor.json 的运行时起老师进程(qwen 之类,读输出、关工具、环境都在同目录的适配器 adapters.ts 与各家的文件),
|
|
3
|
+
* stream-json 落 <日期>.<job>.log、stderr 落 .err.log;每行读成统一事件,一行只解析一次,同一批事件给拼正文、工具、会话 id 用。
|
|
4
|
+
* - 预热(./warm.ts):消息走 stdin 的运行时,下一轮的进程提前起好,对得上就接过来
|
|
5
|
+
* - 断流看门狗:stall.ms 没吐一个字节、也没有工具在跑 → 杀掉,resume 同一个会话接着写(最多 stall.retries 次)。
|
|
6
|
+
* CLI 自己的断流重试可能要等很久(2026-09-21 真跑一轮连断两次,等了 6 分钟)
|
|
7
|
+
* - 回复停在写成正文的工具调用上(这轮没给它那个工具,qwen 照自己的格式写出来):resume 同一个会话告诉它不会有结果、接着回孩子,只一次
|
|
8
|
+
* - 收尾:从 .log 读整轮转录;断流接着跑的,断在半截的那段拼回最后一段前面
|
|
9
|
+
*/
|
|
10
|
+
import { spawn } from 'node:child_process';
|
|
11
|
+
import { closeSync, createWriteStream, openSync, writeSync } from 'node:fs';
|
|
12
|
+
import { appendFile, mkdir, readFile } from 'node:fs/promises';
|
|
13
|
+
import { basename } from 'node:path';
|
|
14
|
+
import { parserOf, prepareCli, processEnv, toolsOf, unexpectedTools } from "./adapters.js";
|
|
15
|
+
import { planRun, stallPrompt, toolLeakPrompt } from "./run-plan.js";
|
|
16
|
+
import { createPartialReader } from "../stream.js";
|
|
17
|
+
import { parseTranscript, toolCalls, toolSummary } from "../transcript.js";
|
|
18
|
+
import { WarmPool } from "./warm.js";
|
|
19
|
+
const cliName = (p) => p.argv[0].slice(p.argv[0].lastIndexOf('/') + 1);
|
|
20
|
+
export class CliBrain {
|
|
21
|
+
spares;
|
|
22
|
+
workspace;
|
|
23
|
+
/** 起子进程用的环境(测试注入);缺省 process.env */
|
|
24
|
+
env;
|
|
25
|
+
constructor(opts) {
|
|
26
|
+
this.workspace = opts.workspace;
|
|
27
|
+
this.env = opts.env;
|
|
28
|
+
this.spares = new WarmPool({ idleMs: opts.warmIdleMs });
|
|
29
|
+
}
|
|
30
|
+
plan(req) {
|
|
31
|
+
const { config, root } = this.workspace();
|
|
32
|
+
return planRun(config, { session: req.session }, { agent: req.agent, prompt: req.prompt, agentBody: req.agentBody, systemBody: req.systemBody, boardFile: req.boardFile, runtime: req.runtime, effort: req.effort, tools: req.tools, root, readDirs: req.readDirs });
|
|
33
|
+
}
|
|
34
|
+
prepare(plan) {
|
|
35
|
+
return prepareCli(plan.cli, this.workspace().root).catch(() => { });
|
|
36
|
+
}
|
|
37
|
+
canWarm(runtime) {
|
|
38
|
+
return Boolean(runtime.stdin);
|
|
39
|
+
}
|
|
40
|
+
warm(tutor, slot, plan, key) {
|
|
41
|
+
this.spares.warm(tutor, slot, { argv: plan.argv, env: plan.env, ...key }, this.processEnv(plan));
|
|
42
|
+
}
|
|
43
|
+
warmed(tutor, slot) {
|
|
44
|
+
return this.spares.has(tutor, slot);
|
|
45
|
+
}
|
|
46
|
+
dropWarm(tutor, slot) {
|
|
47
|
+
this.spares.drop(tutor, slot);
|
|
48
|
+
}
|
|
49
|
+
close() {
|
|
50
|
+
this.spares.dropAll();
|
|
51
|
+
}
|
|
52
|
+
processEnv(p) {
|
|
53
|
+
return processEnv(p, { ...(this.env ?? process.env), COTUTOR_WORKSPACE: this.workspace().root });
|
|
54
|
+
}
|
|
55
|
+
start(req, plan, ctx, hooks) {
|
|
56
|
+
// 预热的进程:resume 的接那个位置(对得上 = 这个话题从它起来之后没人写过),新开的接 fresh;对不上(或这轮不走 stdin)就杀掉
|
|
57
|
+
const spare = this.spares.claim(ctx.tutor, plan.resume ? 'resume' : 'fresh', { argv: plan.argv, env: plan.env, ...ctx.key });
|
|
58
|
+
// 断流接着跑:carried = 被杀那次已经拼出的正文(接着跑的那次换新读取器,正文 = carried + 新的);
|
|
59
|
+
// open = 断在半截、没进会话的那段(递回给老师,收尾时拼在最后一段前面)
|
|
60
|
+
let reader = createPartialReader();
|
|
61
|
+
let carried = '';
|
|
62
|
+
let open = '';
|
|
63
|
+
const liveText = () => { const t = reader.text(); return !carried ? t : !t ? carried : open ? carried + t : `${carried}\n\n${t}`; };
|
|
64
|
+
const resumePlan = (id, prompt) => this.plan({ ...req, runtime: plan.runtime, session: { id, runtime: plan.runtime }, prompt });
|
|
65
|
+
const stall = ctx.stall;
|
|
66
|
+
const files = ctx.files;
|
|
67
|
+
const cwd = ctx.key.cwd;
|
|
68
|
+
const go = async () => {
|
|
69
|
+
await mkdir(cwd, { recursive: true });
|
|
70
|
+
const out = createWriteStream(files.log);
|
|
71
|
+
const err = openSync(files.err, 'w');
|
|
72
|
+
hooks.onStart({ cli: cliName(plan), runtime: plan.runtime, resume: plan.resume, ...(spare ? { warmBornAt: spare.bornAt } : {}) });
|
|
73
|
+
// 工具调用回报一条(子代理的标 sub);顺手记哪些顶层工具还没回结果:工具在跑时进程不吐字是正常的,断流看门狗不算这段
|
|
74
|
+
const parse = parserOf(plan.cli);
|
|
75
|
+
let lineBuf = '';
|
|
76
|
+
const toolsRunning = new Set();
|
|
77
|
+
// 消息走 stdin 的运行时:看到收尾就关 stdin,进程自己退(每次 runOnce 换一个)
|
|
78
|
+
let onResult = null;
|
|
79
|
+
// 进程起来报的工具表里不该有的(适配器核对;不带工具那轮却有工具 = 关工具的旗标失效了,CLI 升版本最先坏的地方)
|
|
80
|
+
let unexpected = [];
|
|
81
|
+
let session = plan.session;
|
|
82
|
+
// 新会话要等模型开始回了(开始回复、吐字、在想、整条回复)才在盘上、才 resume 得了
|
|
83
|
+
// (2026-09-22 真跑:init 吐了会话 id 就被杀,resume 报 No conversation found;吐过三个字再杀,盘上有这条用户消息)
|
|
84
|
+
let persisted = plan.resume;
|
|
85
|
+
let stalls = 0;
|
|
86
|
+
// warm:预热好的进程(只给第一次;断流接着跑的那次照旧冷起)
|
|
87
|
+
const runOnce = (p, warm = null) => new Promise((resolveExit) => {
|
|
88
|
+
// 被杀的那次没收完的半行不要了
|
|
89
|
+
lineBuf = '';
|
|
90
|
+
const child = warm?.child ?? spawn(p.argv[0], p.argv.slice(1), {
|
|
91
|
+
cwd,
|
|
92
|
+
env: this.processEnv(p),
|
|
93
|
+
stdio: [p.stdin ? 'pipe' : 'ignore', 'pipe', err],
|
|
94
|
+
});
|
|
95
|
+
if (warm) {
|
|
96
|
+
// 预热的进程 stderr 是管道(起它时还没有这轮的 err.log):攒下的和之后的都写进来(池子交出来时暂停着,这里 resume)
|
|
97
|
+
const toErr = (c) => { try {
|
|
98
|
+
writeSync(err, c);
|
|
99
|
+
}
|
|
100
|
+
catch { /* err.log 已关 */ } };
|
|
101
|
+
warm.stderr.forEach(toErr);
|
|
102
|
+
child.stderr?.on('data', toErr);
|
|
103
|
+
child.stderr?.resume();
|
|
104
|
+
}
|
|
105
|
+
if (p.stdin) {
|
|
106
|
+
child.stdin?.on('error', () => { });
|
|
107
|
+
child.stdin?.write(p.stdin);
|
|
108
|
+
onResult = () => { onResult = null; child.stdin?.end(); };
|
|
109
|
+
}
|
|
110
|
+
else
|
|
111
|
+
onResult = null;
|
|
112
|
+
let stalled = false;
|
|
113
|
+
let idle = null;
|
|
114
|
+
let lastByte = Date.now();
|
|
115
|
+
const arm = () => {
|
|
116
|
+
if (idle)
|
|
117
|
+
clearTimeout(idle);
|
|
118
|
+
if (!stall.ms)
|
|
119
|
+
return;
|
|
120
|
+
idle = setTimeout(() => {
|
|
121
|
+
idle = null;
|
|
122
|
+
if (toolsRunning.size)
|
|
123
|
+
return arm();
|
|
124
|
+
stalled = true;
|
|
125
|
+
child.kill('SIGTERM');
|
|
126
|
+
setTimeout(() => { if (child.exitCode === null && child.signalCode === null)
|
|
127
|
+
child.kill('SIGKILL'); }, 2000).unref();
|
|
128
|
+
}, stall.ms);
|
|
129
|
+
};
|
|
130
|
+
arm();
|
|
131
|
+
child.stdout?.on('data', (chunk) => {
|
|
132
|
+
lastByte = Date.now();
|
|
133
|
+
arm();
|
|
134
|
+
out.write(chunk);
|
|
135
|
+
lineBuf += chunk.toString('utf8');
|
|
136
|
+
const lines = lineBuf.split('\n');
|
|
137
|
+
lineBuf = lines.pop() ?? '';
|
|
138
|
+
let changed = false;
|
|
139
|
+
for (const line of lines) {
|
|
140
|
+
const events = parse(line);
|
|
141
|
+
for (const e of events) {
|
|
142
|
+
if (e.kind === 'session') {
|
|
143
|
+
if (!session)
|
|
144
|
+
session = e.id;
|
|
145
|
+
}
|
|
146
|
+
else if (e.kind === 'init')
|
|
147
|
+
unexpected = unexpectedTools(plan.cli, plan.tools, e.tools);
|
|
148
|
+
else if (e.kind === 'result')
|
|
149
|
+
onResult?.();
|
|
150
|
+
else if (e.kind === 'results') {
|
|
151
|
+
if (!e.sub)
|
|
152
|
+
for (const r of e.results)
|
|
153
|
+
toolsRunning.delete(r.id);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
if (e.kind === 'start' || e.kind === 'delta' || e.kind === 'thinking' || e.kind === 'assistant')
|
|
157
|
+
persisted = true;
|
|
158
|
+
if (e.kind === 'assistant')
|
|
159
|
+
for (const tool of toolsOf(e.parts)) {
|
|
160
|
+
if (!e.sub && tool.id)
|
|
161
|
+
toolsRunning.add(tool.id);
|
|
162
|
+
hooks.onTool({ name: toolSummary(tool.name, tool.input), sub: e.sub });
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (reader.apply(events))
|
|
167
|
+
changed = true;
|
|
168
|
+
}
|
|
169
|
+
if (changed)
|
|
170
|
+
hooks.onText();
|
|
171
|
+
});
|
|
172
|
+
const done = (r) => {
|
|
173
|
+
if (idle)
|
|
174
|
+
clearTimeout(idle);
|
|
175
|
+
resolveExit({ ...r, ...(stalled ? { stalled: true } : {}) });
|
|
176
|
+
};
|
|
177
|
+
child.once('error', (e) => done({ code: null, spawnError: e }));
|
|
178
|
+
child.once('close', (code) => { if (stalled)
|
|
179
|
+
void appendFile(files.err, `cotutor: ${Date.now() - lastByte}ms 没有输出,当断流杀掉\n`).catch(() => { }); done({ code }); });
|
|
180
|
+
if (warm) {
|
|
181
|
+
// 开口前吐的按顺序补喂,再放开暂停;接手之前就退了的,close 已经错过,直接收尾
|
|
182
|
+
for (const c of warm.stdout)
|
|
183
|
+
child.stdout?.emit('data', c);
|
|
184
|
+
child.stdout?.resume();
|
|
185
|
+
if (warm.closed())
|
|
186
|
+
done({ code: child.exitCode });
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
let exit = await runOnce(plan, spare);
|
|
190
|
+
while (exit.stalled) {
|
|
191
|
+
stalls++;
|
|
192
|
+
if (persisted)
|
|
193
|
+
open += reader.current();
|
|
194
|
+
else {
|
|
195
|
+
session = plan.session;
|
|
196
|
+
open = '';
|
|
197
|
+
}
|
|
198
|
+
const retry = stalls <= stall.retries ? stalls : 0;
|
|
199
|
+
hooks.onStall({ idleMs: stall.ms, retry, kept: Array.from(open).length });
|
|
200
|
+
if (!retry)
|
|
201
|
+
break;
|
|
202
|
+
carried = persisted ? liveText() : '';
|
|
203
|
+
reader = createPartialReader();
|
|
204
|
+
toolsRunning.clear();
|
|
205
|
+
// 会话还没落盘(进程起来就卡住、一条整的回复都没有):原样从头再起一次;落了盘就 resume 接着写
|
|
206
|
+
const next = persisted && session ? resumePlan(session, stallPrompt(open)) : plan;
|
|
207
|
+
hooks.onStart({ cli: cliName(next), runtime: next.runtime, resume: next.resume });
|
|
208
|
+
exit = await runOnce(next);
|
|
209
|
+
}
|
|
210
|
+
// 回复停在写成正文的工具调用上(板书解析器已剥掉,孩子没看到):老师在等结果,resume 同一个会话告诉它不会有结果、接着回孩子,只一次。
|
|
211
|
+
// 这次的正文接在前面那段后面
|
|
212
|
+
let leaked = '';
|
|
213
|
+
if (!exit.stalled && exit.code === 0 && session && req.stuckOnTool?.(liveText())) {
|
|
214
|
+
leaked = liveText();
|
|
215
|
+
carried = leaked;
|
|
216
|
+
open = '';
|
|
217
|
+
reader = createPartialReader();
|
|
218
|
+
toolsRunning.clear();
|
|
219
|
+
const next = resumePlan(session, toolLeakPrompt());
|
|
220
|
+
hooks.onStart({ cli: cliName(next), runtime: next.runtime, resume: next.resume });
|
|
221
|
+
exit = await runOnce(next);
|
|
222
|
+
}
|
|
223
|
+
hooks.onExit(Date.now());
|
|
224
|
+
await new Promise((r) => out.end(r));
|
|
225
|
+
closeSync(err);
|
|
226
|
+
if (exit.spawnError)
|
|
227
|
+
await appendFile(files.err, `cotutor: 起不来 ${plan.argv[0]}:${exit.spawnError.message}\n`);
|
|
228
|
+
const logText = await readFile(files.log, 'utf8').catch(() => '');
|
|
229
|
+
const transcript = parseTranscript(logText, parse);
|
|
230
|
+
// 断流接着跑的:断在半截的那段没进会话、也不在最后的 result 里,拼回最后一段前面(老师是从断处接着写的)
|
|
231
|
+
// (result 的正文被 trim 过,断在句末 / 围栏上的补回换行,免得两句粘成一行)
|
|
232
|
+
if (open && transcript.final?.text)
|
|
233
|
+
transcript.final.text = open + (/[。!!??;;`\n]\s*$/.test(open) ? '\n' : '') + transcript.final.text;
|
|
234
|
+
if (leaked && transcript.final?.text)
|
|
235
|
+
transcript.final.text = `${leaked}\n\n${transcript.final.text}`;
|
|
236
|
+
if (exit.stalled && !transcript.final)
|
|
237
|
+
transcript.final = { text: null, ok: false, reason: `stalled:${stalls} 次断流(每次 ${stall.ms}ms 没输出),接着跑的次数用完了` };
|
|
238
|
+
// 这轮用了哪些工具、读了什么:从 .log 抽出来物化(家长端「看原文」一站、cotutor show)
|
|
239
|
+
const tools = toolCalls(logText, parse).slice(0, 200);
|
|
240
|
+
if (!transcript.final) {
|
|
241
|
+
// 进程退了但没有 result 事件:起不来、被杀、或 CLI 崩了;标 error,原因指向 err.log
|
|
242
|
+
transcript.final = { text: null, ok: false, reason: exit.spawnError ? `spawn:${exit.spawnError.message}` : `exit:${exit.code ?? 'signal'}` };
|
|
243
|
+
transcript.items.push({ kind: 'done', text: `本轮没有收尾(${transcript.final.reason}),看 ${basename(files.err)}` });
|
|
244
|
+
}
|
|
245
|
+
const warnings = [];
|
|
246
|
+
if (unexpected.length)
|
|
247
|
+
warnings.push(`${plan.cli} 起来时带着这轮不该有的工具:${unexpected.join('、')}(${plan.tools === 'off' ? '这轮应该一个工具都不带' : '这轮只该带只读的几样'});关工具的旗标可能随 CLI 升级失效了,看 src/brain/cli/${plan.cli}.ts`);
|
|
248
|
+
if (leaked)
|
|
249
|
+
warnings.push('老师把工具调用写成了正文、停在那里等结果(板上没出、嘴没念),应用 resume 同一个会话叫它直接回孩子');
|
|
250
|
+
if (stalls)
|
|
251
|
+
warnings.push(`API 流断了 ${stalls} 次(每次 ${stall.ms / 1000} 秒没动静),应用杀掉进程、resume 会话接着写的${exit.stalled ? ';次数用完还断,这轮没收尾' : ''}`);
|
|
252
|
+
return { transcript: { ...transcript, final: transcript.final }, tools, warnings };
|
|
253
|
+
};
|
|
254
|
+
return { warm: Boolean(spare), text: liveText, done: go() };
|
|
255
|
+
}
|
|
256
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Qwen Code 的 stream-json(`--output-format stream-json`,一行一个 JSON)读成统一事件。
|
|
3
|
+
* 同时保留历史日志的费用字段解析,让已有对话仍能查看。Qwen Code 0.25 的输出:
|
|
4
|
+
* - `{"type":"system","subtype":"init","session_id","tools":[…]}`(qwen 的 json 模式叫 session_start)
|
|
5
|
+
* - `{"type":"stream_event","event":{…}}`:`--include-partial-messages` 才有;message_start 开新的一条,content_block_delta 的 text_delta 是正文、thinking_delta 是在想
|
|
6
|
+
* - `{"type":"assistant","message":{"id","content":[text / tool_use 块],"usage"}}`:一条整的回复;usage 是这一次请求自己的
|
|
7
|
+
* - `{"type":"user","message":{"content":[tool_result 块]}}`:工具结果
|
|
8
|
+
* - `{"type":"result","subtype","is_error","result","num_turns","usage"}`:收尾;记账只认 usage 的 token(total_cost_usd 有也不读)。
|
|
9
|
+
* qwen 续会话时这里的 usage 是整个会话的累计(2026-10-30 在 ray 上量出来的:续了 28 轮的话题,索引里加起来 15.6M,实际约 1.2M),
|
|
10
|
+
* 所以 assistant 那几行的 usage 也读出来,parseTranscript 按它们加总
|
|
11
|
+
* parent_tool_use_id 非空的是子代理的。
|
|
12
|
+
*/
|
|
13
|
+
import type { CliEvent } from './types.ts';
|
|
14
|
+
/** 结果块的文字:字符串原样,块数组拼各块的 text */
|
|
15
|
+
export declare const blockText: (c: unknown) => string;
|
|
16
|
+
export declare function parseStreamJson(line: string): CliEvent[];
|
|
17
|
+
/** stream-json 输入的一条用户消息(`--input-format stream-json` 一行一条) */
|
|
18
|
+
export declare function streamJsonUserMessage(prompt: string): string;
|