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.
- package/.blueprint/agents/AGENT_SPECIFICATION_ALEX.md +33 -3
- package/.blueprint/features/feature_config-factory/FEATURE_SPEC.md +138 -0
- package/.blueprint/features/feature_config-factory/IMPLEMENTATION_PLAN.md +187 -0
- package/.blueprint/features/feature_config-factory/handoff-nigel.md +57 -0
- package/.blueprint/features/feature_export-history/FEATURE_SPEC.md +215 -0
- package/.blueprint/features/feature_export-history/IMPLEMENTATION_PLAN.md +48 -0
- package/.blueprint/features/feature_export-history/story-basic-export.md +48 -0
- package/.blueprint/features/feature_export-history/story-date-filter.md +42 -0
- package/.blueprint/features/feature_export-history/story-feature-filter.md +42 -0
- package/.blueprint/features/feature_export-history/story-file-output.md +48 -0
- package/.blueprint/features/feature_export-history/story-status-filter.md +42 -0
- package/.blueprint/features/feature_extract-prompt-util/FEATURE_SPEC.md +42 -0
- package/.blueprint/features/feature_fix-status-icons/FEATURE_SPEC.md +37 -0
- package/.blueprint/features/feature_murm-subagent/FEATURE_SPEC.md +137 -0
- package/.blueprint/features/feature_murm-subagent/SKILL_CHANGES.md +345 -0
- package/.blueprint/features/feature_split-cli-commands/FEATURE_SPEC.md +125 -0
- package/.blueprint/features/feature_split-cli-commands/IMPLEMENTATION_PLAN.md +119 -0
- package/.blueprint/features/feature_split-cli-commands/handoff-nigel.md +45 -0
- package/.blueprint/features/feature_theme-adoption/FEATURE_SPEC.md +143 -0
- package/.blueprint/features/feature_theme-adoption/IMPLEMENTATION_PLAN.md +68 -0
- package/.blueprint/features/feature_theme-adoption/handoff-nigel.md +35 -0
- package/.blueprint/templates/BACKLOG_TEMPLATE.md +46 -0
- package/README.md +26 -10
- package/SKILL.md +377 -3
- package/bin/cli.js +20 -384
- package/package.json +1 -1
- package/src/commands/feedback-config.js +32 -0
- package/src/commands/help.js +81 -0
- package/src/commands/history.js +42 -0
- package/src/commands/init.js +12 -0
- package/src/commands/insights.js +23 -0
- package/src/commands/murm-config.js +52 -0
- package/src/commands/murm.js +109 -0
- package/src/commands/queue.js +19 -0
- package/src/commands/retry-config.js +28 -0
- package/src/commands/stack-config.js +32 -0
- package/src/commands/update.js +12 -0
- package/src/commands/utils.js +24 -0
- package/src/commands/validate.js +15 -0
- package/src/config-factory.js +190 -0
- package/src/feedback.js +5 -2
- package/src/history.js +92 -1
- package/src/init.js +1 -15
- package/src/insights.js +19 -16
- package/src/retry.js +5 -2
- package/src/stack.js +4 -1
- package/src/theme.js +4 -4
- package/src/update.js +2 -15
- package/src/utils.js +26 -0
- 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 = ['\
|
|
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('\
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
'
|
|
46
|
+
'murm_queued': '\u00b7', // ·
|
|
47
47
|
'worktree_created': '\u25cb', // ○
|
|
48
|
-
'
|
|
48
|
+
'murm_running': '\u25d4', // ◔
|
|
49
49
|
'merge_pending': '\u25d1', // ◑
|
|
50
|
-
'
|
|
51
|
-
'
|
|
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
|
-
|
|
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
|
|
139
|
-
const
|
|
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');
|