| author | |
| committer | |
| log | b5bab3eb134fd7555914fe57031a064b08beb195 |
| tree | cd09779d8f322ff26fa07bf875815a5929deb7e3 |
| parent | 8ebd2479cf976a6ef79843b97d477777efb7cb6a |
| signature | Commit is signed but in an unrecognized format. |
34 files changed, 101 insertions(+), 99 deletions(-)
AGENTS.md+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # CLAUDE.md |
| 2 | 2 | |
| 3 | 3 | ## Project Snapshot |
| 4 | CodeThing is a minimal web GUI for using code agents like Codex and Claude Code (coming soon). | |
| 4 | T3 Code is a minimal web GUI for using code agents like Codex and Claude Code (coming soon). | |
| 5 | 5 | |
| 6 | 6 | This repository is a VERY EARLY WIP. Proposing sweeping changes that improve long-term maintainability is encouraged. |
| 7 | 7 | |
| ... | ... | @@ -18,7 +18,7 @@ If a tradeoff is required, choose correctness and robustness over short-term con |
| 18 | 18 | - `packages/contracts`: Shared Zod schemas and TypeScript contracts for provider events, WebSocket protocol, and model/session types. |
| 19 | 19 | |
| 20 | 20 | ## Codex App Server (Important) |
| 21 | CodeThing is currently Codex-first. The server starts `codex app-server` (JSON-RPC over stdio) per provider session, then streams structured events to the browser through WebSocket push messages. | |
| 21 | T3 Code is currently Codex-first. The server starts `codex app-server` (JSON-RPC over stdio) per provider session, then streams structured events to the browser through WebSocket push messages. | |
| 22 | 22 | |
| 23 | 23 | How we use it in this codebase: |
| 24 | 24 | - Session startup/resume and turn lifecycle are brokered in `apps/server/src/codexAppServerManager.ts`. |
README.md+7-7| ... | ... | @@ -1,13 +1,13 @@ |
| 1 | # CodeThing | |
| 1 | # T3 Code | |
| 2 | 2 | |
| 3 | CodeThing is a minimal web GUI for coding agents. Currently Codex-first, with Claude Code support coming soon. | |
| 3 | T3 Code is a minimal web GUI for coding agents. Currently Codex-first, with Claude Code support coming soon. | |
| 4 | 4 | |
| 5 | 5 | Run `npx t3` in any project directory to launch the web interface. |
| 6 | 6 | Run `bun run dev:desktop` to launch the Electron desktop app in this monorepo. |
| 7 | 7 | |
| 8 | 8 | ## Architecture |
| 9 | 9 | |
| 10 | CodeThing runs as a **Node.js WebSocket server** that wraps `codex app-server` (JSON-RPC over stdio) and serves a React web app. | |
| 10 | T3 Code runs as a **Node.js WebSocket server** that wraps `codex app-server` (JSON-RPC over stdio) and serves a React web app. | |
| 11 | 11 | |
| 12 | 12 | ``` |
| 13 | 13 | ┌─────────────────────────────────┐ |
| ... | ... | @@ -37,8 +37,8 @@ CodeThing runs as a **Node.js WebSocket server** that wraps `codex app-server` ( |
| 37 | 37 | ## Codex prerequisites |
| 38 | 38 | |
| 39 | 39 | - Install Codex CLI so `codex` is on your PATH. |
| 40 | - Authenticate Codex before running CodeThing (for example via API key or ChatGPT auth supported by Codex). | |
| 41 | - CodeThing starts the server via `codex app-server` per session. | |
| 40 | - Authenticate Codex before running T3 Code (for example via API key or ChatGPT auth supported by Codex). | |
| 41 | - T3 Code starts the server via `codex app-server` per session. | |
| 42 | 42 | |
| 43 | 43 | ## Quick start |
| 44 | 44 | |
| ... | ... | @@ -69,7 +69,7 @@ npx t3 |
| 69 | 69 | |
| 70 | 70 | ## Runtime modes |
| 71 | 71 | |
| 72 | CodeThing has a global runtime mode switch in the chat toolbar: | |
| 72 | T3 Code has a global runtime mode switch in the chat toolbar: | |
| 73 | 73 | |
| 74 | 74 | - **Full access** (default): starts sessions with `approvalPolicy: never` and `sandboxMode: danger-full-access`. |
| 75 | 75 | - **Supervised**: starts sessions with `approvalPolicy: on-request` and `sandboxMode: workspace-write`, then prompts in-app for command/file approvals. |
| ... | ... | @@ -81,7 +81,7 @@ The renderer communicates with the server via WebSocket using a simple JSON-RPC- |
| 81 | 81 | - **Request/Response**: `{ id, method, params }` → `{ id, result }` or `{ id, error }` |
| 82 | 82 | - **Push events**: `{ type: "push", channel, data }` for streaming provider events |
| 83 | 83 | |
| 84 | Methods mirror the `NativeApi` interface defined in `@acme/contracts`: | |
| 84 | Methods mirror the `NativeApi` interface defined in `@t3tools/contracts`: | |
| 85 | 85 | |
| 86 | 86 | - `providers.startSession`, `providers.sendTurn`, `providers.interruptTurn` |
| 87 | 87 | - `providers.respondToRequest`, `providers.stopSession`, `providers.listSessions` |
apps/desktop/package.json+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | { |
| 2 | "name": "@acme/desktop", | |
| 2 | "name": "@t3tools/desktop", | |
| 3 | 3 | "version": "0.0.0", |
| 4 | 4 | "private": true, |
| 5 | 5 | "main": "dist-electron/main.js", |
apps/desktop/src/main.ts+6-6| ... | ... | @@ -48,11 +48,11 @@ async function reserveLoopbackPort(): Promise<number> { |
| 48 | 48 | function backendEnv(): NodeJS.ProcessEnv { |
| 49 | 49 | return { |
| 50 | 50 | ...process.env, |
| 51 | CODETHING_MODE: "desktop", | |
| 52 | CODETHING_NO_BROWSER: "1", | |
| 53 | CODETHING_PORT: String(backendPort), | |
| 54 | CODETHING_STATE_DIR: STATE_DIR, | |
| 55 | CODETHING_AUTH_TOKEN: backendAuthToken, | |
| 51 | T3CODE_MODE: "desktop", | |
| 52 | T3CODE_NO_BROWSER: "1", | |
| 53 | T3CODE_PORT: String(backendPort), | |
| 54 | T3CODE_STATE_DIR: STATE_DIR, | |
| 55 | T3CODE_AUTH_TOKEN: backendAuthToken, | |
| 56 | 56 | }; |
| 57 | 57 | } |
| 58 | 58 | |
| ... | ... | @@ -186,7 +186,7 @@ async function bootstrap(): Promise<void> { |
| 186 | 186 | backendPort = await reserveLoopbackPort(); |
| 187 | 187 | backendAuthToken = randomBytes(24).toString("hex"); |
| 188 | 188 | backendWsUrl = `ws://127.0.0.1:${backendPort}/?token=${encodeURIComponent(backendAuthToken)}`; |
| 189 | process.env.CODETHING_DESKTOP_WS_URL = backendWsUrl; | |
| 189 | process.env.T3CODE_DESKTOP_WS_URL = backendWsUrl; | |
| 190 | 190 | |
| 191 | 191 | registerIpcHandlers(); |
| 192 | 192 | startBackend(); |
apps/desktop/src/preload.ts+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | import { contextBridge, ipcRenderer } from "electron"; |
| 2 | 2 | |
| 3 | 3 | const PICK_FOLDER_CHANNEL = "desktop:pick-folder"; |
| 4 | const wsUrl = process.env.CODETHING_DESKTOP_WS_URL ?? null; | |
| 4 | const wsUrl = process.env.T3CODE_DESKTOP_WS_URL ?? null; | |
| 5 | 5 | |
| 6 | 6 | contextBridge.exposeInMainWorld("desktopBridge", { |
| 7 | 7 | getWsUrl: () => wsUrl, |
apps/desktop/tsup.config.ts+1-1| ... | ... | @@ -6,5 +6,5 @@ export default defineConfig({ |
| 6 | 6 | outDir: "dist-electron", |
| 7 | 7 | sourcemap: true, |
| 8 | 8 | clean: true, |
| 9 | noExternal: ["@acme/contracts"], | |
| 9 | noExternal: ["@t3tools/contracts"], | |
| 10 | 10 | }); |
apps/renderer/index.html+4-1| ... | ... | @@ -3,7 +3,10 @@ |
| 3 | 3 | <head> |
| 4 | 4 | <meta charset="UTF-8" /> |
| 5 | 5 | <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
| 6 | <title>CodeThing</title> | |
| 6 | <link rel="preconnect" href="https://fonts.googleapis.com" /> | |
| 7 | <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> | |
| 8 | <link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300..800;1,9..40,300..800&display=swap" rel="stylesheet" /> | |
| 9 | <title>T3 Code</title> | |
| 7 | 10 | </head> |
| 8 | 11 | <body> |
| 9 | 12 | <div id="root"></div> |
apps/renderer/package.json+2-2| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | { |
| 2 | "name": "@acme/renderer", | |
| 2 | "name": "@t3tools/renderer", | |
| 3 | 3 | "version": "0.0.0", |
| 4 | 4 | "private": true, |
| 5 | 5 | "type": "module", |
| ... | ... | @@ -11,7 +11,7 @@ |
| 11 | 11 | "test": "vitest run --passWithNoTests" |
| 12 | 12 | }, |
| 13 | 13 | "dependencies": { |
| 14 | "@acme/contracts": "workspace:*", | |
| 14 | "@t3tools/contracts": "workspace:*", | |
| 15 | 15 | "highlight.js": "^11.11.1", |
| 16 | 16 | "lucide-react": "^0.563.0", |
| 17 | 17 | "react": "^19.0.0", |
apps/renderer/src/App.tsx+1-1| ... | ... | @@ -148,7 +148,7 @@ function Layout() { |
| 148 | 148 | return ( |
| 149 | 149 | <div className="flex h-screen flex-col bg-background text-foreground"> |
| 150 | 150 | <div className="flex flex-1 items-center justify-center"> |
| 151 | <p className="text-sm text-muted-foreground">Connecting to CodeThing server...</p> | |
| 151 | <p className="text-sm text-muted-foreground">Connecting to T3 Code server...</p> | |
| 152 | 152 | </div> |
| 153 | 153 | </div> |
| 154 | 154 | ); |
apps/renderer/src/components/ChatView.tsx+3-3| ... | ... | @@ -2,7 +2,7 @@ import { |
| 2 | 2 | PROVIDER_SEND_TURN_MAX_INPUT_CHARS, |
| 3 | 3 | type ProviderApprovalDecision, |
| 4 | 4 | type ProviderEvent, |
| 5 | } from "@acme/contracts"; | |
| 5 | } from "@t3tools/contracts"; | |
| 6 | 6 | import { |
| 7 | 7 | type FormEvent, |
| 8 | 8 | Fragment, |
| ... | ... | @@ -13,7 +13,7 @@ import { |
| 13 | 13 | useState, |
| 14 | 14 | } from "react"; |
| 15 | 15 | |
| 16 | import { EDITORS, type EditorId } from "@acme/contracts"; | |
| 16 | import { EDITORS, type EditorId } from "@t3tools/contracts"; | |
| 17 | 17 | import { isElectron } from "../env"; |
| 18 | 18 | import { buildBootstrapInput } from "../historyBootstrap"; |
| 19 | 19 | import { |
| ... | ... | @@ -50,7 +50,7 @@ function editorLabel(editor: (typeof EDITORS)[number]): string { |
| 50 | 50 | return editor.command ? editor.label : FILE_MANAGER_LABEL; |
| 51 | 51 | } |
| 52 | 52 | |
| 53 | const LAST_EDITOR_KEY = "codething:last-editor"; | |
| 53 | const LAST_EDITOR_KEY = "t3code:last-editor"; | |
| 54 | 54 | const MAX_VISIBLE_WORK_LOG_ENTRIES = 6; |
| 55 | 55 | |
| 56 | 56 | function workToneClass(tone: "thinking" | "tool" | "info" | "error"): string { |
apps/renderer/src/components/Sidebar.tsx+2-5| ... | ... | @@ -202,12 +202,9 @@ export default function Sidebar() { |
| 202 | 202 | {/* Drag region / traffic light space (Electron only) */} |
| 203 | 203 | {isElectron && <div className="drag-region h-[52px] shrink-0" />} |
| 204 | 204 | {/* Branding */} |
| 205 | <div className={`flex items-center gap-2 px-4 pb-4 ${isElectron ? "" : "pt-4"}`}> | |
| 206 | <div className="flex h-7 w-7 items-center justify-center rounded-lg bg-primary text-xs font-bold text-primary-foreground"> | |
| 207 | CT | |
| 208 | </div> | |
| 205 | <div className={`flex items-center gap-2.5 px-4 pb-4 ${isElectron ? "" : "pt-4"}`}> | |
| 209 | 206 | <span className="flex-1 text-sm font-semibold tracking-tight text-foreground"> |
| 210 | CodeThing | |
| 207 | T3 <span className="font-normal text-muted-foreground">Code</span> | |
| 211 | 208 | </span> |
| 212 | 209 | <button |
| 213 | 210 | type="button" |
apps/renderer/src/hooks/useTheme.ts+1-1| ... | ... | @@ -2,7 +2,7 @@ import { useCallback, useEffect, useSyncExternalStore } from "react"; |
| 2 | 2 | |
| 3 | 3 | type Theme = "light" | "dark" | "system"; |
| 4 | 4 | |
| 5 | const STORAGE_KEY = "codething:theme"; | |
| 5 | const STORAGE_KEY = "t3code:theme"; | |
| 6 | 6 | const MEDIA_QUERY = "(prefers-color-scheme: dark)"; |
| 7 | 7 | |
| 8 | 8 | let listeners: Array<() => void> = []; |
apps/renderer/src/index.css+8-8| ... | ... | @@ -83,8 +83,8 @@ |
| 83 | 83 | --card-foreground: var(--color-neutral-800); |
| 84 | 84 | --popover: var(--color-white); |
| 85 | 85 | --popover-foreground: var(--color-neutral-800); |
| 86 | --primary: var(--color-neutral-800); | |
| 87 | --primary-foreground: var(--color-neutral-50); | |
| 86 | --primary: oklch(0.488 0.217 264); | |
| 87 | --primary-foreground: var(--color-white); | |
| 88 | 88 | --secondary: --alpha(var(--color-black) / 4%); |
| 89 | 89 | --secondary-foreground: var(--color-neutral-800); |
| 90 | 90 | --muted: --alpha(var(--color-black) / 4%); |
| ... | ... | @@ -93,12 +93,12 @@ |
| 93 | 93 | var(--color-neutral-500) 90%, |
| 94 | 94 | var(--color-black) |
| 95 | 95 | ); |
| 96 | --accent: --alpha(var(--color-black) / 4%); | |
| 96 | --accent: --alpha(var(--color-black) / 5%); | |
| 97 | 97 | --accent-foreground: var(--color-neutral-800); |
| 98 | 98 | --destructive: var(--color-red-500); |
| 99 | 99 | --border: --alpha(var(--color-black) / 8%); |
| 100 | 100 | --input: --alpha(var(--color-black) / 10%); |
| 101 | --ring: var(--color-neutral-400); | |
| 101 | --ring: oklch(0.488 0.217 264); | |
| 102 | 102 | --chart-1: oklch(0.646 0.222 41.116); |
| 103 | 103 | --chart-2: oklch(0.6 0.118 184.704); |
| 104 | 104 | --chart-3: oklch(0.398 0.07 227.392); |
| ... | ... | @@ -132,8 +132,8 @@ |
| 132 | 132 | --card-foreground: var(--color-neutral-100); |
| 133 | 133 | --popover: color-mix(in srgb, var(--background) 98%, var(--color-white)); |
| 134 | 134 | --popover-foreground: var(--color-neutral-100); |
| 135 | --primary: var(--color-neutral-100); | |
| 136 | --primary-foreground: var(--color-neutral-800); | |
| 135 | --primary: oklch(0.588 0.217 264); | |
| 136 | --primary-foreground: var(--color-white); | |
| 137 | 137 | --secondary: --alpha(var(--color-white) / 4%); |
| 138 | 138 | --secondary-foreground: var(--color-neutral-100); |
| 139 | 139 | --muted: --alpha(var(--color-white) / 4%); |
| ... | ... | @@ -151,7 +151,7 @@ |
| 151 | 151 | ); |
| 152 | 152 | --border: --alpha(var(--color-white) / 6%); |
| 153 | 153 | --input: --alpha(var(--color-white) / 8%); |
| 154 | --ring: var(--color-neutral-500); | |
| 154 | --ring: oklch(0.588 0.217 264); | |
| 155 | 155 | --chart-1: oklch(0.488 0.243 264.376); |
| 156 | 156 | --chart-2: oklch(0.696 0.17 162.48); |
| 157 | 157 | --chart-3: oklch(0.769 0.188 70.08); |
| ... | ... | @@ -177,7 +177,7 @@ |
| 177 | 177 | |
| 178 | 178 | body { |
| 179 | 179 | font-family: |
| 180 | -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; | |
| 180 | "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; | |
| 181 | 181 | margin: 0; |
| 182 | 182 | padding: 0; |
| 183 | 183 | min-height: 100vh; |
apps/renderer/src/model-logic.ts+1-1| ... | ... | @@ -3,7 +3,7 @@ export { |
| 3 | 3 | MODEL_OPTIONS, |
| 4 | 4 | normalizeModelSlug, |
| 5 | 5 | resolveModelSlug, |
| 6 | } from "@acme/contracts"; | |
| 6 | } from "@t3tools/contracts"; | |
| 7 | 7 | |
| 8 | 8 | export const REASONING_OPTIONS = ["xhigh", "high", "medium", "low"] as const; |
| 9 | 9 | export const DEFAULT_REASONING = "high"; |
apps/renderer/src/session-logic.test.ts+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | import { describe, expect, it } from "vitest"; |
| 2 | 2 | |
| 3 | import type { ProviderEvent, ProviderSession } from "@acme/contracts"; | |
| 3 | import type { ProviderEvent, ProviderSession } from "@t3tools/contracts"; | |
| 4 | 4 | import { |
| 5 | 5 | type WorkLogEntry, |
| 6 | 6 | applyEventToMessages, |
apps/renderer/src/session-logic.ts+1-1| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | import type { NativeApi, ProviderEvent, ProviderKind, ProviderSession } from "@acme/contracts"; | |
| 1 | import type { NativeApi, ProviderEvent, ProviderKind, ProviderSession } from "@t3tools/contracts"; | |
| 2 | 2 | import type { ChatMessage, SessionPhase } from "./types"; |
| 3 | 3 | import { createWsNativeApi } from "./wsNativeApi"; |
| 4 | 4 |
apps/renderer/src/store.test.ts+1-1| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | import type { ProviderEvent, ProviderSession } from "@acme/contracts"; | |
| 1 | import type { ProviderEvent, ProviderSession } from "@t3tools/contracts"; | |
| 2 | 2 | import { describe, expect, it } from "vitest"; |
| 3 | 3 | |
| 4 | 4 | import { type AppState, reducer } from "./store"; |
apps/renderer/src/store.ts+4-2| ... | ... | @@ -8,7 +8,7 @@ import { |
| 8 | 8 | useReducer, |
| 9 | 9 | } from "react"; |
| 10 | 10 | |
| 11 | import type { ProviderEvent, ProviderSession } from "@acme/contracts"; | |
| 11 | import type { ProviderEvent, ProviderSession } from "@t3tools/contracts"; | |
| 12 | 12 | import { resolveModelSlug } from "./model-logic"; |
| 13 | 13 | import { hydratePersistedState, toPersistedState } from "./persistenceSchema"; |
| 14 | 14 | import { applyEventToMessages, asObject, asString, evolveSession } from "./session-logic"; |
| ... | ... | @@ -45,8 +45,10 @@ export interface AppState { |
| 45 | 45 | diffOpen: boolean; |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | const PERSISTED_STATE_KEY = "codething:renderer-state:v4"; | |
| 48 | const PERSISTED_STATE_KEY = "t3code:renderer-state:v4"; | |
| 49 | 49 | const LEGACY_PERSISTED_STATE_KEYS = [ |
| 50 | "t3code:renderer-state:v3", | |
| 51 | "codething:renderer-state:v4", | |
| 50 | 52 | "codething:renderer-state:v3", |
| 51 | 53 | "codething:renderer-state:v2", |
| 52 | 54 | "codething:renderer-state:v1", |
apps/renderer/src/types.ts+1-1| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | import type { ProviderEvent, ProviderSession } from "@acme/contracts"; | |
| 1 | import type { ProviderEvent, ProviderSession } from "@t3tools/contracts"; | |
| 2 | 2 | |
| 3 | 3 | export type SessionPhase = "disconnected" | "connecting" | "ready" | "running"; |
| 4 | 4 | export type RuntimeMode = "approval-required" | "full-access"; |
apps/renderer/src/vite-env.d.ts+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | /// <reference types="vite/client" /> |
| 2 | 2 | |
| 3 | import type { NativeApi } from "@acme/contracts"; | |
| 3 | import type { NativeApi } from "@t3tools/contracts"; | |
| 4 | 4 | |
| 5 | 5 | interface DesktopBridge { |
| 6 | 6 | getWsUrl: () => string | null; |
apps/renderer/src/wsNativeApi.ts+1-1| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | import { type NativeApi, WS_CHANNELS, WS_METHODS, type WsWelcomePayload } from "@acme/contracts"; | |
| 1 | import { type NativeApi, WS_CHANNELS, WS_METHODS, type WsWelcomePayload } from "@t3tools/contracts"; | |
| 2 | 2 | |
| 3 | 3 | import { WsTransport } from "./wsTransport"; |
| 4 | 4 |
apps/renderer/src/wsTransport.ts+1-1| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | import type { WsPush, WsRequest, WsResponse } from "@acme/contracts"; | |
| 1 | import type { WsPush, WsRequest, WsResponse } from "@t3tools/contracts"; | |
| 2 | 2 | |
| 3 | 3 | type PushListener = (data: unknown) => void; |
| 4 | 4 |
apps/server/package.json+4-4| ... | ... | @@ -11,10 +11,10 @@ |
| 11 | 11 | "main": "./dist/index.js", |
| 12 | 12 | "scripts": { |
| 13 | 13 | "dev": "VITE_DEV_SERVER_URL=http://localhost:5173 tsx src/index.ts", |
| 14 | "dev:desktop": "CODETHING_MODE=desktop CODETHING_NO_BROWSER=1 tsx src/index.ts", | |
| 14 | "dev:desktop": "T3CODE_MODE=desktop T3CODE_NO_BROWSER=1 tsx src/index.ts", | |
| 15 | 15 | "build": "tsup && node scripts/bundle-client.mjs", |
| 16 | 16 | "start": "node dist/index.js", |
| 17 | "start:desktop": "CODETHING_MODE=desktop CODETHING_NO_BROWSER=1 node dist/index.js", | |
| 17 | "start:desktop": "T3CODE_MODE=desktop T3CODE_NO_BROWSER=1 node dist/index.js", | |
| 18 | 18 | "typecheck": "tsc --noEmit", |
| 19 | 19 | "test": "vitest run" |
| 20 | 20 | }, |
| ... | ... | @@ -23,8 +23,8 @@ |
| 23 | 23 | "ws": "^8.18.0" |
| 24 | 24 | }, |
| 25 | 25 | "devDependencies": { |
| 26 | "@acme/contracts": "workspace:*", | |
| 27 | "@acme/renderer": "workspace:*", | |
| 26 | "@t3tools/contracts": "workspace:*", | |
| 27 | "@t3tools/renderer": "workspace:*", | |
| 28 | 28 | "@types/node": "^22.10.2", |
| 29 | 29 | "@types/ws": "^8.5.13", |
| 30 | 30 | "tsup": "^8.3.5", |
apps/server/src/codexAppServerManager.ts+4-4| ... | ... | @@ -11,8 +11,8 @@ import type { |
| 11 | 11 | ProviderSession, |
| 12 | 12 | ProviderSessionStartInput, |
| 13 | 13 | ProviderTurnStartResult, |
| 14 | } from "@acme/contracts"; | |
| 15 | import { normalizeModelSlug } from "@acme/contracts"; | |
| 14 | } from "@t3tools/contracts"; | |
| 15 | import { normalizeModelSlug } from "@t3tools/contracts"; | |
| 16 | 16 | |
| 17 | 17 | type PendingRequestKey = string; |
| 18 | 18 | |
| ... | ... | @@ -180,8 +180,8 @@ export class CodexAppServerManager extends EventEmitter<CodexAppServerManagerEve |
| 180 | 180 | try { |
| 181 | 181 | await this.sendRequest(context, "initialize", { |
| 182 | 182 | clientInfo: { |
| 183 | name: "codething_desktop", | |
| 184 | title: "CodeThing Desktop", | |
| 183 | name: "t3code_desktop", | |
| 184 | title: "T3 Code Desktop", | |
| 185 | 185 | version: "0.1.0", |
| 186 | 186 | }, |
| 187 | 187 | capabilities: { |
apps/server/src/index.ts+8-8| ... | ... | @@ -29,7 +29,7 @@ function parsePort(value: string | undefined): number | undefined { |
| 29 | 29 | if (!value) return undefined; |
| 30 | 30 | const parsed = Number(value); |
| 31 | 31 | if (!Number.isInteger(parsed) || parsed < 1 || parsed > 65535) { |
| 32 | throw new Error(`Invalid CODETHING_PORT: ${value}`); | |
| 32 | throw new Error(`Invalid T3CODE_PORT: ${value}`); | |
| 33 | 33 | } |
| 34 | 34 | return parsed; |
| 35 | 35 | } |
| ... | ... | @@ -97,15 +97,15 @@ function resolveStaticDir(): string | undefined { |
| 97 | 97 | } |
| 98 | 98 | |
| 99 | 99 | async function main() { |
| 100 | const mode: RuntimeMode = process.env.CODETHING_MODE === "desktop" ? "desktop" : "web"; | |
| 101 | const requestedPort = parsePort(process.env.CODETHING_PORT); | |
| 100 | const mode: RuntimeMode = process.env.T3CODE_MODE === "desktop" ? "desktop" : "web"; | |
| 101 | const requestedPort = parsePort(process.env.T3CODE_PORT); | |
| 102 | 102 | const port = |
| 103 | 103 | requestedPort ?? (mode === "desktop" ? DEFAULT_PORT : await findAvailablePort(DEFAULT_PORT)); |
| 104 | const stateDir = resolveStateDir(process.env.CODETHING_STATE_DIR); | |
| 104 | const stateDir = resolveStateDir(process.env.T3CODE_STATE_DIR); | |
| 105 | 105 | const projectRegistry = new ProjectRegistry(stateDir); |
| 106 | 106 | const devUrl = process.env.VITE_DEV_SERVER_URL; |
| 107 | const noBrowser = parseBooleanEnv(process.env.CODETHING_NO_BROWSER) ?? mode === "desktop"; | |
| 108 | const authToken = process.env.CODETHING_AUTH_TOKEN; | |
| 107 | const noBrowser = parseBooleanEnv(process.env.T3CODE_NO_BROWSER) ?? mode === "desktop"; | |
| 108 | const authToken = process.env.T3CODE_AUTH_TOKEN; | |
| 109 | 109 | const staticDir = devUrl ? undefined : resolveStaticDir(); |
| 110 | 110 | |
| 111 | 111 | if (!devUrl && !staticDir) { |
| ... | ... | @@ -126,7 +126,7 @@ async function main() { |
| 126 | 126 | await server.start(); |
| 127 | 127 | |
| 128 | 128 | const url = `http://localhost:${port}`; |
| 129 | logger.info("CodeThing running", { | |
| 129 | logger.info("T3 Code running", { | |
| 130 | 130 | url, |
| 131 | 131 | cwd, |
| 132 | 132 | mode, |
| ... | ... | @@ -171,6 +171,6 @@ async function main() { |
| 171 | 171 | } |
| 172 | 172 | |
| 173 | 173 | main().catch((err) => { |
| 174 | logger.error("failed to start CodeThing", { error: err }); | |
| 174 | logger.error("failed to start T3 Code", { error: err }); | |
| 175 | 175 | process.exit(1); |
| 176 | 176 | }); |
apps/server/src/projectRegistry.ts+1-1| ... | ... | @@ -11,7 +11,7 @@ import { |
| 11 | 11 | projectAddInputSchema, |
| 12 | 12 | projectRecordSchema, |
| 13 | 13 | projectRemoveInputSchema, |
| 14 | } from "@acme/contracts"; | |
| 14 | } from "@t3tools/contracts"; | |
| 15 | 15 | |
| 16 | 16 | function normalizeCwd(rawCwd: string): string { |
| 17 | 17 | const resolved = path.resolve(rawCwd.trim()); |
apps/server/src/providerManager.ts+1-1| ... | ... | @@ -16,7 +16,7 @@ import { |
| 16 | 16 | providerSendTurnInputSchema, |
| 17 | 17 | providerSessionStartInputSchema, |
| 18 | 18 | providerStopSessionInputSchema, |
| 19 | } from "@acme/contracts"; | |
| 19 | } from "@t3tools/contracts"; | |
| 20 | 20 | import { CodexAppServerManager } from "./codexAppServerManager"; |
| 21 | 21 | |
| 22 | 22 | export interface ProviderManagerEvents { |
apps/server/src/wsServer.test.ts+6-6| ... | ... | @@ -6,7 +6,7 @@ import { describe, expect, it, afterEach, vi } from "vitest"; |
| 6 | 6 | import { createServer } from "./wsServer"; |
| 7 | 7 | import WebSocket from "ws"; |
| 8 | 8 | |
| 9 | import { WS_CHANNELS, WS_METHODS, type WsPush, type WsResponse } from "@acme/contracts"; | |
| 9 | import { WS_CHANNELS, WS_METHODS, type WsPush, type WsResponse } from "@t3tools/contracts"; | |
| 10 | 10 | import { ProjectRegistry } from "./projectRegistry"; |
| 11 | 11 | |
| 12 | 12 | interface PendingMessages { |
| ... | ... | @@ -87,7 +87,7 @@ describe("WebSocket Server", () => { |
| 87 | 87 | stateDir?: string; |
| 88 | 88 | } = {}, |
| 89 | 89 | ): ReturnType<typeof createServer> { |
| 90 | const stateDir = options.stateDir ?? makeTempDir("codething-ws-state-"); | |
| 90 | const stateDir = options.stateDir ?? makeTempDir("t3code-ws-state-"); | |
| 91 | 91 | return createServer({ |
| 92 | 92 | port: 0, |
| 93 | 93 | cwd: options.cwd ?? "/test/project", |
| ... | ... | @@ -234,8 +234,8 @@ describe("WebSocket Server", () => { |
| 234 | 234 | }); |
| 235 | 235 | |
| 236 | 236 | it("supports projects list/add/dedupe/remove", async () => { |
| 237 | const stateDir = makeTempDir("codething-ws-projects-state-"); | |
| 238 | const firstProjectCwd = makeTempDir("codething-ws-project-a-"); | |
| 237 | const stateDir = makeTempDir("t3code-ws-projects-state-"); | |
| 238 | const firstProjectCwd = makeTempDir("t3code-ws-project-a-"); | |
| 239 | 239 | |
| 240 | 240 | server = createTestServer({ stateDir, cwd: "/test" }); |
| 241 | 241 | await server.start(); |
| ... | ... | @@ -282,8 +282,8 @@ describe("WebSocket Server", () => { |
| 282 | 282 | }); |
| 283 | 283 | |
| 284 | 284 | it("prunes missing projects on startup", async () => { |
| 285 | const stateDir = makeTempDir("codething-ws-prune-state-"); | |
| 286 | const existing = makeTempDir("codething-ws-existing-project-"); | |
| 285 | const stateDir = makeTempDir("t3code-ws-prune-state-"); | |
| 286 | const existing = makeTempDir("t3code-ws-existing-project-"); | |
| 287 | 287 | const missing = path.join(stateDir, "definitely-missing"); |
| 288 | 288 | const now = new Date().toISOString(); |
| 289 | 289 | const projectsFile = path.join(stateDir, "projects.json"); |
apps/server/src/wsServer.ts+2-2| ... | ... | @@ -13,7 +13,7 @@ import { |
| 13 | 13 | type WsRequest, |
| 14 | 14 | type WsResponse, |
| 15 | 15 | wsRequestSchema, |
| 16 | } from "@acme/contracts"; | |
| 16 | } from "@t3tools/contracts"; | |
| 17 | 17 | import { WebSocketServer, type WebSocket } from "ws"; |
| 18 | 18 | |
| 19 | 19 | import { createLogger } from "./logger"; |
| ... | ... | @@ -71,7 +71,7 @@ export function createServer(options: ServerOptions) { |
| 71 | 71 | const clients = new Set<WebSocket>(); |
| 72 | 72 | const logger = createLogger("ws"); |
| 73 | 73 | const logWebSocketEvents = |
| 74 | explicitLogWsEvents ?? parseBooleanEnv(process.env.CODETHING_LOG_WS_EVENTS) ?? Boolean(devUrl); | |
| 74 | explicitLogWsEvents ?? parseBooleanEnv(process.env.T3CODE_LOG_WS_EVENTS) ?? Boolean(devUrl); | |
| 75 | 75 | |
| 76 | 76 | function logOutgoingPush(push: WsPush, recipients: number) { |
| 77 | 77 | if (!logWebSocketEvents) return; |
apps/server/tsup.config.ts+1-1| ... | ... | @@ -6,7 +6,7 @@ export default defineConfig({ |
| 6 | 6 | outDir: "dist", |
| 7 | 7 | sourcemap: true, |
| 8 | 8 | clean: true, |
| 9 | noExternal: ["@acme/contracts"], | |
| 9 | noExternal: ["@t3tools/contracts"], | |
| 10 | 10 | banner: { |
| 11 | 11 | js: '#!/usr/bin/env node\n', |
| 12 | 12 | }, |
bun.lock+12-12| ... | ... | @@ -13,7 +13,7 @@ |
| 13 | 13 | }, |
| 14 | 14 | }, |
| 15 | 15 | "apps/desktop": { |
| 16 | "name": "@acme/desktop", | |
| 16 | "name": "@t3tools/desktop", | |
| 17 | 17 | "version": "0.0.0", |
| 18 | 18 | "dependencies": { |
| 19 | 19 | "electron": "33.4.11", |
| ... | ... | @@ -29,10 +29,10 @@ |
| 29 | 29 | }, |
| 30 | 30 | }, |
| 31 | 31 | "apps/renderer": { |
| 32 | "name": "@acme/renderer", | |
| 32 | "name": "@t3tools/renderer", | |
| 33 | 33 | "version": "0.0.0", |
| 34 | 34 | "dependencies": { |
| 35 | "@acme/contracts": "workspace:*", | |
| 35 | "@t3tools/contracts": "workspace:*", | |
| 36 | 36 | "highlight.js": "^11.11.1", |
| 37 | 37 | "lucide-react": "^0.563.0", |
| 38 | 38 | "react": "^19.0.0", |
| ... | ... | @@ -64,8 +64,8 @@ |
| 64 | 64 | "ws": "^8.18.0", |
| 65 | 65 | }, |
| 66 | 66 | "devDependencies": { |
| 67 | "@acme/contracts": "workspace:*", | |
| 68 | "@acme/renderer": "workspace:*", | |
| 67 | "@t3tools/contracts": "workspace:*", | |
| 68 | "@t3tools/renderer": "workspace:*", | |
| 69 | 69 | "@types/node": "^22.10.2", |
| 70 | 70 | "@types/ws": "^8.5.13", |
| 71 | 71 | "tsup": "^8.3.5", |
| ... | ... | @@ -74,7 +74,7 @@ |
| 74 | 74 | }, |
| 75 | 75 | }, |
| 76 | 76 | "packages/contracts": { |
| 77 | "name": "@acme/contracts", | |
| 77 | "name": "@t3tools/contracts", | |
| 78 | 78 | "version": "0.0.0", |
| 79 | 79 | "dependencies": { |
| 80 | 80 | "zod": "^3.24.1", |
| ... | ... | @@ -86,12 +86,6 @@ |
| 86 | 86 | }, |
| 87 | 87 | }, |
| 88 | 88 | "packages": { |
| 89 | "@acme/contracts": ["@acme/contracts@workspace:packages/contracts"], | |
| 90 | ||
| 91 | "@acme/desktop": ["@acme/desktop@workspace:apps/desktop"], | |
| 92 | ||
| 93 | "@acme/renderer": ["@acme/renderer@workspace:apps/renderer"], | |
| 94 | ||
| 95 | 89 | "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], |
| 96 | 90 | |
| 97 | 91 | "@babel/compat-data": ["@babel/compat-data@7.29.0", "", {}, "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg=="], |
| ... | ... | @@ -296,6 +290,12 @@ |
| 296 | 290 | |
| 297 | 291 | "@szmarczak/http-timer": ["@szmarczak/http-timer@4.0.6", "", { "dependencies": { "defer-to-connect": "^2.0.0" } }, "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w=="], |
| 298 | 292 | |
| 293 | "@t3tools/contracts": ["@t3tools/contracts@workspace:packages/contracts"], | |
| 294 | ||
| 295 | "@t3tools/desktop": ["@t3tools/desktop@workspace:apps/desktop"], | |
| 296 | ||
| 297 | "@t3tools/renderer": ["@t3tools/renderer@workspace:apps/renderer"], | |
| 298 | ||
| 299 | 299 | "@tailwindcss/node": ["@tailwindcss/node@4.1.18", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.1.18" } }, "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ=="], |
| 300 | 300 | |
| 301 | 301 | "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.18", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.18", "@tailwindcss/oxide-darwin-arm64": "4.1.18", "@tailwindcss/oxide-darwin-x64": "4.1.18", "@tailwindcss/oxide-freebsd-x64": "4.1.18", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18", "@tailwindcss/oxide-linux-arm64-musl": "4.1.18", "@tailwindcss/oxide-linux-x64-gnu": "4.1.18", "@tailwindcss/oxide-linux-x64-musl": "4.1.18", "@tailwindcss/oxide-wasm32-wasi": "4.1.18", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18", "@tailwindcss/oxide-win32-x64-msvc": "4.1.18" } }, "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A=="], |
package.json+2-2| ... | ... | @@ -1,12 +1,12 @@ |
| 1 | 1 | { |
| 2 | "name": "ct-round-5", | |
| 2 | "name": "@t3tools/monorepo", | |
| 3 | 3 | "private": true, |
| 4 | 4 | "workspaces": [ |
| 5 | 5 | "apps/*", |
| 6 | 6 | "packages/*" |
| 7 | 7 | ], |
| 8 | 8 | "scripts": { |
| 9 | "dev": "CODETHING_LOG_WS_EVENTS=1 VITE_WS_URL=ws://localhost:3773 turbo run dev --ui=tui --filter=@acme/contracts --filter=@acme/renderer --filter=t3 --parallel", | |
| 9 | "dev": "T3CODE_LOG_WS_EVENTS=1 VITE_WS_URL=ws://localhost:3773 turbo run dev --ui=tui --filter=@t3tools/contracts --filter=@t3tools/renderer --filter=t3 --parallel", | |
| 10 | 10 | "dev:server": "bun run build:contracts && bun run --cwd apps/server dev", |
| 11 | 11 | "dev:web": "VITE_WS_URL=ws://localhost:3773 bun run --cwd apps/renderer dev", |
| 12 | 12 | "dev:desktop": "bun run --cwd apps/desktop dev", |
packages/contracts/package.json+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | { |
| 2 | "name": "@acme/contracts", | |
| 2 | "name": "@t3tools/contracts", | |
| 3 | 3 | "version": "0.0.0", |
| 4 | 4 | "private": true, |
| 5 | 5 | "files": [ |
turbo.json+8-8| ... | ... | @@ -4,13 +4,13 @@ |
| 4 | 4 | "PORT", |
| 5 | 5 | "VITE_WS_URL", |
| 6 | 6 | "VITE_DEV_SERVER_URL", |
| 7 | "CODETHING_LOG_WS_EVENTS", | |
| 8 | "CODETHING_MODE", | |
| 9 | "CODETHING_PORT", | |
| 10 | "CODETHING_NO_BROWSER", | |
| 11 | "CODETHING_STATE_DIR", | |
| 12 | "CODETHING_AUTH_TOKEN", | |
| 13 | "CODETHING_DESKTOP_WS_URL" | |
| 7 | "T3CODE_LOG_WS_EVENTS", | |
| 8 | "T3CODE_MODE", | |
| 9 | "T3CODE_PORT", | |
| 10 | "T3CODE_NO_BROWSER", | |
| 11 | "T3CODE_STATE_DIR", | |
| 12 | "T3CODE_AUTH_TOKEN", | |
| 13 | "T3CODE_DESKTOP_WS_URL" | |
| 14 | 14 | ], |
| 15 | 15 | "tasks": { |
| 16 | 16 | "build": { |
| ... | ... | @@ -18,7 +18,7 @@ |
| 18 | 18 | "outputs": ["dist/**", "dist-electron/**"] |
| 19 | 19 | }, |
| 20 | 20 | "dev": { |
| 21 | "dependsOn": ["@acme/contracts#build"], | |
| 21 | "dependsOn": ["@t3tools/contracts#build"], | |
| 22 | 22 | "cache": false, |
| 23 | 23 | "persistent": true |
| 24 | 24 | }, |