singularity-forge/src/help-text.ts
Nils Reeh 15bccca78f feat(graph): implement knowledge graph system (closes #4202)
Ports the v1 graphify system to v2 as a native TypeScript implementation.
The knowledge graph builds semantic relationships between milestones, slices,
tasks, and knowledge entries — and injects relevant subgraphs automatically
into every agent dispatch prompt.

## Core implementation (packages/mcp-server/src/readers/graph.ts)

- `buildGraph(projectDir)` — walks all .gsd/ artifacts (STATE.md,
  milestone PLANs, slice PLANs, KNOWLEDGE.md), extracts nodes and edges
  with confidence tiers (EXTRACTED / INFERRED / AMBIGUOUS). Parse errors
  skip the node rather than crashing.
- `writeGraph(gsdRoot, graph)` — atomic write via tmp file + rename.
- `writeSnapshot(gsdRoot)` — saves a diff baseline before each rebuild.
- `graphQuery(projectDir, term, budget?)` — BFS subgraph search with
  case-insensitive matching on label + description; trims AMBIGUOUS edges
  first, then INFERRED, respecting the token budget (default 4 000).
- `graphStatus(projectDir)` — freshness check; stale = older than 24 h.
- `graphDiff(projectDir)` — compares current graph to last snapshot,
  returns added / removed / changed counts for nodes and edges.

## MCP tool (packages/mcp-server/src/server.ts)

Registers `gsd_graph` immediately after `gsd_knowledge` with four modes:
build | query | status | diff. All errors returned as isError: true.

## CLI subcommand (src/cli.ts, src/help-text.ts)

`gsd graph build|status|query <term>|diff` — follows the established
`if (cliFlags.messages[0] === '...')` dispatch pattern. Uses
`resolveGsdRoot()` for git-root-aware path resolution (not a naive
`.gsd` append). Help text updated with correct positional argument format.

## Auto-rebuild after slice completion
(src/resources/extensions/gsd/tools/complete-slice.ts)

Fire-and-forget `buildGraph → writeGraph` triggered after every slice
completion. Uses `@gsd-build/mcp-server` package import (not a relative
src path) and `resolveGsdRoot()` for correct path resolution in monorepos.

## Graph-aware dispatch injection
(src/resources/extensions/gsd/graph-context.ts,
 src/resources/extensions/gsd/auto-prompts.ts)

`inlineGraphSubgraph(projectDir, term, { budget })` queries the graph and
formats the result as a `### Knowledge Graph Context` markdown block,
consistent with all other inlined context blocks. Adds a stale warning
annotation when the graph is older than 24 h. Returns null (graceful
skip) when graph.json is missing, the query returns zero nodes, or the
import fails — no agent dispatch is ever blocked by graph availability.

Injected into three prompt builders:
- `buildResearchSlicePrompt` — 3 000 token budget
- `buildPlanSlicePrompt`     — 3 000 token budget
- `buildExecuteTaskPrompt`   — 2 000 token budget

## Tests

- 22 tests for the core graph reader (graph.test.ts)
- 14 tests for the dispatch injection helper (graph-context.test.ts)
- All tests use real on-disk fixtures (no module mocking needed)
- Full suite: 6 318 passed, 0 failed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 02:20:49 +02:00

210 lines
10 KiB
TypeScript

const SUBCOMMAND_HELP: Record<string, string> = {
config: [
'Usage: gsd config',
'',
'Re-run the interactive setup wizard to configure:',
' - LLM provider (Anthropic, OpenAI, Google, OpenRouter, Ollama, LM Studio, etc.)',
' - Web search provider (Brave, Tavily, built-in)',
' - Remote questions (Discord, Slack, Telegram)',
' - Tool API keys (Context7, Jina, Groq)',
'',
'All steps are skippable and can be changed later with /login or /search-provider.',
'',
'For detailed provider setup instructions (OpenRouter, Ollama, LM Studio, vLLM,',
'and other OpenAI-compatible endpoints), see docs/providers.md.',
].join('\n'),
update: [
'Usage: gsd update',
'',
'Update GSD to the latest version.',
'',
'Equivalent to: npm install -g gsd-pi@latest',
].join('\n'),
sessions: [
'Usage: gsd sessions',
'',
'List all saved sessions for the current directory and interactively',
'pick one to resume. Shows date, message count, and a preview of the',
'first message for each session.',
'',
'Sessions are stored per-directory, so you only see sessions that were',
'started from the current working directory.',
'',
'Compare with --continue (-c) which always resumes the most recent session.',
].join('\n'),
install: [
'Usage: gsd install <source> [-l, --local]',
'',
'Install a package/extension source and run post-install validation (dependency checks, setup).',
'',
'Examples:',
' gsd install npm:@foo/bar',
' gsd install git:github.com/user/repo',
' gsd install https://github.com/user/repo',
' gsd install ./local/path',
].join('\n'),
remove: [
'Usage: gsd remove <source> [-l, --local]',
'',
'Remove an installed package source and its settings entry.',
].join('\n'),
list: [
'Usage: gsd list',
'',
'List installed package sources from user and project settings.',
].join('\n'),
worktree: [
'Usage: gsd worktree <command> [args]',
'',
'Manage isolated git worktrees for parallel work streams.',
'',
'Commands:',
' list List worktrees with status (files changed, commits, dirty)',
' merge [name] Squash-merge a worktree into main and clean up',
' clean Remove all worktrees that have been merged or are empty',
' remove <name> Remove a worktree (--force to remove with unmerged changes)',
'',
'The -w flag creates/resumes worktrees for interactive sessions:',
' gsd -w Auto-name a new worktree, or resume the only active one',
' gsd -w my-feature Create or resume a named worktree',
'',
'Lifecycle:',
' 1. gsd -w Create worktree, start session inside it',
' 2. (work normally) All changes happen on the worktree branch',
' 3. Ctrl+C Exit — dirty work is auto-committed',
' 4. gsd -w Resume where you left off',
' 5. gsd worktree merge Squash-merge into main when done',
'',
'Examples:',
' gsd -w Start in a new auto-named worktree',
' gsd -w auth-refactor Create/resume "auth-refactor" worktree',
' gsd worktree list See all worktrees and their status',
' gsd worktree merge auth-refactor Merge and clean up',
' gsd worktree clean Remove all merged/empty worktrees',
' gsd worktree remove old-branch Remove a specific worktree',
' gsd worktree remove old-branch --force Remove even with unmerged changes',
].join('\n'),
graph: [
'Usage: gsd graph <subcommand> [options]',
'',
'Manage the GSD project knowledge graph. Reads .gsd/ artifacts and builds',
'a queryable graph of milestones, slices, tasks, rules, patterns, and lessons.',
'',
'Subcommands:',
' build Parse .gsd/ artifacts (STATE.md, milestone ROADMAPs, slice PLANs,',
' KNOWLEDGE.md) and write .gsd/graphs/graph.json atomically.',
' query Search graph nodes by term (BFS from seed matches, budget-trimmed).',
' Returns matching nodes and reachable edges within the token budget.',
' status Show whether graph.json exists, its age, node/edge counts, and',
' whether it is stale (built more than 24 hours ago).',
' diff Compare current graph.json with .last-build-snapshot.json.',
' Returns added, removed, and changed nodes and edges.',
'',
'Examples:',
' gsd graph build Build the graph from .gsd/ artifacts',
' gsd graph status Check graph age and node/edge counts',
' gsd graph query auth Find nodes related to "auth"',
' gsd graph diff Show changes since last snapshot',
].join('\n'),
headless: [
'Usage: gsd headless [flags] [command] [args...]',
'',
'Run /gsd commands without the TUI. Default command: auto',
'',
'Flags:',
' --timeout N Overall timeout in ms (default: 300000)',
' --json JSONL event stream to stdout (alias for --output-format stream-json)',
' --output-format <fmt> Output format: text (default), json (structured result), stream-json (JSONL events)',
' --bare Minimal context: skip CLAUDE.md, AGENTS.md, user settings, user skills',
' --resume <id> Resume a prior headless session by ID',
' --model ID Override model',
' --supervised Forward interactive UI requests to orchestrator via stdout/stdin',
' --response-timeout N Timeout (ms) for orchestrator response (default: 30000)',
' --answers <path> Pre-supply answers and secrets (JSON file)',
' --events <types> Filter JSONL output to specific event types (comma-separated)',
'',
'Commands:',
' auto Run all queued units continuously (default)',
' next Run one unit',
' status Show progress dashboard',
' new-milestone Create a milestone from a specification document',
' query JSON snapshot: state + next dispatch + costs (no LLM)',
'',
'new-milestone flags:',
' --context <path> Path to spec/PRD file (use \'-\' for stdin)',
' --context-text <txt> Inline specification text',
' --auto Start auto-mode after milestone creation',
' --verbose Show tool calls in progress output',
'',
'Output formats:',
' text Human-readable progress on stderr (default)',
' json Collect events silently, emit structured HeadlessJsonResult on stdout at exit',
' stream-json Stream JSONL events to stdout in real time (same as --json)',
'',
'Examples:',
' gsd headless Run /gsd auto',
' gsd headless next Run one unit',
' gsd headless --output-format json auto Structured JSON result on stdout',
' gsd headless --json status Machine-readable JSONL stream',
' gsd headless --timeout 60000 With 1-minute timeout',
' gsd headless --bare auto Minimal context (CI/ecosystem use)',
' gsd headless --resume abc123 auto Resume a prior session',
' gsd headless new-milestone --context spec.md Create milestone from file',
' cat spec.md | gsd headless new-milestone --context - From stdin',
' gsd headless new-milestone --context spec.md --auto Create + auto-execute',
' gsd headless --supervised auto Supervised orchestrator mode',
' gsd headless --answers answers.json auto With pre-supplied answers',
' gsd headless --events agent_end,extension_ui_request auto Filtered event stream',
' gsd headless query Instant JSON state snapshot',
'',
'Exit codes: 0 = success, 1 = error/timeout, 10 = blocked, 11 = cancelled',
].join('\n'),
}
// Alias: `gsd wt --help` → same as `gsd worktree --help`
SUBCOMMAND_HELP['wt'] = SUBCOMMAND_HELP['worktree']
export function printHelp(version: string): void {
process.stdout.write(`GSD v${version} — Get Shit Done\n\n`)
process.stdout.write('Usage: gsd [options] [message...]\n\n')
process.stdout.write('Options:\n')
process.stdout.write(' --mode <text|json|rpc|mcp> Output mode (default: interactive)\n')
process.stdout.write(' --print, -p Single-shot print mode\n')
process.stdout.write(' --continue, -c Resume the most recent session\n')
process.stdout.write(' --worktree, -w [name] Start in an isolated worktree (auto-named if omitted)\n')
process.stdout.write(' --model <id> Override model (e.g. provider/model-id)\n')
process.stdout.write(' --no-session Disable session persistence\n')
process.stdout.write(' --extension <path> Load additional extension\n')
process.stdout.write(' --tools <a,b,c> Restrict available tools\n')
process.stdout.write(' --list-models [search] List available models and exit\n')
process.stdout.write(' --version, -v Print version and exit\n')
process.stdout.write(' --help, -h Print this help and exit\n')
process.stdout.write('\nSubcommands:\n')
process.stdout.write(' config Re-run the setup wizard\n')
process.stdout.write(' install <source> Install a package/extension source\n')
process.stdout.write(' remove <source> Remove an installed package source\n')
process.stdout.write(' list List installed package sources\n')
process.stdout.write(' update Update GSD to the latest version\n')
process.stdout.write(' sessions List and resume a past session\n')
process.stdout.write(' worktree <cmd> Manage worktrees (list, merge, clean, remove)\n')
process.stdout.write(' auto [args] Run auto-mode without TUI (pipeable)\n')
process.stdout.write(' headless [cmd] [args] Run /gsd commands without TUI (default: auto)\n')
process.stdout.write(' graph <subcommand> Manage knowledge graph (build, query, status, diff)\n')
process.stdout.write('\nRun gsd <subcommand> --help for subcommand-specific help.\n')
}
export function printSubcommandHelp(subcommand: string, version: string): boolean {
const help = SUBCOMMAND_HELP[subcommand]
if (!help) return false
process.stdout.write(`GSD v${version} — Get Shit Done\n\n`)
process.stdout.write(help + '\n')
return true
}