skill-chef 0.3.2 → 0.3.13

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 (244) hide show
  1. package/SKILL.md +42 -29
  2. package/dist/add/commands.js +1 -1
  3. package/dist/add/index.d.ts +1 -0
  4. package/dist/add/index.d.ts.map +1 -1
  5. package/dist/add/index.js +1 -0
  6. package/dist/add/index.js.map +1 -1
  7. package/dist/add/pages.d.ts +62 -0
  8. package/dist/add/pages.d.ts.map +1 -0
  9. package/dist/add/pages.js +362 -0
  10. package/dist/add/pages.js.map +1 -0
  11. package/dist/add/routes.d.ts +4 -4
  12. package/dist/add/routes.d.ts.map +1 -1
  13. package/dist/add/routes.js +12 -6
  14. package/dist/add/routes.js.map +1 -1
  15. package/dist/add/run-write.d.ts.map +1 -1
  16. package/dist/add/run-write.js +39 -0
  17. package/dist/add/run-write.js.map +1 -1
  18. package/dist/cli/cmd_read.js +17 -1
  19. package/dist/cli/cmd_read.js.map +1 -1
  20. package/dist/cli/config.d.ts +0 -10
  21. package/dist/cli/config.d.ts.map +1 -1
  22. package/dist/cli/config.js +22 -1
  23. package/dist/cli/config.js.map +1 -1
  24. package/dist/cli/keys.d.ts +1 -1
  25. package/dist/cli/keys.d.ts.map +1 -1
  26. package/dist/cli/keys.js +16 -4
  27. package/dist/cli/keys.js.map +1 -1
  28. package/dist/cook/commands.js +1 -1
  29. package/dist/cook/index.d.ts +2 -1
  30. package/dist/cook/index.d.ts.map +1 -1
  31. package/dist/cook/index.js +1 -1
  32. package/dist/cook/index.js.map +1 -1
  33. package/dist/cook/page-art.d.ts +18 -0
  34. package/dist/cook/page-art.d.ts.map +1 -0
  35. package/dist/cook/page-art.js +30 -0
  36. package/dist/cook/page-art.js.map +1 -0
  37. package/dist/cook/page-css.d.ts +9 -0
  38. package/dist/cook/page-css.d.ts.map +1 -0
  39. package/dist/cook/page-css.js +206 -0
  40. package/dist/cook/page-css.js.map +1 -0
  41. package/dist/cook/page-text.d.ts +28 -0
  42. package/dist/cook/page-text.d.ts.map +1 -0
  43. package/dist/cook/page-text.js +65 -0
  44. package/dist/cook/page-text.js.map +1 -0
  45. package/dist/cook/routes.js +4 -4
  46. package/dist/cook/run.d.ts +56 -1
  47. package/dist/cook/run.d.ts.map +1 -1
  48. package/dist/cook/run.js +252 -22
  49. package/dist/cook/run.js.map +1 -1
  50. package/dist/data/commands.d.ts +6 -7
  51. package/dist/data/commands.d.ts.map +1 -1
  52. package/dist/data/commands.js +15 -8
  53. package/dist/data/commands.js.map +1 -1
  54. package/dist/data/index.d.ts +2 -0
  55. package/dist/data/index.d.ts.map +1 -1
  56. package/dist/data/index.js +2 -0
  57. package/dist/data/index.js.map +1 -1
  58. package/dist/data/pages.d.ts +50 -0
  59. package/dist/data/pages.d.ts.map +1 -0
  60. package/dist/data/pages.js +226 -0
  61. package/dist/data/pages.js.map +1 -0
  62. package/dist/data/routes.d.ts +4 -5
  63. package/dist/data/routes.d.ts.map +1 -1
  64. package/dist/data/routes.js +8 -10
  65. package/dist/data/routes.js.map +1 -1
  66. package/dist/data/run-batch.d.ts +21 -0
  67. package/dist/data/run-batch.d.ts.map +1 -0
  68. package/dist/data/run-batch.js +123 -0
  69. package/dist/data/run-batch.js.map +1 -0
  70. package/dist/data/run-query.d.ts +5 -6
  71. package/dist/data/run-query.d.ts.map +1 -1
  72. package/dist/data/run-query.js +113 -28
  73. package/dist/data/run-query.js.map +1 -1
  74. package/dist/help/lookup.d.ts.map +1 -1
  75. package/dist/help/lookup.js +20 -4
  76. package/dist/help/lookup.js.map +1 -1
  77. package/dist/help/sceneData.d.ts +8 -7
  78. package/dist/help/sceneData.d.ts.map +1 -1
  79. package/dist/help/sceneData.js +22 -21
  80. package/dist/help/sceneData.js.map +1 -1
  81. package/dist/history/commands.js +1 -1
  82. package/dist/history/page-css.d.ts +12 -0
  83. package/dist/history/page-css.d.ts.map +1 -0
  84. package/dist/history/page-css.js +208 -0
  85. package/dist/history/page-css.js.map +1 -0
  86. package/dist/history/pages.d.ts +77 -0
  87. package/dist/history/pages.d.ts.map +1 -0
  88. package/dist/history/pages.js +282 -0
  89. package/dist/history/pages.js.map +1 -0
  90. package/dist/history/routes.d.ts +4 -6
  91. package/dist/history/routes.d.ts.map +1 -1
  92. package/dist/history/routes.js +22 -16
  93. package/dist/history/routes.js.map +1 -1
  94. package/dist/history/run-query.d.ts +48 -0
  95. package/dist/history/run-query.d.ts.map +1 -1
  96. package/dist/history/run-query.js +96 -10
  97. package/dist/history/run-query.js.map +1 -1
  98. package/dist/history/run-record.d.ts +12 -2
  99. package/dist/history/run-record.d.ts.map +1 -1
  100. package/dist/history/run-record.js +28 -14
  101. package/dist/history/run-record.js.map +1 -1
  102. package/dist/history/validate.d.ts +22 -0
  103. package/dist/history/validate.d.ts.map +1 -0
  104. package/dist/history/validate.js +69 -0
  105. package/dist/history/validate.js.map +1 -0
  106. package/dist/policy/wakewords.d.ts +1 -1
  107. package/dist/policy/wakewords.d.ts.map +1 -1
  108. package/dist/policy/wakewords.js +23 -2
  109. package/dist/policy/wakewords.js.map +1 -1
  110. package/dist/relation/commands.d.ts +6 -5
  111. package/dist/relation/commands.d.ts.map +1 -1
  112. package/dist/relation/commands.js +23 -6
  113. package/dist/relation/commands.js.map +1 -1
  114. package/dist/relation/index.d.ts +3 -0
  115. package/dist/relation/index.d.ts.map +1 -1
  116. package/dist/relation/index.js +3 -0
  117. package/dist/relation/index.js.map +1 -1
  118. package/dist/relation/pages.d.ts +37 -0
  119. package/dist/relation/pages.d.ts.map +1 -0
  120. package/dist/relation/pages.js +224 -0
  121. package/dist/relation/pages.js.map +1 -0
  122. package/dist/relation/routes.d.ts +6 -5
  123. package/dist/relation/routes.d.ts.map +1 -1
  124. package/dist/relation/routes.js +17 -16
  125. package/dist/relation/routes.js.map +1 -1
  126. package/dist/relation/run-query.d.ts +10 -0
  127. package/dist/relation/run-query.d.ts.map +1 -0
  128. package/dist/relation/run-query.js +104 -0
  129. package/dist/relation/run-query.js.map +1 -0
  130. package/dist/relation/run-write.d.ts +13 -0
  131. package/dist/relation/run-write.d.ts.map +1 -0
  132. package/dist/relation/run-write.js +114 -0
  133. package/dist/relation/run-write.js.map +1 -0
  134. package/dist/relation/shapes.d.ts +8 -0
  135. package/dist/relation/shapes.d.ts.map +1 -0
  136. package/dist/relation/shapes.js +153 -0
  137. package/dist/relation/shapes.js.map +1 -0
  138. package/dist/relation/treeShapes.d.ts +23 -0
  139. package/dist/relation/treeShapes.d.ts.map +1 -0
  140. package/dist/relation/treeShapes.js +289 -0
  141. package/dist/relation/treeShapes.js.map +1 -0
  142. package/dist/render/copyArea.d.ts +67 -0
  143. package/dist/render/copyArea.d.ts.map +1 -0
  144. package/dist/render/copyArea.js +146 -0
  145. package/dist/render/copyArea.js.map +1 -0
  146. package/dist/render/envelope.d.ts.map +1 -1
  147. package/dist/render/envelope.js +4 -0
  148. package/dist/render/envelope.js.map +1 -1
  149. package/dist/render/index.d.ts +7 -0
  150. package/dist/render/index.d.ts.map +1 -1
  151. package/dist/render/index.js +7 -0
  152. package/dist/render/index.js.map +1 -1
  153. package/dist/render/sceneBand.d.ts +36 -0
  154. package/dist/render/sceneBand.d.ts.map +1 -0
  155. package/dist/render/sceneBand.js +166 -0
  156. package/dist/render/sceneBand.js.map +1 -0
  157. package/dist/render/sceneRhythm.d.ts +6 -0
  158. package/dist/render/sceneRhythm.d.ts.map +1 -0
  159. package/dist/render/sceneRhythm.js +149 -0
  160. package/dist/render/sceneRhythm.js.map +1 -0
  161. package/dist/render/sceneShell.d.ts +17 -0
  162. package/dist/render/sceneShell.d.ts.map +1 -0
  163. package/dist/render/sceneShell.js +46 -0
  164. package/dist/render/sceneShell.js.map +1 -0
  165. package/dist/render/skin.d.ts +13 -0
  166. package/dist/render/skin.d.ts.map +1 -0
  167. package/dist/render/skin.js +282 -0
  168. package/dist/render/skin.js.map +1 -0
  169. package/dist/search/routes.d.ts +12 -4
  170. package/dist/search/routes.d.ts.map +1 -1
  171. package/dist/search/routes.js +39 -7
  172. package/dist/search/routes.js.map +1 -1
  173. package/dist/search/run.d.ts +10 -2
  174. package/dist/search/run.d.ts.map +1 -1
  175. package/dist/search/run.js +61 -9
  176. package/dist/search/run.js.map +1 -1
  177. package/dist/setup/commands.d.ts +5 -5
  178. package/dist/setup/commands.d.ts.map +1 -1
  179. package/dist/setup/commands.js +14 -6
  180. package/dist/setup/commands.js.map +1 -1
  181. package/dist/setup/index.d.ts +3 -5
  182. package/dist/setup/index.d.ts.map +1 -1
  183. package/dist/setup/index.js +3 -5
  184. package/dist/setup/index.js.map +1 -1
  185. package/dist/setup/pages.d.ts +19 -0
  186. package/dist/setup/pages.d.ts.map +1 -0
  187. package/dist/setup/pages.js +163 -0
  188. package/dist/setup/pages.js.map +1 -0
  189. package/dist/setup/routes.d.ts +4 -5
  190. package/dist/setup/routes.d.ts.map +1 -1
  191. package/dist/setup/routes.js +7 -8
  192. package/dist/setup/routes.js.map +1 -1
  193. package/dist/setup/run-init.d.ts +11 -0
  194. package/dist/setup/run-init.d.ts.map +1 -0
  195. package/dist/setup/run-init.js +19 -0
  196. package/dist/setup/run-init.js.map +1 -0
  197. package/dist/shared/command-spec.d.ts +5 -3
  198. package/dist/shared/command-spec.d.ts.map +1 -1
  199. package/dist/shopping/commands.js +1 -1
  200. package/dist/shopping/commands.js.map +1 -1
  201. package/dist/shopping/index.d.ts +1 -0
  202. package/dist/shopping/index.d.ts.map +1 -1
  203. package/dist/shopping/index.js +1 -0
  204. package/dist/shopping/index.js.map +1 -1
  205. package/dist/shopping/pages.d.ts +22 -0
  206. package/dist/shopping/pages.d.ts.map +1 -0
  207. package/dist/shopping/pages.js +170 -0
  208. package/dist/shopping/pages.js.map +1 -0
  209. package/dist/shopping/routes.js +4 -4
  210. package/dist/shopping/routes.js.map +1 -1
  211. package/dist/shopping/run.d.ts +9 -5
  212. package/dist/shopping/run.d.ts.map +1 -1
  213. package/dist/shopping/run.js +58 -10
  214. package/dist/shopping/run.js.map +1 -1
  215. package/dist/triggers/chef-scenes.d.ts +3 -2
  216. package/dist/triggers/chef-scenes.d.ts.map +1 -1
  217. package/dist/triggers/chef-scenes.js +16 -15
  218. package/dist/triggers/chef-scenes.js.map +1 -1
  219. package/dist/update/routes.d.ts +6 -4
  220. package/dist/update/routes.d.ts.map +1 -1
  221. package/dist/update/routes.js +20 -6
  222. package/dist/update/routes.js.map +1 -1
  223. package/dist/update/run-write.d.ts.map +1 -1
  224. package/dist/update/run-write.js +211 -1
  225. package/dist/update/run-write.js.map +1 -1
  226. package/dist/view/commands.js +1 -1
  227. package/dist/view/page.d.ts +25 -0
  228. package/dist/view/page.d.ts.map +1 -0
  229. package/dist/view/page.js +306 -0
  230. package/dist/view/page.js.map +1 -0
  231. package/dist/view/pageCss.d.ts +8 -0
  232. package/dist/view/pageCss.d.ts.map +1 -0
  233. package/dist/view/pageCss.js +327 -0
  234. package/dist/view/pageCss.js.map +1 -0
  235. package/dist/view/pageSection.d.ts +21 -0
  236. package/dist/view/pageSection.d.ts.map +1 -0
  237. package/dist/view/pageSection.js +59 -0
  238. package/dist/view/pageSection.js.map +1 -0
  239. package/dist/view/routes.js +7 -7
  240. package/dist/view/run.d.ts +5 -1
  241. package/dist/view/run.d.ts.map +1 -1
  242. package/dist/view/run.js +66 -7
  243. package/dist/view/run.js.map +1 -1
  244. package/package.json +3 -3
