Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 11 additions & 14 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
# macOS
.DS_Store

# Node
node_modules/

# Dev tool / AI assistant state (track committed skills, ignore local agent state)
.claude/*
!.claude/skills/
!.claude/skills/**
.claude/*
.codegraph/
.opencode/
.codex/
.DS_Store
.gemini/

# Local caches / build output
.gocache/
.gomodcache/
.opencode/
.tmp/
dist/
build/

# Logs
*.log
# Dev tool / AI assistant state (track committed skills, ignore local agent state)
# Local caches / build output
# Logs
# macOS
# Node
build/
dist/
node_modules/
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# hawk-graph — Unified Architecture Platform

Single platform for the hawk-eco ecosystem (14 repos). Architecture trees, call flows, live queries — all from one place.
Single platform for the hawk-eco ecosystem (15 source repos). Architecture trees, call flows, live queries — all from one place.

## Quick Start

Expand Down Expand Up @@ -50,4 +50,4 @@ hawk-graph/
- Node.js 22+
- `graphify` — `uv tool install graphify`
- `gitnexus` — `npm install -g gitnexus`
- 14 repos in parent directory (`../`)
- 15 source repos in parent directory (`../`), plus this visualization repo
432 changes: 432 additions & 0 deletions global/ecosystem-agentic-graph-architecture.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion global/global-arch.html

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@
<div class="sidebar-header">
<h1><span>HAWK</span>-GRAPH</h1>
<div class="stats">
<div><span class="stat-num" id="statRepos">14</span> REPOS</div>
<div><span class="stat-num" id="statRepos">15</span> REPOS</div>
<div><span class="stat-num" id="statNodes">0</span> NODES</div>
</div>
</div>
Expand Down Expand Up @@ -309,7 +309,7 @@ <h1><span>HAWK</span>-GRAPH</h1>
<div class="landing" id="landingView">
<div class="logo"><span class="highlight">HAWK</span>-GRAPH</div>
<div class="subtitle">
14 repos · 88K nodes · architecture trees · call flows · live queries
15 repos · architecture trees · call flows · live queries
</div>
<div class="cards">
<div class="card" onclick="selectRepo('hawk')">
Expand All @@ -325,7 +325,7 @@ <h1><span>HAWK</span>-GRAPH</h1>
<div class="card" onclick="showGlobal()">
<div class="icon">◆</div>
<div class="label">Global</div>
<div class="desc">All 14 repos combined</div>
<div class="desc">All 15 source repos combined</div>
</div>
</div>
</div>
Expand All @@ -345,6 +345,7 @@ <h1><span>HAWK</span>-GRAPH</h1>
{ name: 'hawk-cloud', layer: 4, label: 'CLOUD' },
{ name: 'hawk-sdk-go', layer: 3, label: 'SDKS' },
{ name: 'hawk-sdk-python', layer: 3, label: 'SDKS' },
{ name: 'hawk-sdk-typescript', layer: 3, label: 'SDKS' },
{ name: 'hawk-core-contracts', layer: 0, label: 'FOUNDATIONS' },
{ name: 'hawk-mcpkit', layer: 0, label: 'FOUNDATIONS' },
{ name: 'hawk-community-skills', layer: 5, label: 'CONTENT' },
Expand Down
15 changes: 15 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "hawk-graph",
"version": "0.1.0",
"private": true,
"description": "Unified architecture platform for the hawk-eco ecosystem",
"main": "server.js",
"scripts": {
"start": "node server.js",
"serve": "./scripts/serve.sh"
},
"engines": {
"node": ">=18.0.0"
},
"license": "MIT"
}
1,314 changes: 1,314 additions & 0 deletions repos/hawk-sdk-typescript-callflow.html

Large diffs are not rendered by default.

363 changes: 363 additions & 0 deletions repos/hawk-sdk-typescript-tree.html

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions scripts/analyze-all-gitnexus.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
set -euo pipefail
HAWK_ECO="${HAWK_ECO:-..}"

repos=(eyrie graycode-core hawk-cloud hawk-community-skills hawk-core-contracts hawk-mcpkit hawk-sdk-go hawk-sdk-python hawk inspect sight tok trace yaad)
repos=(eyrie graycode-core hawk-cloud hawk-community-skills hawk-core-contracts hawk-mcpkit hawk-sdk-go hawk-sdk-python hawk-sdk-typescript hawk inspect sight tok trace yaad)

echo "=== Analyzing all repos with GitNexus ==="
for r in "${repos[@]}"; do
echo " $r..."
gitnexus analyze "$HAWK_ECO/$r" 2>/dev/null || echo " (retrying $r...)" && gitnexus analyze "$HAWK_ECO/$r"
done
echo "=== Done ==="
echo "=== Done ==="
4 changes: 2 additions & 2 deletions scripts/extract-all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
set -euo pipefail
HAWK_ECO="${HAWK_ECO:-..}"

repos=(eyrie graycode-core hawk-cloud hawk-community-skills hawk-core-contracts hawk-mcpkit hawk-sdk-go hawk-sdk-python hawk inspect sight tok trace yaad)
repos=(eyrie graycode-core hawk-cloud hawk-community-skills hawk-core-contracts hawk-mcpkit hawk-sdk-go hawk-sdk-python hawk-sdk-typescript hawk inspect sight tok trace yaad)

echo "=== Extracting all repos with Graphify (code-only) ==="
for r in "${repos[@]}"; do
echo " $r..."
graphify extract "$HAWK_ECO/$r" --code-only --global --as "$r"
done
echo "=== Done ==="
echo "=== Done ==="
263 changes: 263 additions & 0 deletions scripts/graph-visualizer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
/**
* Graph visualization utilities for hawk-graph.
*
* This module provides utilities for visualizing graphs using
* D3.js-style data structures and Cytoscape.js-compatible formats.
*/

