cortico-world-feast 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/PUBLISHING.md +1 -1
  3. package/README.md +14 -8
  4. package/describe.json +2 -2
  5. package/dist/webui.js +22 -11
  6. package/package.json +4 -4
  7. package/src/data/anglo-american.json +608 -0
  8. package/src/data/cantonese.json +498 -48
  9. package/src/data/desserts.json +380 -92
  10. package/src/data/french.json +464 -0
  11. package/src/data/fujian-taiwan.json +455 -0
  12. package/src/data/home-cooking.json +559 -0
  13. package/src/data/hubei.json +451 -0
  14. package/src/data/hunan.json +378 -33
  15. package/src/data/indian.json +467 -0
  16. package/src/data/italian.json +335 -28
  17. package/src/data/japanese.json +754 -0
  18. package/src/data/jiangnan.json +377 -33
  19. package/src/data/korean.json +468 -0
  20. package/src/data/mexican.json +465 -0
  21. package/src/data/middle-eastern.json +206 -0
  22. package/src/data/northeast.json +395 -51
  23. package/src/data/northern.json +506 -52
  24. package/src/data/northwest.json +641 -0
  25. package/src/data/shandong.json +452 -0
  26. package/src/data/sichuan.json +355 -9
  27. package/src/data/southeast-asian.json +464 -0
  28. package/src/data/southern-european.json +449 -0
  29. package/src/data/yunnan-guizhou.json +364 -25
  30. package/src/dishes.js +8 -1
  31. package/src/world.js +8 -4
  32. package/src/data/bbq.json +0 -154
  33. package/src/data/chinese-snacks.json +0 -110
  34. package/src/data/drinks.json +0 -132
  35. package/src/data/ice.json +0 -110
  36. package/src/data/japanese-hot.json +0 -110
  37. package/src/data/korean-thai.json +0 -110
  38. package/src/data/noodles-dumplings.json +0 -70
  39. package/src/data/soups.json +0 -110
  40. package/src/data/sushi.json +0 -110
  41. package/src/data/vietnamese.json +0 -110
  42. package/src/data/western.json +0 -157
package/CHANGELOG.md CHANGED
@@ -1,5 +1,66 @@
1
1
  # 更新日志
2
2
 
