@cyning/harness 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/AGENTS.md +20 -0
  2. package/CHANGELOG.md +127 -0
  3. package/README.md +133 -0
  4. package/bin/harness.js +7 -0
  5. package/ci/samples/README.md +42 -0
  6. package/ci/samples/pytest.yml.example +49 -0
  7. package/ci/samples/quality.yml.example +56 -0
  8. package/coding_wiki/templates/README.md +11 -0
  9. package/coding_wiki/templates/context.md +11 -0
  10. package/coding_wiki/templates/stable.md +19 -0
  11. package/coding_wiki/templates/volatile.md +15 -0
  12. package/docs/ARCHITECTURE.md +71 -0
  13. package/docs/DESIGN_ONTOLOGY_v1_zh.md +9 -0
  14. package/docs/HARNESS_GRAPH_MODEL_design_v0_zh.md +6 -0
  15. package/docs/HARNESS_GRAPH_MODEL_dialogue_archive_v1_zh.md +8 -0
  16. package/docs/ONBOARDING.md +126 -0
  17. package/docs/P0_V0.2_GAP.md +6 -0
  18. package/docs/README.md +38 -0
  19. package/docs/methodology/AUDIT_doc_consistency_2026-06-15_zh.md +69 -0
  20. package/docs/methodology/DOCUMENT_MAP_v1_zh.md +122 -0
  21. package/docs/methodology/README.md +147 -0
  22. package/docs/methodology/ROADMAP_v1_zh.md +136 -0
  23. package/docs/methodology/execution/P0_V0.2_GAP.md +93 -0
  24. package/docs/methodology/execution/PILOT_EVIDENCE_B2_v1_zh.md +132 -0
  25. package/docs/methodology/execution/README.md +12 -0
  26. package/docs/methodology/graph/HARNESS_GRAPH_MODEL_design_v0_zh.md +258 -0
  27. package/docs/methodology/graph/HARNESS_GRAPH_MODEL_dialogue_archive_v1_zh.md +132 -0
  28. package/docs/methodology/graph/README.md +22 -0
  29. package/docs/methodology/pointers/ADOPTION_METHODOLOGY_v1_zh.md +8 -0
  30. package/docs/methodology/pointers/ADOPTION_TARGET_STATE_v1_zh.md +6 -0
  31. package/docs/methodology/pointers/ASSESSMENT_etclovg_v1_zh.md +5 -0
  32. package/docs/methodology/pointers/ASSESSMENT_ink_v1_zh.md +5 -0
  33. package/docs/methodology/pointers/GUIDANCE_distribution_v1_zh.md +6 -0
  34. package/docs/methodology/pointers/HARNESS_V2_PLAN_v1_zh.md +8 -0
  35. package/docs/methodology/pointers/PILOT_kimi_code_fork_v1_zh.md +6 -0
  36. package/docs/methodology/pointers/POINTER_cyning_harness_repo_v1_zh.md +6 -0
  37. package/docs/methodology/pointers/README.md +40 -0
  38. package/docs/methodology/pointers/SDD_HAT_FLOW_v1_zh.md +8 -0
  39. package/docs/methodology/pointers/STRATEGY_MASTER_v1_zh.md +8 -0
  40. package/docs/methodology/pointers/STRATEGY_ONTOLOGY_v1_zh.md +9 -0
  41. package/docs/methodology/product/DESIGN_ONTOLOGY_v1_zh.md +719 -0
  42. package/docs/methodology/product/README.md +25 -0
  43. package/docs/methodology/prompts/PROMPT_article_theory_roundtable_v1_zh.md +127 -0
  44. package/docs/methodology/prompts/PROMPT_doc_consistency_audit_v1_zh.md +131 -0
  45. package/docs/methodology/prompts/PROMPT_feasibility_review_b_evidence_v1_zh.md +86 -0
  46. package/docs/methodology/prompts/README.md +10 -0
  47. package/docs/methodology/reviews/PROCESS_track_b_evidence_audit_2026-06-15_v1_zh.md +101 -0
  48. package/docs/methodology/reviews/README.md +9 -0
  49. package/docs/methodology/reviews/REVIEW_B3_pilot_evidence_and_sdd_compliance_bench_v1_zh.md +154 -0
  50. package/docs/methodology/reviews/REVIEW_B9_agent_shell_parallel_v1_zh.md +158 -0
  51. package/examples/demo_checkout/ACCEPTANCE.md +80 -0
  52. package/examples/demo_checkout/README.md +41 -0
  53. package/examples/demo_checkout/task_demo_p0_golden_v1.md +101 -0
  54. package/examples/oss-fork/README.md +139 -0
  55. package/examples/oss-fork/kimi-code/00_main.ai.md +23 -0
  56. package/examples/oss-fork/kimi-code/00_main.md +38 -0
  57. package/examples/oss-fork/kimi-code/01_struct.md +39 -0
  58. package/examples/oss-fork/kimi-code/02_version.md +6 -0
  59. package/examples/oss-fork/kimi-code/10_flow_cli_session.md +22 -0
  60. package/examples/oss-fork/kimi-code/README.md +15 -0
  61. package/golden/POINTER_gold_epic_serial.md +93 -0
  62. package/golden/README.md +30 -0
  63. package/graph/stubs/README.md +6 -0
  64. package/graph/templates/00_main.ai.md +28 -0
  65. package/graph/templates/00_main.md +52 -0
  66. package/graph/templates/01_struct.md +38 -0
  67. package/graph/templates/10_flow_MAIN.ai.md +43 -0
  68. package/graph/templates/10_flow_MAIN.md +47 -0
  69. package/graph/templates/99_mermaid_protocol.md +100 -0
  70. package/graph/templates/README.md +34 -0
  71. package/harness/README.md +18 -0
  72. package/harness/invokes/README.md +22 -0
  73. package/harness/invokes/TEMPLATE_invoke.md +59 -0
  74. package/harness/prompts/10-requirements.md +42 -0
  75. package/harness/prompts/22-task-audit.md +67 -0
  76. package/harness/prompts/30-execute-code.md +50 -0
  77. package/harness/prompts/FRAGMENT_30_gate_verify_v1_zh.md +30 -0
  78. package/harness/prompts/FRAGMENT_30_invoke_block_v1_zh.md +27 -0
  79. package/harness/prompts/README.md +28 -0
  80. package/harness/prompts/TEMPLATE_30_gate_stop.md +34 -0
  81. package/harness/templates/FRAGMENT_task_domain_infer_v1_zh.md +16 -0
  82. package/harness/templates/README.md +48 -0
  83. package/harness/templates/TASK_TEMPLATE.md +111 -0
  84. package/harness/templates/TASK_done_README.md +75 -0
  85. package/harness/templates/TASK_epic.md +101 -0
  86. package/harness/templates/TASK_graph_bootstrap.md +113 -0
  87. package/harness/templates/VIEW_done_by_domain.md +66 -0
  88. package/harness/templates/VIEW_done_thin_pointer.md +16 -0
  89. package/ide/adapters/AGENTS.md.fragment.example +31 -0
  90. package/ide/adapters/CLAUDE.md.fragment.example +30 -0
  91. package/ide/adapters/README.md +46 -0
  92. package/ide/adapters/cursor-harness-starter.mdc.example +37 -0
  93. package/lib/cli.js +180 -0
  94. package/lib/manifest.js +38 -0
  95. package/lib/paths.js +36 -0
  96. package/lib/run.js +33 -0
  97. package/package.json +37 -0
  98. package/schema/manifest.v1.schema.json +37 -0
  99. package/standards/POINTER_workspace_truth_v1_zh.md +57 -0
  100. package/standards/README.md +35 -0
  101. package/standards/SOURCES_v1_zh.md +49 -0
  102. package/standards/TEMPLATE_CODING_BASELINE_L1_v1_zh.md +88 -0
  103. package/standards/TEMPLATE_CODING_BASELINE_L2_backend_v1_zh.md +75 -0
  104. package/standards/TEMPLATE_CODING_BASELINE_L2_frontend_v1_zh.md +76 -0
  105. package/wizard/ONBOARDING_wizard_v1_zh.md +112 -0
  106. package/wizard/README.md +213 -0
  107. package/wizard/adopt-existing.sh +37 -0
  108. package/wizard/bootstrap-oss-fork-meta.sh +177 -0
  109. package/wizard/gate-check.sh +118 -0
  110. package/wizard/harness-sync.sh +237 -0
  111. package/wizard/install.sh +206 -0
  112. package/wizard/lib/common.sh +247 -0
  113. package/wizard/lib/manifest.sh +110 -0
  114. package/wizard/profiles/fullstack-node-py.json +21 -0
  115. package/wizard/profiles/harness-only.json +19 -0
  116. package/wizard/profiles/ios-cursor.json +19 -0
  117. package/wizard/profiles/issue-scan-presets.json +51 -0
  118. package/wizard/profiles/oss-fork-meta.json +17 -0
  119. package/wizard/scan-upstream-issues.sh +287 -0
  120. package/wizard/templates/FRAGMENT_rethink_backfill_task_v1_zh.md +44 -0
  121. package/wizard/templates/POINTER_PILOT_adoption_workspace.md +23 -0
  122. package/wizard/templates/TASK_TEMPLATE_upstream_pr_v1.md +164 -0
  123. package/wizard/templates/task_graph_bootstrap_v1.md +53 -0
  124. package/wizard/uninstall.sh +218 -0
  125. package/wizard/upgrade.sh +164 -0
