agileflow 2.76.0 → 2.77.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.
@@ -36,24 +36,44 @@ const c = {
36
36
 
37
37
  // Agents that have expertise files
38
38
  const AGENTS_WITH_EXPERTISE = [
39
- 'accessibility', 'adr-writer', 'analytics', 'api', 'ci', 'compliance',
40
- 'database', 'datamigration', 'design', 'devops', 'documentation',
41
- 'epic-planner', 'integrations', 'mentor', 'mobile', 'monitoring',
42
- 'performance', 'product', 'qa', 'readme-updater', 'refactor',
43
- 'research', 'security', 'testing', 'ui'
39
+ 'accessibility',
40
+ 'adr-writer',
41
+ 'analytics',
42
+ 'api',
43
+ 'ci',
44
+ 'compliance',
45
+ 'database',
46
+ 'datamigration',
47
+ 'design',
48
+ 'devops',
49
+ 'documentation',
50
+ 'epic-planner',
51
+ 'integrations',
52
+ 'mentor',
53
+ 'mobile',
54
+ 'monitoring',
55
+ 'performance',
56
+ 'product',
57
+ 'qa',
58
+ 'readme-updater',
59
+ 'refactor',
60
+ 'research',
61
+ 'security',
62
+ 'testing',
63
+ 'ui',
44
64
  ];
45
65
 
46
66
  // File patterns that suggest domain expertise
47
67
  const DOMAIN_PATTERNS = {
48
- 'database': [/schema/, /migration/, /\.sql$/, /prisma/, /drizzle/, /sequelize/],
49
- 'api': [/\/api\//, /controller/, /route/, /endpoint/, /graphql/],
50
- 'ui': [/component/, /\.tsx$/, /\.jsx$/, /styles/, /\.css$/, /\.scss$/],
51
- 'testing': [/\.test\./, /\.spec\./, /__tests__/, /jest/, /vitest/],
52
- 'security': [/auth/, /password/, /token/, /jwt/, /oauth/, /permission/],
53
- 'ci': [/\.github\/workflows/, /\.gitlab-ci/, /dockerfile/i, /docker-compose/],
54
- 'documentation': [/\.md$/, /readme/i, /docs\//, /jsdoc/],
55
- 'performance': [/cache/, /optimize/, /performance/, /benchmark/],
56
- 'devops': [/deploy/, /kubernetes/, /k8s/, /terraform/, /ansible/],
68
+ database: [/schema/, /migration/, /\.sql$/, /prisma/, /drizzle/, /sequelize/],
69
+ api: [/\/api\//, /controller/, /route/, /endpoint/, /graphql/],
70
+ ui: [/component/, /\.tsx$/, /\.jsx$/, /styles/, /\.css$/, /\.scss$/],
71
+ testing: [/\.test\./, /\.spec\./, /__tests__/, /jest/, /vitest/],
72
+ security: [/auth/, /password/, /token/, /jwt/, /oauth/, /permission/],
73
+ ci: [/\.github\/workflows/, /\.gitlab-ci/, /dockerfile/i, /docker-compose/],
74
+ documentation: [/\.md$/, /readme/i, /docs\//, /jsdoc/],
75
+ performance: [/cache/, /optimize/, /performance/, /benchmark/],
76
+ devops: [/deploy/, /kubernetes/, /k8s/, /terraform/, /ansible/],
57
77
  };
58
78
 
59
79
  // Find project root
@@ -83,19 +103,28 @@ function getGitDiff(rootDir) {
83
103
  const diffFiles = execSync('git diff --name-only HEAD 2>/dev/null || git diff --name-only', {
84
104
  cwd: rootDir,
85
105
  encoding: 'utf8',
86
- }).trim().split('\n').filter(Boolean);
106
+ })
107
+ .trim()
108
+ .split('\n')
109
+ .filter(Boolean);
87
110
 
88
111
  // Get staged files
89
112
  const stagedFiles = execSync('git diff --cached --name-only 2>/dev/null', {
90
113
  cwd: rootDir,
91
114
  encoding: 'utf8',
92
- }).trim().split('\n').filter(Boolean);
115
+ })
116
+ .trim()
117
+ .split('\n')
118
+ .filter(Boolean);
93
119
 
94
120
  // Get untracked files
95
121
  const untrackedFiles = execSync('git ls-files --others --exclude-standard 2>/dev/null', {
96
122
  cwd: rootDir,
97
123
  encoding: 'utf8',
98
- }).trim().split('\n').filter(Boolean);
124
+ })
125
+ .trim()
126
+ .split('\n')
127
+ .filter(Boolean);
99
128
 
100
129
  // Combine all
101
130
  const allFiles = [...new Set([...diffFiles, ...stagedFiles, ...untrackedFiles])];
