feat: Add intelligent auto-router and enhanced integrations

- Add intelligent-router.sh hook for automatic agent routing
- Add AUTO-TRIGGER-SUMMARY.md documentation
- Add FINAL-INTEGRATION-SUMMARY.md documentation
- Complete Prometheus integration (6 commands + 4 tools)
- Complete Dexto integration (12 commands + 5 tools)
- Enhanced Ralph with access to all agents
- Fix /clawd command (removed disable-model-invocation)
- Update hooks.json to v5 with intelligent routing
- 291 total skills now available
- All 21 commands with automatic routing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
admin
2026-01-28 00:27:56 +04:00
Unverified
parent 3b128ba3bd
commit b52318eeae
1724 changed files with 351216 additions and 0 deletions

View File

@@ -0,0 +1,334 @@
/**
* DiffRenderer Component
*
* Renders unified diff with syntax highlighting.
* Shows filename, +N/-M stats, and colored diff lines.
*/
import { useState } from 'react';
import { FileEdit, ChevronDown, ChevronRight, Copy, Check } from 'lucide-react';
import { cn } from '@/lib/utils';
import type { DiffDisplayData } from '@dexto/core';
interface DiffRendererProps {
/** Diff display data from tool result */
data: DiffDisplayData;
/** Maximum lines before truncation (default: 50) */
maxLines?: number;
/** Whether to start expanded (default: false) */
defaultExpanded?: boolean;
}
// =============================================================================
// Diff Parsing (ported from CLI)
// =============================================================================
interface ParsedHunk {
oldStart: number;
newStart: number;
lines: ParsedLine[];
}
interface ParsedLine {
type: 'context' | 'addition' | 'deletion';
content: string;
lineNum: number;
}
/**
* Parse unified diff into structured hunks.
*/
function parseUnifiedDiff(unified: string): ParsedHunk[] {
const lines = unified.split('\n');
const hunks: ParsedHunk[] = [];
let currentHunk: ParsedHunk | null = null;
let oldLine = 0;
let newLine = 0;
for (const line of lines) {
if (line.startsWith('---') || line.startsWith('+++') || line.startsWith('Index:')) {
continue;
}
const hunkMatch = line.match(/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/);
if (hunkMatch) {
if (currentHunk) {
hunks.push(currentHunk);
}
oldLine = parseInt(hunkMatch[1]!, 10);
newLine = parseInt(hunkMatch[3]!, 10);
currentHunk = {
oldStart: oldLine,
newStart: newLine,
lines: [],
};
continue;
}
if (!currentHunk) continue;
if (line.startsWith('+')) {
currentHunk.lines.push({
type: 'addition',
content: line.slice(1),
lineNum: newLine++,
});
} else if (line.startsWith('-')) {
currentHunk.lines.push({
type: 'deletion',
content: line.slice(1),
lineNum: oldLine++,
});
} else if (line.startsWith(' ') || line === '') {
currentHunk.lines.push({
type: 'context',
content: line.startsWith(' ') ? line.slice(1) : line,
lineNum: newLine,
});
oldLine++;
newLine++;
}
}
if (currentHunk) {
hunks.push(currentHunk);
}
return hunks;
}
/**
* Get line number width for consistent alignment.
*/
function getLineNumWidth(maxLineNum: number): number {
return Math.max(3, String(maxLineNum).length);
}
/**
* Format line number with padding.
*/
function formatLineNum(num: number, width: number): string {
return String(num).padStart(width, ' ');
}
// =============================================================================
// Line Components
// =============================================================================
interface DiffLineProps {
type: 'context' | 'addition' | 'deletion';
lineNum: number;
lineNumWidth: number;
content: string;
}
/**
* Render a single diff line with gutter and content.
*/
function DiffLine({ type, lineNum, lineNumWidth, content }: DiffLineProps) {
const lineNumStr = formatLineNum(lineNum, lineNumWidth);
const getStyles = () => {
switch (type) {
case 'deletion':
return {
bg: 'bg-red-100/50 dark:bg-red-900/20',
text: 'text-red-800 dark:text-red-300',
symbol: '-',
symbolColor: 'text-red-600 dark:text-red-400',
};
case 'addition':
return {
bg: 'bg-green-100/50 dark:bg-green-900/20',
text: 'text-green-800 dark:text-green-300',
symbol: '+',
symbolColor: 'text-green-600 dark:text-green-400',
};
default:
return {
bg: '',
text: 'text-foreground/60',
symbol: ' ',
symbolColor: 'text-transparent',
};
}
};
const styles = getStyles();
return (
<div className={cn('flex font-mono text-[11px] leading-5', styles.bg)}>
{/* Gutter: line number + symbol */}
<div className="flex-shrink-0 select-none">
<span className="text-muted-foreground/50 px-1">{lineNumStr}</span>
<span className={cn('px-0.5', styles.symbolColor)}>{styles.symbol}</span>
</div>
{/* Content */}
<pre className={cn('flex-1 px-1 whitespace-pre-wrap break-all', styles.text)}>
{content || ' '}
</pre>
</div>
);
}
/**
* Hunk separator.
*/
function HunkSeparator() {
return (
<div className="text-muted-foreground text-[10px] py-0.5 px-2 bg-muted/20">
<span className="text-muted-foreground/60">···</span>
</div>
);
}
// =============================================================================
// Main Component
// =============================================================================
/**
* Extract relative path from full path.
*/
function getRelativePath(path: string): string {
const parts = path.split('/').filter(Boolean);
if (parts.length <= 3) return path;
return `.../${parts.slice(-3).join('/')}`;
}
/**
* Renders unified diff with syntax highlighting and line numbers.
*/
export function DiffRenderer({ data, maxLines = 50, defaultExpanded = false }: DiffRendererProps) {
const { unified, filename, additions, deletions } = data;
const [expanded, setExpanded] = useState(defaultExpanded);
const [showAll, setShowAll] = useState(false);
const [copied, setCopied] = useState(false);
const hunks = parseUnifiedDiff(unified);
// Calculate max line number for width
let maxLineNum = 1;
let totalLines = 0;
for (const hunk of hunks) {
for (const line of hunk.lines) {
maxLineNum = Math.max(maxLineNum, line.lineNum);
totalLines++;
}
}
const lineNumWidth = getLineNumWidth(maxLineNum);
const shouldTruncate = totalLines > maxLines && !showAll;
const handleCopy = async () => {
await navigator.clipboard.writeText(unified);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
return (
<div className="space-y-1.5">
{/* Header with filename and stats */}
<div className="flex items-center gap-2 flex-wrap">
<FileEdit className="h-3.5 w-3.5 text-muted-foreground flex-shrink-0" />
<span className="font-mono text-xs text-foreground/80 truncate" title={filename}>
{getRelativePath(filename)}
</span>
<div className="flex items-center gap-1.5">
<span className="text-[10px] font-medium text-green-600 dark:text-green-400">
+{additions}
</span>
<span className="text-[10px] font-medium text-red-600 dark:text-red-400">
-{deletions}
</span>
</div>
</div>
{/* Diff content */}
<div className="pl-5">
{!expanded ? (
<button
onClick={() => setExpanded(true)}
className="flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors"
>
<ChevronRight className="h-3 w-3" />
<span>
Show diff ({totalLines} line{totalLines !== 1 ? 's' : ''})
</span>
</button>
) : (
<div className="space-y-1">
<div className="flex items-center justify-between">
<button
onClick={() => setExpanded(false)}
className="flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors"
>
<ChevronDown className="h-3 w-3" />
<span>Diff</span>
</button>
<button
onClick={handleCopy}
className="flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground transition-colors"
>
{copied ? (
<>
<Check className="h-3 w-3 text-green-500" />
<span>Copied</span>
</>
) : (
<>
<Copy className="h-3 w-3" />
<span>Copy</span>
</>
)}
</button>
</div>
<div className="bg-muted/30 rounded-md overflow-hidden border border-border/50">
<div className="max-h-96 overflow-y-auto scrollbar-thin">
{(() => {
let linesRendered = 0;
return hunks.map((hunk, hunkIndex) => {
if (shouldTruncate && linesRendered >= maxLines) {
return null;
}
return (
<div key={hunkIndex}>
{hunkIndex > 0 && <HunkSeparator />}
{hunk.lines.map((line, lineIndex) => {
if (
shouldTruncate &&
linesRendered >= maxLines
) {
return null;
}
linesRendered++;
return (
<DiffLine
key={`${hunkIndex}-${lineIndex}`}
type={line.type}
lineNum={line.lineNum}
lineNumWidth={lineNumWidth}
content={line.content}
/>
);
})}
</div>
);
});
})()}
</div>
{shouldTruncate && (
<button
onClick={() => setShowAll(true)}
className="w-full py-2 text-xs text-blue-500 hover:text-blue-600 dark:text-blue-400 bg-muted/50 border-t border-border/50"
>
Show {totalLines - maxLines} more lines...
</button>
)}
</div>
</div>
)}
</div>
</div>
);
}