@hunter-harness/workflow-harness 0.2.52 → 0.2.54
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/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 +3 -2
- package/harness/bundles/general/claude-code/harness-review/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-run/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-submit/SKILL.md +1 -1
- 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_context.py +52 -0
- package/harness/bundles/general/claude-code/scripts/harness_events.py +26 -0
- package/harness/bundles/general/claude-code/scripts/harness_events_sync.py +602 -84
- package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
- 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 +3 -2
- package/harness/bundles/general/codebuddy/harness-review/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-run/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +1 -1
- 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_context.py +52 -0
- package/harness/bundles/general/codebuddy/scripts/harness_events.py +26 -0
- package/harness/bundles/general/codebuddy/scripts/harness_events_sync.py +602 -84
- package/harness/bundles/general/codex/.harness-build.json +1 -1
- 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 +3 -2
- package/harness/bundles/general/codex/harness-review/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-run/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-submit/SKILL.md +1 -1
- 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_context.py +52 -0
- package/harness/bundles/general/codex/scripts/harness_events.py +26 -0
- package/harness/bundles/general/codex/scripts/harness_events_sync.py +602 -84
- package/harness/bundles/general/cursor/.harness-build.json +1 -1
- 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 +3 -2
- package/harness/bundles/general/cursor/harness-review/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-run/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-submit/SKILL.md +1 -1
- 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_context.py +52 -0
- package/harness/bundles/general/cursor/scripts/harness_events.py +26 -0
- package/harness/bundles/general/cursor/scripts/harness_events_sync.py +602 -84
- package/harness/bundles/java/claude-code/.harness-build.json +1 -1
- 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 +3 -2
- package/harness/bundles/java/claude-code/harness-review/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-run/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-submit/SKILL.md +1 -1
- 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_context.py +52 -0
- package/harness/bundles/java/claude-code/scripts/harness_events.py +26 -0
- package/harness/bundles/java/claude-code/scripts/harness_events_sync.py +602 -84
- package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
- 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 +3 -2
- package/harness/bundles/java/codebuddy/harness-review/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-run/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +1 -1
- 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_context.py +52 -0
- package/harness/bundles/java/codebuddy/scripts/harness_events.py +26 -0
- package/harness/bundles/java/codebuddy/scripts/harness_events_sync.py +602 -84
- package/harness/bundles/java/codex/.harness-build.json +1 -1
- 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 +3 -2
- package/harness/bundles/java/codex/harness-review/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-run/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-submit/SKILL.md +1 -1
- 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_context.py +52 -0
- package/harness/bundles/java/codex/scripts/harness_events.py +26 -0
- package/harness/bundles/java/codex/scripts/harness_events_sync.py +602 -84
- package/harness/bundles/java/cursor/.harness-build.json +1 -1
- 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 +3 -2
- package/harness/bundles/java/cursor/harness-review/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-run/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-submit/SKILL.md +1 -1
- 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_context.py +52 -0
- package/harness/bundles/java/cursor/scripts/harness_events.py +26 -0
- package/harness/bundles/java/cursor/scripts/harness_events_sync.py +602 -84
- package/harness/manifests/general/claude-code.json +16 -16
- package/harness/manifests/general/codebuddy.json +16 -16
- package/harness/manifests/general/codex.json +16 -16
- package/harness/manifests/general/cursor.json +16 -16
- package/harness/manifests/java/claude-code.json +18 -18
- package/harness/manifests/java/codebuddy.json +18 -18
- package/harness/manifests/java/codex.json +18 -18
- package/harness/manifests/java/cursor.json +18 -18
- package/hunter-workflow-family.json +4 -4
- package/package.json +1 -1
|
@@ -21,7 +21,7 @@ disallowed-tools:
|
|
|
21
21
|
- Bash(awk *)
|
|
22
22
|
- Bash(curl *)
|
|
23
23
|
---
|
|
24
|
-
<!-- generated by harness_deploy.py; core=
|
|
24
|
+
<!-- generated by harness_deploy.py; core=9f66b2de1ca64c6e; overlay=none; agent=claude-code; do not edit -->
|
|
25
25
|
# harness-archive — 变更归档
|
|
26
26
|
|
|
27
27
|
## Purpose
|
|
@@ -20,7 +20,7 @@ disallowed-tools:
|
|
|
20
20
|
- Bash(awk *)
|
|
21
21
|
- Bash(curl *)
|
|
22
22
|
---
|
|
23
|
-
<!-- generated by harness_deploy.py; core=
|
|
23
|
+
<!-- generated by harness_deploy.py; core=9f66b2de1ca64c6e; overlay=none; agent=claude-code; do not edit -->
|
|
24
24
|
# harness-codebase-map — 代码库地图
|
|
25
25
|
|
|
26
26
|
## Purpose
|
|
@@ -8,7 +8,7 @@ disallowed-tools:
|
|
|
8
8
|
- Bash(git *)
|
|
9
9
|
- Bash(curl *)
|
|
10
10
|
---
|
|
11
|
-
<!-- generated by harness_deploy.py; core=
|
|
11
|
+
<!-- generated by harness_deploy.py; core=9f66b2de1ca64c6e; overlay=none; agent=claude-code; do not edit -->
|
|
12
12
|
# harness-knowledge-ingest
|
|
13
13
|
|
|
14
14
|
知识 ingest 完全由 Hunter Platform 负责。归档完成时,客户端生成一个确定性 ZIP;
|
|
@@ -8,7 +8,7 @@ disallowed-tools:
|
|
|
8
8
|
- Bash(git *)
|
|
9
9
|
- Bash(curl *)
|
|
10
10
|
---
|
|
11
|
-
<!-- generated by harness_deploy.py; core=
|
|
11
|
+
<!-- generated by harness_deploy.py; core=9f66b2de1ca64c6e; overlay=none; agent=claude-code; do not edit -->
|
|
12
12
|
# harness-knowledge-query
|
|
13
13
|
|
|
14
14
|
项目知识以 Hunter Platform 的服务端索引为唯一真源。客户端只提交查询并消费结果:
|
|
@@ -21,7 +21,7 @@ disallowed-tools:
|
|
|
21
21
|
- Bash(awk *)
|
|
22
22
|
- Bash(curl *)
|
|
23
23
|
---
|
|
24
|
-
<!-- generated by harness_deploy.py; core=
|
|
24
|
+
<!-- generated by harness_deploy.py; core=9f66b2de1ca64c6e; overlay=none; agent=claude-code; do not edit -->
|
|
25
25
|
# harness-plan — 需求规划
|
|
26
26
|
|
|
27
27
|
## Purpose
|
|
@@ -85,7 +85,7 @@ disallowed-tools:
|
|
|
85
85
|
| 阶段 | 动作 |
|
|
86
86
|
|------|------|
|
|
87
87
|
| 0 | 用当前解释器运行 `harness_runtime.py doctor`,后续消费绝对 argv;git status;脏工作区 → baseline 隔离 + `decision`,不询问 |
|
|
88
|
-
| 0.5 |
|
|
88
|
+
| 0.5 | 确定英文 `change-name` 后,根据需求生成一次简洁的中文展示标题(建议 6~24 个可见字符,保留必要产品名),执行 `harness_context.py prepare --phase plan --executor <tool> [--change <id>] --title "<中文标题>" --json`;英文名继续作为目录与稳定标识。以其唯一 change/executionRoot 初始化 plan-run-id 与 attempt(首次为 1),用同一身份追加 `phase.start`;从第一条知识查询起保留事件证据,并在 finalizer 中复用该身份 |
|
|
89
89
|
| 1 | `harness-knowledge-query` 单次远端 query(失败记 `issue`,不建立本地索引或离线回退) |
|
|
90
90
|
| 2 | 歧义优先检查 + 复杂度分级;先确认会改变实现方向的语义歧义 |
|
|
91
91
|
| 3 | 按复杂度执行有预算的代码探索;简单修复不得扩散到无关模块 |
|
|
@@ -113,6 +113,7 @@ change-name 范围变更 → 提示重命名或记 🟡WARN(→ `reference.md`
|
|
|
113
113
|
| 规则 | 要点 |
|
|
114
114
|
|------|------|
|
|
115
115
|
| 产物路径 | 只写 `.harness/changes/<cn>/`;禁止 superpowers 输入 |
|
|
116
|
+
| Change 标题 | 首次 Plan 同时确定英文 `change-name` 与中文展示标题;英文名保持目录和机器标识不变,中文标题由 `prepare --title` 持久化,后续阶段只复用、不重新生成 |
|
|
116
117
|
| 设计审批包 | 一次 blocking user confirmation 含 worktree(读 `harness.json` `defaultWorktree`) |
|
|
117
118
|
| 阶段 8 | spec/plan/detail/scenarios/gate-policy/worktree 六项标准产物先进入 staging;仅 finalizer 校验成功后发布并写唯一 `phase.end`/log;随后 `verify` 必须确认 start/end、收据完整覆盖六项标准产物、哈希、全部任务表和非空场景清单一致,失败不得手工补终态 |
|
|
118
119
|
| Plan 结束 | **禁止**询问执行模式;只提示 `/harness-run` |
|
|
@@ -22,7 +22,7 @@ disallowed-tools:
|
|
|
22
22
|
- Bash(curl *)
|
|
23
23
|
- Bash(codegraph *)
|
|
24
24
|
---
|
|
25
|
-
<!-- generated by harness_deploy.py; core=
|
|
25
|
+
<!-- generated by harness_deploy.py; core=9f66b2de1ca64c6e; overlay=none; agent=claude-code; do not edit -->
|
|
26
26
|
# harness-review — 代码审查
|
|
27
27
|
|
|
28
28
|
## Purpose
|
|
@@ -22,7 +22,7 @@ disallowed-tools:
|
|
|
22
22
|
- Bash(curl *)
|
|
23
23
|
- Bash(codegraph *)
|
|
24
24
|
---
|
|
25
|
-
<!-- generated by harness_deploy.py; core=
|
|
25
|
+
<!-- generated by harness_deploy.py; core=9f66b2de1ca64c6e; overlay=none; agent=claude-code; do not edit -->
|
|
26
26
|
# harness-run — 需求编码
|
|
27
27
|
|
|
28
28
|
## Purpose
|
|
@@ -21,7 +21,7 @@ disallowed-tools:
|
|
|
21
21
|
- Bash(awk *)
|
|
22
22
|
- Bash(curl *)
|
|
23
23
|
---
|
|
24
|
-
<!-- generated by harness_deploy.py; core=
|
|
24
|
+
<!-- generated by harness_deploy.py; core=9f66b2de1ca64c6e; overlay=none; agent=claude-code; do not edit -->
|
|
25
25
|
# harness-submit — 最终提交(含 worktree 合并)
|
|
26
26
|
|
|
27
27
|
## Purpose
|
|
@@ -19,7 +19,7 @@ disallowed-tools:
|
|
|
19
19
|
- Bash(awk *)
|
|
20
20
|
- Bash(curl *)
|
|
21
21
|
---
|
|
22
|
-
<!-- generated by harness_deploy.py; core=
|
|
22
|
+
<!-- generated by harness_deploy.py; core=9f66b2de1ca64c6e; overlay=none; agent=claude-code; do not edit -->
|
|
23
23
|
# harness-sync
|
|
24
24
|
|
|
25
25
|
## Purpose
|
|
@@ -23,7 +23,7 @@ disallowed-tools:
|
|
|
23
23
|
- Bash(node *)
|
|
24
24
|
- Bash(codegraph *)
|
|
25
25
|
---
|
|
26
|
-
<!-- generated by harness_deploy.py; core=
|
|
26
|
+
<!-- generated by harness_deploy.py; core=9f66b2de1ca64c6e; overlay=none; agent=claude-code; do not edit -->
|
|
27
27
|
# harness-test — 测试执行
|
|
28
28
|
|
|
29
29
|
## Purpose
|
|
@@ -23,6 +23,8 @@ PHASE_GRAPH = {
|
|
|
23
23
|
"submit": (),
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
DISPLAY_TITLE_MAX_LENGTH = 80
|
|
27
|
+
|
|
26
28
|
|
|
27
29
|
def _now() -> dt.datetime:
|
|
28
30
|
return dt.datetime.now(dt.timezone.utc)
|
|
@@ -35,6 +37,41 @@ def _read_json(path: Path) -> dict[str, Any]:
|
|
|
35
37
|
return data
|
|
36
38
|
|
|
37
39
|
|
|
40
|
+
def _normalize_display_title(value: Any) -> str | None:
|
|
41
|
+
if value is None:
|
|
42
|
+
return None
|
|
43
|
+
if not isinstance(value, str):
|
|
44
|
+
raise ValueError("display title must be text")
|
|
45
|
+
title = value.strip()
|
|
46
|
+
if not title:
|
|
47
|
+
raise ValueError("display title must not be empty")
|
|
48
|
+
if len(title) > DISPLAY_TITLE_MAX_LENGTH:
|
|
49
|
+
raise ValueError(
|
|
50
|
+
f"display title exceeds {DISPLAY_TITLE_MAX_LENGTH} characters"
|
|
51
|
+
)
|
|
52
|
+
if any(ord(character) < 32 or ord(character) == 127 for character in title):
|
|
53
|
+
raise ValueError("display title contains control characters")
|
|
54
|
+
return title
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _ensure_display_title(contract_root: Path, value: Any) -> str | None:
|
|
58
|
+
path = contract_root / "meta" / "change-title.json"
|
|
59
|
+
if path.is_file():
|
|
60
|
+
payload = _read_json(path)
|
|
61
|
+
return _normalize_display_title(payload.get("displayTitle"))
|
|
62
|
+
title = _normalize_display_title(value)
|
|
63
|
+
if title is None:
|
|
64
|
+
return None
|
|
65
|
+
_write_json_atomic(
|
|
66
|
+
path,
|
|
67
|
+
{
|
|
68
|
+
"schemaVersion": 1,
|
|
69
|
+
"displayTitle": title,
|
|
70
|
+
},
|
|
71
|
+
)
|
|
72
|
+
return title
|
|
73
|
+
|
|
74
|
+
|
|
38
75
|
def _write_json_atomic(path: Path, payload: dict[str, Any]) -> None:
|
|
39
76
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
40
77
|
fd, raw = tempfile.mkstemp(prefix=f".{path.name}.", dir=str(path.parent))
|
|
@@ -243,6 +280,7 @@ def prepare_context(
|
|
|
243
280
|
phase: str,
|
|
244
281
|
executor: str,
|
|
245
282
|
change: str | None = None,
|
|
283
|
+
display_title: str | None = None,
|
|
246
284
|
ttl_seconds: int = 3600,
|
|
247
285
|
) -> dict[str, Any]:
|
|
248
286
|
project = Path(project).resolve()
|
|
@@ -265,6 +303,16 @@ def prepare_context(
|
|
|
265
303
|
contract_root, contract, state_root = _contract(project, change)
|
|
266
304
|
except (OSError, ValueError, json.JSONDecodeError) as exc:
|
|
267
305
|
return {"ok": False, "code": str(exc).split(":", 1)[0], "error": str(exc)}
|
|
306
|
+
try:
|
|
307
|
+
resolved_display_title = _ensure_display_title(
|
|
308
|
+
contract_root, display_title
|
|
309
|
+
)
|
|
310
|
+
except (OSError, ValueError, json.JSONDecodeError) as exc:
|
|
311
|
+
return {
|
|
312
|
+
"ok": False,
|
|
313
|
+
"code": "DISPLAY_TITLE_INVALID",
|
|
314
|
+
"error": str(exc),
|
|
315
|
+
}
|
|
268
316
|
lifecycle = contract.get("lifecycle")
|
|
269
317
|
if (
|
|
270
318
|
isinstance(lifecycle, dict)
|
|
@@ -343,6 +391,7 @@ def prepare_context(
|
|
|
343
391
|
"executionRoot": str(execution_root),
|
|
344
392
|
"preparedAt": now.isoformat(),
|
|
345
393
|
"receiptHash": latest.get("receiptHash") if latest else None,
|
|
394
|
+
"displayTitle": resolved_display_title,
|
|
346
395
|
},
|
|
347
396
|
)
|
|
348
397
|
next_phases = (
|
|
@@ -363,6 +412,7 @@ def prepare_context(
|
|
|
363
412
|
"latestTransition": latest,
|
|
364
413
|
"lease": lease,
|
|
365
414
|
"recovery": recovery,
|
|
415
|
+
"displayTitle": resolved_display_title,
|
|
366
416
|
}
|
|
367
417
|
|
|
368
418
|
|
|
@@ -657,6 +707,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
657
707
|
prepare.add_argument("--change")
|
|
658
708
|
prepare.add_argument("--phase", required=True)
|
|
659
709
|
prepare.add_argument("--executor", required=True)
|
|
710
|
+
prepare.add_argument("--title")
|
|
660
711
|
prepare.add_argument("--ttl-seconds", type=int, default=3600)
|
|
661
712
|
close = sub.add_parser("close")
|
|
662
713
|
close.add_argument("--json", action="store_true")
|
|
@@ -688,6 +739,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
688
739
|
phase=args.phase,
|
|
689
740
|
executor=args.executor,
|
|
690
741
|
change=args.change,
|
|
742
|
+
display_title=args.title,
|
|
691
743
|
ttl_seconds=args.ttl_seconds,
|
|
692
744
|
)
|
|
693
745
|
elif args.command == "close":
|
|
@@ -33,6 +33,28 @@ if str(SCRIPTS_DIR) not in sys.path:
|
|
|
33
33
|
import harness_paths # noqa: E402
|
|
34
34
|
|
|
35
35
|
|
|
36
|
+
def _project_root_for_change(change_dir: Path) -> Path | None:
|
|
37
|
+
resolved = change_dir.resolve()
|
|
38
|
+
for candidate in (resolved, *resolved.parents):
|
|
39
|
+
if candidate.name == "changes" and candidate.parent.name == ".harness":
|
|
40
|
+
return candidate.parent.parent
|
|
41
|
+
return None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _nudge_remote_sync(change_dir: Path) -> None:
|
|
45
|
+
"""Best-effort wake-up after the event append has been flushed to disk."""
|
|
46
|
+
project_root = _project_root_for_change(change_dir)
|
|
47
|
+
if project_root is None:
|
|
48
|
+
return
|
|
49
|
+
try:
|
|
50
|
+
from harness_events_sync import schedule_events_sync
|
|
51
|
+
|
|
52
|
+
schedule_events_sync(project_root, change_dir)
|
|
53
|
+
except Exception:
|
|
54
|
+
# Local event durability is authoritative; remote outages never roll it back.
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
|
|
36
58
|
if hasattr(sys.stdout, "reconfigure"):
|
|
37
59
|
sys.stdout.reconfigure(encoding="utf-8")
|
|
38
60
|
if hasattr(sys.stderr, "reconfigure"):
|
|
@@ -623,6 +645,7 @@ def append_event(
|
|
|
623
645
|
"event": event,
|
|
624
646
|
"autoSealed": result.get("autoSealed") or [],
|
|
625
647
|
}
|
|
648
|
+
_nudge_remote_sync(change_dir)
|
|
626
649
|
return {
|
|
627
650
|
"ok": True,
|
|
628
651
|
"event": event,
|
|
@@ -748,6 +771,7 @@ def batch_append_events(
|
|
|
748
771
|
atomic_append_line(
|
|
749
772
|
events_path_obj, json.dumps(event, ensure_ascii=False, separators=(",", ":"))
|
|
750
773
|
)
|
|
774
|
+
_nudge_remote_sync(change_dir)
|
|
751
775
|
return {
|
|
752
776
|
"ok": True,
|
|
753
777
|
"action": "batch-append",
|
|
@@ -1796,6 +1820,8 @@ def cmd_append(args: argparse.Namespace) -> int:
|
|
|
1796
1820
|
error_code=error_code,
|
|
1797
1821
|
)
|
|
1798
1822
|
|
|
1823
|
+
_nudge_remote_sync(change_dir)
|
|
1824
|
+
|
|
1799
1825
|
# §6.1: phase.end append(或写路径产生了 auto-seal)-> 追加成功后执行一次
|
|
1800
1826
|
# render(从完整 events 重建 log)。普通 command/issue 等 append 不渲染
|
|
1801
1827
|
# (O(1));显式 `render` 子命令随时重建。
|