@@ -1,49 +1,55 @@
1
1
  /** 历史能力的路由声明(唤醒词命中哪条命令,声明面唯一一处)。
2
2
  *
3
- * 六行对应 `src/policy/wakewords.ts` 里历史六句唤醒词:记录做菜/补录做菜/改评分
4
- * 进 `chef.history.record`,查看历史/查看统计/体检进 `chef.history.query`。
5
- * `order` 沿用唤醒词表里的相对顺序(31–36),只保证本文件内有序;全表级顺序
6
- * 由整包落位票统一到场景表,本票不另立顺序。
7
- * 命令行写法照 `packages/skill-chef/SKILL.md` 同命令示例:需菜名的带菜名,
8
- * 查统计与体检带 `kind`(空库可跑的那一行)。
3
+ * 七行对应 `src/policy/wakewords.ts` 里归历史的七句唤醒词:记录做菜/补录做菜/改评分
4
+ * 进 `chef.history.record`,查看历史/查看统计/体检/备份进 `chef.history.query`。
5
+ * `order` 取唤醒词表 1-based 下标(32–37),与全表同序;表序是唯一顺序事实源,本文件不另立顺序。
6
+ * 命令行写法照本表各条的槽位示例:需菜名的带菜名,查统计/体检/备份带 `kind`(空库可跑的那一行)。
9
7
  */
