mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
# Conflicts: # docs/config-catalog.md # docs/development.i18n.yaml # docs/development.zh.md # docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.md # docs/rfc/implemented/feature/2026-07-06-sandbox.md # examples/AGENTS.md # examples/README.md # examples/acp-agent/README.md # examples/acp-agent/cordis.yml # examples/acp-agent/tests/acp.e2e.ts # examples/acp-agent/tests/escalation.e2e.ts # examples/sandbox-acp-agent/README.md # examples/sandbox-acp-agent/cordis.snapshot.yml # examples/sandbox-acp-agent/cordis.yml # examples/sandbox-acp-agent/tests/acp.snapshot.ts # packages/ui/acp-agent/src/bin.ts # packages/ui/acp/README.md # packages/ui/jsonrpc-agent/README.md # packages/ui/jsonrpc-agent/src/bin.ts # scripts/verify-translation-pairing.ts
115 lines
3.6 KiB
TypeScript
115 lines
3.6 KiB
TypeScript
/**
|
|
* Generate `docs/module-graph.md` from in-repo `peerDependencies`, the canonical
|
|
* runtime edges. The deterministic output groups packages by directory and
|
|
* renders both Mermaid and a dependency table; `--check` verifies freshness.
|
|
*/
|
|
|
|
import { resolve } from 'node:path'
|
|
import { readFileSync, writeFileSync } from 'node:fs'
|
|
import {
|
|
collectPackageGraph,
|
|
escapeMermaidLabel as escLabel,
|
|
graphNodeId as nodeId,
|
|
type PackageGraphNode,
|
|
} from './package-graph.ts'
|
|
|
|
const root = resolve(import.meta.dirname, '..')
|
|
const OUT = 'docs/module-graph.md'
|
|
type Pkg = PackageGraphNode
|
|
|
|
const GROUP_ORDER = [
|
|
'util',
|
|
'llm',
|
|
'core',
|
|
'bash',
|
|
'fs',
|
|
'skill',
|
|
'compact',
|
|
'subagent',
|
|
'web',
|
|
'timeout',
|
|
'todo',
|
|
'cordis',
|
|
'hooks',
|
|
'session-persistence',
|
|
'session-query',
|
|
'support',
|
|
'ui',
|
|
]
|
|
|
|
function packageLink(pkg: Pkg): string {
|
|
return `[\`${pkg.short}\`](../${pkg.rel})`
|
|
}
|
|
|
|
/** Render the full docs/module-graph.md content (pure, deterministic). */
|
|
function render(pkgs: Pkg[]): string {
|
|
const edges: string[] = []
|
|
for (const p of pkgs) {
|
|
for (const d of p.deps) edges.push(` ${nodeId('pkg', p.short)} --> ${nodeId('pkg', d)}`)
|
|
}
|
|
const byShort = new Map(pkgs.map(pkg => [pkg.short, pkg]))
|
|
const groups = [...new Set(pkgs.map(pkg => pkg.group))].sort((a, b) => {
|
|
const ia = GROUP_ORDER.indexOf(a)
|
|
const ib = GROUP_ORDER.indexOf(b)
|
|
const na = ia === -1 ? Number.MAX_SAFE_INTEGER : ia
|
|
const nb = ib === -1 ? Number.MAX_SAFE_INTEGER : ib
|
|
return na - nb || a.localeCompare(b)
|
|
})
|
|
const groupBlocks: string[] = []
|
|
for (const group of groups) {
|
|
groupBlocks.push(` subgraph ${nodeId('group', group)}["packages/${escLabel(group)}"]`)
|
|
for (const pkg of pkgs.filter(p => p.group === group).sort((a, b) => a.short.localeCompare(b.short))) {
|
|
groupBlocks.push(` ${nodeId('pkg', pkg.short)}["${escLabel(pkg.short)}"]`)
|
|
}
|
|
groupBlocks.push(' end')
|
|
}
|
|
const rows = pkgs.map((p) => {
|
|
const deps = p.deps.length ? p.deps.map((d) => {
|
|
const dep = byShort.get(d)
|
|
return dep ? packageLink(dep) : `\`${d}\``
|
|
}).join(', ') : '—'
|
|
return `| ${packageLink(p)} | \`${p.group}\` | ${deps} |`
|
|
})
|
|
return [
|
|
'<!-- Generated by scripts/gen-module-graph.ts — do not edit by hand.',
|
|
' Run `pnpm run gen-module-graph` to regenerate. -->',
|
|
'',
|
|
'# Module dependency graph',
|
|
'',
|
|
'Inter-package dependencies among the `@deepseek-ai/dsh-*` harness packages, derived from each package\'s `peerDependencies` (the canonical runtime-dependency signal) and grouped by the `packages/<group>/<pkg>` hierarchy. An edge `a --> b` means package `a` depends on package `b`. Names have the `@deepseek-ai/dsh-` prefix stripped.',
|
|
'',
|
|
'```mermaid',
|
|
'flowchart TD',
|
|
...groupBlocks,
|
|
...edges,
|
|
'```',
|
|
'',
|
|
'| Package | Group | Depends on |',
|
|
'| --- | --- | --- |',
|
|
...rows,
|
|
'',
|
|
].join('\n')
|
|
}
|
|
|
|
const content = render(collectPackageGraph(root, GROUP_ORDER, 'gen-module-graph'))
|
|
|
|
if (process.argv.includes('--check')) {
|
|
let committed: string | null = null
|
|
try {
|
|
committed = readFileSync(resolve(root, OUT), 'utf8')
|
|
} catch {
|
|
// A missing artifact is the expected read failure. Any read failure has the
|
|
// same remedy here—regenerate—so it is reported as stale below.
|
|
committed = null
|
|
}
|
|
if (committed === content) {
|
|
console.log(`gen-module-graph: ${OUT} is up to date.`)
|
|
process.exit(0)
|
|
}
|
|
console.error(`gen-module-graph: ${OUT} is stale. Run \`pnpm run gen-module-graph\` and commit ${OUT}.`)
|
|
process.exit(1)
|
|
}
|
|
|
|
writeFileSync(resolve(root, OUT), content)
|
|
console.log(`gen-module-graph: wrote ${OUT}.`)
|