cotutor 0.4.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +24 -6
  2. package/dist/app/cli/backup.d.ts +68 -0
  3. package/dist/app/cli/backup.js +243 -0
  4. package/dist/app/cli/doctor-fix.d.ts +18 -0
  5. package/dist/app/cli/doctor-fix.js +70 -0
  6. package/dist/app/cli/doctor.js +19 -2
  7. package/dist/app/cli/init.d.ts +2 -0
  8. package/dist/app/cli/init.js +6 -3
  9. package/dist/app/cli/main.js +117 -2
  10. package/dist/app/cli/report.d.ts +11 -0
  11. package/dist/app/cli/report.js +110 -0
  12. package/dist/app/cli/serve.d.ts +0 -1
  13. package/dist/app/cli/serve.js +14 -0
  14. package/dist/app/cli/service.d.ts +26 -0
  15. package/dist/app/cli/service.js +36 -5
  16. package/dist/app/cli/skeleton.d.ts +1 -1
  17. package/dist/app/cli/skeleton.js +2 -2
  18. package/dist/app/cli/tray.js +6 -4
  19. package/dist/app/cli/update-cmd.d.ts +38 -0
  20. package/dist/app/cli/update-cmd.js +174 -0
  21. package/dist/app/cli/usage.d.ts +1 -1
  22. package/dist/app/cli/usage.js +4 -1
  23. package/dist/app/http/app.d.ts +2 -0
  24. package/dist/app/http/app.js +18 -3
  25. package/dist/app/http/parent-home.js +4 -0
  26. package/dist/app/http/parent-setup.d.ts +19 -0
  27. package/dist/app/http/parent-setup.js +96 -0
  28. package/dist/app/machine/bailian.d.ts +26 -0
  29. package/dist/app/machine/bailian.js +91 -4
  30. package/dist/app/machine/update.d.ts +14 -1
  31. package/dist/app/machine/update.js +35 -14
  32. package/dist/brain/api.js +6 -3
  33. package/dist/memory/vault-notes.d.ts +4 -0
  34. package/dist/memory/vault-notes.js +11 -0
  35. package/dist/realtime/preview.d.ts +16 -0
  36. package/dist/realtime/preview.js +43 -1
  37. package/dist/runtime/live/call.d.ts +2 -0
  38. package/dist/runtime/live/call.js +6 -1
  39. package/dist/shared/upgrade.d.ts +5 -3
  40. package/dist/shared/upgrade.js +8 -4
  41. package/dist/ui/kid/kid-page.js +8 -2
  42. package/dist/ui/parent/parent-home-page.js +67 -3
  43. package/dist/ui/parent/parent-settings-page.js +65 -1
  44. package/package.json +7 -1
  45. package/skills/cotutor-analyze/references//345/221/275/344/273/244/344/270/216/346/226/207/344/273/266.md +1 -1
  46. package/skills/cotutor-tune/references//345/255/227/346/256/265.md +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * 家长端「设置」(/parent/settings):设一次就不常动的。现在只有一项——孩子的平板上,按住说话那一栏放哪边(cotutor.json 的 kid.hand)。
2
+ * 家长端「设置」(/parent/settings):设一次就不常动的。备份和诊断信息也放这(parent-setup.ts)。孩子的平板上,按住说话那一栏放哪边(cotutor.json 的 kid.hand)。
3
3
  * 两张示意图(不是截图,页面现画的 SVG):横着的平板,窄的一栏是老师头像 + 按住说话,宽的一边是写字的白纸;点一张就存。
4
4
  * 孩子端首页的接口带着它(/api/kid/home 的 hand),孩子下次进老师页就换过来;画板那一列工具跟着一起挪。
5
5
  * 零依赖内联脚本,只走 /api/parent/settings(GET 读,PATCH {kid: {hand}} 改)。
@@ -32,6 +32,10 @@ ${BRAND_CSS}
32
32
  .seg > * { flex:1; height:36px; border-radius:9px; font-size:15px; color:var(--dim); display:flex; align-items:center; justify-content:center; text-decoration:none; }
