@qilitt-mickey/vue3-temp-skill 1.2.7 → 1.2.9

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/bin/cli.js CHANGED
@@ -39,6 +39,13 @@ export function createInstaller({ home = os.homedir(), skillDir = PACKAGE_DIR, c
39
39
  try { return fs.lstatSync(file); } catch (err) { if (err.code === "ENOENT") return null; throw err; }
40
40
  };
41
41
  const conflict = (file) => { throw new Error(`未管理或类型不符的路径冲突,保留原内容: ${file}`); };
42
+ // 迁移受阻一次报全:逐个文件中止会让用户反复重试才知道还有冲突。
43
+ function unclaimed(list, dir) {
44
+ const unique = [...new Set(list)];
45
+ const shown = unique.slice(0, 20);
46
+ const rest = unique.length - shown.length;
47
+ throw new Error(`旧资源冲突:${unique.length} 个路径无法与本包核对,原内容全部保留:\n${shown.map((file) => ` ${file}`).join("\n")}${rest ? `\n …另有 ${rest} 个` : ""}\n人工迁移:把 ${dir} 改名备份(如 ${dir}.bak)后重新执行 ${SKILL_NAME} install <target>;或只删除以上路径后重试 --force。`);
48
+ }
42
49
  function safePath(file) {
43
50
  for (let current = path.resolve(file); ; current = path.dirname(current)) {
44
51
  const info = stat(current);
@@ -115,22 +122,26 @@ export function createInstaller({ home = os.homedir(), skillDir = PACKAGE_DIR, c
115
122
  }
116
123
  return { files: data.files, exists: true };
117
124
  }
118
- if (!force) throw new Error(`未管理的旧目录冲突: ${dir};仅可用 --force 尝试识别自有资源后迁移`);
125
+ if (!force) throw new Error(`未管理的旧目录冲突: ${dir};用 --force 仅迁移可识别的自有资源,或把 ${dir} 改名备份后重新执行 ${SKILL_NAME} install <target>`);
119
126
  source ||= runtimeFiles();
127
+ const keys = [...source.keys()];
120
128
  const files = [];
129
+ const offenders = [];
121
130
  function inspect(relative = "") {
122
131
  for (const entry of fs.readdirSync(path.join(dir, relative), { withFileTypes: true })) {
123
132
  const file = relative ? `${relative}/${entry.name}` : entry.name;
124
133
  const full = path.join(dir, file);
125
- if (entry.isSymbolicLink()) conflict(full);
134
+ if (entry.isSymbolicLink()) { offenders.push(full); continue; }
126
135
  if (entry.isDirectory()) {
127
- if (![...source.keys()].some((key) => key.startsWith(`${file}/`))) conflict(full);
136
+ // 整目录不可核对时只报目录本身,不把它里面的文件逐个铺开。
137
+ if (!keys.some((key) => key.startsWith(`${file}/`))) { offenders.push(full); continue; }
128
138
  inspect(file);
129
139
  } else if (entry.isFile() && source.has(file) && fs.readFileSync(full).equals(source.get(file))) files.push(file);
130
- else conflict(full);
140
+ else offenders.push(full);
131
141
  }
132
142
  }
133
143
  inspect();
144
+ if (offenders.length) unclaimed(offenders, dir);
134
145
  if (!files.includes("SKILL.md")) conflict(dir);
135
146
  return { files, exists: true, legacy: true };
136
147
  }
@@ -163,17 +174,19 @@ export function createInstaller({ home = os.homedir(), skillDir = PACKAGE_DIR, c
163
174
  safePath(dest);
164
175
  if (!stat(dest)) return { text: "", range: null };
165
176
  if (stat(dest).isDirectory()) {
166
- if (!force) throw new Error(`旧目录占用了索引文件: ${dest};需要 --force 并识别自有资源后迁移`);
177
+ if (!force) throw new Error(`旧目录占用了索引文件: ${dest};把 ${dest} 改名备份后重新执行 ${SKILL_NAME} install <target>,或用 --force 仅迁移可识别的自有资源`);
167
178
  const directory = ownership(dest, force, source);
168
179
  // 索引目录必须可完整移走;不能先删除受管文件再发现其中还留有用户文件。
180
+ const offenders = [];
169
181
  function check(relative = "") {
170
182
  for (const entry of fs.readdirSync(path.join(dest, relative), { withFileTypes: true })) {
171
183
  const file = relative ? `${relative}/${entry.name}` : entry.name;
172
184
  if (entry.isDirectory() && directory.files.some((owned) => owned.startsWith(`${file}/`))) check(file);
173
- else if (!entry.isFile() || (!directory.files.includes(file) && (directory.legacy || file !== MANIFEST))) conflict(path.join(dest, file));
185
+ else if (!entry.isFile() || (!directory.files.includes(file) && (directory.legacy || file !== MANIFEST))) offenders.push(path.join(dest, file));
174
186
  }
175
187
  }
176
188
  check();
189
+ if (offenders.length) unclaimed(offenders, dest);
177
190
  return { text: "", range: null, directory };
178
191
  }
179
192
  if (!stat(dest).isFile()) conflict(dest);
@@ -182,7 +195,7 @@ export function createInstaller({ home = os.homedir(), skillDir = PACKAGE_DIR, c
182
195
  if (cfg.type === "rules" && !range) {
183
196
  const legacyBody = path.join(path.dirname(path.dirname(dest)), "skills", SKILL_NAME);
184
197
  if (!force || text !== legacyRulesText(legacyBody)) {
185
- throw new Error(`未管理的规则文件冲突: ${dest};旧版本需 --force 且可识别,否则请人工迁移`);
198
+ throw new Error(`未管理的规则文件冲突: ${dest};内容与本包旧版本逐字一致时可用 --force 迁移,否则把 ${dest} 改名备份后重新执行 ${SKILL_NAME} install <target>`);
186
199
  }
187
200
  return { text: "", range: null, legacyBody, legacyOwnership: ownership(legacyBody, force, source) };
188
201
  }
@@ -321,6 +334,15 @@ export function createInstaller({ home = os.homedir(), skillDir = PACKAGE_DIR, c
321
334
  jobs = track.filter((entry) => !target || target === "all" || entry.target === target);
322
335
  if (opts.project !== undefined) jobs = jobs.map((entry) => ({ ...entry, project: opts.project }));
323
336
  if (target && target !== "all" && (opts.project !== undefined || jobs.length === 0)) jobs = [{ target, project: opts.project || null }];
337
+ // 批量任务沿用 install 的规则:无 --project 的项目专属目标跳过并说明,不让一条历史记录中止整批。
338
+ if (!target || target === "all") {
339
+ const batch = [];
340
+ for (const job of jobs) {
341
+ if (targets[job.target].projectOnly && !job.project) { log(`${job.target} 仅支持项目安装,未指定 --project,已跳过`); continue; }
342
+ batch.push(job);
343
+ }
344
+ jobs = batch;
345
+ }
324
346
  }
325
347
  const identity = (entry) => JSON.stringify([entry.target, entry.project]);
326
348
  jobs = [...new Map(jobs.map((entry) => [identity(entry), entry])).values()];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qilitt-mickey/vue3-temp-skill",
3
- "version": "1.2.7",
3
+ "version": "1.2.9",
4
4
  "type": "module",
5
5
  "description": "vue3-web-temp 项目工程技能:按需功能开发、保留业务的设计还原与视觉及功能双重验证",
6
6
  "bin": {
@@ -29,6 +29,9 @@
29
29
  - 对同一视觉角色的不同实例使用独立作用域或变体;不以通用角色类将所有页面强制变成同一布局。
30
30
  - 布局允许调整 display、方向和层次;调整前明确节点职责,调整后检查子节点、引用及高度链。不要把只应作用在工具栏的横向布局挂到复合根。
31
31
  - 核查变量宿主、选择器特异性、组件 scoped 注入顺序和行内样式;后置 import 后仍需实测。必要时在最小范围对单属性提权并说明原因。
32
+ - 全局覆盖层(`src/styles/element-plus.scss`)逐条提权:顶层选择器统一加 `html` 前缀(`html .el-*` 为 0-1-1,含伪类/多类时更高);根级 `--el-*` 桥接写在 `html:root`;组件级变量写在组件类上,页根覆盖无效。
33
+ - 行高令牌生效时把单元格纵向 padding 归零,由 `height` + 垂直居中承担留白;EP 复选框、开关、按钮的出厂高度(28/32px)会顶高表格行,需实测 th/td 的 computed height。
34
+ - computed `border-width` 会被设备像素吸附(写 1px 可能读到 0.8px);按令牌与声明值判定命中,不以吸附后的 computed 判失败。
32
35
  - 完成条件:每条新增视觉规则在真实页面命中预期节点,未污染其他页面或状态。
33
36
 
34
37
  ## 3. 保留项目结构与能力
@@ -24,6 +24,7 @@
24
24
  - 检查 `src/layout`、`src/styles/design-tokens.scss`、`design-shell.scss`、`sidebar.scss`、`element-plus.scss`、页面 scoped 样式和入口导入顺序;读取相关 `Re*` 与 Hooks 的真实 Props、Emits、Slots 和 DOM。
25
25
  - 按实际依赖读取适配:Element Plus 用 `references/adapters/vue-element-plus.md`,Ant Design Vue 用 `references/adapters/vue-antdv.md`;其他 Vue 组件库按 `references/adapters/_new-adapter.md` 核对实际 DOM、绘制层和状态。不用静态 adapter 的默认颜色或尺寸覆盖原稿。
26
26
  - 检查 fixed 侧栏、主体 margin、固定顶栏、内容 padding、`data-content-mode`、`data-fill` 及内部滚动之间的关系。每项几何只保留一个负责机制,避免旧偏移与新 grid 叠加。
27
+ - 执行层叠三查:① 核对 `main.ts` 样式导入顺序(`index.scss` 先、`element-plus/dist/index.css` 后)与 `public/platform-config.json` 的 `EpThemeColor`/`Theme`;② 覆盖 `--el-*` 根级变量写在 `html:root`,同权 `:root` 会被后加载的 EP 默认值胜出;③ EP 组件级变量声明在组件类上(`.el-card{--el-card-border-radius}`、`.el-button{--el-button-*}`),页面根覆盖无效,只在 `element-plus.scss` 用 `html .el-*`(≥0-1-1)覆盖绘制属性本身。主色由 `useTheme` 以 `documentElement` 内联样式写入并高于任何样式表,改主色改 `EpThemeColor`;EP 出厂 `--el-color-primary-light-*` / `-dark-*` 为写死绝对值,按品牌色显式重算色阶。
27
28
  - 列表保留 `content`、`otherRef`、`multipleTableRef` 和分页/表格容器约束;保留 `ReTableBar` 密度与列控制、`RePagination` 事件、`ReTableOperate` 权限和操作分发。
28
29
  - 完成条件:目标区域的 DOM、样式来源和业务依赖均已核对;不存在按想象挂 class 或重复挂载 Layout。
29
30
 
@@ -43,6 +44,7 @@
43
44
  ## 5. 双重验收
44
45
 
45
46
  - 执行 `code-quality.md` 的工程及业务检查,再执行 `visual-verification.md` 的原稿对照。
47
+ - 还原链路新建的 `.design/<任务>/` 只作原稿与证据,不入工程检查:`eslint.config.mjs` 的 `ignores` 追加 `**/.design/**`(`/.design`、`/.design/**` 对隐藏目录遍历无效),stylelint glob 同样排除该目录。
46
48
  - 逐项复核业务基线:接口/参数、字段、菜单、路由、权限、字典、校验、事件及状态流。对视图重构后的交互实际操作验证。
47
49
  - 在同一运行环境对原稿和实现截图,按映射逐区域测量和目视对照;差异定位到源值、DOM、层叠、字体、素材或布局,修复后重测。
48
50
  - 只在原稿证据证明抽取错误时修改交接;不得改原稿、调整阈值、删除必需区域或修改项目业务让验收变绿。
@@ -12,6 +12,7 @@
12
12
 
13
13
  - 先对比整体截图,再逐区域裁切对比。检查外壳尺寸与偏移、内容边界、对齐、滚动、控件间距、字体行高、图标路径/线宽、边框圆角、阴影、图片裁切和伪元素。
14
14
  - 采集对应节点的 `getBoundingClientRect()` 与实际绘制层 `getComputedStyle()`;每个预期实例分别检查。相同角色存在多个实例时不得以其中一个通过代替全部。
15
+ - 会话无可视视口(`innerWidth` 为 0、截图不可用)时,用注入探针读取 `getComputedStyle()` 作为计算样式级证据:探针必须复刻组件真实祖先(如 `.el-checkbox` 包 `.el-checkbox__inner`、`.re-table-operate` 包 `.el-button`),并按被测角色分别放置节点,避免同层其它容器改写取值;此类证据标注「计算样式级」,`unverified` 保留悬停、滚动与逐像素项。
15
16
  - 缺失、隐藏、尺寸为零、被遮挡或选择器未命中的必需元素记 `fail`,不记 `skip`。
16
17
  - 检查表头换行、长文本、操作列裁切、表格横向滚动及固定列底色、弹层层级、菜单折叠和页签激活/关闭。
17
18
  - 可比内容相同时保留全图及区域像素 diff/叠加图;记录工具、算法、阈值、差异像素及区域。没有像素工具时保留并排/叠加图与几何实测,注明「未做像素级检查」。