murmur8 4.1.1 → 4.3.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 (50) hide show
  1. package/.blueprint/agents/AGENT_SPECIFICATION_ALEX.md +33 -3
  2. package/.blueprint/features/feature_config-factory/FEATURE_SPEC.md +138 -0
  3. package/.blueprint/features/feature_config-factory/IMPLEMENTATION_PLAN.md +187 -0
  4. package/.blueprint/features/feature_config-factory/handoff-nigel.md +57 -0
  5. package/.blueprint/features/feature_export-history/FEATURE_SPEC.md +215 -0
  6. package/.blueprint/features/feature_export-history/IMPLEMENTATION_PLAN.md +48 -0
  7. package/.blueprint/features/feature_export-history/story-basic-export.md +48 -0
  8. package/.blueprint/features/feature_export-history/story-date-filter.md +42 -0
  9. package/.blueprint/features/feature_export-history/story-feature-filter.md +42 -0
  10. package/.blueprint/features/feature_export-history/story-file-output.md +48 -0
  11. package/.blueprint/features/feature_export-history/story-status-filter.md +42 -0
  12. package/.blueprint/features/feature_extract-prompt-util/FEATURE_SPEC.md +42 -0
  13. package/.blueprint/features/feature_fix-status-icons/FEATURE_SPEC.md +37 -0
  14. package/.blueprint/features/feature_murm-subagent/FEATURE_SPEC.md +137 -0
  15. package/.blueprint/features/feature_murm-subagent/SKILL_CHANGES.md +345 -0
  16. package/.blueprint/features/feature_split-cli-commands/FEATURE_SPEC.md +125 -0
  17. package/.blueprint/features/feature_split-cli-commands/IMPLEMENTATION_PLAN.md +119 -0
  18. package/.blueprint/features/feature_split-cli-commands/handoff-nigel.md +45 -0
  19. package/.blueprint/features/feature_theme-adoption/FEATURE_SPEC.md +143 -0
  20. package/.blueprint/features/feature_theme-adoption/IMPLEMENTATION_PLAN.md +68 -0
  21. package/.blueprint/features/feature_theme-adoption/handoff-nigel.md +35 -0
  22. package/.blueprint/templates/BACKLOG_TEMPLATE.md +46 -0
  23. package/README.md +26 -10
  24. package/SKILL.md +377 -3
  25. package/bin/cli.js +20 -384
  26. package/package.json +1 -1
  27. package/src/commands/feedback-config.js +32 -0
  28. package/src/commands/help.js +81 -0
  29. package/src/commands/history.js +42 -0
  30. package/src/commands/init.js +12 -0
  31. package/src/commands/insights.js +23 -0
  32. package/src/commands/murm-config.js +52 -0
  33. package/src/commands/murm.js +109 -0
  34. package/src/commands/queue.js +19 -0
  35. package/src/commands/retry-config.js +28 -0
  36. package/src/commands/stack-config.js +32 -0
  37. package/src/commands/update.js +12 -0
  38. package/src/commands/utils.js +24 -0
  39. package/src/commands/validate.js +15 -0
  40. package/src/config-factory.js +190 -0
  41. package/src/feedback.js +5 -2
  42. package/src/history.js +92 -1
  43. package/src/init.js +1 -15
  44. package/src/insights.js +19 -16
  45. package/src/retry.js +5 -2
  46. package/src/stack.js +4 -1
  47. package/src/theme.js +4 -4
  48. package/src/update.js +2 -15
  49. package/src/utils.js +26 -0
  50. package/src/validate.js +5 -12
package/src/insights.js CHANGED
@@ -1,4 +1,5 @@
1
1
  const { readHistoryFile, formatDuration } = require('./history');
2
+ const { colorize } = require('./theme');
2
3
 
3
4
  const STAGES = ['alex', 'cass', 'nigel', 'codey-plan', 'codey-implement'];
4
5
 
@@ -229,8 +230,8 @@ function analyzeTrends(history) {
229
230
  };
230
231
  }
231
232
 
