@hunter-harness/workflow-harness 0.2.23 → 0.2.24
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-build.json +1 -1
- package/harness/bundles/general/claude-code/README.md +2 -2
- package/harness/bundles/general/claude-code/agents/harness-evaluator.md +4 -4
- package/harness/bundles/general/claude-code/agents/harness-explorer.md +2 -2
- package/harness/bundles/general/claude-code/agents/harness-reviewer.md +2 -2
- package/harness/bundles/general/claude-code/harness-archive/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-plan/SKILL.md +7 -4
- package/harness/bundles/general/claude-code/harness-plan/checklist.md +12 -17
- package/harness/bundles/general/claude-code/harness-plan/reference.md +7 -19
- package/harness/bundles/general/claude-code/harness-review/SKILL.md +3 -3
- package/harness/bundles/general/claude-code/harness-run/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-run/protocols.md +3 -3
- package/harness/bundles/general/claude-code/harness-submit/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-submit/checklist.md +8 -2
- package/harness/bundles/general/claude-code/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-test/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/scripts/harness_deploy.py +22 -3
- package/harness/bundles/general/claude-code/scripts/harness_preflight.py +50 -29
- package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
- package/harness/bundles/general/codebuddy/README.md +2 -2
- package/harness/bundles/general/codebuddy/agents/harness-evaluator.md +5 -6
- package/harness/bundles/general/codebuddy/agents/harness-explorer.md +3 -3
- package/harness/bundles/general/codebuddy/agents/harness-reviewer.md +3 -5
- package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-plan/SKILL.md +7 -4
- package/harness/bundles/general/codebuddy/harness-plan/checklist.md +12 -17
- package/harness/bundles/general/codebuddy/harness-plan/reference.md +7 -19
- package/harness/bundles/general/codebuddy/harness-review/SKILL.md +3 -3
- package/harness/bundles/general/codebuddy/harness-run/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-run/protocols.md +3 -3
- package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-submit/checklist.md +8 -2
- package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-test/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/scripts/harness_deploy.py +22 -3
- package/harness/bundles/general/codebuddy/scripts/harness_preflight.py +50 -29
- package/harness/bundles/general/codex/.harness-build.json +1 -1
- package/harness/bundles/general/codex/README.md +2 -2
- package/harness/bundles/general/codex/harness-archive/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-plan/SKILL.md +7 -5
- package/harness/bundles/general/codex/harness-plan/checklist.md +12 -17
- package/harness/bundles/general/codex/harness-plan/reference.md +7 -19
- package/harness/bundles/general/codex/harness-review/SKILL.md +2 -2
- package/harness/bundles/general/codex/harness-run/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-run/protocols.md +3 -3
- package/harness/bundles/general/codex/harness-submit/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-submit/checklist.md +8 -2
- package/harness/bundles/general/codex/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-test/SKILL.md +1 -1
- package/harness/bundles/general/codex/scripts/harness_deploy.py +22 -3
- package/harness/bundles/general/codex/scripts/harness_preflight.py +50 -29
- package/harness/bundles/general/cursor/.harness-build.json +1 -1
- package/harness/bundles/general/cursor/README.md +2 -2
- package/harness/bundles/general/cursor/harness-archive/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-plan/SKILL.md +7 -5
- package/harness/bundles/general/cursor/harness-plan/checklist.md +12 -17
- package/harness/bundles/general/cursor/harness-plan/reference.md +7 -19
- package/harness/bundles/general/cursor/harness-review/SKILL.md +2 -2
- package/harness/bundles/general/cursor/harness-run/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-run/protocols.md +3 -3
- package/harness/bundles/general/cursor/harness-submit/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-submit/checklist.md +8 -2
- package/harness/bundles/general/cursor/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-test/SKILL.md +1 -1
- package/harness/bundles/general/cursor/scripts/harness_deploy.py +22 -3
- package/harness/bundles/general/cursor/scripts/harness_preflight.py +50 -29
- package/harness/bundles/java/claude-code/.harness-build.json +1 -1
- package/harness/bundles/java/claude-code/README.md +2 -2
- package/harness/bundles/java/claude-code/agents/harness-evaluator.md +4 -4
- package/harness/bundles/java/claude-code/agents/harness-explorer.md +2 -2
- package/harness/bundles/java/claude-code/agents/harness-reviewer.md +2 -2
- package/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-archive/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-package/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-plan/SKILL.md +7 -4
- package/harness/bundles/java/claude-code/harness-plan/checklist.md +12 -17
- package/harness/bundles/java/claude-code/harness-plan/reference.md +7 -19
- package/harness/bundles/java/claude-code/harness-review/SKILL.md +3 -3
- package/harness/bundles/java/claude-code/harness-run/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-run/protocols.md +3 -3
- package/harness/bundles/java/claude-code/harness-submit/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-submit/checklist.md +8 -2
- package/harness/bundles/java/claude-code/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-test/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/scripts/harness_deploy.py +22 -3
- package/harness/bundles/java/claude-code/scripts/harness_preflight.py +50 -29
- package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
- package/harness/bundles/java/codebuddy/README.md +2 -2
- package/harness/bundles/java/codebuddy/agents/harness-evaluator.md +5 -6
- package/harness/bundles/java/codebuddy/agents/harness-explorer.md +3 -3
- package/harness/bundles/java/codebuddy/agents/harness-reviewer.md +3 -5
- package/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-archive/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-package/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-plan/SKILL.md +7 -4
- package/harness/bundles/java/codebuddy/harness-plan/checklist.md +12 -17
- package/harness/bundles/java/codebuddy/harness-plan/reference.md +7 -19
- package/harness/bundles/java/codebuddy/harness-review/SKILL.md +3 -3
- package/harness/bundles/java/codebuddy/harness-run/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-run/protocols.md +3 -3
- package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-submit/checklist.md +8 -2
- package/harness/bundles/java/codebuddy/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-test/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/scripts/harness_deploy.py +22 -3
- package/harness/bundles/java/codebuddy/scripts/harness_preflight.py +50 -29
- package/harness/bundles/java/codex/.harness-build.json +1 -1
- package/harness/bundles/java/codex/README.md +2 -2
- package/harness/bundles/java/codex/harness-apidoc/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-archive/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-package/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-plan/SKILL.md +7 -5
- package/harness/bundles/java/codex/harness-plan/checklist.md +12 -17
- package/harness/bundles/java/codex/harness-plan/reference.md +7 -19
- package/harness/bundles/java/codex/harness-review/SKILL.md +2 -2
- package/harness/bundles/java/codex/harness-run/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-run/protocols.md +3 -3
- package/harness/bundles/java/codex/harness-submit/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-submit/checklist.md +8 -2
- package/harness/bundles/java/codex/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-test/SKILL.md +1 -1
- package/harness/bundles/java/codex/scripts/harness_deploy.py +22 -3
- package/harness/bundles/java/codex/scripts/harness_preflight.py +50 -29
- package/harness/bundles/java/cursor/.harness-build.json +1 -1
- package/harness/bundles/java/cursor/README.md +2 -2
- package/harness/bundles/java/cursor/harness-apidoc/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-archive/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-package/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-plan/SKILL.md +7 -5
- package/harness/bundles/java/cursor/harness-plan/checklist.md +12 -17
- package/harness/bundles/java/cursor/harness-plan/reference.md +7 -19
- package/harness/bundles/java/cursor/harness-review/SKILL.md +2 -2
- package/harness/bundles/java/cursor/harness-run/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-run/protocols.md +3 -3
- package/harness/bundles/java/cursor/harness-submit/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-submit/checklist.md +8 -2
- package/harness/bundles/java/cursor/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-test/SKILL.md +1 -1
- package/harness/bundles/java/cursor/scripts/harness_deploy.py +22 -3
- package/harness/bundles/java/cursor/scripts/harness_preflight.py +50 -29
- package/harness/manifests/general/claude-code.json +22 -22
- package/harness/manifests/general/codebuddy.json +22 -22
- package/harness/manifests/general/codex.json +19 -19
- package/harness/manifests/general/cursor.json +19 -19
- package/harness/manifests/java/claude-code.json +24 -24
- package/harness/manifests/java/codebuddy.json +24 -24
- package/harness/manifests/java/codex.json +21 -21
- package/harness/manifests/java/cursor.json +21 -21
- package/hunter-workflow-family.json +2 -2
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: harness-sync
|
|
3
3
|
description: 检查并更新项目AI元数据(CodeGraph索引、harness-codebase-map分析、CLAUDE.md、AGENTS.md、.harness/完整性),确保Claude对代码库的理解与最新代码一致。当用户说'同步/更新索引/刷新元数据/检查一致性'时使用
|
|
4
4
|
---
|
|
5
|
-
<!-- generated by harness_deploy.py; core=
|
|
5
|
+
<!-- generated by harness_deploy.py; core=ba489b1737d25aef; overlay=java; agent=codex; do not edit -->
|
|
6
6
|
# harness-sync — 元数据同步
|
|
7
7
|
|
|
8
8
|
## Purpose
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: harness-test
|
|
3
3
|
description: 测试执行:读取场景表,执行单元测试+API接口测试+数据兼容验证,输出测试报告。当用户说'跑测试/验证/跑用例/接口测试/单元测试'时使用
|
|
4
4
|
---
|
|
5
|
-
<!-- generated by harness_deploy.py; core=
|
|
5
|
+
<!-- generated by harness_deploy.py; core=ba489b1737d25aef; overlay=java; agent=codex; do not edit -->
|
|
6
6
|
# harness-test — 测试执行
|
|
7
7
|
|
|
8
8
|
## Purpose
|
|
@@ -16,6 +16,7 @@ import re
|
|
|
16
16
|
import shutil
|
|
17
17
|
import subprocess
|
|
18
18
|
import sys
|
|
19
|
+
import time
|
|
19
20
|
import uuid
|
|
20
21
|
from pathlib import Path
|
|
21
22
|
from typing import Any, Iterable
|
|
@@ -38,6 +39,7 @@ HEADING_RE = re.compile(r"^(#{2,6})\s+(.+?)\s*$")
|
|
|
38
39
|
FRAGMENT_HINT_RE = re.compile(r"^>\s*片段:\[\[shared/[^\]]+\]\]\s*.*$")
|
|
39
40
|
|
|
40
41
|
BUILD_MARKER = ".harness-build.json"
|
|
42
|
+
_REPLACE_RETRY_DELAYS_SECONDS = (0.05, 0.1, 0.2, 0.4, 0.8)
|
|
41
43
|
# Install-side managed manifests record which files a prior install owned, so a
|
|
42
44
|
# later conservative install can delete removed managed files while preserving
|
|
43
45
|
# user-owned files (design §3.8 要点4). Skills manifest lives in the skills
|
|
@@ -76,6 +78,23 @@ def now_iso() -> str:
|
|
|
76
78
|
return dt.datetime.now().astimezone().isoformat(timespec="seconds")
|
|
77
79
|
|
|
78
80
|
|
|
81
|
+
def replace_with_retry(source: Path, target: Path) -> None:
|
|
82
|
+
"""Bounded retry for transient directory locks during atomic swaps.
|
|
83
|
+
|
|
84
|
+
Windows indexers and antivirus scanners may briefly hold a newly generated
|
|
85
|
+
bundle directory. Retrying only ``PermissionError`` keeps real path and
|
|
86
|
+
contract failures fail-fast while avoiding an expensive full bundle rerun.
|
|
87
|
+
"""
|
|
88
|
+
for attempt in range(len(_REPLACE_RETRY_DELAYS_SECONDS) + 1):
|
|
89
|
+
try:
|
|
90
|
+
os.replace(source, target)
|
|
91
|
+
return
|
|
92
|
+
except PermissionError:
|
|
93
|
+
if attempt >= len(_REPLACE_RETRY_DELAYS_SECONDS):
|
|
94
|
+
raise
|
|
95
|
+
time.sleep(_REPLACE_RETRY_DELAYS_SECONDS[attempt])
|
|
96
|
+
|
|
97
|
+
|
|
79
98
|
def emit_json(payload: dict[str, Any], *, ok: bool = True) -> int:
|
|
80
99
|
print(json.dumps(payload, ensure_ascii=False, indent=2))
|
|
81
100
|
return 0 if ok else 1
|
|
@@ -596,15 +615,15 @@ def cmd_build(
|
|
|
596
615
|
if out_dir.exists():
|
|
597
616
|
if (out_dir / BUILD_MARKER).is_file():
|
|
598
617
|
old_backup = out_dir.parent / f".{out_dir.name}.old-{uuid.uuid4().hex[:8]}"
|
|
599
|
-
|
|
618
|
+
replace_with_retry(out_dir, old_backup)
|
|
600
619
|
else:
|
|
601
620
|
shutil.rmtree(staging, ignore_errors=True)
|
|
602
621
|
raise ValueError(f"refusing to overwrite unmarked out_dir: {out_dir}")
|
|
603
622
|
try:
|
|
604
|
-
|
|
623
|
+
replace_with_retry(staging, out_dir)
|
|
605
624
|
except OSError:
|
|
606
625
|
if old_backup is not None and old_backup.exists():
|
|
607
|
-
|
|
626
|
+
replace_with_retry(old_backup, out_dir)
|
|
608
627
|
raise
|
|
609
628
|
if old_backup is not None:
|
|
610
629
|
shutil.rmtree(old_backup, ignore_errors=True)
|
|
@@ -374,12 +374,14 @@ def _resolve_agents_root(skills_root: Path, agents_root: Path | None) -> tuple[P
|
|
|
374
374
|
return (skills_root / "agents").resolve(), None
|
|
375
375
|
|
|
376
376
|
|
|
377
|
-
def _read_host_capabilities(skills_root: Path) -> set[str]:
|
|
377
|
+
def _read_host_capabilities(skills_root: Path) -> tuple[set[str], bool]:
|
|
378
378
|
"""Read agent capabilities declared by the host adapter (retro §5.3).
|
|
379
379
|
|
|
380
380
|
Adapter installs may declare available agent roles in
|
|
381
381
|
`meta/runtime.json` under `agentCapabilities` (list of role names).
|
|
382
|
-
Returns
|
|
382
|
+
Returns ``(capabilities, manifest_present)``. ``manifest_present`` is true
|
|
383
|
+
only when a readable capability list exists; an unrelated runtime.json
|
|
384
|
+
must not turn an unknown host into a hard "agent missing" failure.
|
|
383
385
|
"""
|
|
384
386
|
# runtime.json lives in the change's meta/ dir, but agent capabilities are
|
|
385
387
|
# project-level. Check the adapter's runtime.json at the project root.
|
|
@@ -398,8 +400,8 @@ def _read_host_capabilities(skills_root: Path) -> set[str]:
|
|
|
398
400
|
continue
|
|
399
401
|
caps = data.get("agentCapabilities")
|
|
400
402
|
if isinstance(caps, list):
|
|
401
|
-
return {str(c) for c in caps if isinstance(c, str)}
|
|
402
|
-
return set()
|
|
403
|
+
return {str(c) for c in caps if isinstance(c, str)}, True
|
|
404
|
+
return set(), False
|
|
403
405
|
|
|
404
406
|
|
|
405
407
|
def cmd_check_agents(
|
|
@@ -420,7 +422,7 @@ def cmd_check_agents(
|
|
|
420
422
|
}
|
|
421
423
|
|
|
422
424
|
resolved_agents_root, _ = _resolve_agents_root(skills_root, agents_root)
|
|
423
|
-
host_capabilities = _read_host_capabilities(skills_root)
|
|
425
|
+
host_capabilities, capability_manifest_present = _read_host_capabilities(skills_root)
|
|
424
426
|
host_callable = agent_name in host_capabilities
|
|
425
427
|
|
|
426
428
|
# Three independent fields (retro §5.3):
|
|
@@ -437,32 +439,37 @@ def cmd_check_agents(
|
|
|
437
439
|
agent_path = resolved_agents_root / filename
|
|
438
440
|
definition_present = agent_path.is_file()
|
|
439
441
|
|
|
440
|
-
#
|
|
441
|
-
#
|
|
442
|
+
# Codex/Cursor bundles intentionally do not install fixed harness-* agent
|
|
443
|
+
# definitions. Missing host capabilities therefore select the normal
|
|
444
|
+
# inline path instead of reporting UNKNOWN/"subagent unavailable".
|
|
442
445
|
if not definition_present and not host_callable:
|
|
443
|
-
# Check if this adapter is known to not support custom agents
|
|
444
446
|
adapter_name = skills_root.parent.name
|
|
445
447
|
if adapter_name in (".agents", ".cursor"):
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
448
|
+
reason_code = (
|
|
449
|
+
"HOST_CAPABILITY_NOT_DECLARED"
|
|
450
|
+
if capability_manifest_present
|
|
451
|
+
else "INLINE_BY_ADAPTER"
|
|
452
|
+
)
|
|
453
|
+
return {
|
|
454
|
+
"ok": True,
|
|
455
|
+
"action": "check-agents",
|
|
456
|
+
"agent": agent_name,
|
|
457
|
+
"usable": False,
|
|
458
|
+
"executionMode": "inline",
|
|
459
|
+
"fallbackPolicy": "inline-no-retry",
|
|
460
|
+
"definitionPresent": False,
|
|
461
|
+
"hostCallable": False,
|
|
462
|
+
"toolContractValid": False,
|
|
463
|
+
"capabilityManifestPresent": capability_manifest_present,
|
|
464
|
+
"reasonCode": reason_code,
|
|
465
|
+
"reason": (
|
|
466
|
+
"host capability manifest does not declare this fixed agent; "
|
|
467
|
+
"use the normal inline path"
|
|
468
|
+
if capability_manifest_present
|
|
469
|
+
else "adapter uses inline execution unless the host explicitly "
|
|
470
|
+
"declares a callable agent capability"
|
|
471
|
+
),
|
|
472
|
+
}
|
|
466
473
|
return {
|
|
467
474
|
"ok": False,
|
|
468
475
|
"action": "check-agents",
|
|
@@ -470,9 +477,12 @@ def cmd_check_agents(
|
|
|
470
477
|
"path": str(agent_path) if agent_path else None,
|
|
471
478
|
"agentsRoot": str(resolved_agents_root) if resolved_agents_root else None,
|
|
472
479
|
"usable": False,
|
|
480
|
+
"executionMode": "unavailable",
|
|
481
|
+
"fallbackPolicy": "inline-no-retry",
|
|
473
482
|
"definitionPresent": False,
|
|
474
483
|
"hostCallable": False,
|
|
475
484
|
"toolContractValid": False,
|
|
485
|
+
"capabilityManifestPresent": capability_manifest_present,
|
|
476
486
|
"reasonCode": "AGENT_DEFINITION_NOT_FOUND",
|
|
477
487
|
"reason": f"agent file not found and host does not declare role: {agent_name}",
|
|
478
488
|
}
|
|
@@ -488,9 +498,13 @@ def cmd_check_agents(
|
|
|
488
498
|
"agent": agent_name,
|
|
489
499
|
"path": str(agent_path),
|
|
490
500
|
"usable": False,
|
|
501
|
+
"executionMode": "unavailable",
|
|
502
|
+
"fallbackPolicy": "inline-no-retry",
|
|
491
503
|
"definitionPresent": True,
|
|
492
504
|
"hostCallable": host_callable,
|
|
493
505
|
"toolContractValid": False,
|
|
506
|
+
"capabilityManifestPresent": capability_manifest_present,
|
|
507
|
+
"reasonCode": "AGENT_DEFINITION_UNREADABLE",
|
|
494
508
|
"reason": f"cannot read agent file: {exc}",
|
|
495
509
|
}
|
|
496
510
|
|
|
@@ -502,9 +516,13 @@ def cmd_check_agents(
|
|
|
502
516
|
"agent": agent_name,
|
|
503
517
|
"path": str(agent_path),
|
|
504
518
|
"usable": False,
|
|
519
|
+
"executionMode": "unavailable",
|
|
520
|
+
"fallbackPolicy": "inline-no-retry",
|
|
505
521
|
"definitionPresent": True,
|
|
506
522
|
"hostCallable": host_callable,
|
|
507
523
|
"toolContractValid": False,
|
|
524
|
+
"capabilityManifestPresent": capability_manifest_present,
|
|
525
|
+
"reasonCode": "AGENT_DEFINITION_INVALID",
|
|
508
526
|
"reason": f"frontmatter parse failed: {err or 'unknown'}",
|
|
509
527
|
}
|
|
510
528
|
|
|
@@ -525,7 +543,7 @@ def cmd_check_agents(
|
|
|
525
543
|
name_field = meta.get("name") if meta else None
|
|
526
544
|
tools_field = meta.get("tools") if meta else None
|
|
527
545
|
|
|
528
|
-
reason_code = "READY" if usable else "
|
|
546
|
+
reason_code = "READY" if usable else "TOOL_CONTRACT_INVALID"
|
|
529
547
|
if not definition_present and host_callable:
|
|
530
548
|
reason_code = "DEFINITION_NOT_FOUND_HOST_CAPABLE"
|
|
531
549
|
|
|
@@ -536,9 +554,12 @@ def cmd_check_agents(
|
|
|
536
554
|
"path": str(agent_path) if agent_path else None,
|
|
537
555
|
"agentsRoot": str(resolved_agents_root) if resolved_agents_root else None,
|
|
538
556
|
"usable": usable,
|
|
557
|
+
"executionMode": "delegated" if usable else "unavailable",
|
|
558
|
+
"fallbackPolicy": "inline-no-retry",
|
|
539
559
|
"definitionPresent": definition_present,
|
|
540
560
|
"hostCallable": host_callable,
|
|
541
561
|
"toolContractValid": tool_contract_valid,
|
|
562
|
+
"capabilityManifestPresent": capability_manifest_present,
|
|
542
563
|
"reasonCode": reason_code,
|
|
543
564
|
"reason": (
|
|
544
565
|
"agent available; "
|
|
@@ -260,7 +260,7 @@ harness-skills/
|
|
|
260
260
|
| 阶段 | 强制检查 |
|
|
261
261
|
|------|---------|
|
|
262
262
|
| **plan 阶段 0** | 检查工作区是否有未提交业务代码变更,已有则询问用户处理方式(继续/暂存/回滚/取消),不得假装"编码前规划" |
|
|
263
|
-
| **plan 阶段 3** |
|
|
263
|
+
| **plan 阶段 3** | 默认主会话 CodeGraph/Read inline 探索;仅高复杂度且准备委派固定 agent 时单次预检,失败或无效返回立即 inline,不 retry |
|
|
264
264
|
| **plan 阶段 4/6** | 原生规划协议必须记录风险/复用/替代方案/推荐方案/关键决策,以及任务拆分摘要 |
|
|
265
265
|
| **plan 阶段 5** | 设计文档自审结果必须展示给用户;测试场景表未覆盖维度必须标记为 ⚠️ 缺口,不得全部 ✅ |
|
|
266
266
|
| **run 步骤 0** | 任何代码修改前必须先向 `events.ndjson` 追加 `phase.start`;执行日志由阶段结束事件自动渲染 |
|
|
@@ -401,7 +401,7 @@ powershell.exe -Command "Copy-Item -Path 'harness-skills/harness-*' -Destination
|
|
|
401
401
|
powershell.exe -Command "Copy-Item -Path 'harness-skills/harness-test' -Destination '<目标项目>/.claude/skills/' -Recurse -Force"
|
|
402
402
|
```
|
|
403
403
|
|
|
404
|
-
|
|
404
|
+
Claude Code/CodeBuddy 可选复制 3 个隔离角色:`harness-explorer` 仅高复杂度探索、`harness-evaluator` 仅 `--adversarial`/高风险规划、`harness-reviewer` 仅发布候选/高风险审查。Codex/Cursor 默认使用主会话或宿主临时隔离任务,不安装固定角色,也不执行固定 agent 预检:
|
|
405
405
|
|
|
406
406
|
```powershell
|
|
407
407
|
powershell.exe -Command "Copy-Item -Path 'harness-skills/agents/*.md' -Destination '<目标项目>/.claude/agents/' -Recurse -Force"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: harness-apidoc
|
|
3
3
|
description: 从 Java 后端代码生成结构化前端 API 文档(Controller/VO/ErrorCode)。使用场景:接口文档、前端接口文档、API 文档生成
|
|
4
4
|
---
|
|
5
|
-
<!-- generated by harness_deploy.py; core=
|
|
5
|
+
<!-- generated by harness_deploy.py; core=d50ff0ad2421c0cb; overlay=java; agent=cursor; do not edit -->
|
|
6
6
|
# harness-apidoc — 前端接口文档(Java overlay)
|
|
7
7
|
|
|
8
8
|
## Purpose
|
|
@@ -3,7 +3,7 @@ name: harness-archive
|
|
|
3
3
|
description: 归档所有变更产出(计划/测试报告/审查/SQL/API文档)到
|
|
4
4
|
.harness/archive/,含归档元数据和可视化最终总结。使用场景:归档、完成归档、收尾、打包产出物
|
|
5
5
|
---
|
|
6
|
-
<!-- generated by harness_deploy.py; core=
|
|
6
|
+
<!-- generated by harness_deploy.py; core=d50ff0ad2421c0cb; overlay=java; agent=cursor; do not edit -->
|
|
7
7
|
# harness-archive — 变更归档
|
|
8
8
|
|
|
9
9
|
## Purpose
|
|
@@ -3,7 +3,7 @@ name: harness-codebase-map
|
|
|
3
3
|
description: 分析现有代码库并生成 .harness/codebase/map/
|
|
4
4
|
下的结构化代码库地图。用于陌生项目理解、重大改造前梳理、harness-sync 提示 map 过期后的人工刷新。
|
|
5
5
|
---
|
|
6
|
-
<!-- generated by harness_deploy.py; core=
|
|
6
|
+
<!-- generated by harness_deploy.py; core=d50ff0ad2421c0cb; overlay=java; agent=cursor; do not edit -->
|
|
7
7
|
# harness-codebase-map — 代码库地图
|
|
8
8
|
|
|
9
9
|
## Purpose
|
|
@@ -3,7 +3,7 @@ name: harness-knowledge-ingest
|
|
|
3
3
|
description: 从 .harness/archive 归档整理、同步和维护项目知识索引。适用场景:ingest knowledge、sync
|
|
4
4
|
knowledge、rebuild knowledge index、promote knowledge、确认知识条目、检查知识库是否过期。
|
|
5
5
|
---
|
|
6
|
-
<!-- generated by harness_deploy.py; core=
|
|
6
|
+
<!-- generated by harness_deploy.py; core=d50ff0ad2421c0cb; overlay=java; agent=cursor; do not edit -->
|
|
7
7
|
# harness-knowledge-ingest
|
|
8
8
|
|
|
9
9
|
从 `.harness/archive/**/reports/final/summary-data.json` 抽取项目知识,生成并维护本地 `.harness/knowledge/` 索引。
|
|
@@ -3,7 +3,7 @@ name: harness-knowledge-query
|
|
|
3
3
|
description: 根据新需求、设计任务、代码修改请求或问题排查,在规划和编码前查询 .harness/knowledge
|
|
4
4
|
历史上下文。适用场景:query knowledge、查找历史需求、根据归档理解需求、继续之前类似开发、生成需求上下文包。
|
|
5
5
|
---
|
|
6
|
-
<!-- generated by harness_deploy.py; core=
|
|
6
|
+
<!-- generated by harness_deploy.py; core=d50ff0ad2421c0cb; overlay=java; agent=cursor; do not edit -->
|
|
7
7
|
# harness-knowledge-query
|
|
8
8
|
|
|
9
9
|
并行 change 中查询必须传 `--change <change-id>`;成功后以该 change 的 `meta/knowledge-context.json` 为稳定指针。全局 `context-packs/latest.json` 仅向后兼容,不得用于判断多个 active change 的上下文归属。
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: harness-package
|
|
3
3
|
description: 增量模块打包:拉取最新→编译验证→mvn package→汇总 jar/war。使用场景:打包、package、发版准备
|
|
4
4
|
---
|
|
5
|
-
<!-- generated by harness_deploy.py; core=
|
|
5
|
+
<!-- generated by harness_deploy.py; core=d50ff0ad2421c0cb; overlay=java; agent=cursor; do not edit -->
|
|
6
6
|
# harness-package — 增量模块打包(Java overlay)
|
|
7
7
|
|
|
8
8
|
## Purpose
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: harness-plan
|
|
3
3
|
description: 将需求转化为设计文档+实施计划+完整测试场景表,必须在编码前完成。使用场景:需求分析、feature plan、技术方案设计、实现方案规划
|
|
4
4
|
---
|
|
5
|
-
<!-- generated by harness_deploy.py; core=
|
|
5
|
+
<!-- generated by harness_deploy.py; core=d50ff0ad2421c0cb; overlay=java; agent=cursor; do not edit -->
|
|
6
6
|
# harness-plan — 需求规划
|
|
7
7
|
|
|
8
8
|
## Purpose
|
|
@@ -51,11 +51,13 @@ description: 将需求转化为设计文档+实施计划+完整测试场景表
|
|
|
51
51
|
|
|
52
52
|
内化为 `protocols.md`:`clarification-protocol`、`decision-grilling-protocol`、`implementation-planning-protocol`。不运行时调用 Superpowers/grill-me。
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
- **阶段 3 探索**:先运行 `python <skills-root>/scripts/harness_preflight.py check-agents --skills-root <skills-root> --agent harness-explorer --json`;可用则委派,否则主会话探索且不 retry。`reasonCode=CUSTOM_AGENTS_UNSUPPORTED` 表示当前工具本身没有自定义 agent 能力,是正常的 inline 路径,控制台不得显示“harness-explorer subagent 不可用”类告警。
|
|
57
|
-
- **阶段 7.5**:仅 `--adversarial`;先运行 `python <skills-root>/scripts/harness_preflight.py check-agents --skills-root <skills-root> --agent harness-evaluator --json`;可用才委派到 `reports/plan-review/`
|
|
54
|
+
<!-- @section-id plan.delegate -->
|
|
55
|
+
## 执行路由(宿主原生、无固定 agent 预检)
|
|
58
56
|
|
|
57
|
+
- 阶段 3 默认由主会话直接使用 CodeGraph/Read 完成探索,**不运行 `check-agents --agent harness-explorer`**。
|
|
58
|
+
- 只有多个独立模块、陌生大型代码库或可并行调查等高复杂度任务,且当前宿主显式提供通用隔离任务工具时,才可临时委派一次只读探索。
|
|
59
|
+
- 阶段 7.5 仅 `--adversarial` 或 auth/支付/迁移/并发等高风险规划启用;可用宿主临时隔离任务,否则主会话执行同一对抗检查。
|
|
60
|
+
- spawn 失败、空返回、0 tool uses、仅 "Done" 或元数据时立即 inline,`fallbackPolicy=inline-no-retry`。正常 inline 只记 `decision`,不显示 subagent 不可用告警。
|
|
59
61
|
## Workflow 概要
|
|
60
62
|
|
|
61
63
|
| 阶段 | 动作 |
|
|
@@ -37,21 +37,16 @@ description: harness-plan 的阶段检查清单和覆盖检查列表。仅在执
|
|
|
37
37
|
阶段 3 执行完成后,确认以下事项:
|
|
38
38
|
|
|
39
39
|
```
|
|
40
|
-
□
|
|
41
|
-
□
|
|
42
|
-
□
|
|
43
|
-
□ `
|
|
44
|
-
□
|
|
45
|
-
□
|
|
46
|
-
- 是否成功调用
|
|
47
|
-
- 使用的 agent 名称
|
|
48
|
-
- 是否只读
|
|
49
|
-
- 子代理实际 tool uses 计数
|
|
50
|
-
- 返回的核心结论
|
|
40
|
+
□ 已按复杂度选择 `executionMode=inline|delegated`;默认 inline
|
|
41
|
+
□ inline 时主会话直接使用 CodeGraph/Read,并返回结构化设计概要
|
|
42
|
+
□ 仅高复杂度且准备委派固定 agent 时,才运行一次 `check-agents --agent harness-explorer`
|
|
43
|
+
□ 只有预检 `executionMode=delegated` 才委派;`inline` 静默继续,不显示不可用告警
|
|
44
|
+
□ spawn 失败、空返回、0 tool uses、仅 "Done"/元数据 → 主会话探索,**不 retry 委派**
|
|
45
|
+
□ 执行日志记录 executionMode、委派原因(如有)、只读约束和核心结论
|
|
51
46
|
```
|
|
52
47
|
|
|
53
|
-
>
|
|
54
|
-
> -
|
|
48
|
+
> 正常 inline 只记 `decision`,不是降级或故障。如果已尝试委派但未返回有效输出(0 tool uses / 空返回 / 仅 "Done"),必须:
|
|
49
|
+
> - 追加一次 `issue` 事件并在 note 写明:子代理未返回有效输出,改为主会话只读探索
|
|
55
50
|
> - 主会话直接使用 codegraph MCP 工具(`mcp__codegraph__codegraph_explore`)和 Read 探索代码(只读,不执行写操作)
|
|
56
51
|
> - 不得在主会话中执行任何写操作
|
|
57
52
|
> - CodeGraph 如通过 MCP 调用,必须优先用 MCP 工具,不允许通过普通 Bash 调 codegraph 命令
|
|
@@ -156,10 +151,10 @@ source: harness-plan
|
|
|
156
151
|
```
|
|
157
152
|
□ 已用 **设计审批包** 一次 blocking user confirmation(设计 + 场景表摘要 + worktree + change-name)
|
|
158
153
|
□ **未**单独询问 worktree 或对抗评审(对抗评审仅 `--adversarial`)
|
|
159
|
-
□
|
|
160
|
-
□
|
|
161
|
-
□
|
|
162
|
-
□
|
|
154
|
+
□ 已按宿主能力选择隔离 evaluator 或主会话对抗自审;正常 inline 不记故障
|
|
155
|
+
□ 若委派,已使用隔离上下文且校验 tool uses > 0
|
|
156
|
+
□ 若委派返回 0/空/Done/元数据,已立即 inline 自审且未 retry
|
|
157
|
+
□ 已产出 VERDICT(APPROVED/REVISE) + 结构化问题清单(RED/YELLOW)
|
|
163
158
|
□ 评审报告已写入 .harness/changes/<change-name>/reports/plan-review/plan-review-YYYYMMDD-HHmm.md
|
|
164
159
|
□ VERDICT 和问题清单已展示给用户(不得仅记"已评审")
|
|
165
160
|
□ REVISE 时已询问用户是否修订;修订后可选再审
|
|
@@ -345,25 +345,13 @@ status: approved
|
|
|
345
345
|
- 最终输出只提示产出物路径和下一步 `/harness-run`
|
|
346
346
|
- `docs/superpowers/` 不得作为最终产物路径出现在输出中
|
|
347
347
|
|
|
348
|
-
## C2
|
|
348
|
+
## C2 升级口:跨 provider 评审(显式、非默认)
|
|
349
349
|
|
|
350
|
-
阶段 7.5
|
|
350
|
+
阶段 7.5 默认只做主会话对抗自审或宿主原生隔离任务,不自动启动第二个 CLI/provider。高风险构建确需跨 provider 二次确认时,由用户显式要求并提供可用宿主能力;该升级不属于正常 harness-plan 路径,也不得因外部工具不可用而 retry。
|
|
351
351
|
|
|
352
|
-
###
|
|
353
|
-
- Codex CLI ≥ 0.130:`npm install -g @openai/codex@latest`(现 0.142.3)
|
|
354
|
-
- Codex 已登录:`codex login`(ChatGPT 账号即可)
|
|
355
|
-
- Windows + bridge 环境未实测,TODO(review)
|
|
352
|
+
### 安全线
|
|
356
353
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
### 安全线 ⚠️
|
|
363
|
-
- 首次 `codex exec -s read-only` 强制只读沙箱
|
|
364
|
-
- resume 必须加 `-c sandbox_mode="read-only"`(`resume` 不接受 `-s`,漏写会继承 config 默认,可能 `danger-full-access`)——这是最关键安全线
|
|
365
|
-
- Codex 全程只读,从不写文件
|
|
366
|
-
- 不 pin `-m` 模型(ChatGPT 账号鉴权会拒 `gpt-5.x-codex` 变体并 400 报错)
|
|
367
|
-
|
|
368
|
-
### 状态
|
|
369
|
-
本节为**升级口**,当前 harness-plan 阶段 7.5 默认走 harness-evaluator(C1),不自动触发 Codex。需手动启用,且建议先验证 Codex CLI 在当前环境可用。详见 grill-me 文档的 grill-me-codex Act 2(技术知识库/02-Skills与扩展/Skills合集/grill-me.md)。
|
|
354
|
+
- 外部评审必须只读,输入只包含已脱敏的设计/计划/场景表
|
|
355
|
+
- 不继承未确认的生产凭证、写权限或危险沙箱设置
|
|
356
|
+
- 一次失败即返回主会话,不自动安装 CLI、不自动登录、不循环 resume
|
|
357
|
+
- 报告必须标注 provider、执行模式和证据边界
|
|
@@ -3,7 +3,7 @@ name: harness-review
|
|
|
3
3
|
description: 6维度代码审查(架构/安全/规范/兼容/测试/性能),对照项目规则(见
|
|
4
4
|
.harness/context-index.json)和测试场景表,在隔离上下文运行。使用场景:代码审查、提交前检查、合并评审
|
|
5
5
|
---
|
|
6
|
-
<!-- generated by harness_deploy.py; core=
|
|
6
|
+
<!-- generated by harness_deploy.py; core=d50ff0ad2421c0cb; overlay=java; agent=cursor; do not edit -->
|
|
7
7
|
# harness-review — 代码审查
|
|
8
8
|
|
|
9
9
|
## Purpose
|
|
@@ -53,7 +53,7 @@ description: 6维度代码审查(架构/安全/规范/兼容/测试/性能)
|
|
|
53
53
|
<!-- @section-id review.delegate -->
|
|
54
54
|
### 2. 审查执行(主会话优先)
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
默认在主会话按同一 6 维度检查清单执行,**不运行固定 `harness-reviewer` 预检**。仅发布候选或命中权限/安全、支付、迁移、并发幂等、公共契约、跨模块核心路径,且当前宿主显式提供通用隔离任务工具时,才可临时委派一次只读审查。spawn 失败、空返回或无报告正文 → 不 retry,继续主会话审查并记一次 `issue`;正常 inline 只记 `decision`,不显示不可用告警。
|
|
57
57
|
## Review 定位(重要)
|
|
58
58
|
|
|
59
59
|
**harness-review 是参考性代码审查阶段,不是硬门禁。**
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: harness-run
|
|
3
3
|
description: 按变更簇执行 TDD 编码循环(RED→GREEN→REFACTOR→编译验证),逐变更簇实现计划中的任务。使用场景:开始编码、实现功能、写代码、TDD 编码
|
|
4
4
|
---
|
|
5
|
-
<!-- generated by harness_deploy.py; core=
|
|
5
|
+
<!-- generated by harness_deploy.py; core=d50ff0ad2421c0cb; overlay=java; agent=cursor; do not edit -->
|
|
6
6
|
# harness-run — 需求编码
|
|
7
7
|
|
|
8
8
|
## Purpose
|
|
@@ -49,13 +49,13 @@ REFACTOR 只允许不改变行为的整理。若重构改变行为,必须回
|
|
|
49
49
|
满足**全部**条件时启用:
|
|
50
50
|
|
|
51
51
|
- 变更簇命中高风险(数据迁移、权限、安全、并发、幂等、核心契约变更、缺真实测试证据等,见原触发列表任一)
|
|
52
|
-
-
|
|
52
|
+
- 当前宿主已显式提供隔离 reviewer 能力;需要固定 reviewer 时,单次 `check-agents` 返回 `executionMode=delegated`
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
未满足时记录“跳过变更簇隔离审查:低风险 / 正常 inline / 后续 harness-review 覆盖”,不得视为降级或显示不可用告警。
|
|
55
55
|
|
|
56
56
|
### 审查方式
|
|
57
57
|
|
|
58
|
-
`
|
|
58
|
+
`executionMode=delegated` 时委派只读 `harness-reviewer` 审查当前变更簇 diff。**不 retry**;spawn 失败或无效返回 → 主会话 checklist 自审,记一次 `issue` 事件。
|
|
59
59
|
|
|
60
60
|
审查范围只限当前变更簇:
|
|
61
61
|
|
|
@@ -3,7 +3,7 @@ name: harness-submit
|
|
|
3
3
|
description: 最终提交封装:验证→中文 commit→提交/推送;worktree 模式含 --no-ff
|
|
4
4
|
合并回主分支。使用场景:提交代码、commit、push、合并分支、merge to main、完成开发
|
|
5
5
|
---
|
|
6
|
-
<!-- generated by harness_deploy.py; core=
|
|
6
|
+
<!-- generated by harness_deploy.py; core=d50ff0ad2421c0cb; overlay=java; agent=cursor; do not edit -->
|
|
7
7
|
# harness-submit — 最终提交(含 worktree 合并)
|
|
8
8
|
|
|
9
9
|
## Purpose
|
|
@@ -367,7 +367,13 @@ python harness/scripts/harness_integration.py verify --change <change-name> --ru
|
|
|
367
367
|
|
|
368
368
|
任一命令非零退出 → step FAILED,不进入 push。
|
|
369
369
|
|
|
370
|
-
|
|
370
|
+
**产品候选证据门槛**:
|
|
371
|
+
|
|
372
|
+
- 项目存在远端 CI:本地 push 只运行有界静态门槛,push 后必须取得当前候选 commit 的 CI 绿灯,才能归档或发布。
|
|
373
|
+
- 项目没有远端 CI:在候选 commit 对应的同一棵 tree 上完整执行 resolved check;成功后写本地候选收据。收据必须同时匹配时间、命令和 tree hash,不接受口头声明或旧提交结果。
|
|
374
|
+
- 不得在 pre-push 中无条件重复全量测试;失败后不自动重跑,先报告失败阶段与残留进程。
|
|
375
|
+
|
|
376
|
+
**写 check-ok marker**(`npm run check` exit 0 后强制;无 CI 项目以此作为产品候选绿灯证据):
|
|
371
377
|
|
|
372
378
|
```powershell
|
|
373
379
|
node scripts/check-gate.mjs --write
|
|
@@ -375,7 +381,7 @@ node scripts/check-gate.mjs --write
|
|
|
375
381
|
|
|
376
382
|
### 步骤 M5:push
|
|
377
383
|
|
|
378
|
-
**硬门槛(eslint × feature worktree)**:integration / 主仓 `pre-push`
|
|
384
|
+
**硬门槛(eslint × feature worktree)**:integration / 主仓 `pre-push` 跑有界 `check:push` 时,eslint 不得把 sibling `.worktrees/<change>/` 当成第二工程根(双 `tsconfigRootDir`)。本仓以 `eslint.config.mjs` 的 `.worktrees/**` ignore 为准;若自定义 eslint 未 ignore,须先 `move_agent_to_root(<projectRoot>)` 再清 feature worktree,再 push。
|
|
379
385
|
|
|
380
386
|
```powershell
|
|
381
387
|
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>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: harness-sync
|
|
3
3
|
description: 检查并更新项目AI元数据(CodeGraph索引、harness-codebase-map分析、CLAUDE.md、AGENTS.md、.harness/完整性),确保Claude对代码库的理解与最新代码一致。当用户说'同步/更新索引/刷新元数据/检查一致性'时使用
|
|
4
4
|
---
|
|
5
|
-
<!-- generated by harness_deploy.py; core=
|
|
5
|
+
<!-- generated by harness_deploy.py; core=d50ff0ad2421c0cb; overlay=java; agent=cursor; do not edit -->
|
|
6
6
|
# harness-sync — 元数据同步
|
|
7
7
|
|
|
8
8
|
## Purpose
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: harness-test
|
|
3
3
|
description: 测试执行:读取场景表,执行单元测试+API接口测试+数据兼容验证,输出测试报告。当用户说'跑测试/验证/跑用例/接口测试/单元测试'时使用
|
|
4
4
|
---
|
|
5
|
-
<!-- generated by harness_deploy.py; core=
|
|
5
|
+
<!-- generated by harness_deploy.py; core=d50ff0ad2421c0cb; overlay=java; agent=cursor; do not edit -->
|
|
6
6
|
# harness-test — 测试执行
|
|
7
7
|
|
|
8
8
|
## Purpose
|
|
@@ -16,6 +16,7 @@ import re
|
|
|
16
16
|
import shutil
|
|
17
17
|
import subprocess
|
|
18
18
|
import sys
|
|
19
|
+
import time
|
|
19
20
|
import uuid
|
|
20
21
|
from pathlib import Path
|
|
21
22
|
from typing import Any, Iterable
|
|
@@ -38,6 +39,7 @@ HEADING_RE = re.compile(r"^(#{2,6})\s+(.+?)\s*$")
|
|
|
38
39
|
FRAGMENT_HINT_RE = re.compile(r"^>\s*片段:\[\[shared/[^\]]+\]\]\s*.*$")
|
|
39
40
|
|
|
40
41
|
BUILD_MARKER = ".harness-build.json"
|
|
42
|
+
_REPLACE_RETRY_DELAYS_SECONDS = (0.05, 0.1, 0.2, 0.4, 0.8)
|
|
41
43
|
# Install-side managed manifests record which files a prior install owned, so a
|
|
42
44
|
# later conservative install can delete removed managed files while preserving
|
|
43
45
|
# user-owned files (design §3.8 要点4). Skills manifest lives in the skills
|
|
@@ -76,6 +78,23 @@ def now_iso() -> str:
|
|
|
76
78
|
return dt.datetime.now().astimezone().isoformat(timespec="seconds")
|
|
77
79
|
|
|
78
80
|
|
|
81
|
+
def replace_with_retry(source: Path, target: Path) -> None:
|
|
82
|
+
"""Bounded retry for transient directory locks during atomic swaps.
|
|
83
|
+
|
|
84
|
+
Windows indexers and antivirus scanners may briefly hold a newly generated
|
|
85
|
+
bundle directory. Retrying only ``PermissionError`` keeps real path and
|
|
86
|
+
contract failures fail-fast while avoiding an expensive full bundle rerun.
|
|
87
|
+
"""
|
|
88
|
+
for attempt in range(len(_REPLACE_RETRY_DELAYS_SECONDS) + 1):
|
|
89
|
+
try:
|
|
90
|
+
os.replace(source, target)
|
|
91
|
+
return
|
|
92
|
+
except PermissionError:
|
|
93
|
+
if attempt >= len(_REPLACE_RETRY_DELAYS_SECONDS):
|
|
94
|
+
raise
|
|
95
|
+
time.sleep(_REPLACE_RETRY_DELAYS_SECONDS[attempt])
|
|
96
|
+
|
|
97
|
+
|
|
79
98
|
def emit_json(payload: dict[str, Any], *, ok: bool = True) -> int:
|
|
80
99
|
print(json.dumps(payload, ensure_ascii=False, indent=2))
|
|
81
100
|
return 0 if ok else 1
|
|
@@ -596,15 +615,15 @@ def cmd_build(
|
|
|
596
615
|
if out_dir.exists():
|
|
597
616
|
if (out_dir / BUILD_MARKER).is_file():
|
|
598
617
|
old_backup = out_dir.parent / f".{out_dir.name}.old-{uuid.uuid4().hex[:8]}"
|
|
599
|
-
|
|
618
|
+
replace_with_retry(out_dir, old_backup)
|
|
600
619
|
else:
|
|
601
620
|
shutil.rmtree(staging, ignore_errors=True)
|
|
602
621
|
raise ValueError(f"refusing to overwrite unmarked out_dir: {out_dir}")
|
|
603
622
|
try:
|
|
604
|
-
|
|
623
|
+
replace_with_retry(staging, out_dir)
|
|
605
624
|
except OSError:
|
|
606
625
|
if old_backup is not None and old_backup.exists():
|
|
607
|
-
|
|
626
|
+
replace_with_retry(old_backup, out_dir)
|
|
608
627
|
raise
|
|
609
628
|
if old_backup is not None:
|
|
610
629
|
shutil.rmtree(old_backup, ignore_errors=True)
|