@hunter-harness/workflow-harness 0.2.17 → 0.2.18
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/bundles/general/claude-code/harness-plan/reference.md +5 -5
- package/harness/bundles/general/claude-code/harness-review/checklist.md +1 -1
- package/harness/bundles/general/claude-code/harness-run/checklist.md +1 -1
- package/harness/bundles/general/claude-code/harness-run/reference.md +1 -1
- package/harness/bundles/general/claude-code/harness-submit/checklist.md +6 -6
- package/harness/bundles/general/claude-code/scripts/harness_profile.py +1 -0
- package/harness/bundles/general/claude-code/scripts/harness_runtime.py +4 -4
- package/harness/bundles/general/claude-code/scripts/harness_service.py +1 -0
- package/harness/bundles/general/codebuddy/harness-plan/reference.md +5 -5
- package/harness/bundles/general/codebuddy/harness-review/checklist.md +1 -1
- package/harness/bundles/general/codebuddy/harness-run/checklist.md +1 -1
- package/harness/bundles/general/codebuddy/harness-run/reference.md +1 -1
- package/harness/bundles/general/codebuddy/harness-submit/checklist.md +6 -6
- package/harness/bundles/general/codebuddy/scripts/harness_profile.py +1 -0
- package/harness/bundles/general/codebuddy/scripts/harness_runtime.py +4 -4
- package/harness/bundles/general/codebuddy/scripts/harness_service.py +1 -0
- package/harness/bundles/general/codex/harness-plan/reference.md +5 -5
- package/harness/bundles/general/codex/harness-review/checklist.md +1 -1
- package/harness/bundles/general/codex/harness-run/checklist.md +1 -1
- package/harness/bundles/general/codex/harness-run/reference.md +1 -1
- package/harness/bundles/general/codex/harness-submit/checklist.md +6 -6
- package/harness/bundles/general/codex/scripts/harness_profile.py +1 -0
- package/harness/bundles/general/codex/scripts/harness_runtime.py +4 -4
- package/harness/bundles/general/codex/scripts/harness_service.py +1 -0
- package/harness/bundles/general/cursor/harness-plan/reference.md +5 -5
- package/harness/bundles/general/cursor/harness-review/checklist.md +1 -1
- package/harness/bundles/general/cursor/harness-run/checklist.md +1 -1
- package/harness/bundles/general/cursor/harness-run/reference.md +1 -1
- package/harness/bundles/general/cursor/harness-submit/checklist.md +6 -6
- package/harness/bundles/general/cursor/scripts/harness_profile.py +1 -0
- package/harness/bundles/general/cursor/scripts/harness_runtime.py +4 -4
- package/harness/bundles/general/cursor/scripts/harness_service.py +1 -0
- package/harness/bundles/java/claude-code/harness-package/checklist.md +1 -1
- package/harness/bundles/java/claude-code/harness-plan/reference.md +5 -5
- package/harness/bundles/java/claude-code/harness-review/checklist.md +1 -1
- package/harness/bundles/java/claude-code/harness-run/checklist.md +2 -2
- package/harness/bundles/java/claude-code/harness-run/reference.md +352 -352
- package/harness/bundles/java/claude-code/harness-submit/checklist.md +6 -6
- package/harness/bundles/java/claude-code/scripts/harness_profile.py +1 -0
- package/harness/bundles/java/claude-code/scripts/harness_runtime.py +4 -4
- package/harness/bundles/java/claude-code/scripts/harness_service.py +1 -0
- package/harness/bundles/java/codebuddy/harness-package/checklist.md +1 -1
- package/harness/bundles/java/codebuddy/harness-plan/reference.md +5 -5
- package/harness/bundles/java/codebuddy/harness-review/checklist.md +1 -1
- package/harness/bundles/java/codebuddy/harness-run/checklist.md +2 -2
- package/harness/bundles/java/codebuddy/harness-run/reference.md +352 -352
- package/harness/bundles/java/codebuddy/harness-submit/checklist.md +6 -6
- package/harness/bundles/java/codebuddy/scripts/harness_profile.py +1 -0
- package/harness/bundles/java/codebuddy/scripts/harness_runtime.py +4 -4
- package/harness/bundles/java/codebuddy/scripts/harness_service.py +1 -0
- package/harness/bundles/java/codex/harness-package/checklist.md +1 -1
- package/harness/bundles/java/codex/harness-plan/reference.md +5 -5
- package/harness/bundles/java/codex/harness-review/checklist.md +1 -1
- package/harness/bundles/java/codex/harness-run/checklist.md +2 -2
- package/harness/bundles/java/codex/harness-run/reference.md +352 -352
- package/harness/bundles/java/codex/harness-submit/checklist.md +6 -6
- package/harness/bundles/java/codex/scripts/harness_profile.py +1 -0
- package/harness/bundles/java/codex/scripts/harness_runtime.py +4 -4
- package/harness/bundles/java/codex/scripts/harness_service.py +1 -0
- package/harness/bundles/java/cursor/harness-package/checklist.md +1 -1
- package/harness/bundles/java/cursor/harness-plan/reference.md +5 -5
- package/harness/bundles/java/cursor/harness-review/checklist.md +1 -1
- package/harness/bundles/java/cursor/harness-run/checklist.md +2 -2
- package/harness/bundles/java/cursor/harness-run/reference.md +352 -352
- package/harness/bundles/java/cursor/harness-submit/checklist.md +6 -6
- package/harness/bundles/java/cursor/scripts/harness_profile.py +1 -0
- package/harness/bundles/java/cursor/scripts/harness_runtime.py +4 -4
- package/harness/bundles/java/cursor/scripts/harness_service.py +1 -0
- package/harness/manifests/general/claude-code.json +8 -8
- package/harness/manifests/general/codebuddy.json +8 -8
- package/harness/manifests/general/codex.json +8 -8
- package/harness/manifests/general/cursor.json +8 -8
- package/harness/manifests/java/claude-code.json +9 -9
- package/harness/manifests/java/codebuddy.json +9 -9
- package/harness/manifests/java/codex.json +9 -9
- package/harness/manifests/java/cursor.json +9 -9
- package/hunter-workflow-family.json +1 -1
- package/package.json +1 -1
|
@@ -15,10 +15,10 @@ description: harness-plan 的需求提取模板、任务拆分规则、测试场
|
|
|
15
15
|
"requested": true,
|
|
16
16
|
"created": false,
|
|
17
17
|
"agent": "<active-adapter>",
|
|
18
|
-
"worktreeRoot": "
|
|
19
|
-
"branchPrefix": "
|
|
20
|
-
"path": "
|
|
21
|
-
"branch": "
|
|
18
|
+
"worktreeRoot": ".worktrees",
|
|
19
|
+
"branchPrefix": "harness/",
|
|
20
|
+
"path": ".worktrees/<change-name>",
|
|
21
|
+
"branch": "harness/<change-name>",
|
|
22
22
|
"decisionBy": "user",
|
|
23
23
|
"decisionAt": "YYYY-MM-DD HH:mm",
|
|
24
24
|
"ownerSkill": "harness-run"
|
|
@@ -41,7 +41,7 @@ description: harness-plan 的需求提取模板、任务拆分规则、测试场
|
|
|
41
41
|
|
|
42
42
|
### 决策事件 note 示例
|
|
43
43
|
|
|
44
|
-
`path` 与 `branch` 必须来自 `harness_runtime.py adapter`/`meta/runtime.json
|
|
44
|
+
`path` 与 `branch` 必须来自 `harness_runtime.py adapter`/`meta/runtime.json`。所有 agent 共享统一路径 `.worktrees/<change-name>` 与统一分支前缀 `harness/`;`agent` 字段仅作创建者元数据,不再决定路径。
|
|
45
45
|
|
|
46
46
|
`用户选择使用 Worktree;决策文件为 meta/worktree.json;requested=true, created=false;创建责任为 harness-run。`
|
|
47
47
|
|
|
@@ -8,7 +8,7 @@ description: harness-review 的6维度审查检查项详细列表。仅在执行
|
|
|
8
8
|
|
|
9
9
|
用 Glob 搜索 `.harness/changes/*/plans/*-plan.md`(**排除 `.harness/archive/*/`**),读取 frontmatter 提取 `change-name`。默认最多一个未归档变更;如有多个,优先取最近修改的,或询问用户。后续所有路径基于此变更名。
|
|
10
10
|
|
|
11
|
-
**读取 worktree 状态**:读 `.harness/changes/<change-name>/meta/worktree.json`。`requested=true` 且 worktree 已创建 → 后续 `git diff` 的 `<项目路径>` 用 worktree 路径(`.
|
|
11
|
+
**读取 worktree 状态**:读 `.harness/changes/<change-name>/meta/worktree.json`。`requested=true` 且 worktree 已创建 → 后续 `git diff` 的 `<项目路径>` 用 worktree 路径(`.worktrees/<change-name>`);`requested=true` 但 worktree 不存在 → 停止,提示先修复 `harness-run`,不得静默回主目录。
|
|
12
12
|
|
|
13
13
|
## 审查流程
|
|
14
14
|
|
|
@@ -17,7 +17,7 @@ description: harness-run 的执行检查清单。仅在编码执行时读取。
|
|
|
17
17
|
- [ ] `requested=true` 且 worktree 存在 → 切换到 worktree 执行
|
|
18
18
|
- [ ] `requested=true` 且 worktree 不存在 → 必须创建 worktree
|
|
19
19
|
- [ ] worktree 创建命令必须使用 PowerShell:`git worktree add ...`
|
|
20
|
-
- [ ] 创建后验证
|
|
20
|
+
- [ ] 创建后验证 `.worktrees/<change-name>/.git` 存在
|
|
21
21
|
- [ ] 创建成功后更新 `meta/worktree.json` 的 `created=true/createdAt/createdBy`
|
|
22
22
|
- [ ] 创建失败 → 停止,或 blocking user confirmation 询问是否改为主目录执行
|
|
23
23
|
- [ ] 禁止 `requested=true && worktree 不存在` 时直接主目录执行
|
|
@@ -76,7 +76,7 @@ requested=true + path missing
|
|
|
76
76
|
```json
|
|
77
77
|
{
|
|
78
78
|
"projectRoot": ".../udp",
|
|
79
|
-
"worktreeRoot": ".../udp/<
|
|
79
|
+
"worktreeRoot": ".../udp/.worktrees/<change-name>",
|
|
80
80
|
"stateDir": ".../udp/.harness/changes/<change-name>"
|
|
81
81
|
}
|
|
82
82
|
```
|
|
@@ -328,7 +328,7 @@ append `phase.start`(`--phase merge`;`note` 含 worktree 分支、主分支
|
|
|
328
328
|
### 步骤 M1:preflight
|
|
329
329
|
|
|
330
330
|
```powershell
|
|
331
|
-
python harness/scripts/harness_integration.py preflight --change <change-name> --run-id <run-id> --feature-branch
|
|
331
|
+
python harness/scripts/harness_integration.py preflight --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp>
|
|
332
332
|
```
|
|
333
333
|
|
|
334
334
|
获取 integration lock、解析 base/feature head、写 journal 与保护 refs(`refs/harness/integration/<txn>/base|head`)。锁被其他 run 持有 → **停止**,不改动工作区与状态文件。
|
|
@@ -336,7 +336,7 @@ python harness/scripts/harness_integration.py preflight --change <change-name> -
|
|
|
336
336
|
### 步骤 M2:prepare
|
|
337
337
|
|
|
338
338
|
```powershell
|
|
339
|
-
python harness/scripts/harness_integration.py prepare --change <change-name> --run-id <run-id> --feature-branch
|
|
339
|
+
python harness/scripts/harness_integration.py prepare --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp>
|
|
340
340
|
```
|
|
341
341
|
|
|
342
342
|
fetch 后从**已提交** target 创建临时 integration worktree;primary 的 staged/unstaged/untracked/ignored 与 mtime 均不被触碰。
|
|
@@ -344,7 +344,7 @@ fetch 后从**已提交** target 创建临时 integration worktree;primary 的
|
|
|
344
344
|
### 步骤 M3:merge
|
|
345
345
|
|
|
346
346
|
```powershell
|
|
347
|
-
python harness/scripts/harness_integration.py merge --change <change-name> --run-id <run-id> --feature-branch
|
|
347
|
+
python harness/scripts/harness_integration.py merge --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp>
|
|
348
348
|
```
|
|
349
349
|
|
|
350
350
|
- 方式固定 `--no-ff`;merge diff 出现其他 Change 的 contract/runtime 路径 → 结构化 `FOREIGN_CHANGE_PATHS` 拒绝
|
|
@@ -356,7 +356,7 @@ python harness/scripts/harness_integration.py merge --change <change-name> --run
|
|
|
356
356
|
在 integration worktree 内执行验证命令;远端引入他人提交或 ledger 不可复用时必跑:
|
|
357
357
|
|
|
358
358
|
```powershell
|
|
359
|
-
python harness/scripts/harness_integration.py verify --change <change-name> --run-id <run-id> --feature-branch
|
|
359
|
+
python harness/scripts/harness_integration.py verify --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp> --command "<resolved command>"
|
|
360
360
|
```
|
|
361
361
|
|
|
362
362
|
任一命令非零退出 → step FAILED,不进入 push。
|
|
@@ -370,7 +370,7 @@ powershell.exe -Command "python harness/scripts/harness_check_gate.py --write"
|
|
|
370
370
|
### 步骤 M5:push
|
|
371
371
|
|
|
372
372
|
```powershell
|
|
373
|
-
python harness/scripts/harness_integration.py push --change <change-name> --run-id <run-id> --feature-branch
|
|
373
|
+
python harness/scripts/harness_integration.py push --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp>
|
|
374
374
|
```
|
|
375
375
|
|
|
376
376
|
远端基线漂移 → `TARGET_MOVED` 结构化失败,不继续。成功后 journal `pushedHead` 即 `mergeFinalHash`。
|
|
@@ -378,7 +378,7 @@ python harness/scripts/harness_integration.py push --change <change-name> --run-
|
|
|
378
378
|
### 步骤 M6:cleanup
|
|
379
379
|
|
|
380
380
|
```powershell
|
|
381
|
-
python harness/scripts/harness_integration.py cleanup --change <change-name> --run-id <run-id> --feature-branch
|
|
381
|
+
python harness/scripts/harness_integration.py cleanup --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp>
|
|
382
382
|
```
|
|
383
383
|
|
|
384
384
|
- `git worktree remove --force` 精确路径 → 验证注销 → 临时分支 `branch -D` → (push 成功后)删除保护 refs → 释放 integration lock
|
|
@@ -23,10 +23,10 @@ if hasattr(sys.stderr, "reconfigure"):
|
|
|
23
23
|
SCHEMA_VERSION = 1
|
|
24
24
|
_CHANGE_ID = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$")
|
|
25
25
|
_ADAPTERS = {
|
|
26
|
-
"claude-code": (".
|
|
27
|
-
"codex": (".
|
|
28
|
-
"cursor": (".
|
|
29
|
-
"codebuddy": (".
|
|
26
|
+
"claude-code": (".worktrees", "harness/"),
|
|
27
|
+
"codex": (".worktrees", "harness/"),
|
|
28
|
+
"cursor": (".worktrees", "harness/"),
|
|
29
|
+
"codebuddy": (".worktrees", "harness/"),
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
|
|
@@ -164,6 +164,7 @@ def get_service_start(profile: dict[str, Any]) -> dict[str, Any]:
|
|
|
164
164
|
# runtime resolve 把具体 overlay/profile 注入到 session,不写回持久 profile
|
|
165
165
|
# (spec §3.1 持久 profile 只保存模板;§3.4 修复输入端陈旧 profile)。
|
|
166
166
|
STALE_WORKTREE_MARKERS: tuple[str, ...] = (
|
|
167
|
+
".worktrees/",
|
|
167
168
|
".claude/worktrees/",
|
|
168
169
|
".cursor/worktrees/",
|
|
169
170
|
".codeium/worktrees/",
|
|
@@ -15,10 +15,10 @@ description: harness-plan 的需求提取模板、任务拆分规则、测试场
|
|
|
15
15
|
"requested": true,
|
|
16
16
|
"created": false,
|
|
17
17
|
"agent": "<active-adapter>",
|
|
18
|
-
"worktreeRoot": "
|
|
19
|
-
"branchPrefix": "
|
|
20
|
-
"path": "
|
|
21
|
-
"branch": "
|
|
18
|
+
"worktreeRoot": ".worktrees",
|
|
19
|
+
"branchPrefix": "harness/",
|
|
20
|
+
"path": ".worktrees/<change-name>",
|
|
21
|
+
"branch": "harness/<change-name>",
|
|
22
22
|
"decisionBy": "user",
|
|
23
23
|
"decisionAt": "YYYY-MM-DD HH:mm",
|
|
24
24
|
"ownerSkill": "harness-run"
|
|
@@ -41,7 +41,7 @@ description: harness-plan 的需求提取模板、任务拆分规则、测试场
|
|
|
41
41
|
|
|
42
42
|
### 决策事件 note 示例
|
|
43
43
|
|
|
44
|
-
`path` 与 `branch` 必须来自 `harness_runtime.py adapter`/`meta/runtime.json
|
|
44
|
+
`path` 与 `branch` 必须来自 `harness_runtime.py adapter`/`meta/runtime.json`。所有 agent 共享统一路径 `.worktrees/<change-name>` 与统一分支前缀 `harness/`;`agent` 字段仅作创建者元数据,不再决定路径。
|
|
45
45
|
|
|
46
46
|
`用户选择使用 Worktree;决策文件为 meta/worktree.json;requested=true, created=false;创建责任为 harness-run。`
|
|
47
47
|
|
|
@@ -8,7 +8,7 @@ description: harness-review 的6维度审查检查项详细列表。仅在执行
|
|
|
8
8
|
|
|
9
9
|
用 Glob 搜索 `.harness/changes/*/plans/*-plan.md`(**排除 `.harness/archive/*/`**),读取 frontmatter 提取 `change-name`。默认最多一个未归档变更;如有多个,优先取最近修改的,或询问用户。后续所有路径基于此变更名。
|
|
10
10
|
|
|
11
|
-
**读取 worktree 状态**:读 `.harness/changes/<change-name>/meta/worktree.json`。`requested=true` 且 worktree 已创建 → 后续 `git diff` 的 `<项目路径>` 用 worktree 路径(`.
|
|
11
|
+
**读取 worktree 状态**:读 `.harness/changes/<change-name>/meta/worktree.json`。`requested=true` 且 worktree 已创建 → 后续 `git diff` 的 `<项目路径>` 用 worktree 路径(`.worktrees/<change-name>`);`requested=true` 但 worktree 不存在 → 停止,提示先修复 `harness-run`,不得静默回主目录。
|
|
12
12
|
|
|
13
13
|
## 审查流程
|
|
14
14
|
|
|
@@ -17,7 +17,7 @@ description: harness-run 的执行检查清单。仅在编码执行时读取。
|
|
|
17
17
|
- [ ] `requested=true` 且 worktree 存在 → 切换到 worktree 执行
|
|
18
18
|
- [ ] `requested=true` 且 worktree 不存在 → 必须创建 worktree
|
|
19
19
|
- [ ] worktree 创建命令必须使用 PowerShell:`git worktree add ...`
|
|
20
|
-
- [ ] 创建后验证
|
|
20
|
+
- [ ] 创建后验证 `.worktrees/<change-name>/.git` 存在
|
|
21
21
|
- [ ] 创建成功后更新 `meta/worktree.json` 的 `created=true/createdAt/createdBy`
|
|
22
22
|
- [ ] 创建失败 → 停止,或 blocking user confirmation 询问是否改为主目录执行
|
|
23
23
|
- [ ] 禁止 `requested=true && worktree 不存在` 时直接主目录执行
|
|
@@ -76,7 +76,7 @@ requested=true + path missing
|
|
|
76
76
|
```json
|
|
77
77
|
{
|
|
78
78
|
"projectRoot": ".../udp",
|
|
79
|
-
"worktreeRoot": ".../udp/<
|
|
79
|
+
"worktreeRoot": ".../udp/.worktrees/<change-name>",
|
|
80
80
|
"stateDir": ".../udp/.harness/changes/<change-name>"
|
|
81
81
|
}
|
|
82
82
|
```
|
|
@@ -328,7 +328,7 @@ append `phase.start`(`--phase merge`;`note` 含 worktree 分支、主分支
|
|
|
328
328
|
### 步骤 M1:preflight
|
|
329
329
|
|
|
330
330
|
```powershell
|
|
331
|
-
python harness/scripts/harness_integration.py preflight --change <change-name> --run-id <run-id> --feature-branch
|
|
331
|
+
python harness/scripts/harness_integration.py preflight --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp>
|
|
332
332
|
```
|
|
333
333
|
|
|
334
334
|
获取 integration lock、解析 base/feature head、写 journal 与保护 refs(`refs/harness/integration/<txn>/base|head`)。锁被其他 run 持有 → **停止**,不改动工作区与状态文件。
|
|
@@ -336,7 +336,7 @@ python harness/scripts/harness_integration.py preflight --change <change-name> -
|
|
|
336
336
|
### 步骤 M2:prepare
|
|
337
337
|
|
|
338
338
|
```powershell
|
|
339
|
-
python harness/scripts/harness_integration.py prepare --change <change-name> --run-id <run-id> --feature-branch
|
|
339
|
+
python harness/scripts/harness_integration.py prepare --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp>
|
|
340
340
|
```
|
|
341
341
|
|
|
342
342
|
fetch 后从**已提交** target 创建临时 integration worktree;primary 的 staged/unstaged/untracked/ignored 与 mtime 均不被触碰。
|
|
@@ -344,7 +344,7 @@ fetch 后从**已提交** target 创建临时 integration worktree;primary 的
|
|
|
344
344
|
### 步骤 M3:merge
|
|
345
345
|
|
|
346
346
|
```powershell
|
|
347
|
-
python harness/scripts/harness_integration.py merge --change <change-name> --run-id <run-id> --feature-branch
|
|
347
|
+
python harness/scripts/harness_integration.py merge --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp>
|
|
348
348
|
```
|
|
349
349
|
|
|
350
350
|
- 方式固定 `--no-ff`;merge diff 出现其他 Change 的 contract/runtime 路径 → 结构化 `FOREIGN_CHANGE_PATHS` 拒绝
|
|
@@ -356,7 +356,7 @@ python harness/scripts/harness_integration.py merge --change <change-name> --run
|
|
|
356
356
|
在 integration worktree 内执行验证命令;远端引入他人提交或 ledger 不可复用时必跑:
|
|
357
357
|
|
|
358
358
|
```powershell
|
|
359
|
-
python harness/scripts/harness_integration.py verify --change <change-name> --run-id <run-id> --feature-branch
|
|
359
|
+
python harness/scripts/harness_integration.py verify --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp> --command "<resolved command>"
|
|
360
360
|
```
|
|
361
361
|
|
|
362
362
|
任一命令非零退出 → step FAILED,不进入 push。
|
|
@@ -370,7 +370,7 @@ powershell.exe -Command "python harness/scripts/harness_check_gate.py --write"
|
|
|
370
370
|
### 步骤 M5:push
|
|
371
371
|
|
|
372
372
|
```powershell
|
|
373
|
-
python harness/scripts/harness_integration.py push --change <change-name> --run-id <run-id> --feature-branch
|
|
373
|
+
python harness/scripts/harness_integration.py push --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp>
|
|
374
374
|
```
|
|
375
375
|
|
|
376
376
|
远端基线漂移 → `TARGET_MOVED` 结构化失败,不继续。成功后 journal `pushedHead` 即 `mergeFinalHash`。
|
|
@@ -378,7 +378,7 @@ python harness/scripts/harness_integration.py push --change <change-name> --run-
|
|
|
378
378
|
### 步骤 M6:cleanup
|
|
379
379
|
|
|
380
380
|
```powershell
|
|
381
|
-
python harness/scripts/harness_integration.py cleanup --change <change-name> --run-id <run-id> --feature-branch
|
|
381
|
+
python harness/scripts/harness_integration.py cleanup --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp>
|
|
382
382
|
```
|
|
383
383
|
|
|
384
384
|
- `git worktree remove --force` 精确路径 → 验证注销 → 临时分支 `branch -D` → (push 成功后)删除保护 refs → 释放 integration lock
|
|
@@ -23,10 +23,10 @@ if hasattr(sys.stderr, "reconfigure"):
|
|
|
23
23
|
SCHEMA_VERSION = 1
|
|
24
24
|
_CHANGE_ID = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$")
|
|
25
25
|
_ADAPTERS = {
|
|
26
|
-
"claude-code": (".
|
|
27
|
-
"codex": (".
|
|
28
|
-
"cursor": (".
|
|
29
|
-
"codebuddy": (".
|
|
26
|
+
"claude-code": (".worktrees", "harness/"),
|
|
27
|
+
"codex": (".worktrees", "harness/"),
|
|
28
|
+
"cursor": (".worktrees", "harness/"),
|
|
29
|
+
"codebuddy": (".worktrees", "harness/"),
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
|
|
@@ -164,6 +164,7 @@ def get_service_start(profile: dict[str, Any]) -> dict[str, Any]:
|
|
|
164
164
|
# runtime resolve 把具体 overlay/profile 注入到 session,不写回持久 profile
|
|
165
165
|
# (spec §3.1 持久 profile 只保存模板;§3.4 修复输入端陈旧 profile)。
|
|
166
166
|
STALE_WORKTREE_MARKERS: tuple[str, ...] = (
|
|
167
|
+
".worktrees/",
|
|
167
168
|
".claude/worktrees/",
|
|
168
169
|
".cursor/worktrees/",
|
|
169
170
|
".codeium/worktrees/",
|
|
@@ -15,10 +15,10 @@ description: harness-plan 的需求提取模板、任务拆分规则、测试场
|
|
|
15
15
|
"requested": true,
|
|
16
16
|
"created": false,
|
|
17
17
|
"agent": "<active-adapter>",
|
|
18
|
-
"worktreeRoot": "
|
|
19
|
-
"branchPrefix": "
|
|
20
|
-
"path": "
|
|
21
|
-
"branch": "
|
|
18
|
+
"worktreeRoot": ".worktrees",
|
|
19
|
+
"branchPrefix": "harness/",
|
|
20
|
+
"path": ".worktrees/<change-name>",
|
|
21
|
+
"branch": "harness/<change-name>",
|
|
22
22
|
"decisionBy": "user",
|
|
23
23
|
"decisionAt": "YYYY-MM-DD HH:mm",
|
|
24
24
|
"ownerSkill": "harness-run"
|
|
@@ -41,7 +41,7 @@ description: harness-plan 的需求提取模板、任务拆分规则、测试场
|
|
|
41
41
|
|
|
42
42
|
### 决策事件 note 示例
|
|
43
43
|
|
|
44
|
-
`path` 与 `branch` 必须来自 `harness_runtime.py adapter`/`meta/runtime.json
|
|
44
|
+
`path` 与 `branch` 必须来自 `harness_runtime.py adapter`/`meta/runtime.json`。所有 agent 共享统一路径 `.worktrees/<change-name>` 与统一分支前缀 `harness/`;`agent` 字段仅作创建者元数据,不再决定路径。
|
|
45
45
|
|
|
46
46
|
`用户选择使用 Worktree;决策文件为 meta/worktree.json;requested=true, created=false;创建责任为 harness-run。`
|
|
47
47
|
|
|
@@ -8,7 +8,7 @@ description: harness-review 的6维度审查检查项详细列表。仅在执行
|
|
|
8
8
|
|
|
9
9
|
用 Glob 搜索 `.harness/changes/*/plans/*-plan.md`(**排除 `.harness/archive/*/`**),读取 frontmatter 提取 `change-name`。默认最多一个未归档变更;如有多个,优先取最近修改的,或询问用户。后续所有路径基于此变更名。
|
|
10
10
|
|
|
11
|
-
**读取 worktree 状态**:读 `.harness/changes/<change-name>/meta/worktree.json`。`requested=true` 且 worktree 已创建 → 后续 `git diff` 的 `<项目路径>` 用 worktree 路径(`.
|
|
11
|
+
**读取 worktree 状态**:读 `.harness/changes/<change-name>/meta/worktree.json`。`requested=true` 且 worktree 已创建 → 后续 `git diff` 的 `<项目路径>` 用 worktree 路径(`.worktrees/<change-name>`);`requested=true` 但 worktree 不存在 → 停止,提示先修复 `harness-run`,不得静默回主目录。
|
|
12
12
|
|
|
13
13
|
## 审查流程
|
|
14
14
|
|
|
@@ -17,7 +17,7 @@ description: harness-run 的执行检查清单。仅在编码执行时读取。
|
|
|
17
17
|
- [ ] `requested=true` 且 worktree 存在 → 切换到 worktree 执行
|
|
18
18
|
- [ ] `requested=true` 且 worktree 不存在 → 必须创建 worktree
|
|
19
19
|
- [ ] worktree 创建命令必须使用 PowerShell:`git worktree add ...`
|
|
20
|
-
- [ ] 创建后验证
|
|
20
|
+
- [ ] 创建后验证 `.worktrees/<change-name>/.git` 存在
|
|
21
21
|
- [ ] 创建成功后更新 `meta/worktree.json` 的 `created=true/createdAt/createdBy`
|
|
22
22
|
- [ ] 创建失败 → 停止,或 blocking user confirmation 询问是否改为主目录执行
|
|
23
23
|
- [ ] 禁止 `requested=true && worktree 不存在` 时直接主目录执行
|
|
@@ -76,7 +76,7 @@ requested=true + path missing
|
|
|
76
76
|
```json
|
|
77
77
|
{
|
|
78
78
|
"projectRoot": ".../udp",
|
|
79
|
-
"worktreeRoot": ".../udp/<
|
|
79
|
+
"worktreeRoot": ".../udp/.worktrees/<change-name>",
|
|
80
80
|
"stateDir": ".../udp/.harness/changes/<change-name>"
|
|
81
81
|
}
|
|
82
82
|
```
|
|
@@ -328,7 +328,7 @@ append `phase.start`(`--phase merge`;`note` 含 worktree 分支、主分支
|
|
|
328
328
|
### 步骤 M1:preflight
|
|
329
329
|
|
|
330
330
|
```powershell
|
|
331
|
-
python harness/scripts/harness_integration.py preflight --change <change-name> --run-id <run-id> --feature-branch
|
|
331
|
+
python harness/scripts/harness_integration.py preflight --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp>
|
|
332
332
|
```
|
|
333
333
|
|
|
334
334
|
获取 integration lock、解析 base/feature head、写 journal 与保护 refs(`refs/harness/integration/<txn>/base|head`)。锁被其他 run 持有 → **停止**,不改动工作区与状态文件。
|
|
@@ -336,7 +336,7 @@ python harness/scripts/harness_integration.py preflight --change <change-name> -
|
|
|
336
336
|
### 步骤 M2:prepare
|
|
337
337
|
|
|
338
338
|
```powershell
|
|
339
|
-
python harness/scripts/harness_integration.py prepare --change <change-name> --run-id <run-id> --feature-branch
|
|
339
|
+
python harness/scripts/harness_integration.py prepare --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp>
|
|
340
340
|
```
|
|
341
341
|
|
|
342
342
|
fetch 后从**已提交** target 创建临时 integration worktree;primary 的 staged/unstaged/untracked/ignored 与 mtime 均不被触碰。
|
|
@@ -344,7 +344,7 @@ fetch 后从**已提交** target 创建临时 integration worktree;primary 的
|
|
|
344
344
|
### 步骤 M3:merge
|
|
345
345
|
|
|
346
346
|
```powershell
|
|
347
|
-
python harness/scripts/harness_integration.py merge --change <change-name> --run-id <run-id> --feature-branch
|
|
347
|
+
python harness/scripts/harness_integration.py merge --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp>
|
|
348
348
|
```
|
|
349
349
|
|
|
350
350
|
- 方式固定 `--no-ff`;merge diff 出现其他 Change 的 contract/runtime 路径 → 结构化 `FOREIGN_CHANGE_PATHS` 拒绝
|
|
@@ -356,7 +356,7 @@ python harness/scripts/harness_integration.py merge --change <change-name> --run
|
|
|
356
356
|
在 integration worktree 内执行验证命令;远端引入他人提交或 ledger 不可复用时必跑:
|
|
357
357
|
|
|
358
358
|
```powershell
|
|
359
|
-
python harness/scripts/harness_integration.py verify --change <change-name> --run-id <run-id> --feature-branch
|
|
359
|
+
python harness/scripts/harness_integration.py verify --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp> --command "<resolved command>"
|
|
360
360
|
```
|
|
361
361
|
|
|
362
362
|
任一命令非零退出 → step FAILED,不进入 push。
|
|
@@ -370,7 +370,7 @@ powershell.exe -Command "python harness/scripts/harness_check_gate.py --write"
|
|
|
370
370
|
### 步骤 M5:push
|
|
371
371
|
|
|
372
372
|
```powershell
|
|
373
|
-
python harness/scripts/harness_integration.py push --change <change-name> --run-id <run-id> --feature-branch
|
|
373
|
+
python harness/scripts/harness_integration.py push --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp>
|
|
374
374
|
```
|
|
375
375
|
|
|
376
376
|
远端基线漂移 → `TARGET_MOVED` 结构化失败,不继续。成功后 journal `pushedHead` 即 `mergeFinalHash`。
|
|
@@ -378,7 +378,7 @@ python harness/scripts/harness_integration.py push --change <change-name> --run-
|
|
|
378
378
|
### 步骤 M6:cleanup
|
|
379
379
|
|
|
380
380
|
```powershell
|
|
381
|
-
python harness/scripts/harness_integration.py cleanup --change <change-name> --run-id <run-id> --feature-branch
|
|
381
|
+
python harness/scripts/harness_integration.py cleanup --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp>
|
|
382
382
|
```
|
|
383
383
|
|
|
384
384
|
- `git worktree remove --force` 精确路径 → 验证注销 → 临时分支 `branch -D` → (push 成功后)删除保护 refs → 释放 integration lock
|
|
@@ -23,10 +23,10 @@ if hasattr(sys.stderr, "reconfigure"):
|
|
|
23
23
|
SCHEMA_VERSION = 1
|
|
24
24
|
_CHANGE_ID = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$")
|
|
25
25
|
_ADAPTERS = {
|
|
26
|
-
"claude-code": (".
|
|
27
|
-
"codex": (".
|
|
28
|
-
"cursor": (".
|
|
29
|
-
"codebuddy": (".
|
|
26
|
+
"claude-code": (".worktrees", "harness/"),
|
|
27
|
+
"codex": (".worktrees", "harness/"),
|
|
28
|
+
"cursor": (".worktrees", "harness/"),
|
|
29
|
+
"codebuddy": (".worktrees", "harness/"),
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
|
|
@@ -164,6 +164,7 @@ def get_service_start(profile: dict[str, Any]) -> dict[str, Any]:
|
|
|
164
164
|
# runtime resolve 把具体 overlay/profile 注入到 session,不写回持久 profile
|
|
165
165
|
# (spec §3.1 持久 profile 只保存模板;§3.4 修复输入端陈旧 profile)。
|
|
166
166
|
STALE_WORKTREE_MARKERS: tuple[str, ...] = (
|
|
167
|
+
".worktrees/",
|
|
167
168
|
".claude/worktrees/",
|
|
168
169
|
".cursor/worktrees/",
|
|
169
170
|
".codeium/worktrees/",
|
|
@@ -15,10 +15,10 @@ description: harness-plan 的需求提取模板、任务拆分规则、测试场
|
|
|
15
15
|
"requested": true,
|
|
16
16
|
"created": false,
|
|
17
17
|
"agent": "<active-adapter>",
|
|
18
|
-
"worktreeRoot": "
|
|
19
|
-
"branchPrefix": "
|
|
20
|
-
"path": "
|
|
21
|
-
"branch": "
|
|
18
|
+
"worktreeRoot": ".worktrees",
|
|
19
|
+
"branchPrefix": "harness/",
|
|
20
|
+
"path": ".worktrees/<change-name>",
|
|
21
|
+
"branch": "harness/<change-name>",
|
|
22
22
|
"decisionBy": "user",
|
|
23
23
|
"decisionAt": "YYYY-MM-DD HH:mm",
|
|
24
24
|
"ownerSkill": "harness-run"
|
|
@@ -41,7 +41,7 @@ description: harness-plan 的需求提取模板、任务拆分规则、测试场
|
|
|
41
41
|
|
|
42
42
|
### 决策事件 note 示例
|
|
43
43
|
|
|
44
|
-
`path` 与 `branch` 必须来自 `harness_runtime.py adapter`/`meta/runtime.json
|
|
44
|
+
`path` 与 `branch` 必须来自 `harness_runtime.py adapter`/`meta/runtime.json`。所有 agent 共享统一路径 `.worktrees/<change-name>` 与统一分支前缀 `harness/`;`agent` 字段仅作创建者元数据,不再决定路径。
|
|
45
45
|
|
|
46
46
|
`用户选择使用 Worktree;决策文件为 meta/worktree.json;requested=true, created=false;创建责任为 harness-run。`
|
|
47
47
|
|
|
@@ -8,7 +8,7 @@ description: harness-review 的6维度审查检查项详细列表。仅在执行
|
|
|
8
8
|
|
|
9
9
|
用 Glob 搜索 `.harness/changes/*/plans/*-plan.md`(**排除 `.harness/archive/*/`**),读取 frontmatter 提取 `change-name`。默认最多一个未归档变更;如有多个,优先取最近修改的,或询问用户。后续所有路径基于此变更名。
|
|
10
10
|
|
|
11
|
-
**读取 worktree 状态**:读 `.harness/changes/<change-name>/meta/worktree.json`。`requested=true` 且 worktree 已创建 → 后续 `git diff` 的 `<项目路径>` 用 worktree 路径(`.
|
|
11
|
+
**读取 worktree 状态**:读 `.harness/changes/<change-name>/meta/worktree.json`。`requested=true` 且 worktree 已创建 → 后续 `git diff` 的 `<项目路径>` 用 worktree 路径(`.worktrees/<change-name>`);`requested=true` 但 worktree 不存在 → 停止,提示先修复 `harness-run`,不得静默回主目录。
|
|
12
12
|
|
|
13
13
|
## 审查流程
|
|
14
14
|
|
|
@@ -17,7 +17,7 @@ description: harness-run 的执行检查清单。仅在编码执行时读取。
|
|
|
17
17
|
- [ ] `requested=true` 且 worktree 存在 → 切换到 worktree 执行
|
|
18
18
|
- [ ] `requested=true` 且 worktree 不存在 → 必须创建 worktree
|
|
19
19
|
- [ ] worktree 创建命令必须使用 PowerShell:`git worktree add ...`
|
|
20
|
-
- [ ] 创建后验证
|
|
20
|
+
- [ ] 创建后验证 `.worktrees/<change-name>/.git` 存在
|
|
21
21
|
- [ ] 创建成功后更新 `meta/worktree.json` 的 `created=true/createdAt/createdBy`
|
|
22
22
|
- [ ] 创建失败 → 停止,或 blocking user confirmation 询问是否改为主目录执行
|
|
23
23
|
- [ ] 禁止 `requested=true && worktree 不存在` 时直接主目录执行
|
|
@@ -76,7 +76,7 @@ requested=true + path missing
|
|
|
76
76
|
```json
|
|
77
77
|
{
|
|
78
78
|
"projectRoot": ".../udp",
|
|
79
|
-
"worktreeRoot": ".../udp/<
|
|
79
|
+
"worktreeRoot": ".../udp/.worktrees/<change-name>",
|
|
80
80
|
"stateDir": ".../udp/.harness/changes/<change-name>"
|
|
81
81
|
}
|
|
82
82
|
```
|
|
@@ -328,7 +328,7 @@ append `phase.start`(`--phase merge`;`note` 含 worktree 分支、主分支
|
|
|
328
328
|
### 步骤 M1:preflight
|
|
329
329
|
|
|
330
330
|
```powershell
|
|
331
|
-
python harness/scripts/harness_integration.py preflight --change <change-name> --run-id <run-id> --feature-branch
|
|
331
|
+
python harness/scripts/harness_integration.py preflight --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp>
|
|
332
332
|
```
|
|
333
333
|
|
|
334
334
|
获取 integration lock、解析 base/feature head、写 journal 与保护 refs(`refs/harness/integration/<txn>/base|head`)。锁被其他 run 持有 → **停止**,不改动工作区与状态文件。
|
|
@@ -336,7 +336,7 @@ python harness/scripts/harness_integration.py preflight --change <change-name> -
|
|
|
336
336
|
### 步骤 M2:prepare
|
|
337
337
|
|
|
338
338
|
```powershell
|
|
339
|
-
python harness/scripts/harness_integration.py prepare --change <change-name> --run-id <run-id> --feature-branch
|
|
339
|
+
python harness/scripts/harness_integration.py prepare --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp>
|
|
340
340
|
```
|
|
341
341
|
|
|
342
342
|
fetch 后从**已提交** target 创建临时 integration worktree;primary 的 staged/unstaged/untracked/ignored 与 mtime 均不被触碰。
|
|
@@ -344,7 +344,7 @@ fetch 后从**已提交** target 创建临时 integration worktree;primary 的
|
|
|
344
344
|
### 步骤 M3:merge
|
|
345
345
|
|
|
346
346
|
```powershell
|
|
347
|
-
python harness/scripts/harness_integration.py merge --change <change-name> --run-id <run-id> --feature-branch
|
|
347
|
+
python harness/scripts/harness_integration.py merge --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp>
|
|
348
348
|
```
|
|
349
349
|
|
|
350
350
|
- 方式固定 `--no-ff`;merge diff 出现其他 Change 的 contract/runtime 路径 → 结构化 `FOREIGN_CHANGE_PATHS` 拒绝
|
|
@@ -356,7 +356,7 @@ python harness/scripts/harness_integration.py merge --change <change-name> --run
|
|
|
356
356
|
在 integration worktree 内执行验证命令;远端引入他人提交或 ledger 不可复用时必跑:
|
|
357
357
|
|
|
358
358
|
```powershell
|
|
359
|
-
python harness/scripts/harness_integration.py verify --change <change-name> --run-id <run-id> --feature-branch
|
|
359
|
+
python harness/scripts/harness_integration.py verify --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp> --command "<resolved command>"
|
|
360
360
|
```
|
|
361
361
|
|
|
362
362
|
任一命令非零退出 → step FAILED,不进入 push。
|
|
@@ -370,7 +370,7 @@ powershell.exe -Command "python harness/scripts/harness_check_gate.py --write"
|
|
|
370
370
|
### 步骤 M5:push
|
|
371
371
|
|
|
372
372
|
```powershell
|
|
373
|
-
python harness/scripts/harness_integration.py push --change <change-name> --run-id <run-id> --feature-branch
|
|
373
|
+
python harness/scripts/harness_integration.py push --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp>
|
|
374
374
|
```
|
|
375
375
|
|
|
376
376
|
远端基线漂移 → `TARGET_MOVED` 结构化失败,不继续。成功后 journal `pushedHead` 即 `mergeFinalHash`。
|
|
@@ -378,7 +378,7 @@ python harness/scripts/harness_integration.py push --change <change-name> --run-
|
|
|
378
378
|
### 步骤 M6:cleanup
|
|
379
379
|
|
|
380
380
|
```powershell
|
|
381
|
-
python harness/scripts/harness_integration.py cleanup --change <change-name> --run-id <run-id> --feature-branch
|
|
381
|
+
python harness/scripts/harness_integration.py cleanup --change <change-name> --run-id <run-id> --feature-branch harness/<change-name> --target-branch <主分支> --temp-root <task-temp>
|
|
382
382
|
```
|
|
383
383
|
|
|
384
384
|
- `git worktree remove --force` 精确路径 → 验证注销 → 临时分支 `branch -D` → (push 成功后)删除保护 refs → 释放 integration lock
|
|
@@ -23,10 +23,10 @@ if hasattr(sys.stderr, "reconfigure"):
|
|
|
23
23
|
SCHEMA_VERSION = 1
|
|
24
24
|
_CHANGE_ID = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$")
|
|
25
25
|
_ADAPTERS = {
|
|
26
|
-
"claude-code": (".
|
|
27
|
-
"codex": (".
|
|
28
|
-
"cursor": (".
|
|
29
|
-
"codebuddy": (".
|
|
26
|
+
"claude-code": (".worktrees", "harness/"),
|
|
27
|
+
"codex": (".worktrees", "harness/"),
|
|
28
|
+
"cursor": (".worktrees", "harness/"),
|
|
29
|
+
"codebuddy": (".worktrees", "harness/"),
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
|
|
@@ -164,6 +164,7 @@ def get_service_start(profile: dict[str, Any]) -> dict[str, Any]:
|
|
|
164
164
|
# runtime resolve 把具体 overlay/profile 注入到 session,不写回持久 profile
|
|
165
165
|
# (spec §3.1 持久 profile 只保存模板;§3.4 修复输入端陈旧 profile)。
|
|
166
166
|
STALE_WORKTREE_MARKERS: tuple[str, ...] = (
|
|
167
|
+
".worktrees/",
|
|
167
168
|
".claude/worktrees/",
|
|
168
169
|
".cursor/worktrees/",
|
|
169
170
|
".codeium/worktrees/",
|
|
@@ -10,7 +10,7 @@ description: harness-package 的8步工作流详细步骤、模块识别方法
|
|
|
10
10
|
|
|
11
11
|
如果 `$ARGUMENTS` 非空且与检测到的变更名不一致,以 `$ARGUMENTS` 为准。
|
|
12
12
|
|
|
13
|
-
**读取 worktree 状态并切换**:读 `.harness/changes/<change-name>/meta/worktree.json`(旧路径 `worktree.json` 兼容)。`requested=true` 且 `.
|
|
13
|
+
**读取 worktree 状态并切换**:读 `.harness/changes/<change-name>/meta/worktree.json`(旧路径 `worktree.json` 兼容)。`requested=true` 且 `.worktrees/<change-name>/` 已创建 → cd 到该 worktree 目录;`requested=true` 但 worktree 不存在 → 停止,提示先修复 `harness-run`,不得静默回主目录;`requested=false` → 在主目录执行。切换后检查构建配置文件(`.mvn/maven.config`、`settings-*.xml` 等)是否完整,缺失时从主目录复制。
|
|
14
14
|
|
|
15
15
|
**强制前置检查 — harness-test(硬门禁)和 harness-review(参考性)**:
|
|
16
16
|
|