cotutor 0.4.3 → 0.4.5
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/CHANGELOG.md +47 -0
- package/INSTALL.md +159 -0
- package/README.md +64 -17
- package/dist/app/cli/activities.d.ts +1 -1
- package/dist/app/cli/activities.js +2 -2
- package/dist/app/cli/cert.js +2 -1
- package/dist/app/cli/chalk/main.d.ts +0 -1
- package/dist/app/cli/chalk/main.js +8 -12
- package/dist/app/cli/commands.d.ts +50 -0
- package/dist/app/cli/commands.js +353 -0
- package/dist/app/cli/doctor.js +32 -17
- package/dist/app/cli/guide.d.ts +6 -0
- package/dist/app/cli/guide.js +17 -0
- package/dist/app/cli/init.d.ts +2 -0
- package/dist/app/cli/init.js +60 -6
- package/dist/app/cli/main.js +109 -46
- package/dist/app/cli/migrate.js +1 -1
- package/dist/app/cli/port.js +2 -10
- package/dist/app/cli/root-ca.d.ts +8 -0
- package/dist/app/cli/root-ca.js +33 -0
- package/dist/app/cli/sandbox.js +2 -7
- package/dist/app/cli/serve.d.ts +11 -2
- package/dist/app/cli/serve.js +49 -3
- package/dist/app/cli/service.d.ts +4 -1
- package/dist/app/cli/service.js +5 -2
- package/dist/app/cli/shipped.js +1 -1
- package/dist/app/cli/skeleton.d.ts +2 -0
- package/dist/app/cli/skeleton.js +3 -2
- package/dist/app/cli/skills.js +2 -2
- package/dist/app/cli/themes.js +2 -2
- package/dist/app/cli/tray.d.ts +6 -1
- package/dist/app/cli/tray.js +8 -5
- package/dist/app/cli/tutors.d.ts +2 -2
- package/dist/app/cli/tutors.js +4 -4
- package/dist/app/cli/update-cmd.js +4 -4
- package/dist/app/cli/usage.d.ts +26 -2
- package/dist/app/cli/usage.js +167 -38
- package/dist/app/http/access.js +1 -1
- package/dist/app/http/app.js +5 -1
- package/dist/app/http/parent-home.js +5 -0
- package/dist/app/http/stage.js +2 -2
- package/dist/app/mock/mock.js +3 -0
- package/dist/app/skills/analyze-doc.js +4 -8
- package/dist/app/skills/home-doc.js +3 -7
- package/dist/app/skills/tune-doc.js +4 -8
- package/dist/app/workspace.d.ts +16 -3
- package/dist/app/workspace.js +31 -9
- package/dist/runtime/home/home.js +1 -1
- package/dist/runtime/runner.js +2 -2
- package/dist/shared/home.d.ts +2 -0
- package/dist/shared/home.js +9 -0
- package/dist/stage/fonts/Assistant/Assistant-Bold.woff2 +0 -0
- package/dist/stage/fonts/Assistant/Assistant-Medium.woff2 +0 -0
- package/dist/stage/fonts/Assistant/Assistant-Regular.woff2 +0 -0
- package/dist/stage/fonts/Assistant/Assistant-SemiBold.woff2 +0 -0
- package/dist/stage/fonts/Cascadia/CascadiaCode-Regular.woff2 +0 -0
- package/dist/stage/fonts/ComicShanns/ComicShanns-Regular-279a7b317d12eb88de06167bd672b4b4.woff2 +0 -0
- package/dist/stage/fonts/ComicShanns/ComicShanns-Regular-6e066e8de2ac57ea9283adb9c24d7f0c.woff2 +0 -0
- package/dist/stage/fonts/ComicShanns/ComicShanns-Regular-dc6a8806fa96795d7b3be5026f989a17.woff2 +0 -0
- package/dist/stage/fonts/ComicShanns/ComicShanns-Regular-fcb0fc02dcbee4c9846b3e2508668039.woff2 +0 -0
- package/dist/stage/fonts/Excalifont/Excalifont-Regular-349fac6ca4700ffec595a7150a0d1e1d.woff2 +0 -0
- package/dist/stage/fonts/Excalifont/Excalifont-Regular-3f2c5db56cc93c5a6873b1361d730c16.woff2 +0 -0
- package/dist/stage/fonts/Excalifont/Excalifont-Regular-41b173a47b57366892116a575a43e2b6.woff2 +0 -0
- package/dist/stage/fonts/Excalifont/Excalifont-Regular-623ccf21b21ef6b3a0d87738f77eb071.woff2 +0 -0
- package/dist/stage/fonts/Excalifont/Excalifont-Regular-a88b72a24fb54c9f94e3b5fdaa7481c9.woff2 +0 -0
- package/dist/stage/fonts/Excalifont/Excalifont-Regular-b9dcf9d2e50a1eaf42fc664b50a3fd0d.woff2 +0 -0
- package/dist/stage/fonts/Excalifont/Excalifont-Regular-be310b9bcd4f1a43f571c46df7809174.woff2 +0 -0
- package/dist/stage/fonts/Liberation/LiberationSans-Regular.woff2 +0 -0
- package/dist/stage/fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYE98RXi4EwSsbg.woff2 +0 -0
- package/dist/stage/fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYEF8RXi4EwQ.woff2 +0 -0
- package/dist/stage/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTA3j6zbXWjgevT5.woff2 +0 -0
- package/dist/stage/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTQ3j6zbXWjgeg.woff2 +0 -0
- package/dist/stage/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTk3j6zbXWjgevT5.woff2 +0 -0
- package/dist/stage/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTo3j6zbXWjgevT5.woff2 +0 -0
- package/dist/stage/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTs3j6zbXWjgevT5.woff2 +0 -0
- package/dist/stage/fonts/Virgil/Virgil-Regular.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-019d66dcad46dc156b162d267f981c20.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-04b718e5623574919c8b0dea5f301444.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-069e77aac84590e2e991d0a0176d34f2.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-06c77b8c66e51ed6c63ccb502dd8b8af.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-08e0dc436ad0ad61ba5558db0674d762.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-093b9ef39a46ceae95a1df18a0a3a326.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-095c169f3314805276f603a362766abd.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-09850c4077f3fffe707905872e0e2460.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-0986d134c05864f5025962eef9f994a0.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-0b5d723fdc4e249c140f0909e87d03b4.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-0f626226ba1272e832aea87bafd9720e.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-0f7fb1e0d5015bb1371343153ecf7ce3.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-0fa55a080fcd0f9dc2e0b0058b793df8.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-0facdf1ea213ba40261022f5d5ed4493.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-10a7ae9a371830a80c3d844acf1c02d7.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-112c051027b2d766c19a519f6ee1f4f7.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-11c345711937f0ba4b8f7b6b919c8440.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-12b52b58eb3df36804b9a654ec9ee194.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-13ae07ed2e272d26d59bc0691cd7117a.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-13d2887ec8ee73c43acdabc52a05af7b.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-145aa02cdd91946e67dc934e1acffe75.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-15dc6d811c9cd078f9086a740d5a1038.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-173945821411c09f70c95f98d590e697.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-1b611157cd46bb184d4fa4dae2d6a2b8.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-1e6fd68f1f3902ce48ce8c69df385622.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-1ee544f0f1dac422545c505baa788992.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-1fdc0c67ed57263a80fd108c1f6ccf24.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-203b0e569e3b14aac86a003dc3fa523e.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-20cc1bbf50e7efb442756cb605672c1f.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-20e7bf72fa05de9adf7dbcc7bf51dde6.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-21430ee05a1248901da8d0de08744d47.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-23686f7f29da6e8008c36dd3a80c83d6.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-23ad2d71b280f00b1363b95b7bea94eb.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-23f228f3999c01983860012330e4be08.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-24476a126f129212beb33f66853ea151.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-24a21c1e4449222e8d1898d69ff3a404.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-25b7f38e18f035f96cb5e547bd2bd08c.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-29cec36cd205b211da97acabaa62f055.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-2a26d20a23b00898ce82f09d2ee47c3f.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-2adbc89c11e65905393d3dfc468b9d5b.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-2b7441d46298788ac94e610ffcc709b6.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-2b77e8ebfb2367ab2662396a60e7d320.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-2cf96d082d35ea3d8106851223ad0d16.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-2d43040e86ff03ba677f6f9c04cd0805.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-2e33e8dc771ef5e1d9127d60a6b73679.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-33432927cd87d40cfe393c7482bf221f.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-353f33792a8f60dc69323ddf635a269e.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-36925dfe329a45086cbb7fc5c20d45ac.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-3717077e38f98d89eae729b6c14e56dc.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-3756e81d3e149cf6099163ee79944fec.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-395c35dd584b56b0789f58a0559beaf1.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-3c9de2ae0ea4bc91a510942dfa4be8d2.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-3cc70dbb64df5b21f1326cc24dee2195.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-3e1f8f654357353bf0e04ba5c34b5f7f.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-3e63ed8162808a9e425ed80a8bc79114.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-3eaa538115d76932653c21d8dc28f207.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4095eb84ef3874e2600247bee0b04026.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-41521fade99856108931b4768b1b2648.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-450da755d5bcb70906e1295e559b9602.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-452225341522a7942f0f6aab1a5c91a3.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4535823663ad81405188a528d8f2b1a2.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4806e761d750087c2d734fc64596eaff.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4a0fdb40036e87b40aa08dd30584cb85.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4a38cc3e9cf104e69ba246d37f8cf135.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4aca6a43e59aceee2166b0c7e4e85ef1.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4bfaa8ffa64c5ee560aa2daba7c9cbd3.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4dc6d5f188d5c96d44815cd1e81aa885.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4ddc14ed3eb0c3e46364317dfc0144a3.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4ee10ae43505e2e0bc62656ced49c0fa.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-4f50e5136e136527280bc902c5817561.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-51502f1206be09c565f1547c406e9558.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-51a0e808bbc8361236ac521a119758a3.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-52a84a22fd1369bffeaf21da2d6158dc.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-5330a2119a716e4e7224ed108b085dac.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-543fa46ace099a7099dad69123399400.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-544fc28abe2c5c30e62383fd4dac255f.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-54acdfc2166ad7fcbd074f75fd4a56ba.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-5572b3513ba8df57a3d5d7303ee6b11b.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-56467a5c8840c4d23a60b2f935114848.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-56a32a7689abd0326e57c10c6c069bb4.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-57862b464a55b18c7bf234ce22907d73.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-583d166e56ba0de4b77eabb47ef67839.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-5882ffa04f32584d26109137e2da4352.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-58fd02350d0bc52cf1ca3bb32ce9766e.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-5935a5775af3d5c6307ac667bd9ae74e.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-59e9ff77b0efaf684bc09274fb6908c9.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-5a1ce3117cfe90c48e8fb4a9a00f694d.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-5a45d991244d4c7140217e1e5f5ca4f4.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-5a7fac4b8b23a6e4e5ba0c9bf1756c91.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-5b0ed6971aaab9c8ad563230bd5471a7.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-5d2898fbc097a7e24c6f38d80587621e.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-603aefd23e350ba7eb124273e3c9bcf1.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-60a3089806700d379f11827ee9843b6b.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-60a41c7e1c68f22424e6d22df544bc82.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-642b26e2e5f5fb780b51b593dbc8c851.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-66493ba5a8367f2928812f446f47b56a.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-670ba603758d94268e8606f240a42e12.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-671a2c20b1eb9e4ef8a192833940e319.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-684d65f1793cac449dde5d59cb3c47fb.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-69c09cc5fa3e55c74fc4821f76909cc3.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-6ae5b42180ad70b971c91e7eefb8eba2.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-6e092f71c1e634059ada0e52abadce67.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-6f3256af8454371776bc46670d33cc65.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-6fe5c5973cc06f74b2387a631ea36b88.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-70c2eb8d64e71a42a834eb857ea9df51.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-70e811fd7994e61f408c923de6ddd078.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-7197d6fda6cba7c3874c53d6381ca239.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-72252d73220fa3cd856677888cee1635.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-72536a3d71b694a0d53dd90ddceae41e.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-726303e0774b4e678bff8c2deb6ca603.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-733171b4ffcd17ea1fe1c0ba627173bf.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-739bc1a567439c7cffcd1614644593d2.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-73e309718fd16cea44b4d54a33581811.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-7494dc504ae00ee9cd0505f990f88c5d.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-74e2263a91439c25b91d5132ce9f4d62.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-761d05e3cd968cf574166867998ef06a.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-7718fe60986d8b42b1be9c5ace5ccf25.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-774d4f764a1299da5d28ec2f2ffe0d69.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-79d494361ae093b69e74ee9dbe65bfd4.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-79f007c1c6d07557120982951ea67998.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-7a07ddc0f0c0f5f4a9bad6ee3dda66b5.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-7ab2bed91166a9dca83a5ebfbe2a7f38.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-7ccce86603f80a099ddb0cb21d4ae3e3.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-7e4bde7e9c7f84cd34d8a845e384c746.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-7e929f262f30c8ee78bf398150b1a7cd.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-7eb9fffd1aa890d07d0f88cc82e6cfe4.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-7f855356ab893b0d2b9c1c83b8116f0e.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-829615148e6357d826b9242eb7fbbd1e.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-866fa7613df6b3fd272bcfd4530c0bb9.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-87599f94b6cc129d505b375798d0d751.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-8c2f33cee3993174f7e87c28e4bf42ee.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-8d3bcabb847b56243b16afe62adaaf21.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-8de5b863cb50dfefdd07cb11c774d579.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-8e9f97f01034820170065b2921b4fb5e.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-8f476c4c99813d57cbe6eca4727388ad.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-903bb6865f3452e2fda42e3a25547bc5.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-91ddb2969bf2d31ba02ad82998d1314c.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-938d90c10ff8c20386af7f242c05d6b0.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-93fc8f28a33234bcadf1527cafabd502.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-95429962233afd82db1c27df1500a28c.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-9544732d2e62d1a429674f8ee41b5d3a.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-9592bfc861f07bcb8d75c196b370e548.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-95bfd249da4902577b4b7d76ebdd0b44.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-968cffdc8ee679da094e77ebf50f58ef.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-97f7f48ce90c9429bf32ae51469db74d.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-982b630266d87db93d2539affb1275c6.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-98f2ad84457de7f3740d9920b8fa8667.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-99a16ef6a64934d5781933dbd9c46b2e.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-9cfb2a77a4e45025105ad29a1748b90d.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-9d81066dd2b337c938df6e90380a00dc.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-9eb5a99df4e76ac3363453ac9ca288b1.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-a004ddfcb26e67bd6e678c8ed19e25ce.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-a0ca5df4258213d7fc9fce80f65ce760.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-a1f916d6039285c4ffb900cd654e418f.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-a203b91dad570bf05a58c3c3ddb529bf.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-a365e82ed54697a52f27adcea1315fe8.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-a4c34be6d42152e64b0df90bc4607f64.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-a7accba310e821da5505f71c03b76bdb.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-aa0d470430e6391eca720c7cfa44446f.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-aa5c9ca6cf4fba00433b7aa3fa10671a.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-ac9ceb44437becc3e9c4dbfebab7fc2d.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-b1220a3c61f85cc0408deedb4c5f57a2.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-b358f7a51ece39a3247942b1feabdb29.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-b57aaedfd8ebdf3931f25119dc6a5eb2.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-b5c1596551c256e0e9cf02028595b092.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-b6d128682ee29e471486354d486a1b90.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-b6fd38ca30869792244804b04bc058da.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-b7d203b051eff504ff59ddca7576b6a9.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-b96d9226ce77ec94ceca043d712182e6.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-ba3de316d63c7e339987b16f41a0b879.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-bafff7a14c27403dcc6cf1432e8ea836.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-bd77e3c7f9e0b072d96af37f73d1aa32.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-be549ab72f0719d606a5c01e2c0219b6.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-c16ed9740b85badf16e86ea782a3062f.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-c1f94158256bb1f3bf665b053d895af9.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-c40533fdf4cc57177b12803598af7e59.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-c4a687ac4f0c2766eefc9f77ed99cddf.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-c69f61a4ab18d0488c8d1fc12e7028e8.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-c8b71798409ccc126ee264a00aadcf21.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-c99eda15fc26a2941579560f76c3a5cf.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-cb17fc3db95f6d139afc9d31a8e93293.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-cbaaefaaf326668277aa24dfa93c4d28.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-cd145ce4a0ea18469358df53c207bc1b.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-cdbce89e82cc1ab53a2decbf5819278f.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-ce4884f96f11589608b76b726a755803.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-cf2cc71752631e579e35b0e423bf2638.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-cf6ff4e0f491ca0cf3038187a997b9b4.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-cfb211578629b7e8153b37240de6a9d5.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-d0cf73942fea1c74edbdf0b3011f4656.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-d2666cbed13462c5dc36fa2f15c202ca.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-d3716376641d615e2995605b29bca7b6.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-dac48066b5883d8b4551fc584f0c2a3e.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-dbea1af6dcd9860be40c3d18254338f5.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-e11567fd2accf9957cd0d3c2be937d87.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-e2ead7ea7da0437f085f42ffc05f8d13.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-e3fcf5180fd466c8915c4e8069491054.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-e480d9c614742d05f0e78f274f1e69e6.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-e4bca6cfa53e499cae0a6be4894a90e9.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-e51ef413167c6e14e0c0fdcc585f2fc9.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-e5f453bb04da18eed01675eeebd88bf8.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-e656f091b9dc4709722c9f4b84d3c797.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-ec181b795ac1fb5a50d700b6e996d745.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-ee8bae97908d5147b423f77ad0d3c1bb.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-f0f13b5c60e0af5553bd359f5513be1b.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-f2b54d4e7be0eaefe1c2c56836fa5368.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-f56414bf9bced67990def8660e306759.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-f5d079153c99a25b9be5b8583c4cc8a7.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-f6032fc06eb20480f096199713f70885.woff2 +0 -0
- package/dist/stage/fonts/Xiaolai/Xiaolai-Regular-f8ee5d36068a42b51d0e4a1116cfcec1.woff2 +0 -0
- package/dist/ui/dev/dev-page.js +5 -5
- package/dist/ui/kid/kid-page.js +2 -0
- package/dist/ui/kid/offline-sw.d.ts +1 -0
- package/dist/ui/kid/offline-sw.js +42 -0
- package/dist/ui/parent/parent-home-page.js +9 -6
- package/install.ps1 +67 -0
- package/install.sh +84 -0
- package/package.json +15 -10
- package/skills/cotutor-analyze/SKILL.md +1 -1
- package/skills/cotutor-analyze/references//345/221/275/344/273/244/344/270/216/346/226/207/344/273/266.md +168 -10
- package/skills/cotutor-home/SKILL.md +1 -1
- package/skills/cotutor-home/references//345/221/275/344/273/244.md +75 -7
- package/skills/cotutor-tune/SKILL.md +8 -8
- package/skills/cotutor-tune/references//345/255/227/346/256/265.md +164 -10
- package/skills/cotutor-tutor/SKILL.md +1 -1
package/dist/app/cli/usage.js
CHANGED
|
@@ -1,38 +1,167 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
1
|
+
/**
|
|
2
|
+
* 帮助与参数检查,都从命令表(commands.ts)来:顶层帮助只列命令和一句话,参数、例子在 cotutor <命令> --help。
|
|
3
|
+
* 纯函数、不碰 I/O:技能生成(app/skills/*-doc.ts)和测试都 import 它,不能把 CLI 带进去。
|
|
4
|
+
*/
|
|
5
|
+
import { COMMANDS, GROUP_TITLE, commandSpec } from "./commands.js";
|
|
6
|
+
const WORKSPACE_DESC = '哪个孩子的 cotutor 文件夹(缺省:COTUTOR_WORKSPACE → 当前目录往上找 → ~/.config/cotutor/config.json → ~/cotutor/ 下唯一的那个)';
|
|
7
|
+
const SANDBOX_DESC = '在试用副本里跑(旁边的 .sandbox/,写的东西不进孩子的记录;--fresh 重新分一份)';
|
|
8
|
+
/** 顶层帮助;all 时连开发与调试的命令也列 */
|
|
9
|
+
export function topHelp(opts = {}) {
|
|
10
|
+
const groups = opts.all ? ['setup', 'daily', 'custom', 'debug'] : ['setup', 'daily', 'custom'];
|
|
11
|
+
const width = Math.max(...COMMANDS.map((c) => c.name.length)) + 2;
|
|
12
|
+
const out = ['cotutor — 家里的 AI 老师团', '', '用法:cotutor <命令> [选项]'];
|
|
13
|
+
for (const g of groups) {
|
|
14
|
+
out.push('', GROUP_TITLE[g]);
|
|
15
|
+
for (const c of COMMANDS.filter((x) => x.group === g && !x.hidden))
|
|
16
|
+
out.push(` ${pad(c.name, width)}${c.summary}`);
|
|
17
|
+
}
|
|
18
|
+
out.push('', '常用选项:', ' --workspace <目录> 选哪个孩子(缺省自动找)', ' --json 机器可读的输出', ' --sandbox 在试用副本里跑,不进孩子的记录', ' --version 版本号', '各命令认哪些,看它的帮助;不认的选项、多余的参数都报错,不会悄悄忽略。', '退出码:0 成功 · 1 没通过(体检、检查有要改的) · 2 用法错 · 4 内部错误', '', '参数和例子:cotutor <命令> --help');
|
|
19
|
+
if (!opts.all)
|
|
20
|
+
out.push(`开发与调试的命令(${COMMANDS.filter((c) => c.group === 'debug' && !c.hidden).map((c) => c.name).join('、')}):cotutor --help --all`);
|
|
21
|
+
return `${out.join('\n')}\n`;
|
|
22
|
+
}
|
|
23
|
+
/** 一条命令的全部选项(连同它认的全局选项),帮助和检查共用 */
|
|
24
|
+
function flagsOf(c, opts = {}) {
|
|
25
|
+
const out = [...(c.flags ?? [])];
|
|
26
|
+
const place = opts.place !== false;
|
|
27
|
+
if (c.workspace)
|
|
28
|
+
out.push({ name: 'workspace', value: '<目录>', desc: WORKSPACE_DESC, ...(place ? {} : { hidden: true }) });
|
|
29
|
+
if (c.sandbox)
|
|
30
|
+
out.push({ name: 'sandbox', desc: SANDBOX_DESC, ...(place ? {} : { hidden: true }) }, { name: 'fresh', desc: '', hidden: true });
|
|
31
|
+
if (c.json)
|
|
32
|
+
out.push({ name: 'json', desc: '机器可读的输出', ...(Array.isArray(c.json) ? { subs: c.json } : {}) });
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
/** 终端里占几格:中文、全角两格 */
|
|
36
|
+
const cells = (s) => [...s].reduce((n, ch) => n + (/[ᄀ-ᅟ⺀-가-힣豈-︰-﹏-⦆¢-₩]/.test(ch) ? 2 : 1), 0);
|
|
37
|
+
const pad = (s, width) => s + ' '.repeat(Math.max(0, width - cells(s)));
|
|
38
|
+
/** 帮助里旗标说明前面的 [install];'' 是不带子命令的那种 */
|
|
39
|
+
const subsTag = (subs) => `[${subs.map((s) => (s === '' ? '不带子命令' : s)).join('、')}] `;
|
|
40
|
+
/** 报错里说「只给谁用」 */
|
|
41
|
+
const subsWho = (c, subs) => subs.map((s) => (s === '' ? `cotutor ${c.name}(不带子命令)` : `${c.name} ${s}`)).join('、');
|
|
42
|
+
/** cotutor <命令> --help;place: false 不列 --workspace / --sandbox(技能参考里统一说一次) */
|
|
43
|
+
export function commandHelp(name, opts = {}) {
|
|
44
|
+
const c = commandSpec(name);
|
|
45
|
+
if (!c)
|
|
46
|
+
return topHelp();
|
|
47
|
+
const out = [`cotutor ${c.name} — ${c.summary}`, '', '用法:', ...c.usage.map((u) => ` ${u}`)];
|
|
48
|
+
const shown = flagsOf(c, opts).filter((f) => !f.hidden);
|
|
49
|
+
if (shown.length) {
|
|
50
|
+
const label = (f) => `--${f.name}${f.value ? ` ${f.value}` : ''}`;
|
|
51
|
+
const width = Math.min(26, Math.max(...shown.map((f) => cells(label(f)))) + 2);
|
|
52
|
+
out.push('', '选项:');
|
|
53
|
+
for (const f of shown) {
|
|
54
|
+
const l = label(f);
|
|
55
|
+
out.push(` ${cells(l) >= width ? `${l}\n ${' '.repeat(width)}` : pad(l, width)}${f.subs ? subsTag(f.subs) : ''}${f.desc}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (c.notes?.length)
|
|
59
|
+
out.push('', '说明:', ...c.notes.map((n) => ` - ${n}`));
|
|
60
|
+
if (c.effects?.length)
|
|
61
|
+
out.push('', '注意:', ...c.effects.map((n) => ` - ${n}`));
|
|
62
|
+
out.push('', '例子:', ...c.examples.map((e) => ` ${e}`));
|
|
63
|
+
return `${out.join('\n')}\n`;
|
|
64
|
+
}
|
|
65
|
+
/** 技能里的命令参考:这几条命令各自的帮助;--workspace、--sandbox 在开头说一次 */
|
|
66
|
+
export function commandsReference(names) {
|
|
67
|
+
return [
|
|
68
|
+
'这些命令都认 --workspace <目录>(在 workspace 根跑可以不写)和 --sandbox(在试用副本里跑,不进孩子的记录)。',
|
|
69
|
+
...names.map((n) => commandHelp(n, { place: false }).trimEnd()),
|
|
70
|
+
].join('\n\n');
|
|
71
|
+
}
|
|
72
|
+
/** 编辑距离,给打错的字找最像的 */
|
|
73
|
+
function distance(a, b) {
|
|
74
|
+
const d = Array.from({ length: a.length + 1 }, (_, i) => [i, ...Array(b.length).fill(0)]);
|
|
75
|
+
for (let j = 1; j <= b.length; j++)
|
|
76
|
+
d[0][j] = j;
|
|
77
|
+
for (let i = 1; i <= a.length; i++) {
|
|
78
|
+
for (let j = 1; j <= b.length; j++) {
|
|
79
|
+
d[i][j] = Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
80
|
+
// 两个字母打反了(josn → json)算一步
|
|
81
|
+
if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1])
|
|
82
|
+
d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + 1);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return d[a.length][b.length];
|
|
86
|
+
}
|
|
87
|
+
function closest(word, candidates) {
|
|
88
|
+
let best;
|
|
89
|
+
let score = Infinity;
|
|
90
|
+
for (const c of candidates) {
|
|
91
|
+
const s = c.startsWith(word) || word.startsWith(c) ? 1 : distance(word, c);
|
|
92
|
+
if (s < score) {
|
|
93
|
+
score = s;
|
|
94
|
+
best = c;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return score <= Math.max(1, Math.floor(word.length / 3)) ? best : undefined;
|
|
98
|
+
}
|
|
99
|
+
/** 不认识的命令:一句话,带最像的那个 */
|
|
100
|
+
export function unknownCommand(cmd) {
|
|
101
|
+
const near = closest(cmd, COMMANDS.filter((c) => !c.hidden).map((c) => c.name));
|
|
102
|
+
return `没有 '${cmd}' 这条命令${near ? `,是不是 cotutor ${near}?` : ''}`;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 照命令表检查参数:不认识的旗标、用错子命令的旗标、不认识的子命令、多余的参数。
|
|
106
|
+
* 通过返回 null,不通过返回一句话(调用方补「看 cotutor <命令> --help」)。命令本身认不认识由调用方先判。
|
|
107
|
+
*/
|
|
108
|
+
export function checkArgs(c, positionals, flags) {
|
|
109
|
+
const sub = positionals[0];
|
|
110
|
+
if (c.subs && (sub !== undefined || c.subRequired) && !c.subs.includes(sub ?? '') && !c.hiddenSubs?.includes(sub ?? '')) {
|
|
111
|
+
const near = sub === undefined ? undefined : closest(sub, c.subs);
|
|
112
|
+
return `${c.name} 后面跟 ${c.subs.join(' / ')}${c.subRequired ? ' 之一' : ''}${sub === undefined ? '' : `,不认识 '${sub}'`}${near ? `,是不是 ${near}?` : ''}`;
|
|
113
|
+
}
|
|
114
|
+
if (positionals.length > c.maxArgs) {
|
|
115
|
+
const extra = positionals[c.maxArgs];
|
|
116
|
+
return c.maxArgs === 0 ? `${c.name} 不带参数,多了 '${extra}'` : `多余的参数 '${extra}':${c.name} 最多 ${c.maxArgs} 个${extra.includes(' ') ? '(带空格的值要加引号)' : ''}`;
|
|
117
|
+
}
|
|
118
|
+
const known = flagsOf(c);
|
|
119
|
+
const actualSub = c.subs?.includes(sub ?? '') || c.hiddenSubs?.includes(sub ?? '') ? (sub ?? '') : '';
|
|
120
|
+
for (const key of Object.keys(flags)) {
|
|
121
|
+
// --sandbox / --fresh 由 main 自己说清楚(这条命令为什么不用试用副本),这里不抢
|
|
122
|
+
if (key === 'help' || key === 'all' || key === 'version' || key === 'sandbox' || key === 'fresh')
|
|
123
|
+
continue;
|
|
124
|
+
const f = known.find((x) => x.name === key);
|
|
125
|
+
if (!f) {
|
|
126
|
+
const near = closest(key, known.filter((x) => !x.hidden).map((x) => x.name));
|
|
127
|
+
return `${c.name} 不认识 --${key}${near ? `,是不是 --${near}?` : ''}`;
|
|
128
|
+
}
|
|
129
|
+
if (f.subs && !f.subs.includes(actualSub))
|
|
130
|
+
return `--${key} 只给 ${subsWho(c, f.subs)} 用`;
|
|
131
|
+
if (f.value && flags[key] === true && key !== 'force')
|
|
132
|
+
return `--${key} 要一个值:--${key} ${f.value}`;
|
|
133
|
+
}
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
/** 一行 cotutor 命令(文档、测试里写的)照命令表对不对得上;对得上返回 null */
|
|
137
|
+
export function checkCommandLine(line) {
|
|
138
|
+
const words = line.trim().split(/\s+/);
|
|
139
|
+
if (words[0] !== 'cotutor' && words[0] !== 'cotutor.cmd')
|
|
140
|
+
return `不是 cotutor 命令:${line}`;
|
|
141
|
+
const [cmd, ...rest] = words.slice(1);
|
|
142
|
+
if (cmd === '--version' || cmd === '--help')
|
|
143
|
+
return null;
|
|
144
|
+
const c = commandSpec(cmd);
|
|
145
|
+
if (!c)
|
|
146
|
+
return unknownCommand(cmd);
|
|
147
|
+
if (rest.includes('--help'))
|
|
148
|
+
return null;
|
|
149
|
+
const positionals = [];
|
|
150
|
+
const flags = {};
|
|
151
|
+
for (let i = 0; i < rest.length; i++) {
|
|
152
|
+
const w = rest[i];
|
|
153
|
+
if (!w.startsWith('--')) {
|
|
154
|
+
positionals.push(w);
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
const key = w.slice(2).split('=')[0];
|
|
158
|
+
const spec = flagsOf(c).find((f) => f.name === key);
|
|
159
|
+
if (spec?.value && rest[i + 1] !== undefined && !rest[i + 1].startsWith('--'))
|
|
160
|
+
flags[key] = rest[++i];
|
|
161
|
+
else
|
|
162
|
+
flags[key] = true;
|
|
163
|
+
}
|
|
164
|
+
return checkArgs(c, positionals, flags);
|
|
165
|
+
}
|
|
166
|
+
/** 旧名:顶层帮助 */
|
|
167
|
+
export const USAGE = topHelp();
|
package/dist/app/http/access.js
CHANGED
|
@@ -23,7 +23,7 @@ export const PIN_RE = /^\d{4,8}$/;
|
|
|
23
23
|
const MAX_FAILS = 5;
|
|
24
24
|
const LOCK_MS = 60_000;
|
|
25
25
|
/** 孩子端的路径:设了 PIN 也开;别的都要凭证。改孩子端加了新接口要来这里登记(tests/access.test.ts 盯着孩子端页面源码里用到的每条) */
|
|
26
|
-
const KID_EXACT = new Set(['/', '/manifest.webmanifest', '/favicon.svg', '/favicon-32.png', '/favicon.ico', '/api/health', '/api/auth', '/dictation', '/dictation/', '/talk', '/talk/', '/api/dictation', '/api/talk']);
|
|
26
|
+
const KID_EXACT = new Set(['/', '/sw.js', '/manifest.webmanifest', '/favicon.svg', '/favicon-32.png', '/favicon.ico', '/api/health', '/api/auth', '/dictation', '/dictation/', '/talk', '/talk/', '/api/dictation', '/api/talk']);
|
|
27
27
|
const KID_PREFIX = ['/kid/', '/stage/', '/api/kid/', '/api/audio/', '/api/bundles/', '/api/dictation/', '/api/talk/', '/api/live/'];
|
|
28
28
|
export function isKidPath(p) {
|
|
29
29
|
return KID_EXACT.has(p) || KID_PREFIX.some((x) => p.startsWith(x)) || /^\/icon-\d{2,4}\.png$/.test(p);
|
package/dist/app/http/app.js
CHANGED
|
@@ -37,6 +37,7 @@ import { knownLatest, knownNotes } from "../machine/update.js";
|
|
|
37
37
|
import { isNewer } from "../../shared/upgrade.js";
|
|
38
38
|
import { qrPage } from "../../ui/parent/qr-page.js";
|
|
39
39
|
import { kidPage } from "../../ui/kid/kid-page.js";
|
|
40
|
+
import { KID_SW_JS } from "../../ui/kid/offline-sw.js";
|
|
40
41
|
import { parentPage } from "../../ui/parent/parent-page.js";
|
|
41
42
|
import { kidHomeView } from "../../runtime/home/store.js";
|
|
42
43
|
import { photosOf } from "../../runtime/kid-input.js";
|
|
@@ -624,7 +625,7 @@ export async function route(method, path, ctx, body, who = 'local', client = {})
|
|
|
624
625
|
}
|
|
625
626
|
return { status: 405, json: { error: 'method_not_allowed' } };
|
|
626
627
|
}
|
|
627
|
-
// 政策文件补缺(与 cotutor
|
|
628
|
+
// 政策文件补缺(与 cotutor refresh --config 同一条路):只加缺的出厂件,家长写过的值不动
|
|
628
629
|
if (p === '/api/config/migrate' && method === 'POST') {
|
|
629
630
|
const r = await upgradeConfig(ws.root);
|
|
630
631
|
await ctx.reload();
|
|
@@ -1070,6 +1071,9 @@ export async function route(method, path, ctx, body, who = 'local', client = {})
|
|
|
1070
1071
|
// 主屏幕(iPad「添加到主屏幕」):清单与图标都按标题现生成,没有静态资源
|
|
1071
1072
|
if (p === '/manifest.webmanifest')
|
|
1072
1073
|
return { status: 200, json: webManifest(ws.config.title), contentType: 'application/manifest+json; charset=utf-8' };
|
|
1074
|
+
// 孩子端的离线页(offline-sw.ts):平板打开时电脑关了、睡着了,给「老师们还没到」,不给浏览器的报错
|
|
1075
|
+
if (p === '/sw.js')
|
|
1076
|
+
return { status: 200, body: Buffer.from(KID_SW_JS), contentType: 'text/javascript; charset=utf-8', cacheControl: 'no-cache' };
|
|
1073
1077
|
const icon = /^\/icon-(\d{2,4})\.png$/.exec(p);
|
|
1074
1078
|
if (icon) {
|
|
1075
1079
|
const n = Number(icon[1]);
|
|
@@ -26,6 +26,7 @@ import { shownAvatar } from "./avatars.js";
|
|
|
26
26
|
import { qrNotes, qrSvg } from "../../ui/shared/qr-svg.js";
|
|
27
27
|
import { readDevices } from "../../runtime/journal/kid-log.js";
|
|
28
28
|
import { parentSetupRoute } from "./parent-setup.js";
|
|
29
|
+
import { rootCaFile } from "../cli/root-ca.js";
|
|
29
30
|
const isObj = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
30
31
|
const bad = (message) => ({ status: 400, json: { error: 'bad_request', message } });
|
|
31
32
|
/** 家长端列的老师:有脸的(-tutor 结尾)、开着的;藏着的也列(家长要能把他放回首页) */
|
|
@@ -154,9 +155,13 @@ async function kidQr(ctx) {
|
|
|
154
155
|
const devices = Object.values(await readDevices(ctx.ws));
|
|
155
156
|
const last = devices.map((d) => d.last).sort().at(-1) ?? null;
|
|
156
157
|
const parent = { url: `${info.name}parent`, ip: info.ip ? `${info.ip}parent` : null };
|
|
158
|
+
// 装根证书:走同一个端口的 http 那一面(serve.ts 的 plainHandler),平板这时还不信任 https;端口照写,http 缺省是 80
|
|
159
|
+
const caUrl = (u) => { const x = new URL(u); return `http://${x.hostname}:${x.port || '443'}/ca.crt`; };
|
|
160
|
+
const ca = info.https && (await rootCaFile()) ? { url: caUrl(info.name), ip: info.ip ? caUrl(info.ip) : null } : null;
|
|
157
161
|
return {
|
|
158
162
|
ready: true, https: info.https, url: info.name, svg: qrSvg(info.name), ip: info.ip, svgIp: info.ip ? qrSvg(info.ip) : null,
|
|
159
163
|
parent: { ...parent, svg: qrSvg(parent.url), svgIp: parent.ip ? qrSvg(parent.ip) : null },
|
|
164
|
+
ca: ca ? { ...ca, svg: qrSvg(ca.url), svgIp: ca.ip ? qrSvg(ca.ip) : null } : null,
|
|
160
165
|
notes: qrNotes(info.https).slice(1), devices: devices.length, last,
|
|
161
166
|
};
|
|
162
167
|
}
|
package/dist/app/http/stage.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 舞台包的静态文件:dist/stage/(esbuild 打的 stage.js / stage.css / index.html)+ /stage/fonts/(excalidraw
|
|
3
|
-
*
|
|
2
|
+
* 舞台包的静态文件:dist/stage/(esbuild 打的 stage.js / stage.css / index.html)+ /stage/fonts/(excalidraw 的字体)。
|
|
3
|
+
* 字体由 build:stage 拷进 dist/stage/fonts/,npm 装的包里没有 excalidraw(它只在打包时用);开发时没打包就从 node_modules 现取。
|
|
4
4
|
* serve 与 mock 共用;没打包(开发时没跑 pnpm run build:stage)→ null,页面开重卡舞台时什么都不出现,doctor 点名。
|
|
5
5
|
*/
|
|
6
6
|
import { existsSync } from 'node:fs';
|
package/dist/app/mock/mock.js
CHANGED
|
@@ -74,6 +74,7 @@ import { kidThreads } from "../../runtime/kid-view.js";
|
|
|
74
74
|
import { ICON_SIZES, appIconPng, webManifest } from "../../ui/shared/icon.js";
|
|
75
75
|
import { faviconResponse } from "../../ui/shared/favicon.js";
|
|
76
76
|
import { kidPage } from "../../ui/kid/kid-page.js";
|
|
77
|
+
import { KID_SW_JS } from "../../ui/kid/offline-sw.js";
|
|
77
78
|
import { parentPage } from "../../ui/parent/parent-page.js";
|
|
78
79
|
import { arrangeHome, homeOwners, kidButtons, kidTiles, parseHome } from "../../runtime/home/home.js";
|
|
79
80
|
import { packageTheme } from "../cli/themes.js";
|
|
@@ -644,6 +645,8 @@ export function createMock(opts = {}) {
|
|
|
644
645
|
return { status: 200, html: VOICE_GALLERY_PAGE };
|
|
645
646
|
if (p === '/manifest.webmanifest')
|
|
646
647
|
return { status: 200, json: webManifest(title), contentType: 'application/manifest+json; charset=utf-8' };
|
|
648
|
+
if (p === '/sw.js')
|
|
649
|
+
return { status: 200, body: Buffer.from(KID_SW_JS), contentType: 'text/javascript; charset=utf-8', cacheControl: 'no-cache' };
|
|
647
650
|
// 家长端「记录」:自己的一页(parent-page.ts);清单接口照真服务(答案不剥,第一节带一条给家长的尾巴与记忆)。mock 没有工作台 /dev
|
|
648
651
|
if (p === '/parent')
|
|
649
652
|
return { status: 200, html: parentPage(title) };
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* cotutor-analyze 技能的生成部分(2026-09-15):references/命令与文件.md
|
|
2
|
+
* cotutor-analyze 技能的生成部分(2026-09-15):references/命令与文件.md 从命令表(app/cli/commands.ts,经 usage.ts 的 commandsReference)与对话文件的命名规则(runtime/journal/conversation.ts
|
|
3
3
|
* conversationFiles)现生成,scripts/gen-skills.ts 写进包根 skills/cotutor-analyze/,tests/skills.test.ts 断言入库的和生成的一致——
|
|
4
4
|
* 技能里的命令与文件名永远和代码同源。SKILL.md 本体(怎么查、禁区)是手写的。
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { commandsReference } from "../cli/usage.js";
|
|
7
7
|
import { conversationFiles } from "../../schema/index.js";
|
|
8
8
|
export const ANALYZE_SKILL = 'cotutor-analyze';
|
|
9
9
|
/** 分析用的那几条命令(按用法文本里的第二个词挑) */
|
|
10
10
|
const ANALYZE_COMMANDS = ['show', 'pack', 'replay', 'compare', 'trace', 'doctor', 'send', 'rate', 'bookkeep'];
|
|
11
11
|
export function analyzeReferenceDoc() {
|
|
12
|
-
const cmds = USAGE.split('\n').filter((l) => {
|
|
13
|
-
const m = /^\s+cotutor (\S+)/.exec(l);
|
|
14
|
-
return m !== null && ANALYZE_COMMANDS.includes(m[1]);
|
|
15
|
-
});
|
|
16
12
|
const f = conversationFiles('conversations', '<老师>', '<日期>');
|
|
17
13
|
const rows = [
|
|
18
14
|
[f.index, '一天的索引:每条消息物化了 text / kidText / section(卡与讲稿)/ tools(读了什么)/ timing / tokens(这轮老师用的 token:输入 / 输出)/ warnings / bookkeeping;顶层 sessions / ratings / booked(老数据里还有 costUsd,是 claude 时代的美元,不用管)'],
|
|
@@ -25,10 +21,10 @@ export function analyzeReferenceDoc() {
|
|
|
25
21
|
];
|
|
26
22
|
return `# 命令与文件(机器生成,别改)
|
|
27
23
|
|
|
28
|
-
## 分析用的命令(在 workspace
|
|
24
|
+
## 分析用的命令(在 workspace 根跑;每条就是 cotutor <命令> --help 的内容)
|
|
29
25
|
|
|
30
26
|
\`\`\`
|
|
31
|
-
${
|
|
27
|
+
${commandsReference(ANALYZE_COMMANDS)}
|
|
32
28
|
\`\`\`
|
|
33
29
|
|
|
34
30
|
## 一轮的文件(conversations/ 下;回放的在 evals/ 下,同一套名字)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* tests/skills.test.ts 断言入库的和生成的一致。首页语法.md 从首页能用的卡的 card.md 拼(首页专属的全文,和板书共用的只给一句 + 指向 cotutor-board),
|
|
4
4
|
* <kind>.md 是首页专属卡的协议全文,命令.md 从 CLI 用法文本取。SKILL.md 本体(流程、铁律)是手写的。
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { commandsReference } from "../cli/usage.js";
|
|
7
7
|
import { BUTTON_LABEL_MAX, TUTOR_BUTTONS_MAX, kindsFor } from "../../board/cards/index.js";
|
|
8
8
|
import { PACKAGE_CARDS_DIR, readCardDoc } from "../../board/cards/docs.js";
|
|
9
9
|
export const HOME_SKILL = 'cotutor-home';
|
|
@@ -81,16 +81,12 @@ for: 2026-09-18
|
|
|
81
81
|
`;
|
|
82
82
|
}
|
|
83
83
|
export function homeCommandsDoc() {
|
|
84
|
-
const cmds = USAGE.split('\n').filter((l) => {
|
|
85
|
-
const m = /^\s+cotutor (\S+)/.exec(l);
|
|
86
|
-
return m !== null && HOME_COMMANDS.includes(m[1]);
|
|
87
|
-
});
|
|
88
84
|
return `# 命令(机器生成,别改)
|
|
89
85
|
|
|
90
|
-
在 workspace
|
|
86
|
+
在 workspace 根跑;每条就是 cotutor <命令> --help 的内容。
|
|
91
87
|
|
|
92
88
|
\`\`\`
|
|
93
|
-
${
|
|
89
|
+
${commandsReference(HOME_COMMANDS)}
|
|
94
90
|
\`\`\`
|
|
95
91
|
|
|
96
92
|
## 文件
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* tests/skills.test.ts 断言入库的和生成的一致——改老师团时能改哪些字段、缺省是什么,永远和契约同源。SKILL.md 本体(三条路子、禁区)是手写的。
|
|
5
5
|
*/
|
|
6
6
|
import { z } from 'zod';
|
|
7
|
-
import {
|
|
7
|
+
import { commandsReference } from "../cli/usage.js";
|
|
8
8
|
import { POLICY_DEFAULTS, PolicySchema, TutorSchema } from "../../schema/config.js";
|
|
9
9
|
import { AGENT_FRONTMATTER_KEYS } from "../../runtime/agent-file.js";
|
|
10
10
|
export const TUNE_SKILL = 'cotutor-tune';
|
|
11
|
-
const TUNE_COMMANDS = ['add', 'add-theme', '
|
|
11
|
+
const TUNE_COMMANDS = ['add', 'add-theme', 'refresh', 'reset', 'doctor', 'pack', 'replay', 'compare', 'show'];
|
|
12
12
|
function unwrap(s) {
|
|
13
13
|
let cur = s;
|
|
14
14
|
for (let i = 0; i < 5; i++) {
|
|
@@ -39,10 +39,6 @@ function rows(shape, defaults, prefix = '') {
|
|
|
39
39
|
return out;
|
|
40
40
|
}
|
|
41
41
|
export function tuneReferenceDoc() {
|
|
42
|
-
const cmds = USAGE.split('\n').filter((l) => {
|
|
43
|
-
const m = /^\s+cotutor (\S+)/.exec(l);
|
|
44
|
-
return m !== null && TUNE_COMMANDS.includes(m[1]);
|
|
45
|
-
});
|
|
46
42
|
// tutors 字段的缺省从 zod 的 .default() 取(enabled / hidden);display 是必需的,给个占位再抹掉
|
|
47
43
|
const tutorDefaults = TutorSchema.parse({ display: 'x' });
|
|
48
44
|
delete tutorDefaults.display;
|
|
@@ -68,10 +64,10 @@ ${tutorRows.join('\n')}
|
|
|
68
64
|
|---|---|---|---|
|
|
69
65
|
${policyRows.join('\n')}
|
|
70
66
|
|
|
71
|
-
## 相关命令(
|
|
67
|
+
## 相关命令(每条就是 cotutor <命令> --help 的内容)
|
|
72
68
|
|
|
73
69
|
\`\`\`
|
|
74
|
-
${
|
|
70
|
+
${commandsReference(TUNE_COMMANDS)}
|
|
75
71
|
\`\`\`
|
|
76
72
|
`;
|
|
77
73
|
}
|
package/dist/app/workspace.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ConfigError, UsageError } from '../shared/errors.ts';
|
|
2
|
-
import { redactDeep, redactHome } from '../shared/home.ts';
|
|
2
|
+
import { expandPath, redactDeep, redactHome } from '../shared/home.ts';
|
|
3
3
|
import { type RootSource, type SandboxMark, type Workspace } from '../schema/workspace.ts';
|
|
4
4
|
import { type CotutorConfig } from '../schema/index.ts';
|
|
5
|
-
export { ConfigError, UsageError, redactDeep, redactHome };
|
|
5
|
+
export { ConfigError, UsageError, expandPath, redactDeep, redactHome };
|
|
6
6
|
export type { RootSource, Workspace };
|
|
7
7
|
export declare const CONFIG_FILE = "cotutor.json";
|
|
8
8
|
export declare const USER_CONFIG: string;
|
|
@@ -13,13 +13,26 @@ export interface ResolvedRoot {
|
|
|
13
13
|
root: string;
|
|
14
14
|
source: RootSource;
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
/** p 是 dir 本身或在它里面 */
|
|
17
|
+
export declare function isInside(p: string, dir: string): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* vault 与 workspace 分开:谁也不在谁里面(2026-11-09)。vault 是家长的长期记忆,workspace 是机器的运行记录;
|
|
20
|
+
* 混在一起时 Obsidian 里满是 agents/、conversations/,扫 vault 要走遍对话与照片,备份恢复把家长的笔记跟着 workspace 一起盖掉。
|
|
21
|
+
* 旧版 init 不写 paths.vault(缺省 `.`,vault 就是 workspace 根),那样的照旧读得进来,doctor 的 vault.separate 提一句。
|
|
22
|
+
*/
|
|
23
|
+
export declare const vaultSeparate: (root: string, vault: string) => boolean;
|
|
24
|
+
/** init 缺省的 vault:workspace 旁边的 <目录名>-vault(~/cotutor/ming → ~/cotutor/ming-vault;不在「文稿」与 iCloud 里,后台服务读得到) */
|
|
25
|
+
export declare const defaultVaultOf: (root: string) => string;
|
|
26
|
+
/** 写进 cotutor.json 的路径:家目录下的写成 ~/…(输出里不带用户名,换了用户名也对得上),别处写绝对路径 */
|
|
27
|
+
export declare function homePath(abs: string): string;
|
|
17
28
|
/** 读 JSON:不存在 → null;坏 → ConfigError */
|
|
18
29
|
export declare function readJson(file: string): unknown | null;
|
|
19
30
|
/** 从 dir 向上找 cotutor.json,找到返回目录 */
|
|
20
31
|
export declare function findUp(dir: string): string | null;
|
|
21
32
|
/** ~/cotutor/ 下带 cotutor.json 的子目录 */
|
|
22
33
|
export declare function homeWorkspaces(homeRoot?: string): string[];
|
|
34
|
+
/** 这台电脑上认得的孩子:~/cotutor/ 下的,加用户配置指的那个(在别处 --dir 建的) */
|
|
35
|
+
export declare function knownWorkspaces(): string[];
|
|
23
36
|
export interface ResolveOptions {
|
|
24
37
|
env?: NodeJS.ProcessEnv;
|
|
25
38
|
cwd?: string;
|
package/dist/app/workspace.js
CHANGED
|
@@ -9,24 +9,35 @@
|
|
|
9
9
|
import { readFileSync, readdirSync, statSync } from 'node:fs';
|
|
10
10
|
import { readFile, writeFile, rename } from 'node:fs/promises';
|
|
11
11
|
import { ConfigError, UsageError } from "../shared/errors.js";
|
|
12
|
-
import { redactDeep, redactHome } from "../shared/home.js";
|
|
12
|
+
import { expandPath, redactDeep, redactHome } from "../shared/home.js";
|
|
13
13
|
import { SANDBOX_MARK, SKILLS_DIR, SandboxMarkSchema } from "../schema/workspace.js";
|
|
14
14
|
import { homedir } from 'node:os';
|
|
15
|
-
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
15
|
+
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
16
16
|
import { CotutorConfigSchema, PATH_ROLES, ROLE_DEFAULTS, WORKSPACE_ROLES, explainIssues, } from "../schema/index.js";
|
|
17
17
|
// 挪走了的几样照旧从这里转出(旧的引法不用改)
|
|
18
|
-
export { ConfigError, UsageError, redactDeep, redactHome };
|
|
18
|
+
export { ConfigError, UsageError, expandPath, redactDeep, redactHome };
|
|
19
19
|
export const CONFIG_FILE = 'cotutor.json';
|
|
20
20
|
export const USER_CONFIG = join(homedir(), '.config', 'cotutor', 'config.json');
|
|
21
21
|
/** 机器级自签证书目录(cotutor cert 写 cert.pem + key.pem):证书签的是本机名与局域网 IP,与孩子无关,所以不在 workspace 里 */
|
|
22
22
|
export const USER_CERT_DIR = join(homedir(), '.config', 'cotutor', 'certs');
|
|
23
23
|
export const HOME_ROOT = join(homedir(), 'cotutor');
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
/** p 是 dir 本身或在它里面 */
|
|
25
|
+
export function isInside(p, dir) {
|
|
26
|
+
const r = relative(dir, p);
|
|
27
|
+
return r === '' || (r !== '..' && !r.startsWith(`..${sep}`) && !isAbsolute(r));
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* vault 与 workspace 分开:谁也不在谁里面(2026-11-09)。vault 是家长的长期记忆,workspace 是机器的运行记录;
|
|
31
|
+
* 混在一起时 Obsidian 里满是 agents/、conversations/,扫 vault 要走遍对话与照片,备份恢复把家长的笔记跟着 workspace 一起盖掉。
|
|
32
|
+
* 旧版 init 不写 paths.vault(缺省 `.`,vault 就是 workspace 根),那样的照旧读得进来,doctor 的 vault.separate 提一句。
|
|
33
|
+
*/
|
|
34
|
+
export const vaultSeparate = (root, vault) => !isInside(vault, root) && !isInside(root, vault);
|
|
35
|
+
/** init 缺省的 vault:workspace 旁边的 <目录名>-vault(~/cotutor/ming → ~/cotutor/ming-vault;不在「文稿」与 iCloud 里,后台服务读得到) */
|
|
36
|
+
export const defaultVaultOf = (root) => join(dirname(root), `${basename(root)}-vault`);
|
|
37
|
+
/** 写进 cotutor.json 的路径:家目录下的写成 ~/…(输出里不带用户名,换了用户名也对得上),别处写绝对路径 */
|
|
38
|
+
export function homePath(abs) {
|
|
39
|
+
const rel = relative(homedir(), abs);
|
|
40
|
+
return rel && !rel.startsWith('..') && !isAbsolute(rel) ? `~/${rel.split(sep).join('/')}` : abs;
|
|
30
41
|
}
|
|
31
42
|
const isDir = (p) => {
|
|
32
43
|
try {
|
|
@@ -84,6 +95,17 @@ export function homeWorkspaces(homeRoot = HOME_ROOT) {
|
|
|
84
95
|
return [];
|
|
85
96
|
}
|
|
86
97
|
}
|
|
98
|
+
/** 这台电脑上认得的孩子:~/cotutor/ 下的,加用户配置指的那个(在别处 --dir 建的) */
|
|
99
|
+
export function knownWorkspaces() {
|
|
100
|
+
const roots = new Set(homeWorkspaces());
|
|
101
|
+
try {
|
|
102
|
+
const user = readJson(USER_CONFIG);
|
|
103
|
+
if (typeof user?.workspace === 'string' && user.workspace)
|
|
104
|
+
roots.add(expandPath(user.workspace, homedir()));
|
|
105
|
+
}
|
|
106
|
+
catch { /* 用户配置坏了 doctor 去报 */ }
|
|
107
|
+
return [...roots];
|
|
108
|
+
}
|
|
87
109
|
export function resolveRoot(override, opts = {}) {
|
|
88
110
|
const env = opts.env ?? process.env;
|
|
89
111
|
const cwd = resolve(opts.cwd ?? process.cwd());
|
|
@@ -127,7 +127,7 @@ export function homeIssues(doc, ctx) {
|
|
|
127
127
|
if (act && ctx.activities) {
|
|
128
128
|
const got = ctx.activities.get(`${name}/${act.name}`);
|
|
129
129
|
if (!got)
|
|
130
|
-
out.push({ level: 'fix', line, card: n, button: k, text: b.kind === 'lecture' && !b.activity ? `${t.display}的「${b.label}」:看完怎么聊写在 agents/${name}/activities/${LECTURE_ACTIVITY}.md,这份不在(cotutor
|
|
130
|
+
out.push({ level: 'fix', line, card: n, button: k, text: b.kind === 'lecture' && !b.activity ? `${t.display}的「${b.label}」:看完怎么聊写在 agents/${name}/activities/${LECTURE_ACTIVITY}.md,这份不在(cotutor refresh 补出厂的;或按钮下面写一行 activity: <名> 换一个)` : `${t.display}的「${b.label}」:agents/${name}/activities/${act.name}.md 不在(cotutor activity check ${name} 看这位老师有哪些)` });
|
|
131
131
|
else {
|
|
132
132
|
if (got.fixes)
|
|
133
133
|
out.push({ level: 'fix', line, card: n, button: k, text: `${t.display}的「${b.label}」:activity 文件 ${act.name}.md 有 ${got.fixes} 处要改(cotutor activity check ${name} ${act.name})` });
|
package/dist/runtime/runner.js
CHANGED
|
@@ -92,7 +92,7 @@ export async function gatherContext(ws, tutor, input, report) {
|
|
|
92
92
|
pack.rules = TUTOR_RULES_PATH;
|
|
93
93
|
}
|
|
94
94
|
catch {
|
|
95
|
-
pack.rules = `缺:${TUTOR_RULES_PATH} 不在(cotutor
|
|
95
|
+
pack.rules = `缺:${TUTOR_RULES_PATH} 不在(cotutor refresh 补),照你老师文件里的做`;
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
pack.notes.push(...mem.notes);
|
|
@@ -186,7 +186,7 @@ async function systemParts(ws, tutor, policy, pack, act = null) {
|
|
|
186
186
|
return { systemBody: agentBody, activityInSystem: false };
|
|
187
187
|
const guide = await boardGuideOf(ws, tutor);
|
|
188
188
|
if (!guide) {
|
|
189
|
-
pack.boardGuide = `缺:${BOARD_GUIDE_PATH} 不在(cotutor
|
|
189
|
+
pack.boardGuide = `缺:${BOARD_GUIDE_PATH} 不在(cotutor refresh 补),照你会的写`;
|
|
190
190
|
return { systemBody: agentBody, activityInSystem: false };
|
|
191
191
|
}
|
|
192
192
|
pack.boardGuide = BOARD_GUIDE_IN_SYSTEM;
|
package/dist/shared/home.d.ts
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
|
+
/** cotutor.json 里的路径:~ 与 ~/ 是家目录,绝对的照用,相对的相对 base(从 app/workspace.ts 挪来,2026-11-09:托盘不带 zod 也要用) */
|
|
2
|
+
export declare function expandPath(p: string, base: string): string;
|
|
1
3
|
export declare function redactHome(value: string): string;
|
|
2
4
|
export declare function redactDeep<T>(value: T): T;
|
package/dist/shared/home.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
/** 给人看的路径里把家目录换成 $HOME(报错、doctor、--json 输出不带出用户名;从 app/workspace.ts 挪来,2026-10-29) */
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
|
+
import { isAbsolute, join, resolve } from 'node:path';
|
|
4
|
+
/** cotutor.json 里的路径:~ 与 ~/ 是家目录,绝对的照用,相对的相对 base(从 app/workspace.ts 挪来,2026-11-09:托盘不带 zod 也要用) */
|
|
5
|
+
export function expandPath(p, base) {
|
|
6
|
+
if (p === '~')
|
|
7
|
+
return homedir();
|
|
8
|
+
if (p.startsWith('~/'))
|
|
9
|
+
return join(homedir(), p.slice(2));
|
|
10
|
+
return isAbsolute(p) ? p : resolve(base, p);
|
|
11
|
+
}
|
|
3
12
|
export function redactHome(value) {
|
|
4
13
|
const home = homedir();
|
|
5
14
|
return home && value.startsWith(home) ? '$HOME' + value.slice(home.length) : value;
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/stage/fonts/ComicShanns/ComicShanns-Regular-279a7b317d12eb88de06167bd672b4b4.woff2
ADDED
|
Binary file
|
package/dist/stage/fonts/ComicShanns/ComicShanns-Regular-6e066e8de2ac57ea9283adb9c24d7f0c.woff2
ADDED
|
Binary file
|
package/dist/stage/fonts/ComicShanns/ComicShanns-Regular-dc6a8806fa96795d7b3be5026f989a17.woff2
ADDED
|
Binary file
|
package/dist/stage/fonts/ComicShanns/ComicShanns-Regular-fcb0fc02dcbee4c9846b3e2508668039.woff2
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|