@@ -186,7 +215,16 @@ function getExpertisePath(rootDir, agent) {
186
215
  if (fs.existsSync(installedPath)) return installedPath;
187
216
 
188
217
  // Try source location
189
- const sourcePath = path.join(rootDir, 'packages', 'cli', 'src', 'core', 'experts', agent, 'expertise.yaml');
218
+ const sourcePath = path.join(
219
+ rootDir,
220
+ 'packages',
221
+ 'cli',
222
+ 'src',
223
+ 'core',
224
+ 'experts',
225
+ agent,
226
+ 'expertise.yaml'
227
+ );
190
228
  if (fs.existsSync(sourcePath)) return sourcePath;
191
229
 
192
230
  return null;
@@ -219,7 +257,10 @@ function appendLearning(expertisePath, learning) {
219
257
  // Format learning as YAML
220
258
  function formatLearning(summary, files, detectedDomain) {
221
259
  const date = new Date().toISOString().split('T')[0];
222
- const topFiles = files.slice(0, 5).map(f => ` - ${f}`).join('\n');
260
+ const topFiles = files
261
+ .slice(0, 5)
262
+ .map(f => ` - ${f}`)
263
+ .join('\n');
223
264
 
224
265
  return ` - date: "${date}"
225
266
  auto_generated: true
@@ -281,7 +322,9 @@ function main() {
281
322
  console.log('');
282
323
  console.log(`${c.green}✓ Auto-learned:${c.reset} ${c.dim}${activeAgent}${c.reset}`);
283
324
  console.log(`${c.dim} ${summary}${c.reset}`);
284
- console.log(`${c.dim} → Updated ${path.basename(path.dirname(expertisePath))}/expertise.yaml${c.reset}`);
325
+ console.log(
326
+ `${c.dim} → Updated ${path.basename(path.dirname(expertisePath))}/expertise.yaml${c.reset}`
327
+ );
285
328
  console.log('');
286
329
  }
287
330
  }
@@ -232,10 +232,7 @@ async function checkForUpdates(options = {}) {
232
232
  }
233
233
 
234
234
  // Check if we just updated (lastSeenVersion < installed)
235
- if (
236
- config.lastSeenVersion &&
237
- compareVersions(config.lastSeenVersion, installedVersion) < 0
238
- ) {
235
+ if (config.lastSeenVersion && compareVersions(config.lastSeenVersion, installedVersion) < 0) {
239
236
  result.justUpdated = true;
240
237
  result.previousVersion = config.lastSeenVersion;
241
238
  }
@@ -154,32 +154,40 @@ function formatOutput(info, asJson = false, compact = false) {
154
154
  cyan: '\x1b[36m',
155
155
  red: '\x1b[31m',
156
156
  brand: '\x1b[38;2;232;104;58m', // #e8683a - AgileFlow brand orange
157
+
158
+ // Vibrant 256-color palette (modern, sleek look)
159
+ mintGreen: '\x1b[38;5;158m', // Healthy/success states
160
+ peach: '\x1b[38;5;215m', // Warning states
161
+ coral: '\x1b[38;5;203m', // Critical/error states
162
+ lightGreen: '\x1b[38;5;194m', // Session healthy
163
+ skyBlue: '\x1b[38;5;117m', // Directories/paths
164
+ lavender: '\x1b[38;5;147m', // Model info
157
165
  };
158
166
 
159
- // Beautiful compact colorful format
167
+ // Beautiful compact colorful format (using vibrant 256-color palette)
160
168
  const lines = [];
161
169
 
162
170
  // Header line with project info (brand color name, dim version, colored branch)
163
- const branchColor = info.git.branch === 'main' ? c.green : c.cyan;
171
+ const branchColor = info.git.branch === 'main' ? c.mintGreen : c.skyBlue;
164
172
  lines.push(
165
173
  `${c.brand}${c.bold}${info.project.name}${c.reset} ${c.dim}v${info.project.version}${c.reset} | ${branchColor}${info.git.branch}${c.reset} ${c.dim}(${info.git.commit})${c.reset}`
166
174
  );
167
175
 
168
- // Status line (yellow WIP, red blocked)
169
- const wipColor = info.agileflow.wipCount > 0 ? c.yellow : c.dim;
176
+ // Status line (peach WIP, coral blocked)
177
+ const wipColor = info.agileflow.wipCount > 0 ? c.peach : c.dim;
170
178
  let statusLine =
171
179
  info.agileflow.wipCount > 0
172
180
  ? `${wipColor}WIP: ${info.agileflow.wipCount}${c.reset}`
173
181
  : `${c.dim}No active work${c.reset}`;
174
182
  if (info.agileflow.blockedCount > 0) {
175
- statusLine += ` | ${c.red}Blocked: ${info.agileflow.blockedCount}${c.reset}`;
183
+ statusLine += ` | ${c.coral}Blocked: ${info.agileflow.blockedCount}${c.reset}`;
176
184
  }
177
185
  lines.push(statusLine);
178
186
 
179
- // Active story (if any) - just the first one (blue label)
187
+ // Active story (if any) - just the first one (sky blue label)
180
188
  if (info.agileflow.activeStories.length > 0) {
181
189
  const story = info.agileflow.activeStories[0];
182
- lines.push(`${c.blue}Current:${c.reset} ${story.id} - ${story.title}`);
190
+ lines.push(`${c.skyBlue}Current:${c.reset} ${story.id} - ${story.title}`);
183
191
  }
184
192
 
185
193
  // Last commit (just one, dim)
@@ -69,7 +69,10 @@ function normalizeTools(tools) {
69
69
  if (!tools) return [];
70
70
  if (Array.isArray(tools)) return tools;
71
71
  if (typeof tools === 'string') {
72
- return tools.split(',').map(t => t.trim()).filter(Boolean);
72
+ return tools
73
+ .split(',')
74
+ .map(t => t.trim())
75
+ .filter(Boolean);
73
76
  }
74
77
  return [];
75
78
  }
@@ -55,6 +55,16 @@ const C = {
55
55
  brightYellow: '\x1b[93m',
56
56
  brightGreen: '\x1b[92m',
57
57
  brand: '\x1b[38;2;232;104;58m', // AgileFlow brand orange
58
+
59
+ // Vibrant 256-color palette (modern, sleek look)
60
+ mintGreen: '\x1b[38;5;158m', // Healthy/success states
61
+ peach: '\x1b[38;5;215m', // Warning states
62
+ coral: '\x1b[38;5;203m', // Critical/error states
63
+ lightGreen: '\x1b[38;5;194m', // Session healthy
64
+ lightYellow: '\x1b[38;5;228m', // Session warning
65
+ skyBlue: '\x1b[38;5;117m', // Directories/paths
66
+ lavender: '\x1b[38;5;147m', // Model info
67
+ softGold: '\x1b[38;5;222m', // Cost/money
58
68
  };
59
69
 
60
70
  function safeRead(filePath) {
@@ -111,7 +121,7 @@ function generateSummary() {
111
121
 
112
122
  const W = 58; // Total inner width (matches welcome script)
113
123
  const L = 20; // Left column width
114
- const R = W - L - 3; // Right column width (35 chars)
124
+ const R = W - 24; // Right column width (34 chars) - matches welcome
115
125
 
116
126
  // Pad string to length, accounting for ANSI codes
117
127
  function pad(str, len) {
@@ -155,11 +165,12 @@ function generateSummary() {
155
165
  return `${C.dim}${box.v}${C.reset} ${pad(leftStr, L)} ${C.dim}${box.v}${C.reset} ${pad(rightStr, R)} ${C.dim}${box.v}${C.reset}\n`;
156
166
  }
157
167
 
168
+ // All borders use same width formula: 22 dashes + separator + 36 dashes = 61 total chars
158
169
  const divider = () =>
159
- `${C.dim}${box.lT}${box.h.repeat(L + 2)}${box.cross}${box.h.repeat(R + 2)}${box.rT}${C.reset}\n`;
160
- const headerTopBorder = `${C.dim}${box.tl}${box.h.repeat(W + 2)}${box.tr}${C.reset}\n`;
161
- const headerDivider = `${C.dim}${box.lT}${box.h.repeat(L + 2)}${box.tT}${box.h.repeat(R + 2)}${box.rT}${C.reset}\n`;
162
- const bottomBorder = `${C.dim}${box.bl}${box.h.repeat(L + 2)}${box.bT}${box.h.repeat(R + 2)}${box.br}${C.reset}\n`;
170
+ `${C.dim}${box.lT}${box.h.repeat(L + 2)}${box.cross}${box.h.repeat(W - L - 2)}${box.rT}${C.reset}\n`;
171
+ const headerTopBorder = `${C.dim}${box.tl}${box.h.repeat(L + 2)}${box.tT}${box.h.repeat(W - L - 2)}${box.tr}${C.reset}\n`;
172
+ const headerDivider = `${C.dim}${box.lT}${box.h.repeat(L + 2)}${box.tT}${box.h.repeat(W - L - 2)}${box.rT}${C.reset}\n`;
173
+ const bottomBorder = `${C.dim}${box.bl}${box.h.repeat(L + 2)}${box.bT}${box.h.repeat(W - L - 2)}${box.br}${C.reset}\n`;
163
174
 
164
175
  // Gather data
165
176
  const branch = safeExec('git branch --show-current') || 'unknown';
@@ -200,35 +211,35 @@ function generateSummary() {
200
211
 
201
212
  // Header row (full width, no column divider)
202
213
  const title = commandName ? `Context [${commandName}]` : 'Context Summary';
203
- const branchColor = branch === 'main' ? C.green : branch.startsWith('fix') ? C.red : C.cyan;
214
+ const branchColor = branch === 'main' ? C.mintGreen : branch.startsWith('fix') ? C.coral : C.skyBlue;
204
215
  const maxBranchLen = 20;
205
216
  const branchDisplay =
206
217
  branch.length > maxBranchLen ? branch.substring(0, maxBranchLen - 2) + '..' : branch;
207
218
  const header = `${C.brand}${C.bold}${title}${C.reset} ${branchColor}${branchDisplay}${C.reset} ${C.dim}(${lastCommitShort})${C.reset}`;
208
- summary += `${C.dim}${box.v}${C.reset} ${pad(header, W)} ${C.dim}${box.v}${C.reset}\n`;
219
+ summary += `${C.dim}${box.v}${C.reset} ${pad(header, W - 1)} ${C.dim}${box.v}${C.reset}\n`;
209
220
 
210
221
  summary += headerDivider;
211
222
 
212
- // Story counts with colorful labels
223
+ // Story counts with vibrant 256-color palette
213
224
  summary += row(
214
225
  'In Progress',
215
226
  byStatus['in-progress'] ? `${byStatus['in-progress']}` : '0',
216
- C.yellow,
217
- byStatus['in-progress'] ? C.brightYellow : C.dim
227
+ C.peach,
228
+ byStatus['in-progress'] ? C.peach : C.dim
218
229
  );
219
230
  summary += row(
220
231
  'Blocked',
221
232
  byStatus['blocked'] ? `${byStatus['blocked']}` : '0',
222
- C.red,
223
- byStatus['blocked'] ? C.red : C.dim
233
+ C.coral,
234
+ byStatus['blocked'] ? C.coral : C.dim
224
235
  );
225
236
  summary += row(
226
237
  'Ready',
227
238
  byStatus['ready'] ? `${byStatus['ready']}` : '0',
228
- C.cyan,
229
- byStatus['ready'] ? C.brightCyan : C.dim
239
+ C.skyBlue,
240
+ byStatus['ready'] ? C.skyBlue : C.dim
230
241
  );
231
- const completedColor = `${C.bold}${C.green}`;
242
+ const completedColor = `${C.bold}${C.mintGreen}`;
232
243
  summary += row(
233
244
  'Completed',
234
245
  byStatus['done'] ? `${byStatus['done']}` : '0',
@@ -238,27 +249,27 @@ function generateSummary() {
238
249
 
239
250
  summary += divider();
240
251
 
241
- // Git status
252
+ // Git status (using vibrant 256-color palette)
242
253
  const uncommittedStatus =
243
254
  statusLines.length > 0 ? `${statusLines.length} uncommitted` : '✓ clean';
244
- summary += row('Git', uncommittedStatus, C.blue, statusLines.length > 0 ? C.yellow : C.green);
255
+ summary += row('Git', uncommittedStatus, C.blue, statusLines.length > 0 ? C.peach : C.mintGreen);
245
256
 
246
257
  // Session
247
258
  const sessionText = sessionDuration !== null ? `${sessionDuration} min active` : 'no session';
248
- summary += row('Session', sessionText, C.blue, sessionDuration !== null ? C.brightGreen : C.dim);
259
+ summary += row('Session', sessionText, C.blue, sessionDuration !== null ? C.lightGreen : C.dim);
249
260
 
250
261
  // Current story
251
262
  const storyText = currentStory ? currentStory : 'none';
252
- summary += row('Working on', storyText, C.blue, currentStory ? C.brightYellow : C.dim);
263
+ summary += row('Working on', storyText, C.blue, currentStory ? C.lightYellow : C.dim);
253
264
 
254
265
  // Ready stories (if any)
255
266
  if (readyStories.length > 0) {
256
- summary += row('⭐ Up Next', readyStories.slice(0, 3).join(', '), C.brightCyan, C.cyan);
267
+ summary += row('⭐ Up Next', readyStories.slice(0, 3).join(', '), C.skyBlue, C.skyBlue);
257
268
  }
258
269
 
259
270
  summary += divider();
260
271
 
261
- // Key files
272
+ // Key files (using vibrant 256-color palette)
262
273
  const keyFileChecks = [
263
274
  { path: 'CLAUDE.md', label: 'CLAUDE' },
264
275
  { path: 'README.md', label: 'README' },
@@ -268,31 +279,31 @@ function generateSummary() {
268
279
  const keyFileStatus = keyFileChecks
269
280
  .map(f => {
270
281
  const exists = fs.existsSync(f.path);
271
- return exists ? `${C.brightGreen}✓${C.reset}${f.label}` : `${C.dim}○${f.label}${C.reset}`;
282
+ return exists ? `${C.mintGreen}✓${C.reset}${f.label}` : `${C.dim}○${f.label}${C.reset}`;
272
283
  })
273
284
  .join(' ');
274
- summary += row('Key files', keyFileStatus, C.magenta, '');
285
+ summary += row('Key files', keyFileStatus, C.lavender, '');
275
286
 
276
287
  // Research
277
288
  const researchText = researchFiles.length > 0 ? `${researchFiles.length} notes` : 'none';
278
- summary += row('Research', researchText, C.magenta, researchFiles.length > 0 ? C.cyan : C.dim);
289
+ summary += row('Research', researchText, C.lavender, researchFiles.length > 0 ? C.skyBlue : C.dim);
279
290
 
280
291
  // Epics
281
292
  const epicText = epicFiles.length > 0 ? `${epicFiles.length} epics` : 'none';
282
- summary += row('Epics', epicText, C.magenta, epicFiles.length > 0 ? C.cyan : C.dim);
293
+ summary += row('Epics', epicText, C.lavender, epicFiles.length > 0 ? C.skyBlue : C.dim);
283
294
 
284
295
  summary += divider();
285
296
 
286
- // Last commit
297
+ // Last commit (using vibrant 256-color palette)
287
298
  summary += row(
288
299
  'Last commit',
289
- `${C.yellow}${lastCommitShort}${C.reset} ${lastCommitMsg}`,
300
+ `${C.peach}${lastCommitShort}${C.reset} ${lastCommitMsg}`,
290
301
  C.dim,
291
302
  ''
292
303
  );
293
304
 
294
305
  summary += bottomBorder;
295
-
306
+ summary += '\n';
296
307
  summary += `${C.dim}Full context continues below (Claude sees all)...${C.reset}\n\n`;
297
308
 
298
309
  return summary;
@@ -306,29 +317,29 @@ function generateFullContent() {
306
317
  let content = '';
307
318
 
308
319
  const title = commandName ? `AgileFlow Context [${commandName}]` : 'AgileFlow Context';
309
- content += `${C.magenta}${C.bold}${title}${C.reset}\n`;
320
+ content += `${C.lavender}${C.bold}${title}${C.reset}\n`;
310
321
  content += `${C.dim}Generated: ${new Date().toISOString()}${C.reset}\n`;
311
322
 
312
- // 1. GIT STATUS
313
- content += `\n${C.cyan}${C.bold}═══ Git Status ═══${C.reset}\n`;
323
+ // 1. GIT STATUS (using vibrant 256-color palette)
324
+ content += `\n${C.skyBlue}${C.bold}═══ Git Status ═══${C.reset}\n`;
314
325
  const branch = safeExec('git branch --show-current') || 'unknown';
315
326
  const status = safeExec('git status --short') || '';
316
327
  const statusLines = status.split('\n').filter(Boolean);
317
328
  const lastCommit = safeExec('git log -1 --format="%h %s"') || 'no commits';
318
329
 
319
- content += `Branch: ${C.green}${branch}${C.reset}\n`;
330
+ content += `Branch: ${C.mintGreen}${branch}${C.reset}\n`;
320
331
  content += `Last commit: ${C.dim}${lastCommit}${C.reset}\n`;
321
332
  if (statusLines.length > 0) {
322
- content += `Uncommitted: ${C.yellow}${statusLines.length} file(s)${C.reset}\n`;
333
+ content += `Uncommitted: ${C.peach}${statusLines.length} file(s)${C.reset}\n`;
323
334
  statusLines.slice(0, 10).forEach(line => (content += ` ${C.dim}${line}${C.reset}\n`));
324
335
  if (statusLines.length > 10)
325
336
  content += ` ${C.dim}... and ${statusLines.length - 10} more${C.reset}\n`;
326
337
  } else {
327
- content += `Uncommitted: ${C.green}clean${C.reset}\n`;
338
+ content += `Uncommitted: ${C.mintGreen}clean${C.reset}\n`;
328
339
  }
329
340
 
330
- // 2. STATUS.JSON - Full Content
331
- content += `\n${C.cyan}${C.bold}═══ Status.json (Full Content) ═══${C.reset}\n`;
341
+ // 2. STATUS.JSON - Full Content (using vibrant 256-color palette)
342
+ content += `\n${C.skyBlue}${C.bold}═══ Status.json (Full Content) ═══${C.reset}\n`;
332
343
  const statusJsonPath = 'docs/09-agents/status.json';
333
344
  const statusJson = safeReadJSON(statusJsonPath);
334
345
 
@@ -344,30 +355,30 @@ function generateFullContent() {
344
355
  content += `${C.dim}No status.json found${C.reset}\n`;
345
356
  }
346
357
 
347
- // 3. SESSION STATE
348
- content += `\n${C.cyan}${C.bold}═══ Session State ═══${C.reset}\n`;
358
+ // 3. SESSION STATE (using vibrant 256-color palette)
359
+ content += `\n${C.skyBlue}${C.bold}═══ Session State ═══${C.reset}\n`;
349
360
  const sessionState = safeReadJSON('docs/09-agents/session-state.json');
350
361
  if (sessionState) {
351
362
  const current = sessionState.current_session;
352
363
  if (current && current.started_at) {
353
364
  const started = new Date(current.started_at);
354
365
  const duration = Math.round((Date.now() - started.getTime()) / 60000);
355
- content += `Active session: ${C.green}${duration} min${C.reset}\n`;
366
+ content += `Active session: ${C.lightGreen}${duration} min${C.reset}\n`;
356
367
  if (current.current_story) {
357
- content += `Working on: ${C.yellow}${current.current_story}${C.reset}\n`;
368
+ content += `Working on: ${C.lightYellow}${current.current_story}${C.reset}\n`;
358
369
  }
359
370
  } else {
360
371
  content += `${C.dim}No active session${C.reset}\n`;
361
372
  }
362
373
  if (sessionState.active_command) {
363
- content += `Active command: ${C.cyan}${sessionState.active_command.name}${C.reset}\n`;
374
+ content += `Active command: ${C.skyBlue}${sessionState.active_command.name}${C.reset}\n`;
364
375
  }
365
376
  } else {
366
377
  content += `${C.dim}No session-state.json found${C.reset}\n`;
367
378
  }
368
379
 
369
- // 4. DOCS STRUCTURE
370
- content += `\n${C.cyan}${C.bold}═══ Documentation ═══${C.reset}\n`;
380
+ // 4. DOCS STRUCTURE (using vibrant 256-color palette)
381
+ content += `\n${C.skyBlue}${C.bold}═══ Documentation ═══${C.reset}\n`;
371
382
  const docsDir = 'docs';
372
383
  const docFolders = safeLs(docsDir).filter(f => {
373
384
  try {
@@ -390,8 +401,8 @@ function generateFullContent() {
390
401
  });
391
402
  }
392
403
 
393
- // 5. RESEARCH NOTES - List + Full content of most recent
394
- content += `\n${C.cyan}${C.bold}═══ Research Notes ═══${C.reset}\n`;
404
+ // 5. RESEARCH NOTES - List + Full content of most recent (using vibrant 256-color palette)
405
+ content += `\n${C.skyBlue}${C.bold}═══ Research Notes ═══${C.reset}\n`;
395
406
  const researchDir = 'docs/10-research';
396
407
  const researchFiles = safeLs(researchDir).filter(f => f.endsWith('.md') && f !== 'README.md');
397
408
  if (researchFiles.length > 0) {
@@ -404,7 +415,7 @@ function generateFullContent() {
404
415
  const mostRecentContent = safeRead(mostRecentPath);
405
416
 
406
417
  if (mostRecentContent) {
407
- content += `\n${C.green}📄 Most Recent: ${mostRecentFile}${C.reset}\n`;
418
+ content += `\n${C.mintGreen}📄 Most Recent: ${mostRecentFile}${C.reset}\n`;
408
419
  content += `${C.dim}${'─'.repeat(60)}${C.reset}\n`;
409
420
  content += mostRecentContent + '\n';
410
421
  content += `${C.dim}${'─'.repeat(60)}${C.reset}\n`;
@@ -413,8 +424,8 @@ function generateFullContent() {
413
424
  content += `${C.dim}No research notes${C.reset}\n`;
414
425
  }
415
426
 
416
- // 6. BUS MESSAGES
417
- content += `\n${C.cyan}${C.bold}═══ Recent Agent Messages ═══${C.reset}\n`;
427
+ // 6. BUS MESSAGES (using vibrant 256-color palette)
428
+ content += `\n${C.skyBlue}${C.bold}═══ Recent Agent Messages ═══${C.reset}\n`;
418
429
  const busPath = 'docs/09-agents/bus/log.jsonl';
419
430
  const busContent = safeRead(busPath);
420
431
  if (busContent) {
@@ -136,9 +136,7 @@ function getNextStory(status, epicId, currentStoryId) {
136
136
  // Get all stories in this epic that are ready
137
137
  const readyStories = Object.entries(stories)
138
138
  .filter(([id, story]) => {
139
- return story.epic === epicId &&
140
- story.status === 'ready' &&
141
- id !== currentStoryId;
139
+ return story.epic === epicId && story.status === 'ready' && id !== currentStoryId;
142
140
  })
143
141
  .sort((a, b) => {
144
142
  // Sort by story number if possible
@@ -215,9 +213,15 @@ function handleLoop(rootDir) {
215
213
  const maxIterations = loop.max_iterations || 20;
216
214
 
217
215
  console.log('');
218
- console.log(`${c.brand}${c.bold}══════════════════════════════════════════════════════════${c.reset}`);
219
- console.log(`${c.brand}${c.bold} RALPH LOOP - Iteration ${iteration}/${maxIterations}${c.reset}`);
220
- console.log(`${c.brand}${c.bold}══════════════════════════════════════════════════════════${c.reset}`);
216
+ console.log(
217
+ `${c.brand}${c.bold}══════════════════════════════════════════════════════════${c.reset}`
218
+ );
219
+ console.log(
220
+ `${c.brand}${c.bold} RALPH LOOP - Iteration ${iteration}/${maxIterations}${c.reset}`
221
+ );
222
+ console.log(
223
+ `${c.brand}${c.bold}══════════════════════════════════════════════════════════${c.reset}`
224
+ );
221
225
  console.log('');
222
226
 
223
227
  // Check iteration limit
@@ -243,7 +247,9 @@ function handleLoop(rootDir) {
243
247
  return;
244
248
  }
245
249
 
246
- console.log(`${c.cyan}Current Story:${c.reset} ${currentStoryId} - ${currentStory.title || 'Untitled'}`);
250
+ console.log(
251
+ `${c.cyan}Current Story:${c.reset} ${currentStoryId} - ${currentStory.title || 'Untitled'}`
252
+ );
247
253
  console.log('');
248
254
 
249
255
  // Run tests
@@ -283,11 +289,12 @@ function handleLoop(rootDir) {
283
289
  criteria.slice(0, 3).forEach(ac => console.log(` • ${ac}`));
284
290
  }
285
291
  console.log('');
286
- console.log(`${c.dim}Epic Progress: ${progress.completed}/${progress.total} stories complete${c.reset}`);
292
+ console.log(
293
+ `${c.dim}Epic Progress: ${progress.completed}/${progress.total} stories complete${c.reset}`
294
+ );
287
295
  console.log('');
288
296
  console.log(`${c.brand}▶ Continue implementing ${nextStory.id}${c.reset}`);
289
297
  console.log(`${c.dim} Run tests when ready. Loop will validate and continue.${c.reset}`);
290
-
291
298
  } else {
292
299
  // No more stories - epic complete!
293
300
  const progress = getEpicProgress(getStatus(rootDir), epicId);
@@ -297,15 +304,18 @@ function handleLoop(rootDir) {
297
304
  saveSessionState(rootDir, state);
298
305
 
299
306
  console.log('');
300
- console.log(`${c.green}${c.bold}════════════════════════════════════════════════════════${c.reset}`);
307
+ console.log(
308
+ `${c.green}${c.bold}════════════════════════════════════════════════════════${c.reset}`
309
+ );
301
310
  console.log(`${c.green}${c.bold} 🎉 EPIC COMPLETE!${c.reset}`);
302
- console.log(`${c.green}${c.bold}════════════════════════════════════════════════════════${c.reset}`);
311
+ console.log(
312
+ `${c.green}${c.bold}════════════════════════════════════════════════════════${c.reset}`
313
+ );
303
314
  console.log('');
304
315
  console.log(`${c.green}Epic ${epicId} finished in ${iteration} iterations${c.reset}`);
305
316
  console.log(`${c.dim}${progress.completed} stories completed${c.reset}`);
306
317
  console.log('');
307
318
  }
308
-
309
319
  } else {
310
320
  // Tests failed - feed back to Claude
311
321
  console.log(`${c.red}✗ Tests failed${c.reset} (${(testResult.duration / 1000).toFixed(1)}s)`);
@@ -440,7 +450,9 @@ function handleCLI() {
440
450
  criteria.slice(0, 3).forEach(ac => console.log(` • ${ac}`));
441
451
  }
442
452
  console.log('');
443
- console.log(`${c.dim}Work on this story. When you stop, tests will run automatically.${c.reset}`);
453
+ console.log(
454
+ `${c.dim}Work on this story. When you stop, tests will run automatically.${c.reset}`
455
+ );
444
456
  console.log(`${c.dim}If tests pass, the next story will be loaded.${c.reset}`);
445
457
  console.log('');
446
458
 
@@ -22,12 +22,16 @@
22
22
 
23
23
  set -e
24
24
 
25
- # Colors
26
- RED='\033[0;31m'
27
- YELLOW='\033[1;33m'
28
- GREEN='\033[0;32m'
29
- BLUE='\033[0;34m'
30
- NC='\033[0m' # No Color
25
+ # Colors (using vibrant 256-color palette)
26
+ NC='\033[0m' # No Color / Reset
27
+ RED='\033[0;31m' # Standard red (fallback)
28
+ GREEN='\033[0;32m' # Standard green (fallback)
29
+
30
+ # Vibrant 256-color palette
31
+ MINT_GREEN='\033[38;5;158m' # Healthy/success states
32
+ PEACH='\033[38;5;215m' # Warning states
33
+ CORAL='\033[38;5;203m' # Critical/error states
34
+ SKY_BLUE='\033[38;5;117m' # Headers/titles
31
35
 
32
36
  # Configuration
33
37
  EXPERTS_DIR="packages/cli/src/core/experts"
@@ -180,18 +184,18 @@ validate_expertise() {
180
184
  fi
181
185
  fi
182
186
 
183
- # Output result
187
+ # Output result (using vibrant 256-color palette)
184
188
  case "$status" in
185
189
  PASS)
186
- echo -e "${GREEN}PASS${NC} $domain"
190
+ echo -e "${MINT_GREEN}PASS${NC} $domain"
187
191
  PASSED=$((PASSED + 1))
188
192
  ;;
189
193
  WARN)
190
- echo -e "${YELLOW}WARN${NC} $domain - ${issues[*]}"
194
+ echo -e "${PEACH}WARN${NC} $domain - ${issues[*]}"
191
195
  WARNINGS=$((WARNINGS + 1))
192
196
  ;;
193
197
  FAIL)
194
- echo -e "${RED}FAIL${NC} $domain - ${issues[*]}"
198
+ echo -e "${CORAL}FAIL${NC} $domain - ${issues[*]}"
195
199
  FAILED=$((FAILED + 1))
196
200
  ;;
197
201
  esac
@@ -212,12 +216,12 @@ main() {
212
216
 
213
217
  # Check experts directory exists
214
218
  if [ ! -d "$EXPERTS_DIR" ]; then
215
- echo -e "${RED}Error:${NC} Experts directory not found: $EXPERTS_DIR"
219
+ echo -e "${CORAL}Error:${NC} Experts directory not found: $EXPERTS_DIR"
216
220
  echo "Are you running this from the repository root?"
217
221
  exit 1
218
222
  fi
219
223
 
220
- echo -e "${BLUE}Validating Agent Expert Files${NC}"
224
+ echo -e "${SKY_BLUE}Validating Agent Expert Files${NC}"
221
225
  echo "================================"
222
226
  echo ""
223
227
 
@@ -225,7 +229,7 @@ main() {
225
229
  if [ -n "$1" ]; then
226
230
  # Single domain
227
231
  if [ ! -d "$EXPERTS_DIR/$1" ]; then
228
- echo -e "${RED}Error:${NC} Domain not found: $1"
232
+ echo -e "${CORAL}Error:${NC} Domain not found: $1"
229
233
  echo "Available domains:"
230
234
  ls -1 "$EXPERTS_DIR" | grep -v templates | grep -v README
231
235
  exit 1
@@ -244,10 +248,10 @@ main() {
244
248
  done
245
249
  fi
246
250
 
247
- # Summary
251
+ # Summary (using vibrant 256-color palette)
248
252
  echo ""
249
253
  echo "================================"
250
- echo -e "Total: $TOTAL | ${GREEN}Passed: $PASSED${NC} | ${YELLOW}Warnings: $WARNINGS${NC} | ${RED}Failed: $FAILED${NC}"
254
+ echo -e "Total: $TOTAL | ${MINT_GREEN}Passed: $PASSED${NC} | ${PEACH}Warnings: $WARNINGS${NC} | ${CORAL}Failed: $FAILED${NC}"
251
255
 
252
256
  # Exit code
253
257
  if [ "$FAILED" -gt 0 ]; then
@@ -10,7 +10,9 @@ const fs = require('fs-extra');
10
10
  const yaml = require('js-yaml');
11
11
  const { Installer } = require('../installers/core/installer');
12
12
  const { displayLogo, displaySection, success, warning, info } = require('../lib/ui');
13
- const { parseFrontmatter: parseYamlFrontmatter } = require('../../../scripts/lib/frontmatter-parser');
13
+ const {
14
+ parseFrontmatter: parseYamlFrontmatter,
15
+ } = require('../../../scripts/lib/frontmatter-parser');
14
16
 
15
17
  const installer = new Installer();
16
18