create-issflow 1.2.0 → 1.4.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.
@@ -0,0 +1,233 @@
1
+ ---
2
+ description: The Scrum sprint layer — group PLAN phases into time-/scope-boxed sprints and run the full ceremony set (planning → standups → review/demo → retrospective → close) with burndown + velocity. AUTO-facilitated: the orchestrator runs every ceremony itself and drives the sprint end-to-end without stopping, pausing only at the real hard-stops. The layer between PLAN (backlog) and PHASE (build loop).
3
+ argument-hint: [run|plan|standup|review|retro|close|status] [sprint number]
4
+ ---
5
+
6
+ Caveman ULTRA mode. You are the ORCHESTRATOR / SCRUM MASTER. You FACILITATE the
7
+ ceremonies and ROUTE build work to subagents — you do NOT implement or debug yourself.
8
+
9
+ Subcommand: $ARGUMENTS (default: `status`)
10
+
11
+ Hierarchy: **PLAN (product backlog) → SPRINT (committed slice of phases) → PHASE
12
+ (the build loop)**. A sprint groups consecutive PLAN phases behind ONE sprint goal
13
+ and ships ONE deployable increment. Phases still run via `/phase` exactly as before
14
+ — the sprint layer wraps them with planning, standups, a review, and a retro.
15
+
16
+ **AUTONOMY (read first).** Sprint planning only SLICES the already-approved
17
+ `docs/PLAN.md` — the requirements gate already happened at `/overview` plan approval —
18
+ so the ceremonies are AUTO-safe and the orchestrator runs them WITHOUT stopping.
19
+ - **AUTO (default):** `/sprint run` drives the whole sprint hands-off — plan → loop
20
+ `/phase` → standup tick after each phase → review → retro → close → roll forward →
21
+ start the next sprint. Decisions (points, scope-fit, accept/carry) are made from the
22
+ PLAN + velocity, logged, and the run continues. Pause ONLY for a methodology
23
+ hard-stop (deploy/irreversible/outbound, security-sensitive change, contradictory
24
+ spec, or debug budget spent with no independent slice left).
25
+ - **GUIDED:** each ceremony presents its result and waits for you before the next.
26
+ The PLAN-approval, commercial (`/propose`, `/change-request`), and release
27
+ (`/release`, `/uat`, prod promote) gates are SEPARATE and stay interactive in both
28
+ modes — the sprint layer never auto-passes them.
29
+
30
+ Artifacts: `docs/sprints/sprint-<n>.md` (one per sprint — goal, committed phases,
31
+ burndown, standups, review, retro) and `docs/sprints/VELOCITY.md` (the rolling
32
+ velocity table). Create `docs/sprints/` if absent. STATE.md carries the active sprint.
33
+
34
+ =====================================================================
35
+ ## ROUTER
36
+
37
+ - `run` → §RUN (AUTO end-to-end driver — the default way to use this)
38
+ - `plan` → §1 PLANNING
39
+ - `standup` → §2 STANDUP
40
+ - `review` → §3 REVIEW
41
+ - `retro` → §4 RETRO
42
+ - `close` → §5 CLOSE
43
+ - `status` → §STATUS (default when no subcommand)
44
+
45
+ =====================================================================
46
+ ## §1 — SPRINT PLANNING (ceremony)
47
+
48
+ Pre: `docs/PLAN.md` exists AND its `> Approval:` header reads `approved …` (the
49
+ PLAN-APPROVAL gate, hard rule 13). Still `PENDING` / missing → STOP, route to the
50
+ `/overview` plan-approval gate. A sprint only SLICES an already-signed-off plan.
51
+
52
+ a. **Estimate (one-time, lazy).** Every pending PLAN phase needs a points estimate
53
+ (Fibonacci `1 2 3 5 8`, relative effort from the phase `slice` + `acceptance`
54
+ size; a phase that feels `>8` is too big — note it for `/replan` to split). If the
55
+ planner already wrote `[N pts]` tags, reuse them; otherwise assign now and write
56
+ them back into PLAN.md next to each phase header.
57
+
58
+ b. **Capacity.** Read `docs/sprints/VELOCITY.md`.
59
+ - Have history → capacity = rolling-average completed velocity (last ≤3 sprints).
60
+ - First sprint (no history) → capacity = `flow-config.json` `sprint.defaultCapacity`
61
+ (fallback 8 pts).
62
+
63
+ c. **Commit.** Walk the PLAN in dependency order, pull pending phases into this sprint
64
+ until the next phase would exceed capacity. Don't split a phase across a sprint
65
+ boundary; respect dependencies (never commit a phase whose dependency is in a later
66
+ sprint). Keep one coherent theme → that becomes the **sprint goal** (one line: the
67
+ user-visible increment this sprint ships). Optionally mark 1 phase `stretch`.
68
+
69
+ d. **Write** `docs/sprints/sprint-<n>.md` from the template below; set
70
+ `status: active`; seed the burndown tick 0 = total committed points. Group the
71
+ committed phases under a `## Sprint <n>` header in PLAN.md if not already grouped.
72
+ Update STATE.md: `sprint: <n> (active)`.
73
+
74
+ AUTO: auto-commit the computed backlog, log the goal + points + capacity, continue.
75
+ GUIDED: present goal + committed phases + points, wait for confirm.
76
+
77
+ =====================================================================
78
+ ## §2 — STANDUP (auto-tick — fires once per phase close inside an active sprint)
79
+
80
+ The AI dev loop has no calendar days, so the "daily" standup is rebound to a
81
+ **per-phase-close tick** — the natural cadence of progress. After each `/phase` CLOSE
82
+ while a sprint is active (the `/phase` command fires this; `/sprint run` fires it
83
+ inline; or run `/sprint standup` by hand):
84
+
85
+ 1. Append a standup line to the active sprint doc:
86
+ `- tick <k> (Phase <p> <done|blocked>): done <what>; next <phase/none>; blockers <none|ref>`
87
+ 2. Update the **burndown**: append a row `tick <k> | Phase <p> <state> | <remaining pts>`
88
+ where remaining = committed points minus points of phases now `done`. Re-render the
89
+ ASCII sparkline.
90
+ 3. Surface blockers immediately if any (a blocked phase is the standup's whole point).
91
+ AUTO: the blocker is already parked per the circuit breaker — just record it here
92
+ and keep the burndown honest. GUIDED: relay it.
93
+
94
+ Keep it ONE line per tick. No prose. The burndown is the signal.
95
+
96
+ =====================================================================
97
+ ## §3 — SPRINT REVIEW / DEMO (ceremony — at sprint boundary)
98
+
99
+ Run when every committed phase is `done` or `blocked` (sprint timebox reached).
100
+
101
+ a. **Demo.** Summarise the shipped increment: for each accepted phase, the
102
+ user-visible behaviour now working (pull from the phase `slice` + `docs/ENDPOINTS.md`).
103
+ This is the "done = demoable" check — a phase that can't be demoed isn't done.
104
+
105
+ b. **Boundary audits.** Run the whole-product audits ONCE for the increment (cheaper
106
+ here than per-phase, broader than the inline gates):
107
+ `/ui-audit` (if UI shipped) · `/qa-audit` · `/security-audit`. Fold the scores in.
108
+ Open BLOCKER/HIGH/CRITICAL → route to FIX (`debugger`/`implementer`), re-audit.
109
+ (Security findings remain an autonomy hard-stop.)
110
+
111
+ c. **Accept / carry.** Mark each phase `accepted` (demoed + audits clean) or
112
+ `carried` (not done / failed audit → rolls to the next sprint at §5).
113
+
114
+ d. Write the `## Review` block into the sprint doc (demo bullets, audit scores,
115
+ accepted vs carried).
116
+
117
+ =====================================================================
118
+ ## §4 — RETROSPECTIVE (ceremony — after review)
119
+
120
+ Inspect-and-adapt on the PROCESS, not the product. Write the `## Retro` block:
121
+
122
+ - **went well** — what to keep (2–4 bullets).
123
+ - **didn't** — friction, repeated debugging, churned tests, estimate misses.
124
+ - **actions** — each a CONCRETE, routed change, not a wish. Route every action to a
125
+ durable home so it actually happens:
126
+ - a recurring bug/root-cause pattern → it's already in `docs/ISSUES.md`; note the ref.
127
+ - a workflow/structure change → `/log-decision` (`docs/DESIGN_LOG.md`).
128
+ - an ops/incident lesson → `/runbook`.
129
+ - a plan correction (re-estimate, split, reorder) → `/replan`.
130
+ - a durable, cross-project lesson → flag for `/store-wisdom`.
131
+ - **estimate accuracy** — committed vs completed points; note phases that blew their
132
+ estimate so the next sprint's poker is calibrated.
133
+
134
+ AUTO: auto-apply the routed actions (log/replan) and continue. GUIDED: list actions,
135
+ confirm before applying.
136
+
137
+ =====================================================================
138
+ ## §5 — SPRINT CLOSE
139
+
140
+ a. **Velocity.** completed = sum of `accepted` phase points. Append a row to
141
+ `docs/sprints/VELOCITY.md`:
142
+ `| <n> | <committed> | <completed> | <goal met? yes/no> |` and recompute the rolling
143
+ average (last ≤3 sprints).
144
+ b. **Carry forward.** Each `carried`/`blocked` phase stays pending in PLAN.md — the
145
+ next `/sprint plan` re-commits it first (carried work has priority). Don't lose it.
146
+ c. Set the sprint doc `status: done`; stamp the close date. HISTORY line:
147
+ `sprint <n> closed — <completed>/<committed> pts, goal <met|missed> (<date>)`.
148
+ d. Update STATE.md: clear the active sprint (or set the next one if `/sprint run`
149
+ continues).
150
+
151
+ =====================================================================
152
+ ## §RUN — AUTO END-TO-END DRIVER (the headline: "do all the process automatically")
153
+
154
+ `/sprint run [n]` drives one full sprint — or, if you keep going, every remaining
155
+ sprint until the PLAN is exhausted — with NO human stop except a hard-stop:
156
+
157
+ ```
158
+ loop while pending phases remain in PLAN.md:
159
+ 1. §1 PLANNING → commit the next sprint from PLAN + velocity
160
+ 2. for each committed phase, in dependency order:
161
+ run /phase <p> → the full build loop (its own gates + circuit breaker)
162
+ §2 STANDUP tick → append standup + update burndown
163
+ phase BLOCKED (circuit breaker parked it) → record, keep going to the next
164
+ INDEPENDENT phase; if none remain, end the sprint early (timebox)
165
+ 3. §3 REVIEW → demo + boundary audits (fix blockers, re-audit)
166
+ 4. §4 RETRO → routed actions, applied
167
+ 5. §5 CLOSE → velocity + carry-forward + HISTORY
168
+ 6. /synthesize → suggest /clear (token reset at the sprint boundary, like a phase)
169
+ AUTO: start the next sprint automatically. GUIDED: stop, report, wait.
170
+ HARD-STOP at any point: deploy/irreversible/outbound action, security-sensitive
171
+ change, contradictory spec, or debug budget spent with no independent slice left →
172
+ pause, surface the consolidated report, hand to the human.
173
+ ```
174
+
175
+ When the last PLAN phase is `accepted`, the build is sprint-complete → recommend
176
+ `/release` (the pre-production pipeline) as the next step. Do NOT auto-promote to prod
177
+ — that is a separate, human-signed hard-stop.
178
+
179
+ =====================================================================
180
+ ## §STATUS
181
+
182
+ Read STATE.md + the active `docs/sprints/sprint-<n>.md` + VELOCITY.md and print:
183
+ sprint number + goal, status, the burndown sparkline, committed vs done points,
184
+ the current/next phase, any open blockers, and rolling velocity. One screen. No edits.
185
+
186
+ =====================================================================
187
+ ## SPRINT DOC TEMPLATE (`docs/sprints/sprint-<n>.md`)
188
+
189
+ ```
190
+ # Sprint <n> — <short name>
191
+ goal: <one line — the user-visible increment this sprint ships>
192
+ status: active # planning | active | review | done
193
+ capacity: <cap> pts (basis: velocity avg | default)
194
+
195
+ ## Committed
196
+ - Phase <p>: <name> [<pts> pts] [status: pending|done|blocked|accepted|carried]
197
+ - ...
198
+ ## Stretch
199
+ - Phase <q>: <name> [<pts> pts] # optional, pulled in only if capacity frees up
200
+
201
+ ## Burndown
202
+ tick | event | remaining pts
203
+ 0 | sprint start | <total>
204
+ 1 | Phase <p> done | <rem>
205
+ ...
206
+ <ascii sparkline of remaining pts, e.g. 8 ▆▅▃▂ 0>
207
+
208
+ ## Standups
209
+ - tick 1 (Phase <p> done): done <what>; next Phase <q>; blockers none
210
+ - ...
211
+
212
+ ## Review (<date>)
213
+ - demo: <increment shipped — user-visible behaviour now working>
214
+ - audits: ui <score|n/a> · qa <score> · security <score> · code <clean|issues>
215
+ - accepted: <phases> carried: <phases or —>
216
+
217
+ ## Retro (<date>)
218
+ - went well: ...
219
+ - didn't: ...
220
+ - actions: <each routed → ISSUES | DESIGN_LOG | RUNBOOK | replan | store-wisdom>
221
+ - estimates: committed <c> pts / completed <d> pts — <misses noted>
222
+ ```
223
+
224
+ ## VELOCITY TEMPLATE (`docs/sprints/VELOCITY.md`)
225
+
226
+ ```
227
+ # Velocity
228
+ | sprint | committed | completed | goal met? |
229
+ |--------|-----------|-----------|-----------|
230
+ | 1 | <c> | <d> | yes/no |
231
+
232
+ rolling avg (last ≤3): <v> pts/sprint
233
+ ```
@@ -0,0 +1,36 @@
1
+ ---
2
+ description: Manual UAT cycle — generate an all-case test-scenario document for human testers, hand it off, capture their pasted results, and drive the defect loop until every scenario passes. Used inside /release; the human-in-the-loop acceptance gate.
3
+ argument-hint: [optional: feature scope, or "failed" to re-issue only failures]
4
+ ---
5
+
6
+ Caveman ULTRA mode. You are the ORCHESTRATOR.
7
+
8
+ UAT is a HUMAN gate: real testers run the product and report results. Your job is to
9
+ make that easy — produce a clear scenario sheet, capture results, and loop on defects.
10
+
11
+ ## STEP 1 — BUILD SCENARIOS
12
+ From `docs/OVERVIEW.md` (flows) + `docs/PLAN.md` (acceptance) + `docs/ENDPOINTS.md`,
13
+ write `docs/UAT-<date>.md` covering ALL cases a tester should run:
14
+ ```
15
+ ## UAT — <project> (<date>, build <ref>)
16
+ | # | scenario | preconditions | steps | expected | Result (PASS/FAIL) | Notes |
17
+ |---|----------|---------------|-------|----------|--------------------|-------|
18
+ | 1 | … | … | … | … | | |
19
+ ```
20
+ Cover: every happy path, every acceptance criterion, edge / negative cases, each user
21
+ role, and each critical flow. Group by feature, number them, leave Result + Notes
22
+ blank for the tester. Keep steps concrete enough to follow without you.
23
+
24
+ ## STEP 2 — HAND OFF
25
+ Show me the scenario sheet, ready to run. Tell me to execute it (or pass it to QA /
26
+ the client), then **paste the results back** here. WAIT — do not assume results.
27
+
28
+ ## STEP 3 — CAPTURE RESULTS
29
+ Take the pasted results, fill PASS/FAIL + notes into `docs/UAT-<date>.md`, and
30
+ summarise: **X / Y passed**, list the failures with their scenario IDs.
31
+
32
+ ## STEP 4 — DEFECT LOOP
33
+ For each FAIL: log to `docs/ISSUES.md` (repro = the scenario steps), fix
34
+ (`implementer` / `debugger`, debug cap 3), re-run the automated tests for that area,
35
+ then re-issue **only the failed scenarios** to me for re-test. Loop until 100% PASS.
36
+ On all-green, hand back to `/release` for sign-off.
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ // PreToolUse context watchdog (iStartSoftFlow). Two tiers, one hook:
4
+ // warnPct -> non-blocking nudge (additionalContext) once per climb into the band
5
+ // gatePct -> HARD block of NEW build work (Edit/Write-to-source/feature Task)
6
+ // Reads REAL token usage from the transcript. Fail-OPEN: any error -> allow,
7
+ // never wedge the tool loop on a hook bug.
8
+ const path = require('path');
9
+ const fs = require('fs');
10
+
11
+ const silent = () => process.exit(0);
12
+ const out = (obj) => { process.stdout.write(JSON.stringify(obj)); process.exit(0); };
13
+
14
+ let input = '';
15
+ process.stdin.setEncoding('utf8');
16
+ process.stdin.on('data', (d) => (input += d));
17
+ process.stdin.on('end', () => {
18
+ let evt;
19
+ try { evt = JSON.parse(input); } catch (_) { return silent(); }
20
+ try { run(evt); } catch (_) { silent(); }
21
+ });
22
+
23
+ function run(evt) {
24
+ const projectDir = process.env.CLAUDE_PROJECT_DIR || evt.cwd || '.';
25
+ let ctx;
26
+ try { ctx = require(path.join(projectDir, '.claude/hooks/lib/ctx.js')); } catch (_) { return silent(); }
27
+ const cfg = ctx.loadConfig(projectDir);
28
+ const warn = cfg.warnPct || 60;
29
+ const gate = cfg.gatePct || 78;
30
+
31
+ const u = ctx.contextUsage(evt.transcript_path, cfg);
32
+ if (!u) return silent();
33
+
34
+ const tool = evt.tool_name || '';
35
+ const ti = evt.tool_input || {};
36
+ const band = u.pct >= gate ? 'gate' : u.pct >= warn ? 'warn' : 'ok';
37
+ const BLOCKABLE = new Set(['Edit', 'Write', 'MultiEdit', 'NotebookEdit', 'Task']);
38
+
39
+ // HARD GATE — block new build mutations; reason is fed to the model.
40
+ if (band === 'gate' && BLOCKABLE.has(tool) && !isEscape(tool, ti)) {
41
+ return out({
42
+ hookSpecificOutput: {
43
+ hookEventName: 'PreToolUse',
44
+ permissionDecision: 'deny',
45
+ permissionDecisionReason: gateReason(u, gate),
46
+ },
47
+ });
48
+ }
49
+
50
+ // NON-BLOCKING WARN — emit once each time we climb into a higher band.
51
+ const bandFile = path.join(projectDir, 'docs/.snapshots/.ctx-band');
52
+ const rank = (b) => (b === 'gate' ? 2 : b === 'warn' ? 1 : 0);
53
+ let prev = 'ok';
54
+ try { prev = (fs.readFileSync(bandFile, 'utf8').trim() || 'ok'); } catch (_) {}
55
+
56
+ if (rank(band) !== rank(prev)) {
57
+ try { fs.mkdirSync(path.dirname(bandFile), { recursive: true }); fs.writeFileSync(bandFile, band); } catch (_) {}
58
+ }
59
+ if (rank(band) > rank(prev) && band !== 'ok') {
60
+ return out({
61
+ hookSpecificOutput: {
62
+ hookEventName: 'PreToolUse',
63
+ additionalContext: band === 'gate' ? gateReason(u, gate) : warnReason(u, warn, gate),
64
+ },
65
+ });
66
+ }
67
+ return silent();
68
+ }
69
+
70
+ // Checkpoint/logging writes + the synthesizer ritual are never blocked, so the
71
+ // model always has an escape path out of the gate.
72
+ function isEscape(tool, ti) {
73
+ if (tool === 'Edit' || tool === 'Write' || tool === 'MultiEdit' || tool === 'NotebookEdit') {
74
+ const fp = ti.file_path || ti.path || ti.notebook_path || '';
75
+ return /(^|\/)docs\//.test(fp) || /STATE\.md|ISSUES\.md|\.snapshots\//.test(fp);
76
+ }
77
+ if (tool === 'Task') return (ti.subagent_type || '').toLowerCase() === 'synthesizer';
78
+ return false;
79
+ }
80
+
81
+ const fmt = (n) => (n >= 1000 ? Math.round(n / 1000) + 'k' : String(n));
82
+
83
+ function gateReason(u, gate) {
84
+ return [
85
+ `⛔ CONTEXT GATE — ${u.pct}% (${fmt(u.tokens)}/${fmt(u.window)} tok), เกิน ${gate}% = หยุดเปิดงาน build ใหม่.`,
86
+ 'ทำก่อนไปต่อ:',
87
+ ' 1) ปิด/commit งานค้างให้จบ (Bash/git ไม่ถูก block)',
88
+ ' 2) /synthesize (อัด handoff docs — subagent นี้ไม่ถูก block)',
89
+ ' 3) /clear (session ใหม่ บางลง)',
90
+ 'build ต่อหลัง clear. กลาง irreversible op? ใช้ Bash ปิดให้จบก่อน clear.',
91
+ 'ปลดล็อกชั่วคราว: เพิ่ม gatePct ใน .claude/flow-config.json.',
92
+ ].join('\n');
93
+ }
94
+
95
+ function warnReason(u, warn, gate) {
96
+ return [
97
+ `⚠️ CONTEXT ${u.pct}% (${fmt(u.tokens)}/${fmt(u.window)} tok) — แตะ warn band ${warn}%.`,
98
+ `วางแผนปิด phase: ทยอย /synthesize → /clear ก่อนถึง gate ${gate}% (เลยจุดนั้น hook block งาน build ใหม่).`,
99
+ 'Delegate งาน noisy ให้ subagent เพื่อกัน context โต.',
100
+ ].join('\n');
101
+ }
@@ -0,0 +1,82 @@
1
+ 'use strict';
2
+ // Shared context-budget math for iStartSoftFlow watchdog hooks.
3
+ // Reads the live Claude Code transcript (JSONL) and reports how full the
4
+ // model's context window currently is — from the REAL token usage the API
5
+ // reported, not a heuristic. Pure Node, cross-platform.
6
+ const fs = require('fs');
7
+
8
+ // Known context windows by model-id substring. First match wins. The 1M
9
+ // Opus/Sonnet variants advertise "[1m]" in the model id.
10
+ const WINDOWS = [
11
+ [/\[1m\]|-1m\b|:1m\b|1m-/i, 1000000],
12
+ [/opus|sonnet|haiku|claude/i, 200000],
13
+ ];
14
+
15
+ function inferWindow(model) {
16
+ if (!model) return 200000;
17
+ for (const [re, w] of WINDOWS) if (re.test(model)) return w;
18
+ return 200000;
19
+ }
20
+
21
+ // Read project flow config; returns the `context` block or {}.
22
+ function loadConfig(projectDir) {
23
+ try {
24
+ const cfg = JSON.parse(fs.readFileSync(projectDir + '/.claude/flow-config.json', 'utf8'));
25
+ return (cfg && cfg.context) || {};
26
+ } catch (_) { return {}; }
27
+ }
28
+
29
+ // Read only the last `bytes` of a file (the recent assistant turns live at the
30
+ // tail of the JSONL — no need to load a multi-MB transcript on every tool).
31
+ function readTail(p, bytes) {
32
+ const fd = fs.openSync(p, 'r');
33
+ try {
34
+ const size = fs.fstatSync(fd).size;
35
+ const start = Math.max(0, size - bytes);
36
+ const len = size - start;
37
+ const buf = Buffer.alloc(len);
38
+ fs.readSync(fd, buf, 0, len, start);
39
+ return { text: buf.toString('utf8'), partial: start > 0 };
40
+ } finally { fs.closeSync(fd); }
41
+ }
42
+
43
+ // Scan lines (newest first) for the most recent assistant usage block.
44
+ // input_tokens + cache_read + cache_creation == the full prompt size actually
45
+ // sent == current context occupancy.
46
+ function scanUsage(text, dropFirst) {
47
+ const lines = text.split('\n');
48
+ const lo = dropFirst ? 1 : 0; // first line may be a truncated tail fragment
49
+ for (let i = lines.length - 1; i >= lo; i--) {
50
+ const ln = lines[i].trim();
51
+ if (!ln) continue;
52
+ let obj;
53
+ try { obj = JSON.parse(ln); } catch (_) { continue; }
54
+ const m = obj && obj.message;
55
+ if (m && m.role === 'assistant' && m.usage && typeof m.usage.input_tokens === 'number') {
56
+ return { usage: m.usage, model: m.model || obj.model || null };
57
+ }
58
+ }
59
+ return null;
60
+ }
61
+
62
+ function contextUsage(transcriptPath, cfg) {
63
+ if (!transcriptPath) return null;
64
+ let hit;
65
+ try {
66
+ const tail = readTail(transcriptPath, 512 * 1024);
67
+ hit = scanUsage(tail.text, tail.partial);
68
+ if (!hit && tail.partial) {
69
+ // usage not in the tail window — fall back to a full read (rare).
70
+ hit = scanUsage(fs.readFileSync(transcriptPath, 'utf8'), false);
71
+ }
72
+ } catch (_) { return null; }
73
+ if (!hit) return null;
74
+ const u = hit.usage;
75
+ const tokens = (u.input_tokens || 0)
76
+ + (u.cache_read_input_tokens || 0)
77
+ + (u.cache_creation_input_tokens || 0);
78
+ const window = (cfg && cfg.window) ? cfg.window : inferWindow(hit.model);
79
+ return { tokens, window, model: hit.model, pct: Math.round((tokens / window) * 100) };
80
+ }
81
+
82
+ module.exports = { contextUsage, inferWindow, loadConfig, readTail, scanUsage };
@@ -39,6 +39,21 @@ if (state !== null) {
39
39
  emit('');
40
40
  }
41
41
 
42
+ // 2b. active sprint (sprint layer) — surface goal + burndown if one is active
43
+ const sprintMatch = (state || '').match(/^\s*sprint:\s*(\d+)\s*\(active\)/m);
44
+ if (sprintMatch) {
45
+ const sf = read(`docs/sprints/sprint-${sprintMatch[1]}.md`);
46
+ if (sf !== null) {
47
+ emit(`## Sprint ${sprintMatch[1]} (active)`);
48
+ const goal = (sf.match(/goal:\s*(.+)/i) || [])[1];
49
+ if (goal) emit('goal: ' + goal.trim());
50
+ const burn = sf.split('\n').find((l) => /burndown|remaining|pts? left|[▁▂▃▄▅▆▇█]/i.test(l));
51
+ if (burn) emit('burndown: ' + burn.trim());
52
+ emit(`see docs/sprints/sprint-${sprintMatch[1]}.md for the full sprint.`);
53
+ emit('');
54
+ }
55
+ }
56
+
42
57
  // 3. issue log — inject only OPEN issues (resolved ones stay in the file for
43
58
  // grep, but are NOT re-paid in tokens every session). Capped.
44
59
  const issues = read('docs/ISSUES.md');
@@ -120,6 +135,8 @@ emit('- AUTO mode (default) governs the DEV loop: follow the plan — decide + l
120
135
  emit(' continue, do NOT stop to ask. (Planning / grill still asks — that part is fine.)');
121
136
  emit(' Hard-stops only: security / irreversible-or-outbound actions / contradictory spec.');
122
137
  emit('- caveman ULTRA mode is active.');
138
+ emit('- PLAN-APPROVAL gate (rule 13): no /phase or /sprint while STATE `plan:` reads');
139
+ emit(' PENDING — the plan needs a human sign-off via /overview first.');
123
140
  emit('- before debugging ANY error: grep ISSUES.md AND research/INDEX.md first.');
124
141
  emit('- debug attempts: WARN at 2; cap 3. AUTO: log + park the slice + continue (batched');
125
142
  emit(' report at the phase boundary). GUIDED: stop and ask you.');