claude-flow-novice 1.5.13 → 1.5.15
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/.claude/agents/analysis/code-review/analyze-code-quality.md +160 -177
- package/.claude/agents/architecture/system-design/arch-system-design.md +118 -153
- package/.claude-flow-novice/dist/src/cli/simple-commands/init/templates/CLAUDE.md +2 -1
- package/.claude-flow-novice/dist/src/config/web-portal-config.js +2 -1
- package/.claude-flow-novice/dist/src/config/web-portal-config.js.map +1 -1
- package/.claude-flow-novice/dist/src/preferences/user-preference-manager.js +371 -0
- package/.claude-flow-novice/dist/src/preferences/user-preference-manager.js.map +1 -0
- package/.claude-flow-novice/dist/src/validators/index.js +8 -8
- package/.claude-flow-novice/dist/src/validators/todowrite-batching-validator.js +70 -70
- package/.claude-flow-novice/dist/src/validators/todowrite-batching-validator.js.map +1 -1
- package/.claude-flow-novice/dist/src/validators/todowrite-integration.js +49 -49
- package/.claude-flow-novice/dist/src/validators/todowrite-integration.js.map +1 -1
- package/.claude-flow-novice/dist/src/web/portal-server.js +12 -5
- package/.claude-flow-novice/dist/src/web/portal-server.js.map +1 -1
- package/config/hooks/post-edit-pipeline.js +272 -10
- package/package.json +3 -1
- package/scripts/src/web/frontend/.claude-flow/metrics/agent-metrics.json +1 -0
- package/scripts/src/web/frontend/.claude-flow/metrics/performance.json +9 -0
- package/scripts/src/web/frontend/.claude-flow/metrics/task-metrics.json +10 -0
- package/src/cli/simple-commands/init/templates/CLAUDE.md +4 -1
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
* Comprehensive validation, formatting, and quality checks after file edits
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import fs from 'fs';
|
|
10
|
+
import { exec, spawn } from 'child_process';
|
|
11
|
+
import { promisify } from 'util';
|
|
12
|
+
|
|
13
|
+
const execAsync = promisify(exec);
|
|
13
14
|
|
|
14
15
|
class PostEditPipeline {
|
|
15
16
|
constructor() {
|
|
@@ -386,12 +387,13 @@ class PostEditPipeline {
|
|
|
386
387
|
}
|
|
387
388
|
}
|
|
388
389
|
|
|
389
|
-
async run(filePath) {
|
|
390
|
+
async run(filePath, options = {}) {
|
|
390
391
|
const language = this.detectLanguage(filePath);
|
|
391
392
|
const results = {
|
|
392
393
|
file: filePath,
|
|
393
394
|
language,
|
|
394
395
|
timestamp: new Date().toISOString(),
|
|
396
|
+
agentContext: this.extractAgentContext(options),
|
|
395
397
|
steps: {},
|
|
396
398
|
summary: {
|
|
397
399
|
success: true,
|
|
@@ -464,6 +466,9 @@ class PostEditPipeline {
|
|
|
464
466
|
// Generate summary
|
|
465
467
|
this.printSummary(results);
|
|
466
468
|
|
|
469
|
+
// Log to root file
|
|
470
|
+
await this.logToRootFile(results);
|
|
471
|
+
|
|
467
472
|
return results;
|
|
468
473
|
}
|
|
469
474
|
|
|
@@ -478,6 +483,236 @@ class PostEditPipeline {
|
|
|
478
483
|
}
|
|
479
484
|
}
|
|
480
485
|
|
|
486
|
+
extractAgentContext(options = {}) {
|
|
487
|
+
// Extract agent information from various sources
|
|
488
|
+
const context = {
|
|
489
|
+
memoryKey: options.memoryKey || process.env.MEMORY_KEY || null,
|
|
490
|
+
agentType: options.agentType || process.env.AGENT_TYPE || null,
|
|
491
|
+
agentName: options.agentName || process.env.AGENT_NAME || null,
|
|
492
|
+
swarmId: options.swarmId || process.env.SWARM_ID || null,
|
|
493
|
+
taskId: options.taskId || process.env.TASK_ID || null,
|
|
494
|
+
sessionId: options.sessionId || process.env.SESSION_ID || null
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
// Parse agent info from memory key (format: "swarm/[agent]/[step]")
|
|
498
|
+
if (context.memoryKey && !context.agentType) {
|
|
499
|
+
const keyParts = context.memoryKey.split('/');
|
|
500
|
+
if (keyParts.length >= 2) {
|
|
501
|
+
context.agentType = keyParts[1];
|
|
502
|
+
}
|
|
503
|
+
if (keyParts.length >= 3) {
|
|
504
|
+
context.taskStep = keyParts[2];
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
return context;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
formatTimestamp(isoTimestamp) {
|
|
512
|
+
const date = new Date(isoTimestamp);
|
|
513
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
514
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
515
|
+
const year = date.getFullYear();
|
|
516
|
+
const hours = String(date.getHours()).padStart(2, '0');
|
|
517
|
+
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
518
|
+
|
|
519
|
+
return `${month}/${day}/${year} ${hours}:${minutes}`;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
async logToRootFile(results) {
|
|
523
|
+
const logPath = path.join(process.cwd(), 'post-edit-pipeline.log');
|
|
524
|
+
const MAX_ENTRIES = 500;
|
|
525
|
+
|
|
526
|
+
// Create log entry
|
|
527
|
+
const logEntry = {
|
|
528
|
+
timestamp: results.timestamp,
|
|
529
|
+
displayTimestamp: this.formatTimestamp(results.timestamp),
|
|
530
|
+
file: results.file,
|
|
531
|
+
language: results.language,
|
|
532
|
+
agent: results.agentContext,
|
|
533
|
+
status: results.summary.success ? 'PASSED' : 'FAILED',
|
|
534
|
+
errors: results.summary.errors.length,
|
|
535
|
+
warnings: results.summary.warnings.length,
|
|
536
|
+
suggestions: results.summary.suggestions.length,
|
|
537
|
+
steps: {
|
|
538
|
+
formatting: results.steps.formatting?.success || false,
|
|
539
|
+
linting: results.steps.linting?.success || false,
|
|
540
|
+
typeCheck: results.steps.typeCheck?.success || false,
|
|
541
|
+
dependencies: results.steps.dependencies?.success || false,
|
|
542
|
+
security: results.steps.security?.success || false,
|
|
543
|
+
tests: results.steps.tests?.success || false
|
|
544
|
+
},
|
|
545
|
+
details: {
|
|
546
|
+
errors: results.summary.errors,
|
|
547
|
+
warnings: results.summary.warnings,
|
|
548
|
+
suggestions: results.summary.suggestions
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
|
|
552
|
+
// Format log entry with separator
|
|
553
|
+
const logText = [
|
|
554
|
+
'═'.repeat(80),
|
|
555
|
+
`TIMESTAMP: ${logEntry.displayTimestamp}`,
|
|
556
|
+
`FILE: ${logEntry.file}`,
|
|
557
|
+
`LANGUAGE: ${logEntry.language}`,
|
|
558
|
+
`STATUS: ${logEntry.status}`,
|
|
559
|
+
'',
|
|
560
|
+
'AGENT CONTEXT:',
|
|
561
|
+
` Memory Key: ${logEntry.agent.memoryKey || 'N/A'}`,
|
|
562
|
+
` Agent Type: ${logEntry.agent.agentType || 'N/A'}`,
|
|
563
|
+
` Agent Name: ${logEntry.agent.agentName || 'N/A'}`,
|
|
564
|
+
` Swarm ID: ${logEntry.agent.swarmId || 'N/A'}`,
|
|
565
|
+
` Task ID: ${logEntry.agent.taskId || 'N/A'}`,
|
|
566
|
+
` Session ID: ${logEntry.agent.sessionId || 'N/A'}`,
|
|
567
|
+
'',
|
|
568
|
+
'VALIDATION STEPS:',
|
|
569
|
+
` ✓ Formatting: ${logEntry.steps.formatting ? '✅' : '❌'}`,
|
|
570
|
+
` ✓ Linting: ${logEntry.steps.linting ? '✅' : '❌'}`,
|
|
571
|
+
` ✓ Type Check: ${logEntry.steps.typeCheck ? '✅' : '❌'}`,
|
|
572
|
+
` ✓ Dependencies: ${logEntry.steps.dependencies ? '✅' : '❌'}`,
|
|
573
|
+
` ✓ Security: ${logEntry.steps.security ? '✅' : '❌'}`,
|
|
574
|
+
` ✓ Tests: ${logEntry.steps.tests ? '✅' : '❌'}`,
|
|
575
|
+
'',
|
|
576
|
+
`ERRORS (${logEntry.errors}):`,
|
|
577
|
+
...logEntry.details.errors.map(e => ` • ${e}`),
|
|
578
|
+
'',
|
|
579
|
+
`WARNINGS (${logEntry.warnings}):`,
|
|
580
|
+
...logEntry.details.warnings.map(w => ` • ${w}`),
|
|
581
|
+
'',
|
|
582
|
+
`SUGGESTIONS (${logEntry.suggestions}):`,
|
|
583
|
+
...logEntry.details.suggestions.map(s => ` • ${s}`),
|
|
584
|
+
'',
|
|
585
|
+
'JSON:',
|
|
586
|
+
JSON.stringify(logEntry, null, 2),
|
|
587
|
+
'═'.repeat(80),
|
|
588
|
+
'',
|
|
589
|
+
''
|
|
590
|
+
].join('\n');
|
|
591
|
+
|
|
592
|
+
try {
|
|
593
|
+
// Read existing log and parse entries
|
|
594
|
+
let existingEntries = [];
|
|
595
|
+
if (fs.existsSync(logPath)) {
|
|
596
|
+
const existingLog = fs.readFileSync(logPath, 'utf8');
|
|
597
|
+
|
|
598
|
+
// Split by separator and parse JSON from each entry
|
|
599
|
+
const entrySections = existingLog.split('═'.repeat(80)).filter(s => s.trim());
|
|
600
|
+
|
|
601
|
+
for (const section of entrySections) {
|
|
602
|
+
// Match JSON block more reliably - find JSON: followed by { until the closing }
|
|
603
|
+
const jsonStart = section.indexOf('JSON:');
|
|
604
|
+
if (jsonStart !== -1) {
|
|
605
|
+
const jsonText = section.substring(jsonStart + 5).trim();
|
|
606
|
+
// Find the complete JSON object by counting braces
|
|
607
|
+
let braceCount = 0;
|
|
608
|
+
let jsonEnd = 0;
|
|
609
|
+
let inString = false;
|
|
610
|
+
let escapeNext = false;
|
|
611
|
+
|
|
612
|
+
for (let i = 0; i < jsonText.length; i++) {
|
|
613
|
+
const char = jsonText[i];
|
|
614
|
+
|
|
615
|
+
if (escapeNext) {
|
|
616
|
+
escapeNext = false;
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
if (char === '\\') {
|
|
621
|
+
escapeNext = true;
|
|
622
|
+
continue;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
if (char === '"') {
|
|
626
|
+
inString = !inString;
|
|
627
|
+
continue;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
if (!inString) {
|
|
631
|
+
if (char === '{') braceCount++;
|
|
632
|
+
if (char === '}') {
|
|
633
|
+
braceCount--;
|
|
634
|
+
if (braceCount === 0) {
|
|
635
|
+
jsonEnd = i + 1;
|
|
636
|
+
break;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
if (jsonEnd > 0) {
|
|
643
|
+
try {
|
|
644
|
+
const entry = JSON.parse(jsonText.substring(0, jsonEnd));
|
|
645
|
+
existingEntries.push(entry);
|
|
646
|
+
} catch (e) {
|
|
647
|
+
// Skip malformed entries
|
|
648
|
+
console.error(`Failed to parse JSON entry: ${e.message}`);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// Add new entry at the beginning
|
|
656
|
+
existingEntries.unshift(logEntry);
|
|
657
|
+
|
|
658
|
+
// Enforce 500 entry limit - keep newest 500
|
|
659
|
+
if (existingEntries.length > MAX_ENTRIES) {
|
|
660
|
+
existingEntries = existingEntries.slice(0, MAX_ENTRIES);
|
|
661
|
+
console.log(`\n🗑️ Trimmed log to ${MAX_ENTRIES} most recent entries`);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// Rebuild log file with all entries
|
|
665
|
+
const rebuiltLog = existingEntries.map(entry => {
|
|
666
|
+
const formattedEntry = [
|
|
667
|
+
'═'.repeat(80),
|
|
668
|
+
`TIMESTAMP: ${entry.displayTimestamp}`,
|
|
669
|
+
`FILE: ${entry.file}`,
|
|
670
|
+
`LANGUAGE: ${entry.language}`,
|
|
671
|
+
`STATUS: ${entry.status}`,
|
|
672
|
+
'',
|
|
673
|
+
'AGENT CONTEXT:',
|
|
674
|
+
` Memory Key: ${entry.agent.memoryKey || 'N/A'}`,
|
|
675
|
+
` Agent Type: ${entry.agent.agentType || 'N/A'}`,
|
|
676
|
+
` Agent Name: ${entry.agent.agentName || 'N/A'}`,
|
|
677
|
+
` Swarm ID: ${entry.agent.swarmId || 'N/A'}`,
|
|
678
|
+
` Task ID: ${entry.agent.taskId || 'N/A'}`,
|
|
679
|
+
` Session ID: ${entry.agent.sessionId || 'N/A'}`,
|
|
680
|
+
'',
|
|
681
|
+
'VALIDATION STEPS:',
|
|
682
|
+
` ✓ Formatting: ${entry.steps.formatting ? '✅' : '❌'}`,
|
|
683
|
+
` ✓ Linting: ${entry.steps.linting ? '✅' : '❌'}`,
|
|
684
|
+
` ✓ Type Check: ${entry.steps.typeCheck ? '✅' : '❌'}`,
|
|
685
|
+
` ✓ Dependencies: ${entry.steps.dependencies ? '✅' : '❌'}`,
|
|
686
|
+
` ✓ Security: ${entry.steps.security ? '✅' : '❌'}`,
|
|
687
|
+
` ✓ Tests: ${entry.steps.tests ? '✅' : '❌'}`,
|
|
688
|
+
'',
|
|
689
|
+
`ERRORS (${entry.errors}):`,
|
|
690
|
+
...(entry.details.errors || []).map(e => ` • ${e}`),
|
|
691
|
+
'',
|
|
692
|
+
`WARNINGS (${entry.warnings}):`,
|
|
693
|
+
...(entry.details.warnings || []).map(w => ` • ${w}`),
|
|
694
|
+
'',
|
|
695
|
+
`SUGGESTIONS (${entry.suggestions}):`,
|
|
696
|
+
...(entry.details.suggestions || []).map(s => ` • ${s}`),
|
|
697
|
+
'',
|
|
698
|
+
'JSON:',
|
|
699
|
+
JSON.stringify(entry, null, 2),
|
|
700
|
+
'═'.repeat(80),
|
|
701
|
+
'',
|
|
702
|
+
''
|
|
703
|
+
].join('\n');
|
|
704
|
+
|
|
705
|
+
return formattedEntry;
|
|
706
|
+
}).join('');
|
|
707
|
+
|
|
708
|
+
fs.writeFileSync(logPath, rebuiltLog, 'utf8');
|
|
709
|
+
|
|
710
|
+
console.log(`\n📝 Logged to: ${logPath} (${existingEntries.length}/${MAX_ENTRIES} entries)`);
|
|
711
|
+
} catch (error) {
|
|
712
|
+
console.error(`⚠️ Failed to write log: ${error.message}`);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
481
716
|
printSummary(results) {
|
|
482
717
|
console.log('\n' + '='.repeat(60));
|
|
483
718
|
console.log('📊 VALIDATION SUMMARY');
|
|
@@ -513,7 +748,7 @@ async function main() {
|
|
|
513
748
|
const filePath = process.argv[2];
|
|
514
749
|
|
|
515
750
|
if (!filePath) {
|
|
516
|
-
console.error('Usage: post-edit-pipeline.js <file-path>');
|
|
751
|
+
console.error('Usage: post-edit-pipeline.js <file-path> [--memory-key <key>] [--agent-type <type>] [--agent-name <name>]');
|
|
517
752
|
process.exit(1);
|
|
518
753
|
}
|
|
519
754
|
|
|
@@ -522,18 +757,45 @@ async function main() {
|
|
|
522
757
|
process.exit(1);
|
|
523
758
|
}
|
|
524
759
|
|
|
760
|
+
// Parse command-line options for agent context
|
|
761
|
+
const options = {};
|
|
762
|
+
const args = process.argv.slice(3);
|
|
763
|
+
|
|
764
|
+
for (let i = 0; i < args.length; i++) {
|
|
765
|
+
if (args[i] === '--memory-key' && args[i + 1]) {
|
|
766
|
+
options.memoryKey = args[i + 1];
|
|
767
|
+
i++;
|
|
768
|
+
} else if (args[i] === '--agent-type' && args[i + 1]) {
|
|
769
|
+
options.agentType = args[i + 1];
|
|
770
|
+
i++;
|
|
771
|
+
} else if (args[i] === '--agent-name' && args[i + 1]) {
|
|
772
|
+
options.agentName = args[i + 1];
|
|
773
|
+
i++;
|
|
774
|
+
} else if (args[i] === '--swarm-id' && args[i + 1]) {
|
|
775
|
+
options.swarmId = args[i + 1];
|
|
776
|
+
i++;
|
|
777
|
+
} else if (args[i] === '--task-id' && args[i + 1]) {
|
|
778
|
+
options.taskId = args[i + 1];
|
|
779
|
+
i++;
|
|
780
|
+
} else if (args[i] === '--session-id' && args[i + 1]) {
|
|
781
|
+
options.sessionId = args[i + 1];
|
|
782
|
+
i++;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
|
|
525
786
|
const pipeline = new PostEditPipeline();
|
|
526
|
-
const results = await pipeline.run(filePath);
|
|
787
|
+
const results = await pipeline.run(filePath, options);
|
|
527
788
|
|
|
528
789
|
// Exit with error code if validation failed
|
|
529
790
|
process.exit(results.summary.success ? 0 : 1);
|
|
530
791
|
}
|
|
531
792
|
|
|
532
|
-
|
|
793
|
+
// Run if called directly
|
|
794
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
533
795
|
main().catch(error => {
|
|
534
796
|
console.error('Pipeline error:', error);
|
|
535
797
|
process.exit(1);
|
|
536
798
|
});
|
|
537
799
|
}
|
|
538
800
|
|
|
539
|
-
|
|
801
|
+
export default PostEditPipeline;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-flow-novice",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.15",
|
|
4
4
|
"description": "Standalone Claude Flow for beginners - AI agent orchestration made easy with enhanced TDD testing pipeline. Enhanced init command creates complete agent system, MCP configuration with 30 essential tools, and automated hooks with single-file testing, real-time coverage analysis, and advanced validation. Fully standalone with zero external dependencies, complete project setup in one command.",
|
|
5
5
|
"mcpName": "io.github.ruvnet/claude-flow",
|
|
6
6
|
"main": ".claude-flow-novice/dist/index.js",
|
|
@@ -278,8 +278,10 @@
|
|
|
278
278
|
"eslint-plugin-react": "^7.37.5",
|
|
279
279
|
"express": "^5.1.0",
|
|
280
280
|
"jest": "^29.7.0",
|
|
281
|
+
"node-fetch": "^3.3.2",
|
|
281
282
|
"playwright": "^1.55.1",
|
|
282
283
|
"prettier": "^3.1.1",
|
|
284
|
+
"socket.io-client": "^4.8.1",
|
|
283
285
|
"ts-jest": "^29.4.0",
|
|
284
286
|
"tsx": "^4.6.2",
|
|
285
287
|
"typescript": "^5.6.3"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
5. **NEVER WORK SOLO** - Spawn multiple agents in parallel for ALL significant tasks
|
|
15
15
|
6. **NEVER SAVE TO ROOT** - Organize files in appropriate subdirectories
|
|
16
16
|
7. **USE CLAUDE CODE'S TASK TOOL** - For spawning agents concurrently, not just MCP
|
|
17
|
+
8. **USE THE CFN LOOP** - For a self correcting dev loop that saves time and resources
|
|
18
|
+
9. **DO NOT CREATE GUIDES NOR REPORT FILES** - unless specifically asked.
|
|
19
|
+
10. **Use spartan language** - no fluff encouraged
|
|
17
20
|
|
|
18
21
|
### 🚫 WHEN YOU MUST USE AGENTS (MANDATORY)
|
|
19
22
|
|
|
@@ -321,7 +324,7 @@ claude mcp add claude-flow-novice npx claude-flow-novice mcp start
|
|
|
321
324
|
- `/fullstack "goal"` - Launch full-stack development team with consensus validation
|
|
322
325
|
- `/swarm`, `/sparc`, `/hooks` - Other slash commands (auto-discovered)
|
|
323
326
|
|
|
324
|
-
## 🔄 MANDATORY
|
|
327
|
+
## 🔄 MANDATORY CFN LOOP
|
|
325
328
|
|
|
326
329
|
**YOU MUST FOLLOW THIS LOOP FOR ALL NON-TRIVIAL WORK:**
|
|
327
330
|
|