spec-wave 2.1.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.
Files changed (175) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +327 -0
  3. package/README.zh-CN.md +327 -0
  4. package/RELEASING.md +52 -0
  5. package/assets/README.md +30 -0
  6. package/assets/ci/samples/README.md +76 -0
  7. package/assets/ci/samples/hgm-ingest.yml.example +42 -0
  8. package/assets/ci/samples/lint-wiki-delta.pin.yml.example +47 -0
  9. package/assets/ci/samples/lint-wiki-delta.yml.example +49 -0
  10. package/assets/ci/samples/pytest.yml.example +49 -0
  11. package/assets/ci/samples/quality.yml.example +56 -0
  12. package/assets/ci/samples/skills-validate.yml.example +38 -0
  13. package/assets/ci/samples/tech-graph.yml.example +55 -0
  14. package/assets/coding_wiki/templates/README.md +115 -0
  15. package/assets/coding_wiki/templates/_index.md +19 -0
  16. package/assets/coding_wiki/templates/context.md +18 -0
  17. package/assets/coding_wiki/templates/stable.md +26 -0
  18. package/assets/coding_wiki/templates/topics/wiki_layout.md +13 -0
  19. package/assets/coding_wiki/templates/topics/wikilinks_export.md +13 -0
  20. package/assets/coding_wiki/templates/volatile.md +25 -0
  21. package/assets/docs/POINTER_ONBOARDING.md +9 -0
  22. package/assets/docs/POINTER_RUNBOOK_wiki_delta.md +18 -0
  23. package/assets/docs/POINTER_SDD_HAT_FLOW.md +8 -0
  24. package/assets/docs/POINTER_USER_GUIDE.md +8 -0
  25. package/assets/graph/stubs/README.md +6 -0
  26. package/assets/graph/templates/00_main.graph.yaml +72 -0
  27. package/assets/graph/templates/00_main.md +85 -0
  28. package/assets/graph/templates/01_struct.md +38 -0
  29. package/assets/graph/templates/02_version.md +7 -0
  30. package/assets/graph/templates/10_flow_MAIN.graph.yaml +105 -0
  31. package/assets/graph/templates/10_flow_MAIN.md +103 -0
  32. package/assets/graph/templates/99_mermaid_protocol.md +156 -0
  33. package/assets/graph/templates/README.md +66 -0
  34. package/assets/harness/README.md +18 -0
  35. package/assets/harness/discipline-coverage.yaml +320 -0
  36. package/assets/harness/invokes/README.md +22 -0
  37. package/assets/harness/invokes/TEMPLATE_invoke.md +61 -0
  38. package/assets/harness/lifecycle.yaml +127 -0
  39. package/assets/harness/prompts/00-orchestrator.md +91 -0
  40. package/assets/harness/prompts/10-spec-requirements.md +63 -0
  41. package/assets/harness/prompts/10-task-requirements.md +70 -0
  42. package/assets/harness/prompts/20-spec-audit.md +50 -0
  43. package/assets/harness/prompts/20-task-audit.md +90 -0
  44. package/assets/harness/prompts/30-execute-code.md +64 -0
  45. package/assets/harness/prompts/40-self-check.md +65 -0
  46. package/assets/harness/prompts/FRAGMENT_00_delegate_only_v1_zh.md +19 -0
  47. package/assets/harness/prompts/FRAGMENT_30_gate_verify_v1_zh.md +34 -0
  48. package/assets/harness/prompts/FRAGMENT_30_invoke_block_v1_zh.md +28 -0
  49. package/assets/harness/prompts/FRAGMENT_hat_reanchor_v1_zh.md +19 -0
  50. package/assets/harness/prompts/README.md +67 -0
  51. package/assets/harness/prompts/TEMPLATE_30_gate_stop.md +36 -0
  52. package/assets/harness/templates/FRAGMENT_task_domain_infer_v1_zh.md +16 -0
  53. package/assets/harness/templates/ONTOLOGY_consumer_slice_v1.md +41 -0
  54. package/assets/harness/templates/QUICKREF_v1_zh.md +35 -0
  55. package/assets/harness/templates/README.md +50 -0
  56. package/assets/harness/templates/TASK_TEMPLATE.md +133 -0
  57. package/assets/harness/templates/TASK_done_README.md +76 -0
  58. package/assets/harness/templates/TASK_epic.md +103 -0
  59. package/assets/harness/templates/TASK_graph_bootstrap.md +115 -0
  60. package/assets/harness/templates/VIEW_done_by_domain.md +66 -0
  61. package/assets/harness/templates/VIEW_done_thin_pointer.md +16 -0
  62. package/assets/ide/adapters/AGENTS.md.fragment.example +33 -0
  63. package/assets/ide/adapters/CLAUDE.md.fragment.example +32 -0
  64. package/assets/ide/adapters/README.md +57 -0
  65. package/assets/ide/adapters/cursor-harness-starter.mdc.example +39 -0
  66. package/assets/ide/commands/claude/kit/apply-standards.md +10 -0
  67. package/assets/ide/commands/claude/kit/gate-status.md +10 -0
  68. package/assets/ide/commands/claude/kit/graph-check.md +8 -0
  69. package/assets/ide/commands/claude/kit/hat-00-delegate.md +9 -0
  70. package/assets/ide/commands/claude/kit/hat-10-spec.md +9 -0
  71. package/assets/ide/commands/claude/kit/hat-10-task.md +9 -0
  72. package/assets/ide/commands/claude/kit/hat-20-spec-audit.md +9 -0
  73. package/assets/ide/commands/claude/kit/hat-20-task-audit.md +9 -0
  74. package/assets/ide/commands/claude/kit/hat-reanchor.md +8 -0
  75. package/assets/ide/commands/claude/kit/init-guide.md +16 -0
  76. package/assets/ide/commands/claude/kit/sync-prompts-guide.md +9 -0
  77. package/assets/ide/commands/claude/kit/verify.md +16 -0
  78. package/assets/ide/commands/cursor/kit-apply-standards.md +12 -0
  79. package/assets/ide/commands/cursor/kit-gate-status.md +12 -0
  80. package/assets/ide/commands/cursor/kit-graph-check.md +10 -0
  81. package/assets/ide/commands/cursor/kit-hat-00-delegate.md +11 -0
  82. package/assets/ide/commands/cursor/kit-hat-10-spec.md +11 -0
  83. package/assets/ide/commands/cursor/kit-hat-10-task.md +11 -0
  84. package/assets/ide/commands/cursor/kit-hat-20-spec-audit.md +11 -0
  85. package/assets/ide/commands/cursor/kit-hat-20-task-audit.md +11 -0
  86. package/assets/ide/commands/cursor/kit-hat-reanchor.md +10 -0
  87. package/assets/ide/commands/cursor/kit-init-guide.md +18 -0
  88. package/assets/ide/commands/cursor/kit-sync-prompts-guide.md +11 -0
  89. package/assets/ide/commands/cursor/kit-verify.md +18 -0
  90. package/assets/ide/host-adapt/README.md +113 -0
  91. package/assets/ide/host-adapt/examples/mvp-hosts.yaml +78 -0
  92. package/assets/ide/host-adapt/host-adapt.schema.json +97 -0
  93. package/assets/ide/skills-orch/README.md +16 -0
  94. package/assets/ide/skills-orch/kit-apply-standards/SKILL.md +17 -0
  95. package/assets/ide/skills-orch/kit-gate-status/SKILL.md +17 -0
  96. package/assets/ide/skills-orch/kit-hat-reanchor/SKILL.md +15 -0
  97. package/assets/ide/skills-orch/kit-init-guide/SKILL.md +23 -0
  98. package/assets/ide/skills-orch/kit-verify/SKILL.md +23 -0
  99. package/assets/ontology.yaml +113 -0
  100. package/assets/skills/README.md +37 -0
  101. package/assets/skills/harness-00-delegate-only/SKILL.md +19 -0
  102. package/assets/skills/harness-10-spec/SKILL.md +63 -0
  103. package/assets/skills/harness-10-task/SKILL.md +70 -0
  104. package/assets/skills/harness-20-spec-audit/SKILL.md +50 -0
  105. package/assets/skills/harness-20-task-audit/SKILL.md +90 -0
  106. package/assets/skills/harness-20-task-audit/references/TEMPLATE_30_gate_stop.md +36 -0
  107. package/assets/skills/harness-hat-reanchor/SKILL.md +19 -0
  108. package/assets/standards/POINTER_workspace_truth_v1_zh.md +42 -0
  109. package/assets/standards/README.md +35 -0
  110. package/assets/standards/SOURCES_v1_zh.md +49 -0
  111. package/assets/standards/TEMPLATE_CODING_BASELINE_L1_v1_zh.md +88 -0
  112. package/assets/standards/TEMPLATE_CODING_BASELINE_L2_backend_v1_zh.md +75 -0
  113. package/assets/standards/TEMPLATE_CODING_BASELINE_L2_frontend_v1_zh.md +76 -0
  114. package/bin/dsh-coding-kit.js +7 -0
  115. package/bin/specgate.js +7 -0
  116. package/bin/validate_template_compliance.py +470 -0
  117. package/cordis.patch.yml +5 -0
  118. package/lib/cli-checks.d.ts +68 -0
  119. package/lib/cli-checks.js +812 -0
  120. package/lib/cli-checks.js.map +1 -0
  121. package/lib/cli-graph-hgm.d.ts +74 -0
  122. package/lib/cli-graph-hgm.js +416 -0
  123. package/lib/cli-graph-hgm.js.map +1 -0
  124. package/lib/cli-graph-yaml.d.ts +79 -0
  125. package/lib/cli-graph-yaml.js +602 -0
  126. package/lib/cli-graph-yaml.js.map +1 -0
  127. package/lib/cli-graph.d.ts +1 -0
  128. package/lib/cli-graph.js +199 -0
  129. package/lib/cli-graph.js.map +1 -0
  130. package/lib/cli-host.d.ts +24 -0
  131. package/lib/cli-host.js +1197 -0
  132. package/lib/cli-host.js.map +1 -0
  133. package/lib/cli-lifecycle.d.ts +2 -0
  134. package/lib/cli-lifecycle.js +401 -0
  135. package/lib/cli-lifecycle.js.map +1 -0
  136. package/lib/cli-refresh-ide-blocks.d.ts +66 -0
  137. package/lib/cli-refresh-ide-blocks.js +484 -0
  138. package/lib/cli-refresh-ide-blocks.js.map +1 -0
  139. package/lib/cli-shared.d.ts +74 -0
  140. package/lib/cli-shared.js +281 -0
  141. package/lib/cli-shared.js.map +1 -0
  142. package/lib/cli-skills.d.ts +52 -0
  143. package/lib/cli-skills.js +363 -0
  144. package/lib/cli-skills.js.map +1 -0
  145. package/lib/cli-status.d.ts +2 -0
  146. package/lib/cli-status.js +251 -0
  147. package/lib/cli-status.js.map +1 -0
  148. package/lib/cli-sync-prompts.d.ts +25 -0
  149. package/lib/cli-sync-prompts.js +158 -0
  150. package/lib/cli-sync-prompts.js.map +1 -0
  151. package/lib/cli-sync.d.ts +2 -0
  152. package/lib/cli-sync.js +124 -0
  153. package/lib/cli-sync.js.map +1 -0
  154. package/lib/cli-task-extra.d.ts +53 -0
  155. package/lib/cli-task-extra.js +408 -0
  156. package/lib/cli-task-extra.js.map +1 -0
  157. package/lib/cli-timeline.d.ts +28 -0
  158. package/lib/cli-timeline.js +68 -0
  159. package/lib/cli-timeline.js.map +1 -0
  160. package/lib/cli-wiki.d.ts +21 -0
  161. package/lib/cli-wiki.js +189 -0
  162. package/lib/cli-wiki.js.map +1 -0
  163. package/lib/cli.d.ts +22 -0
  164. package/lib/cli.js +1034 -0
  165. package/lib/cli.js.map +1 -0
  166. package/lib/host-contract.d.ts +23 -0
  167. package/lib/host-contract.js +143 -0
  168. package/lib/host-contract.js.map +1 -0
  169. package/lib/index.d.ts +18 -0
  170. package/lib/index.js +290 -0
  171. package/lib/index.js.map +1 -0
  172. package/lib/yaml.d.ts +4 -0
  173. package/lib/yaml.js +10 -0
  174. package/lib/yaml.js.map +1 -0
  175. package/package.json +87 -0