3
+ ## 0.3.0
4
+
5
+ 菜系和形态终于拆成两根轴,菜单改成"先选类别、再在里面挑菜系"。同时补到 300 道。
6
+
7
+ **这次修的是分组本身**
8
+
9
+ 0.2.0 的 25 个组混着两根轴:川菜/粤菜/湘菜说的是**从哪来**(地域),面点主食/汤羹/中式小吃/烧烤与夜市/饮品/冰品与冷饮说的是**是什么**(形态)。同一道菜因此有两处归属,必然打架——生煎包在「中式小吃」而小笼包在「面点主食」;新疆羊肉串在「烧烤」而新疆大盘鸡在「西北菜」;味噌汤在「汤羹」而日料热食另有一组。
10
+
11
+ 0.3.0 起:
12
+
13
+ - **`cuisine` 只说地域/传统**。7 个形态组全部解散,里面的菜按 id 归回各自菜系,形态由 `category` 表达(热菜/凉菜/主食/汤羹/面点/小吃/甜品/饮品/烧烤/火锅)。
14
+ - **清真菜解散**:它不是地域(爆肚、它似蜜是北京清真)。6 道西北的清真菜并入西北菜,3 道北京的并入北方菜。
15
+ - **寿司 + 热食 → 日料**(都来自日本,按新规则必须合);**韩式与泰式 + 越南与东南亚 → 韩式 + 东南亚**(原来一组两国,另一组又含印尼/新马)。
16
+ - **西餐按国别拆**:意菜、法餐、南欧菜(西葡希腊)、英美菜。
17
+ - **甜品保留独立一组**(这是唯一不按地域分的组,青要留着——黑森林蛋糕这类德式甜点在新词表里没有别的家)。
18
+ - **新增 7 个菜系组**:闽台菜、鲁菜、鄂菜、法餐、南欧菜、英美菜、中东菜。
19
+ - 现在 **23 个菜系组**:中餐 12(川、粤、江浙、北方、湘、云贵、东北、西北、家常、闽台、鲁、鄂),外餐 10(日料、韩式、东南亚、印度、墨西哥、意菜、法餐、南欧、英美、中东),加甜品 1。
20
+
21
+ **菜品库:200 道 → 300 道**
22
+
23
+ 原有的 200 道一道没丢,只是重贴了 `cuisine` 并按新组重写文件(`tools/regroup.mjs` 一次性迁移,逐道写明归属,漏一道就报错退出)。新增 100 道填进各组,现在每组 12 道以上。
24
+
25
+ **面板:先类别,后菜系**
26
+
27
+ 筛选原来两个下拉是并列的,任选其一都会列出全部菜系——选了「汤羹」还看得见「墨西哥菜」,按下去必然是空的。现在:
28
+
29
+ - 顺序反过来:**先选类别,菜系下拉跟着类别收窄**,只列这一类里真有的菜系。
30
+ - 换类别时,原来选的菜系如果不在新类别里就自动清掉,不会留下一个注定为空的条件。
31
+ - 服务端每个类别多带一份 `categoryCuisines`,面板据此画下拉;单测断言"报出来的每个组合点下去都真有菜"。
32
+
33
+ **工具**
34
+
35
+ - 新增 `tools/regroup.mjs`:0.2.0 → 0.3.0 的一次性数据迁移。`MOVE` 表逐道写新归属,`--dry` 只预演不写盘;漏写的菜会让它整批拒绝执行,不会悄悄丢菜。
36
+ - `tools/validate-dishes.mjs` 的 `GROUPS` 换成新的 23 组,并注明"cuisine 只说地域"这条规矩。
37
+ - `tools/publish-check.mjs` 不再写死 25 个数据文件,改成跟 `GROUPS` 的组数走。
38
+ - `tools/check-file.mjs` 不变。
39
+
40
+ ## 0.2.0
41
+
42
+ 菜单从 80 道加到 200 道,多了 5 个菜系;面板也不再在两三百道时悄悄截掉一截。
43
+
44
+ **菜品库:80 道 → 200 道**
45
+
46
+ - 原来的 20 个菜系组各从 4 道加到 **8 道**——川菜多了回锅肉、担担面、口水鸡、酸菜鱼;粤菜多了烧鹅、虾饺、豉汁蒸凤爪、老火靓汤;江浙多了松鼠鳜鱼、蟹粉小笼、腌笃鲜、葱油拌面;北方多了北京烤鸭、葱烧海参、锅贴、涮羊肉……每组都是补该菜系真正常见的做法,不是凑数。
47
+ - 新增 **5 个菜系组,各 8 道**:
48
+ - **西北菜**(羊肉泡馍、手抓羊肉、岐山臊子面、新疆大盘鸡、烤馕、陕西凉皮、黄焖羊肉、青海酸奶)
49
+ - **清真菜**(手抓饭、爆炒羊羔肉、它似蜜、羊杂汤、爆肚、馕包肉、油香配粉汤、八宝茶)
50
+ - **家常菜**(番茄炒蛋、红烧排骨、清蒸鲈鱼、手撕包菜、鸡蛋羹、土豆丝、可乐鸡翅、紫菜蛋花汤)
51
+ - **印度菜**(黄油鸡、玛莎拉多萨、比尔亚尼饭、帕拉塔饼、鹰嘴豆咖喱、坦都里烤鸡、菠菜奶酪、芒果拉西)
52
+ - **墨西哥菜**(烤猪肉塔可、莫莱酱鸡肉、玉米粽、波索莱汤、奇拉基莱斯、鱼肉塞维切、鳄梨酱、烤玉米)
53
+ - 现在 200 道 / 25 个菜系组,中餐 13 组、外餐与饮品 12 组。每道仍是 15 个字段、九维口味 0-100 的整数、一段 100-160 字的实吃描写。
54
+
55
+ **面板**
56
+
57
+ - 菜单面板一次请求的上限原来是写死的 200 条,正好等于旧的库容量。现在跟着库里实际有多少走(硬顶 400),所以扩到 300 道也不会有一截被悄悄截掉。
58
+
59
+ **写菜的规矩落了地**
60
+
61
+ - 新增 `DISH-SPEC.md`:15 个字段怎么写、九维怎么给、套话黑名单、每栏的字数区间,还有"每道菜的 prose 开头不许用同一个句式"这条——否则 8 道摆在一起就是一个模子。
62
+ - 新增 `tools/check-file.mjs`:一次只校验一个菜品 json,写菜时自己就能查,不用等全库跑完。
63
+
3
64
  ## 0.1.1