33
33
  .seg > .on { background:#fff; color:var(--ink); font-weight:600; box-shadow:0 1px 2px rgba(0,0,0,.08); }
34
34
  .gh { font-size:13px; color:var(--mute); padding:8px 16px 6px; }
35
+ .acts { display:flex; flex-wrap:wrap; gap:8px; padding:0 3px 12px; }
36
+ .act { display:inline-flex; align-items:center; min-height:44px; padding:0 14px; border:0; border-radius:10px; background:var(--paper, transparent); box-shadow:0 0 0 1px var(--line); color:inherit; font-size:15px; text-decoration:none; cursor:pointer; }
37
+ .act[disabled] { opacity:.5; }
38
+ #rep-text { margin:0 3px 12px; padding:10px 12px; max-height:320px; overflow:auto; border-radius:10px; box-shadow:0 0 0 1px var(--line); font:12px/1.55 ui-monospace,Menlo,Consolas,monospace; white-space:pre-wrap; overflow-wrap:anywhere; }
35
39
  .grp { background:var(--card); border-radius:14px; padding:14px; display:flex; flex-direction:column; gap:12px; }
36
40
  .q { font-size:16px; font-weight:500; padding:0 2px; }
37
41
  .hands { display:grid; grid-template-columns:1fr 1fr; gap:12px; }
@@ -63,6 +67,22 @@ ${BRAND_CSS}
63
67
  <div class="note">平板横着用的时候,老师页上那一栏(老师的头像、按住说话)放在这边,另一边留给写字;画板上那一列工具也跟着放这边。孩子下次进老师页就换过来。</div>
64
68
  </div>
65
69
  </div>
70
+ <div>
71
+ <div class="gh">备份</div>
72
+ <div class="grp">
73
+ <div class="note" id="bk-note">读取中……</div>
74
+ <div class="acts"><button type="button" class="act" id="bk-go">现在备份一份</button></div>
75
+ </div>
76
+ </div>
77
+ <div>
78
+ <div class="gh">遇到问题</div>
79
+ <div class="grp">
80
+ <div class="note">生成一份诊断信息,发给开发者或帮你的 AI 助手,不用来回问。里面没有孩子的对话、照片、录音、档案和 key,名字和 IP 已经抹掉。不会自动发出去,你可以先看一遍。</div>
81
+ <div class="acts"><button type="button" class="act" id="rep-go">生成诊断信息</button></div>
82
+ <pre id="rep-text" hidden></pre>
83
+ <div class="acts" id="rep-acts" hidden><button type="button" class="act" id="rep-copy">复制</button><a class="act" href="https://github.com/TarsLab/cotutor/issues/new?template=bug.yml" target="_blank" rel="noopener">到 GitHub 反馈</a></div>
84
+ </div>
85
+ </div>
66
86
  ${BRAND_FOOTER}
67
87
  </div>
68
88
  <div id="toast"></div>
@@ -125,8 +145,52 @@ ${pageDomJs(3200)}
125
145
  if (S) { document.title = S.title + ' · 家长 · 设置'; $('#title').textContent = S.title; }
126
146
  draw();
127
147
  };
148
+ // 备份:只读和「现在备一份」;恢复要停服务,在终端里做,这里说怎么做
149
+ const bkLoad = async () => {
150
+ const d = await api('GET', '/api/parent/backups').catch(() => null);
151
+ const note = $('#bk-note');
152
+ if (!d) { note.textContent = '读不到备份的情况'; return; }
153
+ const last = d.list[0];
154
+ const mb = (n) => (n / 1024 / 1024).toFixed(1) + ' MB';
155
+ note.textContent = (last ? '最近一份 ' + new Date(last.at).toLocaleString() + ',' + last.files + ' 个文件,' + mb(last.bytes) + ';一共留着 ' + d.list.length + ' 份。' : '还没有备份。') + '放在 ' + d.dir + '。服务开着时每天自动备一份,升级前也备一份;录音占地方,不在备份里。要恢复:在这台电脑的终端里跑 ' + d.commands.list + ' 看有哪些,再 ' + d.commands.restore + '。';
156
+ };
157
+ $('#bk-go').addEventListener('click', async () => {
158
+ const b = $('#bk-go');
159
+ b.disabled = true;
160
+ try { await api('POST', '/api/parent/backups', {}); toast('备份好了'); } catch (e) { toast('没备份成:' + e.message); }
161
+ b.disabled = false;
162
+ bkLoad();
163
+ });
164
+ // 诊断信息:先给人看,复制是人点的;不自动发
165
+ $('#rep-go').addEventListener('click', async () => {
166
+ const b = $('#rep-go');
167
+ b.disabled = true;
168
+ try {
169
+ const r = await api('GET', '/api/parent/report');
170
+ $('#rep-text').textContent = r.text;
171
+ $('#rep-text').hidden = false;
172
+ $('#rep-acts').hidden = false;
173
+ } catch (e) { toast('没生成成:' + e.message); }
174
+ b.disabled = false;
175
+ });
176
+ $('#rep-copy').addEventListener('click', async () => {
177
+ const text = $('#rep-text').textContent;
178
+ try {
179
+ await navigator.clipboard.writeText(text);
180
+ toast('复制好了');
181
+ } catch {
182
+ // 不是 https 的地址没有剪贴板接口:选中,让人自己复制
183
+ const range = document.createRange();
184
+ range.selectNodeContents($('#rep-text'));
185
+ const sel = getSelection();
186
+ sel.removeAllRanges();
187
+ sel.addRange(range);
188
+ toast('已选中,按复制');
189
+ }
190
+ });
128
191
  draw();
129
192
  load();