10
8
  /** 历史能力的路由声明表:恰好导出一个声明数组。 */
11
9
  export const HISTORY_ROUTES = [
12
10
  {
13
- order: 31,
11
+ order: 32,
14
12
  wakeWord: '记录做菜',
15
13
  key: 'chef.history.record',
16
- cli: 'chef-cmd-read chef.history.record --params \'{"name":"宫保虾球"}\'',
14
+ cli: 'chef-cmd-read chef.history.record --params \'{"name":"辣椒炒肉"}\'',
17
15
  },
18
16
  {
19
- order: 32,
17
+ order: 33,
20
18
  wakeWord: '补录做菜',
21
19
  key: 'chef.history.record',
22
- cli: 'chef-cmd-read chef.history.record --params \'{"name":"宫保虾球"}\'',
20
+ cli: 'chef-cmd-read chef.history.record --params \'{"name":"辣椒炒肉"}\'',
23
21
  },
24
22
  {
25
- order: 33,
23
+ order: 34,
26
24
  wakeWord: '改评分',
27
25
  key: 'chef.history.record',
28
- cli: 'chef-cmd-read chef.history.record --params \'{"name":"宫保虾球"}\'',
26
+ cli: 'chef-cmd-read chef.history.record --params \'{"name":"辣椒炒肉"}\'',
29
27
  },
30
28
  {
31
- order: 34,
29
+ order: 35,
32
30
  wakeWord: '查看历史',
33
31
  key: 'chef.history.query',
34
- cli: 'chef-cmd-read chef.history.query --params \'{"name":"宫保虾球"}\'',
32
+ cli: 'chef-cmd-read chef.history.query --params \'{"name":"辣椒炒肉"}\'',
35
33
  },
36
34
  {
37
- order: 35,
35
+ order: 36,
38
36
  wakeWord: '查看统计',
39
37
  key: 'chef.history.query',
40
38
  cli: 'chef-cmd-read chef.history.query --params \'{"kind":"stats"}\'',
41
39
  },
42
40
  {
43
- order: 36,
41
+ order: 37,
44
42
  wakeWord: '体检',
45
43
  key: 'chef.history.query',
46
44
  cli: 'chef-cmd-read chef.history.query --params \'{"kind":"quality"}\'',
47
45
  },
46
+ {
47
+ // #841 追加:`备份`沿用本命令 `kind: 'backup'`(页面装配住数据管理域,事实是本技能的查询语义;
48
+ // 故这条只在本域声明一处,`src/data/routes.ts` 不再重复一行——一份事实一个落点)。
49
+ order: 50,
50
+ wakeWord: '备份',
51
+ key: 'chef.history.query',
52
+ cli: 'chef-cmd-read chef.history.query --params \'{"kind":"backup"}\'',
53
+ },
48
54
  ];
49
55
  //# sourceMappingURL=routes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/history/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAUH,6BAA6B;AAC7B,MAAM,CAAC,MAAM,cAAc,GAAgC;IACzD;QACE,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,MAAM;QAChB,GAAG,EAAE,qBAAqB;QAC1B,GAAG,EAAE,gEAAgE;KACtE;IACD;QACE,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,MAAM;QAChB,GAAG,EAAE,qBAAqB;QAC1B,GAAG,EAAE,gEAAgE;KACtE;IACD;QACE,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,KAAK;QACf,GAAG,EAAE,qBAAqB;QAC1B,GAAG,EAAE,gEAAgE;KACtE;IACD;QACE,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,MAAM;QAChB,GAAG,EAAE,oBAAoB;QACzB,GAAG,EAAE,+DAA+D;KACrE;IACD;QACE,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,MAAM;QAChB,GAAG,EAAE,oBAAoB;QACzB,GAAG,EAAE,gEAAgE;KACtE;IACD;QACE,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,IAAI;QACd,GAAG,EAAE,oBAAoB;QACzB,GAAG,EAAE,kEAAkE;KACxE;CACF,CAAC"}
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/history/routes.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,6BAA6B;AAC7B,MAAM,CAAC,MAAM,cAAc,GAAgC;IACzD;QACE,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,MAAM;QAChB,GAAG,EAAE,qBAAqB;QAC1B,GAAG,EAAE,gEAAgE;KACtE;IACD;QACE,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,MAAM;QAChB,GAAG,EAAE,qBAAqB;QAC1B,GAAG,EAAE,gEAAgE;KACtE;IACD;QACE,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,KAAK;QACf,GAAG,EAAE,qBAAqB;QAC1B,GAAG,EAAE,gEAAgE;KACtE;IACD;QACE,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,MAAM;QAChB,GAAG,EAAE,oBAAoB;QACzB,GAAG,EAAE,+DAA+D;KACrE;IACD;QACE,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,MAAM;QAChB,GAAG,EAAE,oBAAoB;QACzB,GAAG,EAAE,gEAAgE;KACtE;IACD;QACE,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,IAAI;QACd,GAAG,EAAE,oBAAoB;QACzB,GAAG,EAAE,kEAAkE;KACxE;IACD;QACE,6DAA6D;QAC7D,sDAAsD;QACtD,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,IAAI;QACd,GAAG,EAAE,oBAAoB;QACzB,GAAG,EAAE,iEAAiE;KACvE;CACF,CAAC"}
@@ -4,10 +4,58 @@
4
4
  * 只改 import 出处,判定与装配一字不动。quality/backup 两路住数据管理域
5
5
  * (`src/data/run-query.ts`);kind 路由由入口注册表做(非法 kind 入口已拦,落不到这里)。
6
6
  * `toHistoryItem`(原 `src/render/views.ts`)只被本域调用,随行搬入;旧址改转出(搬迁债务)。
7
+ *
8
+ * 本票新增(仍本域独占,不碰 `src/fetch/db.ts`):
9
+ * · 时间线按 `cook_date` 倒序(老件 `history_manager.py list` 的 `ORDER BY cook_date DESC`;
10
+ * 同日按 `cook_sequence` 倒序);
11
+ * · 单菜统计全指标(老件 `stats`:总次数/均分/最高/最低/最近日期);
12
+ * · 全局画像(老件 `global_stats` 单查询口径:做过几道/总次数/最爱均分最高与做得最多/
13
+ * 最近 5/没做过;本票定案:歧义已与老件对账消除,不另立裁定票)。
7
14
  */
8
15
  import type { ChefDb, HistoryRow } from '../fetch/db.js';