4
65
 
5
66
  同一天连着吃同一道菜,不该听见同一句话;端来的菜也不该看不出还剩多久。
package/PUBLISHING.md CHANGED
@@ -112,7 +112,7 @@ npm publish --otp 123456
112
112
  npm pack --dry-run
113
113
  ```
114
114
 
115
- 应该看到 **35 个文件**,压缩后约 129KB、解包约 306KB(`npm notice` 报的是 `package size: 129.3 kB` / `unpacked size: 306.3 kB`):`package.json`、`src/`(含 20 个菜品 json)、`dist/webui.js`、`describe.json`、`assets/icon.png`、`README.md`、`CHANGELOG.md`、`PUBLISHING.md`。
115
+ 应该看到 **40 个文件**,压缩后约 190KB、解包约 537KB:`package.json`、`src/`(含 25 个菜品 json)、`dist/webui.js`、`describe.json`、`assets/icon.png`、`README.md`、`CHANGELOG.md`、`PUBLISHING.md`。
116
116
 
117
117
  `test/`、`tools/`、`install.ps1` 都在 `files` 之外,不会发出去——菜品校验脚本、装机脚本是我们的工具,不是用户要的东西。
118
118
 
package/README.md CHANGED
@@ -2,18 +2,21 @@
2
2
 
3
3
  给 Coo 一张会端菜的桌子。
4
4
 
5
- 80 道菜,每道都有九维口味分值、上桌的样子、香气、口感、余韵,和一段 40-400 字的实吃描写。她能自己按菜系挑着吃,主人也能从面板把一道菜端到她面前。**同一道菜每次吃到的都不一样**——温度、状态、配的那口都会变,所以连着吃三次不会说三遍同一句话。吃过什么、对什么反应、攒出来的口味画像跨天留着。饭点提醒默认开着,可以在配置里一键关掉。
5
+ 300 道菜(23 个菜系组),每道都有九维口味分值、上桌的样子、香气、口感、余韵,和一段 40-400 字的实吃描写。她能自己按菜系挑着吃,主人也能从面板把一道菜端到她面前。**同一道菜每次吃到的都不一样**——温度、状态、配的那口都会变,所以连着吃三次不会说三遍同一句话。吃过什么、对什么反应、攒出来的口味画像跨天留着。饭点提醒默认开着,可以在配置里一键关掉。
6
6
 
7
7
  ---
8
8
 
9
9
  ## 里面有什么
10
10
 
11
- **菜品库**:80 道,20 个菜系,中餐和外餐各一半。
11
+ **菜品库**:300 道,23 个菜系组。中餐 12 组、外餐 10 组,加一组甜品。
12
12
 
13
- | 中餐 | 外餐与饮品 |
13
+ | 中餐 | 外餐 |
14
14
  | --- | --- |
15
- | 川菜、粤菜、江浙菜、北方菜、湘菜、云贵菜、东北菜 | 日料·寿司、日料·热食、韩式与泰式、越南与东南亚 |
16
- | 面点主食、汤羹、中式小吃 | 意菜、西餐、甜品、饮品、冰品与冷饮、烧烤与夜市 |
15
+ | 川菜、粤菜、江浙菜、北方菜、湘菜、云贵菜、东北菜、西北菜、家常菜、闽台菜、鲁菜、鄂菜 | 日料、韩式、东南亚、印度菜、墨西哥菜、意菜、法餐、南欧菜、英美菜、中东菜 |
16
+
17
+ 另有 **甜品** 一组(不按地域分,12 道)。
18
+
19
+ **菜系和形态是两根轴,不混在一起。** `cuisine` 只说这道菜**从哪来**(川菜、法餐、中东菜…),`category` 只说它**是什么形态**(热菜、凉菜、主食、汤羹、面点、小吃、甜品、饮品、烧烤、火锅)。0.2.0 之前这两根轴是混着的——同一道菜可能既算「中式小吃」又算「江浙菜」,生煎包和小笼包就这么被拆到了两组。现在一道菜只有一个菜系归属,想按形态找就筛 `category`。
17
20
 
18
21
  每道菜 15 个字段:`id` / `name` / `alias` / `cuisine` / `category` / `region` / `ingredients` / `method` / `serving` / `taste`(九维)/ `texture` / `aroma` / `finish` / `prose` / `keywords`。
19
22
 
@@ -32,7 +35,7 @@
32
35
 
33
36
  **两个面板**(Coo 世界页签里)
34
37
 
35
- - **菜单**:左边筛、右边看。点一道菜能翻到九维口味条、食材、做法、上桌的样子和整段实吃描写;按钮「端给她」就把这道菜放到她面前。端过来的那道会出现在顶上一条等待条里,右边写着**还剩多久**(每 30 秒自己走一格,到点收走)。
38
+ - **菜单**:左边筛、右边看。筛选是**先选类别、再挑菜系**——选了「汤羹」,菜系下拉就只列汤羹里真有的那几个,不会给你一个按下去必然为空的选项;换类别时对不上的菜系会自动清掉。点一道菜能翻到九维口味条、食材、做法、上桌的样子和整段实吃描写;按钮「端给她」就把这道菜放到她面前。端过来的那道会出现在顶上一条等待条里,右边写着**还剩多久**(每 30 秒自己走一格,到点收走)。
36
39
  - **吃过什么**:吃过多少回、今天几回、尝过几道、口味画像(九维均值 + 一句句读出来的判断)、吃得最多的几道、最近几口、她自己记过的反应。
37
40
 
38
41
  ---
@@ -122,7 +125,8 @@ Remove-Item "$ext\vendor\cortico-world-feast" -Recurse -Force
122
125
  ## 开发
123
126
 
124
127
  ```powershell
