From 687e210c83679ffa35d8a2d57c38ec31f0f204f2 Mon Sep 17 00:00:00 2001 From: Joseph Mearman Date: Sat, 10 Oct 2026 22:28:36 +0100 Subject: [PATCH 01/31] feat: add graph-cli package The process-graph command line as a composition root over the other packages: sync from GitHub issues into the SQLite store through sqlite-node, then ready, blocked, impact, path, cycles, handoffs and why over the stored model, show for every view in Mermaid, DOT or the projection as JSON, add and set to author a model and its run state, and validate for the stored model or a model document. runCli takes injected ports (output streams, store opener, sources by prefix, file reads, facts and an abort signal) and resolves with an exit status, so the whole command surface runs in tests and inside a host such as Switchboard without a process; nodePorts wires the real ones, with the GitHub token from the adapter's environment helper. Each command's operation returns plain data, every command writes JSON with --json, and exit statuses separate usage errors, missing identifiers, invalid models and source refusals. A sync merges every page into the model in one write; when a source fails part way the pages already read are saved and the error prints the command that resumes with --after. --- README.md | 1 + knip.config.ts | 3 +- packages/targets/graph-cli/AGENTS.md | 1 + packages/targets/graph-cli/CLAUDE.md | 1 + packages/targets/graph-cli/README.md | 101 +++ packages/targets/graph-cli/eslint.config.ts | 10 + packages/targets/graph-cli/package.json | 86 +++ packages/targets/graph-cli/src/bin.ts | 7 + .../graph-cli/src/cli-authoring.unit.test.ts | 552 +++++++++++++++ .../targets/graph-cli/src/cli.unit.test.ts | 296 ++++++++ packages/targets/graph-cli/src/edit.ts | 106 +++ packages/targets/graph-cli/src/emit/dot.ts | 275 ++++++++ .../graph-cli/src/emit/emit.unit.test.ts | 279 ++++++++ .../targets/graph-cli/src/emit/mermaid.ts | 233 +++++++ packages/targets/graph-cli/src/emit/text.ts | 47 ++ packages/targets/graph-cli/src/errors.ts | 116 ++++ packages/targets/graph-cli/src/exit-codes.ts | 21 + packages/targets/graph-cli/src/index.ts | 82 +++ packages/targets/graph-cli/src/node.ts | 173 +++++ packages/targets/graph-cli/src/ports.ts | 43 ++ packages/targets/graph-cli/src/program.ts | 633 ++++++++++++++++++ packages/targets/graph-cli/src/queries.ts | 215 ++++++ packages/targets/graph-cli/src/render.ts | 142 ++++ packages/targets/graph-cli/src/session.ts | 121 ++++ packages/targets/graph-cli/src/show.ts | 222 ++++++ packages/targets/graph-cli/src/sync.ts | 175 +++++ .../graph-cli/src/test-support/fixtures.ts | 90 +++ .../graph-cli/src/test-support/harness.ts | 115 ++++ packages/targets/graph-cli/src/validate.ts | 88 +++ packages/targets/graph-cli/stryker.config.ts | 3 + .../graph-cli/test/package.smoke.test.ts | 64 ++ .../targets/graph-cli/tsconfig.build.json | 37 + packages/targets/graph-cli/tsconfig.json | 8 + packages/targets/graph-cli/vitest.config.ts | 16 + pnpm-lock.yaml | 64 ++ tsconfig.build.json | 3 + 36 files changed, 4428 insertions(+), 1 deletion(-) create mode 120000 packages/targets/graph-cli/AGENTS.md create mode 120000 packages/targets/graph-cli/CLAUDE.md create mode 100644 packages/targets/graph-cli/README.md create mode 100644 packages/targets/graph-cli/eslint.config.ts create mode 100644 packages/targets/graph-cli/package.json create mode 100644 packages/targets/graph-cli/src/bin.ts create mode 100644 packages/targets/graph-cli/src/cli-authoring.unit.test.ts create mode 100644 packages/targets/graph-cli/src/cli.unit.test.ts create mode 100644 packages/targets/graph-cli/src/edit.ts create mode 100644 packages/targets/graph-cli/src/emit/dot.ts create mode 100644 packages/targets/graph-cli/src/emit/emit.unit.test.ts create mode 100644 packages/targets/graph-cli/src/emit/mermaid.ts create mode 100644 packages/targets/graph-cli/src/emit/text.ts create mode 100644 packages/targets/graph-cli/src/errors.ts create mode 100644 packages/targets/graph-cli/src/exit-codes.ts create mode 100644 packages/targets/graph-cli/src/index.ts create mode 100644 packages/targets/graph-cli/src/node.ts create mode 100644 packages/targets/graph-cli/src/ports.ts create mode 100644 packages/targets/graph-cli/src/program.ts create mode 100644 packages/targets/graph-cli/src/queries.ts create mode 100644 packages/targets/graph-cli/src/render.ts create mode 100644 packages/targets/graph-cli/src/session.ts create mode 100644 packages/targets/graph-cli/src/show.ts create mode 100644 packages/targets/graph-cli/src/sync.ts create mode 100644 packages/targets/graph-cli/src/test-support/fixtures.ts create mode 100644 packages/targets/graph-cli/src/test-support/harness.ts create mode 100644 packages/targets/graph-cli/src/validate.ts create mode 100644 packages/targets/graph-cli/stryker.config.ts create mode 100644 packages/targets/graph-cli/test/package.smoke.test.ts create mode 100644 packages/targets/graph-cli/tsconfig.build.json create mode 100644 packages/targets/graph-cli/tsconfig.json create mode 100644 packages/targets/graph-cli/vitest.config.ts diff --git a/README.md b/README.md index cea1db8..c85d40a 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ Configuration lives at exactly one of two levels: in the package (`eslint.config | [`graph-react`](packages/ui/graph/react/README.md) | Headless React hooks and unstyled components: follow a stored model, derive statuses, the ready set, blocked chains, impact and explanations, project views, filter, select and navigate by keyboard. | | [`graph-ui`](packages/ui/graph/ui/README.md) | Styled components over `graph-react` and an SVG sequence diagram, in Vanilla Extract with a typed theme contract and light and dark themes, shipped as compiled CSS. | | [`graph-react-flow`](packages/ui/graph/react-flow/README.md) | React Flow views of the model: flowchart, swimlane with lanes as group nodes, and state machine, laid out by `graph-layout`, showing each status and the critical path; sequence projections drawn by `graph-ui`. | +| [`graph-cli`](packages/targets/graph-cli/README.md) | The command line and its library entry: sync GitHub issues into the SQLite store, ready, blocked, impact, critical path, cycles, hand-offs and status explanations, and every view drawn in Mermaid or Graphviz DOT. | | [`process-graph`](packages/targets/process-graph/README.md) | The primary entry point: re-exports the schema, projection and domain APIs flat and the DAG API as the `dag` namespace. | | [`graph-web`](packages/targets/graph-web/README.md) | The web app: an installable, offline-first PWA that syncs GitHub issues into SQLite on the device and shows the work in every view, with what is ready, what is blocked and why, linkable by address. | diff --git a/knip.config.ts b/knip.config.ts index ae5b090..1224d3a 100644 --- a/knip.config.ts +++ b/knip.config.ts @@ -29,7 +29,8 @@ const config: KnipConfig = { project: ["src/**/*.{ts,tsx}!"], }, "packages/targets/*": { - entry: ["src/index.{ts,tsx}"], + // A target's bin is an entry point of its own, run as a process rather than imported. + entry: ["src/index.{ts,tsx}", "src/bin.ts"], project: ["src/**/*.{ts,tsx}!"], }, // An app rather than a library: knip's Vite plugin finds the page's module from index.html; the store's worker, which main.tsx starts by URL, the build script and the Playwright suite are entries of their own. diff --git a/packages/targets/graph-cli/AGENTS.md b/packages/targets/graph-cli/AGENTS.md new file mode 120000 index 0000000..42061c0 --- /dev/null +++ b/packages/targets/graph-cli/AGENTS.md @@ -0,0 +1 @@ +README.md \ No newline at end of file diff --git a/packages/targets/graph-cli/CLAUDE.md b/packages/targets/graph-cli/CLAUDE.md new file mode 120000 index 0000000..42061c0 --- /dev/null +++ b/packages/targets/graph-cli/CLAUDE.md @@ -0,0 +1 @@ +README.md \ No newline at end of file diff --git a/packages/targets/graph-cli/README.md b/packages/targets/graph-cli/README.md new file mode 100644 index 0000000..a1fcdbf --- /dev/null +++ b/packages/targets/graph-cli/README.md @@ -0,0 +1,101 @@ +# @exadev/process-graph-cli + +[![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://github.com/ExaDev/process-graph) [![npm](https://img.shields.io/badge/npm-CB3837?logo=npm&logoColor=white)](https://www.npmjs.com/package/@exadev/process-graph-cli) [![Release](https://img.shields.io/github/v/release/ExaDev/process-graph)](https://github.com/ExaDev/process-graph/releases/latest) [![CI](https://img.shields.io/github/actions/workflow/status/ExaDev/process-graph/ci.yml?branch=main)](https://github.com/ExaDev/process-graph/actions) + +The process-graph command line, and the same commands as a library. It syncs work from GitHub issues into a SQLite store, answers what is ready, blocked, affected, on the critical path or handed off between owners, explains why an element has its status, builds and edits a model by hand, and draws the model as a flowchart, swimlane, state machine or sequence diagram in Mermaid or Graphviz DOT. + +It is a composition root and nothing else: the model, reasoning, projections, sources and store are the other packages of this repository, and this package wires them to a command line through injected ports. The unscoped [`process-graph`](../process-graph/README.md) package carries the same command line as its `process-graph` bin; this package's own bin is `process-graph-cli`. + +```sh +process-graph sync github:ExaDev github:Mearman/agent-permissions +process-graph ready +process-graph why github:ExaDev/process-graph#12 +process-graph show --view swimlane --format mermaid +``` + +## Commands + +| Command | What it does | +| ------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| `sync [--after ]` | Reads the scopes from their sources and merges them into the model in one write; prints what it wrote and any gaps. | +| `ready` | The work that can start now. | +| `blocked ` | The open work an element is waiting on: the ends of its blocked-by chain. | +| `impact ` | The live work that depends on an element. | +| `path` | The critical path: the longest chain of work still ahead, each element counting one step. | +| `cycles` | The cycles no decision closes. | +| `handoffs` | The transitions from one actor's work to another's, such as a dependency across repositories or organisations. | +| `why ` | The rule that decided an element's status, its needs and artefacts, and the blocked-by chain behind it. | +| `show [--view ] [--format ]` | Draws the model. Views: `flowchart` (default), `swimlane`, `state`, `sequence`. Formats: `mermaid` (default), `dot`, `json` (the projection itself). | +| `add participant