9
16
  /** 历史行+菜名拼条目。原 `src/render/views.ts`,本域独占。 */
10
17
  export declare function toHistoryItem(h: HistoryRow, recipeName?: string): Record<string, unknown>;
18
+ /** 单菜统计全指标(老件 `stats` 口径:总次数/均分/最高/最低/最近日期;无记录则后四项为 null)。 */
19
+ export interface HistorySingleStats {
20
+ readonly count: number;
21
+ readonly avgRating: number | null;
22
+ readonly maxRating: number | null;
23
+ readonly minRating: number | null;
24
+ readonly lastDate: string | null;
25
+ }
26
+ /** 取一道菜的统计全指标(单 SQL 聚合,与老件 `stats` 同口径)。 */
27
+ export declare function historySingleStats(handle: ChefDb, recipeId: string): HistorySingleStats;
28
+ /** 全局画像(老件 `global_stats` 画像版口径:做过几道/总次数/菜总数/最爱两项/最近 5/没做过)。 */
29
+ export interface HistoryGlobalPortrait {
30
+ readonly cookedCount: number;
31
+ readonly neverCookedCount: number;
32
+ readonly totalCooks: number;
33
+ readonly recipeTotal: number;
34
+ readonly favoriteAvg: {
35
+ name: string;
36
+ avgRating: number;
37
+ times: number;
38
+ } | null;
39
+ readonly favoriteMost: {
40
+ name: string;
41
+ times: number;
42
+ avgRating: number | null;
43
+ } | null;
44
+ readonly recent: ReadonlyArray<{
45
+ name: string;
46
+ lastDate: string;
47
+ avgRating: number | null;
48
+ }>;
49
+ readonly neverCooked: ReadonlyArray<string>;
50
+ readonly perRecipe: ReadonlyArray<{
51
+ id: string;
52
+ name: string;
53
+ count: number;
54
+ avgRating: number | null;
55
+ }>;
56
+ }
57
+ /** 取全局画像(单查询聚合 `recipes` 全表+`recipe_history`,与老件 `global-stats` 同口径)。 */
58
+ export declare function historyGlobalPortrait(handle: ChefDb): HistoryGlobalPortrait;
11
59
  /** 跑 `chef.history.query` 的 timeline/stats:`kind` 由入口注册表算好下传,本函数只做本域两路分支。 */
12
60
  export declare function runHistoryQuery(handle: ChefDb, params: Record<string, unknown>, kind: string): unknown;
13
61
  //# sourceMappingURL=run-query.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-query.d.ts","sourceRoot":"","sources":["../../src/history/run-query.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAMzD,8CAA8C;AAC9C,wBAAgB,aAAa,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAIzF;AAED,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAuBtG"}
1
+ {"version":3,"file":"run-query.d.ts","sourceRoot":"","sources":["../../src/history/run-query.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAMzD,8CAA8C;AAC9C,wBAAgB,aAAa,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAIzF;AAED,8DAA8D;AAC9D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,4CAA4C;AAC5C,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CAgBvF;AAWD,gEAAgE;AAChE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAChF,QAAQ,CAAC,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IACxF,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IAC7F,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5C,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;CAC1G;AAED,yEAAyE;AACzE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,qBAAqB,CAkD3E;AAQD,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAiCtG"}
@@ -4,8 +4,15 @@
4
4
  * 只改 import 出处,判定与装配一字不动。quality/backup 两路住数据管理域
5
5
  * (`src/data/run-query.ts`);kind 路由由入口注册表做(非法 kind 入口已拦,落不到这里)。
6
6
  * `toHistoryItem`(原 `src/render/views.ts`)只被本域调用,随行搬入;旧址改转出(搬迁债务)。
7
+ *
8
+ * 本票新增(仍本域独占,不碰 `src/fetch/db.ts`):
9
+ * · 时间线按 `cook_date` 倒序(老件 `history_manager.py list` 的 `ORDER BY cook_date DESC`;
10
+ * 同日按 `cook_sequence` 倒序);
11
+ * · 单菜统计全指标(老件 `stats`:总次数/均分/最高/最低/最近日期);
12
+ * · 全局画像(老件 `global_stats` 单查询口径:做过几道/总次数/最爱均分最高与做得最多/
13
+ * 最近 5/没做过;本票定案:歧义已与老件对账消除,不另立裁定票)。
7
14
  */
8
- import { getRecipeDetail, historyStats, listRecipes, queryHistory } from '../fetch/db.js';
15
+ import { getRecipeDetail, mustRecipe, qAll, qGet, queryHistory } from '../fetch/db.js';
9
16
  import { ChefPolicyError } from '../fetch/errors.js';
10
17
  import { buildHistoryQuery } from '../render/index.js';
11
18
  import { needName } from '../policy/index.js';
@@ -16,27 +23,106 @@ export function toHistoryItem(h, recipeName) {
16
23
  out.recipe_name = recipeName;
17
24
  return out;
18
25
  }
26
+ /** 取一道菜的统计全指标(单 SQL 聚合,与老件 `stats` 同口径)。 */
27
+ export function historySingleStats(handle, recipeId) {
28
+ const recipe = mustRecipe(handle, recipeId);
29
+ const row = qGet(handle, 'SELECT COUNT(*) AS c, AVG(rating) AS a, MAX(rating) AS hi, MIN(rating) AS lo, MAX(cook_date) AS last FROM recipe_history WHERE recipe_id = ?', [recipe.id]);
30
+ const numOrNull = (v) => v === null || v === undefined ? null : Number(v);
31
+ return {
32
+ count: Number(row?.c ?? 0),
33
+ avgRating: numOrNull(row?.a),
34
+ maxRating: numOrNull(row?.hi),
35
+ minRating: numOrNull(row?.lo),
36
+ lastDate: row?.last ?? null,
37
+ };
38
+ }
39
+ /** 取全局画像(单查询聚合 `recipes` 全表+`recipe_history`,与老件 `global-stats` 同口径)。 */
40
+ export function historyGlobalPortrait(handle) {
41
+ const rows = qAll(handle, 'SELECT r.id AS recipe_id, r.name AS recipe_name, COUNT(h.id) AS cook_count, AVG(h.rating) AS avg_rating, MAX(h.cook_date) AS last_date ' +
42
+ 'FROM recipes r LEFT JOIN recipe_history h ON h.recipe_id = r.id GROUP BY r.id ORDER BY r.name ASC');
43
+ const cooked = [];
44
+ const neverCooked = [];
45
+ for (const r of rows) {
46
+ const count = Number(r.cook_count ?? 0);
47
+ if (count > 0) {
48
+ cooked.push({
49
+ recipeId: String(r.recipe_id),
50
+ recipeName: String(r.recipe_name),
51
+ cookCount: count,
52
+ avgRating: r.avg_rating === null || r.avg_rating === undefined ? null : Number(r.avg_rating),
53
+ lastDate: r.last_date ?? null,
54
+ });
55
+ }
56
+ else {
57
+ neverCooked.push(String(r.recipe_name));
58
+ }
59
+ }
60
+ const round2 = (v) => Math.round(v * 100) / 100;
61
+ const totalCooks = cooked.reduce((s, r) => s + r.cookCount, 0);
62
+ const rated = cooked.filter((r) => r.avgRating !== null);
63
+ const topAvg = rated.length ? rated.reduce((a, b) => b.avgRating > a.avgRating ? b : a) : null;
64
+ const topMost = cooked.length ? cooked.reduce((a, b) => (b.cookCount > a.cookCount ? b : a)) : null;
65
+ const recent = [...cooked]
66
+ .sort((a, b) => String(b.lastDate ?? '').localeCompare(String(a.lastDate ?? '')))
67
+ .slice(0, 5)
68
+ .map((r) => ({ name: r.recipeName, lastDate: r.lastDate, avgRating: r.avgRating === null ? null : round2(r.avgRating) }));
69
+ return {
70
+ cookedCount: cooked.length,
71
+ neverCookedCount: neverCooked.length,
72
+ totalCooks,
73
+ recipeTotal: rows.length,
74
+ favoriteAvg: topAvg
75
+ ? { name: topAvg.recipeName, avgRating: round2(topAvg.avgRating), times: topAvg.cookCount }
76
+ : null,
77
+ favoriteMost: topMost
78
+ ? {
79
+ name: topMost.recipeName,
80
+ times: topMost.cookCount,
81
+ avgRating: topMost.avgRating === null ? null : round2(topMost.avgRating),
82
+ }
83
+ : null,
84
+ recent,
85
+ neverCooked: [...neverCooked].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)),
86
+ perRecipe: cooked.map((r) => ({ id: r.recipeId, name: r.recipeName, count: r.cookCount, avgRating: r.avgRating })),
87
+ };
88
+ }
89
+ /** 按时间倒序排历史行(`cook_date` 倒序,同日按 `cook_sequence` 倒序;老件 timeline 口径)。 */
90
+ function byTimeDesc(a, b) {
91
+ if (a.cook_date !== b.cook_date)
92
+ return a.cook_date < b.cook_date ? 1 : -1;
93
+ return b.cook_sequence - a.cook_sequence;
94
+ }
19
95
  /** 跑 `chef.history.query` 的 timeline/stats:`kind` 由入口注册表算好下传,本函数只做本域两路分支。 */
