dsh-pighub 0.9.71 → 0.9.74

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.
Binary file
package/lib/assets.js CHANGED
@@ -20,7 +20,8 @@ export const ASSET_ROUTE = '/pighub/asset';
20
20
  * 文件仍放在 assets/img 里(package.json 的 files 已经包含整个 assets/img,不用改发布清单)。
21
21
  */
22
22
  export const PEN_ROUTE = '/pighub/pen';
23
- export const PEN_ART = ['pen-fence.png'];
23
+ // 猪圈布景图:围栏 + 仓库小屋(用户 2026-11-14 指定用这张谷仓图,替掉原来的 SVG 兜底)
24
+ export const PEN_ART = ['pen-fence.png', 'house-barn.png'];
24
25
 
25
26
  /** 读冻结库。缺失或坏掉都不抛:返回 null,由调用方决定怎么降级。 */
26
27
  export function readAssetManifest() {
package/lib/client.js CHANGED
@@ -102,6 +102,8 @@ window.__ModuleLoader__.load({
102
102
  // 但猪走到它前面时猪在小屋之上。小屋整只都在分割线 50.68% 以上,所以永远不会盖到前景栅栏。
103
103
  '.pighub-house{position:absolute;left:9.7%;top:6.7%;width:18%;aspect-ratio:40/34;z-index:' + Z_HOUSE + ';cursor:pointer}',
104
104
  '.pighub-house svg{width:100%;height:100%;display:block;overflow:visible}',
105
+ // 仓库改成位图(谷仓图):铺满盒子并强制拉伸;图本身已去背景(透明)
106
+ '.pighub-house-img{width:100%;height:100%;display:block;object-fit:fill;user-select:none;pointer-events:none}',
105
107
  '.pighub-house-wall{fill:color-mix(in oklab,#f2d8b0 84%,var(--dsw-alias-bg-elevated,#fff))}',
106
108
  '.pighub-house-wall-sh{fill:color-mix(in oklab,#cba57a 82%,var(--dsw-alias-bg-elevated,#fff))}',
107
109
  '.pighub-house-roof{fill:color-mix(in oklab,#dc7148 86%,var(--dsw-alias-bg-elevated,#fff))}',
@@ -1974,8 +1976,36 @@ window.__ModuleLoader__.load({
1974
1976
  h(Meadow, { theme }),
1975
1977
  // 远侧栅栏(顶横梁 + 上角草石 + 侧栏上半):画在猪的后面(z1)
1976
1978
  h(PenFence, { key: 'fence-back', theme }),
1977
- h('div', { className: 'pighub-house', ref: houseRef, title: '把小猪拖进来收进仓库(不再加载)' },
1978
- h(HouseArt, null),
1979
+ /* 小屋(仓库)也纳入主题编辑范围(用户口径 2026-11-14):
1980
+ * theme.house = { image, x, y, w, h }(百分比)。给了 image 就用主题的图,
1981
+ * 没有就继续用内置 SVG —— 两种都用同一个盒子,位置/尺寸由主题覆盖。 */
1982
+ h('div', {
1983
+ className: 'pighub-house',
1984
+ ref: houseRef,
1985
+ title: '把小猪拖进来收进仓库(不再加载)',
1986
+ style: (() => {
1987
+ const house = theme.house || {};
1988
+ const style = {};
1989
+ if (Number.isFinite(house.x)) style.left = house.x + '%';
1990
+ if (Number.isFinite(house.y)) style.top = house.y + '%';
1991
+ if (Number.isFinite(house.w) && house.w > 0) { style.width = house.w + '%'; style.aspectRatio = 'auto'; }
1992
+ if (Number.isFinite(house.h) && house.h > 0) style.height = house.h + '%';
1993
+ if (house.image) {
1994
+ style.backgroundImage = 'url("' + '/pighub/theme/' + encodeURIComponent(theme.name) + '/' + encodeURIComponent(house.image) + '")';
1995
+ style.backgroundSize = '100% 100%'; // 强制拉伸到盒子尺寸,和草坪同一个口径
1996
+ style.backgroundRepeat = 'no-repeat';
1997
+ }
1998
+ return Object.keys(style).length ? style : undefined;
1999
+ })(),
2000
+ },
2001
+ h('img', {
2002
+ className: 'pighub-house-img',
2003
+ draggable: false,
2004
+ alt: '',
2005
+ src: (theme.house && theme.house.image)
2006
+ ? '/pighub/theme/' + encodeURIComponent(theme.name) + '/' + encodeURIComponent(theme.house.image)
2007
+ : '/pighub/pen/house-barn.png',
2008
+ }),
1979
2009
  ),
1980
2010
  penPigs.length === 0
1981
2011
  ? h('div', { className: 'pighub-empty' }, state.phase === 'loading' ? '正在打开猪圈…' : '猪圈还是空的\n点右边的「今日猪猪」领一只')
package/lib/index.js CHANGED
@@ -44,7 +44,7 @@ export const inject = ['tools'];
44
44
  import { startDesktopPet, stopDesktopPet, syncDesktopPet, desktopPetState, sayOnDesktop, reclaimStaleSessions } from './desktop-pet.js';
45
45
 
46
46
  const here = dirname(fileURLToPath(import.meta.url));
47
- const VERSION = '0.9.71';
47
+ const VERSION = '0.9.74';
48
48
  /** 桌面桌宠的精灵边长(CSS px 基准,= manifest 里 sizeRatio 的中位数)。 */
49
49
  const DESKTOP_PET_SIZE = 96;
50
50
  /** 全局尺寸系数(用户口径 2026-11-13:「整体猪猪缩小到 75% 大小」)。三层一起乘。 */
package/lib/themes.js CHANGED
@@ -64,6 +64,18 @@ export function normaliseTheme(raw, name) {
64
64
  split: Number.isFinite(split) && split > 0.05 && split < 0.95 ? split : CLASSIC_FENCE.split,
65
65
  },
66
66
  grassImage: SAFE_FILE.test(String(source.grassImage || '')) ? String(source.grassImage) : '',
67
+ /* 小屋(仓库)也纳入主题编辑范围(用户口径 2026-11-14):image + 百分比盒子,缺项就用 classic 的位置。 */
68
+ house: (() => {
69
+ const raw = source.house && typeof source.house === 'object' ? source.house : {};
70
+ const num = (value, fallback) => (Number.isFinite(Number(value)) ? Number(value) : fallback);
71
+ return {
72
+ image: SAFE_FILE.test(String(raw.image || '')) ? String(raw.image) : '',
73
+ x: num(raw.x, NaN),
74
+ y: num(raw.y, NaN),
75
+ w: num(raw.w, NaN),
76
+ h: num(raw.h, NaN),
77
+ };
78
+ })(),
67
79
  houseImage: source.house && SAFE_FILE.test(String(source.house.image || '')) ? String(source.house.image) : '',
68
80
  };
69
81
  }
@@ -133,7 +145,8 @@ export function validateThemePack(meta, files, prefix) {
133
145
  if (!/^[a-zA-Z0-9._-]{1,48}$/.test(name)) return { ok: false, reason: 'theme_name_invalid:' + name };
134
146
  if (name === CLASSIC_THEME_NAME) return { ok: false, reason: 'theme_name_reserved:classic' };
135
147
  const rel = files.map((f) => (f.name.startsWith(prefix) ? f.name.slice(prefix.length) : f.name)).filter((n) => n && !n.endsWith('/'));
136
- const hasImage = rel.some((n) => /\.(png|jpg|jpeg|webp|svg)$/i.test(n));
148
+ // 用 let:house.image 也算「有图」,下面会把它置 true(const 会在 ESM 严格模式下直接抛错)
149
+ let hasImage = rel.some((n) => /\.(png|jpg|jpeg|webp|svg)$/i.test(n));
137
150
  const geo = meta.geometry;
138
151
  let hasGeometry = false;
139
152
  if (geo !== undefined) {
@@ -151,6 +164,14 @@ export function validateThemePack(meta, files, prefix) {
151
164
  }
152
165
  }
153
166
  if (!hasImage && !hasGeometry) return { ok: false, reason: 'theme_has_nothing:需要至少一张图片或一段合法 geometry' };
167
+ // 小屋图如果声明了,就必须真的在包里(和 fence.image 同一个口径)
168
+ const house = meta.house;
169
+ if (house && typeof house === 'object' && house.image) {
170
+ const img2 = String(house.image);
171
+ if (!/\.(png|jpg|jpeg|webp|svg)$/i.test(img2)) return { ok: false, reason: 'house_image_not_image:' + img2 };
172
+ if (rel.indexOf(img2) < 0) return { ok: false, reason: 'house_image_missing:' + img2 };
173
+ hasImage = true;
174
+ }
154
175
  const fence = meta.fence;
155
176
  if (fence && typeof fence === 'object' && fence.image) {
156
177
  const img = String(fence.image);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-pighub",
3
- "version": "0.9.71",
3
+ "version": "0.9.74",
4
4
  "description": "猪猪库 PigHub 的 DeepSeek Harness 插件:侧边栏猪圈面板、每日一只猪猪、重复获得升星、可拖出的置顶桌宠,数据落在 ~/.PigHub。不内嵌任何上游图片。",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -51,7 +51,9 @@ check('注册了工具、状态路由与每张素材的静态路由', () => {
51
51
  assert.equal(assetRoutes.length, manifest.pigs.length, '每张素材应有一条路由,实际 ' + assetRoutes.length);
52
52
  // 猪圈布景(木栅栏)走单独一条前缀:它不是素材库的一部分,不能混进上面那条「每只猪一条路由」。
53
53
  const penRoutes = [...routes.keys()].filter((path) => path.startsWith('/pighub/pen/'));
54
- assert.deepEqual(penRoutes, ['/pighub/pen/pen-fence.png'], '木栅栏应有且只有一条静态路由,实际 ' + JSON.stringify(penRoutes));
54
+ /* 猪圈布景现在有两张:围栏 + 谷仓小屋(0.9.73 起)。断言条数与内容都跟 PEN_ART 对齐。 */
55
+ assert.deepEqual(penRoutes, ['/pighub/pen/pen-fence.png', '/pighub/pen/house-barn.png'],
56
+ '猪圈布景应有 2 条静态路由(围栏 + 谷仓),实际 ' + JSON.stringify(penRoutes));
55
57
  assert.deepEqual(plugin.inject, ['tools'], '只注入 tools:webServer 缺失时不能让整个 profile 启动失败');
56
58
  });
57
59