cleargate 0.14.0 → 0.15.1

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 (150) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/MANIFEST.json +72 -16
  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-synth.md +2 -0
  25. package/templates/cleargate-planning/.claude/agents/architect.md +4 -2
  26. package/templates/cleargate-planning/.claude/agents/developer.md +4 -11
  27. package/templates/cleargate-planning/.claude/agents/qa.md +14 -6
  28. package/templates/cleargate-planning/.claude/hooks/pending-task-sentinel.sh +2 -2
  29. package/templates/cleargate-planning/.claude/skills/sprint-execution/SKILL.md +19 -1
  30. package/templates/cleargate-planning/.cleargate/config.example.yml +16 -0
  31. package/templates/cleargate-planning/.cleargate/scripts/close_sprint.deferred-verify.red.node.test.ts +245 -0
  32. package/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +227 -0
  33. package/templates/cleargate-planning/.cleargate/scripts/gate-checks.json +5 -4
  34. package/templates/cleargate-planning/.cleargate/scripts/init_sprint.mjs +75 -2
  35. package/templates/cleargate-planning/.cleargate/scripts/pre_gate_common.sh +48 -0
  36. package/templates/cleargate-planning/.cleargate/scripts/pre_gate_runner.sh +57 -1
  37. package/templates/cleargate-planning/.cleargate/scripts/provision_worktree_config.sh +155 -0
  38. package/templates/cleargate-planning/.cleargate/scripts/qa_red_lint.mjs +380 -0
  39. package/templates/cleargate-planning/.cleargate/scripts/run_script.sh +34 -1
  40. package/templates/cleargate-planning/.cleargate/scripts/test/cr077_eviction.red.sh +113 -0
  41. package/templates/cleargate-planning/.cleargate/scripts/test/cr078_init.test.sh +309 -0
  42. package/templates/cleargate-planning/.cleargate/scripts/test/cr079_provision.red.sh +262 -0
  43. package/templates/cleargate-planning/.cleargate/scripts/test/cr080_wrapper.test.sh +177 -0
  44. package/templates/cleargate-planning/.cleargate/scripts/test/cr081_qa_red_lint.red.sh +348 -0
  45. package/templates/cleargate-planning/.cleargate/sprint-runs/_off-sprint/.session-totals.json +1 -0
  46. package/templates/cleargate-planning/.cleargate/sprint-runs/_off-sprint/token-ledger.jsonl +222 -0
  47. package/templates/cleargate-planning/.cleargate/templates/sprint_context.md +17 -0
  48. package/templates/cleargate-planning/.cleargate/templates/story.md +1 -0
  49. package/templates/cleargate-planning/MANIFEST.json +72 -16
  50. package/dist/admin-api/index.cjs.map +0 -1
  51. package/dist/admin-api/index.js.map +0 -1
  52. package/dist/auth/factory.cjs.map +0 -1
  53. package/dist/auth/factory.js.map +0 -1
  54. package/dist/auth/require-token.cjs.map +0 -1
  55. package/dist/auth/require-token.js.map +0 -1
  56. package/dist/auth/token-store.cjs.map +0 -1
  57. package/dist/auth/token-store.js.map +0 -1
  58. package/dist/bootstrap-root-QKSA5V75.js.map +0 -1
  59. package/dist/chunk-5DI2Z3C2.js.map +0 -1
  60. package/dist/chunk-BTSZOEWC.js.map +0 -1
  61. package/dist/chunk-E3X7IE5E.js.map +0 -1
  62. package/dist/chunk-PDE37WFQ.js.map +0 -1
  63. package/dist/cli.cjs.map +0 -1
  64. package/dist/cli.js.map +0 -1
  65. package/dist/lib/ledger.cjs.map +0 -1
  66. package/dist/lib/ledger.js.map +0 -1
  67. package/dist/lib/lifecycle-reconcile.cjs.map +0 -1
  68. package/dist/lib/lifecycle-reconcile.js.map +0 -1
  69. package/dist/templates/cleargate-planning/.claude/agents/architect-reader.md +0 -61
  70. package/dist/templates/cleargate-planning/.claude/agents/architect-synth.md +0 -124
  71. package/dist/templates/cleargate-planning/.claude/agents/architect.md +0 -230
  72. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-contradict.md +0 -108
  73. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-ingest.md +0 -194
  74. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-lint.md +0 -261
  75. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-query.md +0 -143
  76. package/dist/templates/cleargate-planning/.claude/agents/developer.md +0 -185
  77. package/dist/templates/cleargate-planning/.claude/agents/devops.md +0 -257
  78. package/dist/templates/cleargate-planning/.claude/agents/qa.md +0 -171
  79. package/dist/templates/cleargate-planning/.claude/agents/reporter.md +0 -274
  80. package/dist/templates/cleargate-planning/.claude/hooks/pending-task-sentinel.sh +0 -209
  81. package/dist/templates/cleargate-planning/.claude/hooks/pre-commit-surface-gate.sh +0 -33
  82. package/dist/templates/cleargate-planning/.claude/hooks/pre-commit-test-ratchet.sh +0 -58
  83. package/dist/templates/cleargate-planning/.claude/hooks/pre-commit.sh +0 -19
  84. package/dist/templates/cleargate-planning/.claude/hooks/pre-edit-gate.sh +0 -162
  85. package/dist/templates/cleargate-planning/.claude/hooks/pre-tool-use-autonomy.sh +0 -58
  86. package/dist/templates/cleargate-planning/.claude/hooks/pre-tool-use-task.sh +0 -148
  87. package/dist/templates/cleargate-planning/.claude/hooks/session-start.sh +0 -75
  88. package/dist/templates/cleargate-planning/.claude/hooks/stamp-and-gate.sh +0 -43
  89. package/dist/templates/cleargate-planning/.claude/hooks/token-ledger.sh +0 -590
  90. package/dist/templates/cleargate-planning/.claude/settings.json +0 -68
  91. package/dist/templates/cleargate-planning/.claude/skills/flashcard/SKILL.md +0 -102
  92. package/dist/templates/cleargate-planning/.claude/skills/sprint-execution/SKILL.md +0 -742
  93. package/dist/templates/cleargate-planning/.cleargate/FLASHCARD.md +0 -7
  94. package/dist/templates/cleargate-planning/.cleargate/config.example.yml +0 -67
  95. package/dist/templates/cleargate-planning/.cleargate/config.yml +0 -18
  96. package/dist/templates/cleargate-planning/.cleargate/delivery/archive/.gitkeep +0 -0
  97. package/dist/templates/cleargate-planning/.cleargate/delivery/pending-sync/.gitkeep +0 -0
  98. package/dist/templates/cleargate-planning/.cleargate/knowledge/cleargate-enforcement.md +0 -551
  99. package/dist/templates/cleargate-planning/.cleargate/knowledge/cleargate-protocol.md +0 -878
  100. package/dist/templates/cleargate-planning/.cleargate/knowledge/mid-sprint-triage-rubric.md +0 -160
  101. package/dist/templates/cleargate-planning/.cleargate/knowledge/readiness-gates.md +0 -213
  102. package/dist/templates/cleargate-planning/.cleargate/knowledge/sprint-closeout-checklist.md +0 -71
  103. package/dist/templates/cleargate-planning/.cleargate/scripts/_migrate-schema-v3.mjs +0 -120
  104. package/dist/templates/cleargate-planning/.cleargate/scripts/assert_story_files.mjs +0 -265
  105. package/dist/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +0 -1012
  106. package/dist/templates/cleargate-planning/.cleargate/scripts/collision_surface.sh +0 -114
  107. package/dist/templates/cleargate-planning/.cleargate/scripts/constants.mjs +0 -62
  108. package/dist/templates/cleargate-planning/.cleargate/scripts/dedupe_frontmatter.mjs +0 -219
  109. package/dist/templates/cleargate-planning/.cleargate/scripts/file_surface_diff.sh +0 -320
  110. package/dist/templates/cleargate-planning/.cleargate/scripts/gate-checks.json +0 -15
  111. package/dist/templates/cleargate-planning/.cleargate/scripts/init_gate_config.sh +0 -38
  112. package/dist/templates/cleargate-planning/.cleargate/scripts/init_sprint.mjs +0 -240
  113. package/dist/templates/cleargate-planning/.cleargate/scripts/launch_wave.mjs +0 -341
  114. package/dist/templates/cleargate-planning/.cleargate/scripts/lib/report-filename.mjs +0 -54
  115. package/dist/templates/cleargate-planning/.cleargate/scripts/pre_gate_common.sh +0 -206
  116. package/dist/templates/cleargate-planning/.cleargate/scripts/pre_gate_runner.sh +0 -371
  117. package/dist/templates/cleargate-planning/.cleargate/scripts/prefill_report.mjs +0 -280
  118. package/dist/templates/cleargate-planning/.cleargate/scripts/prep_doc_refresh.mjs +0 -378
  119. package/dist/templates/cleargate-planning/.cleargate/scripts/prep_qa_context.mjs +0 -888
  120. package/dist/templates/cleargate-planning/.cleargate/scripts/run_script.sh +0 -209
  121. package/dist/templates/cleargate-planning/.cleargate/scripts/sprint_trends.mjs +0 -71
  122. package/dist/templates/cleargate-planning/.cleargate/scripts/state.schema.json +0 -127
  123. package/dist/templates/cleargate-planning/.cleargate/scripts/suggest_improvements.mjs +0 -717
  124. package/dist/templates/cleargate-planning/.cleargate/scripts/surface-whitelist.txt +0 -27
  125. package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_assert_story_files.sh +0 -261
  126. package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_file_surface.sh +0 -210
  127. package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_flashcard_gate.sh +0 -190
  128. package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_prep_qa_context.sh +0 -482
  129. package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_test_ratchet.sh +0 -327
  130. package/dist/templates/cleargate-planning/.cleargate/scripts/test_ratchet.mjs +0 -261
  131. package/dist/templates/cleargate-planning/.cleargate/scripts/update_state.mjs +0 -246
  132. package/dist/templates/cleargate-planning/.cleargate/scripts/validate_bounce_readiness.mjs +0 -111
  133. package/dist/templates/cleargate-planning/.cleargate/scripts/validate_state.mjs +0 -184
  134. package/dist/templates/cleargate-planning/.cleargate/scripts/write_dispatch.sh +0 -172
  135. package/dist/templates/cleargate-planning/.cleargate/templates/Bug.md +0 -126
  136. package/dist/templates/cleargate-planning/.cleargate/templates/CR.md +0 -130
  137. package/dist/templates/cleargate-planning/.cleargate/templates/Sprint Plan Template.md +0 -137
  138. package/dist/templates/cleargate-planning/.cleargate/templates/epic.md +0 -166
  139. package/dist/templates/cleargate-planning/.cleargate/templates/hotfix.md +0 -111
  140. package/dist/templates/cleargate-planning/.cleargate/templates/initiative.md +0 -122
  141. package/dist/templates/cleargate-planning/.cleargate/templates/sprint_context.md +0 -50
  142. package/dist/templates/cleargate-planning/.cleargate/templates/sprint_report.md +0 -224
  143. package/dist/templates/cleargate-planning/.cleargate/templates/story.md +0 -213
  144. package/dist/templates/cleargate-planning/CLAUDE.md +0 -66
  145. package/dist/templates/cleargate-planning/MANIFEST.json +0 -503
  146. package/dist/templates/synthesis/active-sprint.md +0 -30
  147. package/dist/templates/synthesis/open-gates.md +0 -38
  148. package/dist/templates/synthesis/product-state.md +0 -31
  149. package/dist/templates/synthesis/roadmap.md +0 -63
  150. 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