From b6b2fb885731d1a238a56eeccc968397e50ec132 Mon Sep 17 00:00:00 2001 From: Lakshman Patel Date: Thu, 23 Jul 2026 20:20:54 +0530 Subject: [PATCH 1/4] chore: add package.json, remove .DS_Store from tracking Add a proper package.json for the Node.js server with start/serve scripts. Remove .DS_Store from git tracking and add to .gitignore. --- .gitignore | 25 +++++++++++-------------- package.json | 15 +++++++++++++++ 2 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 package.json diff --git a/.gitignore b/.gitignore index d08b165..fa43513 100644 --- a/.gitignore +++ b/.gitignore @@ -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/ diff --git a/package.json b/package.json new file mode 100644 index 0000000..7ccabb3 --- /dev/null +++ b/package.json @@ -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" +} From ff09e3eae00536deb26ec70e23512a7d21387a53 Mon Sep 17 00:00:00 2001 From: Lakshman Patel Date: Fri, 24 Jul 2026 13:02:34 +0530 Subject: [PATCH 2/4] fix(proxy): add response error handling, retry logic, and client-disconnect cleanup - Handle mid-stream proxy response errors (GitNexus restart) with clean 502 - Retry transient connection errors (ECONNREFUSED/RESET/ENOTFOUND/EPIPE) up to 2 times for idempotent GET/HEAD requests only - Add 30s timeout to proxy requests with proper 504 response - Destroy proxy socket when client disconnects to avoid leaked connections --- server.js | 87 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 22 deletions(-) diff --git a/server.js b/server.js index b40f1f2..0719005 100755 --- a/server.js +++ b/server.js @@ -102,29 +102,72 @@ function graphData() { function proxyGitNexus(apiReq, apiRes) { const targetPath = apiReq.url.replace(/^\/gitnexus/, '') || '/'; - const options = { - hostname: 'localhost', - port: 4747, - path: targetPath, - method: apiReq.method, - headers: Object.assign({}, apiReq.headers, { - host: 'localhost:4747', - connection: 'close', - }), + const MAX_RETRIES = 2; + // Only retry idempotent methods — retrying POST/PUT/DELETE can cause + // duplicate side effects if the first attempt actually reached GitNexus. + const RETRYABLE = apiReq.method === 'GET' || apiReq.method === 'HEAD'; + let attempt = 0; + + const doProxy = () => { + attempt++; + const options = { + hostname: 'localhost', + port: 4747, + path: targetPath, + method: apiReq.method, + headers: Object.assign({}, apiReq.headers, { + host: 'localhost:4747', + connection: 'close', + }), + timeout: 30_000, + }; + delete options.headers['accept-encoding']; + const proxy = http.request(options, (proxyRes) => { + const { statusCode, headers } = proxyRes; + const cleanHeaders = Object.assign({}, headers); + delete cleanHeaders['transfer-encoding']; + // Handle mid-stream errors (e.g. GitNexus restarts mid-response). + proxyRes.on('error', () => { + if (!apiRes.headersSent) { + apiRes.writeHead(502, { 'Content-Type': 'text/plain' }); + } + apiRes.end(); + }); + apiRes.writeHead(statusCode, cleanHeaders); + proxyRes.pipe(apiRes); + }); + proxy.on('timeout', () => { + proxy.destroy(new Error('GitNexus proxy timeout')); + if (!apiRes.headersSent) { + apiRes.writeHead(504, { 'Content-Type': 'text/plain' }); + apiRes.end('GitNexus timed out'); + } + }); + proxy.on('error', (err) => { + // Retry transient connection errors for idempotent requests. + const transient = + err.code === 'ECONNREFUSED' || + err.code === 'ECONNRESET' || + err.code === 'ENOTFOUND' || + err.code === 'EPIPE'; + if (RETRYABLE && transient && attempt <= MAX_RETRIES) { + setTimeout(doProxy, 200 * attempt); + return; + } + if (!apiRes.headersSent) { + apiRes.writeHead(502, { 'Content-Type': 'text/plain' }); + apiRes.end('GitNexus not running on port 4747'); + } + }); + // If the client disconnects, stop piping to GitNexus. + apiReq.on('aborted', () => proxy.destroy()); + apiReq.on('close', () => { + if (!apiReq.complete) proxy.destroy(); + }); + apiReq.pipe(proxy); }; - delete options.headers['accept-encoding']; - const proxy = http.request(options, (proxyRes) => { - const { statusCode, headers } = proxyRes; - const cleanHeaders = Object.assign({}, headers); - delete cleanHeaders['transfer-encoding']; - apiRes.writeHead(statusCode, cleanHeaders); - proxyRes.pipe(apiRes); - }); - proxy.on('error', () => { - apiRes.writeHead(502, { 'Content-Type': 'text/plain' }); - apiRes.end('GitNexus not running on port 4747'); - }); - apiReq.pipe(proxy); + + doProxy(); } const server = http.createServer((req, res) => { From 88f2050801c5fa646788d16c66f6b319e52df919 Mon Sep 17 00:00:00 2001 From: Lakshman Patel Date: Sat, 25 Jul 2026 12:31:29 +0530 Subject: [PATCH 3/4] feat: add ecosystem agentic graph architecture docs and reports - Add ecosystem-agentic-graph-architecture.md - Add repos/hawk-sdk-typescript-callflow.html - Add repos/hawk-sdk-typescript-tree.html - Update global-arch.html, index.html, scripts - Update README --- README.md | 4 +- .../ecosystem-agentic-graph-architecture.md | 432 ++++++ global/global-arch.html | 2 +- index.html | 7 +- repos/hawk-sdk-typescript-callflow.html | 1314 +++++++++++++++++ repos/hawk-sdk-typescript-tree.html | 363 +++++ scripts/analyze-all-gitnexus.sh | 4 +- scripts/extract-all.sh | 4 +- scripts/refresh-trees.sh | 4 +- server.js | 2 +- 10 files changed, 2123 insertions(+), 13 deletions(-) create mode 100644 global/ecosystem-agentic-graph-architecture.md create mode 100644 repos/hawk-sdk-typescript-callflow.html create mode 100644 repos/hawk-sdk-typescript-tree.html diff --git a/README.md b/README.md index 2be6af1..45d4327 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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 diff --git a/global/ecosystem-agentic-graph-architecture.md b/global/ecosystem-agentic-graph-architecture.md new file mode 100644 index 0000000..7e95c05 --- /dev/null +++ b/global/ecosystem-agentic-graph-architecture.md @@ -0,0 +1,432 @@ +# Ecosystem Agentic Graph Architecture + +## Status + +Implementation in progress. This document distinguishes shipped slices from +the target architecture and preserves the ecosystem's local-first execution +model and repository boundaries. + +Implemented in the current working branches: + +- Graph Contract v1 in `hawk-core-contracts`, mirrored in Go and protobuf; +- a read-only Trace execution-graph projection for sessions, checkpoints, + `produced` relationships, and lifecycle events; +- `trace graph export`, also composed into Hawk as + `hawk trace graph export`; +- a Hawk execution-graph projection for sessions, task requests, structured + tasks, runtime tasks, tool calls, policy verdicts, verification reports, and + explicit Trace checkpoint references; +- `hawk graph export`, with metadata-only payloads and strict dangling-edge + rejection; +- bounded validation of Hawk blocking-task dependencies with deterministic + topological waves and fail-closed ready-work selection; +- append-only, privacy-safe capture of Hawk tool permission outcomes, enabled + approval-gate outcomes, and built-in plan-verification summaries; +- a Yaad `yaad.graph/v1` portable knowledge projection and automatic Hawk + capture of retrieved Yaad memory subgraphs and Hawk code-index chunks; +- an Inspect `inspect.graph/v1` bounded quality projection and opt-in Hawk + capture/composition of report and finding subgraphs; +- a Sight `sight.graph/v1` bounded quality projection and opt-in Hawk + capture/composition of review and finding subgraphs; +- neutral, privacy-safe verification summaries emitted alongside observed + Inspect and Sight quality graphs for `validated_by` composition; +- a Tok `tok.graph/v1` mixed operations/policy/quality projection and automatic + Hawk capture of persisted-session context-compression statistics; +- an Eyrie `eyrie.graph/v1` operations projection and automatic Hawk capture + of model route and normalized usage for persisted-session turns; +- a Hawk Cloud-owned, project-scoped D1 graph ledger with authenticated + ingestion, deterministic privacy normalization, transactional idempotency, + stable-ID collision rejection, and bounded self-contained reads; +- a GrayCode Core BFF projection that validates cloud responses, removes + provenance and non-display metadata, and serves a read-only dashboard + node-link view; +- portable data-only Graph v1 models in the Go, Python, and TypeScript SDKs, + including topology validation and runtime boundary parsing where supported; +- an authenticated Hawk daemon session-graph endpoint, consumed through + matching Go, Python sync/async, and TypeScript SDK methods; +- an opt-in Hawk task-graph execution path that consumes validated scheduling + waves, dispatches bounded parallel mission workers per wave, and persists + deterministic wave joins while leaving downstream tasks pending after an + upstream failure; +- a reusable staged-mission graph execution option (`WithExecutionWaves`) so + library callers can combine dependency waves with PRD, verification, and + fix phases; +- a portable Hawk mission graph artifact written beside `mission.json`, with + mission, feature, and wave-join facts in the shared `hawk.graph/v1` envelope; +- an additive MCPKit helper for exposing producer-owned graph documents as + typed, read-only MCP resources, with explicit whole-surface auth guidance; +- a deterministic Community Skills registry projection linking the registry, + categories, skills, and cross-cutting tags without changing registry truth; +- an explicit Hawk-to-Cloud graph sync command with deterministic privacy + preparation, local preflight limits, device authentication, and fail-open + separation from local execution; +- first-class export and explicit Cloud synchronization of the portable Hawk + mission graph artifact, with local schema/topology validation before upload; +- schema validation, stable IDs, repository scope, provenance, correlation, + idempotency keys, deterministic ordering, filtering, limits, and tests. + +Not yet implemented: + +- Full graph-fact export streaming and user-requested deletion workflows + remain planned follow-on capabilities; current graph reads are bounded, + cursor-pageable, project-scoped, and governed by admin retention purge and + project-delete cleanup. + +## Architectural model + +Every agentic operation is designed through five layers: + +```text +prompt -> context -> harness -> loop -> graph +``` + +The graph layer contains six typed, temporal views over a compatible event and +provenance vocabulary. These views remain owned by the repositories that +produce them; there is no central operational graph database in `hawk-graph`: + +```text +system | knowledge | execution | policy | quality | operations +``` + +`hawk-core-contracts` owns the portable vocabulary. Individual repositories +own their facts, storage, and runtime behavior; they publish only contracts +and events that other repositories genuinely need. + +## Current versus proposed graph techniques + +The ecosystem uses several graph methods, but each has a different authority +and maturity. “Graph everywhere” means every important relationship can be +projected and inspected; it does not mean every repository needs a graph +database or every task needs multi-agent fan-out. + +| Technique | Best use | Current state | Proposed next state | +|---|---|---|---| +| Typed property graph | Portable entities, relationships, and metadata | Graph v1 has six node views, six edge types, and string-bounded attributes | Additive vocabulary only when two or more producers need the same concept | +| Temporal/event graph | Lifecycle, replay, audit, and idempotency | Created/updated/transitioned/observed/deleted events; Trace checkpoints; Cloud append ledger | Retention tiers and explicit supersession/version links | +| Execution DAG | Task dependencies and tool provenance | Hawk projects task/runtime/tool relationships, validates blocking dependencies, can execute validated waves through `hawk mission --from-tasks`, and persists mission-scoped graph artifacts with deterministic joins | Expand only where genuine dependency/parallel work benefits from the existing bounded mission controls | +| Knowledge graph / GraphRAG | Evidence-backed context and memory | Yaad memory subgraphs and Hawk code chunks are retrieved, bounded, and journaled | Retrieval evaluation, freshness scoring, and supersession-aware ranking | +| Heterogeneous multilayer graph | Join execution, knowledge, policy, quality, and operations | Hawk composes Yaad, Inspect, Sight, Tok, Eyrie, and Trace facts through shared references | Cross-view queries with explicit authorization and cost budgets | +| Policy graph | Explain what governed an action | Hawk journals permission and approval outcomes as `governed_by` facts | Policy dependency/conflict analysis without moving enforcement out of current owners | +| Quality/security graph | Findings, evidence, remediation, and regressions | Inspect and Sight publish bounded report/finding projections | Finding lifecycle and regression links after stable identity rules are agreed | +| Operations graph | Routing, usage, budgets, compression, and health | Eyrie route/usage plus Tok compression, redaction, usage, and budget decisions are captured | Add cost/latency SLO queries and durable aggregate windows | +| Capability graph | Skills, tags, tools, and compatibility | Community Skills projects registry/category/skill/tag topology; MCPKit exposes read-only resources | Signed capability and required-tool/version relationships | +| Provenance graph | Attribution and immutable evidence | Every portable fact carries producer/version/source/evidence fields | Evidence retention policies and verifiable artifact digests | +| Cloud project graph | Authorized durable coordination and dashboards | Device-auth sync, privacy normalization, D1 ledger, cursor-pageable BFF, node-link UI, graph retention purge, export summary, and project-delete cleanup | Full fact export streaming and aggregate analytics | +| Multi-agent orchestration graph | Parallel specialists with join/approval gates | Used for the opt-in task-graph mission path, not as a universal scheduler | Keep expansion behind typed state, bounded fan-out, cancellation, budgets, and deterministic joins | +| Causal graph | Explain why a later event occurred | Correlation, causation, and idempotency fields are stored, privacy-normalized, and queryable through bounded Cloud/BFF filters | Causal analysis and lineage expansion after producers emit reliable causation links | +| Code/dependency graph | Impact analysis and architecture navigation | Hawk code intelligence and visualization artifacts are read-only inputs | Freshness metadata and automated drift checks; never an execution authority | + +## Shared contract requirements + +Every externally visible graph node, edge, and event must have: + +- a stable, opaque ID and a type; +- tenant/project/repository scope; +- creation and effective timestamps; +- source, evidence, and producer version; +- access classification and policy decision where relevant; +- idempotency key for side-effecting execution nodes; +- bounded payloads, with large artifacts represented by immutable references. + +## Repository specifications + +### `hawk-core-contracts` — cross-repository vocabulary + +**Owns:** common graph DTOs, event envelopes, provenance references, execution +states, policy decisions, approvals, and checkpoint metadata. + +**Publishes:** additive, versioned Go and protobuf contracts only. It must not +own a graph database, orchestrator, CLI, or product behavior. + +**Consumes:** nothing outside the Go standard library. + +**Robustness:** additive schema evolution, strict type parsing, contract tests, +and cross-language generated schema validation. + +### `hawk` — local execution graph runtime + +**Owns:** the task execution graph for local coding work: task, context plan, +agent loop, worktree, tool invocation, validation, decision, and completion. + +**Publishes:** lifecycle events, requested/approved capabilities, evidence +references, result summaries, and checkpoint references. + +**Consumes:** scoped code/knowledge context, policy verdicts, provider results, +review/inspection findings, and shared contracts. + +**Robustness:** bounded retries, explicit cancellation, worktree isolation, +idempotent mutating tools, budget limits, and a mandatory verify gate before +integration. + +### `eyrie` — provider and model operations graph + +**Owns:** provider, model, credential scope, request, fallback, cache, health, +latency, token use, and cost relationships. + +**Publishes:** provider health, route choice, retry/fallback reason, usage, and +redacted request provenance. + +**Consumes:** model-selection policy and request budgets from Hawk/Cloud. + +**Robustness:** provider isolation, typed errors, circuit breaking, bounded +retries, cache correctness, and no credential material in graph payloads. + +### `tok` — context quality and safety signals + +**Owns:** token budgets, compaction snapshots, redaction findings, context +segments, compression lineage, and rate-limit signals. + +**Publishes:** safe context references, token/cost accounting, redaction +outcomes, and compaction provenance. + +**Consumes:** phase budgets and content-classification policy. + +**Robustness:** deterministic redaction before persistence/export, immutable +anchors during compaction, and budget exhaustion as a controlled state. + +**Implemented runtime:** Hawk feeds Tok from the central deduplicated provider +usage seam. Tok publishes a usage operations node and a dependent budget-policy +node for persisted sessions, while its decision participates in Hawk's +pre-turn guard. A thread-safe limit snapshot API keeps runtime configuration +and graph observations consistent. + +### `yaad` — temporal knowledge graph + +**Owns:** memories, entities, conventions, decisions, source evidence, +supersession, communities, and retention/decay state. + +**Publishes:** scoped, ranked, evidence-backed knowledge subgraphs and memory +write events. + +**Consumes:** validated task outcomes, repository scope, privacy policy, and +optional code/entity links. + +**Robustness:** source attribution, confidence, temporal supersession, privacy +filtering before ingestion, deterministic IDs, and a review path for disputed +memory. + +### `trace` — provenance and replay graph + +**Owns:** sessions, agent turns, checkpoints, Git commits, branch/fork links, +artifact references, and replay lineage. + +**Publishes:** immutable checkpoint and provenance events. + +**Consumes:** execution lifecycle events and repository/Git metadata. + +**Robustness:** append-only checkpoint records, secret redaction, resumable +session state, fork-safe identity, and retention policies. + +### `sight` — code quality graph + +**Owns:** diffs, findings, comments, review runs, evidence locations, +remediation status, and regression links. + +**Publishes:** typed review findings tied to commit, file, symbol, and execution +node references. + +**Consumes:** diffs, code graph context, review policy, and optional prior +finding history. + +**Robustness:** deterministic finding identity, severity/confidence contracts, +deduplication, and evidence required for blocking verdicts. + +### `inspect` — security and external-surface graph + +**Owns:** targets, domains, endpoints, TLS/cookie/header observations, +vulnerabilities, attack-surface findings, and remediation state. + +**Publishes:** timestamped, evidence-backed security findings and target +relationships. + +**Consumes:** authorized target scope, policy, and application/deployment +metadata. + +**Robustness:** read-only default, explicit target authorization, scan limits, +reproducible evidence, and clear distinction between observation and inference. + +### `hawk-mcpkit` — graph-aware capability gateway + +**Owns:** shared MCP transport and handler construction patterns. + +**Publishes:** standardized MCP tool metadata, capability declarations, schemas, +and graph query/result envelopes. + +**Consumes:** tool contracts, permission verdicts, and individual engine +handlers. + +**Robustness:** strict schemas, capability-scoped tool exposure, redacted error +messages, and correlation IDs propagated to tracing. + +**Implemented foundation:** `AddGraphResource` registers producer-supplied JSON +as a read-only `application/vnd.hawk.graph+json` MCP resource. MCPKit remains +contract-agnostic and has no ecosystem dependency; producers still own schema +validation, redaction, authorization, and size bounds. Sensitive graph +resources must use the whole-HTTP-surface token gate because the tool-only +bearer mode does not protect resources. + +### `hawk-graph` — ecosystem architecture visualization + +**Owns:** the static dashboard, generated architecture trees/call-flow pages, +and documentation that visually presents all repositories. + +**Publishes:** visualization pages and non-authoritative navigation links only. + +**Consumes:** generated, read-only analysis artifacts from each repository. +It does not consume runtime events, perform agent retrieval, or make policy or +execution decisions. + +**Robustness:** rebuildable generated pages, source-version labels, stale-index +visibility, and no authority to mutate or serve as a source of truth for any +other repository. + +### `hawk-cloud` — durable cloud coordination graph + +**Owns:** organization, tenant, project, device, policy, approval, audit, usage, +deployment, and cloud execution state. + +**Publishes:** authoritative tenancy/policy/audit/usage events and approval +decisions. + +**Consumes:** user-approved synchronization from local Hawk, GrayCode identity, +and provider/deployment facts. + +**Robustness:** durable workflow instances for long-running cloud operations, +strong per-entity coordination, idempotent ledger writes, event archival, and +fail-open local execution where cloud sync is optional. + +**Implemented foundation:** Hawk Cloud independently validates `*.graph/v1` +payloads without importing another ecosystem repository. Device-authenticated +syncs are capped at 1 MiB and 900 facts, scoped to one project/session, and +stored transactionally in D1. Local identifiers and provenance pointers are +hashed before persistence. Authorized reads return a bounded topology whose +edges and events cannot dangle outside the returned node set. + +Hawk's explicit `cloud graph sync` command builds a stable completed-session +snapshot, hashes sensitive attribute values before transport, enforces Cloud's +fact and body limits locally, and derives a deterministic sync ID. The adapter +returns errors to this user-invoked command but is not part of local execution, +so Cloud remains optional and fail-open. + +### `graycode-core` — product, identity, and dashboard graph + +**Owns:** web UX, authenticated API surface, account identity, dashboard views, +and product-facing integrations. + +**Publishes:** authenticated requests, user/organization/project references, +and UI-safe graph projections. + +**Consumes:** Hawk Cloud control-plane data and read-only ecosystem graph views. + +**Robustness:** tenant isolation, authorization on every graph query, secure +headers/CORS, D1 migration discipline, and no client-side trust in policy +verdicts. + +**Implemented foundation:** the authenticated BFF validates Hawk Cloud's +response and emits a smaller UI contract containing counts, display-safe node +details, relationships, and lifecycle events. The dashboard visualizes that +projection but owns no graph facts, policy decisions, or runtime behavior. + +### `hawk-community-skills` — skill and capability graph + +**Owns:** skills, manifests, source/provenance, tool requirements, compatibility, +audit results, and trust status. + +**Publishes:** installable capability metadata and audit evidence. + +**Consumes:** policy/risk classification, tool contract versions, and registry +validation results. + +**Robustness:** signed/versioned manifests where available, quarantine for +untrusted skills, dependency scanning, and explicit capability disclosure. + +**Implemented foundation:** `tools/skill_graph.py` projects the validated +registry into a `community-skills.graph/v1` heterogeneous graph. The registry +contains categories and tags, categories contain skills, and skills reference +their tags. Stable opaque IDs, a canonical input digest, one idempotent snapshot +event, optional bounds, and SDK compatibility tests make it reproducible while +leaving `registry.json` authoritative and generated by its existing workflow. + +### `hawk-sdk-go` — Go graph/runtime client + +**Owns:** idiomatic Go bindings for Hawk task, execution, trace, and graph APIs. + +**Publishes:** no source-of-truth graph facts; it is a typed client. + +**Consumes:** versioned Hawk and shared contract APIs. + +**Robustness:** context-aware cancellation, typed errors, retries only for +idempotent operations, SSE reconnect safety, and contract parity tests. + +### `hawk-sdk-python` — Python graph/runtime client + +**Owns:** Python bindings and models for the same API surface. + +**Publishes:** no source-of-truth graph facts. + +**Consumes:** versioned Hawk and shared contract APIs. + +**Robustness:** async cancellation, Pydantic validation, safe retries, and +contract compatibility tests. + +### `hawk-sdk-typescript` — TypeScript graph/runtime client + +**Owns:** TypeScript bindings, streaming clients, and typed tool/agent access. + +**Publishes:** no source-of-truth graph facts. + +**Consumes:** versioned Hawk and shared contract APIs. + +**Robustness:** runtime schema validation at API boundaries, abort support, +streaming recovery, and compatibility tests. + +## Cross-repository execution flow + +```text +user task + -> Hawk creates execution graph + -> Yaad + Hawk's local code intelligence provide scoped context subgraph + -> Eyrie routes model request within budget + -> Hawk invokes approved tools in an isolated worktree + -> Tok measures/redacts/compacts context + -> Sight + Inspect validate in parallel where applicable + -> Trace records checkpoints and evidence + -> Hawk resolves outcome or requests approval + -> Yaad learns validated knowledge; Hawk Cloud receives approved audit/usage sync +``` + +## Rollout order + +1. Add Graph Contract v1 and compatibility tests in `hawk-core-contracts`. + **Implemented.** +2. Implement a single Hawk execution-graph vertical slice with Trace checkpoints. + **Implemented as read-only Hawk and Trace projections plus Hawk's append-only + runtime observation journal. Trace's exact-match correlation lookup and + Hawk-side automatic session/checkpoint reference composition are + implemented with bounded, fail-open validation.** +3. Connect Yaad and Hawk's local code intelligence as read-only context sources. + **Implemented for retrieved Yaad memory subgraphs and Yaad-backed Hawk code + index chunks, journaled and linked to Hawk sessions.** +4. Attach Sight, Inspect, and Tok as validation, safety, and budget nodes. + **Inspect and Sight quality projections plus Hawk composition implemented; + Tok projection plus context-compression and response-redaction capture + implemented. Tok usage/budget capture and next-turn enforcement now run from + Hawk's deduplicated provider-accounting seam.** +5. Project approved cloud events into Hawk Cloud and GrayCode Core. + **Cloud ingestion/ledger/query and GrayCode's UI-safe BFF/dashboard are + implemented, including Hawk's explicit opt-in upload client.** +6. Regenerate `hawk-graph` visualizations from approved repository artifacts. +7. Expand SDKs and MCP tools only after the API contracts stabilize. + **Portable Graph v1 SDK models and the generic read-only MCP resource helper + are implemented; HTTP client methods remain intentionally deferred until + Hawk exposes a stable graph endpoint.** + +## Acceptance criteria + +- Every side effect is attributable, policy-checked, and idempotent. +- Failed execution resumes without repeating completed side effects. +- Context is scoped, redacted, evidence-backed, and budgeted. +- Graph queries cannot cross tenant or repository authorization boundaries. +- Every graph topology has deterministic tests and telemetry. +- A simple task uses a simple loop; graph fan-out is reserved for real parallel or + branching dependencies. diff --git a/global/global-arch.html b/global/global-arch.html index 454912d..6b43e13 100644 --- a/global/global-arch.html +++ b/global/global-arch.html @@ -85,7 +85,7 @@

