diff --git a/.gitignore b/.gitignore index 9c94e80..f9aadef 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,9 @@ external/* *.tsbuildinfo coverage/ *.tgz +.wrangler/ .env .env.* !.env.example +.dev.vars +.dev.vars.* diff --git a/README.md b/README.md index f737007..886ace5 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,24 @@ # codex-js -`codex-js` is an unofficial TypeScript port of the Codex runtime for building -Codex-backed web apps and interfaces. +Unofficial TypeScript packages for building Codex-backed web applications. -The workspace publishes two npm packages: +This workspace publishes: -- `@jrkropp/codex-js`: core client, server, runtime, and testing utilities. -- `@jrkropp/codex-js-react`: React chat UI, shadcn-compatible primitives, and CSS. - -Examples show how a host application supplies credentials, storage, prompts, -tools, and routes. +- `@jrkropp/codex-js`: browser client, server app-server helpers, runtime contracts, stores, model transport, and testing utilities. +- `@jrkropp/codex-js-react`: React chat UI, hooks, shadcn-compatible primitives, and generated CSS. This project is not affiliated with, endorsed by, or sponsored by OpenAI. ## Install -```bash -pnpm add @jrkropp/codex-js +```sh +npm install @jrkropp/codex-js ``` -For React UI: +For the packaged React UI: -```bash -pnpm add @jrkropp/codex-js @jrkropp/codex-js-react react react-dom +```sh +npm install @jrkropp/codex-js @jrkropp/codex-js-react react react-dom ``` ```tsx @@ -31,7 +27,11 @@ import { CodexChat } from "@jrkropp/codex-js-react"; import "@jrkropp/codex-js-react/styles.css"; const appServer = createCodexAppServerClient({ - url: async () => getCodexAppServerWebSocketUrl(), + url: async () => { + const response = await fetch("/api/codex/session", { method: "POST" }); + const { webSocketUrl } = await response.json(); + return webSocketUrl; + }, }); export function Chat({ threadId }: { threadId: string }) { @@ -41,52 +41,97 @@ export function Chat({ threadId }: { threadId: string }) { ## Public Surfaces -- `@jrkropp/codex-js`: small root client conveniences. -- `@jrkropp/codex-js/client`: browser app-server WebSocket client and protocol event helpers. -- `@jrkropp/codex-js/server`: Codex runtime, app-server processors, stores, model transport, and server helpers. -- `@jrkropp/codex-js/testing`: test stores and package test helpers. -- `@jrkropp/codex-js-react`: React chat components, hooks, render state, and composer helpers. -- `@jrkropp/codex-js-react/shadcn`: optional shadcn primitives for chat layout composition. -- `@jrkropp/codex-js-react/styles.css`: generated package CSS. +Core package: + +- `@jrkropp/codex-js` +- `@jrkropp/codex-js/client` +- `@jrkropp/codex-js/server` +- `@jrkropp/codex-js/testing` + +React package: + +- `@jrkropp/codex-js-react` +- `@jrkropp/codex-js-react/shadcn` +- `@jrkropp/codex-js-react/styles.css` + +There are no public upstream mirror or unstable imports. + +## Server Shape + +```ts +import { + createCodexAppServer, + createModelClient, + defineDynamicTool, + dynamicToolResponse, +} from "@jrkropp/codex-js/server"; +import { InMemoryThreadStore } from "@jrkropp/codex-js/testing"; + +const lookupDeployment = defineDynamicTool({ + name: "lookup_deployment", + description: "Look up deployment status.", + inputSchema: { type: "object", properties: {}, additionalProperties: false }, + async execute() { + return dynamicToolResponse.text("Deployment is healthy."); + }, +}); + +const appServer = createCodexAppServer({ + threadStore: new InMemoryThreadStore(), + dynamicTools: [lookupDeployment], + defaults: { + cwd: "/workspace", + model: "gpt-5-mini", + modelProvider: "openai", + }, + createModelClient({ session, threadId }) { + return createModelClient({ + apiKey: process.env.OPENAI_API_KEY!, + installationId: "my-app", + sessionId: session.id, + threadId, + }); + }, +}); +``` + +Host applications own HTTP routing, authentication, persistence, credentials, and platform bindings. `codex-js` owns the Codex app-server protocol, connection processing, runtime contracts, and dynamic tool mapping. -## Development +## Examples -```bash +```sh pnpm install -pnpm external:sync --codex /path/to/codex --t3 /path/to/t3-chat +pnpm dev:node-local +pnpm dev:cloudflare-example +``` + +`examples/node-local` is the smallest full-stack local path: Vite, a Node WebSocket endpoint, `createCodexAppServer`, `createCodexAppServerConnection`, in-memory threads, and example dynamic tools. + +`examples/cloudflare` is the deployable production-style path: plain Vite React, Worker API, Durable Object SQLite storage, one-time WebSocket tickets, hibernating Durable Object WebSockets, and server-executed dynamic tools. + +## Checks + +```sh pnpm typecheck +pnpm lint +pnpm build pnpm test pnpm test:pack -pnpm build pnpm publint pnpm pack:dry-run -pnpm dev:minimal +pnpm build:examples ``` -Upstream reference source should stay local and unchecked-in under -`external/`. The recommended setup is to sync local Codex and T3 source trees -into `external/codex` and `external/t3code` with `pnpm external:sync`, then keep -publishable package code inside the tracked `packages/*/src` trees. - ## Releases This repo uses Changesets. Add a changeset for user-visible changes: -```bash +```sh pnpm changeset ``` -Merging the Changesets release PR updates `CHANGELOG.md`, bumps package -versions, publishes to npm, and creates the GitHub release. - -Releases use npm trusted publishing. Existing package names can publish through -OIDC from `.github/workflows/release.yml`; brand-new package names must be -bootstrapped once with an npm token or a manual first publish before trusted -publishing can be configured for them. Run `pnpm release:preflight` to catch -that state before a release can partially publish. +Merging the Changesets release PR updates changelogs, publishes to npm, and creates the GitHub release. Releases use npm trusted publishing through GitHub Actions. ## License And Attribution -`codex-js` is licensed under Apache-2.0. Portions are modified TypeScript ports -of OpenAI Codex, which is also Apache-2.0. T3-derived UI code is used under the -T3 Tools MIT license. See `LICENSE` and `NOTICE`. +`codex-js` is licensed under Apache-2.0. Portions are modified TypeScript ports of OpenAI Codex, which is also Apache-2.0. T3-derived UI code is used under the T3 Tools MIT license. See `LICENSE` and `NOTICE`. diff --git a/docs/AGENTS.md b/docs/AGENTS.md index 7d7fd8b..acb8751 100644 --- a/docs/AGENTS.md +++ b/docs/AGENTS.md @@ -8,11 +8,11 @@ This documentation describes the intended production design of `@jrkropp/codex-j - Establish durable primitives before implementation details. - Keep the public model small, standard, and composable. -- Treat `src/upstream/codex-rs` as a Codex-shaped upstream source and `src/upstream/t3code` as a T3-shaped upstream source. Codex and T3 are proven source references; follow their folder structure, naming, concepts, classes, contracts, and lifecycle patterns as closely as practical. -- Keep package-owned abstractions outside the upstream trees. +- Treat `external/codex` as the Codex terminology and lifecycle source of truth. +- Keep publishable package code semantic and boring: `client`, `server`, `testing`, `internal`, `generated`, `components`, `hooks`, and `shadcn`. - `ThreadStore` is the storage boundary. Product grouping, account boundaries, workspace selection, and deployment placement are not package primitives. - Runtime delivery follows Codex's server names: `OutgoingMessageSender`, `ThreadScopedOutgoingMessageSender`, `ThreadState`, and `ThreadStateManager`. -- Examples use the public doorways: `CodexChat`, `createCodexAppServerClient`, `CodexAppServerMessageProcessor`, `createCodexAppServerRuntime`, `ThreadStore`, `createModelClient`, and `sendOutgoingMessage`. +- Examples use the public doorways: `CodexChat`, `createCodexAppServerClient`, `createCodexAppServer`, `ThreadStore`, `createModelClient`, and dynamic tool helpers. - When behavior is wrong or unclear, compare against Codex or T3 first. If local code differs, realign it with the source reference instead of inventing a custom fix. - Prefer precise names over broad abstractions. - Separate accepted docs from staged thinking. @@ -20,10 +20,8 @@ This documentation describes the intended production design of `@jrkropp/codex-j ## Source References -- Codex source reference: `/Users/justinkropp/Github/host-app/external/codex` -- T3 source reference: `/Users/justinkropp/Github/host-app/external/t3code` -- Package Codex upstream source: `/Users/justinkropp/Github/host-app/packages/codex-js/src/upstream/codex-rs` -- Package T3 upstream source: `/Users/justinkropp/Github/host-app/packages/codex-js/src/upstream/t3code` +- Codex source reference: `/Users/justinkropp/Github/codex-js/external/codex` +- T3 source reference: `/Users/justinkropp/Github/codex-js/external/t3code` The `external/` directories are read-only. Do not import from them, edit them, or treat them as package source. @@ -38,12 +36,14 @@ The `external/` directories are read-only. Do not import from them, edit them, o ## Folder Structure -- `src/upstream/codex-rs/`: Codex-shaped upstream source tree. -- `src/upstream/t3code/`: T3-shaped upstream source tree. -- `src/runtime/`: platform-neutral Codex lifecycle code and contracts. -- `src/components/`: stable public React component surface. -- `src/hooks/`: stable public React hooks. -- `src/testing/`: package and consumer testing utilities. +- `packages/codex-js/src/client/`: browser app-server client facade. +- `packages/codex-js/src/server/`: platform-neutral app-server helpers. +- `packages/codex-js/src/testing/`: package and consumer testing utilities. +- `packages/codex-js/src/internal/`: implemented Codex ports and package internals. +- `packages/codex-js/src/generated/`: generated protocol surfaces. +- `packages/codex-js-react/src/components/`: stable public React component surface. +- `packages/codex-js-react/src/hooks/`: stable public React hooks. +- `packages/codex-js-react/src/shadcn/`: shadcn-compatible primitives. - `start-here/`: short onboarding path for the package model, philosophy, and primitives. - `architecture/`: accepted architecture notes and deeper system explanations. - `design/decisions/`: accepted ADR-style decisions. diff --git a/docs/README.md b/docs/README.md index 7e8ffcb..91a03f9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,18 +9,27 @@ Exploratory proposals live in [Staging](./staging/README.md) until their termino ## Package Source ```text -src/ - upstream/ - codex-rs/ - t3code/ - - runtime/ - components/ - hooks/ - testing/ +packages/ + codex-js/ + src/client/ + src/server/ + src/testing/ + src/internal/ + src/generated/ + + codex-js-react/ + src/components/ + src/hooks/ + src/shadcn/ + src/styles.css + +external/ + codex/ + t3code/ ``` -The source structure is accepted in [ADR 0001](./design/decisions/0001-package-source-structure.md). +Publishable source lives in `packages/*/src`. Source reference material lives in +`external/` or `docs/internal/` and is not part of the npm package surface. ## Documentation Areas diff --git a/docs/design/decisions/0001-package-source-structure.md b/docs/design/decisions/0001-package-source-structure.md index 1fab786..39eb189 100644 --- a/docs/design/decisions/0001-package-source-structure.md +++ b/docs/design/decisions/0001-package-source-structure.md @@ -4,44 +4,52 @@ Status: accepted ## Context -`@jrkropp/codex-js` is a Codex runtime and UI kit. The package needs a source layout that makes upstream source trees obvious, keeps package-owned runtime code separate, and lets consuming applications extend behavior without editing package source. +The workspace publishes a core Codex SDK and a separate React UI package. The +source layout should look like a conventional npm workspace, not like an +extracted application or a public mirror of reference repositories. -Codex and T3 are source references. Their folder structure, naming, concepts, classes, contracts, and lifecycle boundaries are preserved as closely as practical so updates can be ported by comparing the corresponding source files. +Codex remains the terminology and runtime source of truth, but reference +material belongs outside publishable package source. ## Decision -The package source is organized around upstream source trees, a package-owned runtime, React components, React hooks, and testing utilities. +The workspace uses two packages: ```text -src/ - upstream/ - codex-rs/ - t3code/ - - runtime/ - components/ - hooks/ - testing/ +packages/ + codex-js/ + src/client/ + src/server/ + src/testing/ + src/internal/ + src/generated/ + + codex-js-react/ + src/components/ + src/hooks/ + src/shadcn/ + src/styles.css ``` -`src/upstream/codex-rs` is the Codex-shaped runtime upstream source. `src/upstream/t3code` is the T3-shaped chat UI upstream source. Code in these trees follows upstream names, file boundaries, contracts, and lifecycle patterns. +`packages/codex-js` is dependency-light and non-React. It owns browser client +helpers, platform-neutral app-server helpers, runtime contracts, store +contracts, model-client creation, dynamic tool mapping, and testing utilities. -`src/runtime` contains package-owned, platform-neutral Codex lifecycle code and contracts. It does not depend on React, routing, Cloudflare, Durable Objects, host application projects, or host-app business behavior. +`packages/codex-js-react` owns React components, hooks, shadcn-compatible +primitives, generated CSS, and React-only dependencies. -`src/components` contains the stable public React component surface built from the T3 upstream source. Developers import application-facing chat components from `components` rather than from the upstream tree. - -`src/hooks` contains the stable public React hooks that bind a configured runtime to React applications. Hooks stay separate from components so developers can use the runtime with their own UI. - -`src/testing` contains test utilities and lightweight helpers for package consumers and package tests. - -Platform-specific implementation details are not source primitives. Cloudflare Workers, Durable Objects, browser storage, routing, credentials, tools, prompts, and product-specific renderers live in consuming applications or documentation guides. +Reference and parity material lives in `external/`, `reference/`, or +`docs/internal/`. It is not exposed through package exports or included in npm +tarballs. ## Consequences -Upstream-shaped code is visually isolated from package-owned code. Package-owned abstractions stay outside the upstream trees. - -The package remains replaceable. Consuming applications extend behavior through composition, contracts, slots, renderers, tools, prompts, storage, and app-server boundaries instead of modifying package source. +Public imports are boring and semantic. Consumers use `/client`, `/server`, +`/testing`, the React package root, `/shadcn`, and `/styles.css`. -A Durable Object is one possible implementation of a Codex store and app-server boundary. It is not a primitive of the Codex assistant package. +Cloudflare Workers, Durable Objects, local files, databases, credentials, auth, +prompts, and product-specific tools remain host application concerns. -When behavior is wrong or unclear, the first step is to compare against Codex or T3 and realign the package with the corresponding source reference. +When behavior is wrong or unclear, compare against Codex terminology and +lifecycle concepts, then implement the package-facing API in the conventional +package folders. diff --git a/docs/design/decisions/0002-core-runtime-boundary.md b/docs/design/decisions/0002-core-runtime-boundary.md index f3356e3..fc7ee82 100644 --- a/docs/design/decisions/0002-core-runtime-boundary.md +++ b/docs/design/decisions/0002-core-runtime-boundary.md @@ -26,7 +26,10 @@ Core `EventMsg` values are runtime and storage internals. App-server implementat React chat state reduces generated app-server protocol events into `ThreadEventStore`. Hooks and components render `ThreadEventSnapshot` state derived from generated `Thread`, `Turn`, `ThreadItem`, `ServerNotification`, and `ServerRequest` values. Core events remain below the app-server boundary. -Protocol state belongs in `src/runtime`; T3 projection belongs at the component boundary. The runtime reducer does not import T3 timeline types. Components create `CodexChatRenderState` from protocol snapshots and lifecycle UI state before rendering the T3-derived timeline, composer, banners, and pending-request slots. +Protocol state belongs in the core package runtime internals. React projection +belongs in `@jrkropp/codex-js-react`. Components create +`CodexChatRenderState` from protocol snapshots and lifecycle UI state before +rendering the timeline, composer, banners, and pending-request slots. The package model uses Codex-shaped terms: @@ -57,10 +60,11 @@ Product grouping, account boundaries, workspace selection, and deployment placem The package layers remain explicit: -- `src/upstream/codex-rs` is the faithful Codex runtime upstream source. -- `src/runtime` contains platform-neutral lifecycle contracts around Codex concepts. -- `src/components` contains the stable T3-derived React component surface. -- `src/hooks` contains React hooks around a configured runtime. +- `packages/codex-js/src/client` contains browser app-server client helpers. +- `packages/codex-js/src/server` contains platform-neutral app-server helpers. +- `packages/codex-js/src/internal` contains implemented Codex ports and internals. +- `packages/codex-js-react/src/components` contains the stable React component surface. +- `packages/codex-js-react/src/hooks` contains React hooks around a configured app-server client. - The consuming app owns storage, routing, auth, tools, prompts, product renderers, and deployment. The app server runs Codex. The store remembers Codex. The UI renders Codex as generated app-server snapshots and live events. diff --git a/docs/design/decisions/0003-public-runtime-contract.md b/docs/design/decisions/0003-public-runtime-contract.md index 4517ffc..8204d45 100644 --- a/docs/design/decisions/0003-public-runtime-contract.md +++ b/docs/design/decisions/0003-public-runtime-contract.md @@ -4,7 +4,10 @@ Status: accepted ## Context -`@jrkropp/codex-js` exposes a public package surface on top of two upstream source trees: Codex for runtime semantics and T3 for chat interaction ownership. The public contract must stay small enough to understand quickly while remaining faithful to those source systems. +`@jrkropp/codex-js` exposes a public package surface for Codex runtime semantics. +`@jrkropp/codex-js-react` exposes the React presentation surface. The public +contract must stay small enough to understand quickly while remaining faithful +to Codex terminology. The package surface contains ergonomic concepts only where they clarify usage without creating a second runtime model. The pressure test compares the public surface against Codex primitives, T3 lifecycle ownership, and common consuming application shapes. @@ -37,49 +40,52 @@ T3 terms define the React chat lifecycle boundary. Optimistic rows, local dispat The canonical public import paths are: +- `@jrkropp/codex-js` +- `@jrkropp/codex-js/client` - `@jrkropp/codex-js/server` -- `@jrkropp/codex-js/react` -- `@jrkropp/codex-js/react` +- `@jrkropp/codex-js/testing` +- `@jrkropp/codex-js-react` +- `@jrkropp/codex-js-react/shadcn` +- `@jrkropp/codex-js-react/styles.css` -The package root is a small plug-and-play chat entrypoint. It does not flatten -runtime, hook, component, Codex mirror, or T3 mirror exports into one namespace. - -The Codex and T3 upstream source import paths remain available for advanced use, but app-facing code should prefer the canonical package surfaces. +The package roots are small. They do not flatten runtime, hook, component, or +reference-source exports into one namespace. Reference-source paths are not +public imports. ## Public Surface Classification -| Concept | Classification | Decision | -| --- | --- | --- | -| `ThreadStore` | Codex-native | Use the Codex-shaped store contract as the storage boundary. | -| `ThreadReader` | Codex store read view | Use for store-only and headless hydration when hooks need only `readThread` and `loadHistory`. | -| `LiveThread` | Codex-native | Use for live thread lifecycle and store-backed thread operations. | -| `ClientRequest` | Codex app-server protocol | Use for typed client-to-server app-server method calls. | -| `ServerNotification` | Codex app-server protocol | Use for typed server-to-client notification flow. | -| `ServerRequest` | Codex app-server protocol | Use for server-to-client requests that require request-id resolution. | -| `RequestId` | Codex app-server protocol | Use to resolve or reject server requests. | -| `AppServerSession` | Codex app-server client helper | Own request-id lifecycle and typed lifecycle helpers over generated `ClientRequest` values. | -| `PendingAppServerRequests` | Codex app-server request state | Own pending UI state keyed by `RequestId`. | -| `ThreadEventStore` | Codex app-server protocol state | Own generated `Thread`, `Turn`, `ThreadItem`, pending server request, warning, error, active-turn, and connection state for chat UI. | -| `ThreadEventSnapshot` | Codex app-server protocol state | Expose immutable protocol-native state to hooks and components. | -| `Submission` | Codex-native | Use inside Codex runtime/session internals, not as the public UI response contract. | -| `Event` and `EventMsg` | Codex-native | Use for core runtime event flow inside runtime and storage internals. | -| `ThreadHistoryBuilder` | Codex-native | Use for low-level history projection. | -| `RenderedThreadState` | Codex-native projection | Keep as a low-level core projection, not the primary app-facing chat state. | -| `CodexChatRuntimeOptions` | Component ergonomic facade | Configure an app-server-backed chat runtime with optional thread and optional store reader fallback. | -| `CodexAppServer` | Codex app-server boundary | Shape around Codex generated `ClientRequest`, `ServerNotification`, `ServerRequest`, `RequestId`, event streaming, and request-id resolution; hide route, credential, WebSocket, and platform details in the host adapter. | -| Component and hook props | React ergonomics | Keep package-name-neutral and store-centered. | -| Draft helpers | T3 lifecycle/app routing | Keep in `hooks` or host-app glue unless they operate only on Codex data. | -| Local dispatch helpers | T3 lifecycle | Keep with chat lifecycle code, close to `ChatView` and composer ownership. | +| Concept | Classification | Decision | +| -------------------------- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `ThreadStore` | Codex-native | Use the Codex-shaped store contract as the storage boundary. | +| `ThreadReader` | Codex store read view | Use for store-only and headless hydration when hooks need only `readThread` and `loadHistory`. | +| `LiveThread` | Codex-native | Use for live thread lifecycle and store-backed thread operations. | +| `ClientRequest` | Codex app-server protocol | Use for typed client-to-server app-server method calls. | +| `ServerNotification` | Codex app-server protocol | Use for typed server-to-client notification flow. | +| `ServerRequest` | Codex app-server protocol | Use for server-to-client requests that require request-id resolution. | +| `RequestId` | Codex app-server protocol | Use to resolve or reject server requests. | +| `AppServerSession` | Codex app-server client helper | Own request-id lifecycle and typed lifecycle helpers over generated `ClientRequest` values. | +| `PendingAppServerRequests` | Codex app-server request state | Own pending UI state keyed by `RequestId`. | +| `ThreadEventStore` | Codex app-server protocol state | Own generated `Thread`, `Turn`, `ThreadItem`, pending server request, warning, error, active-turn, and connection state for chat UI. | +| `ThreadEventSnapshot` | Codex app-server protocol state | Expose immutable protocol-native state to hooks and components. | +| `Submission` | Codex-native | Use inside Codex runtime/session internals, not as the public UI response contract. | +| `Event` and `EventMsg` | Codex-native | Use for core runtime event flow inside runtime and storage internals. | +| `ThreadHistoryBuilder` | Codex-native | Use for low-level history projection. | +| `RenderedThreadState` | Codex-native projection | Keep as a low-level core projection, not the primary app-facing chat state. | +| `CodexChatRuntimeOptions` | Component ergonomic facade | Configure an app-server-backed chat runtime with optional thread and optional store reader fallback. | +| `CodexAppServer` | Codex app-server boundary | Shape around Codex generated `ClientRequest`, `ServerNotification`, `ServerRequest`, `RequestId`, event streaming, and request-id resolution; hide route, credential, WebSocket, and platform details in the host adapter. | +| Component and hook props | React ergonomics | Keep package-name-neutral and store-centered. | +| Draft helpers | T3 lifecycle/app routing | Keep in `hooks` or host-app glue unless they operate only on Codex data. | +| Local dispatch helpers | T3 lifecycle | Keep with chat lifecycle code, close to `ChatView` and composer ownership. | ## Pressure Test Findings -| Scenario | Required package concepts | Host-owned concepts | Result | -| --- | --- | --- | --- | -| Local file-backed app | `ThreadStore`, `LiveThread`, `Submission`, `ThreadEventStore`, hooks or components | Local file paths, user identity, persistence location | Passes when the store is configured before entering runtime. | -| Cloudflare Durable Object app | Same runtime concepts plus an app-server implementation | Durable Object naming, bindings, auth, routing, deployment | Passes when Durable Object placement is hidden behind store and app-server boundaries. | -| Custom product app | Runtime plus renderer/tool/prompt extension points | Product prompts, tools, auth, renderers, route paths | Passes when extensions enter through composition rather than package source edits. | -| Headless app | `runtime` and `hooks` | Entire UI | Passes when hooks expose state/actions without requiring package components. | -| Plug-and-play app | `components` with configured reader and app server | Store, reader, and app-server construction | Passes when the component API does not expose routes, Cloudflare, deployment placement, or T3 internals. | +| Scenario | Required package concepts | Host-owned concepts | Result | +| ----------------------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | +| Local file-backed app | `ThreadStore`, `LiveThread`, `Submission`, `ThreadEventStore`, hooks or components | Local file paths, user identity, persistence location | Passes when the store is configured before entering runtime. | +| Cloudflare Durable Object app | Same runtime concepts plus an app-server implementation | Durable Object naming, bindings, auth, routing, deployment | Passes when Durable Object placement is hidden behind store and app-server boundaries. | +| Custom product app | Runtime plus renderer/tool/prompt extension points | Product prompts, tools, auth, renderers, route paths | Passes when extensions enter through composition rather than package source edits. | +| Headless app | `runtime` and `hooks` | Entire UI | Passes when hooks expose state/actions without requiring package components. | +| Plug-and-play app | `components` with configured reader and app server | Store, reader, and app-server construction | Passes when the component API does not expose routes, Cloudflare, deployment placement, or T3 internals. | ## Consequences diff --git a/packages/codex-js/CODEX_PARITY_LEDGER.json b/docs/internal/CODEX_PARITY_LEDGER.json similarity index 99% rename from packages/codex-js/CODEX_PARITY_LEDGER.json rename to docs/internal/CODEX_PARITY_LEDGER.json index 007bee7..a4e264d 100644 --- a/packages/codex-js/CODEX_PARITY_LEDGER.json +++ b/docs/internal/CODEX_PARITY_LEDGER.json @@ -1,13 +1,13 @@ { "schema": "codex-rs-typescript-parity-ledger.v1", - "referenceRoot": ".reference/codex/codex-rs", + "referenceRoot": "external/codex/codex-rs", "mirrorRoot": "packages/codex-js/src/upstream/codex-rs", "totals": { "referenceCrates": 89, "referenceRustFiles": 1818, - "implemented": 139, + "implemented": 150, "platform_adaptation": 0, - "stubbed": 1679, + "stubbed": 1668, "missing": 0 }, "crates": [ @@ -204,14 +204,14 @@ "crate": "app-server-client", "referencePath": "app-server-client/src/lib.rs", "mirrorPath": "app-server-client/src/lib.ts", - "reason": "shared app-server client facade and typed request helpers ported to TypeScript", + "reason": "not ported yet", "status": "implemented" }, { "crate": "app-server-client", "referencePath": "app-server-client/src/remote.rs", "mirrorPath": "app-server-client/src/remote.ts", - "reason": "websocket-backed remote app-server client ported to TypeScript", + "reason": "not ported yet", "status": "implemented" }, { @@ -540,7 +540,7 @@ "crate": "app-server-transport", "referencePath": "app-server-transport/src/outgoing_message.rs", "mirrorPath": "app-server-transport/src/outgoing_message.ts", - "reason": "transport-level outgoing message types ported to TypeScript", + "reason": "not ported yet", "status": "implemented" }, { @@ -554,7 +554,7 @@ "crate": "app-server-transport", "referencePath": "app-server-transport/src/transport/mod.rs", "mirrorPath": "app-server-transport/src/transport/mod.ts", - "reason": "JSON-RPC transport parsing and serialization ported to TypeScript", + "reason": "not ported yet", "status": "implemented" }, { @@ -657,8 +657,8 @@ }, { "crate": "app-server", - "referencePath": "app-server/src/bespoke_event_handling.rs", - "mirrorPath": "app-server/src/bespoke_event_handling.ts", + "referencePath": "app-server/src/app_server_event_mapping.rs", + "mirrorPath": "app-server/src/app_server_event_mapping.ts", "reason": "not ported yet", "status": "implemented" }, @@ -827,7 +827,7 @@ "crate": "app-server", "referencePath": "app-server/src/request_processors.rs", "mirrorPath": "app-server/src/request_processors.ts", - "reason": "ported TypeScript app-server request processor", + "reason": "native process", "status": "implemented" }, { @@ -939,7 +939,7 @@ "crate": "app-server", "referencePath": "app-server/src/request_processors/mcp_processor.rs", "mirrorPath": "app-server/src/request_processors/mcp_processor.ts", - "reason": "ported TypeScript app-server request processor", + "reason": "native process", "status": "implemented" }, { @@ -960,7 +960,7 @@ "crate": "app-server", "referencePath": "app-server/src/request_processors/request_errors.rs", "mirrorPath": "app-server/src/request_processors/request_errors.ts", - "reason": "ported TypeScript app-server request processor", + "reason": "native process", "status": "implemented" }, { @@ -995,7 +995,7 @@ "crate": "app-server", "referencePath": "app-server/src/request_processors/thread_processor.rs", "mirrorPath": "app-server/src/request_processors/thread_processor.ts", - "reason": "ported TypeScript app-server request processor", + "reason": "native process", "status": "implemented" }, { @@ -1023,7 +1023,7 @@ "crate": "app-server", "referencePath": "app-server/src/request_processors/turn_processor.rs", "mirrorPath": "app-server/src/request_processors/turn_processor.ts", - "reason": "ported TypeScript app-server request processor", + "reason": "native process", "status": "implemented" }, { @@ -1058,7 +1058,7 @@ "crate": "app-server", "referencePath": "app-server/src/thread_state.rs", "mirrorPath": "app-server/src/thread_state.ts", - "reason": "Thread subscription and connection state manager ported to TypeScript", + "reason": "not ported yet", "status": "implemented" }, { @@ -1079,7 +1079,7 @@ "crate": "app-server", "referencePath": "app-server/src/transport.rs", "mirrorPath": "app-server/src/transport.ts", - "reason": "App-server transport facade points at app-server-transport mirror", + "reason": "not ported yet", "status": "implemented" }, { @@ -2682,15 +2682,15 @@ "crate": "codex-mcp", "referencePath": "codex-mcp/src/auth_elicitation.rs", "mirrorPath": "codex-mcp/src/auth_elicitation.ts", - "reason": "Codex Apps connector auth failure parsing, auth elicitation planning, completed-result shaping, and elicitation messages are ported.", + "reason": "not ported yet", "status": "implemented" }, { "crate": "codex-mcp", "referencePath": "codex-mcp/src/codex_apps.rs", "mirrorPath": "codex-mcp/src/codex_apps.ts", - "reason": "Codex Apps catalog cache and connector normalization are ported; filesystem cache storage is adapted behind a package storage interface.", - "status": "platform_adaptation" + "reason": "not ported yet", + "status": "implemented" }, { "crate": "codex-mcp", @@ -2703,29 +2703,29 @@ "crate": "codex-mcp", "referencePath": "codex-mcp/src/connection_manager.rs", "mirrorPath": "codex-mcp/src/connection_manager.ts", - "reason": "Live MCP manager aggregation, startup snapshot behavior, raw tool routing, resource delegation, transport-origin helpers, and startup error display are ported; native server startup is provided through platform RmcpClientLike adapters.", - "status": "platform_adaptation" + "reason": "not ported yet", + "status": "implemented" }, { "crate": "codex-mcp", "referencePath": "codex-mcp/src/elicitation.rs", "mirrorPath": "codex-mcp/src/elicitation.ts", - "reason": "Elicitation request tracking, policy rejection, auto-deny, empty-form auto-accept, reviewer short-circuiting, event emission, and response resolution are ported.", + "reason": "not ported yet", "status": "implemented" }, { "crate": "codex-mcp", "referencePath": "codex-mcp/src/lib.rs", "mirrorPath": "codex-mcp/src/lib.ts", - "reason": "Crate-level TypeScript exports mirror the ported codex-mcp modules.", + "reason": "not ported yet", "status": "implemented" }, { "crate": "codex-mcp", "referencePath": "codex-mcp/src/mcp/auth.rs", "mirrorPath": "codex-mcp/src/mcp/auth.ts", - "reason": "OAuth support detection, auth status calculation, scope resolution precedence, and retry-without-scopes checks are ported; discovery uses Web fetch as a platform adaptation.", - "status": "platform_adaptation" + "reason": "not ported yet", + "status": "implemented" }, { "crate": "codex-mcp", @@ -2738,15 +2738,15 @@ "crate": "codex-mcp", "referencePath": "codex-mcp/src/mcp/mod.rs", "mirrorPath": "codex-mcp/src/mcp/mod.ts", - "reason": "MCP tool name constants and Responses tool-name sanitization helpers are ported.", + "reason": "not ported yet", "status": "implemented" }, { "crate": "codex-mcp", "referencePath": "codex-mcp/src/rmcp_client.rs", "mirrorPath": "codex-mcp/src/rmcp_client.ts", - "reason": "ManagedClient, AsyncManagedClient, startup snapshots, tool listing, Codex Apps cache use, plugin provenance annotation, and basic client delegation are ported; native process/HTTP construction is a platform adapter.", - "status": "platform_adaptation" + "reason": "not ported yet", + "status": "implemented" }, { "crate": "codex-mcp", @@ -2759,7 +2759,7 @@ "crate": "codex-mcp", "referencePath": "codex-mcp/src/tools.rs", "mirrorPath": "codex-mcp/src/tools.ts", - "reason": "MCP tool filtering, file-parameter schema masking, qualification, collision handling, and callable-name length guards are ported.", + "reason": "not ported yet", "status": "implemented" }, { @@ -4664,7 +4664,7 @@ "referencePath": "core/src/state/session.rs", "mirrorPath": "core/src/state/session.ts", "reason": "not ported yet", - "status": "stubbed" + "status": "implemented" }, { "crate": "core", @@ -4685,7 +4685,7 @@ "referencePath": "core/src/stream_events_utils.rs", "mirrorPath": "core/src/stream_events_utils.ts", "reason": "not ported yet", - "status": "stubbed" + "status": "implemented" }, { "crate": "core", diff --git a/docs/internal/CODEX_PARITY_LEDGER.md b/docs/internal/CODEX_PARITY_LEDGER.md new file mode 100644 index 0000000..7d7a88b --- /dev/null +++ b/docs/internal/CODEX_PARITY_LEDGER.md @@ -0,0 +1,66 @@ +# Codex Runtime Parity Ledger + +This package contains modified TypeScript ports and platform adaptations of +OpenAI Codex source files. OpenAI Codex is licensed under Apache-2.0; attribution +is retained in `NOTICE`. + +This ledger records the package subsystems that intentionally mirror Codex. It +is the working checklist for keeping the TypeScript runtime aligned with +`external/codex/codex-rs` while keeping host application behavior outside the +package. + +The ownership model stays explicit: Codex owns runtime truth, T3 owns +interaction quality, and host apps own product meaning. + +The whole-workspace structural inventory is generated by +`npm --workspace @jrkropp/codex-js run codex:mirror` and stored +in `CODEX_PARITY_LEDGER.json`. The current mirror covers 89 reference crates and +1,818 Rust source files with no `missing` rows: implemented files remain +functional TypeScript ports, unsupported native/CLI/TUI surfaces compile as +shared `UnsupportedCodexFeatureError` stubs, and future ports move rows from +`stubbed` to `implemented` or `platform_adaptation`. + +| Subsystem | Package Path | Codex Reference | Status | Notes | +| --- | --- | --- | --- | --- | +| Model client | `src/upstream/codex-rs/core/src/client.ts` | `external/codex/codex-rs/core/src/client.rs` | Mirrored with platform adaptation | Session-scoped `ModelClient`, turn-scoped `ModelClientSession`, WebSocket-first streaming, HTTP/SSE sticky fallback, prewarm, incremental `previous_response_id`, and best-effort `response.processed` follow Codex. Fetch/WebSocket primitives are Worker-compatible TypeScript adaptations. | +| Responses transport | `src/upstream/codex-rs/codex-api/src/endpoint/responses.ts` and `responses_websocket.ts` | `external/codex/codex-rs/codex-api/src/endpoint/responses.rs` and `responses_websocket.rs` | Mirrored with platform adaptation | The package preserves Codex endpoint split: Responses HTTP/SSE fallback and Responses-over-WebSocket primary transport. Cloudflare `fetch` upgrade replaces Rust client plumbing. | +| Request wire shape | `src/upstream/codex-rs/codex-api/src/common.ts` and `requests/responses.ts` | `external/codex/codex-rs/codex-api/src/common.rs` and `requests/responses.rs` | Mirrored | Optional request fields are omitted from wire payloads like Rust `skip_serializing_if`. `prompt_cache_key` is thread id for normal and compaction requests. | +| Token usage | `src/upstream/codex-rs/codex-api/src/sse/responses.ts` and `src/upstream/codex-rs/core/src/session/session.ts` | `external/codex/codex-rs/codex-api/src/sse/responses.rs` and `core/src/session/session.rs` | Mirrored | Cached tokens come only from `usage.input_tokens_details.cached_tokens`; reasoning tokens come only from `usage.output_tokens_details.reasoning_tokens`; accumulation uses `TokenUsageInfo`. | +| Context updates | `src/upstream/codex-rs/core/src/context` and `src/upstream/codex-rs/core/src/session/session.ts` | `external/codex/codex-rs/core/src/context` and `core/src/session/session.rs` | Mirrored with known gaps | Runtime order matches Codex: context updates are recorded before the user message, and prompts are built from persisted history. Additional Codex context sections are tracked as explicit expansion work. | +| Context manager | `src/upstream/codex-rs/core/src/context_manager` | `external/codex/codex-rs/core/src/context_manager` | Mirrored | `ContextManager.record_items` truncates `function_call_output` and `custom_tool_call_output` before history storage; `for_prompt` normalizes missing/orphan call outputs and strips image content for text-only models; `replace` is an exact rewrite used by compaction and rollback. | +| Session state | `src/upstream/codex-rs/core/src/state/session.ts` | `external/codex/codex-rs/core/src/state/session.rs` | Mirrored with platform adaptation | `SessionState` owns live `ContextManager`, previous turn settings, reference context, token info, rate limits, and server-reasoning accounting while rollout remains the durable cold-start source. | +| Compaction | `src/upstream/codex-rs/core/src/compact-task-runner.ts`, `tasks/compact.ts`, and `compact.ts` | `external/codex/codex-rs/core/src/compact*` and `tasks/compact.rs` | Mirrored with known gaps | Compaction replaces history and advances the model-client window generation. Remaining work is tighter parity for Codex’s full compaction prompt surface. | +| Stream events | `src/upstream/codex-rs/core/src/stream_events_utils.ts` | `external/codex/codex-rs/core/src/stream_events_utils.rs` | Mirrored with platform adaptation | Completed model items, tool-call recording, tool-output recording, follow-up detection, Plan Mode stream parsing, and missing local-shell id responses live in `stream_events_utils`. `session/turn.ts` drives streaming and rebuilds follow-up prompts from live `SessionState.history`. | +| Tool search and spec planning | `src/upstream/codex-rs/core/src/tools/spec.ts`, `spec_plan.ts`, `handlers/tool_search.ts`, and `tools/tool_search_entry.ts` | `external/codex/codex-rs/core/src/tools/spec.rs`, `spec_plan.rs`, `handlers/tool_search.rs`, and `tool_search_entry.rs` | Mirrored with platform adaptation | Deferred dynamic and MCP tools use Codex namespace gating, BM25 search, source info, bucket limits, and history-based follow-up. Deferred MCP handlers are registered for discovered tools, and unavailable previously-called tools get Codex-style placeholder specs. | +| MCP catalog and resources | `src/upstream/codex-rs/core/src/mcp`, `tools/handlers/mcp.ts`, and `tools/handlers/mcp_resource*` | `external/codex/codex-rs/codex-mcp/src/tools.rs`, `codex-mcp/src/codex_apps.rs`, `core/src/tools/handlers/mcp.rs`, and `core/src/tools/handlers/mcp_resource*` | Mirrored with platform adaptation | MCP metadata separates raw server/tool routing from model-visible qualified callable names, carries connector and plugin provenance for search, exposes Codex resource list/read tools when MCP tools are present, caches Codex Apps catalogs by user key, filters disallowed connectors, and emits MCP tool-call lifecycle events for resource operations. | +| MCP connection manager | `src/upstream/codex-rs/codex-mcp/src/connection_manager.ts`, `rmcp_client.ts`, and `core/src/mcp/manager.ts` | `external/codex/codex-rs/codex-mcp/src/connection_manager.rs` and `rmcp_client.rs` | Mirrored with platform adaptation | The package now has Codex-shaped per-server managed clients, startup snapshot reads, live catalog aggregation, hard Codex Apps refresh, raw tool-call routing, resource aggregation, startup error helpers, transport-origin helpers, and a core adapter. Native stdio/HTTP process startup remains host/platform-provided through `RmcpClientLike`. | +| MCP auth and elicitation | `src/upstream/codex-rs/codex-mcp/src/mcp/auth.ts`, `elicitation.ts`, and `auth_elicitation.ts` | `external/codex/codex-rs/codex-mcp/src/mcp/auth.rs`, `elicitation.rs`, and `auth_elicitation.rs` | Mirrored with platform adaptation | OAuth support/status helpers, scope source precedence, retry-without-scopes checks, elicitation request tracking, auto-deny/auto-accept policy behavior, reviewer/event resolution, and Codex Apps auth failure URL elicitations are ported. OAuth discovery uses Web `fetch` instead of Rust reqwest. | +| Tool runtime | `src/upstream/codex-rs/core/src/tools/context.ts`, `tools/parallel.ts`, and `tools/handlers/mcp.ts` | `external/codex/codex-rs/core/src/tools/context.rs`, `tools/parallel.rs`, and `tools/handlers/mcp.rs` | Mirrored with platform adaptation | Tool execution uses Codex read/write ordering: parallel tools overlap, nonparallel tools wait for active parallel work and block later parallel work. TypeScript `CancellationToken` adapts Rust `tokio_util::sync::CancellationToken`. MCP outputs include wall-time model-facing text and preserve raw results for hook/code-mode consumers. | +| App server | `src/upstream/codex-rs/app-server/src` | `external/codex/codex-rs/app-server/src` | Mirrored with platform adaptation | Runtime composition, message processing, request processors, request serialization, connection gating, outgoing messages, initialize state, server-request response routing, and request context follow Codex. Worker WebSocket acceptance remains host code. | +| App server session orchestration | `src/upstream/codex-rs/app-server/src/session_factory.ts` and `session_task_runner.ts` | `external/codex/codex-rs/core/src/thread_manager.rs`, `core/src/tasks`, and `core/src/session/turn.rs` | Mirrored with platform adaptation | Thread/session creation and regular/compact task execution now live inside the upstream mirror so request processors do not depend on package runtime facades. Host callbacks still provide model clients, stores, credentials, and background scheduling. | +| App server transport | `src/upstream/codex-rs/app-server-transport/src/outgoing_message.ts` and `transport/mod.ts` | `external/codex/codex-rs/app-server-transport/src/outgoing_message.rs` and `transport/mod.rs` | Mirrored with platform adaptation | Transport-level outgoing message types plus JSON-RPC request, notification, response, and error parsing/serialization live under the Codex transport crate mirror. Worker socket acceptance remains host code. | +| App server client | `src/upstream/codex-rs/app-server-client/src/lib.ts`, `remote.ts`, `session.ts`, `pending_requests.ts`, and `thread_event_store.ts` | `external/codex/codex-rs/app-server-client/src/lib.rs` and `remote.rs` | Mirrored with platform adaptation | Browser WebSocket client lifecycle, initialize handshake, JSON-RPC request/response routing, server-request resolution, typed request helpers, pending request tracking, and thread notification projection now live under the Codex client crate mirror. Browser ticket URL creation remains host code. | +| Thread state | `src/upstream/codex-rs/app-server/src/thread_state.ts` | `external/codex/codex-rs/app-server/src/thread_state.rs` | Mirrored with platform adaptation | Live connections, thread subscriptions, active turn snapshots, and close cleanup are package-owned. Durable Object socket persistence remains host code. | + +## Platform Adaptations + +- TypeScript mirrors Rust module names and contracts, but uses `.ts` files, + structural types, `fetch`, WebSocket, and Cloudflare-compatible streams. +- Tool cancellation uses a TypeScript `CancellationToken` wrapper around + `AbortSignal` as the platform adaptation for Rust's cancellation token. +- Cloudflare Worker socket acceptance, Durable Object persistence, credentials, + prompts, product tools, project scope, and route paths stay outside the + package. +- Browser app-server WebSocket and OpenAI Responses WebSocket are separate + transports. The former connects UI to the app-server control plane; the latter + connects the runtime to OpenAI. + +## Guarded Rules + +- Package upstream mirrors do not import host application `app`, `src/domain`, + `src/browser`, or `src/worker` modules. +- The removed HTTP-primary `responses_client.ts` surface stays deleted. +- The package does not expose desktop-mediated model transport. +- Parser compatibility aliases for `cached_input_tokens` and + `reasoning_output_tokens` are not accepted. +- Request fixtures and serializers do not encode `prompt_cache_key: null`. diff --git a/packages/codex-js/CUSTOM_TOOLS.md b/docs/internal/CUSTOM_TOOLS.md similarity index 100% rename from packages/codex-js/CUSTOM_TOOLS.md rename to docs/internal/CUSTOM_TOOLS.md diff --git a/packages/codex-js/MIRROR_MAP.md b/docs/internal/MIRROR_MAP.md similarity index 50% rename from packages/codex-js/MIRROR_MAP.md rename to docs/internal/MIRROR_MAP.md index d46bfab..392ea47 100644 --- a/packages/codex-js/MIRROR_MAP.md +++ b/docs/internal/MIRROR_MAP.md @@ -7,74 +7,74 @@ Use it when updating from a newer Codex or T3Chat source drop. | Package Path | Upstream Reference | | --- | --- | -| `src/upstream/codex-rs/core/src/session/session.ts` | `.reference/codex/codex-rs/core/src/session/session.rs` | -| `src/upstream/codex-rs/core/src/session/turn-context.ts` | `.reference/codex/codex-rs/core/src/session/turn_context.rs` | -| `src/upstream/codex-rs/core/src/session/rollout-reconstruction.ts` | `.reference/codex/codex-rs/core/src/session/rollout_reconstruction.rs` | -| `src/upstream/codex-rs/core/src/client.ts` | `.reference/codex/codex-rs/core/src/client.rs` | -| `src/upstream/codex-rs/core/src/agent` | `.reference/codex/codex-rs/core/src/agent` | -| `src/upstream/codex-rs/core/src/tools/handlers/multi_agents.ts` | `.reference/codex/codex-rs/core/src/tools/handlers/multi_agents.rs` | -| `src/upstream/codex-rs/core/src/tools/handlers/agent_jobs*` | `.reference/codex/codex-rs/core/src/tools/handlers/agent_jobs*` | -| `src/upstream/codex-rs/core/src/tasks/mod.ts` | `.reference/codex/codex-rs/core/src/tasks/mod.rs` | -| `src/upstream/codex-rs/core/src/tasks/regular.ts` | `.reference/codex/codex-rs/core/src/tasks/regular.rs` | -| `src/upstream/codex-rs/core/src/tasks/compact.ts` | `.reference/codex/codex-rs/core/src/tasks/compact.rs` | -| `src/upstream/codex-rs/core/src/context` | `.reference/codex/codex-rs/core/src/context` | -| `src/upstream/codex-rs/core/src/context-manager` | `.reference/codex/codex-rs/core/src/context_manager` | -| `src/upstream/codex-rs/config/src/config_toml.ts` | `.reference/codex/codex-rs/config/src/config_toml.rs` | -| `src/upstream/codex-rs/config/src/profile_toml.ts` | `.reference/codex/codex-rs/config/src/profile_toml.rs` | -| `src/upstream/codex-rs/config/src/thread_config.ts` | `.reference/codex/codex-rs/config/src/thread_config.rs` | -| `src/upstream/codex-rs/config/src/merge.ts` | `.reference/codex/codex-rs/config/src/merge.rs` | -| `src/upstream/codex-rs/protocol/src/prompts/base_instructions/default.md` | `.reference/codex/codex-rs/protocol/src/prompts/base_instructions/default.md` | -| `src/upstream/codex-rs/core/src/config/mod.ts` | `.reference/codex/codex-rs/core/src/config/mod.rs` | -| `src/upstream/codex-rs/core/src/config/permissions.ts` | `.reference/codex/codex-rs/core/src/config/permissions.rs` | -| `src/upstream/codex-rs/core/templates` | `.reference/codex/codex-rs/core/templates` | -| `src/upstream/codex-rs/core/templates/model_instructions` | `.reference/codex/codex-rs/core/templates/model_instructions` | -| `src/upstream/codex-rs/core/src/tools` | `.reference/codex/codex-rs/core/src/tools` | -| `src/upstream/codex-rs/core/src/tools/spec.ts` | `.reference/codex/codex-rs/core/src/tools/spec.rs` | -| `src/upstream/codex-rs/core/src/tools/spec_plan.ts` | `.reference/codex/codex-rs/core/src/tools/spec_plan.rs` | -| `src/upstream/codex-rs/core/src/tools/spec_plan_types.ts` | `.reference/codex/codex-rs/core/src/tools/spec_plan_types.rs` | -| `src/upstream/codex-rs/core/src/tools/tool_search_entry.ts` | `.reference/codex/codex-rs/core/src/tools/tool_search_entry.rs` | -| `src/upstream/codex-rs/core/src/tools/tool_dispatch_trace.ts` | `.reference/codex/codex-rs/core/src/tools/tool_dispatch_trace.rs` | -| `src/upstream/codex-rs/core/src/tools/network_approval.ts` | `.reference/codex/codex-rs/core/src/tools/network_approval.rs` | -| `src/upstream/codex-rs/core/src/tools/runtimes` | `.reference/codex/codex-rs/core/src/tools/runtimes` | -| `src/upstream/codex-rs/core/src/tools/handlers/dynamic.ts` | `.reference/codex/codex-rs/core/src/tools/handlers/dynamic.rs` | -| `src/upstream/codex-rs/core/src/tools/handlers/tool_search.ts` | `.reference/codex/codex-rs/core/src/tools/handlers/tool_search.rs` | -| `src/upstream/codex-rs/core/src/tools/handlers/tool_search_spec.ts` | `.reference/codex/codex-rs/core/src/tools/handlers/tool_search_spec.rs` | -| `src/upstream/codex-rs/core/src/tools/handlers/apply_patch.ts` | `.reference/codex/codex-rs/core/src/tools/handlers/apply_patch.rs` | -| `src/upstream/codex-rs/core/src/tools/handlers/apply_patch_spec.ts` | `.reference/codex/codex-rs/core/src/tools/handlers/apply_patch_spec.rs` | -| `src/upstream/codex-rs/core/src/tools/handlers/unified_exec` | `.reference/codex/codex-rs/core/src/tools/handlers/unified_exec` | -| `src/upstream/codex-rs/core/src/tools/handlers/mcp_resource*` | `.reference/codex/codex-rs/core/src/tools/handlers/mcp_resource*` | -| `src/upstream/codex-rs/core/src/tools/handlers/plan*` | `.reference/codex/codex-rs/core/src/tools/handlers/plan*` | -| `src/upstream/codex-rs/core/src/tools/handlers/view_image*` | `.reference/codex/codex-rs/core/src/tools/handlers/view_image*` | -| `src/upstream/codex-rs/core/src/tools/handlers/request_plugin_install*` | `.reference/codex/codex-rs/core/src/tools/handlers/request_plugin_install*` | -| `src/upstream/codex-rs/core/src/tools/code_mode` | `.reference/codex/codex-rs/core/src/tools/code_mode` | -| `src/upstream/codex-rs/core/src/tools/handlers/goal_spec.ts` | `.reference/codex/codex-rs/core/src/tools/handlers/goal_spec.rs` | -| `src/upstream/codex-rs/core/src/event-mapping.ts` | `.reference/codex/codex-rs/core/src/event_mapping.rs` | -| `src/upstream/codex-rs/core/src/thread-history-builder.ts` | `.reference/codex/codex-rs/app-server/src/thread_state.rs` and thread history projection code | -| `src/upstream/codex-rs/thread-store/src` | `.reference/codex/codex-rs/thread-store/src` | -| `src/upstream/codex-rs/codex-api/src/endpoint/responses.ts` | `.reference/codex/codex-rs/codex-api/src/endpoint/responses.rs` | -| `src/upstream/codex-rs/codex-api/src/endpoint/responses_websocket.ts` | `.reference/codex/codex-rs/codex-api/src/endpoint/responses_websocket.rs` | -| `src/upstream/codex-rs/codex-api/src/requests/responses.ts` | `.reference/codex/codex-rs/codex-api/src/requests/responses.rs` | -| `src/upstream/codex-rs/codex-api/src/sse/responses.ts` | `.reference/codex/codex-rs/codex-api/src/sse/responses.rs` | -| `src/upstream/codex-rs/codex-api/src/provider.ts` | `.reference/codex/codex-rs/codex-api/src/provider.rs` | -| `src/upstream/codex-rs/codex-api/src/rate_limits.ts` | `.reference/codex/codex-rs/codex-api/src/rate_limits.rs` | -| `src/upstream/codex-rs/model-provider/src` | `.reference/codex/codex-rs/model-provider/src` | -| `src/upstream/codex-rs/models-manager/src` | `.reference/codex/codex-rs/models-manager/src` | -| `src/upstream/codex-rs/app-server-protocol/schema/typescript` | `.reference/codex/codex-rs/app-server-protocol/schema/typescript` | -| `src/upstream/codex-rs/app-server-protocol/src/protocol/common.ts` | `.reference/codex/codex-rs/app-server-protocol/src/protocol/common.rs` | -| `src/upstream/codex-rs/app-server-protocol/src/protocol/event-mapping.ts` | `.reference/codex/codex-rs/app-server-protocol/src/protocol/event_mapping.rs` | -| `src/upstream/codex-rs/app-server/src/connection_rpc_gate.ts` | `.reference/codex/codex-rs/app-server/src/connection_rpc_gate.rs` | -| `src/upstream/codex-rs/app-server/src/message_processor.ts` | `.reference/codex/codex-rs/app-server/src/message_processor.rs` | -| `src/upstream/codex-rs/app-server/src/request_serialization.ts` | `.reference/codex/codex-rs/app-server/src/request_serialization.rs` | +| `src/upstream/codex-rs/core/src/session/session.ts` | `external/codex/codex-rs/core/src/session/session.rs` | +| `src/upstream/codex-rs/core/src/session/turn-context.ts` | `external/codex/codex-rs/core/src/session/turn_context.rs` | +| `src/upstream/codex-rs/core/src/session/rollout-reconstruction.ts` | `external/codex/codex-rs/core/src/session/rollout_reconstruction.rs` | +| `src/upstream/codex-rs/core/src/client.ts` | `external/codex/codex-rs/core/src/client.rs` | +| `src/upstream/codex-rs/core/src/agent` | `external/codex/codex-rs/core/src/agent` | +| `src/upstream/codex-rs/core/src/tools/handlers/multi_agents.ts` | `external/codex/codex-rs/core/src/tools/handlers/multi_agents.rs` | +| `src/upstream/codex-rs/core/src/tools/handlers/agent_jobs*` | `external/codex/codex-rs/core/src/tools/handlers/agent_jobs*` | +| `src/upstream/codex-rs/core/src/tasks/mod.ts` | `external/codex/codex-rs/core/src/tasks/mod.rs` | +| `src/upstream/codex-rs/core/src/tasks/regular.ts` | `external/codex/codex-rs/core/src/tasks/regular.rs` | +| `src/upstream/codex-rs/core/src/tasks/compact.ts` | `external/codex/codex-rs/core/src/tasks/compact.rs` | +| `src/upstream/codex-rs/core/src/context` | `external/codex/codex-rs/core/src/context` | +| `src/upstream/codex-rs/core/src/context-manager` | `external/codex/codex-rs/core/src/context_manager` | +| `src/upstream/codex-rs/config/src/config_toml.ts` | `external/codex/codex-rs/config/src/config_toml.rs` | +| `src/upstream/codex-rs/config/src/profile_toml.ts` | `external/codex/codex-rs/config/src/profile_toml.rs` | +| `src/upstream/codex-rs/config/src/thread_config.ts` | `external/codex/codex-rs/config/src/thread_config.rs` | +| `src/upstream/codex-rs/config/src/merge.ts` | `external/codex/codex-rs/config/src/merge.rs` | +| `src/upstream/codex-rs/protocol/src/prompts/base_instructions/default.md` | `external/codex/codex-rs/protocol/src/prompts/base_instructions/default.md` | +| `src/upstream/codex-rs/core/src/config/mod.ts` | `external/codex/codex-rs/core/src/config/mod.rs` | +| `src/upstream/codex-rs/core/src/config/permissions.ts` | `external/codex/codex-rs/core/src/config/permissions.rs` | +| `src/upstream/codex-rs/core/templates` | `external/codex/codex-rs/core/templates` | +| `src/upstream/codex-rs/core/templates/model_instructions` | `external/codex/codex-rs/core/templates/model_instructions` | +| `src/upstream/codex-rs/core/src/tools` | `external/codex/codex-rs/core/src/tools` | +| `src/upstream/codex-rs/core/src/tools/spec.ts` | `external/codex/codex-rs/core/src/tools/spec.rs` | +| `src/upstream/codex-rs/core/src/tools/spec_plan.ts` | `external/codex/codex-rs/core/src/tools/spec_plan.rs` | +| `src/upstream/codex-rs/core/src/tools/spec_plan_types.ts` | `external/codex/codex-rs/core/src/tools/spec_plan_types.rs` | +| `src/upstream/codex-rs/core/src/tools/tool_search_entry.ts` | `external/codex/codex-rs/core/src/tools/tool_search_entry.rs` | +| `src/upstream/codex-rs/core/src/tools/tool_dispatch_trace.ts` | `external/codex/codex-rs/core/src/tools/tool_dispatch_trace.rs` | +| `src/upstream/codex-rs/core/src/tools/network_approval.ts` | `external/codex/codex-rs/core/src/tools/network_approval.rs` | +| `src/upstream/codex-rs/core/src/tools/runtimes` | `external/codex/codex-rs/core/src/tools/runtimes` | +| `src/upstream/codex-rs/core/src/tools/handlers/dynamic.ts` | `external/codex/codex-rs/core/src/tools/handlers/dynamic.rs` | +| `src/upstream/codex-rs/core/src/tools/handlers/tool_search.ts` | `external/codex/codex-rs/core/src/tools/handlers/tool_search.rs` | +| `src/upstream/codex-rs/core/src/tools/handlers/tool_search_spec.ts` | `external/codex/codex-rs/core/src/tools/handlers/tool_search_spec.rs` | +| `src/upstream/codex-rs/core/src/tools/handlers/apply_patch.ts` | `external/codex/codex-rs/core/src/tools/handlers/apply_patch.rs` | +| `src/upstream/codex-rs/core/src/tools/handlers/apply_patch_spec.ts` | `external/codex/codex-rs/core/src/tools/handlers/apply_patch_spec.rs` | +| `src/upstream/codex-rs/core/src/tools/handlers/unified_exec` | `external/codex/codex-rs/core/src/tools/handlers/unified_exec` | +| `src/upstream/codex-rs/core/src/tools/handlers/mcp_resource*` | `external/codex/codex-rs/core/src/tools/handlers/mcp_resource*` | +| `src/upstream/codex-rs/core/src/tools/handlers/plan*` | `external/codex/codex-rs/core/src/tools/handlers/plan*` | +| `src/upstream/codex-rs/core/src/tools/handlers/view_image*` | `external/codex/codex-rs/core/src/tools/handlers/view_image*` | +| `src/upstream/codex-rs/core/src/tools/handlers/request_plugin_install*` | `external/codex/codex-rs/core/src/tools/handlers/request_plugin_install*` | +| `src/upstream/codex-rs/core/src/tools/code_mode` | `external/codex/codex-rs/core/src/tools/code_mode` | +| `src/upstream/codex-rs/core/src/tools/handlers/goal_spec.ts` | `external/codex/codex-rs/core/src/tools/handlers/goal_spec.rs` | +| `src/upstream/codex-rs/core/src/event-mapping.ts` | `external/codex/codex-rs/core/src/event_mapping.rs` | +| `src/upstream/codex-rs/core/src/thread-history-builder.ts` | `external/codex/codex-rs/app-server/src/thread_state.rs` and thread history projection code | +| `src/upstream/codex-rs/thread-store/src` | `external/codex/codex-rs/thread-store/src` | +| `src/upstream/codex-rs/codex-api/src/endpoint/responses.ts` | `external/codex/codex-rs/codex-api/src/endpoint/responses.rs` | +| `src/upstream/codex-rs/codex-api/src/endpoint/responses_websocket.ts` | `external/codex/codex-rs/codex-api/src/endpoint/responses_websocket.rs` | +| `src/upstream/codex-rs/codex-api/src/requests/responses.ts` | `external/codex/codex-rs/codex-api/src/requests/responses.rs` | +| `src/upstream/codex-rs/codex-api/src/sse/responses.ts` | `external/codex/codex-rs/codex-api/src/sse/responses.rs` | +| `src/upstream/codex-rs/codex-api/src/provider.ts` | `external/codex/codex-rs/codex-api/src/provider.rs` | +| `src/upstream/codex-rs/codex-api/src/rate_limits.ts` | `external/codex/codex-rs/codex-api/src/rate_limits.rs` | +| `src/upstream/codex-rs/model-provider/src` | `external/codex/codex-rs/model-provider/src` | +| `src/upstream/codex-rs/models-manager/src` | `external/codex/codex-rs/models-manager/src` | +| `src/upstream/codex-rs/app-server-protocol/schema/typescript` | `external/codex/codex-rs/app-server-protocol/schema/typescript` | +| `src/upstream/codex-rs/app-server-protocol/src/protocol/common.ts` | `external/codex/codex-rs/app-server-protocol/src/protocol/common.rs` | +| `src/upstream/codex-rs/app-server-protocol/src/protocol/event-mapping.ts` | `external/codex/codex-rs/app-server-protocol/src/protocol/event_mapping.rs` | +| `src/upstream/codex-rs/app-server/src/connection_rpc_gate.ts` | `external/codex/codex-rs/app-server/src/connection_rpc_gate.rs` | +| `src/upstream/codex-rs/app-server/src/message_processor.ts` | `external/codex/codex-rs/app-server/src/message_processor.rs` | +| `src/upstream/codex-rs/app-server/src/request_serialization.ts` | `external/codex/codex-rs/app-server/src/request_serialization.rs` | | `src/upstream/codex-rs/app-server/src/runtime.ts` | TypeScript app-server runtime composition over Codex message processor, request processors, thread state, and session/task orchestration | | `src/upstream/codex-rs/app-server/src/server_request_response.ts` | TypeScript server-request response translation helper for Codex submissions | -| `src/upstream/codex-rs/app-server/src/session_factory.ts` | TypeScript adaptation of Codex thread/session creation boundaries from `.reference/codex/codex-rs/core/src/thread_manager.rs` and `core/src/session/session.rs` | -| `src/upstream/codex-rs/app-server/src/session_task_runner.ts` | TypeScript adaptation of Codex task execution boundaries from `.reference/codex/codex-rs/core/src/tasks` and `core/src/session/turn.rs` | -| `src/upstream/codex-rs/app-server/src/thread_state.ts` | `.reference/codex/codex-rs/app-server/src/thread_state.rs` | -| `src/upstream/codex-rs/app-server/src/transport.ts` | `.reference/codex/codex-rs/app-server/src/transport.rs` | -| `src/upstream/codex-rs/app-server-transport/src/outgoing_message.ts` | `.reference/codex/codex-rs/app-server-transport/src/outgoing_message.rs` | -| `src/upstream/codex-rs/app-server-transport/src/transport/mod.ts` | `.reference/codex/codex-rs/app-server-transport/src/transport/mod.rs` | -| `src/upstream/codex-rs/app-server-client/src/lib.ts` | `.reference/codex/codex-rs/app-server-client/src/lib.rs` | -| `src/upstream/codex-rs/app-server-client/src/remote.ts` | `.reference/codex/codex-rs/app-server-client/src/remote.rs` | +| `src/upstream/codex-rs/app-server/src/session_factory.ts` | TypeScript adaptation of Codex thread/session creation boundaries from `external/codex/codex-rs/core/src/thread_manager.rs` and `core/src/session/session.rs` | +| `src/upstream/codex-rs/app-server/src/session_task_runner.ts` | TypeScript adaptation of Codex task execution boundaries from `external/codex/codex-rs/core/src/tasks` and `core/src/session/turn.rs` | +| `src/upstream/codex-rs/app-server/src/thread_state.ts` | `external/codex/codex-rs/app-server/src/thread_state.rs` | +| `src/upstream/codex-rs/app-server/src/transport.ts` | `external/codex/codex-rs/app-server/src/transport.rs` | +| `src/upstream/codex-rs/app-server-transport/src/outgoing_message.ts` | `external/codex/codex-rs/app-server-transport/src/outgoing_message.rs` | +| `src/upstream/codex-rs/app-server-transport/src/transport/mod.ts` | `external/codex/codex-rs/app-server-transport/src/transport/mod.rs` | +| `src/upstream/codex-rs/app-server-client/src/lib.ts` | `external/codex/codex-rs/app-server-client/src/lib.rs` | +| `src/upstream/codex-rs/app-server-client/src/remote.ts` | `external/codex/codex-rs/app-server-client/src/remote.rs` | | `src/upstream/codex-rs/app-server-client/src/session.ts` | TypeScript typed session helper for generated app-server requests | | `src/upstream/codex-rs/app-server-client/src/pending_requests.ts` | TypeScript app-server server-request tracking helper | | `src/upstream/codex-rs/app-server-client/src/thread_event_store.ts` | TypeScript app-server notification/request thread projection helper | @@ -83,14 +83,14 @@ Use it when updating from a newer Codex or T3Chat source drop. | Package Path | Upstream Reference | | --- | --- | -| `src/upstream/t3code/apps/web/src/components/chat/ChatComposer.tsx` | `.reference/t3code/apps/web/src/components/chat/ChatComposer.tsx` | -| `src/upstream/t3code/apps/web/src/components/ComposerPromptEditor.tsx` | `.reference/t3code/apps/web/src/components/ComposerPromptEditor.tsx` | -| `src/upstream/t3code/apps/web/src/components/chat/MessagesTimeline.tsx` | `.reference/t3code/apps/web/src/components/chat/MessagesTimeline.tsx` | -| `src/upstream/t3code/apps/web/src/components/chat/ChangedFilesTree.tsx` | `.reference/t3code/apps/web/src/components/chat/ChangedFilesTree.tsx` | -| `src/upstream/t3code/apps/web/src/components/chat/ProviderModelPicker.tsx` | `.reference/t3code/apps/web/src/components/chat/ProviderModelPicker.tsx` | -| `src/upstream/t3code/apps/web/src/components/ui` | `.reference/t3code/apps/web/src/components/ui` or the closest current T3Chat UI primitive source | -| `src/upstream/t3code/apps/web/src/hooks` | `.reference/t3code/apps/web/src/hooks` | -| `src/upstream/t3code/apps/web/src/lib` | `.reference/t3code/apps/web/src/lib` | +| `src/upstream/t3code/apps/web/src/components/chat/ChatComposer.tsx` | `external/t3code/apps/web/src/components/chat/ChatComposer.tsx` | +| `src/upstream/t3code/apps/web/src/components/ComposerPromptEditor.tsx` | `external/t3code/apps/web/src/components/ComposerPromptEditor.tsx` | +| `src/upstream/t3code/apps/web/src/components/chat/MessagesTimeline.tsx` | `external/t3code/apps/web/src/components/chat/MessagesTimeline.tsx` | +| `src/upstream/t3code/apps/web/src/components/chat/ChangedFilesTree.tsx` | `external/t3code/apps/web/src/components/chat/ChangedFilesTree.tsx` | +| `src/upstream/t3code/apps/web/src/components/chat/ProviderModelPicker.tsx` | `external/t3code/apps/web/src/components/chat/ProviderModelPicker.tsx` | +| `src/upstream/t3code/apps/web/src/components/ui` | `external/t3code/apps/web/src/components/ui` or the closest current T3Chat UI primitive source | +| `src/upstream/t3code/apps/web/src/hooks` | `external/t3code/apps/web/src/hooks` | +| `src/upstream/t3code/apps/web/src/lib` | `external/t3code/apps/web/src/lib` | ## Package Shadcn Primitives diff --git a/packages/codex-js/PACKAGE_BOUNDARY.md b/docs/internal/PACKAGE_BOUNDARY.md similarity index 100% rename from packages/codex-js/PACKAGE_BOUNDARY.md rename to docs/internal/PACKAGE_BOUNDARY.md diff --git a/packages/codex-js/AGENTS.md b/docs/internal/codex-js-package-agents.md similarity index 100% rename from packages/codex-js/AGENTS.md rename to docs/internal/codex-js-package-agents.md diff --git a/docs/staging/core-realizations.md b/docs/staging/core-realizations.md index 1c58b91..fb8245b 100644 --- a/docs/staging/core-realizations.md +++ b/docs/staging/core-realizations.md @@ -112,7 +112,7 @@ The model should stay Codex-shaped, not host application-shaped. host applicatio Friendly `sendMessage` APIs belong at the component edge. Runtime dispatch is Codex-shaped app-server lifecycle flow. -Codex App Server is maintained by processor boundaries: thread requests, turn requests, thread state, outgoing messages, and bespoke event handling. +Codex App Server is maintained by processor boundaries: thread requests, turn requests, thread state, outgoing messages, and app-server event mapping. Session creation is a runtime boundary: it attaches ThreadStore history, LiveThread persistence, SessionConfiguration, and app-owned overrides before processors run turns. diff --git a/docs/start-here/00-system-tour.md b/docs/start-here/00-system-tour.md index 5513a4a..0e511cb 100644 --- a/docs/start-here/00-system-tour.md +++ b/docs/start-here/00-system-tour.md @@ -1,24 +1,23 @@ # System Tour -`@jrkropp/codex-js` is a portable Codex runtime and T3-shaped -chat UI kit. It is not a host application package, a Cloudflare package, or a React -Router package. host application is one consuming application that proves the -package boundary. +`@jrkropp/codex-js` is a portable Codex runtime SDK. +`@jrkropp/codex-js-react` is the React UI package. Neither package is a host +application, a Cloudflare package, or a React Router package. ## Layers -The package has four layers: +The workspace has four layers: -| Layer | Responsibility | -| --- | --- | -| `src/upstream/codex-rs` | Codex runtime, thread store, protocol, tools, model transport, and app-server protocol primitives. | -| `src/upstream/t3code` | T3Chat composer, timeline, model picker, image previews, command menus, and chat interaction helpers. | -| `src/runtime` | Package-owned Codex lifecycle contracts, app-server boundary, store boundary, and route-neutral protocol state. | -| `src/components` and `src/hooks` | Stable React surfaces that bind Codex protocol state to T3-derived chat presentation. | +| Layer | Responsibility | +| -------------------------------- | ------------------------------------------------------------------------------------------------- | +| `packages/codex-js/src/client` | Browser app-server WebSocket client and protocol event helpers. | +| `packages/codex-js/src/server` | App-server runtime helpers, connection bridge, stores, model transport, and dynamic tool helpers. | +| `packages/codex-js/src/internal` | Implemented Codex ports and package internals. | +| `packages/codex-js-react/src` | Stable React components, hooks, shadcn primitives, and CSS. | -Codex source defines runtime semantics. T3 source defines browser interaction -ownership. The package facades connect the two without letting product behavior -leak into either upstream-shaped tree. +Codex source defines runtime semantics. The package facades expose those +semantics without leaking product behavior or reference-source layout into npm +imports. ## Runtime Flow @@ -49,7 +48,7 @@ A consuming app provides product policy and platform placement: - prompts, developer instructions, dynamic tools, and scopes - routes, auth, deployment, WebSocket delivery, and product renderers -host application supplies those pieces from its app folders. The package never +The host application supplies those pieces from its app folders. The package never imports host application routes, domains, Worker bindings, storage keys, prompts, or branding. @@ -58,14 +57,11 @@ branding. Most integrations should enter through the public surfaces: - `@jrkropp/codex-js/server` -- `@jrkropp/codex-js/react` -- `@jrkropp/codex-js/react` - -The package root is intentionally small and only exposes the plug-and-play chat -component entrypoint. Runtime, hook, component, Codex mirror, and T3 mirror APIs -stay on their explicit subpaths. - -The upstream-shaped Codex and T3 import paths remain available for low-level -adapter work, tests, and source-parity updates. Product UI should prefer the -public facades unless it is intentionally bridging into a specific upstream -primitive. +- `@jrkropp/codex-js/client` +- `@jrkropp/codex-js/testing` +- `@jrkropp/codex-js-react` +- `@jrkropp/codex-js-react/shadcn` +- `@jrkropp/codex-js-react/styles.css` + +The package roots are intentionally small. Reference-source and mirror material +is not a public import surface. diff --git a/docs/start-here/01-design-philosophy.md b/docs/start-here/01-design-philosophy.md index 642f0d2..9ebab22 100644 --- a/docs/start-here/01-design-philosophy.md +++ b/docs/start-here/01-design-philosophy.md @@ -12,15 +12,15 @@ This avoids a custom product-specific chat runtime. The package preserves Codex concepts for execution and persistence while using T3-shaped components for the browser chat experience. -## Upstream First +## Codex First -The upstream source trees are the maintenance strategy. File names, folder -boundaries, protocol names, and lifecycle concepts stay close to Codex and T3 so -future source drops can be compared and ported directly. +The Codex source tree is the maintenance strategy for runtime behavior. Protocol +names and lifecycle concepts stay close to Codex so future source drops can be +compared and ported directly. -Package-owned abstractions live outside the upstream trees. If a behavior is +Package-owned abstractions live outside reference material. If a behavior is product-specific, expose a contract, prop, renderer, tool, prompt, or adapter -slot instead of editing upstream-shaped package code. +slot instead of editing internal package code. ## Boundaries Over Abstractions @@ -46,7 +46,7 @@ Host applications own the parts that make an assistant product-specific: - product actions, banners, mentions, and custom renderers Those choices enter through stable package contracts. They do not belong in -`src/upstream/codex-rs`, `src/upstream/t3code`, or package runtime internals. +reference material or package runtime internals. ## Current Truth diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..003d62d --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,61 @@ +import js from "@eslint/js"; +import reactHooks from "eslint-plugin-react-hooks"; +import globals from "globals"; +import tseslint from "typescript-eslint"; + +export default tseslint.config( + { + ignores: [ + ".changeset/**", + "external/**", + "node_modules/**", + "packages/*/dist/**", + "examples/*/dist/**", + "examples/cloudflare/worker-configuration.d.ts", + "docs/internal/**", + "pnpm-lock.yaml", + ], + }, + js.configs.recommended, + ...tseslint.configs.recommended, + { + languageOptions: { + ecmaVersion: 2022, + globals: { + ...globals.browser, + ...globals.node, + DurableObjectNamespace: "readonly", + DurableObjectState: "readonly", + DurableObjectStorage: "readonly", + Env: "readonly", + WebSocketPair: "readonly", + }, + sourceType: "module", + }, + rules: { + "no-console": "off", + "no-undef": "off", + "preserve-caught-error": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-this-alias": "off", + "@typescript-eslint/no-unused-vars": [ + "error", + { + argsIgnorePattern: "^_", + caughtErrorsIgnorePattern: "^_", + varsIgnorePattern: "^_", + }, + ], + }, + }, + { + files: ["**/*.tsx"], + plugins: { + "react-hooks": reactHooks, + }, + rules: { + "react-hooks/exhaustive-deps": "error", + "react-hooks/rules-of-hooks": "error", + }, + }, +); diff --git a/examples/cloudflare/README.md b/examples/cloudflare/README.md new file mode 100644 index 0000000..4618e9e --- /dev/null +++ b/examples/cloudflare/README.md @@ -0,0 +1,88 @@ +# codex-js Cloudflare Example + +Deployable Vite React + Cloudflare Worker + Durable Object example for `@jrkropp/codex-js`. + +The browser never receives an OpenAI API key. It creates a Codex session through the Worker, receives a short-lived one-time WebSocket ticket, and then connects to a Durable Object app-server session. + +## Architecture + +```mermaid +sequenceDiagram + participant Browser + participant Worker + participant Session as CodexSessionObject + Browser->>Worker: POST /api/codex/session + Worker->>Session: createTicket(ticket, threadId) + Worker-->>Browser: { threadId, webSocketUrl } + Browser->>Worker: GET /api/codex/app-server?ticket=... + Worker->>Session: fetch(upgrade) + Session-->>Browser: WebSocket 101 + Browser->>Session: app-server JSON-RPC + Session->>Session: createCodexAppServerConnection() + Session->>Session: persist thread, pending requests, snapshots +``` + +## Install + +From the repository root: + +```sh +pnpm install +``` + +For deployed Workers, set the secret with Wrangler: + +```sh +pnpm --filter @jrkropp/codex-js-cloudflare-example exec wrangler secret put OPENAI_API_KEY +``` + +For local development, create `examples/cloudflare/.dev.vars`: + +```env +OPENAI_API_KEY=sk-... +``` + +`wrangler.jsonc` declares `OPENAI_API_KEY` in `secrets.required`. Wrangler uses that declaration for type generation and deploy validation. The Cloudflare Vite plugin may copy `.dev.vars` into `dist` for `vite preview`; Cloudflare documents that this file is for local preview only and is not deployed with the Worker. Do not commit `.dev.vars` or build output. + +## Run + +```sh +pnpm dev:cloudflare-example +``` + +## Deploy Dry Run + +```sh +pnpm --filter @jrkropp/codex-js-cloudflare-example cf:types:check +pnpm --filter @jrkropp/codex-js-cloudflare-example deploy:dry-run +``` + +## Routes + +- `POST /api/codex/session`: creates a session id, thread id, and one-time WebSocket ticket. +- `GET /api/codex/app-server?ticket=...`: validates and consumes the ticket, then upgrades to a Durable Object WebSocket. + +Static assets are served by Workers assets with SPA fallback. Worker-first routing is limited to `/api/*`. + +## Durable Object Responsibilities + +`CodexSessionObject` owns: + +- one app-server runtime per Durable Object instance +- one app-server connection per WebSocket +- Durable Object SQLite thread storage +- pending app-server request storage +- one-time WebSocket ticket validation +- connection session snapshots for hibernation restore +- server-side dynamic tool registration + +It uses `ctx.acceptWebSocket(server)` and stores a small socket attachment so the Durable Object can reconstruct the app-server connection after hibernation. Larger connection state is stored in SQLite. + +## Dynamic Tools + +The example registers two tools in `src/worker/tools.ts`: + +- `lookup_deployment`: visible server-executed tool. +- `billing/lookup_invoice`: deferred namespaced server-executed tool. + +Application tools belong in the Worker or Durable Object, not in the browser. Tools that omit `execute` are still valid escape hatches; they surface as app-server requests for a client to resolve. diff --git a/examples/minimal-app-server/index.html b/examples/cloudflare/index.html similarity index 65% rename from examples/minimal-app-server/index.html rename to examples/cloudflare/index.html index 47d45ae..2ac36ff 100644 --- a/examples/minimal-app-server/index.html +++ b/examples/cloudflare/index.html @@ -3,10 +3,10 @@
-