@hunter-harness/workflow-harness 0.2.48 → 0.2.50
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 +9 -1
- package/harness/bundles/general/claude-code/harness-codebase-map/SKILL.md +6 -1
- package/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +21 -4
- package/harness/bundles/general/claude-code/harness-knowledge-query/SKILL.md +17 -6
- package/harness/bundles/general/claude-code/harness-plan/SKILL.md +6 -1
- package/harness/bundles/general/claude-code/harness-review/SKILL.md +6 -1
- package/harness/bundles/general/claude-code/harness-run/SKILL.md +7 -2
- package/harness/bundles/general/claude-code/harness-submit/SKILL.md +6 -1
- package/harness/bundles/general/claude-code/harness-sync/SKILL.md +6 -1
- package/harness/bundles/general/claude-code/harness-test/SKILL.md +6 -1
- package/harness/bundles/general/claude-code/scripts/harness_archive.py +31 -1
- package/harness/bundles/general/claude-code/scripts/harness_events_sync.py +90 -12
- package/harness/bundles/general/claude-code/scripts/harness_gate.py +17 -0
- package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
- package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +9 -1
- package/harness/bundles/general/codebuddy/harness-codebase-map/SKILL.md +6 -1
- package/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +21 -4
- package/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +17 -6
- package/harness/bundles/general/codebuddy/harness-plan/SKILL.md +6 -1
- package/harness/bundles/general/codebuddy/harness-review/SKILL.md +6 -1
- package/harness/bundles/general/codebuddy/harness-run/SKILL.md +7 -2
- package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +6 -1
- package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +6 -1
- package/harness/bundles/general/codebuddy/harness-test/SKILL.md +6 -1
- package/harness/bundles/general/codebuddy/scripts/harness_archive.py +31 -1
- package/harness/bundles/general/codebuddy/scripts/harness_events_sync.py +90 -12
- package/harness/bundles/general/codebuddy/scripts/harness_gate.py +17 -0
- package/harness/bundles/general/codex/.harness-build.json +1 -1
- package/harness/bundles/general/codex/harness-archive/SKILL.md +9 -1
- package/harness/bundles/general/codex/harness-codebase-map/SKILL.md +6 -1
- package/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +21 -4
- package/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +17 -6
- package/harness/bundles/general/codex/harness-plan/SKILL.md +6 -1
- package/harness/bundles/general/codex/harness-review/SKILL.md +6 -1
- package/harness/bundles/general/codex/harness-run/SKILL.md +7 -2
- package/harness/bundles/general/codex/harness-submit/SKILL.md +6 -1
- package/harness/bundles/general/codex/harness-sync/SKILL.md +6 -1
- package/harness/bundles/general/codex/harness-test/SKILL.md +6 -1
- package/harness/bundles/general/codex/scripts/harness_archive.py +31 -1
- package/harness/bundles/general/codex/scripts/harness_events_sync.py +90 -12
- package/harness/bundles/general/codex/scripts/harness_gate.py +17 -0
- package/harness/bundles/general/cursor/.harness-build.json +1 -1
- package/harness/bundles/general/cursor/harness-archive/SKILL.md +9 -1
- package/harness/bundles/general/cursor/harness-codebase-map/SKILL.md +6 -1
- package/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +21 -4
- package/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +17 -6
- package/harness/bundles/general/cursor/harness-plan/SKILL.md +6 -1
- package/harness/bundles/general/cursor/harness-review/SKILL.md +6 -1
- package/harness/bundles/general/cursor/harness-run/SKILL.md +7 -2
- package/harness/bundles/general/cursor/harness-submit/SKILL.md +6 -1
- package/harness/bundles/general/cursor/harness-sync/SKILL.md +6 -1
- package/harness/bundles/general/cursor/harness-test/SKILL.md +6 -1
- package/harness/bundles/general/cursor/scripts/harness_archive.py +31 -1
- package/harness/bundles/general/cursor/scripts/harness_events_sync.py +90 -12
- package/harness/bundles/general/cursor/scripts/harness_gate.py +17 -0
- package/harness/bundles/java/claude-code/.harness-build.json +1 -1
- package/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +6 -1
- package/harness/bundles/java/claude-code/harness-archive/SKILL.md +9 -1
- package/harness/bundles/java/claude-code/harness-codebase-map/SKILL.md +6 -1
- package/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +21 -4
- package/harness/bundles/java/claude-code/harness-knowledge-query/SKILL.md +17 -6
- package/harness/bundles/java/claude-code/harness-package/SKILL.md +6 -1
- package/harness/bundles/java/claude-code/harness-plan/SKILL.md +6 -1
- package/harness/bundles/java/claude-code/harness-review/SKILL.md +6 -1
- package/harness/bundles/java/claude-code/harness-run/SKILL.md +7 -2
- package/harness/bundles/java/claude-code/harness-submit/SKILL.md +6 -1
- package/harness/bundles/java/claude-code/harness-sync/SKILL.md +6 -1
- package/harness/bundles/java/claude-code/harness-test/SKILL.md +6 -1
- package/harness/bundles/java/claude-code/scripts/harness_archive.py +31 -1
- package/harness/bundles/java/claude-code/scripts/harness_events_sync.py +90 -12
- package/harness/bundles/java/claude-code/scripts/harness_gate.py +17 -0
- package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
- package/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +6 -1
- package/harness/bundles/java/codebuddy/harness-archive/SKILL.md +9 -1
- package/harness/bundles/java/codebuddy/harness-codebase-map/SKILL.md +6 -1
- package/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +21 -4
- package/harness/bundles/java/codebuddy/harness-knowledge-query/SKILL.md +17 -6
- package/harness/bundles/java/codebuddy/harness-package/SKILL.md +6 -1
- package/harness/bundles/java/codebuddy/harness-plan/SKILL.md +6 -1
- package/harness/bundles/java/codebuddy/harness-review/SKILL.md +6 -1
- package/harness/bundles/java/codebuddy/harness-run/SKILL.md +7 -2
- package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +6 -1
- package/harness/bundles/java/codebuddy/harness-sync/SKILL.md +6 -1
- package/harness/bundles/java/codebuddy/harness-test/SKILL.md +6 -1
- package/harness/bundles/java/codebuddy/scripts/harness_archive.py +31 -1
- package/harness/bundles/java/codebuddy/scripts/harness_events_sync.py +90 -12
- package/harness/bundles/java/codebuddy/scripts/harness_gate.py +17 -0
- package/harness/bundles/java/codex/.harness-build.json +1 -1
- package/harness/bundles/java/codex/harness-apidoc/SKILL.md +6 -1
- package/harness/bundles/java/codex/harness-archive/SKILL.md +9 -1
- package/harness/bundles/java/codex/harness-codebase-map/SKILL.md +6 -1
- package/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +21 -4
- package/harness/bundles/java/codex/harness-knowledge-query/SKILL.md +17 -6
- package/harness/bundles/java/codex/harness-package/SKILL.md +6 -1
- package/harness/bundles/java/codex/harness-plan/SKILL.md +6 -1
- package/harness/bundles/java/codex/harness-review/SKILL.md +6 -1
- package/harness/bundles/java/codex/harness-run/SKILL.md +7 -2
- package/harness/bundles/java/codex/harness-submit/SKILL.md +6 -1
- package/harness/bundles/java/codex/harness-sync/SKILL.md +6 -1
- package/harness/bundles/java/codex/harness-test/SKILL.md +6 -1
- package/harness/bundles/java/codex/scripts/harness_archive.py +31 -1
- package/harness/bundles/java/codex/scripts/harness_events_sync.py +90 -12
- package/harness/bundles/java/codex/scripts/harness_gate.py +17 -0
- package/harness/bundles/java/cursor/.harness-build.json +1 -1
- package/harness/bundles/java/cursor/harness-apidoc/SKILL.md +6 -1
- package/harness/bundles/java/cursor/harness-archive/SKILL.md +9 -1
- package/harness/bundles/java/cursor/harness-codebase-map/SKILL.md +6 -1
- package/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +21 -4
- package/harness/bundles/java/cursor/harness-knowledge-query/SKILL.md +17 -6
- package/harness/bundles/java/cursor/harness-package/SKILL.md +6 -1
- package/harness/bundles/java/cursor/harness-plan/SKILL.md +6 -1
- package/harness/bundles/java/cursor/harness-review/SKILL.md +6 -1
- package/harness/bundles/java/cursor/harness-run/SKILL.md +7 -2
- package/harness/bundles/java/cursor/harness-submit/SKILL.md +6 -1
- package/harness/bundles/java/cursor/harness-sync/SKILL.md +6 -1
- package/harness/bundles/java/cursor/harness-test/SKILL.md +6 -1
- package/harness/bundles/java/cursor/scripts/harness_archive.py +31 -1
- package/harness/bundles/java/cursor/scripts/harness_events_sync.py +90 -12
- package/harness/bundles/java/cursor/scripts/harness_gate.py +17 -0
- 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=6b900d319d6b6d77; overlay=none; agent=claude-code; do not edit -->
|
|
25
25
|
# harness-archive — 变更归档
|
|
26
26
|
|
|
27
27
|
## Purpose
|
|
@@ -119,6 +119,9 @@ disallowed-tools:
|
|
|
119
119
|
1. 运行 `python <skills-root>/scripts/harness_archive.py status --change-dir ".harness/changes/<change-name>" --intent release-candidate --json` 前置检查。无 CI 项目若已有完整全量 ledger,先运行 `certify-local`;若用户明确只封存事实,则 status/finalize 均使用 `--intent record-only`。
|
|
120
120
|
2. `meta/archive-meta.md` **由 `harness_archive.py finalize` 自动生成**(与 summary-data `finalStatus` 同源);**禁止 agent 手写**该文件,手写视为数据丢失。维护者结论写入 events(decision/issue)即可,finalize 会汇总到 summary / archive-meta。
|
|
121
121
|
3. 运行 `python <skills-root>/scripts/harness_archive.py finalize --change-dir ".harness/changes/<change-name>" --archive-root ".harness/archive" --intent <release-candidate|record-only> --json`;读 JSON(cleanup、事件、移动、collect、render、validate、manifest 比对、archive-meta)。finalize 内部负责且仅负责一次 `phase.start` / `phase.end`,调用者不得重复追加。**finalize 不再同步执行知识维护**(§8.2):它写一个 `pending` maintenance-outbox 项即返回,`knowledgeMaintenance=QUEUED`;写 outbox 失败时 `NOT_QUEUED`(warning,不回滚 archive,总状态 CONDITIONAL)。后续由 `harness-sync` / `harness_knowledge.py maintain` 异步推进 outbox。**finalize 失败或 validate 报错时不删除原目录**。
|
|
122
|
+
- **平台钩子(best-effort,不阻断归档)**:
|
|
123
|
+
1. **归档推送(C1)**:有远程凭据时自动 `hunter-harness push` 上传核心+可选辅助档(spec/plans/summary-data/knowledge + `reports/review/*`、`reports/test/*`、`meta/archive-meta.md`、`meta/change-context.json`)。
|
|
124
|
+
2. **监控终态(C3)**:auto-push 之后自动 `events-sync`,用归档前 change 路径派生的 `run_id` + 原 `change_key` 上报;平台依据 `phase.end`/`archive` 将 run 置为 succeeded/failed(含 `ended_at`)。失败只记 warning。
|
|
122
125
|
|
|
123
126
|
- **Read `reference.md`** — finalize 输出字段、archive-meta 格式、CONDITIONAL_OK 规则
|
|
124
127
|
- **Read `templates/summary-data-template.json`** — summary-data 数据结构
|
|
@@ -135,6 +138,11 @@ disallowed-tools:
|
|
|
135
138
|
- 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
|
|
136
139
|
- 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
|
|
137
140
|
- 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
|
|
141
|
+
|
|
142
|
+
## 生成内容语言约定
|
|
143
|
+
|
|
144
|
+
- sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
|
|
145
|
+
- 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
|
|
138
146
|
> 片段:p0-trust
|
|
139
147
|
|
|
140
148
|
## 关键规则(硬门禁速查)
|
|
@@ -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=6b900d319d6b6d77; overlay=none; agent=claude-code; do not edit -->
|
|
24
24
|
# harness-codebase-map — 代码库地图
|
|
25
25
|
|
|
26
26
|
## Purpose
|
|
@@ -73,6 +73,11 @@ disallowed-tools:
|
|
|
73
73
|
- 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
|
|
74
74
|
- 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
|
|
75
75
|
- 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
|
|
76
|
+
|
|
77
|
+
## 生成内容语言约定
|
|
78
|
+
|
|
79
|
+
- sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
|
|
80
|
+
- 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
|
|
76
81
|
> 片段:p0-trust · map 额外:文件存在/行数/hash 为证据
|
|
77
82
|
|
|
78
83
|
## 关键规则
|
|
@@ -20,12 +20,21 @@ 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=6b900d319d6b6d77; overlay=none; agent=claude-code; do not edit -->
|
|
24
24
|
# harness-knowledge-ingest
|
|
25
25
|
|
|
26
|
-
从 `.harness/archive/**/reports/final/summary-data.json`
|
|
26
|
+
从 `.harness/archive/**/reports/final/summary-data.json` **本地抽取**知识条目,产物随归档 push 上传;**裁决与投影以平台为准**(远程优先)。本地 SQLite / Agent judge 仅作离线或未连接平台时的回退。
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
> 语言约定:知识条目的 title / summary / body 及一切生成文档优先使用中文(标识符与字段名保持原文)。详见 [[../shared/p0-trust.md|p0-trust]] 的"生成内容语言约定"。
|
|
29
|
+
|
|
30
|
+
## 远程优先模式(平台连接后)
|
|
31
|
+
|
|
32
|
+
1. **本地职责**:抽取 candidate 条目 JSON,写入 `.harness/knowledge/entries/**`(及可选本地 index)。
|
|
33
|
+
2. **上传**:条目随 `hunter-harness push` / 归档 finalize 的 auto-push 上传(见归档分级清单:核心含 `knowledge/entries/active|candidate`)。
|
|
34
|
+
3. **平台职责**:服务端 ingest 后自动裁决 status(promote→active 等启发式),并投影到语义知识库;`deprecate` 粘性不被后续 push 覆盖。
|
|
35
|
+
4. **本地 judge / SQLite**:无平台凭据或离线时仍可用;已连接平台时**不要**把本地裁决当作多人共享真源。
|
|
36
|
+
|
|
37
|
+
未连接平台时,行为退回本地离线 MVP:`candidate` / `stale` / `active` / `superseded` / `conflicted` + SQLite FTS。按新需求查询历史由独立的 `harness-knowledge-query` 负责(默认远程语义搜索,本地索引离线回退)。
|
|
29
38
|
|
|
30
39
|
## Triggers
|
|
31
40
|
|
|
@@ -45,13 +54,16 @@ disallowed-tools:
|
|
|
45
54
|
- `.harness/knowledge/index.json`
|
|
46
55
|
- `.harness/codebase/map-summary.md`(如存在)
|
|
47
56
|
- design.md
|
|
57
|
+
- (可选)`.harness/credentials.local.yaml` — 已连接平台时走远程裁决
|
|
48
58
|
|
|
49
59
|
## Purpose
|
|
50
60
|
|
|
51
61
|
解决两个问题:
|
|
52
62
|
|
|
53
63
|
1. **整理知识库内容**:把归档里的 `businessGoal`、`changedFiles`、`maintenanceNotes`、`knownRisks`、`manualActions`、`verification`、`reviewSummary` 抽成知识条目。
|
|
54
|
-
2.
|
|
64
|
+
2. **维护知识生命周期**:
|
|
65
|
+
- **远程优先**:平台 ingest 后裁决并投影;本地只需保证条目 JSON 可上传。
|
|
66
|
+
- **离线回退**:检查索引是否过期,保留 active;高置信 candidate 由 `autoPromote` 自动提升;其余由 **Agent judge** 闭环裁决。
|
|
55
67
|
|
|
56
68
|
## Outputs
|
|
57
69
|
|
|
@@ -251,6 +263,11 @@ powershell.exe -Command "python '<skill-dir>\scripts\harness_knowledge.py' sync
|
|
|
251
263
|
- 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
|
|
252
264
|
- 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
|
|
253
265
|
- 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
|
|
266
|
+
|
|
267
|
+
## 生成内容语言约定
|
|
268
|
+
|
|
269
|
+
- sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
|
|
270
|
+
- 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
|
|
254
271
|
> 片段:p0-trust · ingest/sync 须绑定 `upToDate`/产物路径证据
|
|
255
272
|
|
|
256
273
|
## Output Format
|
|
@@ -20,14 +20,18 @@ 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=6b900d319d6b6d77; overlay=none; agent=claude-code; do not edit -->
|
|
24
24
|
# harness-knowledge-query
|
|
25
25
|
|
|
26
26
|
并行 change 中查询必须传 `--change <change-id>`;成功后以该 change 的 `meta/knowledge-context.json` 为稳定指针。全局 `context-packs/latest.json` 仅向后兼容,不得用于判断多个 active change 的上下文归属。
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
根据用户的新需求或排查问题检索历史需求、决策、实现、风险和测试证据,并生成 AI 可读的 context pack。
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
## 远程优先 / 离线回退
|
|
31
|
+
|
|
32
|
+
1. **默认(已 `hunter-harness connect`)**:优先查询平台语义知识库(与 ingest 上传 + 服务端裁决结果一致);多机/多人共享同一裁决结果。
|
|
33
|
+
2. **离线回退**:无凭据、网络失败或平台不可用时,回退到本地 `.harness/knowledge`(SQLite FTS / 条目文件)。
|
|
34
|
+
3. 此 skill 只负责查询和使用知识。整理与上传由 `harness-knowledge-ingest` + push/归档负责;**不要**在已连接平台时把本地 promote 当作共享真源。
|
|
31
35
|
|
|
32
36
|
## Triggers
|
|
33
37
|
|
|
@@ -42,9 +46,9 @@ disallowed-tools:
|
|
|
42
46
|
|
|
43
47
|
## Automatic Use
|
|
44
48
|
|
|
45
|
-
|
|
49
|
+
当用户提出新功能、改造、排查、设计方案、继续历史任务,且项目存在平台连接或 `.harness/archive` / `.harness/knowledge` 时,AI 应主动运行本 skill,不需要等用户提醒。
|
|
46
50
|
|
|
47
|
-
不在 query 前单独执行 sync。`query` 命令内部执行一次 ensure-current
|
|
51
|
+
不在 query 前单独执行 sync。`query` 命令内部执行一次 ensure-current:建立一次当前快照,索引新鲜时无操作,过期或缺失时只构建一次,然后在同一调用内完成查询(离线路径)。
|
|
48
52
|
|
|
49
53
|
## Commands
|
|
50
54
|
|
|
@@ -56,6 +60,8 @@ disallowed-tools:
|
|
|
56
60
|
powershell.exe -Command "python '<ingest-skill-dir>\scripts\harness_knowledge.py' query --project '<project-root>' --query '<用户需求原文>'"
|
|
57
61
|
```
|
|
58
62
|
|
|
63
|
+
已连接平台时,优先使用平台语义搜索(CLI/`hunter-harness` 知识查询路径,若可用);上述本地命令作为离线回退。
|
|
64
|
+
|
|
59
65
|
### Query with metadata filters
|
|
60
66
|
|
|
61
67
|
```powershell
|
|
@@ -65,7 +71,7 @@ powershell.exe -Command "python '<ingest-skill-dir>\scripts\harness_knowledge.py
|
|
|
65
71
|
可重复使用:
|
|
66
72
|
|
|
67
73
|
- `--file <path>`:只返回关联到指定文件的知识。
|
|
68
|
-
- `--status active|candidate|stale|superseded|conflicted
|
|
74
|
+
- `--status active|candidate|stale|superseded|conflicted`:按生命周期过滤(远程路径通常已排除 deprecated)。
|
|
69
75
|
- `--type requirement|decision|implementation|risk|test-evidence|pitfall|api-contract`:按知识类型过滤。
|
|
70
76
|
- `--limit <n>`:限制返回数量。
|
|
71
77
|
|
|
@@ -128,6 +134,11 @@ powershell.exe -Command "python '<ingest-skill-dir>\scripts\harness_knowledge.py
|
|
|
128
134
|
- 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
|
|
129
135
|
- 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
|
|
130
136
|
- 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
|
|
137
|
+
|
|
138
|
+
## 生成内容语言约定
|
|
139
|
+
|
|
140
|
+
- sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
|
|
141
|
+
- 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
|
|
131
142
|
> 片段:p0-trust · query 成功须含 `contextPack`/`planInput.kind` 与 `latest.json` 写入
|
|
132
143
|
|
|
133
144
|
## Output Format
|
|
@@ -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=6b900d319d6b6d77; overlay=none; agent=claude-code; do not edit -->
|
|
25
25
|
# harness-plan — 需求规划
|
|
26
26
|
|
|
27
27
|
## Purpose
|
|
@@ -101,6 +101,11 @@ change-name 范围变更 → 提示重命名或记 🟡WARN(→ `reference.md`
|
|
|
101
101
|
- 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
|
|
102
102
|
- 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
|
|
103
103
|
- 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
|
|
104
|
+
|
|
105
|
+
## 生成内容语言约定
|
|
106
|
+
|
|
107
|
+
- sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
|
|
108
|
+
- 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
|
|
104
109
|
> 片段:p0-trust
|
|
105
110
|
|
|
106
111
|
## 关键规则
|
|
@@ -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=6b900d319d6b6d77; overlay=none; agent=claude-code; do not edit -->
|
|
26
26
|
# harness-review — 代码审查
|
|
27
27
|
|
|
28
28
|
## Purpose
|
|
@@ -125,6 +125,11 @@ review:
|
|
|
125
125
|
- 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
|
|
126
126
|
- 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
|
|
127
127
|
- 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
|
|
128
|
+
|
|
129
|
+
## 生成内容语言约定
|
|
130
|
+
|
|
131
|
+
- sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
|
|
132
|
+
- 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
|
|
128
133
|
> 片段:p0-trust
|
|
129
134
|
|
|
130
135
|
## 关键规则(硬门禁速查)
|
|
@@ -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=6b900d319d6b6d77; overlay=none; agent=claude-code; do not edit -->
|
|
26
26
|
# harness-run — 需求编码
|
|
27
27
|
|
|
28
28
|
## Purpose
|
|
@@ -78,7 +78,7 @@ disallowed-tools:
|
|
|
78
78
|
|
|
79
79
|
## Workflow 概要
|
|
80
80
|
|
|
81
|
-
0. 加载上下文:先 `harness_context.py prepare --phase run --executor <tool> [--change <id>] --json`,以返回的唯一 change/executionRoot/transition receipt 为准(多 active 缺参 → `ACTIVE_CHANGE_AMBIGUOUS`,禁止按 mtime 猜测);再 **`harness_context.py begin --phase run --change <id> --executor <tool> --json`** 校验 Plan artifact/hash/HEAD,读 spec/plan/detail/scenarios/ledger/run-task-status/worktree;`--fixback` 读 fixback → **`harness_gate.py begin --phase run --change <id>`**(claim + phase.start + identity;禁止手工 Write `events.ndjson` / 手工 `phase.end
|
|
81
|
+
0. 加载上下文:先 `harness_context.py prepare --phase run --executor <tool> [--change <id>] --json`,以返回的唯一 change/executionRoot/transition receipt 为准(多 active 缺参 → `ACTIVE_CHANGE_AMBIGUOUS`,禁止按 mtime 猜测);再 **`harness_context.py begin --phase run --change <id> --executor <tool> --json`** 校验 Plan artifact/hash/HEAD,读 spec/plan/detail/scenarios/ledger/run-task-status/worktree;`--fixback` 读 fixback → **`harness_gate.py begin --phase run --change <id>`**(claim + phase.start + identity;禁止手工 Write `events.ndjson` / 手工 `phase.end`)。**C3 钩子**:`harness_gate.py begin` 在已连接平台时会 best-effort 调用 events-sync(注册 run / `running`);失败只告警,不阻断 begin。
|
|
82
82
|
0.5. **测试基础设施探测**(先写 `CHECKING`,四项证据齐备后再结论)→ `reference.md` Step 0.5;进入 TDD 前执行 `harness_test_guard.py begin --project . --change-dir ".harness/changes/<cn>" --json`
|
|
83
83
|
1. **变更簇 TDD** — `protocols.md` `run-tdd-protocol`;批量 RED/GREEN;按需 `change-cluster-review-protocol`(高风险 + reviewer 预检可用)
|
|
84
84
|
2. 构建验证 + **仅**通过 `harness_ledger.py record` 写 ledger(禁止 Write/Edit `verification-ledger.json`);`diff-hash --change-dir` 纳入 ignored tests → `reference.md` Step 2c
|
|
@@ -94,6 +94,11 @@ disallowed-tools:
|
|
|
94
94
|
- 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
|
|
95
95
|
- 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
|
|
96
96
|
- 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
|
|
97
|
+
|
|
98
|
+
## 生成内容语言约定
|
|
99
|
+
|
|
100
|
+
- sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
|
|
101
|
+
- 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
|
|
97
102
|
> 片段:p0-trust
|
|
98
103
|
|
|
99
104
|
## 关键规则(硬门禁速查)
|
|
@@ -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=6b900d319d6b6d77; overlay=none; agent=claude-code; do not edit -->
|
|
25
25
|
# harness-submit — 最终提交(含 worktree 合并)
|
|
26
26
|
|
|
27
27
|
## Purpose
|
|
@@ -112,6 +112,11 @@ M7. **ledger + 收尾** — 经 `harness_ledger.py record` 写入 `mergeFinalHas
|
|
|
112
112
|
- 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
|
|
113
113
|
- 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
|
|
114
114
|
- 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
|
|
115
|
+
|
|
116
|
+
## 生成内容语言约定
|
|
117
|
+
|
|
118
|
+
- sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
|
|
119
|
+
- 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
|
|
115
120
|
> 片段:p0-trust
|
|
116
121
|
|
|
117
122
|
## 关键规则(硬门禁速查)
|
|
@@ -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=6b900d319d6b6d77; overlay=none; agent=claude-code; do not edit -->
|
|
23
23
|
# harness-sync
|
|
24
24
|
|
|
25
25
|
## Purpose
|
|
@@ -71,6 +71,11 @@ JSON 报告回显到对话。
|
|
|
71
71
|
- 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
|
|
72
72
|
- 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
|
|
73
73
|
- 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
|
|
74
|
+
|
|
75
|
+
## 生成内容语言约定
|
|
76
|
+
|
|
77
|
+
- sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
|
|
78
|
+
- 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
|
|
74
79
|
> 片段:p0-trust
|
|
75
80
|
|
|
76
81
|
## 执行日志
|
|
@@ -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=6b900d319d6b6d77; overlay=none; agent=claude-code; do not edit -->
|
|
27
27
|
# harness-test — 测试执行
|
|
28
28
|
|
|
29
29
|
## Purpose
|
|
@@ -142,6 +142,11 @@ Runner 强制同项目单实例、低调度优先级、逐命令超时、正常
|
|
|
142
142
|
- 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
|
|
143
143
|
- 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
|
|
144
144
|
- 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
|
|
145
|
+
|
|
146
|
+
## 生成内容语言约定
|
|
147
|
+
|
|
148
|
+
- sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
|
|
149
|
+
- 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
|
|
145
150
|
> 片段:p0-trust
|
|
146
151
|
|
|
147
152
|
## 关键规则(硬门禁速查)
|
|
@@ -70,6 +70,7 @@ if str(SCRIPTS_DIR) not in sys.path:
|
|
|
70
70
|
sys.path.insert(0, str(SCRIPTS_DIR))
|
|
71
71
|
|
|
72
72
|
import harness_events as he # noqa: E402
|
|
73
|
+
import harness_events_sync as hes # noqa: E402
|
|
73
74
|
import harness_efficiency as heff # noqa: E402
|
|
74
75
|
import harness_gate as hgate # noqa: E402
|
|
75
76
|
import harness_ledger as hl # noqa: E402
|
|
@@ -8284,6 +8285,9 @@ def cmd_finalize(
|
|
|
8284
8285
|
|
|
8285
8286
|
# Publish only after every validator passes. The archive path is never used
|
|
8286
8287
|
# as mutable staging, so a failed attempt cannot poison the next retry.
|
|
8288
|
+
# Capture monitoring run_id from the live change path before it is deleted
|
|
8289
|
+
# so archive finalize can report terminal status on the same platform run.
|
|
8290
|
+
monitoring_run_id = hes.run_id_for(original_change_dir)
|
|
8287
8291
|
try:
|
|
8288
8292
|
archive_root.mkdir(parents=True, exist_ok=True)
|
|
8289
8293
|
shutil.move(str(operation_temp_dir), str(archive_dir))
|
|
@@ -8368,6 +8372,23 @@ def cmd_finalize(
|
|
|
8368
8372
|
if push_result.get("warning"):
|
|
8369
8373
|
warnings.append(str(push_result["warning"]))
|
|
8370
8374
|
|
|
8375
|
+
# C3: best-effort terminal events-sync so platform run ends (succeeded/failed).
|
|
8376
|
+
# Use the pre-delete change-path run_id + original change_key for continuity.
|
|
8377
|
+
try:
|
|
8378
|
+
monitor = hes.auto_events_sync(
|
|
8379
|
+
project_root,
|
|
8380
|
+
archive_dir,
|
|
8381
|
+
run_id=monitoring_run_id,
|
|
8382
|
+
change_key=change_name,
|
|
8383
|
+
)
|
|
8384
|
+
payload["steps"]["platform_events_sync"] = monitor
|
|
8385
|
+
if monitor.get("warning"):
|
|
8386
|
+
warnings.append(str(monitor["warning"]))
|
|
8387
|
+
except Exception as exc: # noqa: BLE001 — never roll back archive
|
|
8388
|
+
warn = f"events-sync terminal hook failed: {exc}"
|
|
8389
|
+
warnings.append(warn)
|
|
8390
|
+
payload["steps"]["platform_events_sync"] = {"ok": False, "warning": warn}
|
|
8391
|
+
|
|
8371
8392
|
payload["ok"] = True
|
|
8372
8393
|
payload["finalStatus"] = "OK"
|
|
8373
8394
|
payload["warnings"] = warnings
|
|
@@ -8387,7 +8408,7 @@ def _remote_credentials_configured(project_root: Path) -> bool:
|
|
|
8387
8408
|
|
|
8388
8409
|
|
|
8389
8410
|
def collect_archive_core_paths(project_root: Path, archive_dir: Path) -> list[str]:
|
|
8390
|
-
"""Relative paths for the
|
|
8411
|
+
"""Relative paths for the archive push allowlist (core + optional supporting)."""
|
|
8391
8412
|
root = project_root.resolve()
|
|
8392
8413
|
archive = archive_dir.resolve()
|
|
8393
8414
|
paths: list[str] = []
|
|
@@ -8403,6 +8424,15 @@ def collect_archive_core_paths(project_root: Path, archive_dir: Path) -> list[st
|
|
|
8403
8424
|
for path in sorted(base.rglob("*")):
|
|
8404
8425
|
if path.is_file():
|
|
8405
8426
|
paths.append(path.relative_to(root).as_posix())
|
|
8427
|
+
# C1 optional supporting files.
|
|
8428
|
+
for folder in (("reports", "review"), ("reports", "test")):
|
|
8429
|
+
base = archive.joinpath(*folder)
|
|
8430
|
+
if base.is_dir():
|
|
8431
|
+
for path in sorted(base.rglob("*")):
|
|
8432
|
+
if path.is_file():
|
|
8433
|
+
paths.append(path.relative_to(root).as_posix())
|
|
8434
|
+
add_if_exists(archive / "meta" / "archive-meta.md")
|
|
8435
|
+
add_if_exists(archive / "meta" / "change-context.json")
|
|
8406
8436
|
knowledge = root / ".harness" / "knowledge" / "entries"
|
|
8407
8437
|
for status in ("active", "candidate"):
|
|
8408
8438
|
folder = knowledge / status
|
|
@@ -119,12 +119,19 @@ def post_json(endpoint: dict[str, str], path: str, body: dict[str, Any]) -> dict
|
|
|
119
119
|
return json.loads(response.read().decode("utf-8"))
|
|
120
120
|
|
|
121
121
|
|
|
122
|
-
def sync_change(
|
|
122
|
+
def sync_change(
|
|
123
|
+
project: Path,
|
|
124
|
+
change_dir: Path,
|
|
125
|
+
*,
|
|
126
|
+
heartbeat_only: bool = False,
|
|
127
|
+
run_id: str | None = None,
|
|
128
|
+
change_key: str | None = None,
|
|
129
|
+
) -> dict[str, Any]:
|
|
123
130
|
endpoint = load_endpoint(project)
|
|
124
131
|
if endpoint is None:
|
|
125
132
|
return {"ok": True, "skipped": True, "reason": "remote credentials not configured"}
|
|
126
|
-
|
|
127
|
-
rid = run_id_for(change_dir)
|
|
133
|
+
resolved_key = change_key or change_dir.name
|
|
134
|
+
rid = run_id or run_id_for(change_dir)
|
|
128
135
|
project_id = endpoint["project_id"]
|
|
129
136
|
|
|
130
137
|
# Always heartbeat so the console can separate connection vs run status.
|
|
@@ -138,20 +145,26 @@ def sync_change(project: Path, change_dir: Path, *, heartbeat_only: bool = False
|
|
|
138
145
|
{
|
|
139
146
|
"protocol_version": "hunter-progress-sync/v1",
|
|
140
147
|
"run_id": rid,
|
|
141
|
-
"change_key":
|
|
148
|
+
"change_key": resolved_key,
|
|
142
149
|
"client_time": client_time,
|
|
143
|
-
"title":
|
|
150
|
+
"title": resolved_key,
|
|
144
151
|
},
|
|
145
152
|
)
|
|
146
153
|
except (urllib.error.URLError, TimeoutError, OSError, json.JSONDecodeError) as exc:
|
|
147
154
|
return {"ok": False, "error": f"heartbeat failed: {exc}", "run_id": rid}
|
|
148
155
|
|
|
149
156
|
if heartbeat_only:
|
|
150
|
-
return {"ok": True, "heartbeat": True, "run_id": rid}
|
|
157
|
+
return {"ok": True, "heartbeat": True, "run_id": rid, "change_key": resolved_key}
|
|
151
158
|
|
|
152
159
|
events_file = change_dir / "events.ndjson"
|
|
153
160
|
if not events_file.is_file():
|
|
154
|
-
return {
|
|
161
|
+
return {
|
|
162
|
+
"ok": True,
|
|
163
|
+
"run_id": rid,
|
|
164
|
+
"change_key": resolved_key,
|
|
165
|
+
"uploaded": 0,
|
|
166
|
+
"reason": "no events.ndjson",
|
|
167
|
+
}
|
|
155
168
|
|
|
156
169
|
lines = events_file.read_text(encoding="utf-8").splitlines()
|
|
157
170
|
acked = load_cursor(change_dir)
|
|
@@ -167,7 +180,7 @@ def sync_change(project: Path, change_dir: Path, *, heartbeat_only: bool = False
|
|
|
167
180
|
continue
|
|
168
181
|
if not isinstance(event, dict):
|
|
169
182
|
continue
|
|
170
|
-
event_id = str(event.get("id") or f"{
|
|
183
|
+
event_id = str(event.get("id") or f"{resolved_key}:{acked + offset}")
|
|
171
184
|
payload = sanitize(event)
|
|
172
185
|
batch.append(
|
|
173
186
|
{
|
|
@@ -181,7 +194,13 @@ def sync_change(project: Path, change_dir: Path, *, heartbeat_only: bool = False
|
|
|
181
194
|
)
|
|
182
195
|
if not batch:
|
|
183
196
|
save_cursor(change_dir, len(lines))
|
|
184
|
-
return {
|
|
197
|
+
return {
|
|
198
|
+
"ok": True,
|
|
199
|
+
"run_id": rid,
|
|
200
|
+
"change_key": resolved_key,
|
|
201
|
+
"uploaded": 0,
|
|
202
|
+
"acked_lines": len(lines),
|
|
203
|
+
}
|
|
185
204
|
|
|
186
205
|
# Drop None phase keys for strict schema.
|
|
187
206
|
for item in batch:
|
|
@@ -195,8 +214,8 @@ def sync_change(project: Path, change_dir: Path, *, heartbeat_only: bool = False
|
|
|
195
214
|
{
|
|
196
215
|
"protocol_version": "hunter-progress-sync/v1",
|
|
197
216
|
"run_id": rid,
|
|
198
|
-
"change_key":
|
|
199
|
-
"title":
|
|
217
|
+
"change_key": resolved_key,
|
|
218
|
+
"title": resolved_key,
|
|
200
219
|
"events": batch,
|
|
201
220
|
},
|
|
202
221
|
)
|
|
@@ -222,6 +241,7 @@ def sync_change(project: Path, change_dir: Path, *, heartbeat_only: bool = False
|
|
|
222
241
|
return {
|
|
223
242
|
"ok": accepted == len(batch),
|
|
224
243
|
"run_id": rid,
|
|
244
|
+
"change_key": resolved_key,
|
|
225
245
|
"uploaded": accepted,
|
|
226
246
|
"batch_size": len(batch),
|
|
227
247
|
"acked_lines": acked_lines,
|
|
@@ -229,10 +249,62 @@ def sync_change(project: Path, change_dir: Path, *, heartbeat_only: bool = False
|
|
|
229
249
|
}
|
|
230
250
|
|
|
231
251
|
|
|
252
|
+
def auto_events_sync(
|
|
253
|
+
project_root: Path,
|
|
254
|
+
change_dir: Path,
|
|
255
|
+
*,
|
|
256
|
+
heartbeat_only: bool = False,
|
|
257
|
+
run_id: str | None = None,
|
|
258
|
+
change_key: str | None = None,
|
|
259
|
+
) -> dict[str, Any]:
|
|
260
|
+
"""Best-effort platform events sync (same style as auto_push_archive_core).
|
|
261
|
+
|
|
262
|
+
Failures become warnings so the caller never rolls back the main workflow.
|
|
263
|
+
"""
|
|
264
|
+
project_root = project_root.resolve()
|
|
265
|
+
change_dir = change_dir.resolve()
|
|
266
|
+
if load_endpoint(project_root) is None:
|
|
267
|
+
return {"skipped": True, "reason": "no remote credentials"}
|
|
268
|
+
try:
|
|
269
|
+
result = sync_change(
|
|
270
|
+
project_root,
|
|
271
|
+
change_dir,
|
|
272
|
+
heartbeat_only=heartbeat_only,
|
|
273
|
+
run_id=run_id,
|
|
274
|
+
change_key=change_key,
|
|
275
|
+
)
|
|
276
|
+
except Exception as exc: # noqa: BLE001 — best-effort never blocks caller
|
|
277
|
+
return {
|
|
278
|
+
"skipped": False,
|
|
279
|
+
"ok": False,
|
|
280
|
+
"warning": f"events-sync deferred: {exc}",
|
|
281
|
+
}
|
|
282
|
+
if result.get("skipped"):
|
|
283
|
+
return {"skipped": True, "reason": result.get("reason") or "skipped"}
|
|
284
|
+
if result.get("ok"):
|
|
285
|
+
return {"skipped": False, "ok": True, **{
|
|
286
|
+
key: result[key]
|
|
287
|
+
for key in ("run_id", "change_key", "uploaded", "acked_lines", "heartbeat")
|
|
288
|
+
if key in result
|
|
289
|
+
}}
|
|
290
|
+
return {
|
|
291
|
+
"skipped": False,
|
|
292
|
+
"ok": False,
|
|
293
|
+
"warning": str(result.get("error") or "events-sync failed"),
|
|
294
|
+
**{
|
|
295
|
+
key: result[key]
|
|
296
|
+
for key in ("run_id", "change_key")
|
|
297
|
+
if key in result
|
|
298
|
+
},
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
|
|
232
302
|
def main(argv: list[str] | None = None) -> int:
|
|
233
303
|
parser = argparse.ArgumentParser(description="Sync events.ndjson to platform Run monitoring")
|
|
234
304
|
parser.add_argument("--project", default=".", help="Project root")
|
|
235
305
|
parser.add_argument("--change-dir", help="Specific change directory")
|
|
306
|
+
parser.add_argument("--run-id", help="Override stable run_id (archive finalize continuity)")
|
|
307
|
+
parser.add_argument("--change-key", help="Override change_key sent to the platform")
|
|
236
308
|
parser.add_argument("--heartbeat-only", action="store_true")
|
|
237
309
|
parser.add_argument("--json", action="store_true")
|
|
238
310
|
args = parser.parse_args(argv)
|
|
@@ -243,7 +315,13 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
243
315
|
root = project / ".harness" / "changes"
|
|
244
316
|
changes = sorted(path for path in root.glob("*") if path.is_dir()) if root.is_dir() else []
|
|
245
317
|
results = [
|
|
246
|
-
sync_change(
|
|
318
|
+
sync_change(
|
|
319
|
+
project,
|
|
320
|
+
change_dir,
|
|
321
|
+
heartbeat_only=args.heartbeat_only,
|
|
322
|
+
run_id=args.run_id,
|
|
323
|
+
change_key=args.change_key,
|
|
324
|
+
)
|
|
247
325
|
for change_dir in changes
|
|
248
326
|
]
|
|
249
327
|
ok = all(item.get("ok") for item in results) if results else True
|
|
@@ -31,6 +31,7 @@ if str(SCRIPTS_DIR) not in sys.path:
|
|
|
31
31
|
|
|
32
32
|
import harness_change as hc # noqa: E402
|
|
33
33
|
import harness_events as he # noqa: E402
|
|
34
|
+
import harness_events_sync as hes # noqa: E402
|
|
34
35
|
import harness_ledger as hl # noqa: E402
|
|
35
36
|
import harness_paths as hp # noqa: E402
|
|
36
37
|
import harness_plan_finalize as hpf # noqa: E402
|
|
@@ -2213,6 +2214,22 @@ def cmd_begin(args: argparse.Namespace) -> int:
|
|
|
2213
2214
|
"gateSeverityMode": severity_mode,
|
|
2214
2215
|
"gateWarnings": gate_warnings,
|
|
2215
2216
|
}
|
|
2217
|
+
# C3: best-effort start platform run monitoring (register + running via heartbeat/events).
|
|
2218
|
+
try:
|
|
2219
|
+
monitor = hes.auto_events_sync(project, change_dir)
|
|
2220
|
+
payload["platformMonitor"] = monitor
|
|
2221
|
+
if monitor.get("warning"):
|
|
2222
|
+
warnings_msg = str(monitor["warning"])
|
|
2223
|
+
gate_warnings.append({
|
|
2224
|
+
"code": "PLATFORM_EVENTS_SYNC_WARN",
|
|
2225
|
+
"message": warnings_msg,
|
|
2226
|
+
})
|
|
2227
|
+
payload["gateWarnings"] = gate_warnings
|
|
2228
|
+
except Exception as exc: # noqa: BLE001 — never block phase begin
|
|
2229
|
+
payload["platformMonitor"] = {
|
|
2230
|
+
"ok": False,
|
|
2231
|
+
"warning": f"events-sync hook failed: {exc}",
|
|
2232
|
+
}
|
|
2216
2233
|
emit(payload, as_json=as_json)
|
|
2217
2234
|
return 0
|
|
2218
2235
|
|
|
@@ -3,7 +3,7 @@ name: harness-archive
|
|
|
3
3
|
description: 归档所有变更产出(计划/测试报告/审查/SQL/API文档)到 .harness/archive/,含归档元数据。仅当用户显式调用
|
|
4
4
|
/harness-archive 时使用;不得被其他阶段 skill 自动接续触发。
|
|
5
5
|
---
|
|
6
|
-
<!-- generated by harness_deploy.py; core=
|
|
6
|
+
<!-- generated by harness_deploy.py; core=6b900d319d6b6d77; overlay=none; agent=codebuddy; do not edit -->
|
|
7
7
|
# harness-archive — 变更归档
|
|
8
8
|
|
|
9
9
|
## Purpose
|
|
@@ -101,6 +101,9 @@ description: 归档所有变更产出(计划/测试报告/审查/SQL/API文档
|
|
|
101
101
|
1. 运行 `python <skills-root>/scripts/harness_archive.py status --change-dir ".harness/changes/<change-name>" --intent release-candidate --json` 前置检查。无 CI 项目若已有完整全量 ledger,先运行 `certify-local`;若用户明确只封存事实,则 status/finalize 均使用 `--intent record-only`。
|
|
102
102
|
2. `meta/archive-meta.md` **由 `harness_archive.py finalize` 自动生成**(与 summary-data `finalStatus` 同源);**禁止 agent 手写**该文件,手写视为数据丢失。维护者结论写入 events(decision/issue)即可,finalize 会汇总到 summary / archive-meta。
|
|
103
103
|
3. 运行 `python <skills-root>/scripts/harness_archive.py finalize --change-dir ".harness/changes/<change-name>" --archive-root ".harness/archive" --intent <release-candidate|record-only> --json`;读 JSON(cleanup、事件、移动、collect、render、validate、manifest 比对、archive-meta)。finalize 内部负责且仅负责一次 `phase.start` / `phase.end`,调用者不得重复追加。**finalize 不再同步执行知识维护**(§8.2):它写一个 `pending` maintenance-outbox 项即返回,`knowledgeMaintenance=QUEUED`;写 outbox 失败时 `NOT_QUEUED`(warning,不回滚 archive,总状态 CONDITIONAL)。后续由 `harness-sync` / `harness_knowledge.py maintain` 异步推进 outbox。**finalize 失败或 validate 报错时不删除原目录**。
|
|
104
|
+
- **平台钩子(best-effort,不阻断归档)**:
|
|
105
|
+
1. **归档推送(C1)**:有远程凭据时自动 `hunter-harness push` 上传核心+可选辅助档(spec/plans/summary-data/knowledge + `reports/review/*`、`reports/test/*`、`meta/archive-meta.md`、`meta/change-context.json`)。
|
|
106
|
+
2. **监控终态(C3)**:auto-push 之后自动 `events-sync`,用归档前 change 路径派生的 `run_id` + 原 `change_key` 上报;平台依据 `phase.end`/`archive` 将 run 置为 succeeded/failed(含 `ended_at`)。失败只记 warning。
|
|
104
107
|
|
|
105
108
|
- **Read `reference.md`** — finalize 输出字段、archive-meta 格式、CONDITIONAL_OK 规则
|
|
106
109
|
- **Read `templates/summary-data-template.json`** — summary-data 数据结构
|
|
@@ -117,6 +120,11 @@ description: 归档所有变更产出(计划/测试报告/审查/SQL/API文档
|
|
|
117
120
|
- 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
|
|
118
121
|
- 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
|
|
119
122
|
- 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
|
|
123
|
+
|
|
124
|
+
## 生成内容语言约定
|
|
125
|
+
|
|
126
|
+
- sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
|
|
127
|
+
- 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
|
|
120
128
|
> 片段:p0-trust
|
|
121
129
|
|
|
122
130
|
## 关键规则(硬门禁速查)
|