feat: wire native Codex UI as /console entry, keep classic console at /console-classic
ci / test (push) Successful in 45m25s
ci / test (push) Successful in 45m25s
- Vendor codex-ui-stack host/ as cloud/codex-ui-host/ (original/ not vendored, 650MB) - Bridge emulates 7 methods missing in codex 0.164.0-alpha.9, exposes 29 experimental-protocol methods (150 -> 179), Linux binary candidates, read-only POST /__codex_git - GET /console 302s to the UI host (:8095) when reachable, else falls back to the classic React console; GET /console-classic always serves it - Alignment tables: docs/codex-native-ui-alignment.md - Tests: test_console 7, new test_codex_ui_host 4, handler method pin 247 -> 249
This commit is contained in:
1 parent
41f3985248
commit
3e0ff898e0
20 files changed
+3018
-24
No files matched your search
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Projectless thread workspaces.
|
||||
*
|
||||
* Codex keeps two kinds of conversation: one attached to a project directory and
|
||||
* one that starts from nothing. The desktop main process owns the second kind —
|
||||
* it picks a folder under the user's workspace root, creates it, and hands the
|
||||
* paths back to the renderer through `projectlessThreads.createPaths`.
|
||||
*
|
||||
* The browser cannot touch the filesystem, so the Node host does it here and
|
||||
* exposes the same three paths over HTTP:
|
||||
*
|
||||
* cwd the directory this conversation runs in
|
||||
* outputDirectory where generated files land (same folder)
|
||||
* workspaceRoot the shared root that contains every thread
|
||||
*
|
||||
* Layout mirrors the desktop app: <root>/<YYYY-MM-DD>/<slug>
|
||||
*/
|
||||
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
export const WORKSPACE_ROOT =
|
||||
// Linux server default: ~/Codex. The desktop default ~/Documents/Codex
|
||||
// does not exist on a server, so it is not used here.
|
||||
process.env.CODEX_WEB_WORKSPACE_ROOT || path.join(os.homedir(), "Codex");
|
||||
|
||||
export function ensureWorkspaceRoot() {
|
||||
fs.mkdirSync(WORKSPACE_ROOT, { recursive: true });
|
||||
return WORKSPACE_ROOT;
|
||||
}
|
||||
|
||||
/** Lowercase, collapse anything awkward, keep CJK, cap the length. */
|
||||
function slugify(value) {
|
||||
const text = String(value ?? "").trim();
|
||||
if (!text) return "";
|
||||
return text
|
||||
.toLowerCase()
|
||||
.replace(/[^\p{Letter}\p{Number}]+/gu, "-")
|
||||
.replace(/^-+|-+$/g, "")
|
||||
.slice(0, 40);
|
||||
}
|
||||
|
||||
export function createProjectlessPaths({ directoryName, prompt } = {}) {
|
||||
const root = ensureWorkspaceRoot();
|
||||
const day = new Date().toISOString().slice(0, 10);
|
||||
const base = slugify(directoryName) || slugify(prompt) || "thread";
|
||||
|
||||
let dir = path.join(root, day, base);
|
||||
let suffix = 1;
|
||||
while (fs.existsSync(dir)) {
|
||||
suffix += 1;
|
||||
dir = path.join(root, day, `${base}-${suffix}`);
|
||||
}
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
|
||||
return { cwd: dir, outputDirectory: dir, workspaceRoot: root };
|
||||
}
|
||||
|
||||
export function readWorkspaceRoot() {
|
||||
return { workspaceRoot: ensureWorkspaceRoot() };
|
||||
}
|
||||
Reference in new issue
Block a user