jsharness 1.8.3 → 1.10.0
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/.harness/agents/project-manager/contract.yaml +3 -0
- package/.harness/agents/project-manager/prompt.md +8 -0
- package/.harness/agents/project-manager.md +8 -0
- package/.harness/agents/requirements-analyst/contract.yaml +3 -1
- package/.harness/agents/requirements-analyst/prompt.md +34 -9
- package/.harness/agents/requirements-analyst.md +34 -9
- package/.harness/commands/js/apply.md +31 -0
- package/.harness/commands/js/archive.md +31 -0
- package/.harness/commands/js/explore.md +31 -0
- package/.harness/commands/js/propose.md +31 -0
- package/.harness/doc/originRequirements/.gitkeep +0 -0
- package/.harness/doc/originRequirements/2026-05-22-sample-requirement.md +12 -0
- package/.harness/doc/originRequirements/README.md +36 -0
- package/.harness/doc/ttspec/README.md +33 -0
- package/.harness/doc/ttspec/change/.gitkeep +0 -0
- package/.harness/doc/ttspec/change/archive/.gitkeep +0 -0
- package/.harness/doc/ttspec/specs/.gitkeep +0 -0
- package/.harness/rules/global/process-discipline.md +10 -1
- package/.harness/skills/openspec-apply/SKILL.md +90 -0
- package/.harness/skills/openspec-archive/SKILL.md +77 -0
- package/.harness/skills/openspec-explore/SKILL.md +135 -0
- package/.harness/skills/openspec-propose/SKILL.md +178 -0
- package/.harness/skills/openspec-skill-creator/SKILL.md +157 -0
- package/.harness/workflow/definition.yaml +41 -8
- package/lib/index.mjs +151 -4
- package/package.json +1 -1
package/lib/index.mjs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 多适配器架构:检测 AI 工具 → 转换规则格式 → 注入到对应位置
|
|
5
5
|
*
|
|
6
|
+
* v1.10.0: 新增 5 个 OpenSpec Skills(openspec-explore/propose/apply/archive/skill-creator),Commands 精简为 Skill 委托模式
|
|
6
7
|
* v1.8.0: 四桶分离架构(rules/skills/commands/agents),多源获取策略确保 100% 可用
|
|
7
8
|
* 1. import.meta.url 定位本包 .harness/ (最快)
|
|
8
9
|
* 2. process.argv[1] 反推包根目录(npx 直接执行时)
|
|
@@ -370,6 +371,7 @@ const SKILL_TRANSFORMERS = {
|
|
|
370
371
|
if (lowerName.includes('build')) content += `trigger_type: manual\n`;
|
|
371
372
|
else if (lowerName.includes('test')) content += `trigger_type: on_save\n`;
|
|
372
373
|
else if (lowerName.includes('lint') || lowerName.includes('review')) content += `trigger_type: on_pr\n`;
|
|
374
|
+
else if (lowerName.includes('openspec')) content += `trigger_type: manual\n`;
|
|
373
375
|
else content += `trigger_type: manual\n`;
|
|
374
376
|
content += `---\n\n${body}`;
|
|
375
377
|
outputs.push({ relativePath: `.claude/skills/${skillName}/SKILL.md`, content, source: file.path });
|
|
@@ -1750,6 +1752,17 @@ export async function runInit(projectDir, options = {}) {
|
|
|
1750
1752
|
console.log(` ⏭ 跳过 ${openspecResult.skipped.length} 项 (已存在)`);
|
|
1751
1753
|
}
|
|
1752
1754
|
|
|
1755
|
+
// 7.5 初始化 Harness doc 目录(originRequirements + ttspec)
|
|
1756
|
+
console.log('\n━━━ 初始化 Harness 文档目录 ━━━');
|
|
1757
|
+
const harnessDocResult = initHarnessDoc(projectDir, { force, verbose });
|
|
1758
|
+
if (harnessDocResult.created.length > 0) {
|
|
1759
|
+
console.log(` ✅ 创建 ${harnessDocResult.created.length} 项:`);
|
|
1760
|
+
harnessDocResult.created.forEach(f => console.log(` - ${f}`));
|
|
1761
|
+
}
|
|
1762
|
+
if (harnessDocResult.skipped.length > 0) {
|
|
1763
|
+
console.log(` ⏭ 跳过 ${harnessDocResult.skipped.length} 项 (已存在)`);
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1753
1766
|
// 8. 输出总结
|
|
1754
1767
|
console.log('\n═════════════════════════════');
|
|
1755
1768
|
console.log('✅ 初始化完成!');
|
|
@@ -1873,6 +1886,15 @@ export function showStatus(projectDir) {
|
|
|
1873
1886
|
|
|
1874
1887
|
const OPENSPEC_DIRS = ['openspec', 'openspec/changes', 'openspec/changes/archive', 'openspec/specs'];
|
|
1875
1888
|
|
|
1889
|
+
// Harness doc 子目录(需求入口 + ttspec 变更管理)
|
|
1890
|
+
const HARNESS_DOC_DIRS = [
|
|
1891
|
+
'.harness/doc/originRequirements',
|
|
1892
|
+
'.harness/doc/ttspec',
|
|
1893
|
+
'.harness/doc/ttspec/change',
|
|
1894
|
+
'.harness/doc/ttspec/change/archive',
|
|
1895
|
+
'.harness/doc/ttspec/specs',
|
|
1896
|
+
];
|
|
1897
|
+
|
|
1876
1898
|
const OPENSPEC_GITIGNORE = `# OpenSpec generated files
|
|
1877
1899
|
changes/*/dist/
|
|
1878
1900
|
*.log
|
|
@@ -1919,6 +1941,130 @@ export function initOpenSpec(projectDir, options = {}) {
|
|
|
1919
1941
|
return { created, skipped };
|
|
1920
1942
|
}
|
|
1921
1943
|
|
|
1944
|
+
/**
|
|
1945
|
+
* 初始化 .harness/doc/ 子目录(originRequirements + ttspec)
|
|
1946
|
+
*/
|
|
1947
|
+
export function initHarnessDoc(projectDir, options = {}) {
|
|
1948
|
+
const { force = false, verbose = false } = options;
|
|
1949
|
+
const created = [];
|
|
1950
|
+
const skipped = [];
|
|
1951
|
+
|
|
1952
|
+
for (const dir of HARNESS_DOC_DIRS) {
|
|
1953
|
+
const fullPath = path.join(projectDir, dir);
|
|
1954
|
+
if (fs.existsSync(fullPath)) {
|
|
1955
|
+
if (verbose) console.log(` ⏭ 目录已存在: ${dir}/`);
|
|
1956
|
+
skipped.push(dir);
|
|
1957
|
+
continue;
|
|
1958
|
+
}
|
|
1959
|
+
fs.mkdirSync(fullPath, { recursive: true });
|
|
1960
|
+
created.push(dir);
|
|
1961
|
+
if (verbose) console.log(` ✅ 创建目录: ${dir}/`);
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
// 在空目录中添加 .gitkeep
|
|
1965
|
+
for (const dir of HARNESS_DOC_DIRS) {
|
|
1966
|
+
const gitkeepPath = path.join(projectDir, dir, '.gitkeep');
|
|
1967
|
+
if (!fs.existsSync(gitkeepPath)) fs.writeFileSync(gitkeepPath, '', 'utf-8');
|
|
1968
|
+
}
|
|
1969
|
+
|
|
1970
|
+
// originRequirements README
|
|
1971
|
+
const originReadmePath = path.join(projectDir, '.harness/doc/originRequirements', 'README.md');
|
|
1972
|
+
if (!fs.existsSync(originReadmePath) || force) {
|
|
1973
|
+
fs.writeFileSync(originReadmePath, generateOriginRequirementsReadme(), 'utf-8');
|
|
1974
|
+
created.push('.harness/doc/originRequirements/README.md');
|
|
1975
|
+
} else {
|
|
1976
|
+
skipped.push('.harness/doc/originRequirements/README.md');
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
// ttspec README
|
|
1980
|
+
const ttspecReadmePath = path.join(projectDir, '.harness/doc/ttspec', 'README.md');
|
|
1981
|
+
if (!fs.existsSync(ttspecReadmePath) || force) {
|
|
1982
|
+
fs.writeFileSync(ttspecReadmePath, generateTtspecReadme(), 'utf-8');
|
|
1983
|
+
created.push('.harness/doc/ttspec/README.md');
|
|
1984
|
+
} else {
|
|
1985
|
+
skipped.push('.harness/doc/ttspec/README.md');
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
return { created, skipped };
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
function generateOriginRequirementsReadme() {
|
|
1992
|
+
return `# 原始需求文件目录
|
|
1993
|
+
|
|
1994
|
+
本目录用于存放所有原始需求文件,是 Harness 需求分析的统一入口。
|
|
1995
|
+
|
|
1996
|
+
## 文件命名规则
|
|
1997
|
+
|
|
1998
|
+
格式:\`{YYYY-MM-DD}-{kebab-case-title}.md\`
|
|
1999
|
+
|
|
2000
|
+
示例:
|
|
2001
|
+
- \`2026-05-22-user-avatar-upload.md\`
|
|
2002
|
+
- \`2026-06-15-order-export-feature.md\`
|
|
2003
|
+
|
|
2004
|
+
## 最小内容要求
|
|
2005
|
+
|
|
2006
|
+
每个需求文件至少包含以下两个章节:
|
|
2007
|
+
|
|
2008
|
+
\`\`\`markdown
|
|
2009
|
+
# 需求标题
|
|
2010
|
+
|
|
2011
|
+
## 背景
|
|
2012
|
+
|
|
2013
|
+
描述需求的业务背景、当前痛点和动机。
|
|
2014
|
+
|
|
2015
|
+
## 期望
|
|
2016
|
+
|
|
2017
|
+
描述期望达到的效果或目标。
|
|
2018
|
+
\`\`\`
|
|
2019
|
+
|
|
2020
|
+
## 工作流
|
|
2021
|
+
|
|
2022
|
+
1. 用户在此目录下创建需求文件
|
|
2023
|
+
2. PM Agent 扫描发现新文件
|
|
2024
|
+
3. PM 在 \`.harness/doc/ttspec/change/\` 下创建对应 change
|
|
2025
|
+
4. 需求分析师按 explore → propose → prd 三步执行分析
|
|
2026
|
+
|
|
2027
|
+
> 本目录由 Harness Engineering 系统管理。
|
|
2028
|
+
`;
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
function generateTtspecReadme() {
|
|
2032
|
+
return `# ttspec — 变更规格管理目录
|
|
2033
|
+
|
|
2034
|
+
本目录用于存放 Harness 流程中 OpenSpec 的产出物,包括变更管理(change)和能力规格(specs)。
|
|
2035
|
+
|
|
2036
|
+
## 目录结构
|
|
2037
|
+
|
|
2038
|
+
\`\`\`
|
|
2039
|
+
.harness/doc/ttspec/
|
|
2040
|
+
├── change/ # 变更目录(每个需求对应一个子目录)
|
|
2041
|
+
│ ├── archive/ # 已归档的变更
|
|
2042
|
+
│ └── {change-name}/ # 活跃变更
|
|
2043
|
+
│ ├── explore-notes.md # explore 阶段产出
|
|
2044
|
+
│ ├── proposal.md # propose 阶段产出
|
|
2045
|
+
│ ├── design.md # 设计决策
|
|
2046
|
+
│ ├── specs/ # 能力规格
|
|
2047
|
+
│ └── tasks.md # 实施任务列表
|
|
2048
|
+
└── specs/ # 全局能力规格
|
|
2049
|
+
└── {capability}/
|
|
2050
|
+
└── spec.md
|
|
2051
|
+
\`\`\`
|
|
2052
|
+
|
|
2053
|
+
## 变更命名规则
|
|
2054
|
+
|
|
2055
|
+
change 名称从原始需求文件名派生:去除日期前缀,保留 kebab-case 标题。
|
|
2056
|
+
|
|
2057
|
+
示例:需求文件 \`2026-05-22-user-avatar-upload.md\` → change 名 \`user-avatar-upload\`
|
|
2058
|
+
|
|
2059
|
+
## 与 openspec/ 的关系
|
|
2060
|
+
|
|
2061
|
+
- \`openspec/\` — OpenSpec CLI 原生操作目录(历史数据保持不动)
|
|
2062
|
+
- \`.harness/doc/ttspec/\` — Harness 流程中的变更管理产出目录
|
|
2063
|
+
|
|
2064
|
+
> 本目录由 Harness Engineering 系统管理。
|
|
2065
|
+
`;
|
|
2066
|
+
}
|
|
2067
|
+
|
|
1922
2068
|
function generateOpenSpecReadme() {
|
|
1923
2069
|
return `# OpenSpec 变更管理
|
|
1924
2070
|
|
|
@@ -1937,10 +2083,11 @@ openspec/
|
|
|
1937
2083
|
|
|
1938
2084
|
在 AI 对话中使用 OpenSpec skills:
|
|
1939
2085
|
|
|
1940
|
-
- **openspec-
|
|
1941
|
-
- **openspec-
|
|
1942
|
-
- **openspec-apply
|
|
1943
|
-
- **openspec-archive
|
|
2086
|
+
- **openspec-explore** — 需求深度探索
|
|
2087
|
+
- **openspec-propose** — 创建结构化提案
|
|
2088
|
+
- **openspec-apply** — 实施变更任务
|
|
2089
|
+
- **openspec-archive** — 归档已完成变更
|
|
2090
|
+
- **openspec-skill-creator** — 创建新的 Harness Skill
|
|
1944
2091
|
|
|
1945
2092
|
## 命令行操作
|
|
1946
2093
|
|
package/package.json
CHANGED