@michelj/context-guard 0.4.2 → 0.4.3

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 (72) hide show
  1. package/README.md +74 -6
  2. package/README.zh-CN.md +74 -6
  3. package/{skills/context-guard/SKILL.md → SKILL.md} +216 -77
  4. package/bin/context-guard-skill.js +88 -3
  5. package/hooks.json +25 -1
  6. package/package.json +7 -3
  7. package/{skills/context-guard/references → references}/context-template.md +52 -1
  8. package/references/feature-chain-methodology.md +228 -0
  9. package/{skills/context-guard/scripts → scripts}/context_guard.py +3119 -121
  10. package/{skills/context-guard/scripts → scripts}/context_guard_hook.py +344 -12
  11. package/{skills/context-guard/tests → tests}/BC-20260701-090.sh +8 -7
  12. package/{skills/context-guard/tests → tests}/BC-20260702-096.sh +6 -3
  13. package/tests/BC-20260706-098.sh +66 -0
  14. package/tests/BC-20260707-099.sh +47 -0
  15. package/tests/BC-20260707-100.sh +46 -0
  16. package/tests/BC-20260707-101.sh +47 -0
  17. package/tests/BC-20260707-102.sh +68 -0
  18. package/tests/BC-20260707-103.sh +59 -0
  19. package/tests/BC-20260707-104.sh +103 -0
  20. package/tests/BC-20260707-105.sh +109 -0
  21. package/tests/BC-20260707-106.sh +80 -0
  22. package/tests/BC-20260707-107.sh +74 -0
  23. package/tests/BC-20260707-108.sh +48 -0
  24. package/tests/BC-20260707-109.sh +56 -0
  25. package/tests/BC-20260707-110.sh +71 -0
  26. package/tests/BC-20260707-111.sh +70 -0
  27. package/tests/BC-20260707-112.sh +45 -0
  28. package/tests/BC-20260707-113.sh +73 -0
  29. package/tests/BC-20260707-115.sh +77 -0
  30. package/tests/BC-20260707-116.sh +77 -0
  31. package/tests/BC-20260707-118.sh +115 -0
  32. package/tests/BC-20260707-119.sh +47 -0
  33. package/tests/BC-20260707-120.sh +60 -0
  34. package/tests/BC-20260707-121.sh +66 -0
  35. package/tests/BC-20260707-122.sh +48 -0
  36. package/tests/BC-20260707-123.sh +43 -0
  37. package/tests/BC-20260707-124.sh +56 -0
  38. package/tests/BC-20260707-125.sh +64 -0
  39. package/tests/BC-20260707-126.sh +80 -0
  40. package/tests/BC-20260707-127.sh +88 -0
  41. package/tests/BC-20260707-129.sh +59 -0
  42. package/tests/BC-20260707-130.sh +69 -0
  43. package/tests/BC-20260707-131.sh +140 -0
  44. package/tests/BC-20260707-132.sh +150 -0
  45. package/tests/BC-20260707-133.sh +70 -0
  46. package/tests/BC-20260708-136.sh +210 -0
  47. package/tests/BC-20260708-137.sh +106 -0
  48. package/tests/BC-20260708-138.sh +168 -0
  49. package/tests/BC-20260708-139.sh +79 -0
  50. package/tests/BC-20260709-002.sh +63 -0
  51. package/tests/BC-20260709-003.sh +239 -0
  52. package/tests/BC-20260709-006.sh +76 -0
  53. package/tests/BC-20260709-008.sh +168 -0
  54. package/tests/BC-20260710-001.sh +61 -0
  55. package/tests/BC-20260710-002.sh +111 -0
  56. package/tests/npm-install-smoke.sh +53 -0
  57. package/skills/context-guard/README.md +0 -234
  58. package/skills/context-guard/README.zh-CN.md +0 -234
  59. /package/{skills/context-guard/agents → agents}/openai.yaml +0 -0
  60. /package/{skills/context-guard/references → references}/register-template.md +0 -0
  61. /package/{skills/context-guard/references → references}/task-case-template.md +0 -0
  62. /package/{skills/context-guard/tests → tests}/BC-20260618-063.sh +0 -0
  63. /package/{skills/context-guard/tests → tests}/BC-20260618-065.sh +0 -0
  64. /package/{skills/context-guard/tests → tests}/BC-20260626-080.sh +0 -0
  65. /package/{skills/context-guard/tests → tests}/BC-20260626-081.sh +0 -0
  66. /package/{skills/context-guard/tests → tests}/BC-20260626-082.sh +0 -0
  67. /package/{skills/context-guard/tests → tests}/BC-20260626-083.sh +0 -0
  68. /package/{skills/context-guard/tests → tests}/BC-20260627-084.sh +0 -0
  69. /package/{skills/context-guard/tests → tests}/BC-20260630-086.sh +0 -0
  70. /package/{skills/context-guard/tests → tests}/BC-20260630-087.sh +0 -0
  71. /package/{skills/context-guard/tests → tests}/BC-20260630-088.sh +0 -0
  72. /package/{skills/context-guard/tests → tests}/BC-20260630-089.sh +0 -0
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT="${CONTEXT_GUARD_SCRIPT:-$(cd "$(dirname "$0")/.." && pwd)/scripts/context_guard.py}"
5
+ ROOT="$(mktemp -d "${TMPDIR:-/tmp}/context-guard-loose-bc-XXXXXX")"
6
+ trap 'rm -rf "$ROOT"' EXIT
7
+
8
+ mkdir -p "$ROOT/bin"
9
+ cat >"$ROOT/bin/smoke.sh" <<'SH'
10
+ #!/usr/bin/env bash
11
+ set -euo pipefail
12
+ test -f index.html
13
+ grep -Fq "Evening Reset" index.html
14
+ SH
15
+ chmod +x "$ROOT/bin/smoke.sh"
16
+
17
+ cat >"$ROOT/index.html" <<'HTML'
18
+ <!doctype html>
19
+ <title>Evening Reset</title>
20
+ <main>Evening Reset</main>
21
+ HTML
22
+
23
+ python3 "$SCRIPT" init --root "$ROOT" >/dev/null
24
+ python3 "$SCRIPT" test-hub-add \
25
+ --root "$ROOT" \
26
+ --title "Loose bad-case smoke" \
27
+ --command-text "./bin/smoke.sh" \
28
+ --run-policy every-dev-completion \
29
+ --test-status approved >/dev/null
30
+
31
+ cat >"$ROOT/.codex/context/bad-cases.md" <<'MD'
32
+ # Bad Case Register
33
+
34
+ ## Active Cases
35
+
36
+ - BC-20260709-901 | 状态:resolved | 标签:日期切换, localStorage
37
+ - 现象:第二天打开页面时仍沿用前一天完成状态。
38
+ - 触发:localStorage 只保存勾选状态,不比较日期。
39
+ - 修复:保存日期并在跨天时重置当天状态。
40
+ - 验证:跨天打开后清单恢复待完成。
41
+ - BC-20260709-902 | 状态: resolved | 标题: 部分完成刷新后进度丢失
42
+ - 现象: 勾选两项后刷新,进度回到 0。
43
+ - 触发: 只在最终完成时写入 localStorage。
44
+ - 修复: 每次勾选变化都保存进度。
45
+ - 验证: 刷新后保留已勾选项目。
46
+ - 标签: 日期切换, localStorage
47
+ MD
48
+
49
+ python3 "$SCRIPT" subagent-complete \
50
+ --root "$ROOT" \
51
+ --agent-id "loose-bc-agent" \
52
+ --summary "Subagent wrote loose bad-case register entries." >/tmp/context-guard-loose-bc.out
53
+
54
+ grep -Fq "[context-guard] test hub: 1 passed, 0 failed, 0 blocked." /tmp/context-guard-loose-bc.out
55
+ grep -Fq "created proposed chains: 1" /tmp/context-guard-loose-bc.out
56
+
57
+ python3 - "$ROOT/.codex/context/test-hub/feature-chains.json" <<'PY'
58
+ from pathlib import Path
59
+ import json
60
+ import sys
61
+
62
+ data = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
63
+ chains = data.get("chains", [])
64
+ assert len(chains) == 1, chains
65
+ chain = chains[0]
66
+ assert chain["status"] == "proposed", chain
67
+ assert chain["confirmation_required"] is True, chain
68
+ nodes = chain["nodes"]
69
+ assert len(nodes) == 2, nodes
70
+ refs = [ref for node in nodes for ref in node.get("bad_cases", [])]
71
+ assert refs == ["BC-20260709-901", "BC-20260709-902"], nodes
72
+ titles = [node.get("title", "") for node in nodes]
73
+ checks = [check for node in nodes for check in node.get("checks", [])]
74
+ assert any("部分完成刷新后进度丢失" in item for item in titles), nodes
75
+ assert any("刷新后保留已勾选项目" in item for item in checks), nodes
76
+ PY
@@ -0,0 +1,168 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ ROOT="$(mktemp -d "${TMPDIR:-/tmp}/cg-risk-audit.XXXXXX")"
5
+ trap 'rm -rf "$ROOT"' EXIT
6
+
7
+ SCRIPT="/Users/bytedance/.agents/skills/context-guard/scripts/context_guard.py"
8
+
9
+ python3 "$SCRIPT" init --root "$ROOT" >/dev/null
10
+
11
+ python3 "$SCRIPT" subagent-complete \
12
+ --root "$ROOT" \
13
+ --agent-id "risk-audit-smoke" \
14
+ --summary "加入练习模式、关闭倒计时选项、失败复盘里的逐步回放,以及最高分重置确认;smoke 通过。" \
15
+ >"$ROOT/out-risk.txt"
16
+
17
+ grep -q "risk audit: created bad-case candidate" "$ROOT/out-risk.txt"
18
+ grep -q "risk-audit" "$ROOT/.codex/context/bad-cases.md"
19
+ grep -q "游戏流程.*未验证" "$ROOT/.codex/context/bad-cases.md"
20
+
21
+ python3 "$SCRIPT" subagent-complete \
22
+ --root "$ROOT" \
23
+ --agent-id "risk-audit-duplicate" \
24
+ --summary "加入练习模式、关闭倒计时选项、失败复盘里的逐步回放,以及最高分重置确认;smoke 通过。" \
25
+ >"$ROOT/out-duplicate.txt"
26
+
27
+ grep -q "risk audit: no new bad-case candidate" "$ROOT/out-duplicate.txt"
28
+ if [[ "$(grep -c '^### BC-' "$ROOT/.codex/context/bad-cases.md")" != "1" ]]; then
29
+ echo "duplicate risk-audit summary should not create a second similar bad case" >&2
30
+ exit 1
31
+ fi
32
+
33
+ python3 "$SCRIPT" subagent-complete \
34
+ --root "$ROOT" \
35
+ --agent-id "risk-audit-same-tags-new-step" \
36
+ --summary "继续加入关卡包切换和暂停恢复,失败后展示本轮序列复盘;smoke 通过。" \
37
+ >"$ROOT/out-same-tags-new-step.txt"
38
+
39
+ grep -q "risk audit: created bad-case candidate" "$ROOT/out-same-tags-new-step.txt"
40
+ if [[ "$(grep -c '^### BC-' "$ROOT/.codex/context/bad-cases.md")" != "2" ]]; then
41
+ echo "same-tag but different long-flow step should create another bad case candidate" >&2
42
+ exit 1
43
+ fi
44
+
45
+ python3 "$SCRIPT" subagent-complete \
46
+ --root "$ROOT" \
47
+ --agent-id "risk-audit-distinct" \
48
+ --summary "加入复制结果和导出 Markdown,空输入时显示校验提示;smoke 通过。" \
49
+ >"$ROOT/out-distinct.txt"
50
+
51
+ grep -q "risk audit: created bad-case candidate" "$ROOT/out-distinct.txt"
52
+ if [[ "$(grep -c '^### BC-' "$ROOT/.codex/context/bad-cases.md")" != "3" ]]; then
53
+ echo "distinct risk-audit summary should create a second bad case candidate" >&2
54
+ exit 1
55
+ fi
56
+
57
+ python3 "$SCRIPT" subagent-complete \
58
+ --root "$ROOT" \
59
+ --agent-id "risk-audit-edit-isolation" \
60
+ --summary "新增角色小队的章节计划,重生成单章时不影响其他章节,导出 Markdown 包含章节计划;smoke 通过。" \
61
+ >"$ROOT/out-edit-isolation.txt"
62
+
63
+ grep -q "risk audit: created bad-case candidate" "$ROOT/out-edit-isolation.txt"
64
+ grep -q "局部隔离" "$ROOT/.codex/context/bad-cases.md"
65
+ if [[ "$(grep -c '^### BC-' "$ROOT/.codex/context/bad-cases.md")" != "4" ]]; then
66
+ echo "long-flow edit isolation should create a risk-audit bad case candidate" >&2
67
+ exit 1
68
+ fi
69
+
70
+ ROOT_LOW="$(mktemp -d "${TMPDIR:-/tmp}/cg-risk-audit-low.XXXXXX")"
71
+ trap 'rm -rf "$ROOT" "$ROOT_LOW"' EXIT
72
+ python3 "$SCRIPT" init --root "$ROOT_LOW" >/dev/null
73
+ python3 "$SCRIPT" subagent-complete \
74
+ --root "$ROOT_LOW" \
75
+ --agent-id "risk-audit-low" \
76
+ --summary "更新 README 文案并修正两个错别字;smoke 通过。" \
77
+ >"$ROOT_LOW/out-low.txt"
78
+
79
+ grep -q "risk audit: no new bad-case candidate" "$ROOT_LOW/out-low.txt"
80
+ if grep -q "risk-audit" "$ROOT_LOW/.codex/context/bad-cases.md"; then
81
+ echo "low-risk summary should not create risk-audit bad case" >&2
82
+ exit 1
83
+ fi
84
+
85
+ ROOT_LEGACY="$(mktemp -d "${TMPDIR:-/tmp}/cg-risk-audit-legacy-chain.XXXXXX")"
86
+ trap 'rm -rf "$ROOT" "$ROOT_LOW" "$ROOT_LEGACY"' EXIT
87
+ python3 "$SCRIPT" init --root "$ROOT_LEGACY" >/dev/null
88
+ mkdir -p "$ROOT_LEGACY/.codex/context/test-hub"
89
+ cat >"$ROOT_LEGACY/.codex/context/bad-cases.md" <<'MD'
90
+ # Bad Case Register
91
+
92
+ ## Active Cases
93
+
94
+ ### BC-20260709-101: 状态切换风险未验证
95
+
96
+ - Status: open
97
+ - Scope: 状态切换
98
+ - Tags: #状态流程 #回放 #risk-audit #subagent
99
+ - Display summary: Subagent 本轮开发涉及状态切换和回放,但没有对应功能链节点。
100
+ - Phenomenon: 练习模式和普通模式来回切换后状态可能串线。
101
+ - Trigger / reproduction: 切换练习模式后退出,再继续普通模式。
102
+ - Guard / verification: 运行游戏入口,检查练习模式和普通模式状态互不污染。
103
+
104
+ ### BC-20260709-102: 重置撤销风险未验证
105
+
106
+ - Status: open
107
+ - Scope: 状态切换
108
+ - Tags: #状态流程 #重置 #risk-audit #subagent
109
+ - Display summary: Subagent 本轮开发涉及重置撤销,但没有对应功能链节点。
110
+ - Phenomenon: 重置确认取消后仍可能清空游戏进度。
111
+ - Trigger / reproduction: 点击重置全部进度,再取消确认。
112
+ - Guard / verification: 运行游戏入口,检查取消重置后进度仍保留。
113
+ MD
114
+ cat >"$ROOT_LEGACY/.codex/context/test-hub/feature-chains.json" <<'JSON'
115
+ {
116
+ "version": 1,
117
+ "chains": [
118
+ {
119
+ "id": "FC-20260709-001",
120
+ "title": "Context Guard subagent completion risk audit",
121
+ "status": "proposed",
122
+ "run_policy": "every-dev-completion",
123
+ "entry": "触发内部审计",
124
+ "exit_check": "内部审计通过",
125
+ "command": "",
126
+ "timeout_seconds": 300,
127
+ "artifact_policy": "cleanup-on-pass",
128
+ "resource": "local",
129
+ "created": "2026-07-09",
130
+ "source": "feature-chain-auto-propose",
131
+ "auto_proposed": true,
132
+ "auto_group_key": "#risk-audit|#subagent",
133
+ "confirmation_required": true,
134
+ "nodes": [
135
+ {
136
+ "id": "FC-20260709-001-N1",
137
+ "title": "状态切换风险未验证",
138
+ "bad_cases": ["BC-20260709-101"],
139
+ "checks": ["检查练习模式和普通模式状态互不污染"]
140
+ },
141
+ {
142
+ "id": "FC-20260709-001-N2",
143
+ "title": "重置撤销风险未验证",
144
+ "bad_cases": ["BC-20260709-102"],
145
+ "checks": ["检查取消重置后进度仍保留"]
146
+ }
147
+ ]
148
+ }
149
+ ]
150
+ }
151
+ JSON
152
+
153
+ python3 "$SCRIPT" feature-chain-auto-propose --root "$ROOT_LEGACY" >/tmp/risk-audit-legacy-refresh.out
154
+
155
+ python3 - "$ROOT_LEGACY/.codex/context/test-hub/feature-chains.json" <<'PY'
156
+ from pathlib import Path
157
+ import json
158
+ import sys
159
+
160
+ data = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
161
+ chain = data["chains"][0]
162
+ assert chain["title"] == "状态切换", chain
163
+ assert "risk-audit" not in chain.get("auto_group_key", ""), chain
164
+ assert "subagent" not in chain.get("auto_group_key", ""), chain
165
+ assert "#状态流程" in chain.get("auto_group_key", ""), chain
166
+ assert chain["entry"] == "触发「状态切换」相关用户流程", chain
167
+ assert chain["exit_check"] == "「状态切换」相关结果保持用户可见的正确状态", chain
168
+ PY
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT="${CONTEXT_GUARD_SCRIPT:-$(cd "$(dirname "$0")/.." && pwd)/scripts/context_guard.py}"
5
+ ROOT="$(mktemp -d "${TMPDIR:-/tmp}/context-guard-completion-evidence-XXXXXX")"
6
+ trap 'rm -rf "$ROOT"' EXIT
7
+
8
+ python3 "$SCRIPT" init --root "$ROOT" >/dev/null
9
+ cat >"$ROOT/evidence.txt" <<'TXT'
10
+ 完成了跨空间移动和复制功能。
11
+ CG_BAD_CASE: 跨空间移动会误删同名物品
12
+ CG_PHENOMENON: 把一个物品移动到另一个空间时,源空间里名称相同但 ID 不同的物品也会被删除。
13
+ CG_TRIGGER: 在源空间建立两个同名物品,只移动其中一个。
14
+ CG_CAUSE: 删除源数据时使用名称匹配,而不是本次移动记录的物品 ID。
15
+ CG_FIX: 移动完成后只按本次移动成功的 item.id 删除源物品。
16
+ CG_VERIFICATION: 建立两个同名物品后移动其中一个,目标空间新增一项,源空间仍保留另一项。
17
+ CG_SCOPE: 跨空间复制与移动
18
+ TXT
19
+
20
+ python3 "$SCRIPT" subagent-complete \
21
+ --root "$ROOT" \
22
+ --agent-id "evidence-agent" \
23
+ --summary "完成跨空间移动功能。" \
24
+ --evidence-file "$ROOT/evidence.txt" >"$ROOT/first.out"
25
+
26
+ grep -Fq "completion evidence: archived concrete bad case(s)" "$ROOT/first.out"
27
+ grep -Fq "跨空间移动会误删同名物品" "$ROOT/.codex/context/bad-cases.md"
28
+ grep -Fq -- "- Status: resolved" "$ROOT/.codex/context/bad-cases.md"
29
+ grep -Fq "只按本次移动成功的 item.id 删除源物品" "$ROOT/.codex/context/bad-cases.md"
30
+ if grep -Fq "risk-audit" "$ROOT/.codex/context/bad-cases.md"; then
31
+ echo "concrete completion evidence must win over generic risk audit" >&2
32
+ exit 1
33
+ fi
34
+
35
+ python3 "$SCRIPT" subagent-complete \
36
+ --root "$ROOT" \
37
+ --agent-id "evidence-agent" \
38
+ --summary "完成跨空间移动功能。" \
39
+ --evidence-file "$ROOT/evidence.txt" >"$ROOT/repeat.out"
40
+
41
+ grep -Fq "subagent completion already processed" "$ROOT/repeat.out"
42
+ [[ "$(grep -c '^### BC-' "$ROOT/.codex/context/bad-cases.md")" == "1" ]]
43
+ [[ "$(grep -c 'Subagent completion handoff' "$ROOT/.codex/context/roadmap.md")" == "1" ]]
44
+
45
+ NATURAL_ROOT="$(mktemp -d "${TMPDIR:-/tmp}/context-guard-natural-evidence-XXXXXX")"
46
+ trap 'rm -rf "$ROOT" "$NATURAL_ROOT"' EXIT
47
+ python3 "$SCRIPT" init --root "$NATURAL_ROOT" >/dev/null
48
+ python3 "$SCRIPT" subagent-complete \
49
+ --root "$NATURAL_ROOT" \
50
+ --agent-id "natural-evidence-agent" \
51
+ --summary "修复了跨空间移动会按名称误删同名物品的问题,改为按 item.id 精确删除;验证两个同名物品只移动目标项。" \
52
+ >"$NATURAL_ROOT/out.txt"
53
+
54
+ grep -Fq "completion evidence: archived concrete bad case(s)" "$NATURAL_ROOT/out.txt"
55
+ grep -Fq "跨空间移动会按名称误删同名物品" "$NATURAL_ROOT/.codex/context/bad-cases.md"
56
+ if grep -Fq "risk-audit" "$NATURAL_ROOT/.codex/context/bad-cases.md"; then
57
+ echo "natural concrete repair evidence must not become generic risk audit" >&2
58
+ exit 1
59
+ fi
60
+
61
+ echo "BC-20260710-001 passed"
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
5
+ SCRIPT="${CONTEXT_GUARD_SCRIPT:-$ROOT_DIR/scripts/context_guard.py}"
6
+ HOOK="${CONTEXT_GUARD_HOOK:-$ROOT_DIR/scripts/context_guard_hook.py}"
7
+ BASE="$(mktemp -d "${TMPDIR:-/tmp}/context-guard-subagent-root-XXXXXX")"
8
+ trap 'rm -rf "$BASE"' EXIT
9
+ CONTROL="$BASE/control"
10
+ CHILD="$BASE/child-product"
11
+ mkdir -p "$CONTROL" "$CHILD"
12
+ CONTROL="$(realpath "$CONTROL")"
13
+ CHILD="$(realpath "$CHILD")"
14
+
15
+ cat >"$CHILD/verify.sh" <<'SH'
16
+ #!/usr/bin/env bash
17
+ set -euo pipefail
18
+ test -f product.txt
19
+ grep -Fq "ready" product.txt
20
+ SH
21
+ chmod +x "$CHILD/verify.sh"
22
+ printf 'ready\n' >"$CHILD/product.txt"
23
+
24
+ python3 "$SCRIPT" subagent-register \
25
+ --root "$CONTROL" \
26
+ --agent-id "root-agent" \
27
+ --project-root "$CHILD" \
28
+ --task "完善本地商品流程" >"$BASE/register.out"
29
+
30
+ grep -Fq "subagent project root: $CHILD" "$BASE/register.out"
31
+ python3 "$SCRIPT" test-hub-add \
32
+ --root "$CHILD" \
33
+ --title "商品流程" \
34
+ --command-text "./verify.sh" \
35
+ --run-policy every-dev-completion \
36
+ --test-status approved >/dev/null
37
+
38
+ cat >"$BASE/evidence.txt" <<'TXT'
39
+ CG_BAD_CASE: 商品状态切换后没有保存
40
+ CG_PHENOMENON: 切换商品状态并刷新后,页面恢复旧状态。
41
+ CG_TRIGGER: 修改状态后刷新页面。
42
+ CG_CAUSE: 状态切换没有写入本地存储。
43
+ CG_FIX: 状态变更后立即持久化。
44
+ CG_VERIFICATION: 修改状态后刷新,仍显示新状态。
45
+ CG_SCOPE: 商品状态管理
46
+ TXT
47
+
48
+ python3 - "$CONTROL" "$BASE/evidence.txt" <<'PY' | \
49
+ (cd "$CONTROL" && python3 "$HOOK" subagent-stop) >"$BASE/hook.out" 2>"$BASE/hook.err"
50
+ from pathlib import Path
51
+ import json
52
+ import sys
53
+
54
+ print(json.dumps({
55
+ "agent_id": "root-agent",
56
+ "cwd": sys.argv[1],
57
+ "last_assistant_message": Path(sys.argv[2]).read_text(encoding="utf-8"),
58
+ }, ensure_ascii=False))
59
+ PY
60
+
61
+ grep -Fq "project root: $CHILD" "$BASE/hook.err"
62
+ grep -Fq "test hub: 1 passed, 0 failed, 0 blocked" "$BASE/hook.err"
63
+ test -f "$CHILD/.codex/context/test-hub/last-run.json"
64
+ grep -Fq "completion evidence: archived concrete bad case(s)" "$BASE/hook.err"
65
+
66
+ python3 "$SCRIPT" subagent-complete \
67
+ --root "$CONTROL" \
68
+ --agent-id "root-agent" \
69
+ --evidence-file "$BASE/evidence.txt" >"$BASE/complete.out"
70
+
71
+ grep -Fq "subagent project root: $CHILD" "$BASE/complete.out"
72
+ grep -Fq "subagent completion already processed" "$BASE/complete.out"
73
+ grep -Fq "商品状态切换后没有保存" "$CHILD/.codex/context/bad-cases.md"
74
+ grep -Fq "Subagent completion handoff" "$CHILD/.codex/context/roadmap.md"
75
+ [[ "$(grep -c 'Subagent completion handoff' "$CHILD/.codex/context/roadmap.md")" == "1" ]]
76
+ [[ "$(grep -c '^### BC-' "$CHILD/.codex/context/bad-cases.md")" == "1" ]]
77
+ if grep -Fq "Subagent completion handoff" "$CONTROL/.codex/context/roadmap.md"; then
78
+ echo "completion checkpoint leaked into the control workspace" >&2
79
+ exit 1
80
+ fi
81
+
82
+ python3 - "$CONTROL/.codex/context/subagents/assignments.json" "$CHILD" <<'PY'
83
+ from pathlib import Path
84
+ import json
85
+ import sys
86
+
87
+ data = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
88
+ item = data["assignments"]["root-agent"]
89
+ assert item["project_root"] == sys.argv[2], item
90
+ assert item["status"] == "completed", item
91
+ assert item["last_test_code"] == 0, item
92
+ PY
93
+
94
+ python3 "$SCRIPT" subagent-register \
95
+ --root "$CONTROL" \
96
+ --agent-id "root-agent" \
97
+ --project-root "$CHILD" \
98
+ --task "继续下一轮商品流程" >/dev/null
99
+
100
+ python3 - "$CONTROL/.codex/context/subagents/assignments.json" <<'PY'
101
+ from pathlib import Path
102
+ import json
103
+ import sys
104
+
105
+ item = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))["assignments"]["root-agent"]
106
+ assert item["status"] == "running", item
107
+ assert item["last_test_code"] == 0, item
108
+ assert item.get("last_completion_fingerprint"), item
109
+ PY
110
+
111
+ echo "BC-20260710-002 passed"
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ ROOT="$(mktemp -d "${TMPDIR:-/tmp}/context-guard-npm-install-XXXXXX")"
5
+ ROOT="$(cd "$ROOT" && pwd)"
6
+ trap 'rm -rf "$ROOT"' EXIT
7
+ NODE_BIN="${NODE:-node}"
8
+
9
+ SKILL_COUNT="$(find . -path './.git' -prune -o -name SKILL.md -print | wc -l | tr -d '[:space:]')"
10
+ test "$SKILL_COUNT" = "1"
11
+
12
+ "$NODE_BIN" bin/context-guard-skill.js --help >/dev/null
13
+ "$NODE_BIN" bin/context-guard-skill.js install --target "$ROOT/skill" >/dev/null
14
+
15
+ test -f "$ROOT/skill/SKILL.md"
16
+ test -f "$ROOT/skill/scripts/context_guard.py"
17
+ test -f "$ROOT/skill/README.zh-CN.md"
18
+ INSTALLED_SKILL_COUNT="$(find "$ROOT/skill" -name SKILL.md -print | wc -l | tr -d '[:space:]')"
19
+ test "$INSTALLED_SKILL_COUNT" = "1"
20
+
21
+ CODEX_HOME="$ROOT/codex-home" "$NODE_BIN" bin/context-guard-skill.js install >/dev/null
22
+ test -f "$ROOT/codex-home/skills/context-guard/SKILL.md"
23
+
24
+ npm_config_global=true CODEX_HOME="$ROOT/global-codex-home" "$NODE_BIN" bin/postinstall.js >/dev/null
25
+ test -f "$ROOT/global-codex-home/skills/context-guard/SKILL.md"
26
+
27
+ PROJECT="$ROOT/project"
28
+ "$NODE_BIN" bin/context-guard-skill.js init --root "$PROJECT" >/dev/null
29
+ test -f "$PROJECT/.codex/context/index.md"
30
+
31
+ HOOKS="$ROOT/hooks.json"
32
+ CONFIG="$ROOT/config.toml"
33
+ cat >"$CONFIG" <<'EOF'
34
+ [features]
35
+ codex_hooks = true
36
+ multi_agent = true
37
+
38
+ [model]
39
+ name = "test"
40
+ EOF
41
+ "$NODE_BIN" bin/context-guard-skill.js install --target "$ROOT/skill-with-hooks" --with-hooks --hooks-target "$HOOKS" >/dev/null
42
+ grep -Fq "$ROOT/skill-with-hooks/scripts/context_guard_hook.py" "$HOOKS"
43
+ grep -Fq '"SubagentStart"' "$HOOKS"
44
+ grep -Fq '"SubagentStop"' "$HOOKS"
45
+ grep -Fq 'hooks = true' "$CONFIG"
46
+ grep -Fq 'multi_agent = true' "$CONFIG"
47
+ grep -Fq 'name = "test"' "$CONFIG"
48
+ ! grep -Fq 'codex_hooks' "$CONFIG"
49
+
50
+ EMPTY_HOME="$ROOT/empty-codex-home"
51
+ CODEX_HOME="$EMPTY_HOME" "$NODE_BIN" bin/context-guard-skill.js install --with-hooks >/dev/null
52
+ grep -Fq '[features]' "$EMPTY_HOME/config.toml"
53
+ grep -Fq 'hooks = true' "$EMPTY_HOME/config.toml"