/**
* GraphNode represents a node in the visualization graph.
*/
export interface GraphNode {
id: string;
label: string;
type: string;
x?: number;
y?: number;
vx?: number;
vy?: number;
color?: string;
size?: number;
properties?: Record<string, unknown>;
}

/**
* GraphLink represents an edge in the visualization graph.
*/
export interface GraphLink {
source: string | GraphNode;
target: string | GraphNode;
value?: number;
weight?: number;
type?: string;
color?: string;
}

/**
* GraphData represents a graph for visualization.
*/
export interface GraphData {
nodes: GraphNode[];
links: GraphLink[];
}

/**
* CytoscapeElement represents a Cytoscape.js element.
*/
export interface CytoscapeElement {
data: {
id: string;
source?: string;
target?: string;
label?: string;
type?: string;
weight?: number;
};
classes?: string;
position?: { x: number; y: number };
}

/**
* CytoscapeElements represents Cytoscape.js elements.
*/
export interface CytoscapeElements {
nodes: CytoscapeElement[];
edges: CytoscapeElement[];
}

/**
* GraphStyle represents styling for graph visualization.
*/
export interface GraphStyle {
nodeColors: Record<string, string>;
nodeSizes: Record<string, number>;
edgeColors: Record<string, string>;
defaultNodeColor: string;
defaultNodeSize: number;
defaultEdgeColor: string;
}

/**
* Default graph style.
*/
export const DEFAULT_STYLE: GraphStyle = {
nodeColors: {
agent: '#4F46E5',
tool: '#10B981',
function: '#F59E0B',
start: '#10B981',
end: '#EF4444',
router: '#8B5CF6',
},
nodeSizes: {
agent: 20,
tool: 15,
function: 15,
start: 18,
end: 18,
router: 18,
},
edgeColors: {
default: '#9CA3AF',
conditional: '#F59E0B',
error: '#EF4444',
},
defaultNodeColor: '#6B7280',
defaultNodeSize: 15,
defaultEdgeColor: '#9CA3AF',
};