@@ -0,0 +1,110 @@
1
+ # cyning-harness · VersionManifest 读写(source 用)
2
+ # shellcheck shell=bash
3
+
4
+ manifest_file_path() {
5
+ echo "$1/.cyning-harness/manifest.json"
6
+ }
7
+
8
+ # 从 profile.json 推导 IDE 列表
9
+ manifest_ide_from_profile() {
10
+ local profile="$1"
11
+ local parts=()
12
+ if grep -q '"ide_cursor"[[:space:]]*:[[:space:]]*true' "$profile"; then parts+=("cursor"); fi
13
+ if grep -q '"ide_claude"[[:space:]]*:[[:space:]]*true' "$profile"; then parts+=("claude"); fi
14
+ if grep -q '"ide_agents"[[:space:]]*:[[:space:]]*true' "$profile"; then parts+=("agents"); fi
15
+ local IFS=,
16
+ if [[ ${#parts[@]} -eq 0 ]]; then
17
+ echo "[]"
18
+ else
19
+ local json="["
20
+ local first=1
21
+ for p in "${parts[@]}"; do
22
+ [[ $first -eq 1 ]] || json+=","
23
+ json+="\"$p\""
24
+ first=0
25
+ done
26
+ json+="]"
27
+ echo "$json"
28
+ fi
29
+ }
30
+
31
+ # 将逗号 IDE 列表转为 JSON 数组
32
+ manifest_ide_json_from_list() {
33
+ local ide_list="$1"
34
+ if [[ -z "$ide_list" ]]; then
35
+ echo "[]"
36
+ return
37
+ fi
38
+ local json="["
39
+ local first=1
40
+ IFS=',' read -ra parts <<< "$ide_list"
41
+ for raw in "${parts[@]}"; do
42
+ local p="${raw// /}"
43
+ [[ -n "$p" ]] || continue
44
+ [[ $first -eq 1 ]] || json+=","
45
+ json+="\"$p\""
46
+ first=0
47
+ done
48
+ json+="]"
49
+ echo "$json"
50
+ }
51
+
52
+ manifest_now_utc() {
53
+ date -u +"%Y-%m-%dT%H:%M:%SZ"
54
+ }
55
+
56
+ # init 后写入 manifest(VersionManifest)
57
+ write_manifest_init() {
58
+ local target="$1" version="$2" preset="$3" ide_list="$4" profile="$5"
59
+ local mf ide_json now
60
+ mf="$(manifest_file_path "$target")"
61
+ now="$(manifest_now_utc)"
62
+ if [[ -n "$ide_list" ]]; then
63
+ ide_json="$(manifest_ide_json_from_list "$ide_list")"
64
+ else
65
+ ide_json="$(manifest_ide_from_profile "$profile")"
66
+ fi
67
+ mkdir -p "$target/.cyning-harness"
68
+ cat > "$mf" <<EOF
69
+ {
70
+ "version": "$version",
71
+ "preset": "$preset",
72
+ "ide": $ide_json,
73
+ "from_version": null,
74
+ "upgraded_at": "$now"
75
+ }
76
+ EOF
77
+ echo "已写入 manifest: $mf"
78
+ }
79
+
80
+ # upgrade apply 后更新 manifest
81
+ write_manifest_upgrade() {
82
+ local target="$1" version="$2"
83
+ local mf now from_ver preset ide_json
84
+ mf="$(manifest_file_path "$target")"
85
+ now="$(manifest_now_utc)"
86
+ from_ver="null"
87
+ preset="$(profile_preset_name "$target/.cyning-harness/profile.json")"
88
+ ide_json="$(manifest_ide_from_profile "$target/.cyning-harness/profile.json")"
89
+
90
+ if [[ -f "$mf" ]]; then
91
+ local old_ver
92
+ old_ver="$(grep '"version"' "$mf" | head -1 | sed -E 's/.*:[[:space:]]*"([^"]+)".*/\1/')"
93
+ if [[ -n "$old_ver" && "$old_ver" != "$version" ]]; then
94
+ from_ver="\"$old_ver\""
95
+ fi
96
+ preset="$(grep '"preset"' "$mf" | head -1 | sed -E 's/.*:[[:space:]]*"([^"]+)".*/\1/' || echo "$preset")"
97
+ fi
98
+
99
+ mkdir -p "$target/.cyning-harness"
100
+ cat > "$mf" <<EOF
101
+ {
102
+ "version": "$version",
103
+ "preset": "$preset",
104
+ "ide": $ide_json,
105
+ "from_version": $from_ver,
106
+ "upgraded_at": "$now"
107
+ }
108
+ EOF
109
+ echo "已更新 manifest: $mf"
110
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "version": 1,
3
+ "preset": "fullstack-node-py",
4
+ "description": "全栈 Ink 类:五轨 + quality + pytest",
5
+ "paths": {
6
+ "ide_cursor": ".cursor/rules/05-harness-starter.mdc"
7
+ },
8
+ "tracks": {
9
+ "graph": true,
10
+ "wiki": true,
11
+ "standards_l1": true,
12
+ "standards_l2": true,
13
+ "harness_prompts": true,
14
+ "harness_invoke_template": true,
15
+ "harness_task_bootstrap": true,
16
+ "ide_cursor": true,
17
+ "ide_claude": false,
18
+ "ide_agents": false,
19
+ "ci": "both"
20
+ }
21
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "version": 1,
3
+ "preset": "harness-only",
4
+ "description": "仅过程轨 + Cursor 规则(不覆盖图谱/业务 task)",
5
+ "paths": {
6
+ "ide_cursor": ".cursor/rules/06-harness-pointer.mdc"
7
+ },
8
+ "tracks": {
9
+ "graph": false,
10
+ "wiki": false,
11
+ "standards": false,
12
+ "harness_prompts": true,
13
+ "harness_invoke_template": true,
14
+ "ide_cursor": true,
15
+ "ide_claude": false,
16
+ "ide_agents": false,
17
+ "ci": "none"
18
+ }
19
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "version": 1,
3
+ "preset": "ios-cursor",
4
+ "description": "存量 iOS · S2:图谱模板 + wiki + L1 + harness + Cursor(无 Node CI)",
5
+ "paths": {
6
+ "ide_cursor": ".cursor/rules/06-harness-pointer.mdc"
7
+ },
8
+ "tracks": {
9
+ "graph": true,
10
+ "wiki": true,
11
+ "standards_l1": true,
12
+ "standards_l2": false,
13
+ "harness_prompts": true,
14
+ "harness_invoke_template": true,
15
+ "harness_task_bootstrap": true,
16
+ "ide_cursor": true,
17
+ "ci": "none"
18
+ }
19
+ }
@@ -0,0 +1,51 @@
1
+ {
2
+ "version": 1,
3
+ "description": "scan-upstream-issues.sh 预设 · 参数可被 CLI 覆盖",
4
+ "presets": {
5
+ "kimi-open-bug": {
6
+ "repo": "MoonshotAI/kimi-code",
7
+ "state": "open",
8
+ "labels": ["bug"],
9
+ "limit": 120,
10
+ "check_pr": true,
11
+ "only_no_pr": false,
12
+ "exclude_issues": []
13
+ },
14
+ "kimi-c2-candidate": {
15
+ "repo": "MoonshotAI/kimi-code",
16
+ "state": "open",
17
+ "labels": [],
18
+ "limit": 120,
19
+ "check_pr": true,
20
+ "only_no_pr": true,
21
+ "exclude_issues": [565, 566]
22
+ },
23
+ "kimi-c3-candidate": {
24
+ "repo": "MoonshotAI/kimi-code",
25
+ "state": "open",
26
+ "labels": [],
27
+ "limit": 120,
28
+ "check_pr": true,
29
+ "only_no_pr": true,
30
+ "exclude_issues": [565, 566, 583]
31
+ },
32
+ "kimi-open-all": {
33
+ "repo": "MoonshotAI/kimi-code",
34
+ "state": "open",
35
+ "labels": [],
36
+ "limit": 120,
37
+ "check_pr": true,
38
+ "only_no_pr": false,
39
+ "exclude_issues": []
40
+ },
41
+ "kimi-open-enhancement": {
42
+ "repo": "MoonshotAI/kimi-code",
43
+ "state": "open",
44
+ "labels": ["enhancement"],
45
+ "limit": 120,
46
+ "check_pr": true,
47
+ "only_no_pr": false,
48
+ "exclude_issues": []
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "version": 1,
3
+ "preset": "oss-fork-meta",
4
+ "description": "OSS 个人 fork · cyning/meta:过程轨 + 图谱骨架(S3 · 无 wiki/CI)",
5
+ "paths": {
6
+ "ide_cursor": ".cursor/rules/06-harness-pointer.mdc"
7
+ },
8
+ "tracks": {
9
+ "graph": true,
10
+ "wiki": false,
11
+ "standards": false,
12
+ "harness_prompts": true,
13
+ "harness_invoke_template": true,
14
+ "ide_cursor": true,
15
+ "ci": "none"
16
+ }
17
+ }
@@ -0,0 +1,287 @@
1
+ #!/usr/bin/env bash
2
+ # 上游 Issue 扫描(gh CLI · 无 Agent)
3
+ # 用途:OSS fork 选题 · 检查 PR 占坑 · 可落盘 Markdown 报告
4
+ set -euo pipefail
5
+
6
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
+ PRESETS_FILE="${PRESETS_FILE:-$SCRIPT_DIR/profiles/issue-scan-presets.json}"
8
+
9
+ REPO=""
10
+ STATE="open"
11
+ LIMIT=120
12
+ LABELS=()
13
+ EXCLUDE_ISSUES=()
14
+ CHECK_PR=1
15
+ ONLY_NO_PR=0
16
+ USER_SET_CHECK_PR=0
17
+ USER_SET_ONLY_NO_PR=0
18
+ USER_SET_LIMIT=0
19
+ USER_SET_STATE=0
20
+ USER_SET_REPO=0
21
+ FORMAT="table"
22
+ OUTPUT=""
23
+ SEARCH_EXTRA=""
24
+ PRESET=""
25
+
26
+ usage() {
27
+ cat <<'EOF'
28
+ 用法:
29
+
30
+ scan-upstream-issues.sh --repo OWNER/NAME [选项]
31
+
32
+ scan-upstream-issues.sh --preset kimi-c2-candidate
33
+ scan-upstream-issues.sh --preset kimi-open-bug --limit 20
34
+
35
+ 选项:
36
+ --repo OWNER/NAME 目标仓库(必填,除非 --preset 内含)
37
+ --preset NAME 读取 profiles/issue-scan-presets.json
38
+ --state open|closed|all 默认 open
39
+ --label NAME 可重复;与 gh label 过滤一致
40
+ --limit N 默认 120(gh 自动分页;2026-06 kimi-code open 约 118)
41
+ --exclude-issues N,N 跳过已知 issue 号(如 565,566)
42
+ --check-pr 为每条 issue 查关联 PR(默认开启)
43
+ --no-check-pr 不查 PR(更快)
44
+ --only-no-pr 仅输出「无 open PR」的 issue
45
+ --search QUERY 追加 gh issue list 搜索词
46
+ --format table|markdown|json|text
47
+ --output PATH 写入文件(markdown/json 推荐)
48
+ --presets-file PATH 自定义预设 JSON
49
+
50
+ 预设(profiles/issue-scan-presets.json):
51
+ kimi-open-bug open + label bug
52
+ kimi-c2-candidate open + bug + 排除 565/566 + only-no-pr
53
+ kimi-open-all open 全标签
54
+ kimi-open-enhancement open + enhancement
55
+
56
+ 依赖: gh(已 auth)、jq
57
+
58
+ 示例:
59
+ "$CYNING_HARNESS/wizard/scan-upstream-issues.sh" --preset kimi-c2-candidate \
60
+ --format markdown --output /tmp/kimi-scan.md
61
+
62
+ "$CYNING_HARNESS/wizard/scan-upstream-issues.sh" \
63
+ --repo MoonshotAI/kimi-code --state open --label bug --check-pr --limit 15
64
+ EOF
65
+ }
66
+
67
+ need_cmd() {
68
+ command -v "$1" >/dev/null 2>&1 || { echo "错误: 需要 $1" >&2; exit 1; }
69
+ }
70
+
71
+ load_preset() {
72
+ local name="$1"
73
+ [[ -f "$PRESETS_FILE" ]] || { echo "错误: 无预设文件 $PRESETS_FILE" >&2; exit 1; }
74
+ local data
75
+ data="$(jq -r --arg p "$name" '.presets[$p] // empty' "$PRESETS_FILE")"
76
+ [[ -n "$data" && "$data" != "null" ]] || {
77
+ echo "错误: 未知 preset '$name'" >&2
78
+ jq -r '.presets | keys[]' "$PRESETS_FILE" | sed 's/^/ - /' >&2
79
+ exit 1
80
+ }
81
+
82
+ if [[ "$USER_SET_REPO" == 0 ]]; then REPO="$(jq -r '.repo // empty' <<<"$data")"; fi
83
+ if [[ "$USER_SET_STATE" == 0 ]]; then STATE="$(jq -r '.state // "open"' <<<"$data")"; fi
84
+ if [[ "$USER_SET_LIMIT" == 0 ]]; then LIMIT="$(jq -r '.limit // 30' <<<"$data")"; fi
85
+ if [[ "$USER_SET_CHECK_PR" == 0 ]]; then
86
+ CHECK_PR="$(jq -r '.check_pr // true' <<<"$data")"
87
+ if [[ "$CHECK_PR" == "true" ]]; then CHECK_PR=1; else CHECK_PR=0; fi
88
+ fi
89
+ if [[ "$USER_SET_ONLY_NO_PR" == 0 ]]; then
90
+ ONLY_NO_PR="$(jq -r '.only_no_pr // false' <<<"$data")"
91
+ if [[ "$ONLY_NO_PR" == "true" ]]; then ONLY_NO_PR=1; else ONLY_NO_PR=0; fi
92
+ fi
93
+
94
+ if [[ ${#LABELS[@]} -eq 0 ]]; then
95
+ local preset_labels
96
+ preset_labels="$(jq -r '.labels[]? // empty' <<<"$data")"
97
+ while IFS= read -r lb; do
98
+ [[ -n "$lb" ]] && LABELS+=("$lb")
99
+ done <<<"$preset_labels"
100
+ fi
101
+
102
+ if [[ ${#EXCLUDE_ISSUES[@]} -eq 0 ]]; then
103
+ local preset_exclude
104
+ preset_exclude="$(jq -r '.exclude_issues[]? // empty' <<<"$data")"
105
+ while IFS= read -r num; do
106
+ [[ -n "$num" ]] && EXCLUDE_ISSUES+=("$num")
107
+ done <<<"$preset_exclude"
108
+ fi
109
+ }
110
+
111
+ is_excluded() {
112
+ local n="$1"
113
+ [[ ${#EXCLUDE_ISSUES[@]} -eq 0 ]] && return 1
114
+ for e in "${EXCLUDE_ISSUES[@]}"; do
115
+ [[ "$e" == "$n" ]] && return 0
116
+ done
117
+ return 1
118
+ }
119
+
120
+ find_prs_for_issue() {
121
+ local num="$1"
122
+ # 搜索标题/正文含 issue 号的 PR;可能有多条
123
+ gh pr list --repo "$REPO" --search "$num in:title,body" --state all \
124
+ --limit 5 --json number,state,title,url 2>/dev/null || echo '[]'
125
+ }
126
+
127
+ labels_to_string() {
128
+ jq -r '[.labels[]?.name] | join(", ")' <<<"$1"
129
+ }
130
+
131
+ while [[ $# -gt 0 ]]; do
132
+ case "$1" in
133
+ --repo) REPO="$2"; USER_SET_REPO=1; shift 2 ;;
134
+ --preset) PRESET="$2"; shift 2 ;;
135
+ --state) STATE="$2"; USER_SET_STATE=1; shift 2 ;;
136
+ --label) LABELS+=("$2"); shift 2 ;;
137
+ --limit) LIMIT="$2"; USER_SET_LIMIT=1; shift 2 ;;
138
+ --exclude-issues)
139
+ IFS=',' read -ra _ex <<<"$2"
140
+ EXCLUDE_ISSUES+=("${_ex[@]}")
141
+ shift 2
142
+ ;;
143
+ --check-pr) CHECK_PR=1; USER_SET_CHECK_PR=1; shift ;;
144
+ --no-check-pr) CHECK_PR=0; USER_SET_CHECK_PR=1; shift ;;
145
+ --only-no-pr) ONLY_NO_PR=1; USER_SET_ONLY_NO_PR=1; shift ;;
146
+ --search) SEARCH_EXTRA="$2"; shift 2 ;;
147
+ --format) FORMAT="$2"; shift 2 ;;
148
+ --output) OUTPUT="$2"; shift 2 ;;
149
+ --presets-file) PRESETS_FILE="$2"; shift 2 ;;
150
+ -h|--help) usage; exit 0 ;;
151
+ *) echo "未知参数: $1" >&2; usage; exit 1 ;;
152
+ esac
153
+ done
154
+
155
+ [[ -n "$PRESET" ]] && load_preset "$PRESET"
156
+ [[ -n "$REPO" ]] || { echo "错误: 须指定 --repo 或 --preset" >&2; exit 1; }
157
+
158
+ need_cmd gh
159
+ need_cmd jq
160
+
161
+ GH_ARGS=(issue list --repo "$REPO" --state "$STATE" --limit "$LIMIT")
162
+ GH_ARGS+=(--json number,title,labels,createdAt,url)
163
+ if [[ ${#LABELS[@]} -gt 0 ]]; then
164
+ for lb in "${LABELS[@]}"; do
165
+ GH_ARGS+=(--label "$lb")
166
+ done
167
+ fi
168
+ if [[ -n "$SEARCH_EXTRA" ]]; then
169
+ GH_ARGS+=(--search "$SEARCH_EXTRA")
170
+ fi
171
+
172
+ ISSUES_JSON="$(gh "${GH_ARGS[@]}")"
173
+ ISSUE_COUNT="$(jq 'length' <<<"$ISSUES_JSON")"
174
+
175
+ # 逐条 enrich:PR 占坑(勿用 for+$(jq) 以免标题空格拆碎 JSON)
176
+ RESULTS='[]'
177
+ while IFS= read -r row; do
178
+ [[ -z "$row" ]] && continue
179
+ num="$(jq -r '.number' <<<"$row")"
180
+ if is_excluded "$num"; then continue; fi
181
+
182
+ prs_json='[]'
183
+ pr_open=0
184
+ pr_summary=""
185
+ if [[ "$CHECK_PR" == 1 ]]; then
186
+ prs_json="$(find_prs_for_issue "$num")"
187
+ pr_open="$(jq '[.[] | select(.state=="OPEN")] | length' <<<"$prs_json")"
188
+ pr_summary="$(jq -r '[.[] | "#\(.number)(\(.state))"] | join(", ")' <<<"$prs_json")"
189
+ if [[ -z "$pr_summary" ]]; then pr_summary="—"; fi
190
+ else
191
+ pr_summary="(未检查)"
192
+ fi
193
+
194
+ if [[ "$ONLY_NO_PR" == 1 && "$pr_open" -gt 0 ]]; then continue; fi
195
+
196
+ enriched="$(jq -c --argjson prs "$prs_json" --arg prs_summary "$pr_summary" \
197
+ --argjson pr_open "$pr_open" \
198
+ '. + {linked_prs: $prs, pr_summary: $prs_summary, pr_open_count: $pr_open}' <<<"$row")"
199
+ RESULTS="$(jq -c --argjson e "$enriched" '. + [$e]' <<<"$RESULTS")"
200
+ done < <(jq -c '.[]' <<<"$ISSUES_JSON")
201
+
202
+ FILTERED_COUNT="$(jq 'length' <<<"$RESULTS")"
203
+ SCAN_TIME="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
204
+
205
+ emit_table() {
206
+ printf "=== Issue scan ===\n"
207
+ printf "repo: %s | state: %s | fetched: %s | shown: %s (excluded/filtered)\n" \
208
+ "$REPO" "$STATE" "$ISSUE_COUNT" "$FILTERED_COUNT"
209
+ local labels_display="(无)"
210
+ if [[ ${#LABELS[@]} -gt 0 ]]; then
211
+ labels_display="$(IFS=,; echo "${LABELS[*]}")"
212
+ fi
213
+ printf "labels: %s | check_pr: %s | only_no_pr: %s\n" \
214
+ "$labels_display" "$CHECK_PR" "$ONLY_NO_PR"
215
+ printf "\n"
216
+ printf "%-6s %-12s %-8s %s\n" "#" "labels" "PR" "title"
217
+ printf "%-6s %-12s %-8s %s\n" "------" "------------" "--------" "-----"
218
+ jq -r '.[] | [
219
+ (.number|tostring),
220
+ ([.labels[]?.name] | join(",")),
221
+ .pr_summary,
222
+ .title
223
+ ] | @tsv' <<<"$RESULTS" | while IFS=$'\t' read -r num labs prs title; do
224
+ printf "%-6s %-12s %-8s %s\n" "$num" "$labs" "$prs" "$title"
225
+ done
226
+ }
227
+
228
+ emit_json() {
229
+ jq -n \
230
+ --arg repo "$REPO" \
231
+ --arg state "$STATE" \
232
+ --arg scanned_at "$SCAN_TIME" \
233
+ --argjson fetched "$ISSUE_COUNT" \
234
+ --argjson shown "$FILTERED_COUNT" \
235
+ --argjson issues "$RESULTS" \
236
+ '{repo: $repo, state: $state, scanned_at: $scanned_at, fetched: $fetched, shown: $shown, issues: $issues}'
237
+ }
238
+
239
+ emit_markdown() {
240
+ local labels_display="(无)"
241
+ if [[ ${#LABELS[@]} -gt 0 ]]; then
242
+ labels_display="$(IFS=,; echo "${LABELS[*]}")"
243
+ fi
244
+ cat <<EOF
245
+ # Issue scan · ${REPO}
246
+
247
+ | 项 | 值 |
248
+ |----|-----|
249
+ | **扫描时间** | ${SCAN_TIME} |
250
+ | **state** | ${STATE} |
251
+ | **labels** | ${labels_display:-(无)} |
252
+ | **gh 拉取** | ${ISSUE_COUNT} 条 |
253
+ | **输出** | ${FILTERED_COUNT} 条 |
254
+ | **check_pr** | ${CHECK_PR} |
255
+ | **only_no_pr** | ${ONLY_NO_PR} |
256
+ | **preset** | ${PRESET:-(无)} |
257
+
258
+ ## 结果
259
+
260
+ | # | labels | linked PR | title |
261
+ |---|--------|-----------|-------|
262
+ EOF
263
+ jq -r '.[] | "| [\(.number)](\(.url)) | \([.labels[]?.name] | join(", ")) | \(.pr_summary) | \(.title | gsub("|"; "/")) |"' \
264
+ <<<"$RESULTS"
265
+ cat <<EOF
266
+
267
+ ---
268
+
269
+ _由 \`cyning-harness/wizard/scan-upstream-issues.sh\` 生成_
270
+ EOF
271
+ }
272
+
273
+ OUTPUT_BODY=""
274
+ case "$FORMAT" in
275
+ table) OUTPUT_BODY="$(emit_table)" ;;
276
+ text) OUTPUT_BODY="$(emit_table)" ;;
277
+ json) OUTPUT_BODY="$(emit_json)" ;;
278
+ markdown) OUTPUT_BODY="$(emit_markdown)" ;;
279
+ *) echo "错误: 未知 format $FORMAT(可用 table|text|markdown|json)" >&2; exit 1 ;;
280
+ esac
281
+
282
+ if [[ -n "$OUTPUT" ]]; then
283
+ printf '%s\n' "$OUTPUT_BODY" >"$OUTPUT"
284
+ echo "已写入: $OUTPUT (${FILTERED_COUNT} issues)" >&2
285
+ else
286
+ printf '%s\n' "$OUTPUT_BODY"
287
+ fi
@@ -0,0 +1,44 @@
1
+ # FRAGMENT · 思考轮结论回填 task(mandatory)
2
+
3
+ > 嵌入 `docs/harness/invokes/by-task/<slug>/PROMPT_kimi_agent_rethink_*.md` 与 `docs/tasks/TASK_TEMPLATE_upstream_pr_v1.md` §4。
4
+
5
+ ## 问题
6
+
7
+ Agent 仅在聊天输出 `## R1 结论` **不算完成**;须 task §4 真值 + **思考轮控制** 表,22 才能审、维护者才能签 `HG-AUDIT-R1`。
8
+
9
+ ## 回填协议(Agent 必执行)
10
+
11
+ ### 允许修改(仅此)
12
+
13
+ | 路径 | 操作 |
14
+ |------|------|
15
+ | `<meta-worktree>/docs/tasks/active/<task>.md`(或 `done/`) | 写入 §4 各轮 **回填区** + **思考轮控制** |
16
+ | `docs/harness/invokes/by-task/<slug>/invoke_*_rethink_*.md` | 可选:思考快照 |
17
+
18
+ 双 worktree 时 Open Folder 在产品仓,task 路径示例:`@../your-fork-meta/docs/tasks/active/...`
19
+
20
+ ### 禁止
21
+
22
+ - 产品仓 `packages/**`、`apps/**` 等源码
23
+ - `git commit` / `git push`
24
+
25
+ ### 步骤
26
+
27
+ 1. 完成 R0~Rn 思考(默认槽位 **R0 + R1–R5**;可提前停或增 R6+,见下)。
28
+ 2. 填写 **思考轮控制**:`actual_last_round` · `early_stop` · `early_stop_reason` · `residual_risks`。
29
+ 3. **编辑 task 文件** §4,将各 `**回填区:**` 下 `(待填)` 替换为结论;**跳过轮**写 `(跳过 · 见思考轮控制)`。
30
+ 4. 回复末尾输出 **回填自检表** + `回填完成 · 未 commit · 未改产品代码`。
31
+ 5. 无法写文件时:输出 `## BACKFILL_PACK` 供维护者粘贴。
32
+
33
+ ## 提前停止 / 增轮
34
+
35
+ | 情况 | 必填 |
36
+ |------|------|
37
+ | **提前停止**(如 R3 已收敛) | `early_stop=yes` · reason · `residual_risks`(无则 `none`)· 未执行轮回填区写「跳过」 |
38
+ | **增 R6+** | 追加 `### R6 · …` + **扩展理由**;更新 `actual_last_round` |
39
+
40
+ **22 审查**:reason 不充分或 residual 未落入 §3/§5 → **退回 10 帽** 补思考。
41
+
42
+ ## task §4 标记
43
+
44
+ `### Rk` → `**回填区:**` → ` ```text ` 内为 `(待填)`、结论正文或 `(跳过 · 见思考轮控制)`。
@@ -0,0 +1,23 @@
1
+ # POINTER · Harness 试点(工作区真值)
2
+
3
+ | 项 | 内容 |
4
+ |----|------|
5
+ | **性质** | 个人 fork · **`cyning/meta` 分支** 过程轨 |
6
+ | **勿 PR 上游** | `docs/harness/`、`docs/tasks/`、`.cyning-harness/`、`.cursor/rules/06-*` |
7
+
8
+ ## 初始化脚本
9
+
10
+ `cyning-harness/wizard/bootstrap-oss-fork-meta.sh`
11
+
12
+ ## 分支
13
+
14
+ - 过程开发:`cyning/meta`(push 仅到 **你的 fork**)
15
+ - 上游 PR:仅从干净 `main` → `feature/*`,**仅产品 diff**
16
+
17
+ ## worktree(v0.1.2)
18
+
19
+ ```bash
20
+ git worktree add ../<fork>-meta cyning/meta
21
+ ```
22
+
23
+ 产品改码 Open `<fork>/`;task / invoke / 图谱 `@` `<fork>-meta/`。详见 `cyning-harness/examples/oss-fork/README.md`。