@cyning/harness 1.0.1 → 1.0.2

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 CHANGED
@@ -4,6 +4,13 @@
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [1.0.2] - 2026-06-16
8
+
9
+ ### Fixed
10
+
11
+ - **`verify` 无 `--task`**:摘要不再误匹配闸表行 `❌ 拒 30`;多 task 阻塞时摘要列出 blocked task 名
12
+ - **`verify` BLOCKED**:exit 2 时不再打印空 `Error` stack trace
13
+
7
14
  ## [1.0.1] - 2026-06-16
8
15
 
9
16
  ### Added
package/lib/cli.js CHANGED
@@ -14,7 +14,7 @@ import { auditTarget } from './audit.js';
14
14
  import { mergePackageScripts } from './package-scripts.js';
15
15
 
16
16
  function usage() {
17
- console.log(`@cyning/harness · cyning-harness CLI (v1.0.1)
17
+ console.log(`@cyning/harness · cyning-harness CLI (v1.0.2)
18
18
 
19
19
  用法:
20
20
  npx @cyning/harness --version | -V
@@ -348,7 +348,11 @@ async function cmdVerify(args) {
348
348
  // D3 · implemented in lib/verify.js
349
349
  const { verifyTarget } = await import('./verify.js');
350
350
  if (args.includes('--help') || args.includes('-h')) {
351
- console.log(`用法: npx @cyning/harness verify [--target PATH] [--task FILE] [--graph]`);
351
+ console.log(`用法: npx @cyning/harness verify [--target PATH] [--task FILE] [--graph]
352
+
353
+ 无 --task 时:扫描 docs/tasks/active/task_*.md 并逐项列出闸表(同 gate-check)。
354
+ 任一 task 阻塞则 VERIFY: BLOCKED · exit 2;全部可 30 则 VERIFY: PASS。
355
+ `);
352
356
  return;
353
357
  }
354
358
 
@@ -380,9 +384,8 @@ async function cmdVerify(args) {
380
384
  console.log(summary);
381
385
 
382
386
  if (!result.ok) {
383
- const err = new Error('');
384
- err.exitCode = result.exitCode ?? 2;
385
- throw err;
387
+ process.exitCode = result.exitCode ?? 2;
388
+ return;
386
389
  }
387
390
  }
388
391
 
package/lib/verify.js CHANGED
@@ -77,19 +77,68 @@ function runGateCheck(target, taskFile, graph, harnessRoot) {
77
77
  };
78
78
  }
79
79
 
80
- function extractBlockReason(stdout) {
81
- const lines = stdout.split('\n');
82
- for (const line of lines) {
83
- if (line.includes('→ 30 不可开工')) {
84
- return line.trim().replace(/^→\s*/, '');
80
+ function extractBlockReason(stdout, taskFile) {
81
+ const taskBasename = taskFile ? path.basename(taskFile) : undefined;
82
+ const sections = splitGateCheckTaskSections(stdout);
83
+
84
+ if (taskBasename) {
85
+ const section = sections.get(taskBasename) ?? stdout;
86
+ const arrows = extractArrowBlockLines(section);
87
+ if (arrows.length > 0) return arrows[0];
88
+ return 'gate-check blocked';
89
+ }
90
+
91
+ const blocked = [];
92
+ for (const [name, section] of sections) {
93
+ const arrows = extractArrowBlockLines(section);
94
+ if (arrows.length > 0) {
95
+ blocked.push({ name, reason: arrows[0] });
85
96
  }
86
97
  }
87
- for (const line of lines) {
88
- if (line.includes('❌ 30')) {
89
- return line.trim();
98
+
99
+ if (blocked.length === 0) return 'gate-check blocked';
100
+
101
+ const total = sections.size;
102
+ if (blocked.length === 1) {
103
+ const { name, reason } = blocked[0];
104
+ return total === 1 ? reason : `${name} · ${reason}`;
105
+ }
106
+
107
+ const names = blocked.map((b) => b.name).join(', ');
108
+ return `${blocked.length}/${total} tasks blocked · ${names}`;
109
+ }
110
+
111
+ /** 按 gate-check 输出的 `task: xxx.md` 切段 */
112
+ function splitGateCheckTaskSections(stdout) {
113
+ const map = new Map();
114
+ let current = null;
115
+ const lines = [];
116
+
117
+ const flush = () => {
118
+ if (current) map.set(current, lines.join('\n'));
119
+ };
120
+
121
+ for (const line of stdout.split('\n')) {
122
+ const match = line.match(/^task: (.+\.md)\s*$/);
123
+ if (match) {
124
+ flush();
125
+ current = match[1];
126
+ lines.length = 0;
127
+ lines.push(line);
128
+ } else if (current) {
129
+ lines.push(line);
90
130
  }
91
131
  }
92
- return 'gate-check blocked';
132
+ flush();
133
+ return map;
134
+ }
135
+
136
+ /** 只认 gate-check 的 `→ 30 不可开工` 行,避免误匹配表格里的 `❌ 拒 30` */
137
+ function extractArrowBlockLines(section) {
138
+ return section
139
+ .split('\n')
140
+ .filter((line) => line.trimStart().startsWith('→ 30 不可开工'))
141
+ .map((line) => line.trim().replace(/^→\s*/, ''));
93
142
  }
94
143
 
95
144
  function runGitCleanCheck(target) {
package/ontology.yaml CHANGED
@@ -3,7 +3,7 @@
3
3
  # 冲突时以 Markdown 为准 · 供未来 harness ontology-check 使用
4
4
 
5
5
  version: "1.2"
6
- product_semver: "1.0.1"
6
+ product_semver: "1.0.2"
7
7
  license: MIT
8
8
 
9
9
  classes:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyning/harness",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "cyning-harness discipline package · init / upgrade / check CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",