cleargate 0.14.0 → 0.15.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 (149) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/MANIFEST.json +71 -15
  3. package/dist/admin-api/index.cjs +0 -1
  4. package/dist/admin-api/index.js +1 -2
  5. package/dist/auth/factory.cjs +0 -1
  6. package/dist/auth/factory.js +2 -3
  7. package/dist/auth/require-token.cjs +0 -1
  8. package/dist/auth/require-token.js +1 -2
  9. package/dist/auth/token-store.cjs +0 -1
  10. package/dist/auth/token-store.js +1 -2
  11. package/dist/{bootstrap-root-QKSA5V75.js → bootstrap-root-2H5HVTCC.js} +1 -2
  12. package/dist/{chunk-PDE37WFQ.js → chunk-A7MSQUU7.js} +2 -3
  13. package/dist/{chunk-BTSZOEWC.js → chunk-P6KEDAK2.js} +0 -1
  14. package/dist/{chunk-E3X7IE5E.js → chunk-PY6FHGV5.js} +1 -2
  15. package/dist/{chunk-5DI2Z3C2.js → chunk-Y53ZZYYU.js} +1 -2
  16. package/dist/cli.cjs +1564 -1414
  17. package/dist/cli.js +1514 -1364
  18. package/dist/lib/ledger.cjs +0 -1
  19. package/dist/lib/ledger.js +1 -2
  20. package/dist/lib/lifecycle-reconcile.cjs +0 -1
  21. package/dist/lib/lifecycle-reconcile.js +2 -3
  22. package/dist/{whoami-EANGN46Z.js → whoami-JKQQPABQ.js} +3 -4
  23. package/package.json +4 -3
  24. package/templates/cleargate-planning/.claude/agents/architect.md +4 -2
  25. package/templates/cleargate-planning/.claude/agents/developer.md +4 -11
  26. package/templates/cleargate-planning/.claude/agents/qa.md +14 -6
  27. package/templates/cleargate-planning/.claude/hooks/pending-task-sentinel.sh +2 -2
  28. package/templates/cleargate-planning/.claude/skills/sprint-execution/SKILL.md +19 -1
  29. package/templates/cleargate-planning/.cleargate/config.example.yml +16 -0
  30. package/templates/cleargate-planning/.cleargate/scripts/close_sprint.deferred-verify.red.node.test.ts +245 -0
  31. package/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +227 -0
  32. package/templates/cleargate-planning/.cleargate/scripts/gate-checks.json +5 -4
  33. package/templates/cleargate-planning/.cleargate/scripts/init_sprint.mjs +75 -2
  34. package/templates/cleargate-planning/.cleargate/scripts/pre_gate_common.sh +48 -0
  35. package/templates/cleargate-planning/.cleargate/scripts/pre_gate_runner.sh +57 -1
  36. package/templates/cleargate-planning/.cleargate/scripts/provision_worktree_config.sh +155 -0
  37. package/templates/cleargate-planning/.cleargate/scripts/qa_red_lint.mjs +380 -0
  38. package/templates/cleargate-planning/.cleargate/scripts/run_script.sh +34 -1
  39. package/templates/cleargate-planning/.cleargate/scripts/test/cr077_eviction.red.sh +113 -0
  40. package/templates/cleargate-planning/.cleargate/scripts/test/cr078_init.test.sh +309 -0
  41. package/templates/cleargate-planning/.cleargate/scripts/test/cr079_provision.red.sh +262 -0
  42. package/templates/cleargate-planning/.cleargate/scripts/test/cr080_wrapper.test.sh +177 -0
  43. package/templates/cleargate-planning/.cleargate/scripts/test/cr081_qa_red_lint.red.sh +348 -0
  44. package/templates/cleargate-planning/.cleargate/sprint-runs/_off-sprint/.session-totals.json +1 -0
  45. package/templates/cleargate-planning/.cleargate/sprint-runs/_off-sprint/token-ledger.jsonl +27 -0
  46. package/templates/cleargate-planning/.cleargate/templates/sprint_context.md +17 -0
  47. package/templates/cleargate-planning/.cleargate/templates/story.md +1 -0
  48. package/templates/cleargate-planning/MANIFEST.json +71 -15
  49. package/dist/admin-api/index.cjs.map +0 -1
  50. package/dist/admin-api/index.js.map +0 -1
  51. package/dist/auth/factory.cjs.map +0 -1
  52. package/dist/auth/factory.js.map +0 -1
  53. package/dist/auth/require-token.cjs.map +0 -1
  54. package/dist/auth/require-token.js.map +0 -1
  55. package/dist/auth/token-store.cjs.map +0 -1
  56. package/dist/auth/token-store.js.map +0 -1
  57. package/dist/bootstrap-root-QKSA5V75.js.map +0 -1
  58. package/dist/chunk-5DI2Z3C2.js.map +0 -1
  59. package/dist/chunk-BTSZOEWC.js.map +0 -1
  60. package/dist/chunk-E3X7IE5E.js.map +0 -1
  61. package/dist/chunk-PDE37WFQ.js.map +0 -1
  62. package/dist/cli.cjs.map +0 -1
  63. package/dist/cli.js.map +0 -1
  64. package/dist/lib/ledger.cjs.map +0 -1
  65. package/dist/lib/ledger.js.map +0 -1
  66. package/dist/lib/lifecycle-reconcile.cjs.map +0 -1
  67. package/dist/lib/lifecycle-reconcile.js.map +0 -1
  68. package/dist/templates/cleargate-planning/.claude/agents/architect-reader.md +0 -61
  69. package/dist/templates/cleargate-planning/.claude/agents/architect-synth.md +0 -124
  70. package/dist/templates/cleargate-planning/.claude/agents/architect.md +0 -230
  71. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-contradict.md +0 -108
  72. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-ingest.md +0 -194
  73. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-lint.md +0 -261
  74. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-query.md +0 -143
  75. package/dist/templates/cleargate-planning/.claude/agents/developer.md +0 -185
  76. package/dist/templates/cleargate-planning/.claude/agents/devops.md +0 -257
  77. package/dist/templates/cleargate-planning/.claude/agents/qa.md +0 -171
  78. package/dist/templates/cleargate-planning/.claude/agents/reporter.md +0 -274
  79. package/dist/templates/cleargate-planning/.claude/hooks/pending-task-sentinel.sh +0 -209
  80. package/dist/templates/cleargate-planning/.claude/hooks/pre-commit-surface-gate.sh +0 -33
  81. package/dist/templates/cleargate-planning/.claude/hooks/pre-commit-test-ratchet.sh +0 -58
  82. package/dist/templates/cleargate-planning/.claude/hooks/pre-commit.sh +0 -19
  83. package/dist/templates/cleargate-planning/.claude/hooks/pre-edit-gate.sh +0 -162
  84. package/dist/templates/cleargate-planning/.claude/hooks/pre-tool-use-autonomy.sh +0 -58
  85. package/dist/templates/cleargate-planning/.claude/hooks/pre-tool-use-task.sh +0 -148
  86. package/dist/templates/cleargate-planning/.claude/hooks/session-start.sh +0 -75
  87. package/dist/templates/cleargate-planning/.claude/hooks/stamp-and-gate.sh +0 -43
  88. package/dist/templates/cleargate-planning/.claude/hooks/token-ledger.sh +0 -590
  89. package/dist/templates/cleargate-planning/.claude/settings.json +0 -68
  90. package/dist/templates/cleargate-planning/.claude/skills/flashcard/SKILL.md +0 -102
  91. package/dist/templates/cleargate-planning/.claude/skills/sprint-execution/SKILL.md +0 -742
  92. package/dist/templates/cleargate-planning/.cleargate/FLASHCARD.md +0 -7
  93. package/dist/templates/cleargate-planning/.cleargate/config.example.yml +0 -67
  94. package/dist/templates/cleargate-planning/.cleargate/config.yml +0 -18
  95. package/dist/templates/cleargate-planning/.cleargate/delivery/archive/.gitkeep +0 -0
  96. package/dist/templates/cleargate-planning/.cleargate/delivery/pending-sync/.gitkeep +0 -0
  97. package/dist/templates/cleargate-planning/.cleargate/knowledge/cleargate-enforcement.md +0 -551
  98. package/dist/templates/cleargate-planning/.cleargate/knowledge/cleargate-protocol.md +0 -878
  99. package/dist/templates/cleargate-planning/.cleargate/knowledge/mid-sprint-triage-rubric.md +0 -160
  100. package/dist/templates/cleargate-planning/.cleargate/knowledge/readiness-gates.md +0 -213
  101. package/dist/templates/cleargate-planning/.cleargate/knowledge/sprint-closeout-checklist.md +0 -71
  102. package/dist/templates/cleargate-planning/.cleargate/scripts/_migrate-schema-v3.mjs +0 -120
  103. package/dist/templates/cleargate-planning/.cleargate/scripts/assert_story_files.mjs +0 -265
  104. package/dist/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +0 -1012
  105. package/dist/templates/cleargate-planning/.cleargate/scripts/collision_surface.sh +0 -114
  106. package/dist/templates/cleargate-planning/.cleargate/scripts/constants.mjs +0 -62
  107. package/dist/templates/cleargate-planning/.cleargate/scripts/dedupe_frontmatter.mjs +0 -219
  108. package/dist/templates/cleargate-planning/.cleargate/scripts/file_surface_diff.sh +0 -320
  109. package/dist/templates/cleargate-planning/.cleargate/scripts/gate-checks.json +0 -15
  110. package/dist/templates/cleargate-planning/.cleargate/scripts/init_gate_config.sh +0 -38
  111. package/dist/templates/cleargate-planning/.cleargate/scripts/init_sprint.mjs +0 -240
  112. package/dist/templates/cleargate-planning/.cleargate/scripts/launch_wave.mjs +0 -341
  113. package/dist/templates/cleargate-planning/.cleargate/scripts/lib/report-filename.mjs +0 -54
  114. package/dist/templates/cleargate-planning/.cleargate/scripts/pre_gate_common.sh +0 -206
  115. package/dist/templates/cleargate-planning/.cleargate/scripts/pre_gate_runner.sh +0 -371
  116. package/dist/templates/cleargate-planning/.cleargate/scripts/prefill_report.mjs +0 -280
  117. package/dist/templates/cleargate-planning/.cleargate/scripts/prep_doc_refresh.mjs +0 -378
  118. package/dist/templates/cleargate-planning/.cleargate/scripts/prep_qa_context.mjs +0 -888
  119. package/dist/templates/cleargate-planning/.cleargate/scripts/run_script.sh +0 -209
  120. package/dist/templates/cleargate-planning/.cleargate/scripts/sprint_trends.mjs +0 -71
  121. package/dist/templates/cleargate-planning/.cleargate/scripts/state.schema.json +0 -127
  122. package/dist/templates/cleargate-planning/.cleargate/scripts/suggest_improvements.mjs +0 -717
  123. package/dist/templates/cleargate-planning/.cleargate/scripts/surface-whitelist.txt +0 -27
  124. package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_assert_story_files.sh +0 -261
  125. package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_file_surface.sh +0 -210
  126. package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_flashcard_gate.sh +0 -190
  127. package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_prep_qa_context.sh +0 -482
  128. package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_test_ratchet.sh +0 -327
  129. package/dist/templates/cleargate-planning/.cleargate/scripts/test_ratchet.mjs +0 -261
  130. package/dist/templates/cleargate-planning/.cleargate/scripts/update_state.mjs +0 -246
  131. package/dist/templates/cleargate-planning/.cleargate/scripts/validate_bounce_readiness.mjs +0 -111
  132. package/dist/templates/cleargate-planning/.cleargate/scripts/validate_state.mjs +0 -184
  133. package/dist/templates/cleargate-planning/.cleargate/scripts/write_dispatch.sh +0 -172
  134. package/dist/templates/cleargate-planning/.cleargate/templates/Bug.md +0 -126
  135. package/dist/templates/cleargate-planning/.cleargate/templates/CR.md +0 -130
  136. package/dist/templates/cleargate-planning/.cleargate/templates/Sprint Plan Template.md +0 -137
  137. package/dist/templates/cleargate-planning/.cleargate/templates/epic.md +0 -166
  138. package/dist/templates/cleargate-planning/.cleargate/templates/hotfix.md +0 -111
  139. package/dist/templates/cleargate-planning/.cleargate/templates/initiative.md +0 -122
  140. package/dist/templates/cleargate-planning/.cleargate/templates/sprint_context.md +0 -50
  141. package/dist/templates/cleargate-planning/.cleargate/templates/sprint_report.md +0 -224
  142. package/dist/templates/cleargate-planning/.cleargate/templates/story.md +0 -213
  143. package/dist/templates/cleargate-planning/CLAUDE.md +0 -66
  144. package/dist/templates/cleargate-planning/MANIFEST.json +0 -503
  145. package/dist/templates/synthesis/active-sprint.md +0 -30
  146. package/dist/templates/synthesis/open-gates.md +0 -38
  147. package/dist/templates/synthesis/product-state.md +0 -31
  148. package/dist/templates/synthesis/roadmap.md +0 -63
  149. package/dist/whoami-EANGN46Z.js.map +0 -1
