From b33668ef0586cc66416a12a1e383ad620afa1742 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 16 Jun 2026 21:11:09 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20order=20module-graph=20table=20topo?= =?UTF-8?q?logically=20(low=E2=86=92high=20level)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the alphabetical package ordering with a Kahn-style topological sort (alphabetical tiebreak within each layer to stay deterministic), so the table and graph list leaf interfaces first and dependents last. --- docs/module-graph.md | 32 ++++++++++++++++---------------- scripts/gen-module-graph.ts | 27 ++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/docs/module-graph.md b/docs/module-graph.md index 4caee085f4..e488f61ea1 100644 --- a/docs/module-graph.md +++ b/docs/module-graph.md @@ -9,41 +9,41 @@ package `a` depends on package `b`. Names have the `@deepseek-ai/dsh-` prefix st ```mermaid graph TD + bash-local --> bash + llm-deepseek --> llm + llm-pi-ai --> llm + session --> llm + system-prompt --> llm agent --> llm agent --> session + invariants --> agent + invariants --> llm + invariants --> session + tools --> agent + tools --> llm + tools --> system-prompt agent-loop --> agent agent-loop --> llm agent-loop --> session agent-loop --> system-prompt agent-loop --> tools - bash-local --> bash - invariants --> agent - invariants --> llm - invariants --> session - llm-deepseek --> llm - llm-pi-ai --> llm - session --> llm - system-prompt --> llm tool-bash --> agent tool-bash --> bash tool-bash --> llm tool-bash --> tools - tools --> agent - tools --> llm - tools --> system-prompt ``` | Package | Depends on | | --- | --- | -| `agent` | `llm`, `session` | -| `agent-loop` | `agent`, `llm`, `session`, `system-prompt`, `tools` | | `bash` | — | -| `bash-local` | `bash` | -| `invariants` | `agent`, `llm`, `session` | | `llm` | — | +| `bash-local` | `bash` | | `llm-deepseek` | `llm` | | `llm-pi-ai` | `llm` | | `session` | `llm` | | `system-prompt` | `llm` | -| `tool-bash` | `agent`, `bash`, `llm`, `tools` | +| `agent` | `llm`, `session` | +| `invariants` | `agent`, `llm`, `session` | | `tools` | `agent`, `llm`, `system-prompt` | +| `agent-loop` | `agent`, `llm`, `session`, `system-prompt`, `tools` | +| `tool-bash` | `agent`, `bash`, `llm`, `tools` | diff --git a/scripts/gen-module-graph.ts b/scripts/gen-module-graph.ts index 58e8bd0a36..865211ccde 100644 --- a/scripts/gen-module-graph.ts +++ b/scripts/gen-module-graph.ts @@ -46,7 +46,32 @@ function collect(): Pkg[] { .sort() pkgs.push({ short: json.name.slice(SCOPE.length), deps }) } - return pkgs.sort((a, b) => a.short.localeCompare(b.short)) + return topoSort(pkgs) +} + +/** + * Order packages low-level → high-level: a package appears only after every + * package it depends on. Kahn-style layering with an alphabetical tiebreak + * within each layer, so the output stays deterministic (the freshness check + * compares whole-file). The graph is a DAG, so this always terminates; a cycle + * would leave nodes unplaced and throw. + */ +function topoSort(pkgs: Pkg[]): Pkg[] { + const remaining = new Map(pkgs.map(p => [p.short, p])) + const placed = new Set() + const out: Pkg[] = [] + while (remaining.size > 0) { + const ready = [...remaining.values()] + .filter(p => p.deps.every(d => placed.has(d))) + .sort((a, b) => a.short.localeCompare(b.short)) + if (ready.length === 0) throw new Error(`gen-module-graph: dependency cycle among ${[...remaining.keys()].join(', ')}`) + for (const p of ready) { + out.push(p) + placed.add(p.short) + remaining.delete(p.short) + } + } + return out } /** Render the full docs/module-graph.md content (pure, deterministic). */