Hawk-Eco Architecture — Knowledge Graph

+ + + +
+ +

hawk-sdk-typescript — Complete Call Flow & Architecture Documentation

+

Generated from graphify knowledge graph: 204 nodes, 370 edges, 11 communities. Commit: ff09e3e

+ + + + +

1. Architecture Overview

+ +
+ +%%{init: {"theme": "dark", "themeVariables": {"fontSize": "15.0px", "fontFamily": "Segoe UI, system-ui, sans-serif", "primaryColor": "#1e293b", "primaryTextColor": "#e2e8f0", "primaryBorderColor": "#38bdf8", "secondaryColor": "#0f172a", "tertiaryColor": "#334155", "lineColor": "#64748b", "textColor": "#e2e8f0"}, "flowchart": {"htmlLabels": true, "curve": "basis", "nodeSpacing": 48, "rankSpacing": 64, "padding": 14, "diagramPadding": 10, "useMaxWidth": true}}}%% +flowchart LR + BUILD_GRAPH_321CBB04("Graph Build
98 nodes") + class BUILD_GRAPH_321CBB04 module; + CLI_SKILLS_9964CBB8("CLI & Skill Installers
11 nodes") + class CLI_SKILLS_9964CBB8 module; + TESTS_FIXTURES_B84B1DCC("Tests & Fixtures
88 nodes") + class TESTS_FIXTURES_B84B1DCC module; + STREAMTS_STREAMREADER_CONSTRUCTOR_01E85173("Streamts Streamreader Constructor
7 nodes") + class STREAMTS_STREAMREADER_CONSTRUCTOR_01E85173 module; + TESTS_FIXTURES_B84B1DCC -->|imports x10| CLI_SKILLS_9964CBB8 + CLI_SKILLS_9964CBB8 -->|references x8| TESTS_FIXTURES_B84B1DCC + TESTS_FIXTURES_B84B1DCC -->|imports x4| STREAMTS_STREAMREADER_CONSTRUCTOR_01E85173 + CLI_SKILLS_9964CBB8 -->|references| STREAMTS_STREAMREADER_CONSTRUCTOR_01E85173 + BUILD_GRAPH_321CBB04 -->|re exports| TESTS_FIXTURES_B84B1DCC + TESTS_FIXTURES_B84B1DCC -->|imports| BUILD_GRAPH_321CBB04 + classDef entry fill:#422006,stroke:#fbbf24,color:#fde68a,stroke-width:1px; + classDef api fill:#450a0a,stroke:#f87171,color:#fee2e2,stroke-width:1px; + classDef async fill:#2e1065,stroke:#a78bfa,color:#ede9fe,stroke-width:1px; + classDef klass fill:#064e3b,stroke:#34d399,color:#d1fae5,stroke-width:1px; + classDef ui fill:#831843,stroke:#f472b6,color:#fce7f3,stroke-width:1px; + classDef module fill:#172554,stroke:#60a5fa,color:#dbeafe,stroke-width:1px; + classDef test fill:#3f3f46,stroke:#a1a1aa,color:#f4f4f5,stroke-width:1px; + classDef concept fill:#292524,stroke:#a8a29e,color:#fafaf9,stroke-dasharray:4 3; + classDef function fill:#0f172a,stroke:#38bdf8,color:#e0f2fe,stroke-width:1px; +
+ +
+
+

Architecture Layers

+ + + +
LayerNodesCommunities
Graph Build980, 2, 3, 7
CLI & Skill Installers116
Tests & Fixtures881, 4, 5, 8, 10
Streamts Streamreader Constructor79
+
+
+

Core Flow

+
Graph Build -> Tests & Fixtures -> CLI & Skill Installers -> Streamts Streamreader Constructor
+
+
+
+ +

2. Graph Build

+

Graph Build groups implementation around packagejson, tsconfigjson, graphts, node, mostly in package.json, tsconfig.json, src/graph.ts. This section covers 98 nodes and 115 internal edges; the diagram shows only representative relationships to stay readable.

+ +
+%%{init: {"theme": "dark", "themeVariables": {"fontSize": "15.0px", "fontFamily": "Segoe UI, system-ui, sans-serif", "primaryColor": "#1e293b", "primaryTextColor": "#e2e8f0", "primaryBorderColor": "#38bdf8", "secondaryColor": "#0f172a", "tertiaryColor": "#334155", "lineColor": "#64748b", "textColor": "#e2e8f0"}, "flowchart": {"htmlLabels": true, "curve": "basis", "nodeSpacing": 48, "rankSpacing": 64, "padding": 14, "diagramPadding": 10, "useMaxWidth": true}}}%% +flowchart LR + %% Section: Graph Build (98 nodes, 115 edges) + subgraph build_graph_src_graph_ts_86cd08e0["src/graph.ts"] + src_graph_requiredstring_d0794535("requiredString()
src/graph.ts") + src_graph_record_04390583("record()
src/graph.ts") + src_graph_graphref_022ed992("GraphRef
src/graph.ts") + src_graph_optionalstring_19180000("optionalString()
src/graph.ts") + src_graph_enumvalue_3fdde739("enumValue()
src/graph.ts") + src_graph_parsegraphexport_5ed58660("parseGraphExport()
src/graph.ts") + src_graph_provenance_d6e5c427("provenance()
src/graph.ts") + src_graph_scope_2ff22987("scope()
src/graph.ts") + src_graph_stringrecord_54d6b107("stringRecord()
src/graph.ts") + src_graph_timestamp_ec5de79f("timestamp()
src/graph.ts") + end + subgraph build_graph_package_json_4e40bfbd["package.json"] + package_devdependencies_prettier_e9e59bec("prettier
package.json") + package_devdependencies_tsx_a8f732ed("tsx
package.json") + package_devdependencies_types_node_04b141e9("@types/node
package.json") + types_node_eed9011c("@types/node
package.json") + prettier_9fd021d1("prettier
package.json") + tsx_a90e8eec("tsx
package.json") + package_devdependencies_typescript_6defc6cf("typescript
package.json") + typescript_fb9da861("typescript
package.json") + end + src_graph_graphref_022ed992 -->|calls| src_graph_enumvalue_3fdde739 + src_graph_graphref_022ed992 -->|calls| src_graph_record_04390583 + src_graph_graphref_022ed992 -->|calls| src_graph_requiredstring_d0794535 + src_graph_record_04390583 -->|calls| src_graph_parsegraphexport_5ed58660 + src_graph_record_04390583 -->|calls| src_graph_provenance_d6e5c427 + src_graph_record_04390583 -->|calls| src_graph_scope_2ff22987 + src_graph_record_04390583 -->|calls| src_graph_stringrecord_54d6b107 + src_graph_requiredstring_d0794535 -->|calls| src_graph_enumvalue_3fdde739 + src_graph_requiredstring_d0794535 -->|calls| src_graph_optionalstring_19180000 + src_graph_requiredstring_d0794535 -->|calls| src_graph_parsegraphexport_5ed58660 + src_graph_requiredstring_d0794535 -->|calls| src_graph_provenance_d6e5c427 + src_graph_requiredstring_d0794535 -->|calls| src_graph_timestamp_ec5de79f + src_graph_optionalstring_19180000 -->|calls| src_graph_parsegraphexport_5ed58660 + src_graph_optionalstring_19180000 -->|calls| src_graph_provenance_d6e5c427 + src_graph_optionalstring_19180000 -->|calls| src_graph_scope_2ff22987 + src_graph_timestamp_ec5de79f -->|calls| src_graph_parsegraphexport_5ed58660 + src_graph_stringrecord_54d6b107 -->|calls| src_graph_parsegraphexport_5ed58660 + src_graph_scope_2ff22987 -->|calls| src_graph_parsegraphexport_5ed58660 + src_graph_enumvalue_3fdde739 -->|calls| src_graph_parsegraphexport_5ed58660 + src_graph_provenance_d6e5c427 -->|calls| src_graph_parsegraphexport_5ed58660 + package_devdependencies_types_node_04b141e9 -->|imports| types_node_eed9011c + package_devdependencies_prettier_e9e59bec -->|imports| prettier_9fd021d1 + package_devdependencies_tsx_a8f732ed -->|imports| tsx_a90e8eec + package_devdependencies_typescript_6defc6cf -->|imports| typescript_fb9da861 + %% Omitted for readability: 80 nodes, 0 edges + class src_graph_requiredstring_d0794535 function; + class src_graph_record_04390583 function; + class src_graph_graphref_022ed992 klass; + class src_graph_optionalstring_19180000 function; + class src_graph_enumvalue_3fdde739 function; + class src_graph_parsegraphexport_5ed58660 function; + class src_graph_provenance_d6e5c427 function; + class src_graph_scope_2ff22987 function; + class src_graph_stringrecord_54d6b107 function; + class src_graph_timestamp_ec5de79f function; + class package_devdependencies_prettier_e9e59bec function; + class package_devdependencies_tsx_a8f732ed function; + class package_devdependencies_types_node_04b141e9 function; + class types_node_eed9011c function; + class prettier_9fd021d1 function; + class tsx_a90e8eec function; + class package_devdependencies_typescript_6defc6cf function; + class typescript_fb9da861 function; + classDef entry fill:#422006,stroke:#fbbf24,color:#fde68a,stroke-width:1px; + classDef api fill:#450a0a,stroke:#f87171,color:#fee2e2,stroke-width:1px; + classDef async fill:#2e1065,stroke:#a78bfa,color:#ede9fe,stroke-width:1px; + classDef klass fill:#064e3b,stroke:#34d399,color:#d1fae5,stroke-width:1px; + classDef ui fill:#831843,stroke:#f472b6,color:#fce7f3,stroke-width:1px; + classDef module fill:#172554,stroke:#60a5fa,color:#dbeafe,stroke-width:1px; + classDef test fill:#3f3f46,stroke:#a1a1aa,color:#f4f4f5,stroke-width:1px; + classDef concept fill:#292524,stroke:#a8a29e,color:#fafaf9,stroke-dasharray:4 3; + classDef function fill:#0f172a,stroke:#38bdf8,color:#e0f2fe,stroke-width:1px; +
+ +

Call Details

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#NodeTypeCallerCalleesDescription
1package.json
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgepackage.json node in package.json.
2name
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgename node in package.json.
3version
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgeversion node in package.json.
4description
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgedescription node in package.json.
5type
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgetype node in package.json.
6main
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgemain node in package.json.
7module
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgemodule node in package.json.
8types
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgetypes node in package.json.
9exports
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgeExports documentation data to a target format.
10files
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgefiles node in package.json.
11dist
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgedist node in package.json.
12README.md
package.json
ClassExternal entry / no inbound edgeNo direct outbound edgeREADME.md node in package.json.
13LICENSE
package.json
ClassExternal entry / no inbound edgeNo direct outbound edgeLICENSE node in package.json.
14VERSION
package.json
ClassExternal entry / no inbound edgeNo direct outbound edgeVERSION node in package.json.
15engines
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgeengines node in package.json.
16node
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgenode node in package.json.
17scripts
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgescripts node in package.json.
18build
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgebuild node in package.json.
19clean
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgeclean node in package.json.
20typecheck
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgetypecheck node in package.json.
21lint
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgelint node in package.json.
22format
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgeformat node in package.json.
23test
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgeVerifies imports, entry points, or version behavior.
24test:coverage
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgeSupports retrieval-augmented Q&A or streaming chat.
25prepublishOnly
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgeprepublishOnly node in package.json.
26keywords
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgekeywords node in package.json.
27hawk
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgehawk node in package.json.
28sdk
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgesdk node in package.json.
29ai
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgeai node in package.json.
30agent
package.json
FunctionExternal entry / no inbound edgeNo direct outbound edgeagent node in package.json.
+ +
+
+

Key Files

+ + + + + + +
FileCoverage
package.json46 nodes
tsconfig.json26 nodes
src/graph.ts24 nodes
test/graph.test.ts2 nodes
+
+
+

Design Notes

+

This section comes from graphify community clustering. Relationship summary: contains x74, calls x20, extends x16, imports x5. The diagram prioritizes high-confidence calls or usage relationships; the table keeps the broader node inventory.

+
+
+
+ + +

3. CLI & Skill Installers

+

CLI & Skill Installers groups implementation around agentts, chat, clientts, typests, mostly in src/agent.ts, src/client.ts, src/types.ts. This section covers 11 nodes and 18 internal edges; the diagram shows only representative relationships to stay readable.

+ +
+%%{init: {"theme": "dark", "themeVariables": {"fontSize": "15.0px", "fontFamily": "Segoe UI, system-ui, sans-serif", "primaryColor": "#1e293b", "primaryTextColor": "#e2e8f0", "primaryBorderColor": "#38bdf8", "secondaryColor": "#0f172a", "tertiaryColor": "#334155", "lineColor": "#64748b", "textColor": "#e2e8f0"}, "flowchart": {"htmlLabels": true, "curve": "basis", "nodeSpacing": 48, "rankSpacing": 64, "padding": 14, "diagramPadding": 10, "useMaxWidth": true}}}%% +flowchart LR + %% Section: CLI & Skill Installers (11 nodes, 18 edges) + subgraph cli_skills_src_agent_ts_0c250adb["src/agent.ts"] + src_agent_agent_66b8cda7("Agent
src/agent.ts") + src_agent_agent_chat_3d2d80cf("chat()
src/agent.ts") + src_agent_agent_chatstream_dd586391("chatStream()
src/agent.ts") + src_agent_agent_buildrequest_d0934580("buildRequest()
src/agent.ts") + src_agent_agent_constructor_755afdd4("constructor()
src/agent.ts") + src_agent_agent_sessionid_aa3e7bac("sessionID()
src/agent.ts") + src_agent_agent_updatesession_47d8d725("updateSession()
src/agent.ts") + end + subgraph cli_skills_src_client_ts_74edc25e["src/client.ts"] + src_client_hawkclient_chat_35f2a78c("chat()
src/client.ts") + src_client_hawkclient_chatwithtools_cf8f256b("chatWithTools()
src/client.ts") + end + subgraph cli_skills_src_types_ts_fdda1250["src/types.ts"] + src_types_chatrequest_4c48c39b("ChatRequest
src/types.ts") + src_types_chatresponse_7b210355("ChatResponse
src/types.ts") + end + src_agent_agent_66b8cda7 -->|method| src_agent_agent_buildrequest_d0934580 + src_agent_agent_66b8cda7 -->|method| src_agent_agent_chat_3d2d80cf + src_agent_agent_66b8cda7 -->|method| src_agent_agent_chatstream_dd586391 + src_agent_agent_66b8cda7 -->|method| src_agent_agent_constructor_755afdd4 + src_agent_agent_66b8cda7 -->|method| src_agent_agent_sessionid_aa3e7bac + src_agent_agent_66b8cda7 -->|method| src_agent_agent_updatesession_47d8d725 + src_agent_agent_chat_3d2d80cf -->|calls| src_agent_agent_buildrequest_d0934580 + src_agent_agent_chat_3d2d80cf -->|calls| src_agent_agent_updatesession_47d8d725 + src_agent_agent_chat_3d2d80cf -->|calls| src_client_hawkclient_chat_35f2a78c + src_agent_agent_chat_3d2d80cf -->|calls| src_client_hawkclient_chatwithtools_cf8f256b + src_agent_agent_chatstream_dd586391 -->|calls| src_agent_agent_buildrequest_d0934580 + class src_agent_agent_66b8cda7 klass; + class src_agent_agent_chat_3d2d80cf function; + class src_agent_agent_chatstream_dd586391 async; + class src_agent_agent_buildrequest_d0934580 function; + class src_agent_agent_constructor_755afdd4 function; + class src_agent_agent_sessionid_aa3e7bac function; + class src_agent_agent_updatesession_47d8d725 function; + class src_client_hawkclient_chat_35f2a78c function; + class src_client_hawkclient_chatwithtools_cf8f256b function; + class src_types_chatrequest_4c48c39b klass; + class src_types_chatresponse_7b210355 klass; + classDef entry fill:#422006,stroke:#fbbf24,color:#fde68a,stroke-width:1px; + classDef api fill:#450a0a,stroke:#f87171,color:#fee2e2,stroke-width:1px; + classDef async fill:#2e1065,stroke:#a78bfa,color:#ede9fe,stroke-width:1px; + classDef klass fill:#064e3b,stroke:#34d399,color:#d1fae5,stroke-width:1px; + classDef ui fill:#831843,stroke:#f472b6,color:#fce7f3,stroke-width:1px; + classDef module fill:#172554,stroke:#60a5fa,color:#dbeafe,stroke-width:1px; + classDef test fill:#3f3f46,stroke:#a1a1aa,color:#f4f4f5,stroke-width:1px; + classDef concept fill:#292524,stroke:#a8a29e,color:#fafaf9,stroke-dasharray:4 3; + classDef function fill:#0f172a,stroke:#38bdf8,color:#e0f2fe,stroke-width:1px; +
+ +

Call Details

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#NodeTypeCallerCalleesDescription
1Agent
src/agent.ts
ClassExternal entry / no inbound edgebuildRequest()
src/agent.ts
chat()
src/agent.ts
chatStream()
src/agent.ts
+3 more
Agent node in src/agent.ts.
2.constructor()
src/agent.ts
FunctionAgent
src/agent.ts
No direct outbound edge.constructor() node in src/agent.ts.
3.chat()
src/agent.ts
FunctionAgent
src/agent.ts
buildRequest()
src/agent.ts
chat()
src/client.ts
chatWithTools()
src/client.ts
+1 more
Supports retrieval-augmented Q&A or streaming chat.
4.chatStream()
src/agent.ts
AsyncAgent
src/agent.ts
buildRequest()
src/agent.ts
Supports retrieval-augmented Q&A or streaming chat.
5.sessionID()
src/agent.ts
FunctionAgent
src/agent.ts
No direct outbound edge.sessionID() node in src/agent.ts.
6.buildRequest()
src/agent.ts
FunctionAgent
src/agent.ts
chat()
src/agent.ts
chatStream()
src/agent.ts
No direct outbound edge.buildRequest() node in src/agent.ts.
7.updateSession()
src/agent.ts
FunctionAgent
src/agent.ts
chat()
src/agent.ts
No direct outbound edge.updateSession() node in src/agent.ts.
8.chat()
src/client.ts
Functionchat()
src/agent.ts
No direct outbound edgeSupports retrieval-augmented Q&A or streaming chat.
9.chatWithTools()
src/client.ts
Functionchat()
src/agent.ts
No direct outbound edgeSupports retrieval-augmented Q&A or streaming chat.
10ChatRequest
src/types.ts
ClassExternal entry / no inbound edgeNo direct outbound edgeSupports retrieval-augmented Q&A or streaming chat.
11ChatResponse
src/types.ts
ClassExternal entry / no inbound edgeNo direct outbound edgeSupports retrieval-augmented Q&A or streaming chat.
+ +
+
+

Key Files

+ + + + + +
FileCoverage
src/agent.ts7 nodes
src/client.ts2 nodes
src/types.ts2 nodes
+
+
+

Design Notes

+

This section comes from graphify community clustering. Relationship summary: references x7, method x6, calls x5. The diagram prioritizes high-confidence calls or usage relationships; the table keeps the broader node inventory.

+
+
+
+ + +

4. Tests & Fixtures

+

Tests & Fixtures groups implementation around errorsts, clientts, test, typests, mostly in src/errors.ts, src/client.ts, src/types.ts. This section covers 88 nodes and 203 internal edges; the diagram shows only representative relationships to stay readable.

+ +
+%%{init: {"theme": "dark", "themeVariables": {"fontSize": "15.0px", "fontFamily": "Segoe UI, system-ui, sans-serif", "primaryColor": "#1e293b", "primaryTextColor": "#e2e8f0", "primaryBorderColor": "#38bdf8", "secondaryColor": "#0f172a", "tertiaryColor": "#334155", "lineColor": "#64748b", "textColor": "#e2e8f0"}, "flowchart": {"htmlLabels": true, "curve": "basis", "nodeSpacing": 48, "rankSpacing": 64, "padding": 14, "diagramPadding": 10, "useMaxWidth": true}}}%% +flowchart LR + %% Section: Tests & Fixtures (88 nodes, 203 edges) + subgraph tests_fixtures_src_client_ts_60993fa3["src/client.ts"] + src_client_e4950f7f("client.ts") + src_client_hawkclient_f388023f("HawkClient
src/client.ts") + src_client_hawkclient_chatstream_abd88982("chatStream()
src/client.ts") + src_client_hawkclient_constructor_ec634568("constructor()
src/client.ts") + src_client_hawkclient_deletesession_04d93269("deleteSession()
src/client.ts") + src_client_hawkclient_getjson_41f7ccdd("getJSON()
src/client.ts") + src_client_hawkclient_health_490cfa47("health()
src/client.ts") + src_client_hawkclient_jsonheaders_4e48bb13("jsonHeaders()
src/client.ts") + src_client_hawkclient_messages_26d3e729("messages()
src/client.ts") + src_client_hawkclient_postjson_3d01975c("postJSON()
src/client.ts") + src_client_hawkclient_send_c5c8be24("send()
src/client.ts") + src_client_hawkclient_session_36dae51f("session()
src/client.ts") + src_client_hawkclient_sessions_3e50f559("sessions()
src/client.ts") + src_client_hawkclient_stats_ac4b018c("stats()
src/client.ts") + end + subgraph tests_fixtures_src_errors_ts_b0f29910["src/errors.ts"] + src_errors_authenticationerror_bd2d1c04("AuthenticationError
src/errors.ts") + src_errors_notfounderror_c9c2e6cf("NotFoundError
src/errors.ts") + end + src_agent_1337b576("agent.ts") + src_index_811cdc82("index.ts") + src_client_hawkclient_f388023f -->|method| src_client_hawkclient_chatstream_abd88982 + src_client_hawkclient_f388023f -->|method| src_client_hawkclient_constructor_ec634568 + src_client_hawkclient_f388023f -->|method| src_client_hawkclient_deletesession_04d93269 + src_client_hawkclient_f388023f -->|method| src_client_hawkclient_getjson_41f7ccdd + src_client_hawkclient_f388023f -->|method| src_client_hawkclient_health_490cfa47 + src_client_hawkclient_f388023f -->|method| src_client_hawkclient_jsonheaders_4e48bb13 + src_client_hawkclient_f388023f -->|method| src_client_hawkclient_messages_26d3e729 + src_client_hawkclient_f388023f -->|method| src_client_hawkclient_postjson_3d01975c + src_client_hawkclient_f388023f -->|method| src_client_hawkclient_send_c5c8be24 + src_client_hawkclient_f388023f -->|method| src_client_hawkclient_session_36dae51f + src_client_hawkclient_f388023f -->|method| src_client_hawkclient_sessions_3e50f559 + src_client_hawkclient_f388023f -->|method| src_client_hawkclient_stats_ac4b018c + src_client_hawkclient_health_490cfa47 -->|calls| src_client_hawkclient_getjson_41f7ccdd + src_client_hawkclient_chatstream_abd88982 -->|calls| src_client_hawkclient_jsonheaders_4e48bb13 + src_client_hawkclient_chatstream_abd88982 -->|calls| src_client_hawkclient_send_c5c8be24 + src_client_hawkclient_sessions_3e50f559 -->|calls| src_client_hawkclient_getjson_41f7ccdd + src_client_hawkclient_session_36dae51f -->|calls| src_client_hawkclient_getjson_41f7ccdd + src_client_hawkclient_messages_26d3e729 -->|calls| src_client_hawkclient_getjson_41f7ccdd + src_client_hawkclient_deletesession_04d93269 -->|calls| src_client_hawkclient_jsonheaders_4e48bb13 + src_client_hawkclient_deletesession_04d93269 -->|calls| src_client_hawkclient_send_c5c8be24 + src_client_hawkclient_stats_ac4b018c -->|calls| src_client_hawkclient_getjson_41f7ccdd + src_client_hawkclient_jsonheaders_4e48bb13 -->|calls| src_client_hawkclient_getjson_41f7ccdd + src_client_hawkclient_jsonheaders_4e48bb13 -->|calls| src_client_hawkclient_postjson_3d01975c + src_client_hawkclient_getjson_41f7ccdd -->|calls| src_client_hawkclient_send_c5c8be24 + %% Omitted for readability: 70 nodes, 3 edges + class src_client_e4950f7f entry; + class src_client_hawkclient_f388023f entry; + class src_client_hawkclient_chatstream_abd88982 async; + class src_client_hawkclient_constructor_ec634568 function; + class src_client_hawkclient_deletesession_04d93269 function; + class src_client_hawkclient_getjson_41f7ccdd function; + class src_client_hawkclient_health_490cfa47 function; + class src_client_hawkclient_jsonheaders_4e48bb13 function; + class src_client_hawkclient_messages_26d3e729 function; + class src_client_hawkclient_postjson_3d01975c function; + class src_client_hawkclient_send_c5c8be24 function; + class src_client_hawkclient_session_36dae51f function; + class src_client_hawkclient_sessions_3e50f559 function; + class src_client_hawkclient_stats_ac4b018c function; + class src_errors_authenticationerror_bd2d1c04 klass; + class src_errors_notfounderror_c9c2e6cf klass; + class src_agent_1337b576 module; + class src_index_811cdc82 module; + classDef entry fill:#422006,stroke:#fbbf24,color:#fde68a,stroke-width:1px; + classDef api fill:#450a0a,stroke:#f87171,color:#fee2e2,stroke-width:1px; + classDef async fill:#2e1065,stroke:#a78bfa,color:#ede9fe,stroke-width:1px; + classDef klass fill:#064e3b,stroke:#34d399,color:#d1fae5,stroke-width:1px; + classDef ui fill:#831843,stroke:#f472b6,color:#fce7f3,stroke-width:1px; + classDef module fill:#172554,stroke:#60a5fa,color:#dbeafe,stroke-width:1px; + classDef test fill:#3f3f46,stroke:#a1a1aa,color:#f4f4f5,stroke-width:1px; + classDef concept fill:#292524,stroke:#a8a29e,color:#fafaf9,stroke-dasharray:4 3; + classDef function fill:#0f172a,stroke:#38bdf8,color:#e0f2fe,stroke-width:1px; +
+ +

Call Details

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#NodeTypeCallerCalleesDescription
1agent.ts
src/agent.ts
ModuleExternal entry / no inbound edgeclient.ts
src/client.ts
HawkClient
src/client.ts
stream.ts
src/stream.ts
+3 more
Module file in src/agent.ts.
2MemoryConfig
src/agent.ts
ClassExternal entry / no inbound edgeNo direct outbound edgeReads, resolves, or persists project configuration.
3AgentConfig
src/agent.ts
ClassExternal entry / no inbound edgeNo direct outbound edgeReads, resolves, or persists project configuration.
4client.ts
src/client.ts
Entryagent.ts
src/agent.ts
backoffDurationMs()
src/retry.ts
ChatWithToolsRequest
src/types.ts
ChatWithToolsResponse
src/types.ts
+22 more
Module file in src/client.ts.
5SendInit
src/client.ts
ClassExternal entry / no inbound edgeNo direct outbound edgeSendInit node in src/client.ts.
6.messages()
src/client.ts
FunctionHawkClient
src/client.ts
getJSON()
src/client.ts
paginationParams()
src/client.ts
.messages() node in src/client.ts.
7paginationParams()
src/client.ts
Functionmessages()
src/client.ts
No direct outbound edgepaginationParams() node in src/client.ts.
8index.ts
src/index.ts
ModuleExternal entry / no inbound edgeagent.test.ts
test/agent.test.ts
client.test.ts
test/client.test.ts
errors.test.ts
test/errors.test.ts
+4 more
Module file in src/index.ts.
9stream.ts
src/stream.ts
Asyncagent.ts
src/agent.ts
client.ts
src/client.ts
No direct outbound edgeModule file in src/stream.ts.
10tools.ts
src/tools.ts
Moduleagent.ts
src/agent.ts
client.ts
src/client.ts
ToolSchema
src/types.ts
types.ts
src/types.ts
Module file in src/tools.ts.
11Tool
src/tools.ts
Classagent.ts
src/agent.ts
client.ts
src/client.ts
tools.test.ts
test/tools.test.ts
Tool node in src/tools.ts.
12types.ts
src/types.ts
Moduleagent.ts
src/agent.ts
client.ts
src/client.ts
tools.ts
src/tools.ts
No direct outbound edgeModule file in src/types.ts.
13HealthResponse
src/types.ts
Classclient.ts
src/client.ts
No direct outbound edgeHealthResponse node in src/types.ts.
14SessionSummary
src/types.ts
Classclient.ts
src/client.ts
No direct outbound edgeSessionSummary node in src/types.ts.
15SessionDetail
src/types.ts
Classclient.ts
src/client.ts
No direct outbound edgeSessionDetail node in src/types.ts.
16ToolSchema
src/types.ts
Classclient.ts
src/client.ts
tools.ts
src/tools.ts
No direct outbound edgeToolSchema node in src/types.ts.
17ToolCall
src/types.ts
ClassExternal entry / no inbound edgeNo direct outbound edgeToolCall node in src/types.ts.
18ToolResult
src/types.ts
Classclient.ts
src/client.ts
No direct outbound edgeToolResult node in src/types.ts.
19Message
src/types.ts
Classclient.ts
src/client.ts
No direct outbound edgeMessage node in src/types.ts.
20ChatWithToolsRequest
src/types.ts
Classclient.ts
src/client.ts
No direct outbound edgeSupports retrieval-augmented Q&A or streaming chat.
21ChatWithToolsResponse
src/types.ts
Classclient.ts
src/client.ts
agent.test.ts
test/agent.test.ts
tools.test.ts
test/tools.test.ts
Supports retrieval-augmented Q&A or streaming chat.
22ModelStat
src/types.ts
ClassExternal entry / no inbound edgeNo direct outbound edgeModelStat node in src/types.ts.
23StatsResponse
src/types.ts
Classclient.ts
src/client.ts
No direct outbound edgeStatsResponse node in src/types.ts.
24PaginatedResponse
src/types.ts
Classclient.ts
src/client.ts
No direct outbound edgePaginatedResponse node in src/types.ts.
25ListOptions
src/types.ts
Classclient.ts
src/client.ts
No direct outbound edgeListOptions node in src/types.ts.
26ErrorResponse
src/types.ts
ClassExternal entry / no inbound edgeNo direct outbound edgeErrorResponse node in src/types.ts.
27version.ts
src/version.ts
Moduleclient.ts
src/client.ts
No direct outbound edgeModule file in src/version.ts.
28userAgent()
src/version.ts
Functionclient.ts
src/client.ts
jsonHeaders()
src/client.ts
No direct outbound edgeSupports retrieval-augmented Q&A or streaming chat.
29tools.test.ts
test/tools.test.ts
TestChatWithToolsResponse
src/types.ts
HawkClient
src/client.ts
helpers.ts
test/helpers.ts
+4 more
No direct outbound edgeModule file in test/tools.test.ts.
30echoTool
test/tools.test.ts
TestExternal entry / no inbound edgeNo direct outbound edgeechoTool node in test/tools.test.ts.
+ +
+
+

Key Files

+ + + + + + + + + + +
FileCoverage
src/errors.ts20 nodes
src/client.ts17 nodes
src/types.ts15 nodes
src/retry.ts8 nodes
test/helpers.ts5 nodes
test/version.test.ts4 nodes
src/agent.ts3 nodes
src/stream.ts2 nodes
+
+
+

Design Notes

+

This section comes from graphify community clustering. Relationship summary: imports x57, contains x51, calls x25, imports x24. The diagram prioritizes high-confidence calls or usage relationships; the table keeps the broader node inventory.

+
+
+
+ + +

5. Streamts Streamreader Constructor

+

Streamts Streamreader Constructor groups implementation around streamts, streamreader, constructor, next, mostly in src/stream.ts. This section covers 7 nodes and 9 internal edges; the diagram shows only representative relationships to stay readable.

+ +
+%%{init: {"theme": "dark", "themeVariables": {"fontSize": "15.0px", "fontFamily": "Segoe UI, system-ui, sans-serif", "primaryColor": "#1e293b", "primaryTextColor": "#e2e8f0", "primaryBorderColor": "#38bdf8", "secondaryColor": "#0f172a", "tertiaryColor": "#334155", "lineColor": "#64748b", "textColor": "#e2e8f0"}, "flowchart": {"htmlLabels": true, "curve": "basis", "nodeSpacing": 48, "rankSpacing": 64, "padding": 14, "diagramPadding": 10, "useMaxWidth": true}}}%% +flowchart LR + %% Section: Streamts Streamreader Constructor (7 nodes, 9 edges) + src_stream_streamreader_cdfa26d9("StreamReader
src/stream.ts") + src_stream_streamreader_next_caa7d305("next()
src/stream.ts") + src_stream_streamreader_dispatch_d6fa0675("dispatch()
src/stream.ts") + src_stream_streamreader_close_d17c684d("close()
src/stream.ts") + src_stream_streamreader_constructor_21a06688("constructor()
src/stream.ts") + src_stream_streamreader_processline_aae2e2f9("processLine()
src/stream.ts") + src_stream_streamreader_symbol_asynciterator_5fb0000c("[Symbol.asyncIterator]()
src/stream.ts") + src_stream_streamreader_cdfa26d9 -->|method| src_stream_streamreader_close_d17c684d + src_stream_streamreader_cdfa26d9 -->|method| src_stream_streamreader_constructor_21a06688 + src_stream_streamreader_cdfa26d9 -->|method| src_stream_streamreader_dispatch_d6fa0675 + src_stream_streamreader_cdfa26d9 -->|method| src_stream_streamreader_next_caa7d305 + src_stream_streamreader_cdfa26d9 -->|method| src_stream_streamreader_processline_aae2e2f9 + src_stream_streamreader_cdfa26d9 -->|method| src_stream_streamreader_symbol_asynciterator_5fb0000c + src_stream_streamreader_next_caa7d305 -->|calls| src_stream_streamreader_dispatch_d6fa0675 + src_stream_streamreader_next_caa7d305 -->|calls| src_stream_streamreader_processline_aae2e2f9 + src_stream_streamreader_dispatch_d6fa0675 -->|calls| src_stream_streamreader_processline_aae2e2f9 + class src_stream_streamreader_cdfa26d9 async; + class src_stream_streamreader_next_caa7d305 function; + class src_stream_streamreader_dispatch_d6fa0675 function; + class src_stream_streamreader_close_d17c684d function; + class src_stream_streamreader_constructor_21a06688 function; + class src_stream_streamreader_processline_aae2e2f9 function; + class src_stream_streamreader_symbol_asynciterator_5fb0000c async; + classDef entry fill:#422006,stroke:#fbbf24,color:#fde68a,stroke-width:1px; + classDef api fill:#450a0a,stroke:#f87171,color:#fee2e2,stroke-width:1px; + classDef async fill:#2e1065,stroke:#a78bfa,color:#ede9fe,stroke-width:1px; + classDef klass fill:#064e3b,stroke:#34d399,color:#d1fae5,stroke-width:1px; + classDef ui fill:#831843,stroke:#f472b6,color:#fce7f3,stroke-width:1px; + classDef module fill:#172554,stroke:#60a5fa,color:#dbeafe,stroke-width:1px; + classDef test fill:#3f3f46,stroke:#a1a1aa,color:#f4f4f5,stroke-width:1px; + classDef concept fill:#292524,stroke:#a8a29e,color:#fafaf9,stroke-dasharray:4 3; + classDef function fill:#0f172a,stroke:#38bdf8,color:#e0f2fe,stroke-width:1px; +
+ +

Call Details

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#NodeTypeCallerCalleesDescription
1StreamReader
src/stream.ts
AsyncExternal entry / no inbound edge[Symbol.asyncIterator]()
src/stream.ts
close()
src/stream.ts
constructor()
src/stream.ts
+3 more
StreamReader node in src/stream.ts.
2.constructor()
src/stream.ts
FunctionStreamReader
src/stream.ts
No direct outbound edge.constructor() node in src/stream.ts.
3.next()
src/stream.ts
FunctionStreamReader
src/stream.ts
dispatch()
src/stream.ts
processLine()
src/stream.ts
.next() node in src/stream.ts.
4.[Symbol.asyncIterator]()
src/stream.ts
AsyncStreamReader
src/stream.ts
No direct outbound edge.[Symbol.asyncIterator]() node in src/stream.ts.
5.close()
src/stream.ts
FunctionStreamReader
src/stream.ts
No direct outbound edge.close() node in src/stream.ts.
6.dispatch()
src/stream.ts
Functionnext()
src/stream.ts
StreamReader
src/stream.ts
processLine()
src/stream.ts
.dispatch() node in src/stream.ts.
7.processLine()
src/stream.ts
Functiondispatch()
src/stream.ts
next()
src/stream.ts
StreamReader
src/stream.ts
No direct outbound edge.processLine() node in src/stream.ts.
+ +
+
+

Key Files

+ + + +
FileCoverage
src/stream.ts7 nodes
+
+
+

Design Notes

+

This section comes from graphify community clustering. Relationship summary: method x6, calls x3. The diagram prioritizes high-confidence calls or usage relationships; the table keeps the broader node inventory.

+
+
+
+ +

Project Statistics

+ +
+
+

Graph

+ + + + + + +
Nodes204
Edges370
Hyperedges0
Communities11
Documented Sections4
+
+
+

Edge Confidence

+ + + + +
EXTRACTED370
INFERRED0
AMBIGUOUS0
+
+
+ +
+

hawk-sdk-typescript — Architecture Documentation

+

Generated: 2026-07-25 05:00 UTC · graphify callflow-html

+
+ +
+ + + + + \ No newline at end of file diff --git a/repos/hawk-sdk-typescript-tree.html b/repos/hawk-sdk-typescript-tree.html new file mode 100644 index 0000000..5e97cfe --- /dev/null +++ b/repos/hawk-sdk-typescript-tree.html @@ -0,0 +1,363 @@ + + + + + hawk-sdk-typescript — graphify tree viewer + + + +

hawk-sdk-typescript — Knowledge Graph

+
+ + + +
+
+ +
+ + + + + diff --git a/scripts/analyze-all-gitnexus.sh b/scripts/analyze-all-gitnexus.sh index b8d1646..fc00cd8 100755 --- a/scripts/analyze-all-gitnexus.sh +++ b/scripts/analyze-all-gitnexus.sh @@ -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 ===" \ No newline at end of file +echo "=== Done ===" diff --git a/scripts/extract-all.sh b/scripts/extract-all.sh index 873b064..7a3b9a2 100755 --- a/scripts/extract-all.sh +++ b/scripts/extract-all.sh @@ -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 ===" \ No newline at end of file +echo "=== Done ===" diff --git a/scripts/refresh-trees.sh b/scripts/refresh-trees.sh index 783c708..0737a47 100755 --- a/scripts/refresh-trees.sh +++ b/scripts/refresh-trees.sh @@ -3,7 +3,7 @@ set -euo pipefail HAWK_ECO="${HAWK_ECO:-..}" HAWK_GRAPH="$(cd "$(dirname "$0")/.." && pwd)" -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 "=== Regenerating per-repo D3 trees ===" for r in "${repos[@]}"; do @@ -27,4 +27,4 @@ done echo "=== Regenerating global architecture ===" graphify tree --graph ~/.graphify/global-graph.json --label "Hawk-Eco Architecture" --output "$HAWK_GRAPH/global/global-arch.html" -echo "Done. Refresh browser to see updates." \ No newline at end of file +echo "Done. Refresh browser to see updates." diff --git a/server.js b/server.js index 0719005..c3992a8 100755 --- a/server.js +++ b/server.js @@ -19,7 +19,7 @@ const MIME = { const REPOS = [ 'eyrie', 'graycode-core', 'hawk', 'hawk-cloud', 'hawk-community-skills', 'hawk-core-contracts', 'hawk-mcpkit', 'hawk-sdk-go', 'hawk-sdk-python', - 'inspect', 'sight', 'tok', 'trace', 'yaad' + 'hawk-sdk-typescript', 'inspect', 'sight', 'tok', 'trace', 'yaad' ]; const DARK_CSS = ` From 70b5383664cad21719f4a57c3a6ead440e96ba5f Mon Sep 17 00:00:00 2001 From: Lakshman Patel Date: Sat, 25 Jul 2026 13:06:10 +0530 Subject: [PATCH 4/4] feat: add graph visualization utilities - Add GraphVisualizer with D3 and Cytoscape.js support - Implement force-directed layout simulation - Add SVG generation and customizable styling --- scripts/graph-visualizer.js | 263 ++++++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 scripts/graph-visualizer.js diff --git a/scripts/graph-visualizer.js b/scripts/graph-visualizer.js new file mode 100644 index 0000000..fa02be7 --- /dev/null +++ b/scripts/graph-visualizer.js @@ -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; +} + +/** + * 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; + nodeSizes: Record; + edgeColors: Record; + 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 = {}) { + 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 ` +${node.label}`; + }).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 ``; + }).join('\n'); + + return ` + + ${links} + ${nodes} +`; + } +}