@@ -1,162 +0,0 @@
1
- #!/usr/bin/env bash
2
- # pre-edit-gate.sh — CR-008 Phase B: planning-first PreToolUse gate
3
- #
4
- # Registered as a PreToolUse hook for Edit|Write tool calls.
5
- # In warn mode (default), logs would-block decisions but always exits 0.
6
- # In enforce mode, exits 1 to block the tool call when planning is missing.
7
- #
8
- # Mode controlled by CLEARGATE_PLANNING_GATE_MODE (warn|enforce|off). Default: warn.
9
- # Bypass: CLEARGATE_PLANNING_BYPASS=1 → skip check, log bypass=true, exit 0.
10
-
11
- set -u
12
-
13
- REPO_ROOT="${CLAUDE_PROJECT_DIR:-$(pwd)}"
14
- MODE="${CLEARGATE_PLANNING_GATE_MODE:-warn}"
15
- LOG_FILE="${REPO_ROOT}/.cleargate/hook-log/pre-edit-gate-warn.log"
16
-
17
- # ── 0. Off mode — do nothing ──────────────────────────────────────────────────
18
- if [ "${MODE}" = "off" ]; then
19
- exit 0
20
- fi
21
-
22
- # ── 1. Read file path from stdin (PreToolUse JSON payload) ────────────────────
23
- # Claude Code sends JSON on stdin: {"tool_name":"Edit","tool_input":{"file_path":"..."}}
24
- INPUT=$(cat)
25
- FILE=$(printf '%s' "${INPUT}" | node -e "
26
- try {
27
- var d = require('fs').readFileSync('/dev/stdin','utf8');
28
- var o = JSON.parse(d);
29
- var fp = (o.tool_input && o.tool_input.file_path) ? o.tool_input.file_path : '';
30
- process.stdout.write(fp);
31
- } catch(e) {
32
- process.stdout.write('');
33
- }
34
- " 2>/dev/null || true)
35
-
36
- TOOL_NAME=$(printf '%s' "${INPUT}" | node -e "
37
- try {
38
- var d = require('fs').readFileSync('/dev/stdin','utf8');
39
- var o = JSON.parse(d);
40
- process.stdout.write(o.tool_name || '');
41
- } catch(e) {
42
- process.stdout.write('');
43
- }
44
- " 2>/dev/null || true)
45
-
46
- # ── Guard: if we couldn't parse the file path, fail-open ──────────────────────
47
- if [ -z "${FILE}" ]; then
48
- exit 0
49
- fi
50
-
51
- # ── 2. Bypass env var ─────────────────────────────────────────────────────────
52
- if [ "${CLEARGATE_PLANNING_BYPASS:-0}" = "1" ]; then
53
- ISO_TS=$(date -u +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || date -u +"%Y-%m-%dT%H:%M:%SZ")
54
- mkdir -p "$(dirname "${LOG_FILE}")"
55
- printf '[%s] mode=%s bypass=true file=%s\n' "${ISO_TS}" "${MODE}" "${FILE}" >> "${LOG_FILE}"
56
- exit 0
57
- fi
58
-
59
- # ── 3. Whitelist: always allow these paths ────────────────────────────────────
60
- # Normalise: strip leading REPO_ROOT prefix for matching
61
- REL_FILE="${FILE}"
62
- if [[ "${FILE}" == "${REPO_ROOT}/"* ]]; then
63
- REL_FILE="${FILE#${REPO_ROOT}/}"
64
- fi
65
-
66
- is_whitelisted() {
67
- local f="$1"
68
- # Exact or prefix matches for whitelisted directories/files
69
- case "${f}" in
70
- .cleargate/*|.claude/*|cleargate-planning/*) return 0 ;;
71
- CLAUDE.md|MANIFEST.json|README.md|.gitignore|.gitkeep) return 0 ;;
72
- package.json|package-lock.json) return 0 ;;
73
- .env|.env.*|.npmrc|.editorconfig) return 0 ;;
74
- # Also allow absolute paths that fall under the repo's cleargate dirs
75
- esac
76
- # Check absolute path variants
77
- case "${FILE}" in
78
- "${REPO_ROOT}/.cleargate/"*|"${REPO_ROOT}/.claude/"*|"${REPO_ROOT}/cleargate-planning/"*) return 0 ;;
79
- esac
80
- return 1
81
- }
82
-
83
- if is_whitelisted "${REL_FILE}"; then
84
- exit 0
85
- fi
86
-
87
- # ── 3.5 Sprint-active sentinel bypass ────────────────────────────────────────
88
- # If a sprint is actively running, all in-sprint edits bypass the gate.
89
- if [ -f "${REPO_ROOT}/.cleargate/sprint-runs/.active" ]; then
90
- exit 0
91
- fi
92
-
93
- # ── 4. Resolve cleargate CLI (three-branch resolver — CR-009) ────────────────
94
- if [ -f "${REPO_ROOT}/cleargate-cli/dist/cli.js" ]; then
95
- CG=(node "${REPO_ROOT}/cleargate-cli/dist/cli.js")
96
- elif command -v cleargate >/dev/null 2>&1; then
97
- CG=(cleargate)
98
- else
99
- # Read pinned version from stamp-and-gate.sh
100
- HOOK_PIN=""
101
- HOOK_SH="${REPO_ROOT}/.claude/hooks/stamp-and-gate.sh"
102
- if [ -f "${HOOK_SH}" ]; then
103
- HOOK_PIN=$(grep -oP '(?<=# cleargate-pin: )[\S]+' "${HOOK_SH}" 2>/dev/null || \
104
- grep -oE 'cleargate@[^"]+' "${HOOK_SH}" 2>/dev/null | head -1 | sed 's/.*@//' || true)
105
- fi
106
- if [ -z "${HOOK_PIN}" ]; then
107
- HOOK_PIN="__CLEARGATE_VERSION__"
108
- fi
109
- CG=(npx -y "cleargate@${HOOK_PIN}")
110
- fi
111
-
112
- # ── 5. Read user prompt snippet for log context (optional; best-effort) ───────
113
- PROMPT_SNIPPET=$(printf '%s' "${INPUT}" | node -e "
114
- try {
115
- var d = require('fs').readFileSync('/dev/stdin','utf8');
116
- var o = JSON.parse(d);
117
- var p = (o.user_prompt || '').slice(0, 200);
118
- process.stdout.write(p);
119
- } catch(e) {
120
- process.stdout.write('');
121
- }
122
- " 2>/dev/null || true)
123
-
124
- # ── 6. Ask doctor --can-edit ──────────────────────────────────────────────────
125
- # Capture both stdout AND exit code without || true swallowing the exit code.
126
- _DOCTOR_TMPFILE=$(mktemp)
127
- "${CG[@]}" doctor --can-edit "${FILE}" --cwd "${REPO_ROOT}" > "${_DOCTOR_TMPFILE}" 2>/dev/null
128
- DOCTOR_EXIT=$?
129
- DOCTOR_OUT=$(cat "${_DOCTOR_TMPFILE}")
130
- rm -f "${_DOCTOR_TMPFILE}"
131
-
132
- # Parse reason from doctor output
133
- REASON=$(printf '%s' "${DOCTOR_OUT}" | grep -oP '(?<=blocked: )\S+' 2>/dev/null || \
134
- printf '%s' "${DOCTOR_OUT}" | sed -n 's/blocked: //p' 2>/dev/null || \
135
- echo "unknown")
136
-
137
- # Count approved stories in pending-sync (for log entry)
138
- PENDING_DIR="${REPO_ROOT}/.cleargate/delivery/pending-sync"
139
- PENDING_MATCH_COUNT=0
140
- if [ -d "${PENDING_DIR}" ]; then
141
- PENDING_MATCH_COUNT=$(grep -rl 'approved: true' "${PENDING_DIR}" 2>/dev/null | wc -l | tr -d ' ' || echo "0")
142
- fi
143
-
144
- # ── 7. Gate decision ──────────────────────────────────────────────────────────
145
- if [ "${DOCTOR_EXIT}" -ne 0 ]; then
146
- # Would block
147
- ISO_TS=$(date -u +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || date -u +"%Y-%m-%dT%H:%M:%SZ")
148
- mkdir -p "$(dirname "${LOG_FILE}")"
149
- printf '[%s] mode=%s would_block file=%s reason=%s tool=%s pending_match_count=%d prompt_snippet=%s\n' \
150
- "${ISO_TS}" "${MODE}" "${FILE}" "${REASON}" "${TOOL_NAME}" "${PENDING_MATCH_COUNT}" "${PROMPT_SNIPPET}" \
151
- >> "${LOG_FILE}"
152
-
153
- if [ "${MODE}" = "enforce" ]; then
154
- printf 'ClearGate: planning-first gate — no approved story covers %s (%s). Draft a work item first.\n' \
155
- "${FILE}" "${REASON}" >&2
156
- exit 1
157
- fi
158
-
159
- # warn mode: log written above, exit 0 (do not block)
160
- fi
161
-
162
- exit 0
@@ -1,58 +0,0 @@
1
- #!/usr/bin/env bash
2
- # pre-tool-use-autonomy.sh — PreToolUse:AskUserQuestion soft-warning hook (STORY-071-01)
3
- #
4
- # CR-071: Logs a warning when an agent issues AskUserQuestion during an active sprint.
5
- # Soft mode — ALWAYS exits 0 (never blocks the call). Observability only.
6
- #
7
- # Inputs:
8
- # stdin: Claude Code PreToolUse JSON payload with tool_name, tool_input, etc.
9
- # env: CLAUDE_PROJECT_DIR (project root; fallback to current dir)
10
- #
11
- # Output:
12
- # Appends to .cleargate/hook-log/autonomy-warnings.log when conditions are met.
13
- # Tab-separated columns: <iso-timestamp>\tAskUserQuestion\t<agent>\t<question-summary>
14
- #
15
- # Conditions for logging:
16
- # 1. tool_name == "AskUserQuestion"
17
- # 2. .cleargate/sprint-runs/.active exists and is non-empty
18
- # 3. corresponding state.json sprint_status == "Active"
19
- #
20
- # Exit code: 0 always (soft mode — never blocks).
21
-
22
- set -u
23
-
24
- PAYLOAD="$(cat 2>/dev/null || true)"
25
-
26
- # If jq is absent, degrade gracefully (exit 0, no log).
27
- if ! command -v jq >/dev/null 2>&1; then
28
- exit 0
29
- fi
30
-
31
- TOOL=$(printf '%s' "$PAYLOAD" | jq -r '.tool_name // empty' 2>/dev/null || true)
32
- [ "$TOOL" = "AskUserQuestion" ] || exit 0
33
-
34
- ACTIVE_FILE="${CLAUDE_PROJECT_DIR:-.}/.cleargate/sprint-runs/.active"
35
- [ -s "$ACTIVE_FILE" ] || exit 0
36
-
37
- SPRINT_ID="$(cat "$ACTIVE_FILE" 2>/dev/null || true)"
38
- [ -n "$SPRINT_ID" ] || exit 0
39
-
40
- STATE_FILE="${CLAUDE_PROJECT_DIR:-.}/.cleargate/sprint-runs/$SPRINT_ID/state.json"
41
- [ -f "$STATE_FILE" ] || exit 0
42
-
43
- STATUS=$(jq -r '.sprint_status // empty' "$STATE_FILE" 2>/dev/null || true)
44
- [ "$STATUS" = "Active" ] || exit 0
45
-
46
- LOG="${CLAUDE_PROJECT_DIR:-.}/.cleargate/hook-log/autonomy-warnings.log"
47
- mkdir -p "$(dirname "$LOG")" 2>/dev/null || true
48
-
49
- QUESTION_SUMMARY=$(printf '%s' "$PAYLOAD" | jq -r '.tool_input.question // ""' 2>/dev/null | head -c 200 || true)
50
-
51
- DISPATCH_DIR="${CLAUDE_PROJECT_DIR:-.}/.cleargate/sprint-runs/$SPRINT_ID"
52
- AGENT=$(ls -t "$DISPATCH_DIR"/.dispatch-*.json 2>/dev/null | head -1 | \
53
- xargs -I {} jq -r '.agent // "unknown"' {} 2>/dev/null || echo "unknown")
54
- [ -n "$AGENT" ] || AGENT="unknown"
55
-
56
- printf '%s\tAskUserQuestion\t%s\t%s\n' "$(date -u +%FT%TZ)" "$AGENT" "$QUESTION_SUMMARY" >> "$LOG" 2>/dev/null || true
57
-
58
- exit 0
@@ -1,148 +0,0 @@
1
- #!/usr/bin/env bash
2
- # pre-tool-use-task.sh — PreToolUse:Task hook.
3
- #
4
- # CR-026: Auto-write a dispatch marker on every Task() spawn so the
5
- # SubagentStop hook (token-ledger.sh) can attribute tokens to the correct
6
- # work item and agent without relying on transcript-grep heuristics.
7
- #
8
- # This hook addresses BUG-024 §3.1 Defect 3: manual write_dispatch.sh calls
9
- # were unreliable (~5 calls vs ~19 spawns in SPRINT-18). The hook fires
10
- # automatically on every Task() spawn inside the orchestrator session.
11
- #
12
- # Input: JSON on stdin from Claude Code with fields:
13
- # session_id, transcript_path, cwd, hook_event_name, tool_name, tool_input
14
- # For tool_name == "Task", tool_input has: subagent_type, description, prompt.
15
- #
16
- # Output: writes .cleargate/sprint-runs/<sprint>/.dispatch-<ts>-<pid>-<rand>.json
17
- # with { work_item_id, agent_type, spawned_at, session_id, writer }
18
- # Uniquified filename prevents collision under parallel Task() spawns.
19
- # SubagentStop hook uses newest-file lookup (ls -t) to consume it.
20
- #
21
- # Log: .cleargate/hook-log/pre-tool-use-task.log
22
- #
23
- # Exit code: 0 always. Never blocks a Task spawn.
24
- #
25
- # Banner-immunity: reads tool_input.prompt directly from the JSON payload —
26
- # no transcript involvement, so the SessionStart blocked-items banner cannot
27
- # poison this path (contrast with token-ledger.sh's transcript-grep fallback).
28
-
29
- set -u
30
-
31
- # ─── Resolve repo root (matches token-ledger.sh:59 + write_dispatch.sh:30) ───
32
- REPO_ROOT="${ORCHESTRATOR_PROJECT_DIR:-${CLAUDE_PROJECT_DIR}}"
33
- LOG_DIR="${REPO_ROOT}/.cleargate/hook-log"
34
- mkdir -p "${LOG_DIR}"
35
- HOOK_LOG="${LOG_DIR}/pre-tool-use-task.log"
36
- ACTIVE_SENTINEL="${REPO_ROOT}/.cleargate/sprint-runs/.active"
37
-
38
- TS="$(date -u +%FT%TZ)"
39
-
40
- # Read stdin once
41
- INPUT="$(cat)"
42
-
43
- # ─── Extract tool_name to confirm this is a Task spawn ────────────────────────
44
- TOOL_NAME="$(printf '%s' "${INPUT}" | jq -r '.tool_name // empty' 2>/dev/null)"
45
- if [[ "${TOOL_NAME}" != "Task" ]]; then
46
- # Not a Task spawn — nothing to do; exit silently.
47
- exit 0
48
- fi
49
-
50
- # ─── Resolve active sprint via sentinel ───────────────────────────────────────
51
- if [[ ! -f "${ACTIVE_SENTINEL}" ]]; then
52
- printf '[%s] no .active sentinel — dispatch marker skipped (off-sprint)\n' "${TS}" >> "${HOOK_LOG}"
53
- exit 0
54
- fi
55
-
56
- SPRINT_ID="$(tr -d '[:space:]' < "${ACTIVE_SENTINEL}")"
57
- if [[ -z "${SPRINT_ID}" ]]; then
58
- printf '[%s] .active sentinel is empty — dispatch marker skipped\n' "${TS}" >> "${HOOK_LOG}"
59
- exit 0
60
- fi
61
-
62
- SPRINT_DIR="${REPO_ROOT}/.cleargate/sprint-runs/${SPRINT_ID}"
63
- mkdir -p "${SPRINT_DIR}"
64
-
65
- # ─── Extract subagent_type ────────────────────────────────────────────────────
66
- AGENT_TYPE="$(printf '%s' "${INPUT}" | jq -r '.tool_input.subagent_type // empty' 2>/dev/null)"
67
- ALLOW_LIST="architect developer qa reporter cleargate-wiki-contradict"
68
- if [[ -z "${AGENT_TYPE}" ]] || ! printf '%s\n' ${ALLOW_LIST} | grep -qxF "${AGENT_TYPE}"; then
69
- printf '[%s] no marker: agent_type absent or not in allow-list (%s)\n' "${TS}" "${AGENT_TYPE:-<empty>}" >> "${HOOK_LOG}"
70
- exit 0
71
- fi
72
-
73
- # ─── Extract work_item_id from first 5 lines of tool_input.prompt ─────────────
74
- # Regex: (STORY=?NNN-NN | BUG-NNN | EPIC-NNN | CR-NNN | PROPOSAL-NNN | HOTFIX-NNN)
75
- PROMPT_HEAD="$(printf '%s' "${INPUT}" | jq -r '.tool_input.prompt // ""' 2>/dev/null | head -5)"
76
- if [[ -z "${PROMPT_HEAD}" ]]; then
77
- printf '[%s] no marker: prompt empty or unreadable\n' "${TS}" >> "${HOOK_LOG}"
78
- exit 0
79
- fi
80
-
81
- WORK_ITEM_RAW="$(printf '%s' "${PROMPT_HEAD}" \
82
- | grep -oE '(STORY=?[0-9]{3}-[0-9]{2}|BUG-[0-9]+|EPIC-[0-9]+|CR-[0-9]+|PROPOSAL-[0-9]+|HOTFIX-[0-9]+)' \
83
- | head -1)"
84
-
85
- if [[ -z "${WORK_ITEM_RAW}" ]]; then
86
- printf '[%s] no marker: regex miss (agent=%s prompt_head=%s)\n' \
87
- "${TS}" "${AGENT_TYPE}" "$(printf '%s' "${PROMPT_HEAD}" | head -1 | cut -c1-60)" >> "${HOOK_LOG}"
88
- exit 0
89
- fi
90
-
91
- # Normalize STORY=NNN-NN → STORY-NNN-NN
92
- WORK_ITEM_ID="$(printf '%s' "${WORK_ITEM_RAW}" | sed 's/=/\-/')"
93
-
94
- # ─── Resolve orchestrator session ID ─────────────────────────────────────────
95
- # Path-B: uniquified filename makes session ID irrelevant for lookup.
96
- # We embed it in the JSON body for forensic value only.
97
- # GOTCHA-5: CLAUDE_SESSION_ID may be unset on nested spawns; fall back to stdin payload.
98
- SESSION_ID="${CLAUDE_SESSION_ID:-}"
99
- if [[ -z "${SESSION_ID}" ]]; then
100
- SESSION_ID="$(printf '%s' "${INPUT}" | jq -r '.session_id // empty' 2>/dev/null)"
101
- fi
102
- [[ -z "${SESSION_ID}" ]] && SESSION_ID="unknown"
103
-
104
- # ─── Resolve cleargate version ────────────────────────────────────────────────
105
- PKG_JSON="${REPO_ROOT}/cleargate-cli/package.json"
106
- CG_VERSION="unknown"
107
- if [[ -f "${PKG_JSON}" ]]; then
108
- CG_VERSION="$(jq -r '.version // "unknown"' "${PKG_JSON}" 2>/dev/null || echo "unknown")"
109
- fi
110
-
111
- # ─── Write dispatch file atomically (mktemp + mv, matches write_dispatch.sh:110-112) ──
112
- # Uniquified filename: .dispatch-<ts-epoch>-<pid>-<random>.json
113
- # Prevents collision under parallel Task() spawns; newest-file lookup at SubagentStop.
114
- SPAWNED_AT="${TS}"
115
- DISPATCH_FILENAME=".dispatch-$(date -u +%s)-$$-${RANDOM}.json"
116
- DISPATCH_TARGET="${SPRINT_DIR}/${DISPATCH_FILENAME}"
117
-
118
- DISPATCH_JSON="$(jq -cn \
119
- --arg work_item_id "${WORK_ITEM_ID}" \
120
- --arg agent_type "${AGENT_TYPE}" \
121
- --arg spawned_at "${SPAWNED_AT}" \
122
- --arg session_id "${SESSION_ID}" \
123
- --arg writer "pre-tool-use-task.sh@cleargate-${CG_VERSION}" \
124
- '{
125
- work_item_id: $work_item_id,
126
- agent_type: $agent_type,
127
- spawned_at: $spawned_at,
128
- session_id: $session_id,
129
- writer: $writer
130
- }' 2>/dev/null)"
131
-
132
- if [[ -z "${DISPATCH_JSON}" ]]; then
133
- printf '[%s] error: jq failed to build dispatch JSON\n' "${TS}" >> "${HOOK_LOG}"
134
- exit 0
135
- fi
136
-
137
- TMP="$(mktemp "${SPRINT_DIR}/.dispatch-tmp-XXXXXX" 2>/dev/null)"
138
- if [[ -z "${TMP}" ]]; then
139
- printf '[%s] error: mktemp failed for dispatch file\n' "${TS}" >> "${HOOK_LOG}"
140
- exit 0
141
- fi
142
- printf '%s\n' "${DISPATCH_JSON}" > "${TMP}"
143
- mv "${TMP}" "${DISPATCH_TARGET}"
144
-
145
- printf '[%s] wrote dispatch: sprint=%s work_item=%s agent=%s file=%s\n' \
146
- "${TS}" "${SPRINT_ID}" "${WORK_ITEM_ID}" "${AGENT_TYPE}" "${DISPATCH_FILENAME}" >> "${HOOK_LOG}"
147
-
148
- exit 0
@@ -1,75 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -u
3
- REPO_ROOT="${CLAUDE_PROJECT_DIR}"
4
-
5
- # cleargate-pin: __CLEARGATE_VERSION__
6
- # Resolve cleargate CLI (three-branch resolver — CR-009):
7
- # 1. meta-repo dogfood dist (fastest; only present in ClearGate's own repo)
8
- # 2. on-PATH binary (global install or shim)
9
- # 3. pinned npx invocation (always works wherever Node is present)
10
- if [ -f "${REPO_ROOT}/cleargate-cli/dist/cli.js" ]; then
11
- CG=(node "${REPO_ROOT}/cleargate-cli/dist/cli.js")
12
- elif command -v cleargate >/dev/null 2>&1; then
13
- CG=(cleargate)
14
- else
15
- CG=(npx -y "cleargate@__CLEARGATE_VERSION__")
16
- fi
17
-
18
- "${CG[@]}" doctor --session-start || true
19
-
20
- # --- Sprint-active skill auto-load directive (STORY-026-01) ---
21
- ACTIVE_FILE="${REPO_ROOT}/.cleargate/sprint-runs/.active"
22
- if [ -s "${ACTIVE_FILE}" ] && [ -n "$(tr -d '[:space:]' < "${ACTIVE_FILE}")" ]; then
23
- printf '→ Active sprint detected. Load skill: sprint-execution\n'
24
- fi
25
-
26
- # ── §14.9 SessionStart sync nudge (STORY-010-08) ─────────────────────────────
27
- # Daily-throttled: probe remote for updates at most once per 24h.
28
- # Never auto-pulls or auto-pushes. Exits 0 regardless of outcome.
29
- MARKER="${REPO_ROOT}/.cleargate/.sync-marker.json"
30
- NOW_ISO=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
31
- NOW_EPOCH=$(date +%s)
32
-
33
- if [ ! -f "${MARKER}" ]; then
34
- # First run — write marker with current timestamp and skip MCP call (24h grace).
35
- mkdir -p "$(dirname "${MARKER}")"
36
- printf '{"last_check":"%s"}' "${NOW_ISO}" > "${MARKER}"
37
- else
38
- # Parse last_check epoch from marker using node (portable, avoids jq dep)
39
- LAST_CHECK_ISO=$(node -e "try{const m=JSON.parse(require('fs').readFileSync('${MARKER}','utf8'));process.stdout.write(m.last_check||'1970-01-01T00:00:00Z')}catch{process.stdout.write('1970-01-01T00:00:00Z')}" 2>/dev/null || echo "1970-01-01T00:00:00Z")
40
- LAST_EPOCH=$(node -e "process.stdout.write(String(Math.floor(new Date('${LAST_CHECK_ISO}').getTime()/1000)))" 2>/dev/null || echo "0")
41
- ELAPSED=$(( NOW_EPOCH - LAST_EPOCH ))
42
-
43
- if [ "${ELAPSED}" -ge 86400 ]; then
44
- # ≥24h since last check — run probe (3s timeout, R7 mitigation)
45
- RESULT_FILE=$(mktemp)
46
- # Cross-platform 3-second timeout: prefer `timeout` (Linux); fall back to
47
- # background-process kill (macOS where GNU coreutils may be absent).
48
- if command -v timeout > /dev/null 2>&1; then
49
- timeout 3 "${CG[@]}" sync --check > "${RESULT_FILE}" 2>/dev/null || true
50
- else
51
- "${CG[@]}" sync --check > "${RESULT_FILE}" 2>/dev/null &
52
- _PROBE_PID=$!
53
- (sleep 3 && kill "${_PROBE_PID}" 2>/dev/null) &
54
- _KILL_PID=$!
55
- wait "${_PROBE_PID}" 2>/dev/null || true
56
- kill "${_KILL_PID}" 2>/dev/null || true
57
- wait "${_KILL_PID}" 2>/dev/null || true
58
- fi
59
- UPDATES=$(node -e "
60
- try {
61
- var data = require('fs').readFileSync(process.argv[1], 'utf8').trim();
62
- var obj = JSON.parse(data);
63
- process.stdout.write(String(obj.updates || 0));
64
- } catch(e) {
65
- process.stdout.write('0');
66
- }
67
- " "${RESULT_FILE}" 2>/dev/null || echo "0")
68
- rm -f "${RESULT_FILE}"
69
- if [ "${UPDATES}" -gt 0 ] 2>/dev/null; then
70
- printf '📡 ClearGate: %s remote updates since yesterday — run `cleargate sync` to reconcile.\n' "${UPDATES}"
71
- fi
72
- # Marker is updated by sync --check itself; no re-write needed here.
73
- fi
74
- fi
75
- exit 0
@@ -1,43 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -u
3
- REPO_ROOT="${CLAUDE_PROJECT_DIR}"
4
- LOG="${REPO_ROOT}/.cleargate/hook-log/gate-check.log"
5
- mkdir -p "$(dirname "$LOG")"
6
-
7
- # cleargate-pin: __CLEARGATE_VERSION__
8
- # Resolve cleargate CLI (three-branch resolver — CR-009):
9
- # 1. meta-repo dogfood dist (fastest; only present in ClearGate's own repo)
10
- # 2. on-PATH binary (global install or shim)
11
- # 3. pinned npx invocation (always works wherever Node is present)
12
- if [ -f "${REPO_ROOT}/cleargate-cli/dist/cli.js" ]; then
13
- CG=(node "${REPO_ROOT}/cleargate-cli/dist/cli.js")
14
- elif command -v cleargate >/dev/null 2>&1; then
15
- CG=(cleargate)
16
- else
17
- CG=(npx -y "cleargate@__CLEARGATE_VERSION__")
18
- fi
19
-
20
- FILE=$(jq -r '.tool_input.file_path' 2>/dev/null || echo "")
21
- [ -z "$FILE" ] && exit 0
22
- case "$FILE" in *.cleargate/delivery/*) : ;; *) exit 0 ;; esac
23
- TS=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
24
- # Ordered chain — stamp MUST precede gate (gate may read draft_tokens)
25
- "${CG[@]}" stamp-tokens "$FILE" >>"$LOG" 2>&1
26
- SR1=$?
27
- # CR-032: capture gate check stdout to tmpfile so we can re-emit ⚠️ lines to
28
- # hook stdout (→ Claude Code system-reminder). gate.ts emits ❌ lines to
29
- # stdout (gate.ts:259), not stderr; the tmpfile captures them separately.
30
- GATE_OUT=$(mktemp)
31
- "${CG[@]}" gate check "$FILE" >"$GATE_OUT" 2>>"$LOG"
32
- SR2=$?
33
- cat "$GATE_OUT" >>"$LOG"
34
- if [ "$SR2" -ne 0 ]; then
35
- WORK_ITEM_ID=$(grep -m1 -oE '(EPIC|STORY|CR|BUG|HOTFIX|PROPOSAL|INITIATIVE|SPRINT)-[0-9]+(-[0-9]+)?' "$FILE" | head -1)
36
- : "${WORK_ITEM_ID:=<work-item>}"
37
- grep '^❌' "$GATE_OUT" 2>/dev/null | sed -E "s/^❌ /⚠️ gate failed: ${WORK_ITEM_ID} — /"
38
- fi
39
- rm -f "$GATE_OUT"
40
- "${CG[@]}" wiki ingest "$FILE" >>"$LOG" 2>&1
41
- SR3=$?
42
- echo "[$TS] stamp=$SR1 gate=$SR2 ingest=$SR3 file=$FILE" >>"$LOG"
43
- exit 0 # ALWAYS 0 — severity enforcement is at wiki lint, not hook