/**
* GraphVisualizer provides utilities for graph visualization.
*/
export class GraphVisualizer {
private style: GraphStyle;

constructor(style: Partial<GraphStyle> = {}) {
this.style = { ...DEFAULT_STYLE, ...style };
}

/**
* Convert a graph to D3.js format.
*/
toD3Format(graph: { nodes: any[]; edges: any[] }): GraphData {
const nodes: GraphNode[] = graph.nodes.map(node => ({
id: node.id || node.ID || node.name,
label: node.name || node.id || node.ID,
type: node.type || node.Type || 'agent',
properties: node.properties || node.Attrs || {},
}));

const nodeMap = new Map(nodes.map(n => [n.id, n]));

const links: GraphLink[] = graph.edges.map(edge => {
const source = edge.source || edge.From || edge.from;
const target = edge.target || edge.To || edge.to;
return {
source,
target,
weight: edge.weight || edge.Weight || 1,
type: edge.kind || edge.Kind || 'default',
};
});

return { nodes, links };
}

/**
* Convert a graph to Cytoscape.js format.
*/
toCytoscapeFormat(graph: { nodes: any[]; edges: any[] }): CytoscapeElements {
const nodes: CytoscapeElement[] = graph.nodes.map(node => ({
data: {
id: node.id || node.ID || node.name,
label: node.name || node.id || node.ID,
type: node.type || node.Type || 'agent',
},
}));

const edges: CytoscapeElement[] = graph.edges.map((edge, i) => ({
data: {
id: `e${i}`,
source: edge.source || edge.From || edge.from,
target: edge.target || edge.To || edge.to,
weight: edge.weight || edge.Weight || 1,
type: edge.kind || edge.Kind || 'default',
},
}));

return { nodes, edges };
}

/**
* Apply force-directed layout simulation.
*/
applyForceLayout(data: GraphData, iterations: number = 300): GraphData {
const nodes = data.nodes.map(n => ({ ...n }));
const links = data.links.map(l => ({ ...l }));

// Initialize positions
for (const node of nodes) {
node.x = Math.random() * 800 - 400;
node.y = Math.random() * 600 - 300;
node.vx = 0;
node.vy = 0;
}

const nodeMap = new Map(nodes.map(n => [n.id, n]));

// Simple force simulation
const k = 100; // Spring length
const repulsion = 5000; // Repulsion strength

for (let iter = 0; iter < iterations; iter++) {
// Repulsion between all nodes
for (let i = 0; i < nodes.length; i++) {
for (let j = i + 1; j < nodes.length; j++) {
const dx = nodes[j].x! - nodes[i].x!;
const dy = nodes[j].y! - nodes[i].y!;
const dist = Math.sqrt(dx * dx + dy * dy) || 0.1;
const force = repulsion / (dist * dist);
nodes[i].vx! -= (dx / dist) * force;
nodes[i].vy! -= (dy / dist) * force;
nodes[j].vx! += (dx / dist) * force;
nodes[j].vy! += (dy / dist) * force;
}
}

// Attraction along edges
for (const link of links) {
const source = typeof link.source === 'string' ? nodeMap.get(link.source) : link.source;
const target = typeof link.target === 'string' ? nodeMap.get(link.target) : link.target;
if (!source || !target) continue;

const dx = target.x! - source.x!;
const dy = target.y! - source.y!;
const dist = Math.sqrt(dx * dx + dy * dy) || 0.1;
const force = (dist - k) * 0.1;
source.vx! += (dx / dist) * force;
source.vy! += (dy / dist) * force;
target.vx! -= (dx / dist) * force;
target.vy! -= (dy / dist) * force;
}

// Update positions
for (const node of nodes) {
node.vx! *= 0.1; // Friction
node.vy! *= 0.1;
node.x! += node.vx!;
node.y! += node.vy!;
}
}

return { nodes, links };
}

/**
* Generate SVG for a graph.
*/
toSVG(data: GraphData, width: number = 800, height: number = 600): string {
const layout = this.applyForceLayout(data);

const nodes = layout.nodes.map(node => {
const color = this.style.nodeColors[node.type] || this.style.defaultNodeColor;
const size = this.style.nodeSizes[node.type] || this.style.defaultNodeSize;
return `<circle cx="${node.x}" cy="${node.y}" r="${size}" fill="${color}" stroke="#fff" stroke-width="2"/>
<text x="${node.x}" y="${node.y + size + 15}" text-anchor="middle" font-size="12" fill="#374151">${node.label}</text>`;
}).join('\n');

const links = layout.links.map(link => {
const source = typeof link.source === 'string' ? layout.nodes.find(n => n.id === link.source) : link.source;
const target = typeof link.target === 'string' ? layout.nodes.find(n => n.id === link.target) : link.target;
if (!source || !target) return '';
const color = this.style.edgeColors[link.type || 'default'] || this.style.defaultEdgeColor;
return `<line x1="${source.x}" y1="${source.y}" x2="${target.x}" y2="${target.y}" stroke="${color}" stroke-width="${link.weight || 1}" stroke-opacity="0.6"/>`;
}).join('\n');

return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
<rect width="100%" height="100%" fill="white"/>
${links}
${nodes}
</svg>`;
}
}
Loading