193
+ bkLoad();
130
194
  })();
131
195
  </script>
132
196
  </body></html>
package/package.json CHANGED
@@ -1,6 +1,12 @@
1
1
  {
2
2
  "name": "cotutor",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
+ "releaseNotes": [
5
+ "自动备份:服务开着时每天一份,升级前一份,可以恢复;录音占地方,不在备份里",
6
+ "家长端首页多了「还差几步」,第一次打开就知道接下来做什么;选一下年级老师就知道孩子上几年级",
7
+ "遇到问题时,家长端「设置」能生成诊断信息,不含孩子的对话和 key,先看再发",
8
+ "`cotutor init --grade` 自动算好学期,`cotutor doctor --fix` 一次修掉能自动修的"
9
+ ],
4
10
  "description": "AI tutors that co-teach with parents at home: real-time voice, an interactive whiteboard, and learning memory in your own Obsidian vault. Self-hosted; built for China's elementary curriculum.",
5
11
  "type": "module",
6
12
  "license": "SEE LICENSE IN LICENSE",
@@ -3,7 +3,7 @@
3
3
  ## 分析用的命令(在 workspace 根跑;完整用法 cotutor --help)
4
4
 
5
5
  ```
6
- cotutor doctor [--workspace <dir>] [--json] [--live] 逐项体检;--live 真连一次百炼实时模型、真合成一句配音(花一分钱)把 API 层的坑摆出来(真跑老师用 cotutor send);--json 里不过的项带 cmd(能直接跑)或 human(要人来)
6
+ cotutor doctor [--workspace <dir>] [--json] [--live] [--fix] 逐项体检;--live 真连一次百炼实时模型、真合成一句配音(花一分钱)把 API 层的坑摆出来(真跑老师用 cotutor send);--json 里不过的项带 cmd(能直接跑)或 human(要人来);--fix 把带 cmd 的一条条修掉,要人来的留着
7
7
  cotutor send <老师> [<消息>] [--from kid|system] [--runtime <名>] [--new] [--photo a.jpg,b.png] [--activity <名> [--param '名=值;名=值']] [--lane main,tts] [--quiet] 终端里发一条,现场按道打印每道工序的事件,说完打印结果(孩子的话照实时写,同孩子端:上下文包带 live:、不补提问卡,只是没有嘴;--from system 不算;--new 开新话题;--photo 带作业照片,拷进 captures/,有照片时消息可以空;--activity 像孩子点了首页的 activity 按钮,新开话题,参数同按钮下面那几行;--quiet 只要结果)
8
8
  cotutor pack <老师> [<消息>] [--from kid|system] [--at <ISO时间>] [--activity <名> [--param '名=值;名=值']] [--json] 干跑上下文包(--activity 看 activity 话题第一条老师拿到什么):不起模型,打印现在会发给老师的那份 + 每段来自哪个文件、那里一共几条、按政策带了几条(改了档案 / 日记 / 计划立刻看效果)
9
9
  cotutor replay <老师> <job> [<日期>] [--runtime <名>] [--json] 回放一轮:同一问按现在的 vault 与提示词再跑一遍(落 evals/,不进孩子的对话、不配音),跑完并排打印上下文包 / 讲稿 / 卡 / 读了什么的 diff
@@ -41,7 +41,7 @@ frontmatter 只写应用支持的这几个键:`name`、`description`、`maxTurns
41
41
  ## 相关命令(完整用法 cotutor --help)
42
42
 
43
43
  ```
44
- cotutor doctor [--workspace <dir>] [--json] [--live] 逐项体检;--live 真连一次百炼实时模型、真合成一句配音(花一分钱)把 API 层的坑摆出来(真跑老师用 cotutor send);--json 里不过的项带 cmd(能直接跑)或 human(要人来)
44
+ cotutor doctor [--workspace <dir>] [--json] [--live] [--fix] 逐项体检;--live 真连一次百炼实时模型、真合成一句配音(花一分钱)把 API 层的坑摆出来(真跑老师用 cotutor send);--json 里不过的项带 cmd(能直接跑)或 human(要人来);--fix 把带 cmd 的一条条修掉,要人来的留着
45
45
  cotutor upgrade [--workspace <dir>] [--force <老师>]... 老师文件、activity 与 skill 换新版:没改过的直接换,改过的只报 diff(--force <老师> 或 --force <老师>/<名> 才覆盖,原文留 .bak)
46
46
  cotutor upgrade --config [--dry-run] [--workspace <dir>] cotutor.json 补缺:新出厂老师 / 运行时 / 命令模板旗标(只加缺的,你改过的值不动)
47
47
  cotutor add <老师名> --display <显示名> [--subject <学科>] [--avatar <emoji|图片相对路径>] [--hidden] 加一位自家的老师:出模板文件、进 cotutor.json、建目录(名字以 -tutor 结尾的是老师,figshot 给它做头像)