diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 92d0c8d..cb281b6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,43 +2,32 @@ ## Adding a package +A new package is private and reaches consumers through a subpath of the published `process-graph` package, which bundles it. It needs no name on npm and no trusted publisher. + 1. Pick the layer: `packages/core//` for the model, its analysis and ports; `packages/adapters//` for an implementation of a port against one external system; `packages/ui//` for components; `packages/targets/` (flat) for a deployable entry point. 2. Copy the closest existing package's shape: `package.json` (`exports` map, script set), `tsconfig.json` plus `tsconfig.build.json` (and `tsconfig.node.json` for an isomorphic package), `eslint.config.ts`, `vitest.config.ts`, `stryker.config.ts`, `test/package.smoke.test.ts`. -3. Name it `@exadev/process-graph-` and pin every internal dependency exact (`syncpack lint` enforces it). `workspace:` ranges are not used. -4. Add its `tsconfig.build.json` to the root `tsconfig.build.json` `references`. -5. If it is the first package in its layer, add that layer's workspace entry to `knip.config.ts` (an entry that matches nothing is a knip hint). -6. Write its `README.md`, then `ln -s README.md AGENTS.md && ln -s README.md CLAUDE.md`. -7. Add it to the packages table in the root `README.md`, and to the Dependabot `ignore` list only if its name does not already match `@exadev/process-graph-*`. -8. Give the manifest what the release orchestrator needs (see [Release strategy](#release-strategy)): `version` `0.0.0`, `repository.directory` set to the package's path, `publishConfig` with `access`, `provenance` and the registry as in its siblings, and each sibling dependency as the sibling's exact version. -9. Reserve the name on npm and register its trusted publisher before its first releasable commit reaches `main` (see [Bootstrapping a package name](#bootstrapping-a-package-name)). +3. Name it `@exadev/process-graph-`, mark it `"private": true`, and set `version` to `0.0.0` and `repository.directory` to the package's path. Give it no `publishConfig`. +4. Add dependencies with pnpm: a sibling as `workspace:*` (`pnpm add @exadev/process-graph-@workspace:*`), and a third-party library from the catalog in `pnpm-workspace.yaml` (`pnpm add --save-catalog @`, which adds the catalog entry when there is none). `pnpm run deps:lint` rejects anything else. +5. Add its `tsconfig.build.json` to the root `tsconfig.build.json` `references`. +6. If it is the first package in its layer, add that layer's workspace entry to `knip.config.ts` (an entry that matches nothing is a knip hint). +7. Expose it through `process-graph`, in `packages/targets/process-graph`: a module under `src/` that re-exports it, named for the subpath (`src/.ts`), an entry for that module in `tsdown.config.ts`, the subpath in the `exports` map, the module in the subpath list in `eslint.config.ts`, a case in `src/entrypoints.unit.test.ts` and an import of the subpath in `test/package.smoke.test.ts`. Add the package to `devDependencies` at its exact version (`pnpm add -D --save-exact @exadev/process-graph-@`), never `workspace:*`, since that manifest is published as written. Each third-party library the new subpath needs that the root entry does not goes in `peerDependencies`, marked optional in `peerDependenciesMeta`, at the catalog's exact version (`pnpm add --save-peer --save-exact @`). Where a layer's names collide with another layer's on the same subpath, namespace one layer rather than shadow a name. +8. Write its `README.md`, then `ln -s README.md AGENTS.md && ln -s README.md CLAUDE.md`. +9. Add it to the internal packages table in the root `README.md`, and the subpath to the `process-graph` README. 10. Verify with the repository scripts: `pnpm lint`, `pnpm typecheck`, `pnpm test`, `pnpm test:smoke`, `pnpm exec knip`, `pnpm run deps:lint`. 11. Commit as `feat: add package`, describing the package's role and any deliberate decision, not the process that produced it. ## Release strategy -Every publishable package versions and publishes on its own. `release-workspace.config.ts` configures [`@exadev/semantic-release-workspace`](https://github.com/ExaDev/semantic-release-workspace), which the `release` job in `.github/workflows/ci.yml` runs as `pnpm release` on every push to `main` once the other jobs have passed. +Only `process-graph` is published. `release-workspace.config.ts` configures [`@exadev/semantic-release-workspace`](https://github.com/ExaDev/semantic-release-workspace), which the `release` job in `.github/workflows/ci.yml` runs as `pnpm release` on every push to `main` once the other jobs have passed. -- The orchestrator discovers the packages from `pnpm-workspace.yaml`, orders them by their dependencies on one another and releases each after every sibling it depends on, so the `process-graph` entry point is released after the building-block packages it re-exports. +- The orchestrator discovers the packages from `pnpm-workspace.yaml`, orders them by their dependencies on one another, `devDependencies` included, and releases each after every sibling it depends on, so `process-graph` is released after every package it bundles. - A package's release is decided from the commits that touched its own directory, using the types and release levels in `commit-types.ts`. A commit that touches no package directory releases nothing, and a commit scope has no effect on which package releases. -- Each release is a `@` tag, a package-level `CHANGELOG.md` and a GitHub Release. The whole run's version bumps, changelog entries and dependency-range rewrites are committed once and pushed atomically with the tags before anything is published. -- When a package releases, every dependent's sibling range is rewritten to the new version, the lockfile is regenerated and the dependent releases a patch even if nothing else about it changed, so a published manifest never names a version the repository has moved past. Sibling dependencies are exact versions rather than the `workspace:` protocol for this reason: `npm publish` ships a specifier as written. -- Publishing uses npm trusted publishing (OIDC): `id-token: write` on the job, no `NPM_TOKEN`, and no `registry-url` on `setup-node`, because that writes a token line that wins over the OIDC exchange. +- Every package gets a `@` tag, which the orchestrator reads to find its last release. A private package gets nothing else: it runs only `@semantic-release/npm`, which bumps its version and skips publishing because the manifest is private, so it writes no `CHANGELOG.md` and creates no GitHub Release. `process-graph` gets its `CHANGELOG.md`, its GitHub Release and its npm publish. +- When a package releases, every dependent's range on it is rewritten to the new version where the range names one, the lockfile is regenerated, and the dependent releases a patch even if nothing else about it changed. `process-graph` names each bundled package's exact version in `devDependencies`, so a change confined to a private package's directory still releases `process-graph`, as a patch, carrying the new bundle. A feature in a private package therefore reaches consumers in a `process-graph` patch release unless a commit touching `process-graph` itself says otherwise. +- The whole run's version bumps, changelog entries and dependency-range rewrites are committed once and pushed atomically with the tags before anything is published. +- Publishing uses npm trusted publishing (OIDC): `id-token: write` on the job, no `NPM_TOKEN`, and no `registry-url` on `setup-node`, because that writes a token line that wins over the OIDC exchange. `@semantic-release/npm` publishes with `npm publish`, which ships every specifier as written, which is why the `process-graph` manifest uses literal versions where the private ones use `catalog:` and `workspace:*`. - The release commit and tags reach the protected `main` through a repository deploy key with write access (the `RELEASE_DEPLOY_KEY` secret), which the `main` ruleset lists as a bypass actor; `GITHUB_TOKEN` cannot bypass a ruleset. The `release` job checks out without persisting a credential, writes the key to the runner's temporary directory only in the step before the release, and removes it afterwards. The orchestrator pushes with plain `git push origin`, so the release step rewrites https GitHub URLs to SSH through git's per-process config and sets `GIT_SSH_COMMAND` to use only that key; `GITHUB_TOKEN` stays in that step's environment for the GitHub API calls that create releases and comment on issues and pull requests. Release configuration lives only in `release-workspace.config.ts`. The orchestrator sets the tag format, plugins and analysis options on every per-package run, so a `release.config.*` inside a package would be overridden rather than honoured. To see what a run would do without tagging, committing, pushing or publishing, run `pnpm release --dry-run` from the root on a clean tree and a pushed branch, with `--branches ` naming it and a `GITHUB_TOKEN` in the environment. - -### Bootstrapping a package name - -npm has no trusted publisher settings page for a name that has never been published, so a new package's name is reserved and its trusted publisher registered by a person before CI publishes it for the first time: - -```sh -npm-reserve --trust ExaDev/process-graph --workflow ci.yml -``` - -A first publish from CI under an unregistered name fails the OIDC exchange. The run has already pushed the tag by then, so that version is skipped rather than retried; see the orchestrator's README for recovering from it. - -### Adding a package to releases - -A package joins releases by being a non-private workspace package: no other registration exists. Its manifest carries the fields named in the steps of [Adding a package](#adding-a-package), its first release is `1.0.0` because it has no earlier tag, and a private package is still versioned and tagged but never published. diff --git a/README.md b/README.md index cea1db8..e89b627 100644 --- a/README.md +++ b/README.md @@ -16,12 +16,12 @@ pnpm build pnpm test ``` -Dependencies are added with `pnpm add`, never by editing a version by hand. Every manifest pins exact versions (`syncpack` enforces it), and the install age gate in `pnpm-workspace.yaml` is never lowered; ExaDev's own packages are the only entries in `minimumReleaseAgeExclude`. +Dependencies are added with `pnpm add`, never by editing a version by hand. Every third-party version is written once, exactly, in the catalog in `pnpm-workspace.yaml`: a private package names it as `catalog:` (`pnpm add --save-catalog @`) and a sibling as `workspace:*`. The published `process-graph` manifest names exact literal versions instead, because `npm publish` ships a protocol specifier verbatim; `pnpm run deps:lint` (`syncpack` and `scripts/check-published-manifests.ts`) holds both rules. The install age gate in `pnpm-workspace.yaml` is never lowered; ExaDev's own packages are the only entries in `minimumReleaseAgeExclude`. ## Commands ```sh -pnpm build # tsc -b across the workspace, dependency-ordered +pnpm build # every package, dependency-ordered; process-graph last, bundled by tsdown pnpm lint pnpm lint:fix pnpm typecheck pnpm test pnpm test:coverage pnpm test:smoke pnpm test:mutation pnpm exec knip pnpm run deps:lint @@ -39,12 +39,20 @@ packages/ └── targets// # deployable entry points, deliberately flat ``` -A package may depend on its own layer and the layers below it, never above; `no-uphill-dependency` and `no-dependency-cycle` from `@exadev/eslint-config` enforce it from the manifests, configured in `eslint.shared.ts`. Published names are `@exadev/process-graph-`; the unscoped [`process-graph`](packages/targets/process-graph/README.md) package, in the `targets` layer, is the primary entry point: it re-exports the model, projection, domain and DAG packages so a consumer installs one dependency. +A package may depend on its own layer and the layers below it, never above; `no-uphill-dependency` and `no-dependency-cycle` from `@exadev/eslint-config` enforce it from the manifests, configured in `eslint.shared.ts`. One package is published: the unscoped [`process-graph`](packages/targets/process-graph/README.md), in the `targets` layer. Every other package is private, named `@exadev/process-graph-`, and reaches consumers only bundled into `process-graph` behind one of its subpath exports, so a consumer installs one dependency and imports each part from its own subpath. Configuration lives at exactly one of two levels: in the package (`eslint.config.ts`, `tsconfig*.json`, Vitest projects, Stryker) or at the root (commit rules, git hooks, formatting, release). ## Packages +The published package: + +| Package | What it is | +| ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [`process-graph`](packages/targets/process-graph/README.md) | The one install: the model, projection, domain and DAG APIs at the root entry, layout, the GitHub issues source, the SQLite store for Node and the browser, the React UI and the command line library each behind a subpath, and the `process-graph` bin. | + +The internal packages, private and bundled into `process-graph`: + | Package | What it is | | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`graph-dag`](packages/core/graph/dag/README.md) | Model-independent dependency-graph primitives over a node set and a `needs` accessor: layers, ancestors, descendants, cycles, transitive reduction, critical path. | @@ -61,8 +69,13 @@ 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`. | -| [`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. | +| [`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. | + +The web app, private and not bundled into `process-graph`: + +| Package | What it is | +| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [`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. | ## Conventions @@ -76,12 +89,10 @@ Configuration lives at exactly one of two levels: in the package (`eslint.config ## Releases -Each package versions and publishes independently through [`@exadev/semantic-release-workspace`](https://github.com/ExaDev/semantic-release-workspace), configured in `release-workspace.config.ts` and run by the `release` job in CI. A package releases when commits touch its own directory, or when a sibling it depends on releases; packages release in dependency order, so the entry point follows the packages it re-exports. Tags are `@`, and each package keeps its own `CHANGELOG.md`. +Releases run through [`@exadev/semantic-release-workspace`](https://github.com/ExaDev/semantic-release-workspace), configured in `release-workspace.config.ts` and run by the `release` job in CI. Every package versions independently and is tagged `@`; a package releases when commits touch its own directory, or when a sibling it depends on releases, in dependency order. Only `process-graph` is published, with its own `CHANGELOG.md` and GitHub Release; a private package gets a version and a tag and nothing else. Because `process-graph` lists every package it bundles in `devDependencies`, a change to any of them releases `process-graph` too. The release commit and tags are pushed to the protected `main` with a repository deploy key (the `RELEASE_DEPLOY_KEY` secret) over SSH, because `GITHUB_TOKEN` cannot bypass a ruleset; the `main` ruleset lists that deploy key as a bypass actor. `GITHUB_TOKEN` is still used for the GitHub API calls that create releases and comment on issues and pull requests. -A new package name must be reserved on npm, and its trusted publisher registered, by a person before its first CI publish; the steps are in CONTRIBUTING.md. - ## Contributing -See [CONTRIBUTING.md](CONTRIBUTING.md) for adding a package, the release strategy and bootstrapping a package name. +See [CONTRIBUTING.md](CONTRIBUTING.md) for adding a package and the release strategy. diff --git a/eslint.shared.ts b/eslint.shared.ts index 2b4e062..9b8b1ca 100644 --- a/eslint.shared.ts +++ b/eslint.shared.ts @@ -164,6 +164,9 @@ export interface PackageLintOptions { /** `@exadev/eslint-config`'s own `exadev/barrel-policy` rule defaults to `"banned"` in its recommended type-checked preset. Every published package here exposes exactly one barrel at `src/index.ts`, so this defaults to `"single"` instead. It explicitly overrides the base preset's own default, rather than merely relying on it. */ readonly barrelPolicy?: "banned" | "single" | "siblings" | "off"; + /** The package's other entry files, beside `src/index.ts`: the modules behind its subpath exports, as globs relative to the package. Each is held to the barrel rules (only re-exports) and may re-export another package's surface, as `src/index.ts` may. A package with a single entry point gives none. */ + readonly barrelEntries?: readonly string[]; + /** * Set for a package that renders React components: `.tsx` files get `@exadev/eslint-config`'s React block (eslint-plugin-react with the automatic JSX runtime, the hooks rules and the jsx-a11y rules). `version` is the React version the rules assume; pass React's own `version` export, so it follows the package's dependency. eslint-plugin-react's `"detect"` cannot be used, because it reads the file name through a context method ESLint 10 removed. */ @@ -182,6 +185,7 @@ export function packageLintConfig(options: PackageLintOptions): Config[] { isomorphicExemptions = [], additionalRestrictedSyntax = [], barrelPolicy = "single", + barrelEntries = [], react, } = options; @@ -239,7 +243,14 @@ export function packageLintConfig(options: PackageLintOptions): Config[] { ], "@typescript-eslint/no-non-null-assertion": nonNullAssertion, "exadev/barrel-policy": - barrelPolicy === "off" ? "off" : ["error", { mode: barrelPolicy }], + barrelPolicy === "off" + ? "off" + : [ + "error", + barrelEntries.length === 0 + ? { mode: barrelPolicy } + : { mode: barrelPolicy, entries: [...barrelEntries] }, + ], }, }, { @@ -294,8 +305,7 @@ export function packageLintConfig(options: PackageLintOptions): Config[] { react === undefined ? [] : [ - // Nested rather than spread: at runtime this is an array of config blocks, which defineConfig flattens. - exadev.configs.react, + ...exadev.configs.react, { settings: { react: { version: react.version } } }, ], dataFileLintConfig, diff --git a/knip.config.ts b/knip.config.ts index ae5b090..ff8a968 100644 --- a/knip.config.ts +++ b/knip.config.ts @@ -8,9 +8,10 @@ import type { KnipConfig } from "knip"; const config: KnipConfig = { workspaces: { ".": { - entry: ["*.config.ts"], + entry: ["*.config.ts", "scripts/*.ts"], project: [ "*.config.ts", + "scripts/*.ts", "commit-types.ts", "eslint.shared.ts", "stryker.shared.ts", @@ -20,6 +21,20 @@ const config: KnipConfig = { entry: ["src/index.{ts,tsx}"], project: ["src/**/*.{ts,tsx}!"], }, + // The contracts' Zod schemas embed the model's, which are built on trilean's expression and JSON schemas, so their emitted declarations import trilean although no source file names it, and knip traces source alone. + ...Object.fromEntries( + [ + "packages/core/graph/source-contract", + "packages/core/graph/store-contract", + ].map((workspace) => [ + workspace, + { + entry: ["src/index.{ts,tsx}"], + project: ["src/**/*.{ts,tsx}!"], + ignoreDependencies: ["trilean"], + }, + ]), + ), "packages/adapters/*/*": { entry: ["src/index.{ts,tsx}"], project: ["src/**/*.{ts,tsx}!"], @@ -28,8 +43,20 @@ const config: KnipConfig = { entry: ["src/index.{ts,tsx}"], project: ["src/**/*.{ts,tsx}!"], }, + "packages/targets/process-graph": { + // Its entries are its tsdown entries, the bin included, which knip's tsdown plugin reads. + project: ["src/**/*.{ts,tsx}!"], + // Optional peer dependencies of the bundle that nothing else in this workspace declares as a peer. Each is also a devDependency, as `pnpm add --save-peer` writes it, and only the built bundle imports it, since `src/` reaches it through the workspace packages it inlines, and knip traces `src/`. knip reports an entry here that stops being needed and a new peer missing from it, so the list cannot drift silently. + ignoreDependencies: [ + "@orpc/client", + "@sqlite.org/sqlite-wasm", + "commander", + "elkjs", + ], + }, "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/package.json b/package.json index 6d6fa09..136ff9f 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "test:smoke": "turbo run _test:smoke", "test:e2e": "turbo run _test:e2e", "test:mutation": "turbo run _test:mutation", - "deps:lint": "syncpack lint", + "deps:lint": "syncpack lint && node scripts/check-published-manifests.ts", "deps:fix": "syncpack fix", "release": "semantic-release-workspace release --config release-workspace.config.ts", "prepare": "husky", @@ -40,41 +40,42 @@ "_prepush": "turbo run _lint _lint-all _typecheck _typecheck-all _test _test-all _test:integration _test:smoke" }, "devDependencies": { - "@commitlint/cli": "21.2.3", - "@commitlint/config-conventional": "21.2.3", - "@commitlint/types": "21.2.3", - "@eslint/js": "10.0.1", - "@eslint/json": "2.1.0", - "@eslint/markdown": "8.0.3", - "@exadev/eslint-config": "2.36.3", - "@exadev/semantic-release-workspace": "3.1.29", - "@semantic-release/changelog": "7.0.0", - "@semantic-release/commit-analyzer": "13.0.1", - "@semantic-release/git": "11.0.1", - "@semantic-release/github": "12.0.10", - "@semantic-release/npm": "13.2.0", - "@semantic-release/release-notes-generator": "14.1.1", - "@stryker-mutator/api": "10.0.0", - "@types/node": "26.6.4", - "conventional-changelog-conventionalcommits": "9.3.1", - "eslint": "10.12.0", - "eslint-config-prettier": "10.1.8", - "eslint-plugin-depend": "1.5.0", - "eslint-plugin-jsx-a11y": "6.10.2", - "eslint-plugin-prettier": "5.5.6", - "eslint-plugin-react": "7.37.5", - "eslint-plugin-react-hooks": "7.1.1", - "eslint-plugin-yml": "3.8.1", - "globals": "17.13.0", - "husky": "9.1.7", - "knip": "6.39.0", - "lint-staged": "17.6.0", - "prettier": "3.9.9", - "semantic-release": "25.0.9", - "syncpack": "15.3.3", - "turbo": "2.11.7", - "typescript": "6.0.3", - "typescript-eslint": "8.71.0", - "vitest": "5.0.3" + "@commitlint/cli": "catalog:", + "@commitlint/config-conventional": "catalog:", + "@commitlint/types": "catalog:", + "@eslint/js": "catalog:", + "@eslint/json": "catalog:", + "@eslint/markdown": "catalog:", + "@exadev/eslint-config": "catalog:", + "@exadev/semantic-release-workspace": "catalog:", + "@semantic-release/changelog": "catalog:", + "@semantic-release/commit-analyzer": "catalog:", + "@semantic-release/git": "catalog:", + "@semantic-release/github": "catalog:", + "@semantic-release/npm": "catalog:", + "@semantic-release/release-notes-generator": "catalog:", + "@stryker-mutator/api": "catalog:", + "@types/node": "catalog:", + "conventional-changelog-conventionalcommits": "catalog:", + "eslint": "catalog:", + "eslint-config-prettier": "catalog:", + "eslint-plugin-depend": "catalog:", + "eslint-plugin-jsx-a11y": "catalog:", + "eslint-plugin-prettier": "catalog:", + "eslint-plugin-react": "catalog:", + "eslint-plugin-react-hooks": "catalog:", + "eslint-plugin-yml": "catalog:", + "globals": "catalog:", + "husky": "catalog:", + "knip": "catalog:", + "lint-staged": "catalog:", + "prettier": "catalog:", + "semantic-release": "catalog:", + "syncpack": "catalog:", + "turbo": "catalog:", + "typescript": "catalog:", + "typescript-eslint": "catalog:", + "vitest": "catalog:", + "yaml": "catalog:" } } diff --git a/packages/adapters/graph/source-github-issues/README.md b/packages/adapters/graph/source-github-issues/README.md index e00e818..09463f3 100644 --- a/packages/adapters/graph/source-github-issues/README.md +++ b/packages/adapters/graph/source-github-issues/README.md @@ -1,6 +1,8 @@ # @exadev/process-graph-source-github-issues -[![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-source-github-issues) [![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) +[![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://github.com/ExaDev/process-graph) [![CI](https://img.shields.io/github/actions/workflow/status/ExaDev/process-graph/ci.yml?branch=main)](https://github.com/ExaDev/process-graph/actions) + +A private workspace package, not published on its own: it is bundled into [`process-graph`](../../../targets/process-graph/README.md), which exposes it as `process-graph/source/github`, with its Node token port at `process-graph/source/github/node`. The GitHub issues adapter for the `GraphSource` port in `@exadev/process-graph-source-contract`. It reads issues, what blocks them, what they block and their sub-issues through GitHub's GraphQL API across any number of organisations, repositories and Projects v2 boards, and returns them as pages of the process model. It also lists the scopes a picker offers. It passes the port's conformance kit. The main entry point imports nothing Node-only; `./node` adds a token helper for Node. diff --git a/packages/adapters/graph/source-github-issues/package.json b/packages/adapters/graph/source-github-issues/package.json index 812fa1e..998f2c3 100644 --- a/packages/adapters/graph/source-github-issues/package.json +++ b/packages/adapters/graph/source-github-issues/package.json @@ -2,6 +2,7 @@ "name": "@exadev/process-graph-source-github-issues", "version": "1.1.0", "description": "The GitHub issues GraphSource adapter: issues as bound activities, blockedBy and blocking as transitions, sub-issues, repositories, organisations and assignees, read through the GraphQL API with server-side filters, pagination, rate-limit handling and typed errors across organisations, repositories and Projects v2 boards, with a scope listing for pickers.", + "private": true, "type": "module", "repository": { "type": "git", @@ -63,19 +64,19 @@ "orpc" ], "devDependencies": { - "@arethetypeswrong/cli": "0.18.5", - "@stryker-mutator/core": "10.0.0", - "@stryker-mutator/typescript-checker": "10.0.0", - "@stryker-mutator/vitest-runner": "10.0.0", - "@types/node": "26.6.4", - "@vitest/coverage-v8": "5.0.3", - "eslint": "10.12.0", - "publint": "0.3.25", - "typescript": "6.0.3", - "vitest": "5.0.3" + "@arethetypeswrong/cli": "catalog:", + "@stryker-mutator/core": "catalog:", + "@stryker-mutator/typescript-checker": "catalog:", + "@stryker-mutator/vitest-runner": "catalog:", + "@types/node": "catalog:", + "@vitest/coverage-v8": "catalog:", + "eslint": "catalog:", + "publint": "catalog:", + "typescript": "catalog:", + "vitest": "catalog:" }, "dependencies": { - "@exadev/process-graph-source-contract": "1.1.0", - "zod": "4.6.5" + "@exadev/process-graph-source-contract": "workspace:*", + "zod": "catalog:" } } diff --git a/packages/adapters/graph/sqlite-node/README.md b/packages/adapters/graph/sqlite-node/README.md index cf408f2..2902aa3 100644 --- a/packages/adapters/graph/sqlite-node/README.md +++ b/packages/adapters/graph/sqlite-node/README.md @@ -1,6 +1,8 @@ # @exadev/process-graph-sqlite-node -[![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-sqlite-node) [![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) +[![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://github.com/ExaDev/process-graph) [![CI](https://img.shields.io/github/actions/workflow/status/ExaDev/process-graph/ci.yml?branch=main)](https://github.com/ExaDev/process-graph/actions) + +A private workspace package, not published on its own: it is bundled into [`process-graph`](../../../targets/process-graph/README.md), which exposes it as `process-graph/store/node`. The SQLite graph store from `@exadev/process-graph-store-sqlite` on Node's built-in `node:sqlite`, through `drizzle-orm/node-sqlite`. It is the driver for the command line and for servers, and needs no native module. diff --git a/packages/adapters/graph/sqlite-node/package.json b/packages/adapters/graph/sqlite-node/package.json index b2e1a25..d0da0ef 100644 --- a/packages/adapters/graph/sqlite-node/package.json +++ b/packages/adapters/graph/sqlite-node/package.json @@ -2,6 +2,7 @@ "name": "@exadev/process-graph-sqlite-node", "version": "1.0.4", "description": "The SQLite graph store on Node's built-in node:sqlite through drizzle-orm/node-sqlite, for the command line and servers.", + "private": true, "type": "module", "repository": { "type": "git", @@ -56,22 +57,22 @@ "drizzle" ], "dependencies": { - "@exadev/process-graph-store-contract": "1.1.0", - "@exadev/process-graph-store-sqlite": "1.1.0", - "drizzle-orm": "1.0.0-rc.4" + "@exadev/process-graph-store-contract": "workspace:*", + "@exadev/process-graph-store-sqlite": "workspace:*", + "drizzle-orm": "catalog:" }, "devDependencies": { - "@arethetypeswrong/cli": "0.18.5", - "@orpc/client": "2.0.0-beta.41", - "@orpc/server": "2.0.0-beta.41", - "@stryker-mutator/core": "10.0.0", - "@stryker-mutator/typescript-checker": "10.0.0", - "@stryker-mutator/vitest-runner": "10.0.0", - "@types/node": "26.6.4", - "@vitest/coverage-v8": "5.0.3", - "eslint": "10.12.0", - "publint": "0.3.25", - "typescript": "6.0.3", - "vitest": "5.0.3" + "@arethetypeswrong/cli": "catalog:", + "@orpc/client": "catalog:", + "@orpc/server": "catalog:", + "@stryker-mutator/core": "catalog:", + "@stryker-mutator/typescript-checker": "catalog:", + "@stryker-mutator/vitest-runner": "catalog:", + "@types/node": "catalog:", + "@vitest/coverage-v8": "catalog:", + "eslint": "catalog:", + "publint": "catalog:", + "typescript": "catalog:", + "vitest": "catalog:" } } diff --git a/packages/adapters/graph/sqlite-wasm/README.md b/packages/adapters/graph/sqlite-wasm/README.md index c7f6089..f2e8908 100644 --- a/packages/adapters/graph/sqlite-wasm/README.md +++ b/packages/adapters/graph/sqlite-wasm/README.md @@ -1,6 +1,8 @@ # @exadev/process-graph-sqlite-wasm -[![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-sqlite-wasm) [![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) +[![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://github.com/ExaDev/process-graph) [![CI](https://img.shields.io/github/actions/workflow/status/ExaDev/process-graph/ci.yml?branch=main)](https://github.com/ExaDev/process-graph/actions) + +A private workspace package, not published on its own: it is bundled into [`process-graph`](../../../targets/process-graph/README.md), which exposes it as `process-graph/store/wasm`, with its worker entry at `process-graph/store/wasm/worker`. The SQLite graph store from `@exadev/process-graph-store-sqlite` in the browser. SQLite compiled to WebAssembly (`@sqlite.org/sqlite-wasm`) runs in a dedicated worker on the origin private file system, Drizzle reaches it through `drizzle-orm/sqlite-proxy`, and the page talks to the store over oRPC's message-port transport. Any number of tabs can use one database, and the page needs no `Cross-Origin-Opener-Policy` or `Cross-Origin-Embedder-Policy` headers. diff --git a/packages/adapters/graph/sqlite-wasm/package.json b/packages/adapters/graph/sqlite-wasm/package.json index d7063b8..b214bbc 100644 --- a/packages/adapters/graph/sqlite-wasm/package.json +++ b/packages/adapters/graph/sqlite-wasm/package.json @@ -62,22 +62,22 @@ "worker" ], "dependencies": { - "@exadev/process-graph-store-contract": "1.1.0", - "@exadev/process-graph-store-sqlite": "1.1.0", - "@orpc/client": "2.0.0-beta.41", - "@orpc/server": "2.0.0-beta.41", - "@sqlite.org/sqlite-wasm": "3.53.4-build2", - "drizzle-orm": "1.0.0-rc.4" + "@exadev/process-graph-store-contract": "workspace:*", + "@exadev/process-graph-store-sqlite": "workspace:*", + "@orpc/client": "catalog:", + "@orpc/server": "catalog:", + "@sqlite.org/sqlite-wasm": "catalog:", + "drizzle-orm": "catalog:" }, "devDependencies": { - "@arethetypeswrong/cli": "0.18.5", - "@types/node": "26.6.4", - "@vitest/browser-playwright": "5.0.3", - "@vitest/coverage-v8": "5.0.3", - "eslint": "10.12.0", - "playwright": "1.63.0", - "publint": "0.3.25", - "typescript": "6.0.3", - "vitest": "5.0.3" + "@arethetypeswrong/cli": "catalog:", + "@types/node": "catalog:", + "@vitest/browser-playwright": "catalog:", + "@vitest/coverage-v8": "catalog:", + "eslint": "catalog:", + "playwright": "catalog:", + "publint": "catalog:", + "typescript": "catalog:", + "vitest": "catalog:" } } diff --git a/packages/adapters/graph/store-sqlite/README.md b/packages/adapters/graph/store-sqlite/README.md index 2908394..145530f 100644 --- a/packages/adapters/graph/store-sqlite/README.md +++ b/packages/adapters/graph/store-sqlite/README.md @@ -1,6 +1,8 @@ # @exadev/process-graph-store-sqlite -[![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-store-sqlite) [![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) +[![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://github.com/ExaDev/process-graph) [![CI](https://img.shields.io/github/actions/workflow/status/ExaDev/process-graph/ci.yml?branch=main)](https://github.com/ExaDev/process-graph/actions) + +A private workspace package, not published on its own: it is bundled into [`process-graph`](../../../targets/process-graph/README.md), which exposes it as `process-graph/store`, beside the store contract. The `GraphStore` port from `@exadev/process-graph-store-contract` on SQLite through [Drizzle](https://orm.drizzle.team) (`drizzle-orm` 1.0.0-rc.4). It is written against Drizzle's async SQLite database type, so any Drizzle SQLite driver plugs in: `@exadev/process-graph-sqlite-node` supplies `node:sqlite`, `@exadev/process-graph-sqlite-wasm` supplies SQLite in a browser worker on OPFS. `src/` imports nothing Node-only. diff --git a/packages/adapters/graph/store-sqlite/package.json b/packages/adapters/graph/store-sqlite/package.json index 7f7aa0c..0af747b 100644 --- a/packages/adapters/graph/store-sqlite/package.json +++ b/packages/adapters/graph/store-sqlite/package.json @@ -2,6 +2,7 @@ "name": "@exadev/process-graph-store-sqlite", "version": "1.1.0", "description": "The GraphStore port on SQLite through Drizzle: one schema, committed drizzle-kit migrations applied the same way in every runtime, recursive SQL for the structural queries, written against Drizzle's async SQLite database so any driver plugs in.", + "private": true, "type": "module", "repository": { "type": "git", @@ -57,24 +58,24 @@ "orpc" ], "dependencies": { - "@exadev/process-graph-domain": "1.1.1", - "@exadev/process-graph-schema": "1.1.0", - "@exadev/process-graph-store-contract": "1.1.0", - "@orpc/server": "2.0.0-beta.41", - "drizzle-orm": "1.0.0-rc.4", - "zod": "4.6.5" + "@exadev/process-graph-domain": "workspace:*", + "@exadev/process-graph-schema": "workspace:*", + "@exadev/process-graph-store-contract": "workspace:*", + "@orpc/server": "catalog:", + "drizzle-orm": "catalog:", + "zod": "catalog:" }, "devDependencies": { - "@arethetypeswrong/cli": "0.18.5", - "@stryker-mutator/core": "10.0.0", - "@stryker-mutator/typescript-checker": "10.0.0", - "@stryker-mutator/vitest-runner": "10.0.0", - "@types/node": "26.6.4", - "@vitest/coverage-v8": "5.0.3", - "drizzle-kit": "1.0.0-rc.4", - "eslint": "10.12.0", - "publint": "0.3.25", - "typescript": "6.0.3", - "vitest": "5.0.3" + "@arethetypeswrong/cli": "catalog:", + "@stryker-mutator/core": "catalog:", + "@stryker-mutator/typescript-checker": "catalog:", + "@stryker-mutator/vitest-runner": "catalog:", + "@types/node": "catalog:", + "@vitest/coverage-v8": "catalog:", + "drizzle-kit": "catalog:", + "eslint": "catalog:", + "publint": "catalog:", + "typescript": "catalog:", + "vitest": "catalog:" } } diff --git a/packages/core/graph/dag/README.md b/packages/core/graph/dag/README.md index 73dc1c3..71eaa5d 100644 --- a/packages/core/graph/dag/README.md +++ b/packages/core/graph/dag/README.md @@ -1,6 +1,8 @@ # @exadev/process-graph-dag -[![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-dag) [![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) +[![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://github.com/ExaDev/process-graph) [![CI](https://img.shields.io/github/actions/workflow/status/ExaDev/process-graph/ci.yml?branch=main)](https://github.com/ExaDev/process-graph/actions) + +A private workspace package, not published on its own: it is bundled into [`process-graph`](../../../targets/process-graph/README.md), which exposes it as the `dag` namespace of the root entry, `process-graph`. Dependency-graph primitives over any node set and a `needs` accessor: topological layers, ancestors, descendants, cycle detection, transitive reduction and the critical path. No runtime dependencies, no knowledge of any process model, and no recursion, so a deep graph cannot overflow the call stack. `src/` imports nothing Node-only and runs unchanged in a browser or a Worker. diff --git a/packages/core/graph/dag/package.json b/packages/core/graph/dag/package.json index 17aa931..5dcca40 100644 --- a/packages/core/graph/dag/package.json +++ b/packages/core/graph/dag/package.json @@ -2,6 +2,7 @@ "name": "@exadev/process-graph-dag", "version": "1.1.0", "description": "Model-independent dependency-graph primitives over a node set and a needs accessor: layers, ancestors, descendants, cycles, transitive reduction and the critical path.", + "private": true, "type": "module", "repository": { "type": "git", @@ -57,15 +58,15 @@ "cycle-detection" ], "devDependencies": { - "@arethetypeswrong/cli": "0.18.5", - "@stryker-mutator/core": "10.0.0", - "@stryker-mutator/typescript-checker": "10.0.0", - "@stryker-mutator/vitest-runner": "10.0.0", - "@types/node": "26.6.4", - "@vitest/coverage-v8": "5.0.3", - "eslint": "10.12.0", - "publint": "0.3.25", - "typescript": "6.0.3", - "vitest": "5.0.3" + "@arethetypeswrong/cli": "catalog:", + "@stryker-mutator/core": "catalog:", + "@stryker-mutator/typescript-checker": "catalog:", + "@stryker-mutator/vitest-runner": "catalog:", + "@types/node": "catalog:", + "@vitest/coverage-v8": "catalog:", + "eslint": "catalog:", + "publint": "catalog:", + "typescript": "catalog:", + "vitest": "catalog:" } } diff --git a/packages/core/graph/domain/README.md b/packages/core/graph/domain/README.md index 3bbe363..93ddf6d 100644 --- a/packages/core/graph/domain/README.md +++ b/packages/core/graph/domain/README.md @@ -1,6 +1,8 @@ # @exadev/process-graph-domain -[![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-domain) [![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) +[![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://github.com/ExaDev/process-graph) [![CI](https://img.shields.io/github/actions/workflow/status/ExaDev/process-graph/ci.yml?branch=main)](https://github.com/ExaDev/process-graph/actions) + +A private workspace package, not published on its own: it is bundled into [`process-graph`](../../../targets/process-graph/README.md), which exposes it as its exports at the root entry, `process-graph`. Reasoning over the process model from `@exadev/process-graph-schema` and a run overlay: which work is ready, what blocks what, what a decision's branches do, which cycles are legal, and what finishing something changes. Pure functions over `Model` and `Overlay`, built on `@exadev/process-graph-dag`. Run state is an input, never part of the model. `src/` imports nothing Node-only. diff --git a/packages/core/graph/domain/package.json b/packages/core/graph/domain/package.json index 9c8b65f..3f7b222 100644 --- a/packages/core/graph/domain/package.json +++ b/packages/core/graph/domain/package.json @@ -2,6 +2,7 @@ "name": "@exadev/process-graph-domain", "version": "1.1.1", "description": "Reasoning over the process model and a run overlay: control graph, illegal cycles, three-valued status, decision evaluation, ready set, blocked-by, impact, what-if and critical path.", + "private": true, "type": "module", "repository": { "type": "git", @@ -56,20 +57,20 @@ "what-if" ], "devDependencies": { - "@arethetypeswrong/cli": "0.18.5", - "@stryker-mutator/core": "10.0.0", - "@stryker-mutator/typescript-checker": "10.0.0", - "@stryker-mutator/vitest-runner": "10.0.0", - "@types/node": "26.6.4", - "@vitest/coverage-v8": "5.0.3", - "eslint": "10.12.0", - "publint": "0.3.25", - "typescript": "6.0.3", - "vitest": "5.0.3" + "@arethetypeswrong/cli": "catalog:", + "@stryker-mutator/core": "catalog:", + "@stryker-mutator/typescript-checker": "catalog:", + "@stryker-mutator/vitest-runner": "catalog:", + "@types/node": "catalog:", + "@vitest/coverage-v8": "catalog:", + "eslint": "catalog:", + "publint": "catalog:", + "typescript": "catalog:", + "vitest": "catalog:" }, "dependencies": { - "@exadev/process-graph-dag": "1.1.0", - "@exadev/process-graph-schema": "1.1.0", - "trilean": "1.7.2" + "@exadev/process-graph-dag": "workspace:*", + "@exadev/process-graph-schema": "workspace:*", + "trilean": "catalog:" } } diff --git a/packages/core/graph/layout/README.md b/packages/core/graph/layout/README.md index a8fe942..901c3f2 100644 --- a/packages/core/graph/layout/README.md +++ b/packages/core/graph/layout/README.md @@ -1,6 +1,8 @@ # @exadev/process-graph-layout -[![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-layout) [![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) +[![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://github.com/ExaDev/process-graph) [![CI](https://img.shields.io/github/actions/workflow/status/ExaDev/process-graph/ci.yml?branch=main)](https://github.com/ExaDev/process-graph/actions) + +A private workspace package, not published on its own: it is bundled into [`process-graph`](../../../targets/process-graph/README.md), which exposes it as `process-graph/layout`. Layered layout of a projected view from `@exadev/process-graph-projection`. `layout(view, options)` is a pure async function: it reads a flowchart, swimlane or state machine, never mutates anything, and returns positions in the model's `views` shape, so layout stays apart from the semantic model and no projection reads a coordinate. It runs unchanged in a browser, a Worker or Node: `src/` imports nothing Node-only, and the default engine is elkjs's bundled build, which needs no Worker. diff --git a/packages/core/graph/layout/package.json b/packages/core/graph/layout/package.json index 1fd7010..2826cab 100644 --- a/packages/core/graph/layout/package.json +++ b/packages/core/graph/layout/package.json @@ -2,6 +2,7 @@ "name": "@exadev/process-graph-layout", "version": "1.0.3", "description": "Layered layout of a projected process view into positions keyed by element id, in the model's views shape.", + "private": true, "type": "module", "repository": { "type": "git", @@ -57,20 +58,20 @@ "state-machine" ], "devDependencies": { - "@arethetypeswrong/cli": "0.18.5", - "@stryker-mutator/core": "10.0.0", - "@stryker-mutator/typescript-checker": "10.0.0", - "@stryker-mutator/vitest-runner": "10.0.0", - "@types/node": "26.6.4", - "@vitest/coverage-v8": "5.0.3", - "eslint": "10.12.0", - "publint": "0.3.25", - "typescript": "6.0.3", - "vitest": "5.0.3" + "@arethetypeswrong/cli": "catalog:", + "@stryker-mutator/core": "catalog:", + "@stryker-mutator/typescript-checker": "catalog:", + "@stryker-mutator/vitest-runner": "catalog:", + "@types/node": "catalog:", + "@vitest/coverage-v8": "catalog:", + "eslint": "catalog:", + "publint": "catalog:", + "typescript": "catalog:", + "vitest": "catalog:" }, "dependencies": { - "@exadev/process-graph-projection": "1.1.0", - "@exadev/process-graph-schema": "1.1.0", - "elkjs": "0.12.0" + "@exadev/process-graph-projection": "workspace:*", + "@exadev/process-graph-schema": "workspace:*", + "elkjs": "catalog:" } } diff --git a/packages/core/graph/projection/README.md b/packages/core/graph/projection/README.md index e59567f..0a7614f 100644 --- a/packages/core/graph/projection/README.md +++ b/packages/core/graph/projection/README.md @@ -1,6 +1,8 @@ # @exadev/process-graph-projection -[![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-projection) [![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) +[![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://github.com/ExaDev/process-graph) [![CI](https://img.shields.io/github/actions/workflow/status/ExaDev/process-graph/ci.yml?branch=main)](https://github.com/ExaDev/process-graph/actions) + +A private workspace package, not published on its own: it is bundled into [`process-graph`](../../../targets/process-graph/README.md), which exposes it as its exports at the root entry, `process-graph`. Projections of the process model from `@exadev/process-graph-schema` into each notation. Every projection is a pure function of the model plus the extra input its notation needs, and none of them reads or preserves layout. `src/` imports nothing Node-only. diff --git a/packages/core/graph/projection/package.json b/packages/core/graph/projection/package.json index 61de230..90acfdb 100644 --- a/packages/core/graph/projection/package.json +++ b/packages/core/graph/projection/package.json @@ -2,6 +2,7 @@ "name": "@exadev/process-graph-projection", "version": "1.1.0", "description": "Projections of the process model into a flowchart, swimlane, state machine and sequence diagram, plus the derived hand-offs.", + "private": true, "type": "module", "repository": { "type": "git", @@ -57,19 +58,19 @@ "projection" ], "devDependencies": { - "@arethetypeswrong/cli": "0.18.5", - "@stryker-mutator/core": "10.0.0", - "@stryker-mutator/typescript-checker": "10.0.0", - "@stryker-mutator/vitest-runner": "10.0.0", - "@types/node": "26.6.4", - "@vitest/coverage-v8": "5.0.3", - "eslint": "10.12.0", - "publint": "0.3.25", - "typescript": "6.0.3", - "vitest": "5.0.3" + "@arethetypeswrong/cli": "catalog:", + "@stryker-mutator/core": "catalog:", + "@stryker-mutator/typescript-checker": "catalog:", + "@stryker-mutator/vitest-runner": "catalog:", + "@types/node": "catalog:", + "@vitest/coverage-v8": "catalog:", + "eslint": "catalog:", + "publint": "catalog:", + "typescript": "catalog:", + "vitest": "catalog:" }, "dependencies": { - "@exadev/process-graph-dag": "1.1.0", - "@exadev/process-graph-schema": "1.1.0" + "@exadev/process-graph-dag": "workspace:*", + "@exadev/process-graph-schema": "workspace:*" } } diff --git a/packages/core/graph/projection/src/bounded-work.unit.test.ts b/packages/core/graph/projection/src/bounded-work.unit.test.ts index cc201a1..2c4a4fe 100644 --- a/packages/core/graph/projection/src/bounded-work.unit.test.ts +++ b/packages/core/graph/projection/src/bounded-work.unit.test.ts @@ -782,28 +782,33 @@ const doubled = 2; /** Each projected shape's smaller size in the table: large enough that quadratic work doubles per item while linear work stays level, small enough that a shape whose output is itself quadratic stays quick to build with every collection call counted. */ const tableSize = 100; -describe("work at most doubles when a reported shape doubles", () => { - describe.each(shapes)("%s", (_shape, build, own = tableSize) => { - const small = build(own); - const large = build(doubled * own); - - it.each(entries)("through %s", (_entry, enter) => { - expect(workPerItem(large, enter)).toBeLessThan( - (growthLimit / doubled) * workPerItem(small, enter), - ); +// These cases count reads through a proxy at a size and its double, so how long they take is the machine's, not a property of the code: a clock bound only fails them under load, as with coverage instrumentation on a busy runner. No per-test timeout applies; the CI job's own timeout still ends a hang. +describe( + "work at most doubles when a reported shape doubles", + { timeout: 0 }, + () => { + describe.each(shapes)("%s", (_shape, build, own = tableSize) => { + const small = build(own); + const large = build(doubled * own); + + it.each(entries)("through %s", (_entry, enter) => { + expect(workPerItem(large, enter)).toBeLessThan( + (growthLimit / doubled) * workPerItem(small, enter), + ); + }); }); - }); - it.each(edits)("%s", (_edit, prepare) => { - // Edits re-project the model before reading the edit, a fixed cost per item that a rescan per edited item only overtakes at the larger size. - const small = prepare(size); - const large = prepare(doubled * size); + it.each(edits)("%s", (_edit, prepare) => { + // Edits re-project the model before reading the edit, a fixed cost per item that a rescan per edited item only overtakes at the larger size. + const small = prepare(size); + const large = prepare(doubled * size); - expect(workOf(large.run) / large.input).toBeLessThan( - (growthLimit / doubled) * (workOf(small.run) / small.input), - ); - }); -}); + expect(workOf(large.run) / large.input).toBeLessThan( + (growthLimit / doubled) * (workOf(small.run) / small.input), + ); + }); + }, +); describe("folding never multiplies edges", () => { it.each([1, 2])( diff --git a/packages/core/graph/schema/README.md b/packages/core/graph/schema/README.md index 6d1d2e5..5b6261a 100644 --- a/packages/core/graph/schema/README.md +++ b/packages/core/graph/schema/README.md @@ -1,6 +1,8 @@ # @exadev/process-graph-schema -[![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-schema) [![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) +[![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://github.com/ExaDev/process-graph) [![CI](https://img.shields.io/github/actions/workflow/status/ExaDev/process-graph/ci.yml?branch=main)](https://github.com/ExaDev/process-graph/actions) + +A private workspace package, not published on its own: it is bundled into [`process-graph`](../../../targets/process-graph/README.md), which exposes it as its exports at the root entry, `process-graph`. The process model: one layout-free description of a process that a flowchart, a swimlane, a state machine and a sequence diagram are all views of. Participants, events, actions, elements, transitions and fragments are declared once and cross-referenced by identifier. `src/` imports nothing Node-only and runs unchanged in a browser or a Worker. diff --git a/packages/core/graph/schema/package.json b/packages/core/graph/schema/package.json index 31a2724..357b731 100644 --- a/packages/core/graph/schema/package.json +++ b/packages/core/graph/schema/package.json @@ -2,6 +2,7 @@ "name": "@exadev/process-graph-schema", "version": "1.1.0", "description": "The process model: typed identifier spaces, defineModel with compile-time reference checking, structural validation, and a Zod schema for the open runtime shape.", + "private": true, "type": "module", "repository": { "type": "git", @@ -58,19 +59,19 @@ "typescript" ], "devDependencies": { - "@arethetypeswrong/cli": "0.18.5", - "@stryker-mutator/core": "10.0.0", - "@stryker-mutator/typescript-checker": "10.0.0", - "@stryker-mutator/vitest-runner": "10.0.0", - "@types/node": "26.6.4", - "@vitest/coverage-v8": "5.0.3", - "eslint": "10.12.0", - "publint": "0.3.25", - "typescript": "6.0.3", - "vitest": "5.0.3" + "@arethetypeswrong/cli": "catalog:", + "@stryker-mutator/core": "catalog:", + "@stryker-mutator/typescript-checker": "catalog:", + "@stryker-mutator/vitest-runner": "catalog:", + "@types/node": "catalog:", + "@vitest/coverage-v8": "catalog:", + "eslint": "catalog:", + "publint": "catalog:", + "typescript": "catalog:", + "vitest": "catalog:" }, "dependencies": { - "trilean": "1.7.2", - "zod": "4.6.5" + "trilean": "catalog:", + "zod": "catalog:" } } diff --git a/packages/core/graph/source-contract/README.md b/packages/core/graph/source-contract/README.md index ef21284..964cce1 100644 --- a/packages/core/graph/source-contract/README.md +++ b/packages/core/graph/source-contract/README.md @@ -1,6 +1,8 @@ # @exadev/process-graph-source-contract -[![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-source-contract) [![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) +[![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://github.com/ExaDev/process-graph) [![CI](https://img.shields.io/github/actions/workflow/status/ExaDev/process-graph/ci.yml?branch=main)](https://github.com/ExaDev/process-graph/actions) + +A private workspace package, not published on its own: it is bundled into [`process-graph`](../../../targets/process-graph/README.md), which exposes it as `process-graph/source/github`, beside the GitHub issues adapter. The `GraphSource` port: how the process model from `@exadev/process-graph-schema` reads work from an external tracker. It is an [oRPC](https://orpc.dev) router contract (`@orpc/contract`), so one definition is called in process, across a `MessagePort` to a worker, or over HTTP, and a consumer never changes with the transport. The package also ships the router builder adapters use, an in-memory fake and the conformance kit every adapter must pass. `src/` imports nothing Node-only. diff --git a/packages/core/graph/source-contract/package.json b/packages/core/graph/source-contract/package.json index 89a9734..acff657 100644 --- a/packages/core/graph/source-contract/package.json +++ b/packages/core/graph/source-contract/package.json @@ -2,6 +2,7 @@ "name": "@exadev/process-graph-source-contract", "version": "1.1.0", "description": "The GraphSource port as an oRPC contract: versioned, paginated and streamed sync of bound activities, participants, transitions and overlay status, with an in-memory fake and a conformance kit every adapter must pass.", + "private": true, "type": "module", "repository": { "type": "git", @@ -60,27 +61,27 @@ "conformance" ], "devDependencies": { - "@arethetypeswrong/cli": "0.18.5", - "@stryker-mutator/core": "10.0.0", - "@stryker-mutator/typescript-checker": "10.0.0", - "@stryker-mutator/vitest-runner": "10.0.0", - "@types/node": "26.6.4", - "@vitest/coverage-v8": "5.0.3", - "eslint": "10.12.0", - "publint": "0.3.25", - "typescript": "6.0.3", - "vitest": "5.0.3" + "@arethetypeswrong/cli": "catalog:", + "@stryker-mutator/core": "catalog:", + "@stryker-mutator/typescript-checker": "catalog:", + "@stryker-mutator/vitest-runner": "catalog:", + "@types/node": "catalog:", + "@vitest/coverage-v8": "catalog:", + "eslint": "catalog:", + "publint": "catalog:", + "typescript": "catalog:", + "vitest": "catalog:" }, "dependencies": { - "@exadev/process-graph-schema": "1.1.0", - "@orpc/client": "2.0.0-beta.41", - "@orpc/contract": "2.0.0-beta.41", - "@orpc/server": "2.0.0-beta.41", - "trilean": "1.7.2", - "zod": "4.6.5" + "@exadev/process-graph-schema": "workspace:*", + "@orpc/client": "catalog:", + "@orpc/contract": "catalog:", + "@orpc/server": "catalog:", + "trilean": "catalog:", + "zod": "catalog:" }, "peerDependencies": { - "vitest": "5.0.3" + "vitest": "catalog:" }, "peerDependenciesMeta": { "vitest": { diff --git a/packages/core/graph/store-contract/README.md b/packages/core/graph/store-contract/README.md index 2ef9656..8c40d11 100644 --- a/packages/core/graph/store-contract/README.md +++ b/packages/core/graph/store-contract/README.md @@ -1,6 +1,8 @@ # @exadev/process-graph-store-contract -[![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-store-contract) [![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) +[![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://github.com/ExaDev/process-graph) [![CI](https://img.shields.io/github/actions/workflow/status/ExaDev/process-graph/ci.yml?branch=main)](https://github.com/ExaDev/process-graph/actions) + +A private workspace package, not published on its own: it is bundled into [`process-graph`](../../../targets/process-graph/README.md), which exposes it as `process-graph/store`, beside the SQLite store. The persistence port for process models and their run overlays, as an [oRPC](https://orpc.dev) router contract. One definition runs in process (a router client called directly), across a `MessagePort` to a worker, or over HTTP, with no change to its consumers. Inputs and outputs are Zod schemas built from `@exadev/process-graph-schema`'s `modelSchema` and `overlaySchema`, so the port carries the model as it is and storage layout never reaches it. `src/` imports nothing Node-only. diff --git a/packages/core/graph/store-contract/package.json b/packages/core/graph/store-contract/package.json index b80df6d..86948c1 100644 --- a/packages/core/graph/store-contract/package.json +++ b/packages/core/graph/store-contract/package.json @@ -2,6 +2,7 @@ "name": "@exadev/process-graph-store-contract", "version": "1.1.0", "description": "The persistence port for process models and run overlays as an oRPC contract: versioned procedures with Zod inputs and outputs, an in-memory fake and a conformance kit every store adapter runs.", + "private": true, "type": "module", "repository": { "type": "git", @@ -60,28 +61,28 @@ "conformance" ], "devDependencies": { - "@arethetypeswrong/cli": "0.18.5", - "@orpc/client": "2.0.0-beta.41", - "@stryker-mutator/core": "10.0.0", - "@stryker-mutator/typescript-checker": "10.0.0", - "@stryker-mutator/vitest-runner": "10.0.0", - "@types/node": "26.6.4", - "@vitest/coverage-v8": "5.0.3", - "eslint": "10.12.0", - "publint": "0.3.25", - "typescript": "6.0.3", - "vitest": "5.0.3" + "@arethetypeswrong/cli": "catalog:", + "@orpc/client": "catalog:", + "@stryker-mutator/core": "catalog:", + "@stryker-mutator/typescript-checker": "catalog:", + "@stryker-mutator/vitest-runner": "catalog:", + "@types/node": "catalog:", + "@vitest/coverage-v8": "catalog:", + "eslint": "catalog:", + "publint": "catalog:", + "typescript": "catalog:", + "vitest": "catalog:" }, "dependencies": { - "@exadev/process-graph-domain": "1.1.1", - "@exadev/process-graph-schema": "1.1.0", - "@orpc/contract": "2.0.0-beta.41", - "@orpc/server": "2.0.0-beta.41", - "trilean": "1.7.2", - "zod": "4.6.5" + "@exadev/process-graph-domain": "workspace:*", + "@exadev/process-graph-schema": "workspace:*", + "@orpc/contract": "catalog:", + "@orpc/server": "catalog:", + "trilean": "catalog:", + "zod": "catalog:" }, "peerDependencies": { - "vitest": "5.0.3" + "vitest": "catalog:" }, "peerDependenciesMeta": { "vitest": { 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..383e457 --- /dev/null +++ b/packages/targets/graph-cli/README.md @@ -0,0 +1,108 @@ +# @exadev/process-graph-cli + +[![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://github.com/ExaDev/process-graph) [![CI](https://img.shields.io/github/actions/workflow/status/ExaDev/process-graph/ci.yml?branch=main)](https://github.com/ExaDev/process-graph/actions) + +A private workspace package, not published on its own: it is bundled into [`process-graph`](../process-graph/README.md), which exposes it as `process-graph/cli`, and its command line is the `process-graph` bin. + +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