feat(durable): move Pico into dedicated package

This commit is contained in:
Mario Zechner
2026-09-18 13:39:09 +02:00
parent eed5263cdd
commit 0801601621
18 changed files with 118 additions and 6 deletions
+1
View File
@@ -30,6 +30,7 @@ To learn more about Pi:
| **[@earendil-works/chord](packages/chord)** | Standalone application-composition runtime for services, replicated state, RPC, and plugins |
| **[@earendil-works/pi-telemetry](packages/telemetry)** | Vendor-neutral telemetry contracts, reference adapter, conformance tests, and typed schemas |
| **[@earendil-works/pi-ai](packages/ai)** | Unified multi-provider LLM API (OpenAI, Anthropic, Google, etc.) |
| **[@earendil-works/pi-durable](packages/durable)** | Durable conversation, task, and document runtime |
| **[@earendil-works/pi-agent-core](packages/agent)** | Agent runtime with tool calling and state management |
| **[@earendil-works/pi-coding-agent](packages/coding-agent)** | Interactive coding agent CLI |
| **[@earendil-works/pi-tui](packages/tui)** | Terminal UI library with differential rendering |
+20
View File
@@ -737,6 +737,10 @@
"resolved": "packages/coding-agent",
"link": true
},
"node_modules/@earendil-works/pi-durable": {
"resolved": "packages/durable",
"link": true
},
"node_modules/@earendil-works/pi-evals": {
"resolved": "packages/evals",
"link": true
@@ -5511,6 +5515,22 @@
"extraneous": true,
"license": "MIT"
},
"packages/durable": {
"name": "@earendil-works/pi-durable",
"version": "0.85.1",
"license": "MIT",
"dependencies": {
"@earendil-works/chord": "^0.85.1",
"@earendil-works/pi-ai": "^0.85.1"
},
"devDependencies": {
"shx": "0.4.0",
"vitest": "4.1.9"
},
"engines": {
"node": ">=22.19.0"
}
},
"packages/evals": {
"name": "@earendil-works/pi-evals",
"version": "0.85.1",
+2 -2
View File
@@ -13,8 +13,8 @@
],
"scripts": {
"clean": "npm run clean --workspaces",
"build": "cd packages/chord && npm run build && cd ../tui && npm run build && cd ../telemetry && npm run build && cd ../ai && npm run build && cd ../agent && npm run build && cd ../session-backends/sqlite-node && npm run build && cd ../../protocol && npm run build && cd ../client && npm run build && cd ../server && npm run build && cd ../coding-agent && npm run build",
"build:offline": "cd packages/chord && npm run build && cd ../tui && npm run build && cd ../telemetry && npm run build && cd ../ai && npm run build:offline && cd ../agent && npm run build && cd ../session-backends/sqlite-node && npm run build && cd ../../protocol && npm run build && cd ../client && npm run build && cd ../server && npm run build && cd ../coding-agent && npm run build",
"build": "cd packages/chord && npm run build && cd ../tui && npm run build && cd ../telemetry && npm run build && cd ../ai && npm run build && cd ../durable && npm run build && cd ../agent && npm run build && cd ../session-backends/sqlite-node && npm run build && cd ../../protocol && npm run build && cd ../client && npm run build && cd ../server && npm run build && cd ../coding-agent && npm run build",
"build:offline": "cd packages/chord && npm run build && cd ../tui && npm run build && cd ../telemetry && npm run build && cd ../ai && npm run build:offline && cd ../durable && npm run build && cd ../agent && npm run build && cd ../session-backends/sqlite-node && npm run build && cd ../../protocol && npm run build && cd ../client && npm run build && cd ../server && npm run build && cd ../coding-agent && npm run build",
"build:native:darwin": "npm --prefix packages/tui run build:native:darwin",
"build:native:linux": "npm --prefix packages/tui run build:native:linux",
"build:native:win32": "npm --prefix packages/tui run build:native:win32",
@@ -22,4 +22,4 @@ A foreground server uses repeatable `-e` options to establish its default Sessio
A host may reload selected facets when their declared service shape is unchanged; retained consumers keep the same service facades while replacement implementations and singleton snapshots are installed behind them. Synchronous setup-time `env.provide()`, `env.provideMany()`, `env.use()`, and `env.observe()` calls produce the internal dependency graph; setup does not repeat a declarative dependency list, and service handles remain disconnected until the complete graph validates. Providers activate before consumers, observations connect with their consuming facet, and facet replacement or host shutdown disposes affected lifecycles in reverse dependency order. Server and Session service tokens are non-local and automatically published by their providing host. Presentation-only hookpoints such as `SlashCommands` are explicitly local and never enter an RPC catalogue.
A facet always calls unqualified `env.use()` or `env.observe()`. The host resolves each token across facet-provided and connected services. The example plugin package contributes `/hello` through its TUI facet. `examples/plugins/pi-example-plugin/` is an actual `@earendil-works/pi-example-plugin` package: repeatable `-e` options select plugin packages as server defaults or for one Session branch, Chord discovers and builds their conventional facets, and the attached presentation receives matching TUI artifacts through `PresentationPlugins`. Other host facets from the same plugin remain separate bundle entries rather than one aggregate plugin object. Transport bindings remain internal machinery rather than part of the facet environment. `ExperimentalClientTui` currently owns terminal rendering, state subscriptions, navigation, and action dispatch directly. The server provider remains directly assembled until its complete host environment exists. The canvas, diff-review, and task-observation examples in `packages/agent/docs/pico-v5-chord-usage.md` are extension patterns, not built-in coding-agent services. Private references, trace carriers, and flow control remain protocol/host infrastructure slices rather than presentation service tokens.
A facet always calls unqualified `env.use()` or `env.observe()`. The host resolves each token across facet-provided and connected services. The example plugin package contributes `/hello` through its TUI facet. `examples/plugins/pi-example-plugin/` is an actual `@earendil-works/pi-example-plugin` package: repeatable `-e` options select plugin packages as server defaults or for one Session branch, Chord discovers and builds their conventional facets, and the attached presentation receives matching TUI artifacts through `PresentationPlugins`. Other host facets from the same plugin remain separate bundle entries rather than one aggregate plugin object. Transport bindings remain internal machinery rather than part of the facet environment. `ExperimentalClientTui` currently owns terminal rendering, state subscriptions, navigation, and action dispatch directly. The server provider remains directly assembled until its complete host environment exists. The canvas, diff-review, and task-observation examples in `packages/durable/docs/pico-v5-chord-usage.md` are extension patterns, not built-in coding-agent services. Private references, trace carriers, and flow control remain protocol/host infrastructure slices rather than presentation service tokens.
+7
View File
@@ -0,0 +1,7 @@
# Changelog
## [Unreleased]
### Added
- Added the initial Pico durable record contracts and detached in-memory storage implementation.
+15
View File
@@ -0,0 +1,15 @@
# @earendil-works/pi-durable
Durable conversation, task, and document runtime for Pi.
This package contains the Pico runtime. Its current public API provides the durable record contracts and detached in-memory storage implementation:
```ts
import { MemoryStorage, ROOT_CONVERSATION_ID } from "@earendil-works/pi-durable";
```
The normative design and implementation sequence are in:
- [`docs/pico-v5.md`](docs/pico-v5.md)
- [`docs/pico-v5-handoff.md`](docs/pico-v5-handoff.md)
- [`docs/pico-v5-chord-usage.md`](docs/pico-v5-chord-usage.md)
@@ -1,6 +1,6 @@
# Pico5 implementation handoff
`packages/agent/docs/pico-v5.md` is normative. Implement this list in order.
`packages/durable/docs/pico-v5.md` is normative. Implement this list in order.
After every package: run its tests, run `npm run check`, and stop for user review.
Do not redesign later packages while implementing the current one.
+52
View File
@@ -0,0 +1,52 @@
{
"name": "@earendil-works/pi-durable",
"version": "0.85.1",
"description": "Durable conversation, task, and document runtime for Pi",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"source": "./src/index.ts",
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"./package.json": "./package.json"
},
"sideEffects": false,
"files": [
"dist",
"docs",
"README.md"
],
"scripts": {
"clean": "shx rm -rf dist",
"build": "tsgo -p tsconfig.build.json",
"test": "vitest --run",
"prepublishOnly": "npm run clean && npm run build"
},
"keywords": [
"durable-execution",
"agents",
"conversations",
"tasks"
],
"author": "Earendil Works",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/earendil-works/pi.git",
"directory": "packages/durable"
},
"engines": {
"node": ">=22.19.0"
},
"dependencies": {
"@earendil-works/chord": "^0.85.1",
"@earendil-works/pi-ai": "^0.85.1"
},
"devDependencies": {
"shx": "0.4.0",
"vitest": "4.1.9"
}
}
@@ -1,7 +1,7 @@
import type { JsonValue } from "@earendil-works/chord";
import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
import { describe, expect, it } from "vitest";
import { MemoryStorage } from "../../src/pico/memory-storage.ts";
import { MemoryStorage } from "../src/memory-storage.ts";
import {
type EntryRecord,
type Id,
@@ -9,7 +9,7 @@ import {
ROOT_CONVERSATION_ID,
type StorageWrite,
type TaskRecord,
} from "../../src/pico/types.ts";
} from "../src/types.ts";
const context = BACKGROUND_CONTEXT;
type StoredTask = TaskRecord<JsonValue, JsonValue, JsonValue>;
+13
View File
@@ -0,0 +1,13 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"paths": {
"@earendil-works/chord": ["../chord/dist/index.d.ts"],
"@earendil-works/pi-ai": ["../ai/dist/index.d.ts"]
},
"rootDir": "./src"
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules", "dist", "**/*.d.ts", "src/**/*.d.ts"]
}
+1
View File
@@ -21,6 +21,7 @@ const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
const WORKSPACE = {
"@earendil-works/chord": "packages/chord/src",
"@earendil-works/pi-ai": "packages/ai/src",
"@earendil-works/pi-durable": "packages/durable/src",
"@earendil-works/pi-agent-core": "packages/agent/src",
"@earendil-works/pi-telemetry": "packages/telemetry/src",
"@earendil-works/pi-tui": "packages/tui/src",
+1
View File
@@ -10,6 +10,7 @@ const packages = [
{ directory: "packages/chord", name: "@earendil-works/chord" },
{ directory: "packages/telemetry", name: "@earendil-works/pi-telemetry" },
{ directory: "packages/ai", name: "@earendil-works/pi-ai" },
{ directory: "packages/durable", name: "@earendil-works/pi-durable" },
{ directory: "packages/tui", name: "@earendil-works/pi-tui" },
{ directory: "packages/agent", name: "@earendil-works/pi-agent-core" },
{ directory: "packages/protocol", name: "@earendil-works/pi-protocol" },
+2
View File
@@ -17,6 +17,8 @@
"@earendil-works/pi-ai/oauth": ["./packages/ai/src/oauth.ts"],
"@earendil-works/pi-ai/*": ["./packages/ai/src/*.ts", "./packages/ai/src/providers/*.ts"],
"@earendil-works/pi-ai/dist/*": ["./packages/ai/src/*"],
"@earendil-works/pi-durable": ["./packages/durable/src/index.ts"],
"@earendil-works/pi-durable/*": ["./packages/durable/src/*"],
"@earendil-works/pi-agent-core": ["./packages/agent/src/index.ts"],
"@earendil-works/pi-agent-core/harness/session/testing": [
"./packages/agent/src/harness/session/testing/index.ts"