@cyning/harness 2.2.0 → 2.2.1
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/CHANGELOG.md +11 -0
- package/lib/task-close.js +3 -3
- package/lib/task-lint-done.js +3 -3
- package/lib/task-meta.js +8 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [2.2.1] - 2026-07-22
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **slug 一致性误报**:`task close` 检查 4 与 `task lint-done` 的 slug 比较现在对下划线/连字符惯例等价(`task_cyning_harness_a5_*_v1.md` ↔ `cyning-harness-a5-*`,工作区实测命名惯例)。dogfood 本仓 task 时发现:2.2.0 严格相等比较会把全部工作区 task 误 BLOCKED。
|
|
12
|
+
- `lib/task-meta.js` 新增 `normalizeSlug`;两命令双侧规范化后比较。
|
|
13
|
+
|
|
14
|
+
### Notes
|
|
15
|
+
|
|
16
|
+
- patch · 无 CLI breaking · `npm test` 94 全绿
|
|
17
|
+
|
|
7
18
|
## [2.2.0] - 2026-07-22
|
|
8
19
|
|
|
9
20
|
### Added
|
package/lib/task-close.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { extractSection, extractTaskSlug, parseHarnessMeta } from './task-meta.js';
|
|
3
|
+
import { extractSection, extractTaskSlug, normalizeSlug, parseHarnessMeta } from './task-meta.js';
|
|
4
4
|
|
|
5
5
|
const PLACEHOLDER_RE = /^([^)]*(回填|待填)[^)]*)$/;
|
|
6
6
|
const STATUS_RE = /\*\*状态\*\*:?\s*`?([a-z_]+)/i;
|
|
@@ -42,10 +42,10 @@ export function closeTaskFile(filePath, options = {}) {
|
|
|
42
42
|
const fileSlug = extractTaskSlug(abs);
|
|
43
43
|
const slug = meta.task_slug ?? null;
|
|
44
44
|
|
|
45
|
-
// 检查 4 · task_slug
|
|
45
|
+
// 检查 4 · task_slug 一致(下划线/连字符惯例等价)
|
|
46
46
|
if (!slug) {
|
|
47
47
|
blockers.push('Harness 元信息表缺 task_slug');
|
|
48
|
-
} else if (slug !== fileSlug) {
|
|
48
|
+
} else if (normalizeSlug(slug) !== normalizeSlug(fileSlug)) {
|
|
49
49
|
blockers.push(`slug 不一致: 文件名 ${fileSlug} ≠ 元信息 task_slug ${slug}`);
|
|
50
50
|
}
|
|
51
51
|
|
package/lib/task-lint-done.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { extractTaskSlug } from './task-meta.js';
|
|
3
|
+
import { extractTaskSlug, normalizeSlug } from './task-meta.js';
|
|
4
4
|
|
|
5
5
|
const DONE_DIR_CANDIDATES = ['docs/tasks/done', 'docs/harness/tasks/done'];
|
|
6
6
|
|
|
@@ -15,7 +15,7 @@ export function lintDoneInvokes(target) {
|
|
|
15
15
|
const dir = path.join(target, rel);
|
|
16
16
|
if (!fs.existsSync(dir)) continue;
|
|
17
17
|
for (const file of collectMarkdown(dir)) {
|
|
18
|
-
const slug = extractTaskSlug(path.basename(file));
|
|
18
|
+
const slug = normalizeSlug(extractTaskSlug(path.basename(file)));
|
|
19
19
|
if (!doneSlugs.has(slug)) {
|
|
20
20
|
doneSlugs.set(slug, path.relative(target, file).replace(/\\/g, '/'));
|
|
21
21
|
}
|
|
@@ -26,7 +26,7 @@ export function lintDoneInvokes(target) {
|
|
|
26
26
|
const invokeSlugs = new Set();
|
|
27
27
|
if (fs.existsSync(invokeRoot)) {
|
|
28
28
|
for (const ent of fs.readdirSync(invokeRoot, { withFileTypes: true })) {
|
|
29
|
-
if (ent.isDirectory()) invokeSlugs.add(ent.name);
|
|
29
|
+
if (ent.isDirectory()) invokeSlugs.add(normalizeSlug(ent.name));
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
package/lib/task-meta.js
CHANGED
|
@@ -230,6 +230,14 @@ export function extractTaskSlug(fileName) {
|
|
|
230
230
|
return base;
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
+
/**
|
|
234
|
+
* slug 规范化比较:文件名惯例用下划线、task_slug/invoke 目录惯例用连字符
|
|
235
|
+
* (实测工作区:task_cyning_harness_a5_*_v1.md ↔ cyning-harness-a5-*)。
|
|
236
|
+
*/
|
|
237
|
+
export function normalizeSlug(slug) {
|
|
238
|
+
return String(slug).replace(/_/g, '-');
|
|
239
|
+
}
|
|
240
|
+
|
|
233
241
|
function normalizeCell(cell) {
|
|
234
242
|
return cell.replace(/[`\\*]/g, '').trim();
|
|
235
243
|
}
|