cleargate 0.1.0-alpha.1 → 0.2.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 (67) hide show
  1. package/README.md +41 -2
  2. package/dist/MANIFEST.json +160 -0
  3. package/dist/cli.cjs +4396 -16
  4. package/dist/cli.cjs.map +1 -1
  5. package/dist/cli.js +4380 -4
  6. package/dist/cli.js.map +1 -1
  7. package/dist/templates/cleargate-planning/.claude/agents/architect.md +57 -0
  8. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-ingest.md +145 -0
  9. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-lint.md +256 -0
  10. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-query.md +143 -0
  11. package/dist/templates/cleargate-planning/.claude/agents/developer.md +58 -0
  12. package/dist/templates/cleargate-planning/.claude/agents/qa.md +57 -0
  13. package/dist/templates/cleargate-planning/.claude/agents/reporter.md +114 -0
  14. package/dist/templates/cleargate-planning/.claude/hooks/session-start.sh +4 -0
  15. package/dist/templates/cleargate-planning/.claude/hooks/stamp-and-gate.sh +18 -0
  16. package/dist/templates/cleargate-planning/.claude/hooks/token-ledger.sh +174 -0
  17. package/dist/templates/cleargate-planning/.claude/settings.json +35 -0
  18. package/dist/templates/cleargate-planning/.claude/skills/flashcard/SKILL.md +73 -0
  19. package/dist/templates/cleargate-planning/.cleargate/FLASHCARD.md +6 -0
  20. package/dist/templates/cleargate-planning/.cleargate/delivery/archive/.gitkeep +0 -0
  21. package/dist/templates/cleargate-planning/.cleargate/delivery/pending-sync/.gitkeep +0 -0
  22. package/dist/templates/cleargate-planning/.cleargate/knowledge/cleargate-protocol.md +508 -0
  23. package/dist/templates/cleargate-planning/.cleargate/knowledge/readiness-gates.md +133 -0
  24. package/dist/templates/cleargate-planning/.cleargate/templates/Bug.md +82 -0
  25. package/dist/templates/cleargate-planning/.cleargate/templates/CR.md +77 -0
  26. package/dist/templates/cleargate-planning/.cleargate/templates/Sprint Plan Template.md +63 -0
  27. package/dist/templates/cleargate-planning/.cleargate/templates/epic.md +120 -0
  28. package/dist/templates/cleargate-planning/.cleargate/templates/initiative.md +53 -0
  29. package/dist/templates/cleargate-planning/.cleargate/templates/proposal.md +52 -0
  30. package/dist/templates/cleargate-planning/.cleargate/templates/story.md +125 -0
  31. package/dist/templates/cleargate-planning/CLAUDE.md +41 -0
  32. package/dist/templates/cleargate-planning/MANIFEST.json +160 -0
  33. package/dist/templates/synthesis/active-sprint.md +30 -0
  34. package/dist/templates/synthesis/open-gates.md +38 -0
  35. package/dist/templates/synthesis/product-state.md +32 -0
  36. package/dist/templates/synthesis/roadmap.md +63 -0
  37. package/package.json +9 -2
  38. package/templates/cleargate-planning/.claude/agents/architect.md +57 -0
  39. package/templates/cleargate-planning/.claude/agents/cleargate-wiki-ingest.md +145 -0
  40. package/templates/cleargate-planning/.claude/agents/cleargate-wiki-lint.md +256 -0
  41. package/templates/cleargate-planning/.claude/agents/cleargate-wiki-query.md +143 -0
  42. package/templates/cleargate-planning/.claude/agents/developer.md +58 -0
  43. package/templates/cleargate-planning/.claude/agents/qa.md +57 -0
  44. package/templates/cleargate-planning/.claude/agents/reporter.md +114 -0
  45. package/templates/cleargate-planning/.claude/hooks/session-start.sh +4 -0
  46. package/templates/cleargate-planning/.claude/hooks/stamp-and-gate.sh +18 -0
  47. package/templates/cleargate-planning/.claude/hooks/token-ledger.sh +174 -0
  48. package/templates/cleargate-planning/.claude/settings.json +35 -0
  49. package/templates/cleargate-planning/.claude/skills/flashcard/SKILL.md +73 -0
  50. package/templates/cleargate-planning/.cleargate/FLASHCARD.md +6 -0
  51. package/templates/cleargate-planning/.cleargate/delivery/archive/.gitkeep +0 -0
  52. package/templates/cleargate-planning/.cleargate/delivery/pending-sync/.gitkeep +0 -0
  53. package/templates/cleargate-planning/.cleargate/knowledge/cleargate-protocol.md +508 -0
  54. package/templates/cleargate-planning/.cleargate/knowledge/readiness-gates.md +133 -0
  55. package/templates/cleargate-planning/.cleargate/templates/Bug.md +82 -0
  56. package/templates/cleargate-planning/.cleargate/templates/CR.md +77 -0
  57. package/templates/cleargate-planning/.cleargate/templates/Sprint Plan Template.md +63 -0
  58. package/templates/cleargate-planning/.cleargate/templates/epic.md +120 -0
  59. package/templates/cleargate-planning/.cleargate/templates/initiative.md +53 -0
  60. package/templates/cleargate-planning/.cleargate/templates/proposal.md +52 -0
  61. package/templates/cleargate-planning/.cleargate/templates/story.md +125 -0
  62. package/templates/cleargate-planning/CLAUDE.md +41 -0
  63. package/templates/cleargate-planning/MANIFEST.json +160 -0
  64. package/templates/synthesis/active-sprint.md +30 -0
  65. package/templates/synthesis/open-gates.md +38 -0
  66. package/templates/synthesis/product-state.md +32 -0
  67. package/templates/synthesis/roadmap.md +63 -0