20
96
  export function runHistoryQuery(handle, params, kind) {
21
97
  if (kind === 'timeline') {
22
98
  const name = needName(params);
23
99
  const detail = getRecipeDetail(handle, name);
24
- const rows = queryHistory(handle, detail.recipe.id);
100
+ const rows = queryHistory(handle, detail.recipe.id).sort(byTimeDesc);
25
101
  return buildHistoryQuery('timeline:' + detail.recipe.name, rows.map((h) => toHistoryItem(h, detail.recipe.name)));
26
102
  }
27
103
  if (kind === 'stats') {
28
104
  const name = params.name;
29
105
  if (typeof name === 'string' && name.trim()) {
30
106
  const detail = getRecipeDetail(handle, name.trim());
31
- const st = historyStats(handle, detail.recipe.id);
32
- return buildHistoryQuery('stats:' + detail.recipe.name, [{ name: detail.recipe.name, count: st.count, avgRating: st.avgRating }]);
107
+ const st = historySingleStats(handle, detail.recipe.id);
108
+ return buildHistoryQuery('stats:' + detail.recipe.name, [
109
+ { name: detail.recipe.name, count: st.count, avgRating: st.avgRating, maxRating: st.maxRating, minRating: st.minRating, lastDate: st.lastDate },
110
+ ]);
33
111
  }
34
- const recipes = listRecipes(handle);
35
- const items = recipes.map((r) => {
36
- const st = historyStats(handle, r.id);
37
- return { id: r.id, name: r.name, count: st.count, avgRating: st.avgRating };
38
- });
39
- return buildHistoryQuery('stats:all', items);
112
+ const portrait = historyGlobalPortrait(handle);
113
+ return buildHistoryQuery('stats:all', [
114
+ {
115
+ cookedCount: portrait.cookedCount,
116
+ neverCookedCount: portrait.neverCookedCount,
117
+ totalCooks: portrait.totalCooks,
118
+ recipeTotal: portrait.recipeTotal,
119
+ favoriteAvg: portrait.favoriteAvg,
120
+ favoriteMost: portrait.favoriteMost,
121
+ recent: portrait.recent,
122
+ neverCooked: portrait.neverCooked,
123
+ perRecipe: portrait.perRecipe,
124
+ },
125
+ ]);
40
126
  }
41
127
  // 不可达:入口注册表已拦过非法 kind(原文分支尾 fail(2) 同报文,归用法错 exit 2)。
42
128
  throw new ChefPolicyError('POLICY_BAD_INPUT', 'history.query 只接受 kind=timeline/stats/quality/backup');
@@ -1 +1 @@
1
- {"version":3,"file":"run-query.js","sourceRoot":"","sources":["../../src/history/run-query.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC1F,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,8CAA8C;AAC9C,MAAM,UAAU,aAAa,CAAC,CAAa,EAAE,UAAmB;IAC9D,MAAM,GAAG,GAA4B,EAAE,GAAG,CAAC,EAAE,CAAC;IAC9C,IAAI,UAAU,KAAK,SAAS;QAAE,GAAG,CAAC,WAAW,GAAG,UAAU,CAAC;IAC3D,OAAO,GAAG,CAAC;AACb,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,MAA+B,EAAE,IAAY;IAC3F,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC9B,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC7C,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACpD,OAAO,iBAAiB,CAAC,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpH,CAAC;IACD,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACrB,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QACzB,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;YAC5C,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YACpD,MAAM,EAAE,GAAG,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAClD,OAAO,iBAAiB,CAAC,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QACpI,CAAC;QACD,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;QACpC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YAC9B,MAAM,EAAE,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YACtC,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC;QAC9E,CAAC,CAAC,CAAC;QACH,OAAO,iBAAiB,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IAC/C,CAAC;IACD,sDAAsD;IACtD,MAAM,IAAI,eAAe,CAAC,kBAAkB,EAAE,sDAAsD,CAAC,CAAC;AACxG,CAAC"}
1
+ {"version":3,"file":"run-query.js","sourceRoot":"","sources":["../../src/history/run-query.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,11 @@
5
5
  * 只被本域调用,按“写不出的留回域目录”搬入本文件;旧址改转出(搬迁债务,见对应 index)。
6
6
  */
7
7
  import type { ChefDb, HistoryRow } from '../fetch/db.js';
8
- /** 记一次做菜(评分必填:老库 rating NOT NULL,缺评分直接拦)。原 `src/fetch/db.ts`,本域独占。 */
8
+ /** 记一次做菜(评分必填+反馈必填禁占位:老库 rating NOT NULL,缺值直接拦)。原 `src/fetch/db.ts`,本域独占。
9
+ *
10
+ * 反馈口径见 `./validate.ts`(老仓 `scenes/历史.yaml:56`:必填真实内容、禁「无」占位)。
11
+ * 日期缺省今天(同 `./validate.ts` 的 `validateCookDate`,本文件不再自备 today)。
12
+ */
9
13
  export declare function recordHistory(h: ChefDb, input: {
10
14
  recipe_id: string;
11
15
  rating?: number | null;
@@ -16,6 +20,12 @@ export declare function buildHistoryRecord(message: string): {
16
20
  ok: boolean;
17
21
  message: string;
18
22
  };
19
- /** 跑 `chef.history.record`:定位母菜+评分校验+落历史(receipt 形)。 */
23
+ /** 跑 `chef.history.record`:定位母菜+评分校验+反馈校验+落历史(receipt 形)。
24
+ *
25
+ * 参数:`name` 必填;`rating` 0-5 数字(818 定案甲:缺评分不写历史,取数层抛
26
+ * `CHEF_BAD_QUERY` 即 CLI exit 4);`feedback` 必填真实内容禁占位(口径错 exit 2);
27
+ * 补录日期 `date`(`cook_date` 作兼容别名,老件 `--cook_date` 同名),缺省今天。
28
+ * 「改评分」唤醒词走同一条记录路径(路由见 `./routes.ts:33-38`):记一次新的做菜记录。
29
+ */
20
30
  export declare function runHistoryRecord(handle: ChefDb, params: Record<string, unknown>): unknown;
21
31
  //# sourceMappingURL=run-record.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-record.d.ts","sourceRoot":"","sources":["../../src/history/run-record.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AASzD,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,UAAU,CA4BhJ;AAGD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAEpF;AAED,wDAAwD;AACxD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAYzF"}
1
+ {"version":3,"file":"run-record.d.ts","sourceRoot":"","sources":["../../src/history/run-record.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAKzD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,UAAU,CA8BhJ;AAGD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAEpF;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAiBzF"}
@@ -8,11 +8,12 @@ import { randomUUID } from 'node:crypto';
8
8
  import { ChefFetchError } from '../fetch/errors.js';
9
9
  import { getRecipeDetail, mustRecipe, now, qGet, qRun, toHistory } from '../fetch/db.js';
10
10
  import { needName, validateRating } from '../policy/index.js';
11
- /** 当日日期(本域独占:落历史默认 cook_date 与补录默认 date;原 db.ts `today()`,随 recordHistory 搬入)。 */
12
- function today() {
13
- return new Date().toISOString().slice(0, 10);
14
- }
15
- /** 记一次做菜(评分必填:老库 rating NOT NULL,缺评分直接拦)。原 `src/fetch/db.ts`,本域独占。 */
11
+ import { validateCookDate, validateFeedback } from './validate.js';
12
+ /** 记一次做菜(评分必填+反馈必填禁占位:老库 rating NOT NULL,缺值直接拦)。原 `src/fetch/db.ts`,本域独占。
13
+ *
14
+ * 反馈口径见 `./validate.ts`(老仓 `scenes/历史.yaml:56`:必填真实内容、禁「无」占位)。
15
+ * 日期缺省今天(同 `./validate.ts` 的 `validateCookDate`,本文件不再自备 today)。
16
+ */
16
17
  export function recordHistory(h, input) {
17
18
  const rid = typeof input?.recipe_id === 'string' ? input.recipe_id.trim() : '';
18
19
  if (!rid)
@@ -24,19 +25,21 @@ export function recordHistory(h, input) {
24
25
  if (rawRt === undefined || rawRt === null || rawRt === '')
25
26
  throw new ChefFetchError('CHEF_BAD_QUERY', '记录做菜须给评分 rating(0-5 数字;老库 NOT NULL,未评分请先问用户要分)');
26
27
  {
27
- const n = typeof rawRt === 'string' ? Number(String(rawRt).trim()) : rawRt;
28
+ // 空串/纯空白同样按「没给」处理(与 `recordHistory` 同口径:一份缺值只认一个定义地)。
29
+ const n = typeof rawRt === 'string' ? (rawRt.trim() === '' ? rawRt : Number(rawRt.trim())) : rawRt;
28
30
  if (typeof n !== 'number' || !Number.isFinite(n))
29
- throw new ChefFetchError('CHEF_HISTORY_CORRUPT', '评分须为数字');
31
+ throw new ChefFetchError('CHEF_BAD_QUERY', '记录做菜须给评分 rating(0-5 数字;老库 NOT NULL,未评分请先问用户要分)');
30
32
  if (n < 0 || n > 5)
31
33
  throw new ChefFetchError('CHEF_HISTORY_CORRUPT', '评分须在 0-5 内');
32
34
  rating = n;
33
35
  }
34
- const cookDate = typeof input.cook_date === 'string' && input.cook_date.trim() ? input.cook_date.trim() : today();
36
+ const cookDate = validateCookDate(input.cook_date);
37
+ const feedback = validateFeedback(input.feedback);
35
38
  const maxRow = qGet(h, 'SELECT MAX(cook_sequence) AS m FROM recipe_history WHERE recipe_id = ?', [recipe.id]);
36
39
  const seq = (maxRow?.m ?? 0) + 1;
37
40
  const id = randomUUID();
38
41
  try {
39
- qRun(h, 'INSERT INTO recipe_history (id, recipe_id, cook_date, cook_sequence, rating, feedback) VALUES (?, ?, ?, ?, ?, ?)', [id, recipe.id, cookDate, seq, rating, input.feedback ?? '']);
42
+ qRun(h, 'INSERT INTO recipe_history (id, recipe_id, cook_date, cook_sequence, rating, feedback) VALUES (?, ?, ?, ?, ?, ?)', [id, recipe.id, cookDate, seq, rating, feedback]);
40
43
  if (recipe.status === '未做')
41
44
  qRun(h, 'UPDATE recipes SET status = ?, updated_at = ? WHERE id = ?', ['已做', now(), recipe.id]);
42
45
  }
@@ -54,17 +57,28 @@ export function recordHistory(h, input) {
54
57
  export function buildHistoryRecord(message) {
55
58
  return { ok: true, message };
56
59
  }
57
- /** 跑 `chef.history.record`:定位母菜+评分校验+落历史(receipt 形)。 */
60
+ /** 跑 `chef.history.record`:定位母菜+评分校验+反馈校验+落历史(receipt 形)。
61
+ *
62
+ * 参数:`name` 必填;`rating` 0-5 数字(818 定案甲:缺评分不写历史,取数层抛
63
+ * `CHEF_BAD_QUERY` 即 CLI exit 4);`feedback` 必填真实内容禁占位(口径错 exit 2);
64
+ * 补录日期 `date`(`cook_date` 作兼容别名,老件 `--cook_date` 同名),缺省今天。
65
+ * 「改评分」唤醒词走同一条记录路径(路由见 `./routes.ts:33-38`):记一次新的做菜记录。
66
+ */
58
67
  export function runHistoryRecord(handle, params) {
59
68
  const name = needName(params);
60
69
  const detail = getRecipeDetail(handle, name);
61
70
  let rating = null;
62
71
  if (params.rating !== undefined) {
63
- const raw = typeof params.rating === 'string' && params.rating.trim() !== '' ? Number(params.rating.trim()) : params.rating;
64
- rating = validateRating(raw);
72
+ const raw = params.rating;
73
+ // 空串/纯空白=「用户啥也没填」,与「键不传」同义(#853 契约:缺评分 → 取数失败档 4 且点名 rating)。
74
+ // 不这么归一,`rating: ''` 会先撞口径校验(`validateRating` 只认数字 ⇒ exit 2「缺槽位」),
75
+ // 同一个场景因「空串 vs 不传」分叉成两种错误档——同一件事两个定义地。
76
+ const blank = typeof raw === 'string' && raw.trim() === '';
77
+ rating = blank ? null : validateRating(typeof raw === 'string' ? Number(raw.trim()) : raw);
65
78
  }
66
- const feedback = params.feedback === undefined ? '' : String(params.feedback);
67
- const cookDate = params.date === undefined || params.date === '' ? today() : String(params.date);
79
+ const feedback = validateFeedback(params.feedback);
80
+ const dateRaw = params.date === undefined ? params.cook_date : params.date;
81
+ const cookDate = validateCookDate(dateRaw);
68
82
  const h = recordHistory(handle, { recipe_id: detail.recipe.id, rating, feedback, cook_date: cookDate });
69
83
  return buildHistoryRecord('已记录做菜:' + detail.recipe.name + '(' + h.cook_date + (rating !== null ? ',评分 ' + rating : '') + ')');
70
84
  }
@@ -1 +1 @@
1
- {"version":3,"file":"run-record.js","sourceRoot":"","sources":["../../src/history/run-record.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"run-record.js","sourceRoot":"","sources":["../../src/history/run-record.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /** 历史域独占的写参校验(反馈必填禁占位+补录日期)。
2
+ *
3
+ * 本域独占:只有 `chef.history.record` 一条写路径在用(`run-record.ts` 的
4
+ * 入口校验与落库门)。第二个用法出现前不进共用位(结构标准:共用位从
5
+ * 第二个用法里长出来)。
6
+ *
7
+ * 口径出处:
8
+ * · 反馈必填真实内容、禁「无」占位:老仓 `scenes/历史.yaml:56`
9
+ * (`feedback: 一句话反馈(必填真实内容,禁「无」占位)`)+ 本票验收
10
+ * 反例(`feedback` 为「无」必须拦下并 exit≠0)。
11
+ * · 占位词表:老件 `scripts/validators.py` 的 `PLACEHOLDER_STRINGS`
12
+ * 13 种 + 本域加 1 种「无」(精确匹配,不做子串判断——
13
+ * 「无敌好吃」这类真反馈必须放行)。
14
+ * · 日期:老件 `history_manager.py add` 的 `--cook_date`(`YYYY-MM-DD`,
15
+ * 缺省今天);新命令面收 `date`(见本域 `routes.ts` 与 `SKILL.md`),
16
+ * `cook_date` 作兼容别名由调用方归一后传入。
17
+ */
18
+ /** 校验一条做菜反馈:非空真实内容、禁占位词。非法一律抛口径错(CLI exit 2)。 */
19
+ export declare function validateFeedback(raw: unknown): string;
20
+ /** 校验补录日期:`YYYY-MM-DD` 真日期;缺省(`undefined`/空串)即今天。 */
21
+ export declare function validateCookDate(raw: unknown): string;
22
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/history/validate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAuBH,iDAAiD;AACjD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CASrD;AAOD,qDAAqD;AACrD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAgBrD"}
@@ -0,0 +1,69 @@
1
+ /** 历史域独占的写参校验(反馈必填禁占位+补录日期)。
2
+ *
3
+ * 本域独占:只有 `chef.history.record` 一条写路径在用(`run-record.ts` 的
4
+ * 入口校验与落库门)。第二个用法出现前不进共用位(结构标准:共用位从
5
+ * 第二个用法里长出来)。
6
+ *
7
+ * 口径出处:
8
+ * · 反馈必填真实内容、禁「无」占位:老仓 `scenes/历史.yaml:56`
9
+ * (`feedback: 一句话反馈(必填真实内容,禁「无」占位)`)+ 本票验收
10
+ * 反例(`feedback` 为「无」必须拦下并 exit≠0)。
11
+ * · 占位词表:老件 `scripts/validators.py` 的 `PLACEHOLDER_STRINGS`
12
+ * 13 种 + 本域加 1 种「无」(精确匹配,不做子串判断——
13
+ * 「无敌好吃」这类真反馈必须放行)。
14
+ * · 日期:老件 `history_manager.py add` 的 `--cook_date`(`YYYY-MM-DD`,
15
+ * 缺省今天);新命令面收 `date`(见本域 `routes.ts` 与 `SKILL.md`),
16
+ * `cook_date` 作兼容别名由调用方归一后传入。
17
+ */
18
+ import { ChefPolicyError } from '../fetch/errors.js';
19
+ /** 反馈占位词(精确匹配,调用方先去首尾空白):老件 13 种 + 本域「无」系 3 种。 */
20
+ const FEEDBACK_PLACEHOLDERS = [
21
+ '未知',
22
+ '未提供',
23
+ '不详',
24
+ '未填',
25
+ 'n/a',
26
+ 'N/A',
27
+ 'null',
28
+ 'None',
29
+ '暂时不知道',
30
+ '不知道',
31
+ '我没数据',
32
+ '-',
33
+ '无',
34
+ '无反馈',
35
+ '(无反馈)',
36
+ ];
37
+ /** 校验一条做菜反馈:非空真实内容、禁占位词。非法一律抛口径错(CLI exit 2)。 */
38
+ export function validateFeedback(raw) {
39
+ if (typeof raw !== 'string' || !raw.trim()) {
40
+ throw new ChefPolicyError('POLICY_BAD_INPUT', '记录做菜须给反馈 feedback(一句话真实反馈,禁「无」占位)');
41
+ }
42
+ const text = raw.trim();
43
+ if (FEEDBACK_PLACEHOLDERS.includes(text)) {
44
+ throw new ChefPolicyError('POLICY_BAD_INPUT', '反馈须填真实内容,「' + text + '」是占位词(请向用户要一句真实反馈后重试)');
45
+ }
46
+ return text;
47
+ }
48
+ /** 当日日期(`YYYY-MM-DD`):本域落历史默认 cook_date 的唯一定义地。 */
49
+ function todayStr() {
50
+ return new Date().toISOString().slice(0, 10);
51
+ }
52
+ /** 校验补录日期:`YYYY-MM-DD` 真日期;缺省(`undefined`/空串)即今天。 */
53
+ export function validateCookDate(raw) {
54
+ if (raw === undefined || raw === null || (typeof raw === 'string' && !raw.trim()))
55
+ return todayStr();
56
+ if (typeof raw !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(raw.trim())) {
57
+ throw new ChefPolicyError('POLICY_BAD_INPUT', '补录日期须为 YYYY-MM-DD(实际 ' + JSON.stringify(raw) + ')');
58
+ }
59
+ const text = raw.trim();
60
+ const dt = new Date(text + 'T00:00:00Z');
61
+ if (Number.isNaN(dt.getTime()) ||
62
+ dt.getUTCFullYear() !== Number(text.slice(0, 4)) ||
63
+ dt.getUTCMonth() + 1 !== Number(text.slice(5, 7)) ||
64
+ dt.getUTCDate() !== Number(text.slice(8, 10))) {
65
+ throw new ChefPolicyError('POLICY_BAD_INPUT', '补录日期不是真日期(实际 ' + text + ')');
66
+ }
67
+ return text;
68
+ }
69
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/history/validate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,kDAAkD;AAClD,MAAM,qBAAqB,GAAsB;IAC/C,IAAI;IACJ,KAAK;IACL,IAAI;IACJ,IAAI;IACJ,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,OAAO;IACP,KAAK;IACL,MAAM;IACN,GAAG;IACH,GAAG;IACH,KAAK;IACL,OAAO;CACR,CAAC;AAEF,iDAAiD;AACjD,MAAM,UAAU,gBAAgB,CAAC,GAAY;IAC3C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;QAC3C,MAAM,IAAI,eAAe,CAAC,kBAAkB,EAAE,mCAAmC,CAAC,CAAC;IACrF,CAAC;IACD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACxB,IAAK,qBAA2C,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,eAAe,CAAC,kBAAkB,EAAE,YAAY,GAAG,IAAI,GAAG,uBAAuB,CAAC,CAAC;IAC/F,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,mDAAmD;AACnD,SAAS,QAAQ;IACf,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC/C,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,gBAAgB,CAAC,GAAY;IAC3C,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI,IAAI,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QAAE,OAAO,QAAQ,EAAE,CAAC;IACrG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;QACvE,MAAM,IAAI,eAAe,CAAC,kBAAkB,EAAE,uBAAuB,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;IACrG,CAAC;IACD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACxB,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC,CAAC;IACzC,IACE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC;QAC1B,EAAE,CAAC,cAAc,EAAE,KAAK,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAChD,EAAE,CAAC,WAAW,EAAE,GAAG,CAAC,KAAK,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACjD,EAAE,CAAC,UAAU,EAAE,KAAK,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAC7C,CAAC;QACD,MAAM,IAAI,eAAe,CAAC,kBAAkB,EAAE,eAAe,GAAG,IAAI,GAAG,GAAG,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -1,4 +1,4 @@
1
- export type ChefKey = 'chef.recipe.view' | 'chef.recipe.search' | 'chef.recipe.write' | 'chef.cooking.run' | 'chef.shopping.query' | 'chef.history.record' | 'chef.history.query' | 'chef.help.lookup';
1
+ export type ChefKey = 'chef.recipe.view' | 'chef.recipe.search' | 'chef.recipe.write' | 'chef.cooking.run' | 'chef.shopping.query' | 'chef.history.record' | 'chef.history.query' | 'chef.help.lookup' | 'chef.relation.write' | 'chef.relation.query' | 'chef.setup.init' | 'chef.data.batch';
2
2
  export interface WakeRoute {
3
3
  key: ChefKey;
4
4
  params: Record<string, unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"wakewords.d.ts","sourceRoot":"","sources":["../../src/policy/wakewords.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,OAAO,GACf,kBAAkB,GAAG,oBAAoB,GAAG,mBAAmB,GAAG,kBAAkB,GACpF,qBAAqB,GAAG,qBAAqB,GAAG,oBAAoB,GAAG,kBAAkB,CAAC;AAE9F,MAAM,WAAW,SAAS;IAAG,GAAG,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAAE;AAC7E,MAAM,WAAW,SAAS;IAAG,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAAE;AAEhH,eAAO,MAAM,UAAU,EAAE,SAAS,EAsCjC,CAAC;AAIF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,SAAS,CAmBxF"}
1
+ {"version":3,"file":"wakewords.d.ts","sourceRoot":"","sources":["../../src/policy/wakewords.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,OAAO,GACf,kBAAkB,GAAG,oBAAoB,GAAG,mBAAmB,GAAG,kBAAkB,GACpF,qBAAqB,GAAG,qBAAqB,GAAG,oBAAoB,GAAG,kBAAkB,GAGzF,qBAAqB,GAAG,qBAAqB,GAAG,iBAAiB,GAAG,iBAAiB,CAAC;AAE1F,MAAM,WAAW,SAAS;IAAG,GAAG,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAAE;AAC7E,MAAM,WAAW,SAAS;IAAG,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAAE;AAEhH,eAAO,MAAM,UAAU,EAAE,SAAS,EAyDjC,CAAC;AAIF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,SAAS,CAmBxF"}
@@ -1,5 +1,7 @@
1
- // 口径层·唤醒词路由:自然语言 → 8 联动 key;最长匹配;无命中/缺槽位 throw。
2
- // HELP 速查唯一上游;改这里,HELP 构建期跟进。37 条 = help4 + view7 + search8 (#43 F1 看菜/看菜谱→view) + write4 + cooking4 + shopping4 + record3 + query3。
1
+ // 口径层·唤醒词路由:自然语言 → 联动 key;最长匹配;无命中/缺槽位 throw。
2
+ // HELP 速查唯一上游;改这里,SKILL.md 的说明面与快照(构建期)、HELP 页的卡状态(生成器)三处跟进。
3
+ // 50 条 = 37 条原路由词(下标 1..37 不动)+ 13 条本次接入词(下标 38..50,按域归组)。
4
+ // 改这张表=同时改三处登记面,判据见 `docs/skills/skill-chef/t841-登记面对账.mjs`。
3
5
  import { ChefPolicyError } from '../fetch/errors.js';
4
6
  export const WAKE_TABLE = [
5
7
  { phrase: '私家大厨HELP', key: 'chef.help.lookup' },
@@ -39,6 +41,25 @@ export const WAKE_TABLE = [
39
41
  { phrase: '查看历史', key: 'chef.history.query', needs: ['name'] },
40
42
  { phrase: '查看统计', key: 'chef.history.query', preset: { kind: 'stats' } },
41
43
  { phrase: '体检', key: 'chef.history.query', preset: { kind: 'quality' } },
44
+ // ── 38–50:本次接入的 13 条旧路由表外短语(原文见 `docs/skills/skill-chef/t767-对账表.md` §二)。
45
+ // 这 13 条原是不可路由的老组名;各域在 #770–#776 落好命令分支与页面后,
46
+ // 由 #841 补进本表接管路由。`needs` 逐条对齐各域 run 真正读的参数名,
47
+ // `preset` 逐条对齐 t767 的卡面 `editable_fields`(筛选四条的维度键照卡面写,
48
+ // 不经 `filter` 绕 `cuisine`——同 #771 对既有三条路由错位的处理)。
49
+ // 排序:按域归组,域序照十域表(搜索筛选 → 修改 → 录入 → 派生 → 开始使用 → 数据管理)。
50
+ { phrase: '筛选难度', key: 'chef.recipe.search', needs: ['difficulty'] },
51
+ { phrase: '筛选时间', key: 'chef.recipe.search', needs: ['time_max'] },
52
+ { phrase: '筛选炊具', key: 'chef.recipe.search', needs: ['cookware'] },
53
+ { phrase: '筛选状态', key: 'chef.recipe.search', needs: ['status'] },
54
+ { phrase: '修改步骤', key: 'chef.recipe.write', needs: ['name', 'step'], preset: { op: 'update', target: 'step' } },
55
+ { phrase: '修改食材', key: 'chef.recipe.write', needs: ['name', 'ingredient'], preset: { op: 'update', target: 'ingredient' } },
56
+ { phrase: '导入食谱', key: 'chef.recipe.write', needs: ['name', 'input'], preset: { op: 'add' } },
57
+ { phrase: '添加派生关系', key: 'chef.relation.write', needs: ['child', 'parent', 'relation_type', 'change_summary'] },
58
+ { phrase: '从已有派生新菜', key: 'chef.relation.write', needs: ['source', 'target', 'differences'], preset: { op: 'derive' } },
59
+ { phrase: '首次使用', key: 'chef.setup.init' },
60
+ { phrase: '查看派生关系', key: 'chef.relation.query', needs: ['name'] },
61
+ { phrase: '批量改', key: 'chef.data.batch', needs: ['name'] },
62
+ { phrase: '备份', key: 'chef.history.query', preset: { kind: 'backup' } },
42
63
  ];
43
64
  const SORTED = [...WAKE_TABLE].sort((a, b) => b.phrase.length - a.phrase.length);
44
65
  export function routeWakeword(text, ctx = {}) {