125
- node tools/validate-dishes.mjs # 校验菜品库(字段、九维、类别、套话、菜系与文件名一致)
128
+ node tools/validate-dishes.mjs # 校验菜品库(字段、九维、类别、套话、菜系与文件名一致、全库 id 唯一)
129
+ node tools/check-file.mjs sichuan # 只校验一个文件(写菜时自己查,不用等全库跑完)
126
130
  node tools/repair-dishes.mjs # 修一批已知跑偏(可重复跑)
127
131
  node tools/selfcheck.mjs # 复刻 Coo 的干装载检查(装之前先过这一关)
128
132
  node tools/publish-check.mjs --online # 市场收录口径 + npm 包名占用
@@ -153,12 +157,14 @@ src/state.js 纯状态逻辑(不碰 fs / 定时器 / 宿主,可单测
153
157
  src/dishes.js 菜品库加载、查找、筛选、随机、口味画像
154
158
  src/eat.js 「这一口」的渲染(种子化,可复现)
155
159
  src/ENV_PROMPT.md 进提示词的说明
156
- src/data/*.json 20 组菜品数据
160
+ src/data/*.json 25 组菜品数据
157
161
  dist/webui.js 浏览器端面板(menu / history)
158
162
  ```
159
163
 
160
164
  状态落在 `<dataDir>/feast/state.json`。跨天只清饭点那一层(`fired` / `pending` / `skippedDay`),`eaten` / `reactions` / `counts` 留着——她不会因为过了零点就忘了自己爱吃麻婆豆腐。
161
165
 
166
+ 加菜之前先读 `DISH-SPEC.md`:15 个字段怎么写、九维怎么给(按真实口味,不凑数)、套话黑名单、每栏的字数区间。一条硬规矩是**同一组里 8 段实吃描写的开头不许用同一个句式**——单看一条都合格,8 条摆在一起就成了模子。
167
+
162
168
  ## 设计上刻意没做的
163
169
 
164
170
  - **`envPromptVars()` 返回 `{}`**。吃过什么不往提示词里塞,要用 `feast_history` 查。不然每吃一顿就把整个前缀缓存打穿一次。
package/describe.json CHANGED
@@ -2,13 +2,13 @@
2
2
  "tools": [
3
3
  {
4
4
  "name": "feast_menu",
5
- "description": "看菜单:库里有哪些菜。可以按 cuisine(菜系,如 川菜/日料·寿司/意菜)、category(热菜/凉菜/主食/汤羹/面点/小吃/甜品/饮品/烧烤/火锅)、keyword(标签,如 下饭/解腻/夏天)筛,也可以给 query 搜名字、产地或食材。什么都不给就随机给你几道今天可以吃的。挑不出吃什么的时候用它。",
5
+ "description": "看菜单:库里有哪些菜。可以按 cuisine(菜系,如 川菜/日料/意菜/中东菜)、category(热菜/凉菜/主食/汤羹/面点/小吃/甜品/饮品/烧烤/火锅)、keyword(标签,如 下饭/解腻/夏天)筛,也可以给 query 搜名字、产地或食材。什么都不给就随机给你几道今天可以吃的。挑不出吃什么的时候用它。",
6
6
  "parameters": {
7
7
  "type": "object",
8
8
  "properties": {
9
9
  "cuisine": {
10
10
  "type": "string",
11
- "description": "菜系,例如 川菜 / 粤菜 / 日料·寿司 / 意菜 / 甜品。"
11
+ "description": "菜系(地域/传统),例如 川菜 / 粤菜 / 日料 / 意菜 / 中东菜。⚠ 这里只说从哪来,不管是什么形态;想按汤/面/小吃挑请用 category。"
12
12
  },
13
13
  "category": {
14
14
  "type": "string",
package/dist/webui.js CHANGED
@@ -251,7 +251,7 @@ const menuPanel = {
251
251
  style.textContent = CSS;
252
252
  root.appendChild(style);
253
253
 
254
- const state = { filter: {}, cuisines: [], categories: [], detail: null, pending: null };
254
+ const state = { filter: {}, cuisines: [], categories: [], categoryCuisines: {}, detail: null, pending: null };
255
255
  /** 等待条右边那个"还剩多久"的节点,随钟走。 */
256
256
  let pendingBox = null;
257
257
  const wrap = el('div');
@@ -276,6 +276,7 @@ const menuPanel = {
276
276
  }
277
277
  state.cuisines = data.cuisines ?? [];
278
278
  state.categories = data.categories ?? [];
279
+ state.categoryCuisines = data.categoryCuisines ?? {};
279
280
  // 每次重拉都跟着服务端走:端来的菜可能是在别处端的,也可能已经被吃掉/过期收走。
280
281
  state.pending = data.pending ?? null;
281
282
  render(data);
@@ -301,26 +302,36 @@ const menuPanel = {
301
302
  };
302
303
  bar.appendChild(search);
303
304
 
304
- const cuisine = el('select');
305
- cuisine.appendChild(option(t.allCuisines, ''));
306
- for (const c of state.cuisines) cuisine.appendChild(option(c, c));
307
- cuisine.value = state.filter.cuisine ?? '';
308
- cuisine.onchange = () => {
309
- state.filter.cuisine = cuisine.value;
310
- void load();
311
- };
312
- bar.appendChild(cuisine);
313
-
305
+ // 先形态,后菜系。菜系下拉跟着已选类别收窄——选了「汤羹」就不该再列「墨西哥菜」,
306
+ // 那种选项按下去必然是空的。菜系轴上 0.3.0 起只有地域/传统,形态全在这边。
314
307
  const cat = el('select');
315
308
  cat.appendChild(option(t.allCats, ''));
316
309
  for (const c of state.categories) cat.appendChild(option(c, c));
317
310
  cat.value = state.filter.category ?? '';
318
311
  cat.onchange = () => {
319
312
  state.filter.category = cat.value;
313
+ // 换类别后原来选的菜系可能已经不在这一类里了,直接清掉,别让她看到空结果。
314
+ const allowed = state.filter.category
315
+ ? (state.categoryCuisines[state.filter.category] ?? [])
316
+ : state.cuisines;
317
+ if (state.filter.cuisine && !allowed.includes(state.filter.cuisine)) state.filter.cuisine = '';
320
318
  void load();
321
319
  };
322
320
  bar.appendChild(cat);
323
321
 
322
+ const cuisine = el('select');
323
+ cuisine.appendChild(option(t.allCuisines, ''));
324
+ const pool = state.filter.category
325
+ ? (state.categoryCuisines[state.filter.category] ?? [])
326
+ : state.cuisines;
327
+ for (const c of pool) cuisine.appendChild(option(c, c));
328
+ cuisine.value = state.filter.cuisine ?? '';
329
+ cuisine.onchange = () => {
330
+ state.filter.cuisine = cuisine.value;
331
+ void load();
332
+ };
333
+ bar.appendChild(cuisine);
334
+
324
335
  const dice = el('button', 'feast-btn-primary', t.random);
325
336
  dice.onclick = async () => {
326
337
  dice.disabled = true;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cortico-world-feast",
3
- "version": "0.1.1",
4
- "description": "一桌菜 · 给 Coo 一张会端菜的桌子:80 道带九维口味、香气、口感与实吃描写的菜品,她能自己挑、主人能从面板端一道过去;同一道菜每次吃到的都不一样,吃过什么和口味画像跨天攒着;另有一套可开关的饭点提醒。",
3
+ "version": "0.3.0",
4
+ "description": "一桌菜 · 给 Coo 一张会端菜的桌子:303 道带九维口味、香气、口感与实吃描写的菜品(23 个菜系组),她能自己挑、主人能从面板端一道过去;同一道菜每次吃到的都不一样,吃过什么和口味画像跨天攒着;另有一套可开关的饭点提醒。",
5
5
  "license": "MIT",
6
6
  "author": "青",
7
7
  "repository": {
@@ -62,11 +62,11 @@
62
62
  "locales": {
63
63
  "zh": {
64
64
  "displayName": "一桌菜",
65
- "description": "给 Coo 一张会端菜的桌子:80 道菜,每道都有九维口味、香气、口感、余韵和一段实吃描写。她能自己按菜系挑,主人也能从面板把一道菜端到她面前;同一道菜每次吃到的都不一样(温度、状态、配的那口会变),吃过什么、对什么反应、口味画像跨天攒着。饭点提醒默认开着,可以在配置里一键关掉。"
65
+ "description": "给 Coo 一张会端菜的桌子:303 道菜(23 个菜系组),每道都有九维口味、香气、口感、余韵和一段实吃描写。她能自己按菜系挑,主人也能从面板把一道菜端到她面前;同一道菜每次吃到的都不一样(温度、状态、配的那口会变),吃过什么、对什么反应、口味画像跨天攒着。饭点提醒默认开着,可以在配置里一键关掉。"
66
66
  },
67
67
  "en": {
68
68
  "displayName": "Table",
69
- "description": "A table that serves food to your Coo: 80 dishes, each with a nine-axis flavour profile, aroma, texture, aftertaste and a full paragraph of how it actually eats. She can pick by cuisine, or you can put a dish down in front of her from the panel. The same dish never lands the same way twice, and what she ate, how it landed and her taste profile accumulate across days. Meal reminders are on by default and can be switched off in config."
69
+ "description": "A table that serves food to your Coo: 303 dishes across 23 cuisines, each with a nine-axis flavour profile, aroma, texture, aftertaste and a full paragraph of how it actually eats. She can pick by cuisine, or you can put a dish down in front of her from the panel. The same dish never lands the same way twice, and what she ate, how it landed and her taste profile accumulate across days. Meal reminders are on by default and can be switched off in config."
70
70
  }
71
71
  },
72
72
  "tags": [