232
- function formatTextOutput(analysis, sections) {
233
- const lines = ['\nPipeline Insights\n'];
233
+ function formatTextOutput(analysis, sections, useColor = false) {
234
+ const lines = ['\n' + colorize('Pipeline Insights', 'cyan', useColor) + '\n'];
234
235
 
235
236
  const showAll = sections.length === 0;
236
237
  const showBottlenecks = showAll || sections.includes('bottlenecks');
@@ -239,24 +240,24 @@ function formatTextOutput(analysis, sections) {
239
240
  const showTrends = showAll || sections.includes('trends');
240
241
 
241
242
  if (showBottlenecks) {
242
- lines.push('BOTTLENECK ANALYSIS');
243
+ lines.push(colorize('BOTTLENECK ANALYSIS', 'cyan', useColor));
243
244
  if (analysis.bottlenecks.insufficientData) {
244
245
  lines.push(` ${analysis.bottlenecks.message}`);
245
246
  } else {
246
247
  lines.push(` Slowest stage: ${analysis.bottlenecks.bottleneckStage} (${analysis.bottlenecks.percentage}% of pipeline)`);
247
248
  lines.push(` Average duration: ${formatDuration(analysis.bottlenecks.avgDurationMs)}`);
248
249
  if (analysis.bottlenecks.isBottleneck) {
249
- lines.push(' Status: BOTTLENECK DETECTED');
250
+ lines.push(' Status: ' + colorize('BOTTLENECK DETECTED', 'yellow', useColor));
250
251
  }
251
252
  if (analysis.bottlenecks.recommendation) {
252
- lines.push(` Recommendation: ${analysis.bottlenecks.recommendation}`);
253
+ lines.push(` Recommendation: ${colorize(analysis.bottlenecks.recommendation, 'yellow', useColor)}`);
253
254
  }
254
255
  }
255
256
  lines.push('');
256
257
  }
257
258
 
258
259
  if (showFailures) {
259
- lines.push('FAILURE PATTERNS');
260
+ lines.push(colorize('FAILURE PATTERNS', 'cyan', useColor));
260
261
  if (analysis.failures.noFailures) {
261
262
  lines.push(` ${analysis.failures.message}`);
262
263
  } else {
@@ -269,14 +270,14 @@ function formatTextOutput(analysis, sections) {
269
270
  }
270
271
  }
271
272
  if (analysis.failures.recommendation) {
272
- lines.push(` Recommendation: ${analysis.failures.recommendation}`);
273
+ lines.push(` Recommendation: ${colorize(analysis.failures.recommendation, 'yellow', useColor)}`);
273
274
  }
274
275
  }
275
276
  lines.push('');
276
277
  }
277
278
 
278
279
  if (showAnomalies) {
279
- lines.push('ANOMALY DETECTION');
280
+ lines.push(colorize('ANOMALY DETECTION', 'cyan', useColor));
280
281
  if (analysis.anomalies.insufficientData) {
281
282
  lines.push(` ${analysis.anomalies.message}`);
282
283
  } else if (analysis.anomalies.noAnomalies) {
@@ -287,14 +288,14 @@ function formatTextOutput(analysis, sections) {
287
288
  lines.push(` - ${a.slug}/${a.stage}: ${formatDuration(a.actual)} (expected ~${formatDuration(a.expected)}, ${a.deviation}x stddev)`);
288
289
  }
289
290
  if (analysis.anomalies.recommendation) {
290
- lines.push(` Recommendation: ${analysis.anomalies.recommendation}`);
291
+ lines.push(` Recommendation: ${colorize(analysis.anomalies.recommendation, 'yellow', useColor)}`);
291
292
  }
292
293
  }
293
294
  lines.push('');
294
295
  }
295
296
 
296
297
  if (showTrends) {
297
- lines.push('TREND ANALYSIS');
298
+ lines.push(colorize('TREND ANALYSIS', 'cyan', useColor));
298
299
  if (analysis.trends.insufficientData) {
299
300
  lines.push(` ${analysis.trends.message}`);
300
301
  } else {
@@ -303,7 +304,7 @@ function formatTextOutput(analysis, sections) {
303
304
  lines.push(` Success rate: ${sr.trend} (${sr.change > 0 ? '+' : ''}${sr.change}%)`);
304
305
  lines.push(` Duration: ${dr.trend} (${dr.change > 0 ? '+' : ''}${dr.change}%)`);
305
306
  if (analysis.trends.recommendation) {
306
- lines.push(` Recommendation: ${analysis.trends.recommendation}`);
307
+ lines.push(` Recommendation: ${colorize(analysis.trends.recommendation, 'yellow', useColor)}`);
307
308
  }
308
309
  }
309
310
  lines.push('');
@@ -334,6 +335,7 @@ function formatJsonOutput(analysis, sections) {
334
335
 
335
336
  function displayInsights(options = {}) {
336
337
  const history = readHistoryFile();
338
+ const useColor = options.color !== false && process.stdout.isTTY;
337
339
 
338
340
  if (history.error === 'corrupted') {
339
341
  console.log("Warning: History file is corrupted. Run 'murmur8 history clear' to reset.");
@@ -359,7 +361,7 @@ function displayInsights(options = {}) {
359
361
  if (options.json) {
360
362
  console.log(formatJsonOutput(analysis, sections));
361
363
  } else {
362
- console.log(formatTextOutput(analysis, sections));
364
+ console.log(formatTextOutput(analysis, sections, useColor));
363
365
  }
364
366
  }
365
367
 
@@ -437,6 +439,7 @@ function recommendThreshold(history) {
437
439
  */
438
440
  function displayFeedbackInsights(options = {}) {
439
441
  const history = readHistoryFile();
442
+ const useColor = options.color !== false && process.stdout.isTTY;
440
443
 
441
444
  if (history.error === 'corrupted') {
442
445
  console.log("Warning: History file is corrupted.");
@@ -448,10 +451,10 @@ function displayFeedbackInsights(options = {}) {
448
451
  return;
449
452
  }
450
453
 
451
- console.log('\nFeedback Insights\n');
454
+ console.log('\n' + colorize('Feedback Insights', 'cyan', useColor) + '\n');
452
455
 
453
456
  // Agent calibration
454
- console.log('AGENT CALIBRATION');
457
+ console.log(colorize('AGENT CALIBRATION', 'cyan', useColor));
455
458
  for (const agent of ['alex', 'cass', 'nigel']) {
456
459
  const calibration = calculateCalibration(agent, history);
457
460
  if (calibration === null) {
@@ -466,7 +469,7 @@ function displayFeedbackInsights(options = {}) {
466
469
  // Issue correlations
467
470
  const correlations = correlateIssues(history);
468
471
  if (Object.keys(correlations).length > 0) {
469
- console.log('ISSUE CORRELATIONS');
472
+ console.log(colorize('ISSUE CORRELATIONS', 'cyan', useColor));
470
473
  const sorted = Object.entries(correlations)
471
474
  .sort(([, a], [, b]) => b - a);
472
475
  for (const [issue, corr] of sorted) {
@@ -482,7 +485,7 @@ function displayFeedbackInsights(options = {}) {
482
485
  );
483
486
  if (entriesWithFeedback.length >= 10) {
484
487
  const recommended = recommendThreshold(history);
485
- console.log('RECOMMENDATIONS');
488
+ console.log(colorize('RECOMMENDATIONS', 'cyan', useColor));
486
489
  console.log(` Suggested minRatingThreshold: ${recommended}`);
487
490
  console.log('');
488
491
  }
package/src/retry.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const { readHistoryFile } = require('./history');
4
+ const { colorize } = require('./theme');
4
5
 
5
6
  const CONFIG_FILE = '.claude/retry-config.json';
6
7
 
@@ -179,11 +180,13 @@ function shouldRetry(stage, featureSlug, history, config, attemptCount) {
179
180
  */
180
181
  function displayConfig() {
181
182
  const config = readConfig();
182
- console.log('\nRetry Configuration\n');
183
+ const useColor = process.stdout.isTTY;
184
+
185
+ console.log('\n' + colorize('Retry Configuration', 'cyan', useColor) + '\n');
183
186
  console.log(` Max retries: ${config.maxRetries}`);
184
187
  console.log(` Window size: ${config.windowSize}`);
185
188
  console.log(` High failure threshold: ${config.highFailureThreshold}`);
186
- console.log('\n Stage Strategies:');
189
+ console.log('\n ' + colorize('Stage Strategies:', 'cyan', useColor));
187
190
  for (const [stage, strategies] of Object.entries(config.strategies)) {
188
191
  console.log(` ${stage.padEnd(16)}: ${strategies.join(' -> ')}`);
189
192
  }
package/src/stack.js CHANGED
@@ -1,5 +1,6 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
+ const { colorize } = require('./theme');
3
4
 
4
5
  const CONFIG_FILE = '.claude/stack-config.json';
5
6
 
@@ -296,7 +297,9 @@ function detectStackConfig(projectDir) {
296
297
  */
297
298
  function displayStackConfig() {
298
299
  const config = readStackConfig();
299
- console.log('\nStack Configuration\n');
300
+ const useColor = process.stdout.isTTY;
301
+
302
+ console.log('\n' + colorize('Stack Configuration', 'cyan', useColor) + '\n');
300
303
  console.log(` language: ${config.language || '(not set)'}`);
301
304
  console.log(` runtime: ${config.runtime || '(not set)'}`);
302
305
  console.log(` packageManager: ${config.packageManager || '(not set)'}`);
package/src/theme.js CHANGED
@@ -43,12 +43,12 @@ const STAGE_NAMES = {
43
43
  // --- Status Icons (replacing emoji) ---
44
44
 
45
45
  const STATUS_ICONS = {
46
- 'parallel_queued': '\u00b7', // ·
46
+ 'murm_queued': '\u00b7', // ·
47
47
  'worktree_created': '\u25cb', // ○
48
- 'parallel_running': '\u25d4', // ◔
48
+ 'murm_running': '\u25d4', // ◔
49
49
  'merge_pending': '\u25d1', // ◑
50
- 'parallel_complete': '\u2713', // ✓
51
- 'parallel_failed': '\u2717', // ✗
50
+ 'murm_complete': '\u2713', // ✓
51
+ 'murm_failed': '\u2717', // ✗
52
52
  'merge_conflict': '\u26a0', // ⚠
53
53
  'aborted': '\u25a0' // ■
54
54
  };
package/src/update.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
- const readline = require('readline');
3
+
4
+ const { prompt } = require('./utils');
4
5
 
5
6
  const PACKAGE_ROOT = path.resolve(__dirname, '..');
6
7
  const TARGET_DIR = process.cwd();
@@ -18,20 +19,6 @@ const UPDATABLE = [
18
19
  'ways_of_working'
19
20
  ];
20
21
 
21
- async function prompt(question) {
22
- const rl = readline.createInterface({
23
- input: process.stdin,
24
- output: process.stdout
25
- });
26
-
27
- return new Promise((resolve) => {
28
- rl.question(question, (answer) => {
29
- rl.close();
30
- resolve(answer.toLowerCase().trim());
31
- });
32
- });
33
- }
34
-
35
22
  function copyDir(src, dest) {
36
23
  fs.mkdirSync(dest, { recursive: true });
37
24
 
package/src/utils.js ADDED
@@ -0,0 +1,26 @@
1
+ 'use strict';
2
+
3
+ const readline = require('readline');
4
+
5
+ /**
6
+ * Prompts the user with a question and returns the answer.
7
+ * @param {string} question - The question to ask
8
+ * @returns {Promise<string>} The answer, lowercased and trimmed
9
+ */
10
+ async function prompt(question) {
11
+ const rl = readline.createInterface({
12
+ input: process.stdin,
13
+ output: process.stdout
14
+ });
15
+
16
+ return new Promise((resolve) => {
17
+ rl.question(question, (answer) => {
18
+ rl.close();
19
+ resolve(answer.toLowerCase().trim());
20
+ });
21
+ });
22
+ }
23
+
24
+ module.exports = {
25
+ prompt
26
+ };
package/src/validate.js CHANGED
@@ -1,5 +1,6 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
+ const { colorize } = require('./theme');
3
4
 
4
5
  const REQUIRED_DIRS = ['.blueprint', '.business_context', '.claude/commands'];
5
6
  const AGENT_FILES = [
@@ -135,12 +136,8 @@ async function validate() {
135
136
  function formatOutput(result, useColor = false) {
136
137
  const lines = [];
137
138
 
138
- const green = useColor ? '\x1b[32m' : '';
139
- const red = useColor ? '\x1b[31m' : '';
140
- const reset = useColor ? '\x1b[0m' : '';
141
-
142
- const passIndicator = useColor ? `${green}\u2713${reset}` : '[PASS]';
143
- const failIndicator = useColor ? `${red}\u2717${reset}` : '[FAIL]';
139
+ const passIndicator = useColor ? colorize('\u2713', 'green', useColor) : '[PASS]';
140
+ const failIndicator = useColor ? colorize('\u2717', 'red', useColor) : '[FAIL]';
144
141
 
145
142
  for (const check of result.checks) {
146
143
  const indicator = check.passed ? passIndicator : failIndicator;
@@ -152,14 +149,10 @@ function formatOutput(result, useColor = false) {
152
149
 
153
150
  lines.push('');
154
151
  if (result.success) {
155
- lines.push(useColor
156
- ? `${green}All checks passed. Project is ready.${reset}`
157
- : 'All checks passed. Project is ready.');
152
+ lines.push(colorize('All checks passed. Project is ready.', 'green', useColor));
158
153
  } else {
159
154
  const failedCount = result.checks.filter(c => !c.passed).length;
160
- lines.push(useColor
161
- ? `${red}${failedCount} check(s) failed.${reset}`
162
- : `${failedCount} check(s) failed.`);
155
+ lines.push(colorize(`${failedCount} check(s) failed.`, 'red', useColor));
163
156
  }
164
157
 
165
158
  return lines.join('\n');