@@ -0,0 +1,363 @@
1
+ import { copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync, } from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { fail, isS2AbsPath, packageRoot, resolveTarget, takeOption } from "./cli-shared.js";
5
+ import { yamlDump, yamlLoad } from "./yaml.js";
6
+ export const EXECUTE_TRACK = 'starter-experimental';
7
+ const RESOURCE_RE = /(?<![A-Za-z0-9_])(?:FRAGMENT|TEMPLATE)_[A-Za-z0-9_\-]+\.md/g;
8
+ const MD_LINK_RE = /\]\(\.\/((?:FRAGMENT|TEMPLATE)_[A-Za-z0-9_\-]+\.md)\)/g;
9
+ const NAME_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
10
+ const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---\n([\s\S]*)$/;
11
+ export function parseSkillPrompt(content) {
12
+ const m = FRONTMATTER_RE.exec(content);
13
+ if (!m)
14
+ return { frontmatter: null, body: content };
15
+ try {
16
+ return { frontmatter: yamlLoad(m[1]), body: m[2] };
17
+ }
18
+ catch (e) {
19
+ return { frontmatter: null, body: content, parseError: e.message };
20
+ }
21
+ }
22
+ export function validateSkillFrontmatter(fm, source) {
23
+ const errors = [];
24
+ if (!fm || typeof fm !== 'object')
25
+ return [`${source}: 缺 frontmatter 或非对象`];
26
+ const { name, description, compatibility } = fm;
27
+ if (typeof name !== 'string' || name.length < 1 || name.length > 64) {
28
+ errors.push(`${source}: name 缺失或超长(1–64)`);
29
+ }
30
+ else if (!NAME_RE.test(name)) {
31
+ errors.push(`${source}: name 非法(仅小写字母/数字/单连字符 · 不得首尾连字符/连续连字符): ${name}`);
32
+ }
33
+ if (typeof description !== 'string' || description.length < 1) {
34
+ errors.push(`${source}: description 缺失`);
35
+ }
36
+ else if (description.length > 1024) {
37
+ errors.push(`${source}: description 超长(${description.length} > 1024)`);
38
+ }
39
+ if (compatibility !== undefined) {
40
+ if (typeof compatibility !== 'string' || compatibility.length > 500) {
41
+ errors.push(`${source}: compatibility 超长或非字符串(≤500)`);
42
+ }
43
+ }
44
+ return errors;
45
+ }
46
+ export function loadSkillPrompts({ promptsDir }) {
47
+ const files = readdirSync(promptsDir)
48
+ .filter((f) => f.endsWith('.md'))
49
+ // 00 全文不进默认 Skills(不建 harness-00);TEMPLATE / README 非 skill
50
+ // FRAGMENT_* 仅当带合法 skill frontmatter(name)才入分发(re-anchor / 00-delegate)
51
+ .filter((f) => !/^(README|TEMPLATE_|00-)/.test(f))
52
+ .sort();
53
+ const out = [];
54
+ for (const file of files) {
55
+ const content = readFileSync(path.join(promptsDir, file), 'utf8');
56
+ const { frontmatter, body, parseError } = parseSkillPrompt(content);
57
+ if (/^FRAGMENT_/.test(file) && !parseError && !frontmatter?.name)
58
+ continue;
59
+ const errors = parseError
60
+ ? [`${file}: frontmatter YAML 解析失败: ${parseError}`]
61
+ : validateSkillFrontmatter(frontmatter, file);
62
+ out.push({ file, frontmatter: frontmatter || {}, body, errors });
63
+ }
64
+ return out;
65
+ }
66
+ function rewriteLinks(body) {
67
+ return body.replace(MD_LINK_RE, '](references/$1)');
68
+ }
69
+ function referencedResources(body) {
70
+ return [...new Set(body.match(RESOURCE_RE) || [])].sort();
71
+ }
72
+ function renderSkillMd(frontmatter, body) {
73
+ return `---\n${yamlDump(frontmatter, { lineWidth: -1 })}---\n${body}`;
74
+ }
75
+ function firstSentence(description) {
76
+ const idx = description.indexOf('。');
77
+ return idx === -1 ? description : description.slice(0, idx + 1);
78
+ }
79
+ function renderReadme(skills, { withExecuteHats }) {
80
+ const rows = skills
81
+ .map((s) => `| [\`${s.frontmatter.name}/\`](./${s.frontmatter.name}/SKILL.md) | ${s.frontmatter.metadata?.hat_id ?? ''} | ${firstSentence(s.frontmatter.description || '')} |`)
82
+ .join('\n');
83
+ const executeNote = withExecuteHats
84
+ ? ''
85
+ : `
86
+ ## 执行帽缺席说明
87
+
88
+ \`harness-30-execute\` / \`harness-40-self-check\`(执行帽)**不在本分发**:其 skill 化须先通过 T1 闸绕开评测(\`eval/t1_gate_bypass/\` S1–S3)。
89
+ 评测/维护者可用 \`npx spec-wave skills build --with-execute-hats\` 本地生成(仅供评测环境,勿装入生产 client)。
90
+ `;
91
+ const zeroNote = `
92
+ ## 00 全文缺席说明
93
+
94
+ \`00-orchestrator.md\`(00 全文)**不在本分发**(仅 prompts 同步)。短片段 \`harness-00-delegate-only\` / \`harness-hat-reanchor\` **默认可分发**。
95
+ `;
96
+ return `# skills/ · Agent Skills 标准封装(生成物 · 勿手改)
97
+
98
+ > **本目录由 \`npx spec-wave skills build\` 生成**;真值 = \`harness/prompts/\` 条文(frontmatter + 正文)。
99
+ > 改动请改条文后重跑 build;\`npx spec-wave skills check\` 会拦截任何手改 drift。
100
+ > 规范:https://agentskills.io/specification
101
+
102
+ ## 安装(各 client 路径不同 · 复制或软链均可)
103
+
104
+ | 路径 | 用途 | 谁写入 |
105
+ |------|------|--------|
106
+ | DSH \`<repo>/.dsh/skills/\` | 消费者 Skill 安装落点 | \`npx spec-wave skills install\` |
107
+ | DSH \`$HOME/.dsh/skills/\` | 用户级安装落点 | \`npx spec-wave skills install --global\` |
108
+ | Claude Code \`<repo>/.claude/skills/\` 或 \`~/.claude/skills/\` | Claude skill 目录 | 用户另拷或 \`--out\`;**默认不写** |
109
+
110
+ \`.dsh/coding-kit\` / \`.coding-kit\` 是规范覆盖(\`apply_coding_standards\` / \`init_coding_kit\`),**不是** skill 目录,禁止当作 install dest。
111
+
112
+ 已验证(2026-08-22 · 对照 DSH 上游源码 deepseek-harness@141eb6f,dsh 0.1.0-rc.8):DSH runtime **会自动扫描** \`.dsh/skills\` 与 \`$HOME/.dsh/skills\` 两个 **安装落点** 并 **按需加载**。证据锚点:\`packages/skill/skill-filesystem/src/index.ts:246\`(\`<projectRoot>/.dsh/skills\`,rank 100)与 \`:253\`(\`$DSH_HOME\` 或 \`~/.dsh\` 下 \`skills/\`,rank 400);目录级文档 \`docs/subsystems/skills.md\`「Local discovery priority」表同口径。结构要求:目录包 \`<name>/SKILL.md\` 或平铺 \`<name>.md\`(index.ts:724-728);frontmatter 必填 \`name\`/\`description\`,\`name\` 须 kebab-case(index.ts:810-816)。扫描/加载属 DSH runtime 行为契约,随上游版本演进,锚点对应 0.1.0-rc.8。
113
+
114
+ ## 技能清单
115
+
116
+ | skill | hat_id | 用途 |
117
+ |-------|--------|------|
118
+ ${rows}
119
+ ${executeNote}${zeroNote}`;
120
+ }
121
+ export function generateSkills({ promptsDir, withExecuteHats = false, }) {
122
+ const prompts = loadSkillPrompts({ promptsDir });
123
+ const errors = prompts.flatMap((p) => p.errors);
124
+ const files = new Map();
125
+ const selected = prompts.filter((p) => withExecuteHats || p.frontmatter.metadata?.track !== EXECUTE_TRACK);
126
+ for (const p of selected) {
127
+ const name = p.frontmatter.name;
128
+ if (!name)
129
+ continue;
130
+ files.set(`${name}/SKILL.md`, renderSkillMd(p.frontmatter, rewriteLinks(p.body)));
131
+ for (const res of referencedResources(p.body)) {
132
+ const src = path.join(promptsDir, res);
133
+ if (existsSync(src))
134
+ files.set(`${name}/references/${res}`, readFileSync(src, 'utf8'));
135
+ else
136
+ errors.push(`${p.file}: 引用的资源不存在: ${res}`);
137
+ }
138
+ }
139
+ files.set('README.md', renderReadme(selected, { withExecuteHats }));
140
+ return { files, skills: selected, errors };
141
+ }
142
+ export function buildSkills({ promptsDir, outDir, withExecuteHats = false, }) {
143
+ const { files, errors } = generateSkills({ promptsDir, withExecuteHats });
144
+ if (errors.length > 0) {
145
+ const err = new Error(`skills build 前置校验失败:\n${errors.join('\n')}`);
146
+ throw err;
147
+ }
148
+ rmSync(outDir, { recursive: true, force: true });
149
+ const written = [];
150
+ for (const [rel, content] of [...files.entries()].sort()) {
151
+ const abs = path.join(outDir, rel);
152
+ mkdirSync(path.dirname(abs), { recursive: true });
153
+ writeFileSync(abs, content);
154
+ written.push(rel);
155
+ }
156
+ return { written };
157
+ }
158
+ function readTreeFiles(dir) {
159
+ const out = new Map();
160
+ const walk = (cur, rel) => {
161
+ if (!existsSync(cur))
162
+ return;
163
+ for (const entry of readdirSync(cur, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
164
+ const abs = path.join(cur, entry.name);
165
+ const r = rel ? `${rel}/${entry.name}` : entry.name;
166
+ if (entry.isDirectory())
167
+ walk(abs, r);
168
+ else
169
+ out.set(r, readFileSync(abs, 'utf8'));
170
+ }
171
+ };
172
+ if (existsSync(dir))
173
+ walk(dir, '');
174
+ return out;
175
+ }
176
+ export function checkSkills({ promptsDir, skillsDir, }) {
177
+ const { files: expected, errors } = generateSkills({ promptsDir });
178
+ if (errors.length > 0)
179
+ return { ok: false, errors };
180
+ const actual = readTreeFiles(skillsDir);
181
+ const driftErrors = [];
182
+ for (const key of [...expected.keys()].sort()) {
183
+ if (!actual.has(key))
184
+ driftErrors.push(`缺失: ${key}`);
185
+ else if (actual.get(key) !== expected.get(key))
186
+ driftErrors.push(`drift: ${key}`);
187
+ }
188
+ for (const key of [...actual.keys()].sort()) {
189
+ if (!expected.has(key))
190
+ driftErrors.push(`多余(非生成物或执行帽误入): ${key}`);
191
+ }
192
+ return { ok: driftErrors.length === 0, errors: driftErrors };
193
+ }
194
+ const SKILLS_USAGE = `用法:
195
+ npx spec-wave skills install [--target DIR] [--out DIR] [--global] [--force] [--with-execute-hats]
196
+ npx spec-wave skills build [--with-execute-hats]
197
+ npx spec-wave skills check
198
+
199
+ 落点说明:.dsh/skills 两个安装落点已对照 DSH 上游源码验证(deepseek-harness@141eb6f · 0.1.0-rc.8)——
200
+ DSH runtime 自动扫描 <repo>/.dsh/skills 与 $HOME/.dsh/skills 并按需加载;
201
+ 证据锚点 packages/skill/skill-filesystem/src/index.ts:246 / :253,详见 README「扫描验证」节。
202
+ `;
203
+ export const EXECUTE_HAT_DIRS = new Set(['harness-30-execute', 'harness-40-self-check']);
204
+ function posixNorm(absPath) {
205
+ return path.resolve(absPath).replace(/\\/g, '/');
206
+ }
207
+ function isCodingKitDest(absDest) {
208
+ const n = posixNorm(absDest);
209
+ return (n.endsWith('/.coding-kit') ||
210
+ n.includes('/.coding-kit/') ||
211
+ n.endsWith('/.dsh/coding-kit') ||
212
+ n.includes('/.dsh/coding-kit/'));
213
+ }
214
+ export function isExecuteHatSkipped(parentDir, name, withExecuteHats) {
215
+ if (withExecuteHats)
216
+ return false;
217
+ if (EXECUTE_HAT_DIRS.has(name))
218
+ return true;
219
+ const skillMd = path.join(parentDir, name, 'SKILL.md');
220
+ if (!existsSync(skillMd) || !statSync(skillMd).isFile())
221
+ return false;
222
+ const { frontmatter } = parseSkillPrompt(readFileSync(skillMd, 'utf8'));
223
+ return frontmatter?.metadata?.track === EXECUTE_TRACK;
224
+ }
225
+ function listCopyableSkillDirs(src, withExecuteHats) {
226
+ return readdirSync(src, { withFileTypes: true })
227
+ .filter((ent) => ent.isDirectory() && !isExecuteHatSkipped(src, ent.name, withExecuteHats))
228
+ .map((ent) => ent.name)
229
+ .sort();
230
+ }
231
+ function copySkillsTree({ src, dest, force, withExecuteHats, }) {
232
+ let copied = 0;
233
+ let skipped = 0;
234
+ const visit = (from, to) => {
235
+ mkdirSync(to, { recursive: true });
236
+ for (const ent of readdirSync(from, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
237
+ if (ent.isDirectory()) {
238
+ if (isExecuteHatSkipped(from, ent.name, withExecuteHats))
239
+ continue;
240
+ visit(path.join(from, ent.name), path.join(to, ent.name));
241
+ continue;
242
+ }
243
+ if (!ent.isFile())
244
+ continue;
245
+ const destFile = path.join(to, ent.name);
246
+ if (existsSync(destFile) && !force) {
247
+ skipped += 1;
248
+ continue;
249
+ }
250
+ mkdirSync(path.dirname(destFile), { recursive: true });
251
+ copyFileSync(path.join(from, ent.name), destFile);
252
+ copied += 1;
253
+ }
254
+ };
255
+ visit(src, dest);
256
+ return { copied, skipped };
257
+ }
258
+ function cmdSkillsInstall(args) {
259
+ const global = args.includes('--global');
260
+ const force = args.includes('--force');
261
+ const withExecuteHats = args.includes('--with-execute-hats');
262
+ let rest = args.filter((a) => a !== '--global' && a !== '--force' && a !== '--with-execute-hats');
263
+ const { value: targetArg, rest: r1 } = takeOption(rest, '--target');
264
+ rest = r1;
265
+ const { value: outArg, rest: r2 } = takeOption(rest, '--out');
266
+ rest = r2;
267
+ if (rest.length > 0)
268
+ fail(`skills install 未知参数: ${rest.join(' ')}\n${SKILLS_USAGE}`);
269
+ const hasTarget = targetArg !== undefined;
270
+ const hasOut = outArg !== undefined;
271
+ if (global && (hasOut || hasTarget)) {
272
+ fail(`\`--global\` 与 \`--out\` / \`--target\` 互斥\n${SKILLS_USAGE}`);
273
+ }
274
+ if (hasOut && hasTarget) {
275
+ fail(`\`--out\` 与 \`--target\` 互斥\n${SKILLS_USAGE}`);
276
+ }
277
+ if (hasOut && outArg.startsWith('~')) {
278
+ fail('`--out` 不得以 ~ 开头(禁止在 cwd 创建名为 ~ 的目录)。请用绝对路径或 --global');
279
+ }
280
+ let dest;
281
+ if (global) {
282
+ const home = os.homedir();
283
+ if (!home)
284
+ fail('无法解析 homedir(请设置 HOME 或改用 --out 绝对路径)');
285
+ dest = path.join(home, '.dsh', 'skills');
286
+ }
287
+ else if (hasOut) {
288
+ dest = path.resolve(process.cwd(), outArg);
289
+ }
290
+ else {
291
+ dest = path.join(resolveTarget(process.cwd(), targetArg), '.dsh', 'skills');
292
+ }
293
+ dest = path.resolve(dest);
294
+ if (isCodingKitDest(dest)) {
295
+ fail('拒写:dest 命中 .dsh/coding-kit 或 .coding-kit(规范覆盖目录 ≠ .dsh/skills)');
296
+ }
297
+ if (isS2AbsPath(dest)) {
298
+ fail('拒写:dest 命中 S2 过程域(docs/tasks/ · reviews/ · invokes/by-task/)');
299
+ }
300
+ // DEBT R-05:第四拒写分支——dest 命中产品包自身 assets/skills(安装源 ≠ 安装落点),
301
+ // 含其子目录;判定基准与下方 src 同根(packageRoot()/assets/skills)。
302
+ const packageSkillsRoot = posixNorm(path.join(packageRoot(), 'assets', 'skills'));
303
+ const destNorm = posixNorm(dest);
304
+ if (destNorm === packageSkillsRoot || destNorm.startsWith(`${packageSkillsRoot}/`)) {
305
+ fail('拒写:dest 命中产品包自身 assets/skills(安装源 ≠ 安装落点,会自我覆盖发布资产)');
306
+ }
307
+ if (existsSync(dest) && !statSync(dest).isDirectory()) {
308
+ fail(`dest 已存在且为文件(非目录): ${dest}`);
309
+ }
310
+ // DSH_CK_SKILLS_SRC:内部测试钩子(非公开契约,勿依赖)——允许测试把 skills 源
311
+ // 指向临时副本,避免 install 测试改动包内 assets/skills(DEF-018 T4 / D2=a)。
312
+ const src = process.env.DSH_CK_SKILLS_SRC
313
+ ? path.resolve(process.env.DSH_CK_SKILLS_SRC)
314
+ : path.join(packageRoot(), 'assets', 'skills');
315
+ if (!existsSync(src) || !statSync(src).isDirectory()) {
316
+ fail('源 assets/skills 缺失。消费者请重装 npm 包;维护者请先执行 skills build');
317
+ }
318
+ const skillDirs = listCopyableSkillDirs(src, withExecuteHats);
319
+ if (skillDirs.length === 0) {
320
+ fail('源 assets/skills 无可复制 skill 目录(默认跳过 30/40;可 --with-execute-hats 或先 skills build)');
321
+ }
322
+ const { copied, skipped } = copySkillsTree({ src, dest, force, withExecuteHats });
323
+ console.log(`SKILLS INSTALL: PASS · copied=${copied} skipped=${skipped} → ${dest}`);
324
+ }
325
+ export async function cmdSkills(args) {
326
+ const promptsDir = path.join(packageRoot(), 'assets', 'harness', 'prompts');
327
+ const skillsDir = path.join(packageRoot(), 'assets', 'skills');
328
+ const [sub, ...rest] = args;
329
+ if (!sub || sub === '--help' || sub === '-h' || args.includes('--help') || args.includes('-h')) {
330
+ console.log(SKILLS_USAGE);
331
+ return;
332
+ }
333
+ if (sub === 'install') {
334
+ cmdSkillsInstall(rest);
335
+ return;
336
+ }
337
+ if (sub === 'build') {
338
+ const withExecuteHats = rest.includes('--with-execute-hats');
339
+ const unknown = rest.filter((a) => a !== '--with-execute-hats');
340
+ if (unknown.length > 0)
341
+ fail(`skills build 未知参数: ${unknown.join(' ')}`);
342
+ const { written } = buildSkills({ promptsDir, outDir: skillsDir, withExecuteHats });
343
+ console.log(`SKILLS BUILD: PASS · ${written.length} 文件 → ${skillsDir}${withExecuteHats ? '(含执行帽 · 仅供评测环境)' : ''}`);
344
+ return;
345
+ }
346
+ if (sub === 'check') {
347
+ const unknown = rest.filter((a) => a !== '--json');
348
+ if (unknown.length > 0)
349
+ fail(`skills check 未知参数: ${unknown.join(' ')}`);
350
+ const r = checkSkills({ promptsDir, skillsDir });
351
+ if (rest.includes('--json'))
352
+ console.log(JSON.stringify(r, null, 2));
353
+ else if (r.ok)
354
+ console.log('SKILLS CHECK: PASS · frontmatter 合法 · skills/ 无 drift');
355
+ else
356
+ console.log(`SKILLS CHECK: FAIL\n${r.errors.map((e) => ` - ${e}`).join('\n')}`);
357
+ if (!r.ok)
358
+ fail('skills check FAIL', 2);
359
+ return;
360
+ }
361
+ fail(`skills 子命令未知: ${sub ?? '(空)'}\n${SKILLS_USAGE}`);
362
+ }
363
+ //# sourceMappingURL=cli-skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-skills.js","sourceRoot":"","sources":["../src/cli-skills.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function cmdStatus(args: string[]): Promise<void>;
2
+ export declare function cmdTimeline(args: string[]): Promise<void>;
@@ -0,0 +1,251 @@
1
+ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { evaluateMayStart30, extractHatsFromInvokeFilename, fail, normalizeSlug, parseHarnessMeta, parseHumanGates, resolveTarget, resolveTaskPath, STATUS_RE, takeOption, toRel, } from "./cli-shared.js";
4
+ // DEF-003 T3/T4:findReview 单一实现源迁至 cli-checks.ts(verify / dry-run / status 共用)
5
+ import { findReview } from "./cli-checks.js";
6
+ import { summarizeTaskHgm } from "./cli-graph-hgm.js";
7
+ const OBS_STATUS_SCHEMA = 'obs_status.v1';
8
+ // DEF-016 D1:reviews.CLOSE 检测口径与 cli.ts CLOSE_STATUSES 同(done/completed)
9
+ const CLOSE_STATUSES = new Set(['done', 'completed']);
10
+ function extractTaskStatus(content) {
11
+ const m = content.match(STATUS_RE);
12
+ return m ? m[1].toLowerCase() : null;
13
+ }
14
+ function listActiveTasks(target) {
15
+ const dirs = [path.join(target, 'docs/tasks/active'), path.join(target, 'docs/harness/tasks/active')];
16
+ const out = [];
17
+ for (const dir of dirs) {
18
+ if (!existsSync(dir))
19
+ continue;
20
+ for (const name of readdirSync(dir)) {
21
+ if (!name.endsWith('.md') || !name.startsWith('task_'))
22
+ continue;
23
+ out.push(toRel(target, path.join(dir, name)));
24
+ }
25
+ }
26
+ return out.sort();
27
+ }
28
+ function findLastInvoke(target, slug) {
29
+ const empty = { path: null, hat_id: null };
30
+ if (!slug)
31
+ return empty;
32
+ const candidates = [
33
+ path.join(target, 'docs/harness/invokes/by-task', slug),
34
+ path.join(target, 'docs/harness/invokes/by-task', normalizeSlug(slug)),
35
+ path.join(target, 'invokes/by-task', slug),
36
+ ];
37
+ if (slug.includes('-')) {
38
+ candidates.push(path.join(target, 'docs/harness/invokes/by-task', slug.replace(/-/g, '_')));
39
+ }
40
+ let best = null;
41
+ for (const dir of candidates) {
42
+ if (!existsSync(dir))
43
+ continue;
44
+ for (const name of readdirSync(dir)) {
45
+ if (!name.endsWith('.md'))
46
+ continue;
47
+ const abs = path.join(dir, name);
48
+ const st = statSync(abs);
49
+ if (!best || st.mtimeMs > best.mtimeMs) {
50
+ const hats = extractHatsFromInvokeFilename(name);
51
+ best = {
52
+ mtimeMs: st.mtimeMs,
53
+ path: toRel(target, abs),
54
+ hat_id: hats[0] || null,
55
+ };
56
+ }
57
+ }
58
+ }
59
+ if (!best)
60
+ return empty;
61
+ return { path: best.path, hat_id: best.hat_id };
62
+ }
63
+ function buildTaskStatus(target, taskFile, options = {}) {
64
+ const absTask = resolveTaskPath(target, taskFile);
65
+ if (!existsSync(absTask))
66
+ fail(`task 文件不存在: ${taskFile}`);
67
+ const content = readFileSync(absTask, 'utf8');
68
+ const meta = parseHarnessMeta(content);
69
+ const gates = parseHumanGates(content);
70
+ const gateEval = evaluateMayStart30(gates);
71
+ const slug = meta.task_slug || path.basename(absTask, '.md');
72
+ const blockers = [];
73
+ for (const g of gates) {
74
+ if (g.status !== 'approved' && String(g.blocksHats || '').includes('30')) {
75
+ blockers.push(`${g.id}=${g.status}`);
76
+ }
77
+ }
78
+ if (blockers.length === 0 && !gateEval.ok && gateEval.reason)
79
+ blockers.push(gateEval.reason);
80
+ const reviewFound = findReview(target, absTask);
81
+ const lastInvoke = findLastInvoke(target, slug);
82
+ const hgm = summarizeTaskHgm(target, slug);
83
+ const taskStatus = extractTaskStatus(content);
84
+ // DEF-016 D1(接线):CLOSE = 关账完成信号(代理口径,非「close 审查通过」强证据)——
85
+ // task 状态 ∈ CLOSE_STATUSES(与 task close 归档行为对齐)或文件位于 done/ 目录。
86
+ const inDoneDir = absTask.split(path.sep).includes('done');
87
+ const closeDone = (taskStatus !== null && CLOSE_STATUSES.has(taskStatus)) || inDoneDir;
88
+ const payload = {
89
+ schema_version: OBS_STATUS_SCHEMA,
90
+ task_slug: slug,
91
+ task_path: toRel(target, absTask),
92
+ status: taskStatus || 'unknown',
93
+ gates: gates.map((g) => ({ id: g.id, status: g.status, blocks_hats: g.blocksHats })),
94
+ may_start_30: gateEval.ok,
95
+ blockers,
96
+ last_invoke: lastInvoke,
97
+ reviews: { R1: reviewFound, CLOSE: closeDone },
98
+ verify_preview: {
99
+ ok: gateEval.ok,
100
+ reason: gateEval.ok ? '闸投影 PASS(非正式 verify)' : gateEval.reason,
101
+ },
102
+ hgm: { event_count: hgm.event_count, last_at: hgm.last_at },
103
+ kpi_section: /^###\s*KPI/m.test(content),
104
+ next_hint: gateEval.ok ? '闸已齐 · 跑 verify 后开 30(status 不替代 verify)' : `签收阻塞闸后再开 30(${blockers[0] || '见 gates'})`,
105
+ };
106
+ const warnings = [];
107
+ let checkFailed = false;
108
+ if (options.check) {
109
+ const checkReasons = [];
110
+ if (!reviewFound)
111
+ checkReasons.push('missing R<n> review');
112
+ if (!gateEval.ok) {
113
+ checkReasons.push(`may_start_30=false · ${gateEval.reason || blockers.join('; ') || 'blocked'}`);
114
+ }
115
+ if (checkReasons.length > 0) {
116
+ checkFailed = true;
117
+ for (const r of checkReasons)
118
+ warnings.push(`FAIL: status --check · ${r}`);
119
+ }
120
+ else {
121
+ warnings.push('OK: status --check passed(仍须正式 harness verify;--check ≠ 替代 verify)');
122
+ }
123
+ }
124
+ return { payload, warnings, checkFailed };
125
+ }
126
+ function formatStatusHuman(payload) {
127
+ const gates = payload.gates.length === 0
128
+ ? ' (none)'
129
+ : payload.gates.map((g) => ` - ${g.id}=${g.status} blocks=${g.blocks_hats || '—'}`).join('\n');
130
+ return [
131
+ `task: ${payload.task_slug}`,
132
+ `path: ${payload.task_path}`,
133
+ `status: ${payload.status}`,
134
+ `gates:`,
135
+ gates,
136
+ `may_start_30: ${payload.may_start_30}`,
137
+ `blockers: ${payload.blockers.length === 0 ? '—' : payload.blockers.join('; ')}`,
138
+ `last_invoke: ${payload.last_invoke.path ?? '—'} hat=${payload.last_invoke.hat_id ?? '—'}`,
139
+ `reviews: R1=${payload.reviews.R1 ? 'yes' : 'no'} CLOSE=${payload.reviews.CLOSE ? 'yes' : 'no'}`,
140
+ `verify_preview: ${payload.verify_preview.ok ? 'PASS' : 'BLOCK'} reason=${payload.verify_preview.reason}`,
141
+ `hgm: events=${payload.hgm.event_count ?? 'unknown'} last_at=${payload.hgm.last_at ?? '—'}`,
142
+ `next_hint: ${payload.next_hint}`,
143
+ '',
144
+ 'NOTE: verify_preview 为只读预览;30 前仍须正式运行 verify。',
145
+ ].join('\n');
146
+ }
147
+ export async function cmdStatus(args) {
148
+ if (args.includes('--help') || args.includes('-h')) {
149
+ console.log(`用法: npx spec-wave status [--target PATH] [--task FILE] [--json] [--check]
150
+ `);
151
+ return;
152
+ }
153
+ let rest = args;
154
+ const { value: targetArg, rest: r1 } = takeOption(rest, '--target');
155
+ rest = r1;
156
+ const { value: taskFile, rest: r2 } = takeOption(rest, '--task');
157
+ rest = r2;
158
+ const json = rest.includes('--json');
159
+ const check = rest.includes('--check');
160
+ rest = rest.filter((a) => a !== '--json' && a !== '--check');
161
+ if (rest.length > 0)
162
+ fail(`status 未知参数: ${rest.join(' ')}`);
163
+ const target = resolveTarget(process.cwd(), targetArg);
164
+ if (!taskFile) {
165
+ if (check)
166
+ fail('status --check 须配合 --task FILE');
167
+ const rows = listActiveTasks(target).map((taskPath) => {
168
+ const abs = path.join(target, taskPath);
169
+ const content = readFileSync(abs, 'utf8');
170
+ const meta = parseHarnessMeta(content);
171
+ const gates = parseHumanGates(content);
172
+ const gateEval = evaluateMayStart30(gates);
173
+ const pending = gates.find((g) => g.status !== 'approved' && String(g.blocksHats || '').includes('30'));
174
+ return {
175
+ task_slug: meta.task_slug || path.basename(taskPath, '.md'),
176
+ task_path: taskPath.replace(/\\/g, '/'),
177
+ status: extractTaskStatus(content) || 'unknown',
178
+ blocking_gate: pending ? `${pending.id}=${pending.status}` : null,
179
+ may_start_30: gateEval.ok,
180
+ };
181
+ });
182
+ if (json)
183
+ console.log(JSON.stringify({ schema_version: 'obs_status_list.v1', tasks: rows }, null, 2));
184
+ else {
185
+ if (rows.length === 0)
186
+ process.stdout.write('active tasks: (none)\n');
187
+ else {
188
+ const lines = ['active tasks:'];
189
+ for (const r of rows) {
190
+ lines.push(` - ${r.task_slug} status=${r.status} blocking=${r.blocking_gate || '—'} may_start_30=${r.may_start_30} path=${r.task_path}`);
191
+ }
192
+ process.stdout.write(`${lines.join('\n')}\n`);
193
+ }
194
+ }
195
+ return;
196
+ }
197
+ const { payload, warnings, checkFailed } = buildTaskStatus(target, taskFile, { check });
198
+ for (const w of warnings)
199
+ console.error(w);
200
+ if (json)
201
+ console.log(JSON.stringify(payload, null, 2));
202
+ else
203
+ console.log(formatStatusHuman(payload));
204
+ if (check && checkFailed)
205
+ fail('', 2);
206
+ }
207
+ export async function cmdTimeline(args) {
208
+ if (args.includes('--help') || args.includes('-h')) {
209
+ console.log(`用法: npx spec-wave timeline --task FILE [--target PATH] [--json] [--limit N] [--ingest]
210
+ `);
211
+ return;
212
+ }
213
+ let rest = args.filter((a) => a !== '--json' && a !== '--ingest');
214
+ const json = args.includes('--json');
215
+ const ingest = args.includes('--ingest');
216
+ const { value: targetArg, rest: r1 } = takeOption(rest, '--target');
217
+ rest = r1;
218
+ const { value: taskOpt, rest: r2 } = takeOption(rest, '--task');
219
+ rest = r2;
220
+ const { value: limitRaw, rest: r3 } = takeOption(rest, '--limit');
221
+ rest = r3;
222
+ let taskFile = taskOpt;
223
+ if (taskFile != null && taskFile.startsWith('-')) {
224
+ fail(`timeline --task 须紧跟文件路径(收到了旗标 ${taskFile})`);
225
+ }
226
+ if (!taskFile && rest.length === 1 && !rest[0].startsWith('-')) {
227
+ taskFile = rest[0];
228
+ rest = [];
229
+ }
230
+ if (rest.length > 0)
231
+ fail(`timeline 未知参数: ${rest.join(' ')}`);
232
+ if (!taskFile)
233
+ fail('timeline 须指定 --task FILE');
234
+ let limit = null;
235
+ if (limitRaw != null) {
236
+ limit = Number(limitRaw);
237
+ if (!Number.isFinite(limit) || limit < 0)
238
+ fail(`timeline --limit 须为非负整数: ${limitRaw}`);
239
+ limit = Math.floor(limit);
240
+ }
241
+ const target = resolveTarget(process.cwd(), targetArg);
242
+ const { buildTaskTimeline, formatTimelineHuman } = await import("./cli-timeline.js");
243
+ const { payload, warnings } = buildTaskTimeline(target, taskFile, { limit, ingest });
244
+ for (const w of warnings)
245
+ console.error(w);
246
+ if (json)
247
+ console.log(JSON.stringify(payload, null, 2));
248
+ else
249
+ process.stdout.write(formatTimelineHuman(payload));
250
+ }
251
+ //# sourceMappingURL=cli-status.js.map