@relipa/ai-flow-kit 0.0.8-beta.1 → 0.0.9-beta.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.
@@ -1,274 +1,295 @@
1
- #!/usr/bin/env node
2
- /**
3
- * SessionStart hook for ai-flow-kit
4
- * Injects:
5
- * 1. using-superpowers skill content
6
- * 2. Active ticket context + gate-aware workflow instruction
7
- */
8
-
9
- const fs = require('fs');
10
- const path = require('path');
11
- const { record } = require('../telemetry/record');
12
-
13
- record('session.start');
14
-
15
- // This script lives at .claude/hooks/session-start.js
16
- // Project root is 2 levels up: .claude/hooks → .claude → project root
17
- const projectRoot = path.resolve(__dirname, '..', '..');
18
- const skillPath = path.join(projectRoot, '.claude', 'skills', 'using-superpowers', 'SKILL.md');
19
- const contextPath = path.join(projectRoot, '.aiflow', 'context', 'current.json');
20
- const tasksDir = path.join(projectRoot, '.aiflow', 'tasks');
21
-
22
- // ── 1. Load superpowers skill ──────────────────────────────────
23
- let skillContent = '';
24
- try {
25
- skillContent = fs.readFileSync(skillPath, 'utf-8');
26
- } catch (_) {
27
- process.stderr.write('[aiflow] WARNING: using-superpowers skill missing — run `aiflow update`\n');
28
- }
29
-
30
- // ── 2. Load active ticket context ──────────────────────────────
31
- let contextBlock = '';
32
- try {
33
- if (fs.existsSync(contextPath)) {
34
- const ctx = JSON.parse(fs.readFileSync(contextPath, 'utf-8'));
35
- if (ctx.taskId && ctx.title) {
36
- const taskState = loadTaskState(ctx.taskId);
37
- contextBlock = buildContextPrompt(ctx, taskState);
38
- }
39
- }
40
- } catch (_) {
41
- // Context missing or invalid — continue without it
42
- }
43
-
44
- // ── 3. Check GitNexus background indexing status ───────────────
45
- const GITNEXUS_STALE_MS = 3 * 60 * 60 * 1000; // 3 hours
46
- const gitNexusStatusPath = path.join(projectRoot, '.aiflow', 'gitnexus-status.json');
47
- try {
48
- if (fs.existsSync(gitNexusStatusPath)) {
49
- const gn = JSON.parse(fs.readFileSync(gitNexusStatusPath, 'utf-8'));
50
- if (!gn.notified) {
51
- // Detect stale "running" — process was killed without updating status
52
- if (gn.status === 'running' && gn.startedAt) {
53
- const age = Date.now() - new Date(gn.startedAt).getTime();
54
- if (age > GITNEXUS_STALE_MS) {
55
- gn.status = 'error';
56
- gn.error = 'timed out — process may have been killed or ran out of memory';
57
- }
58
- }
59
- if (gn.status === 'done') {
60
- process.stderr.write('[aiflow] GitNexus indexing complete code intelligence tools are ready.\n');
61
- } else if (gn.status === 'error') {
62
- const detail = gn.error ? ` (${gn.error})` : gn.exitCode != null ? ` (exit ${gn.exitCode})` : '';
63
- process.stderr.write(`[aiflow] ✗ GitNexus indexing failed${detail}.\n`);
64
- // process.stderr.write('[aiflow] Retry: aiflow init --with-gitnexus\n');
65
- }
66
- if (gn.status === 'done' || gn.status === 'error') {
67
- gn.notified = true;
68
- fs.writeFileSync(gitNexusStatusPath, JSON.stringify(gn, null, 2));
69
- }
70
- }
71
- }
72
- } catch (_) {}
73
-
74
- // ── 4. Combine and output ──────────────────────────────────────
75
- const parts = [];
76
-
77
- if (skillContent) {
78
- parts.push(`<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n**Below is the full content of your 'superpowers:using-superpowers' skill - your introduction to using skills. For all other skills, use the 'Skill' tool:**\n\n${skillContent}\n\n</EXTREMELY_IMPORTANT>`);
79
- }
80
-
81
- if (contextBlock) {
82
- parts.push(contextBlock);
83
- }
84
-
85
- const combined = parts.join('\n\n');
86
-
87
- const escaped = combined
88
- .replace(/\\/g, '\\\\')
89
- .replace(/"/g, '\\"')
90
- .replace(/\n/g, '\\n')
91
- .replace(/\r/g, '\\r')
92
- .replace(/\t/g, '\\t');
93
-
94
- process.stdout.write(JSON.stringify({
95
- hookSpecificOutput: {
96
- hookEventName: 'SessionStart',
97
- additionalContext: escaped
98
- }
99
- }));
100
-
101
- process.exit(0);
102
-
103
- // ── Helpers ────────────────────────────────────────────────────
104
-
105
- function loadTaskState(taskId) {
106
- try {
107
- const statePath = path.join(tasksDir, taskId, 'task-state.json');
108
- if (fs.existsSync(statePath)) {
109
- return JSON.parse(fs.readFileSync(statePath, 'utf-8'));
110
- }
111
- } catch (_) {}
112
- return null;
113
- }
114
-
115
- function buildContextPrompt(ctx, taskState) {
116
- const lines = [];
117
- lines.push('<ACTIVE_TASK>');
118
- lines.push(`**Active Ticket:** ${ctx.taskId} — ${ctx.title}`);
119
- lines.push(`**Type:** ${ctx.taskType || 'feature'}`);
120
- lines.push(`**Status:** ${ctx.status || 'Unknown'}`);
121
- lines.push(`**Assignee:** ${ctx.assignee || 'Unknown'}`);
122
- lines.push('');
123
-
124
- if (ctx.description) {
125
- lines.push('**Description:**');
126
- lines.push(ctx.description.substring(0, 2000));
127
- lines.push('');
128
- }
129
-
130
- if (ctx.acceptanceCriteria && ctx.acceptanceCriteria.length > 0) {
131
- lines.push('**Acceptance Criteria:**');
132
- for (const c of ctx.acceptanceCriteria) lines.push(`- ${c}`);
133
- lines.push('');
134
- }
135
-
136
- if (ctx.comments && ctx.comments.length > 0) {
137
- lines.push(`**Comments (${ctx.comments.length}):**`);
138
- const recent = ctx.comments.slice(-5);
139
- for (const c of recent) { lines.push(c); lines.push(''); }
140
- }
141
-
142
- if (ctx.context && ctx.context.files && ctx.context.files.length > 0) {
143
- lines.push('**Related Files:**');
144
- for (const f of ctx.context.files) lines.push(`- \`${f}\``);
145
- lines.push('');
146
- }
147
-
148
- lines.push('---');
149
- lines.push('');
150
-
151
- // ── Gate-aware instruction ──────────────────────────────────
152
- const mode = ctx.mode || 'fast';
153
- const currentGate = taskState && taskState.currentGate ? taskState.currentGate : 1;
154
- const isResume = taskState && taskState.pausedAt;
155
-
156
- if (isResume && currentGate > 1) {
157
- // Resuming a paused task — inject resume context
158
- const gateApprovals = taskState.gateApprovals || {};
159
- lines.push(`**RESUMING TASK: ${ctx.taskId} — Gate ${currentGate}**`);
160
- lines.push('');
161
- lines.push('This task was previously paused and is now being resumed.');
162
- lines.push('');
163
- lines.push('**Gate Progress:**');
164
- for (let g = 1; g < currentGate; g++) {
165
- const approvedAt = gateApprovals[String(g)];
166
- const stamp = approvedAt ? ` approved ${approvedAt}` : ' — approved';
167
- lines.push(`- Gate ${g}: ✅ APPROVED${stamp}`);
168
- }
169
- lines.push(`- Gate ${currentGate}: 🔄 IN PROGRESS`);
170
- lines.push('');
171
- lines.push(`**DO NOT restart from Gate 1.** Resume directly at Gate ${currentGate} (${gateLabel(currentGate)}).`);
172
- lines.push('');
173
-
174
- if (currentGate === 2) {
175
- lines.push('Gate 1 is already APPROVED. The requirement document is at:');
176
- lines.push(` plan/${ctx.taskId}/requirement.md`);
177
- lines.push('');
178
- lines.push('Proceed to Gate 2: create the implementation plan.');
179
- lines.push(buildModeInstruction(mode, 2));
180
- } else if (currentGate === 3) {
181
- lines.push('Gates 1 and 2 are already APPROVED. Plans are at:');
182
- lines.push(` plan/${ctx.taskId}/requirement.md`);
183
- lines.push(` plan/${ctx.taskId}/plan.md`);
184
- lines.push('');
185
- lines.push('Proceed to Gate 3: implement code following the plan (TDD).');
186
- lines.push(buildModeInstruction(mode, 3));
187
- } else if (currentGate === 4) {
188
- lines.push('Gates 1–3 are APPROVED. Code has been implemented.');
189
- lines.push('Proceed to Gate 4: run verification + impact-analysis + review checklist.');
190
- lines.push(buildModeInstruction(mode, 4));
191
- } else if (currentGate === 5) {
192
- lines.push('Gates 1–4 are APPROVED. Self-review is done.');
193
- lines.push('Proceed to Gate 5: guide the developer to create a Pull Request.');
194
- }
195
- if (taskState.notes) {
196
- lines.push('');
197
- lines.push(`**Note from developer:** ${taskState.notes}`);
198
- }
199
- } else {
200
- // Fresh task auto-start Gate 1
201
- lines.push('**AUTO-START GATE 1: You MUST begin analyzing this ticket immediately.**');
202
- lines.push('');
203
- lines.push(`INVOKE the \`read-study-requirement\` skill NOW for ticket ${ctx.taskId}.`);
204
- lines.push('');
205
-
206
- if (mode === 'fast') {
207
- lines.push('**MODE: fast** Use the FAST TRACK path in the skill:');
208
- lines.push('- Read ticket + identify changed files only (no deep source scan)');
209
- lines.push('- Skip Q&A unless there is a critical blocking ambiguity');
210
- lines.push('- Output a lite requirement doc (Sections 1, 3, 5 only)');
211
- lines.push('- Target: Gate 1 complete in < 5 minutes');
212
- } else {
213
- lines.push('Gate 1 process:');
214
- lines.push('1. Read the ticket context above');
215
- lines.push('2. Read CLAUDE.md understand project architecture and conventions');
216
- lines.push('3. Read source code — identify related files, data flow, patterns');
217
- lines.push('4. If anything is unclear — ask ONE question at a time');
218
- lines.push('5. Output plan/' + ctx.taskId + '/requirement.md');
219
- lines.push('6. Display GATE 1 prompt and wait for APPROVED');
220
- }
221
-
222
- lines.push('');
223
- lines.push('DO NOT wait for the developer to ask. START NOW.');
224
- lines.push('If you have not started automatically, begin as soon as the developer types **"start"**.');
225
- }
226
-
227
- lines.push('</ACTIVE_TASK>');
228
- return lines.join('\n');
229
- }
230
-
231
- function gateLabel(n) {
232
- const labels = {
233
- 1: 'AI Analyze Requirement',
234
- 2: 'Implementation Plan',
235
- 3: 'Code Generation',
236
- 4: 'AI Self-Review',
237
- 5: 'Peer Review & PR',
238
- };
239
- return labels[n] || `Gate ${n}`;
240
- }
241
-
242
- function buildModeInstruction(mode, gate) {
243
- if (mode !== 'fast') return ''; // full mode: không inject gì thêm, AI chạy đầy đủ các bước
244
-
245
- const instructions = {
246
- 2: [
247
- '**MODE: fast** — Gate 2 fast track:',
248
- '- Create a simple task list (task-level, NOT step-level)',
249
- '- DO NOT invoke `superpowers:writing-plans`',
250
- '- Format: numbered list of tasks, each with file + action',
251
- '- No code snippets, no step-by-step TDD breakdown required',
252
- ],
253
- 3: [
254
- '**MODE: fast** Gate 3 fast track:',
255
- '- INVOKE `tdd-lean` skill (NOT superpowers:test-driven-development)',
256
- '- tdd-lean uses Batch Red-Green-Refactor: 2–3 test runs total, never per-test',
257
- '- Test Output Discipline: keep only summary line after each run, discard stack traces',
258
- '- DO NOT use `superpowers:subagent-driven-development`',
259
- '- DO NOT spawn Spec Reviewer or Code Quality Reviewer subagents',
260
- '- Call `aiflow checkpoint` at each milestone (tests-written, code-done, tests-pass)',
261
- ],
262
- 4: [
263
- '**MODE: fast** Gate 4 fast track:',
264
- '- Run the full test suite — this is MANDATORY',
265
- '- Impact Analysis: quick scan only — reason from git diff and changed files.',
266
- ' DO NOT grep the entire codebase. List affected files and assess impact level.',
267
- '- Review checklist (3 items only): tests pass ✅, no hardcoded secrets ✅, no SQL injection ✅',
268
- '- summary.md: short format (Implementation table + Test result only)',
269
- ],
270
- };
271
-
272
- const lines = instructions[gate];
273
- return lines ? '\n' + lines.join('\n') : '';
274
- }
1
+ #!/usr/bin/env node
2
+ /**
3
+ * SessionStart hook for ai-flow-kit
4
+ * Injects:
5
+ * 1. using-superpowers skill content
6
+ * 2. Active ticket context + gate-aware workflow instruction
7
+ */
8
+
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+ const os = require('os');
12
+
13
+ function loadTelemetry() {
14
+ try { return require('../telemetry/record'); } catch (_) { }
15
+ return { record: () => { } };
16
+ }
17
+
18
+ function loadTelemetryConfig() {
19
+ try { return require('../telemetry/config'); } catch (_) { }
20
+ return { loadConfig: () => ({}) };
21
+ }
22
+
23
+ const { record } = loadTelemetry();
24
+ const { loadConfig } = loadTelemetryConfig();
25
+
26
+ // ── Paths (set once stdin is read) ────────────────────────────
27
+ let tasksDir = '';
28
+
29
+ let raw = '';
30
+ process.stdin.setEncoding('utf-8');
31
+ process.stdin.on('data', chunk => { raw += chunk; });
32
+ process.stdin.on('end', () => {
33
+ let hookData = {};
34
+ try { hookData = JSON.parse(raw || '{}'); } catch (_) { }
35
+
36
+ const sessionModel = hookData.model || '';
37
+ const cfg = loadConfig();
38
+
39
+ record('session.start', {
40
+ ai_tool: 'claude',
41
+ model: sessionModel || undefined,
42
+ ai_email: cfg.email || '',
43
+ });
44
+
45
+ // This script lives at .claude/hooks/session-start.js
46
+ // Project root is 2 levels up: .claude/hooks .claude → project root
47
+ const projectRoot = path.resolve(__dirname, '..', '..');
48
+ const skillPath = path.join(projectRoot, '.claude', 'skills', 'using-superpowers', 'SKILL.md');
49
+ const contextPath = path.join(projectRoot, '.aiflow', 'context', 'current.json');
50
+ tasksDir = path.join(projectRoot, '.aiflow', 'tasks');
51
+
52
+ // ── 1. Load superpowers skill ──────────────────────────────────
53
+ let skillContent = '';
54
+ try {
55
+ skillContent = fs.readFileSync(skillPath, 'utf-8');
56
+ } catch (_) {
57
+ process.stderr.write('[aiflow] WARNING: using-superpowers skill missing — run `aiflow update`\n');
58
+ }
59
+
60
+ // ── 2. Load active ticket context ──────────────────────────────
61
+ let contextBlock = '';
62
+ try {
63
+ if (fs.existsSync(contextPath)) {
64
+ const ctx = JSON.parse(fs.readFileSync(contextPath, 'utf-8'));
65
+ if (ctx.taskId && ctx.title) {
66
+ const taskState = loadTaskState(ctx.taskId);
67
+ contextBlock = buildContextPrompt(ctx, taskState);
68
+ }
69
+ }
70
+ } catch (_) { }
71
+
72
+ // ── 3. Check GitNexus background indexing status ───────────────
73
+ const GITNEXUS_STALE_MS = 3 * 60 * 60 * 1000;
74
+ const gitNexusStatusPath = path.join(projectRoot, '.aiflow', 'gitnexus-status.json');
75
+ try {
76
+ if (fs.existsSync(gitNexusStatusPath)) {
77
+ const gn = JSON.parse(fs.readFileSync(gitNexusStatusPath, 'utf-8'));
78
+ if (!gn.notified) {
79
+ if (gn.status === 'running' && gn.startedAt) {
80
+ const age = Date.now() - new Date(gn.startedAt).getTime();
81
+ if (age > GITNEXUS_STALE_MS) {
82
+ gn.status = 'error';
83
+ gn.error = 'timed out — process may have been killed or ran out of memory';
84
+ }
85
+ }
86
+ if (gn.status === 'done') {
87
+ process.stderr.write('[aiflow] GitNexus indexing complete — code intelligence tools are ready.\n');
88
+ } else if (gn.status === 'error') {
89
+ const detail = gn.error ? ` (${gn.error})` : gn.exitCode != null ? ` (exit ${gn.exitCode})` : '';
90
+ process.stderr.write(`[aiflow] ✗ GitNexus indexing failed${detail}.\n`);
91
+ }
92
+ if (gn.status === 'done' || gn.status === 'error') {
93
+ gn.notified = true;
94
+ fs.writeFileSync(gitNexusStatusPath, JSON.stringify(gn, null, 2));
95
+ }
96
+ }
97
+ }
98
+ } catch (_) { }
99
+
100
+ // ── 4. Combine and output ──────────────────────────────────────
101
+ const parts = [];
102
+ if (skillContent) {
103
+ parts.push(`<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n**Below is the full content of your 'superpowers:using-superpowers' skill - your introduction to using skills. For all other skills, use the 'Skill' tool:**\n\n${skillContent}\n\n</EXTREMELY_IMPORTANT>`);
104
+ }
105
+ if (contextBlock) {
106
+ parts.push(contextBlock);
107
+ }
108
+
109
+ const combined = parts.join('\n\n');
110
+ const escaped = combined
111
+ .replace(/\\/g, '\\\\')
112
+ .replace(/"/g, '\\"')
113
+ .replace(/\n/g, '\\n')
114
+ .replace(/\r/g, '\\r')
115
+ .replace(/\t/g, '\\t');
116
+
117
+ process.stdout.write(JSON.stringify({
118
+ hookSpecificOutput: {
119
+ hookEventName: 'SessionStart',
120
+ additionalContext: escaped
121
+ }
122
+ }));
123
+
124
+ process.exit(0);
125
+ });
126
+
127
+ // ── Helpers ────────────────────────────────────────────────────
128
+
129
+ function loadTaskState(taskId) {
130
+ try {
131
+ const statePath = path.join(tasksDir, taskId, 'task-state.json');
132
+ if (fs.existsSync(statePath)) {
133
+ return JSON.parse(fs.readFileSync(statePath, 'utf-8'));
134
+ }
135
+ } catch (_) { }
136
+ return null;
137
+ }
138
+
139
+ function buildContextPrompt(ctx, taskState) {
140
+ const lines = [];
141
+ lines.push('<ACTIVE_TASK>');
142
+ lines.push(`**Active Ticket:** ${ctx.taskId} ${ctx.title}`);
143
+ lines.push(`**Type:** ${ctx.taskType || 'feature'}`);
144
+ lines.push(`**Status:** ${ctx.status || 'Unknown'}`);
145
+ lines.push(`**Assignee:** ${ctx.assignee || 'Unknown'}`);
146
+ lines.push('');
147
+
148
+ if (ctx.description) {
149
+ lines.push('**Description:**');
150
+ lines.push(ctx.description.substring(0, 2000));
151
+ lines.push('');
152
+ }
153
+
154
+ if (ctx.acceptanceCriteria && ctx.acceptanceCriteria.length > 0) {
155
+ lines.push('**Acceptance Criteria:**');
156
+ for (const c of ctx.acceptanceCriteria) lines.push(`- ${c}`);
157
+ lines.push('');
158
+ }
159
+
160
+ if (ctx.comments && ctx.comments.length > 0) {
161
+ lines.push(`**Comments (${ctx.comments.length}):**`);
162
+ const recent = ctx.comments.slice(-5);
163
+ for (const c of recent) { lines.push(c); lines.push(''); }
164
+ }
165
+
166
+ if (ctx.context && ctx.context.files && ctx.context.files.length > 0) {
167
+ lines.push('**Related Files:**');
168
+ for (const f of ctx.context.files) lines.push(`- \`${f}\``);
169
+ lines.push('');
170
+ }
171
+
172
+ lines.push('---');
173
+ lines.push('');
174
+
175
+ const mode = ctx.mode || 'fast';
176
+ const currentGate = taskState && taskState.currentGate ? taskState.currentGate : 1;
177
+ const isResume = taskState && (taskState.pausedAt || taskState.currentGate > 1);
178
+
179
+ if (isResume && currentGate > 1) {
180
+ const gateApprovals = taskState.gateApprovals || {};
181
+ lines.push(`**RESUMING TASK: ${ctx.taskId} Gate ${currentGate}**`);
182
+ lines.push('');
183
+ lines.push('This task was previously paused and is now being resumed.');
184
+ lines.push('');
185
+ lines.push('**Gate Progress:**');
186
+ for (let g = 1; g < currentGate; g++) {
187
+ const approvedAt = gateApprovals[String(g)];
188
+ const stamp = approvedAt ? ` approved ${approvedAt}` : ' — approved';
189
+ lines.push(`- Gate ${g}: APPROVED${stamp}`);
190
+ }
191
+ lines.push(`- Gate ${currentGate}: 🔄 IN PROGRESS`);
192
+ lines.push('');
193
+ lines.push(`**DO NOT restart from Gate 1.** Resume directly at Gate ${currentGate} (${gateLabel(currentGate)}).`);
194
+ lines.push('');
195
+
196
+ if (currentGate === 2) {
197
+ lines.push('Gate 1 is already APPROVED. The requirement document is at:');
198
+ lines.push(` plan/${ctx.taskId}/requirement.md`);
199
+ lines.push('');
200
+ lines.push('Proceed to Gate 2: create the implementation plan.');
201
+ lines.push(buildModeInstruction(mode, 2));
202
+ } else if (currentGate === 3) {
203
+ lines.push('Gates 1 and 2 are already APPROVED. Plans are at:');
204
+ lines.push(` plan/${ctx.taskId}/requirement.md`);
205
+ lines.push(` plan/${ctx.taskId}/plan.md`);
206
+ lines.push('');
207
+ lines.push('Proceed to Gate 3: implement code following the plan (TDD).');
208
+ lines.push(buildModeInstruction(mode, 3));
209
+ } else if (currentGate === 4) {
210
+ lines.push('Gates 1–3 are APPROVED. Code has been implemented.');
211
+ lines.push('Proceed to Gate 4: run verification + impact-analysis + review checklist.');
212
+ lines.push(buildModeInstruction(mode, 4));
213
+ } else if (currentGate === 5) {
214
+ lines.push('Gates 1–4 are APPROVED. Self-review is done.');
215
+ lines.push('Proceed to Gate 5: guide the developer to create a Pull Request.');
216
+ }
217
+ if (taskState.notes) {
218
+ lines.push('');
219
+ lines.push(`**Note from developer:** ${taskState.notes}`);
220
+ }
221
+ } else {
222
+ lines.push('**AUTO-START GATE 1: You MUST begin analyzing this ticket immediately.**');
223
+ lines.push('');
224
+ lines.push(`INVOKE the \`read-study-requirement\` skill NOW for ticket ${ctx.taskId}.`);
225
+ lines.push('');
226
+
227
+ if (mode === 'fast') {
228
+ lines.push('**MODE: fast** — Use the FAST TRACK path in the skill:');
229
+ lines.push('- Read ticket + identify changed files only (no deep source scan)');
230
+ lines.push('- Skip Q&A unless there is a critical blocking ambiguity');
231
+ lines.push('- Output a lite requirement doc (Sections 1, 3, 5 only)');
232
+ lines.push('- Target: Gate 1 complete in < 5 minutes');
233
+ } else {
234
+ lines.push('Gate 1 process:');
235
+ lines.push('1. Read the ticket context above');
236
+ lines.push('2. Read CLAUDE.md — understand project architecture and conventions');
237
+ lines.push('3. Read source code — identify related files, data flow, patterns');
238
+ lines.push('4. If anything is unclear — ask ONE question at a time');
239
+ lines.push('5. Output plan/' + ctx.taskId + '/requirement.md');
240
+ lines.push('6. Display GATE 1 prompt and wait for APPROVED');
241
+ }
242
+
243
+ lines.push('');
244
+ lines.push('DO NOT wait for the developer to ask. START NOW.');
245
+ lines.push('If you have not started automatically, begin as soon as the developer types **"start"**.');
246
+ }
247
+
248
+ lines.push('</ACTIVE_TASK>');
249
+ return lines.join('\n');
250
+ }
251
+
252
+ function gateLabel(n) {
253
+ const labels = {
254
+ 1: 'AI Analyze Requirement',
255
+ 2: 'Implementation Plan',
256
+ 3: 'Code Generation',
257
+ 4: 'AI Self-Review',
258
+ 5: 'Peer Review & PR',
259
+ };
260
+ return labels[n] || `Gate ${n}`;
261
+ }
262
+
263
+ function buildModeInstruction(mode, gate) {
264
+ if (mode !== 'fast') return '';
265
+
266
+ const instructions = {
267
+ 2: [
268
+ '**MODE: fast** Gate 2 fast track:',
269
+ '- Create a simple task list (task-level, NOT step-level)',
270
+ '- DO NOT invoke `superpowers:writing-plans`',
271
+ '- Format: numbered list of tasks, each with file + action',
272
+ '- No code snippets, no step-by-step TDD breakdown required',
273
+ ],
274
+ 3: [
275
+ '**MODE: fast** — Gate 3 fast track:',
276
+ '- INVOKE `tdd-lean` skill (NOT superpowers:test-driven-development)',
277
+ '- tdd-lean uses Batch Red-Green-Refactor: 2–3 test runs total, never per-test',
278
+ '- Test Output Discipline: keep only summary line after each run, discard stack traces',
279
+ '- DO NOT use `superpowers:subagent-driven-development`',
280
+ '- DO NOT spawn Spec Reviewer or Code Quality Reviewer subagents',
281
+ '- Call `aiflow checkpoint` at each milestone (tests-written, code-done, tests-pass)',
282
+ ],
283
+ 4: [
284
+ '**MODE: fast** — Gate 4 fast track:',
285
+ '- Run the full test suite — this is MANDATORY',
286
+ '- Impact Analysis: quick scan only — reason from git diff and changed files.',
287
+ ' DO NOT grep the entire codebase. List affected files and assess impact level.',
288
+ '- Review checklist (3 items only): tests pass ✅, no hardcoded secrets ✅, no SQL injection ✅',
289
+ '- summary.md: short format (Implementation table + Test result only)',
290
+ ],
291
+ };
292
+
293
+ const lines = instructions[gate];
294
+ return lines ? '\n' + lines.join('\n') : '';
295
+ }