@@ -0,0 +1,174 @@
1
+ #!/usr/bin/env bash
2
+ # SubagentStop hook: append one JSONL row per subagent completion to the active sprint's token ledger.
3
+ #
4
+ # Input: JSON on stdin from Claude Code with fields session_id, transcript_path, cwd, hook_event_name.
5
+ # Output: appends to .cleargate/sprint-runs/<sprint-id>/token-ledger.jsonl
6
+ # Cost computation is deferred to the Reporter agent (prices change; keep raw).
7
+ #
8
+ # Active sprint detection (FIXED 2026-04-19):
9
+ # Primary : .cleargate/sprint-runs/.active sentinel file (one line: "SPRINT-NN")
10
+ # Orchestrator writes this at sprint kickoff, removes/updates at close.
11
+ # Fallback : .cleargate/sprint-runs/_off-sprint/token-ledger.jsonl
12
+ # When no .active sentinel exists, writes still get captured but
13
+ # tagged off-sprint instead of misrouting to a stale sprint dir.
14
+ # (Removed): the old `ls -td sprint-runs/*/ | head -1` mtime heuristic — it
15
+ # misrouted SPRINT-04 firings to SPRINT-03 because ledger appends
16
+ # themselves bumped SPRINT-03's mtime. See REPORT.md SPRINT-04.
17
+ #
18
+ # Work-item ID detection (GENERALIZED 2026-04-19 STORY-008-04):
19
+ # Primary : first user message in the transcript — that's the orchestrator's
20
+ # dispatch prompt, which by agent convention starts with
21
+ # `STORY=NNN-NN`, `PROPOSAL-NNN`, `EPIC-NNN`, `CR-NNN`, or `BUG-NNN`.
22
+ # Pattern : (STORY|PROPOSAL|EPIC|CR|BUG)[-=]?[0-9]+(-[0-9]+)?
23
+ # Fallback : grep first match anywhere in the transcript.
24
+ # story_id : populated only when the match is a STORY-* (backward compat).
25
+ # work_item_id: always populated when detection succeeds; equals story_id for STORY items.
26
+ # (Removed): grep-first-anywhere as PRIMARY — it picked up SPRINT-05 mentions
27
+ # from architect plans being read by the subagent and mistagged
28
+ # every SPRINT-04 firing as STORY-006-01.
29
+ #
30
+ # Robustness: never exits non-zero on parse failure (never block a subagent stop). Errors go to a
31
+ # sibling hook.log so you can diagnose without fighting the runtime.
32
+
33
+ set -u
34
+
35
+ REPO_ROOT="/Users/ssuladze/Documents/Dev/ClearGate"
36
+ LOG_DIR="${REPO_ROOT}/.cleargate/hook-log"
37
+ mkdir -p "${LOG_DIR}"
38
+ HOOK_LOG="${LOG_DIR}/token-ledger.log"
39
+ ACTIVE_SENTINEL="${REPO_ROOT}/.cleargate/sprint-runs/.active"
40
+
41
+ {
42
+ INPUT="$(cat)"
43
+
44
+ # --- parse hook payload ---
45
+ TRANSCRIPT_PATH="$(printf '%s' "${INPUT}" | jq -r '.transcript_path // empty')"
46
+ SESSION_ID="$(printf '%s' "${INPUT}" | jq -r '.session_id // empty')"
47
+
48
+ if [[ -z "${TRANSCRIPT_PATH}" || ! -f "${TRANSCRIPT_PATH}" ]]; then
49
+ printf '[%s] no transcript_path (session=%s)\n' "$(date -u +%FT%TZ)" "${SESSION_ID}" >> "${HOOK_LOG}"
50
+ exit 0
51
+ fi
52
+
53
+ # --- determine active sprint via sentinel ---
54
+ SPRINT_ID=""
55
+ if [[ -f "${ACTIVE_SENTINEL}" ]]; then
56
+ SPRINT_ID="$(tr -d '[:space:]' < "${ACTIVE_SENTINEL}")"
57
+ fi
58
+
59
+ if [[ -n "${SPRINT_ID}" ]]; then
60
+ SPRINT_DIR="${REPO_ROOT}/.cleargate/sprint-runs/${SPRINT_ID}"
61
+ mkdir -p "${SPRINT_DIR}"
62
+ printf '[%s] routing to sprint=%s (sentinel)\n' "$(date -u +%FT%TZ)" "${SPRINT_ID}" >> "${HOOK_LOG}"
63
+ else
64
+ # No active sprint: capture the row in an off-sprint ledger so we don't lose data.
65
+ SPRINT_ID="_off-sprint"
66
+ SPRINT_DIR="${REPO_ROOT}/.cleargate/sprint-runs/_off-sprint"
67
+ mkdir -p "${SPRINT_DIR}"
68
+ printf '[%s] no .active sentinel — bucketing as _off-sprint\n' "$(date -u +%FT%TZ)" >> "${HOOK_LOG}"
69
+ fi
70
+ LEDGER="${SPRINT_DIR}/token-ledger.jsonl"
71
+
72
+ # --- walk transcript, sum usage across all assistant turns in this subagent run ---
73
+ USAGE_JSON="$(jq -cs '
74
+ map(select(.type == "assistant" and .message.usage))
75
+ | (map(.message.usage.input_tokens // 0) | add) as $in
76
+ | (map(.message.usage.output_tokens // 0) | add) as $out
77
+ | (map(.message.usage.cache_creation_input_tokens // 0) | add) as $cc
78
+ | (map(.message.usage.cache_read_input_tokens // 0) | add) as $cr
79
+ | (map(.message.model) | unique | map(select(. != null)) | join(",")) as $models
80
+ | (length) as $turns
81
+ | {input: $in, output: $out, cache_creation: $cc, cache_read: $cr, model: $models, turns: $turns}
82
+ ' "${TRANSCRIPT_PATH}" 2>/dev/null)"
83
+
84
+ if [[ -z "${USAGE_JSON}" || "${USAGE_JSON}" == "null" ]]; then
85
+ printf '[%s] could not parse usage from %s\n' "$(date -u +%FT%TZ)" "${TRANSCRIPT_PATH}" >> "${HOOK_LOG}"
86
+ exit 0
87
+ fi
88
+
89
+ # --- detect agent_type ---
90
+ # Subagent transcripts contain `subagent_type` in the parent's tool invocation.
91
+ # Best-effort extraction; falls back to grepping role markers in the transcript body.
92
+ AGENT_TYPE="$(jq -rs '
93
+ [.[] | select(.type == "user") | .message.content]
94
+ | tostring
95
+ | capture("subagent_type[\"\\s:=]+(?<t>[a-zA-Z0-9_-]+)"; "g")?.t
96
+ // "unknown"
97
+ ' "${TRANSCRIPT_PATH}" 2>/dev/null)"
98
+ [[ -z "${AGENT_TYPE}" || "${AGENT_TYPE}" == "null" ]] && AGENT_TYPE="unknown"
99
+
100
+ if [[ "${AGENT_TYPE}" == "unknown" ]]; then
101
+ for role in architect developer qa reporter; do
102
+ if grep -qiE "\\b${role}\\b agent|role: ${role}|you are the ${role}" "${TRANSCRIPT_PATH}" 2>/dev/null; then
103
+ AGENT_TYPE="${role}"
104
+ break
105
+ fi
106
+ done
107
+ fi
108
+
109
+ # --- detect work_item_id (PRIMARY: first user message; FALLBACK: anywhere-grep) ---
110
+ # Orchestrator convention (.claude/agents/developer.md): the first line of the
111
+ # dispatch prompt is `STORY=NNN-NN`. The first user message in the transcript
112
+ # is that prompt. Look there first to avoid picking up work-item mentions inside
113
+ # the subagent's later reads of plans, sprint files, etc.
114
+ #
115
+ # Pattern covers: STORY-NNN-NN, PROPOSAL-NNN, EPIC-NNN, CR-NNN, BUG-NNN
116
+ # (and = separator variants like STORY=008-04)
117
+ WORK_ITEM_RAW="$(jq -rs '
118
+ [.[] | select(.type == "user")] | .[0].message.content
119
+ | if type == "array" then map(.text? // "") | join(" ") else (. // "") end
120
+ | tostring
121
+ | scan("(STORY|PROPOSAL|EPIC|CR|BUG)[-=]?([0-9]+(-[0-9]+)?)") | .[0:2] | join("-")
122
+ ' "${TRANSCRIPT_PATH}" 2>/dev/null | head -1)"
123
+
124
+ if [[ -n "${WORK_ITEM_RAW}" && "${WORK_ITEM_RAW}" != "null" && "${WORK_ITEM_RAW}" != "-" ]]; then
125
+ # Normalize: replace any = separator with - in the result
126
+ WORK_ITEM_ID="$(printf '%s' "${WORK_ITEM_RAW}" | sed 's/=/-/g')"
127
+ else
128
+ # Fallback: grep anywhere in the transcript
129
+ WORK_ITEM_ID="$(grep -oE '(STORY|PROPOSAL|EPIC|CR|BUG)[-=]?[0-9]+(-[0-9]+)?' "${TRANSCRIPT_PATH}" 2>/dev/null \
130
+ | head -1 \
131
+ | sed 's/=/-/g')"
132
+ if [[ -n "${WORK_ITEM_ID}" ]]; then
133
+ printf '[%s] work_item_id fallback grep: %s\n' "$(date -u +%FT%TZ)" "${WORK_ITEM_ID}" >> "${HOOK_LOG}"
134
+ fi
135
+ fi
136
+ [[ -z "${WORK_ITEM_ID}" ]] && WORK_ITEM_ID=""
137
+
138
+ # story_id is populated only when the work item is a STORY-* (backward compat)
139
+ STORY_ID=""
140
+ if [[ "${WORK_ITEM_ID}" == STORY-* ]]; then
141
+ STORY_ID="${WORK_ITEM_ID}"
142
+ fi
143
+
144
+ # Legacy fallback: if no work_item_id found at all, fall back to old grep for story_id only
145
+ if [[ -z "${WORK_ITEM_ID}" ]]; then
146
+ STORY_ID="$(grep -oE 'STORY[-=]?[0-9]{3}-[0-9]{2}' "${TRANSCRIPT_PATH}" 2>/dev/null \
147
+ | head -1 \
148
+ | sed -E 's/STORY[-=]?([0-9]{3}-[0-9]{2})/STORY-\1/')"
149
+ [[ -z "${STORY_ID}" ]] && STORY_ID="none"
150
+ WORK_ITEM_ID="${STORY_ID}"
151
+ fi
152
+
153
+ # --- assemble ledger row ---
154
+ TS="$(date -u +%FT%TZ)"
155
+ ROW="$(jq -cn \
156
+ --arg ts "${TS}" \
157
+ --arg agent "${AGENT_TYPE}" \
158
+ --arg story "${STORY_ID}" \
159
+ --arg work_item "${WORK_ITEM_ID}" \
160
+ --arg session "${SESSION_ID}" \
161
+ --arg transcript "${TRANSCRIPT_PATH}" \
162
+ --arg sprint "${SPRINT_ID}" \
163
+ --argjson usage "${USAGE_JSON}" \
164
+ '{ts: $ts, sprint_id: $sprint, agent_type: $agent, story_id: $story, work_item_id: $work_item, session_id: $session, transcript: $transcript} + $usage')"
165
+
166
+ printf '%s\n' "${ROW}" >> "${LEDGER}"
167
+ printf '[%s] wrote row: sprint=%s agent=%s work_item=%s story=%s tokens=in:%s/out:%s\n' \
168
+ "${TS}" "${SPRINT_ID}" "${AGENT_TYPE}" "${WORK_ITEM_ID}" "${STORY_ID}" \
169
+ "$(printf '%s' "${USAGE_JSON}" | jq -r '.input')" \
170
+ "$(printf '%s' "${USAGE_JSON}" | jq -r '.output')" \
171
+ >> "${HOOK_LOG}"
172
+ } 2>> "${HOOK_LOG}"
173
+
174
+ exit 0
@@ -0,0 +1,35 @@
1
+ {
2
+ "hooks": {
3
+ "SubagentStop": [
4
+ {
5
+ "hooks": [
6
+ {
7
+ "type": "command",
8
+ "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/token-ledger.sh"
9
+ }
10
+ ]
11
+ }
12
+ ],
13
+ "PostToolUse": [
14
+ {
15
+ "matcher": "Edit|Write",
16
+ "hooks": [
17
+ {
18
+ "type": "command",
19
+ "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/stamp-and-gate.sh"
20
+ }
21
+ ]
22
+ }
23
+ ],
24
+ "SessionStart": [
25
+ {
26
+ "hooks": [
27
+ {
28
+ "type": "command",
29
+ "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/session-start.sh"
30
+ }
31
+ ]
32
+ }
33
+ ]
34
+ }
35
+ }
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: flashcard
3
+ description: Append-only project lesson log at .cleargate/FLASHCARD.md. Use BEFORE starting non-trivial work to read past gotchas ("check" mode). Use WHEN you hit a surprise, wasted time, or a non-obvious gotcha to record it for future agents ("record: <one-liner>" mode). One-liners only; tag with #schema/#auth/#test-harness/etc. Also triggers on phrases like "turns out", "unexpected", "gotcha", "wasted time on", "starting work on", "before implementing".
4
+ ---
5
+
6
+ # Flashcard — Project Lesson Log
7
+
8
+ Append-only one-liner log of non-obvious gotchas that future agents in this project should know. Lives at `.cleargate/FLASHCARD.md` in the project root. Not a general wiki — only things that surprised us and would surprise someone else.
9
+
10
+ ## Two modes
11
+
12
+ ### `check` — read before work
13
+ Read `.cleargate/FLASHCARD.md`. Scan for tags relevant to your current task (grep by `#schema`, `#auth`, etc.). If a card applies, follow its guidance. If unsure whether a card applies, err on applying it — reading 20 one-liners is cheap.
14
+
15
+ ### `record: <one-liner>` — write after surprise
16
+ Append a single line to `.cleargate/FLASHCARD.md`. Format:
17
+
18
+ ```
19
+ YYYY-MM-DD · #tag1 #tag2 · <lesson ≤ 120 chars>
20
+ ```
21
+
22
+ Example:
23
+ ```
24
+ 2026-04-18 · #redis #auth · Invite tokens in Redis-only vanish on eviction — use Postgres invites table as source of truth.
25
+ ```
26
+
27
+ ### Tag vocabulary (append new tags freely, but prefer these)
28
+ - `#schema` — Drizzle / migration / Postgres table shape gotcha
29
+ - `#auth` — JWT / refresh / bcrypt / token handling
30
+ - `#keychain` — macOS Keychain / libsecret / `@napi-rs/keyring` / `keytar`
31
+ - `#redis` — Redis key shape, TTL, persistence
32
+ - `#test-harness` — local docker compose, Postgres 18, Redis 8, flaky tests
33
+ - `#ci` — pipeline / GitHub Actions / pre-commit hooks
34
+ - `#mcp` — MCP SDK / Streamable HTTP / session protocol
35
+ - `#cli` — Commander / tsup / bin entry / npm publish
36
+ - `#admin-api` — Admin API contract / OpenAPI snapshot / zod
37
+ - `#ui` — SvelteKit / Tailwind / DaisyUI
38
+ - `#reporting` — sprint report generation
39
+ - `#qa` — recurring QA kickback patterns
40
+ - `#ambiguity` — story-spec ambiguities that bit us
41
+
42
+ ## Rules
43
+
44
+ 1. **Grep before append.** `grep -iF "<key phrase>" .cleargate/FLASHCARD.md` — if a matching card exists, skip or edit the existing line with a date suffix (e.g. `… (reconfirmed 2026-05-10)`). Never duplicate.
45
+ 2. **One line per card.** Hard cap 120 characters for the lesson body. If it needs more, you are writing docs, not a flashcard — put docs elsewhere.
46
+ 3. **Lead with the surprise, not the context.** Good: "Drizzle 0.45 silently drops `DEFAULT gen_random_uuid()` — use `sql` template." Bad: "When working on schema migrations yesterday we found that sometimes…"
47
+ 4. **Lessons, not events.** "Shipped STORY-004-07 today" is NOT a flashcard. "Postgres 18 needs `pgcrypto` extension for gen_random_uuid — not enabled by default in official docker image" IS.
48
+ 5. **Ordered newest-first after the header** — new entries go at the TOP of the log section, not bottom. Readers scan the top; old stuff drifts down.
49
+ 6. **Never delete.** Edit to add reconfirmations or deprecation notes; keep the original text. History is the point.
50
+
51
+ ## Invocation contract
52
+
53
+ When an agent invokes this skill:
54
+
55
+ - **`Skill(flashcard, "check")`** — open `.cleargate/FLASHCARD.md`, summarize any cards with tags relevant to the current task context in one line per card. If none apply, respond "no relevant flashcards" and proceed.
56
+ - **`Skill(flashcard, "record: <text>")`** — parse the text for date + tags + body. If date missing, insert today's UTC date. If tags missing, refuse with "add at least one tag." Grep for duplicates; if dup, reconfirm the existing line instead of appending. Append to the top of the log section in the file.
57
+
58
+ ## File shape
59
+
60
+ `.cleargate/FLASHCARD.md` layout:
61
+
62
+ ```markdown
63
+ # ClearGate Flashcards
64
+
65
+ One-liner gotcha log. Newest first. Grep by tag (e.g. `grep '#schema'`).
66
+ Format: `YYYY-MM-DD · #tags · lesson`
67
+
68
+ ---
69
+
70
+ 2026-04-18 · #redis #auth · <newest lesson>
71
+ 2026-04-17 · #schema · <older lesson>
72
+ ...
73
+ ```
@@ -0,0 +1,6 @@
1
+ # ClearGate Flashcards
2
+
3
+ One-liner gotcha log. Newest first. Grep by tag (e.g. `grep '#schema'`).
4
+ Format: `YYYY-MM-DD · #tags · lesson`
5
+
6
+ ---