feat(core-runner-protocol): scaffold protocol package

Hand-scaffolded from the packages/core-events shape: the core-package
turbo generator only covers its eight pre-curated snapshot names
(analytics, audit, consent, dsr, events, realtime, trpc, ui) and
rejects 'runner-protocol' at the name prompt. Flagged in the package
AGENTS.md as a future generator snapshot candidate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016j8z4VHjedXDTjEDNg7qHK
This commit is contained in:
2026-07-12 21:39:22 +02:00
parent 240075d95b
commit 15dc6b9128
12 changed files with 130 additions and 19 deletions

View File

@@ -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".

View File

@@ -0,0 +1,3 @@
import baseConfig from "@repo/core-eslint/base";
export default baseConfig;

View File

@@ -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"
}
}

View File

@@ -0,0 +1 @@
export { PROTOCOL_VERSION, type ProtocolVersion } from "./protocol-version";

View File

@@ -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");
});
});

View File

@@ -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;

View File

@@ -0,0 +1,12 @@
{
"extends": "@repo/core-typescript/base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

View File

@@ -0,0 +1,4 @@
{
"extends": ["//"],
"tags": ["core"]
}

View File

@@ -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") },
},
});