diff --git a/AGENTS.md b/AGENTS.md index 5265a94..0d0bc8f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -30,23 +30,24 @@ See `docs/guides/runbook.md` for the full workflow. ## Package Map -| Package | Tag | Purpose | -| ----------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `@repo/core-shared` | core | Generic primitives (Zod, env, Payload hooks/fields/blocks, tRPC init/context, instrumentation interfaces, jobs, rate-limit, security headers, DI bind contexts) | -| `@repo/core-ui` | core | Design system (atoms, molecules, generic organisms, templates) — the home of Veect's monochrome "ink instrument" language | -| `@repo/core-events` | core | `IEventBus` — `InMemoryEventBus` (dev/test) + `PayloadJobsEventBus` (prod) (ADR-015) | -| `@repo/core-realtime` | core | Socket.IO server + `IRealtimeBroadcaster` + handler registry (ADR-016) | -| `@repo/core-audit` | core | DPA-compliant audit logging (GDPR erasure, OTel correlation) (ADR-018) | -| `@repo/core-analytics` | core | Product analytics capture channel (`IAnalytics`) (ADR-024) | -| `@repo/core-consent` | core | Consent-category runtime gate + cookie banner (ADR-025) | -| `@repo/core-dsr` | core | Data-subject rights: export, delete, rectify, restrict (ADR-025) | -| `@repo/core-api` | core-composition | tRPC router aggregator — imports `@repo//api` only | -| `@repo/core-cms` | core-composition | Payload config aggregator — imports `@repo//cms` only | -| `@repo/core-trpc` | core-composition | Frontend tRPC client + Next.js provider | -| `@repo/auth` | feature | Users collection + sign-in/up/out + sessions — control-plane identity (ADR-027: email/password accounts; repo access is a per-workspace credential, not a user identity) | -| `@repo/core-eslint` | tooling | Shared ESLint 9 flat configs (base, next, react-internal, boundaries) + the 16 conformance rules | -| `@repo/core-typescript` | tooling | Shared TypeScript base configs + Vitest base | -| `@repo/core-testing` | tooling | Shared test utilities (defineFactory, defineContractSuite, renderWithProviders, payload mocks, `Recording*` doubles) | +| Package | Tag | Purpose | +| ---------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `@repo/core-shared` | core | Generic primitives (Zod, env, Payload hooks/fields/blocks, tRPC init/context, instrumentation interfaces, jobs, rate-limit, security headers, DI bind contexts) | +| `@repo/core-ui` | core | Design system (atoms, molecules, generic organisms, templates) — the home of Veect's monochrome "ink instrument" language | +| `@repo/core-events` | core | `IEventBus` — `InMemoryEventBus` (dev/test) + `PayloadJobsEventBus` (prod) (ADR-015) | +| `@repo/core-realtime` | core | Socket.IO server + `IRealtimeBroadcaster` + handler registry (ADR-016) | +| `@repo/core-audit` | core | DPA-compliant audit logging (GDPR erasure, OTel correlation) (ADR-018) | +| `@repo/core-analytics` | core | Product analytics capture channel (`IAnalytics`) (ADR-024) | +| `@repo/core-consent` | core | Consent-category runtime gate + cookie banner (ADR-025) | +| `@repo/core-dsr` | core | Data-subject rights: export, delete, rectify, restrict (ADR-025) | +| `@repo/core-runner-protocol` | core | Versioned runner-protocol wire contract — envelope + `.strict()` zod message schemas shared by control plane, editor, and runners (ADR-027) | +| `@repo/core-api` | core-composition | tRPC router aggregator — imports `@repo//api` only | +| `@repo/core-cms` | core-composition | Payload config aggregator — imports `@repo//cms` only | +| `@repo/core-trpc` | core-composition | Frontend tRPC client + Next.js provider | +| `@repo/auth` | feature | Users collection + sign-in/up/out + sessions — control-plane identity (ADR-027: email/password accounts; repo access is a per-workspace credential, not a user identity) | +| `@repo/core-eslint` | tooling | Shared ESLint 9 flat configs (base, next, react-internal, boundaries) + the 16 conformance rules | +| `@repo/core-typescript` | tooling | Shared TypeScript base configs + Vitest base | +| `@repo/core-testing` | tooling | Shared test utilities (defineFactory, defineContractSuite, renderWithProviders, payload mocks, `Recording*` doubles) | Apps: @@ -66,7 +67,7 @@ Apps: - **app** (3 packages) — `apps/web-next`, `apps/cms`, `apps/storybook` - **core-composition** (3 packages) — `packages/core-api`, `core-cms` (must-have); `core-trpc` (optional, scaffolded) -- **core** (8 packages) — `packages/core-shared` (must-have); `core-ui`, `core-events`, `core-realtime`, `core-audit`, `core-analytics`, `core-consent`, `core-dsr` (optional cores, all currently scaffolded — new ones via `pnpm turbo gen core-package `) +- **core** (9 packages) — `packages/core-shared` (must-have); `core-ui`, `core-events`, `core-realtime`, `core-audit`, `core-analytics`, `core-consent`, `core-dsr` (optional cores, all currently scaffolded — new ones via `pnpm turbo gen core-package `); `core-runner-protocol` (hand-scaffolded — outside the generator's snapshot set) - **feature** (1 package) — `packages/auth` - **tooling** (3 packages) — `packages/core-eslint`, `core-typescript`, `core-testing` @@ -635,7 +636,7 @@ Per-package documentation lives in each `AGENTS.md`: - `packages/core-shared/AGENTS.md` - `packages/core-api/AGENTS.md`, `core-cms/AGENTS.md` (`core-trpc` has none yet) -- `packages/core-ui/AGENTS.md`, `core-events/AGENTS.md`, `core-realtime/AGENTS.md`, `core-audit/AGENTS.md`, `core-analytics/AGENTS.md`, `core-consent/AGENTS.md`, `core-dsr/AGENTS.md` +- `packages/core-ui/AGENTS.md`, `core-events/AGENTS.md`, `core-realtime/AGENTS.md`, `core-audit/AGENTS.md`, `core-analytics/AGENTS.md`, `core-consent/AGENTS.md`, `core-dsr/AGENTS.md`, `core-runner-protocol/AGENTS.md` - `packages/auth/AGENTS.md` - `packages/core-eslint/AGENTS.md`, `core-typescript/AGENTS.md`, `core-testing/AGENTS.md` - `apps/cms/AGENTS.md`, `web-next/AGENTS.md`, `storybook/AGENTS.md` diff --git a/apps/web-next/next.config.mjs b/apps/web-next/next.config.mjs index 3128ab8..593a1cd 100644 --- a/apps/web-next/next.config.mjs +++ b/apps/web-next/next.config.mjs @@ -12,6 +12,7 @@ const nextConfig = { "@repo/core-dsr", "@repo/core-events", "@repo/core-realtime", + "@repo/core-runner-protocol", "@repo/core-shared", "@repo/core-trpc", "@repo/core-ui", diff --git a/packages/core-runner-protocol/AGENTS.md b/packages/core-runner-protocol/AGENTS.md new file mode 100644 index 0000000..e1cb850 --- /dev/null +++ b/packages/core-runner-protocol/AGENTS.md @@ -0,0 +1,11 @@ +# @repo/core-runner-protocol + +Owns the versioned runner-protocol wire contract (ADR-027): the message envelope (`protocolVersion: "0"` + workspace-scoped auth token) and `.strict()` zod schemas for every message exchanged between the control plane/editor and any runner implementation (cloud, local CLI, later Tauri-embedded). Schemas only — the WS server/client implementations live in `apps/runner` and its consumers, never here. + +**Boundary tag:** core. May be imported by feature, core, core-composition, app. May import from tooling. + +**Public surface:** `PROTOCOL_VERSION`, the envelope schema, the per-message `.strict()` schemas + the `runnerMessageSchema` discriminated union, and their inferred types — all through the single index barrel. + +**Scaffolding note:** hand-scaffolded from the `packages/core-events` shape — the `core-package` turbo generator only covers the eight pre-curated snapshot names (analytics, audit, consent, dsr, events, realtime, trpc, ui). Candidate for a future generator snapshot. + +**See:** `docs/decisions/adr-027-hosted-saas-and-runner-split.md`, `docs/work/prds/walking-skeleton.prd.md`, `docs/glossary.md` § "Runner protocol". diff --git a/packages/core-runner-protocol/eslint.config.js b/packages/core-runner-protocol/eslint.config.js new file mode 100644 index 0000000..7440d8f --- /dev/null +++ b/packages/core-runner-protocol/eslint.config.js @@ -0,0 +1,3 @@ +import baseConfig from "@repo/core-eslint/base"; + +export default baseConfig; diff --git a/packages/core-runner-protocol/package.json b/packages/core-runner-protocol/package.json new file mode 100644 index 0000000..2245507 --- /dev/null +++ b/packages/core-runner-protocol/package.json @@ -0,0 +1,26 @@ +{ + "name": "@repo/core-runner-protocol", + "version": "0.0.1", + "private": true, + "type": "module", + "exports": { + ".": "./src/index.ts" + }, + "scripts": { + "build": "tsc --noEmit", + "lint": "eslint .", + "typecheck": "tsc --noEmit", + "test": "vitest run" + }, + "dependencies": { + "zod": "^3.24.0" + }, + "devDependencies": { + "@repo/core-eslint": "workspace:*", + "@repo/core-testing": "workspace:*", + "@repo/core-typescript": "workspace:*", + "@vitest/coverage-v8": "^3.2.4", + "typescript": "^5.8.0", + "vitest": "^3.0.0" + } +} diff --git a/packages/core-runner-protocol/src/index.ts b/packages/core-runner-protocol/src/index.ts new file mode 100644 index 0000000..adfa473 --- /dev/null +++ b/packages/core-runner-protocol/src/index.ts @@ -0,0 +1 @@ +export { PROTOCOL_VERSION, type ProtocolVersion } from "./protocol-version"; diff --git a/packages/core-runner-protocol/src/protocol-version.test.ts b/packages/core-runner-protocol/src/protocol-version.test.ts new file mode 100644 index 0000000..90633c5 --- /dev/null +++ b/packages/core-runner-protocol/src/protocol-version.test.ts @@ -0,0 +1,8 @@ +import { describe, it, expect } from "vitest"; +import { PROTOCOL_VERSION } from "@/protocol-version"; + +describe("PROTOCOL_VERSION", () => { + it('is pinned to "0"', () => { + expect(PROTOCOL_VERSION).toBe("0"); + }); +}); diff --git a/packages/core-runner-protocol/src/protocol-version.ts b/packages/core-runner-protocol/src/protocol-version.ts new file mode 100644 index 0000000..bf4d99a --- /dev/null +++ b/packages/core-runner-protocol/src/protocol-version.ts @@ -0,0 +1,10 @@ +/** + * The pinned runner-protocol version (ADR-027). + * + * Every envelope is validated against this exact literal. Version + * negotiation beyond the pinned "0" is deliberately out of scope for the + * walking skeleton (later PRDs). + */ +export const PROTOCOL_VERSION = "0" as const; + +export type ProtocolVersion = typeof PROTOCOL_VERSION; diff --git a/packages/core-runner-protocol/tsconfig.json b/packages/core-runner-protocol/tsconfig.json new file mode 100644 index 0000000..652e804 --- /dev/null +++ b/packages/core-runner-protocol/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "@repo/core-typescript/base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/core-runner-protocol/turbo.json b/packages/core-runner-protocol/turbo.json new file mode 100644 index 0000000..dcb8fb3 --- /dev/null +++ b/packages/core-runner-protocol/turbo.json @@ -0,0 +1,4 @@ +{ + "extends": ["//"], + "tags": ["core"] +} diff --git a/packages/core-runner-protocol/vitest.config.ts b/packages/core-runner-protocol/vitest.config.ts new file mode 100644 index 0000000..2ee07c1 --- /dev/null +++ b/packages/core-runner-protocol/vitest.config.ts @@ -0,0 +1,9 @@ +import path from "node:path"; +import { mergeConfig } from "vitest/config"; +import { nodeVitestConfig } from "@repo/core-typescript/vitest.base.node"; + +export default mergeConfig(nodeVitestConfig, { + resolve: { + alias: { "@": path.resolve(__dirname, "./src") }, + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bc00920..f0f9c40 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -656,6 +656,31 @@ importers: specifier: ^3.0.0 version: 3.2.4(@types/debug@4.1.13)(@types/node@22.19.17)(happy-dom@20.8.9)(jiti@2.7.0)(jsdom@25.0.1)(lightningcss@1.32.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)(yaml@2.9.0) + packages/core-runner-protocol: + dependencies: + zod: + specifier: ^3.24.0 + version: 3.25.76 + devDependencies: + "@repo/core-eslint": + specifier: workspace:* + version: link:../core-eslint + "@repo/core-testing": + specifier: workspace:* + version: link:../core-testing + "@repo/core-typescript": + specifier: workspace:* + version: link:../core-typescript + "@vitest/coverage-v8": + specifier: ^3.2.4 + version: 3.2.4(vitest@3.2.4(@types/debug@4.1.13)(@types/node@25.5.2)(happy-dom@20.8.9)(jiti@2.7.0)(jsdom@25.0.1)(lightningcss@1.32.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)(yaml@2.9.0)) + typescript: + specifier: ^5.8.0 + version: 5.9.3 + vitest: + specifier: ^3.0.0 + version: 3.2.4(@types/debug@4.1.13)(@types/node@25.5.2)(happy-dom@20.8.9)(jiti@2.7.0)(jsdom@25.0.1)(lightningcss@1.32.0)(sass@1.99.0)(terser@5.46.2)(tsx@4.21.0)(yaml@2.9.0) + packages/core-shared: dependencies: "@opentelemetry/api":