codexui-android 0.1.89 → 0.1.91

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist-cli/index.js CHANGED
@@ -217,10 +217,9 @@ function parseApprovalPolicy(value) {
217
217
 
218
218
  // src/server/httpServer.ts
219
219
  import { fileURLToPath } from "url";
220
- import { basename as basename5, dirname as dirname3, extname as extname3, isAbsolute as isAbsolute3, join as join7 } from "path";
220
+ import { dirname as dirname3, extname as extname3, isAbsolute as isAbsolute3, join as join7 } from "path";
221
221
  import { existsSync as existsSync3 } from "fs";
222
222
  import { writeFile as writeFile5, stat as stat6 } from "fs/promises";
223
- import { createReadStream as createReadStream2 } from "fs";
224
223
  import express from "express";
225
224
 
226
225
  // src/server/codexAppServerBridge.ts
@@ -7281,92 +7280,76 @@ function createAuthSession(password) {
7281
7280
  }
7282
7281
 
7283
7282
  // src/server/localBrowseUi.ts
7284
- import { basename as basename4, dirname as dirname2, extname as extname2, join as join6 } from "path";
7283
+ import { dirname as dirname2, extname as extname2, join as join6 } from "path";
7285
7284
  import { open, readFile as readFile4, readdir as readdir3, stat as stat5 } from "fs/promises";
7286
- var TEXT_LANGUAGE = {
7287
- label: "text",
7288
- aceMode: "text"
7289
- };
7290
- var BAZEL_LANGUAGE = {
7291
- label: "bazel",
7292
- aceMode: "python"
7293
- };
7294
- var FILE_LANGUAGE_RULES_BY_NAME = /* @__PURE__ */ new Map([
7295
- ["build", BAZEL_LANGUAGE],
7296
- ["build.bazel", BAZEL_LANGUAGE],
7297
- ["workspace", BAZEL_LANGUAGE],
7298
- ["workspace.bazel", BAZEL_LANGUAGE],
7299
- ["module.bazel", BAZEL_LANGUAGE],
7300
- [".bazelrc", BAZEL_LANGUAGE],
7301
- [".env", TEXT_LANGUAGE],
7302
- [".gitignore", TEXT_LANGUAGE],
7303
- [".npmrc", TEXT_LANGUAGE]
7285
+ var TEXT_EDITABLE_EXTENSIONS = /* @__PURE__ */ new Set([
7286
+ ".txt",
7287
+ ".md",
7288
+ ".json",
7289
+ ".js",
7290
+ ".ts",
7291
+ ".tsx",
7292
+ ".jsx",
7293
+ ".css",
7294
+ ".scss",
7295
+ ".html",
7296
+ ".htm",
7297
+ ".xml",
7298
+ ".yml",
7299
+ ".yaml",
7300
+ ".log",
7301
+ ".csv",
7302
+ ".env",
7303
+ ".py",
7304
+ ".sh",
7305
+ ".toml",
7306
+ ".ini",
7307
+ ".conf",
7308
+ ".sql",
7309
+ ".bat",
7310
+ ".cmd",
7311
+ ".ps1"
7304
7312
  ]);
7305
- var FILE_LANGUAGE_RULES_BY_EXTENSION = /* @__PURE__ */ new Map([
7306
- [".txt", TEXT_LANGUAGE],
7307
- [".log", TEXT_LANGUAGE],
7308
- [".csv", TEXT_LANGUAGE],
7309
- [".md", { label: "markdown", aceMode: "markdown" }],
7310
- [".markdown", { label: "markdown", aceMode: "markdown" }],
7311
- [".json", { label: "json", aceMode: "json" }],
7312
- [".jsonc", { label: "json", aceMode: "json" }],
7313
- [".yaml", { label: "yaml", aceMode: "yaml" }],
7314
- [".yml", { label: "yaml", aceMode: "yaml" }],
7315
- [".lua", { label: "lua", aceMode: "lua" }],
7316
- [".rs", { label: "rust", aceMode: "rust" }],
7317
- [".py", { label: "python", aceMode: "python" }],
7318
- [".c", { label: "c", aceMode: "c_cpp" }],
7319
- [".h", { label: "c/c++", aceMode: "c_cpp" }],
7320
- [".cpp", { label: "c++", aceMode: "c_cpp" }],
7321
- [".cc", { label: "c++", aceMode: "c_cpp" }],
7322
- [".cxx", { label: "c++", aceMode: "c_cpp" }],
7323
- [".hpp", { label: "c++", aceMode: "c_cpp" }],
7324
- [".hh", { label: "c++", aceMode: "c_cpp" }],
7325
- [".hxx", { label: "c++", aceMode: "c_cpp" }],
7326
- [".toml", { label: "toml", aceMode: "toml" }],
7327
- [".bzl", BAZEL_LANGUAGE],
7328
- [".bazel", BAZEL_LANGUAGE],
7329
- [".js", { label: "javascript", aceMode: "javascript" }],
7330
- [".mjs", { label: "javascript", aceMode: "javascript" }],
7331
- [".cjs", { label: "javascript", aceMode: "javascript" }],
7332
- [".jsx", { label: "jsx", aceMode: "jsx" }],
7333
- [".ts", { label: "typescript", aceMode: "typescript" }],
7334
- [".mts", { label: "typescript", aceMode: "typescript" }],
7335
- [".cts", { label: "typescript", aceMode: "typescript" }],
7336
- [".tsx", { label: "tsx", aceMode: "tsx" }],
7337
- [".vue", { label: "vue", aceMode: "vue" }],
7338
- [".css", { label: "css", aceMode: "css" }],
7339
- [".scss", { label: "scss", aceMode: "scss" }],
7340
- [".html", { label: "html", aceMode: "html" }],
7341
- [".htm", { label: "html", aceMode: "html" }],
7342
- [".xml", { label: "xml", aceMode: "xml" }],
7343
- [".sql", { label: "sql", aceMode: "sql" }],
7344
- [".sh", { label: "shell", aceMode: "sh" }],
7345
- [".bash", { label: "shell", aceMode: "sh" }],
7346
- [".zsh", { label: "shell", aceMode: "sh" }],
7347
- [".ini", { label: "ini", aceMode: "ini" }],
7348
- [".conf", { label: "ini", aceMode: "ini" }],
7349
- [".ps1", { label: "powershell", aceMode: "powershell" }],
7350
- [".bat", TEXT_LANGUAGE],
7351
- [".cmd", TEXT_LANGUAGE]
7352
- ]);
7353
- var MAX_INLINE_PREVIEW_BYTES = 1024 * 1024;
7354
- var DARK_MODE_STORAGE_KEY = "codex-web-local.dark-mode.v1";
7355
- var ACE_CDN_BASE = "https://cdnjs.cloudflare.com/ajax/libs/ace/1.36.2";
7356
- function getLanguageConfigForPath(pathValue) {
7357
- const fileName = basename4(pathValue).toLowerCase();
7358
- if (fileName === ".env" || fileName.startsWith(".env.")) {
7359
- return { language: TEXT_LANGUAGE, recognized: true };
7360
- }
7361
- const exactMatch = FILE_LANGUAGE_RULES_BY_NAME.get(fileName);
7362
- if (exactMatch) {
7363
- return { language: exactMatch, recognized: true };
7313
+ function languageForPath(pathValue) {
7314
+ const extension = extname2(pathValue).toLowerCase();
7315
+ switch (extension) {
7316
+ case ".js":
7317
+ return "javascript";
7318
+ case ".ts":
7319
+ return "typescript";
7320
+ case ".jsx":
7321
+ return "javascript";
7322
+ case ".tsx":
7323
+ return "typescript";
7324
+ case ".py":
7325
+ return "python";
7326
+ case ".sh":
7327
+ return "sh";
7328
+ case ".css":
7329
+ case ".scss":
7330
+ return "css";
7331
+ case ".html":
7332
+ case ".htm":
7333
+ return "html";
7334
+ case ".json":
7335
+ return "json";
7336
+ case ".md":
7337
+ return "markdown";
7338
+ case ".yaml":
7339
+ case ".yml":
7340
+ return "yaml";
7341
+ case ".xml":
7342
+ return "xml";
7343
+ case ".sql":
7344
+ return "sql";
7345
+ case ".toml":
7346
+ return "ini";
7347
+ case ".ini":
7348
+ case ".conf":
7349
+ return "ini";
7350
+ default:
7351
+ return "plaintext";
7364
7352
  }
7365
- const extensionMatch = FILE_LANGUAGE_RULES_BY_EXTENSION.get(extname2(fileName));
7366
- if (extensionMatch) {
7367
- return { language: extensionMatch, recognized: true };
7368
- }
7369
- return { language: TEXT_LANGUAGE, recognized: false };
7370
7353
  }
7371
7354
  function normalizeLocalPath(rawPath) {
7372
7355
  const trimmed = rawPath.trim();
@@ -7389,7 +7372,7 @@ function decodeBrowsePath(rawPath) {
7389
7372
  }
7390
7373
  }
7391
7374
  function isTextEditablePath(pathValue) {
7392
- return getLanguageConfigForPath(pathValue).recognized;
7375
+ return TEXT_EDITABLE_EXTENSIONS.has(extname2(pathValue).toLowerCase());
7393
7376
  }
7394
7377
  function isHiddenName(value) {
7395
7378
  return value.startsWith(".");
@@ -7423,157 +7406,25 @@ async function isTextEditableFile(localPath) {
7423
7406
  return false;
7424
7407
  }
7425
7408
  }
7426
- async function getLocalTextFileMetadata(localPath) {
7427
- const { language, recognized } = getLanguageConfigForPath(localPath);
7428
- try {
7429
- const fileStat = await stat5(localPath);
7430
- if (!fileStat.isFile()) return null;
7431
- if (recognized) {
7432
- return {
7433
- language,
7434
- sizeBytes: fileStat.size
7435
- };
7436
- }
7437
- const isText = await probeFileIsText(localPath);
7438
- if (!isText) return null;
7439
- return {
7440
- language,
7441
- sizeBytes: fileStat.size
7442
- };
7443
- } catch {
7444
- return null;
7445
- }
7446
- }
7447
7409
  function escapeHtml(value) {
7448
7410
  return value.replace(/&/gu, "&amp;").replace(/</gu, "&lt;").replace(/>/gu, "&gt;").replace(/"/gu, "&quot;").replace(/'/gu, "&#39;");
7449
7411
  }
7450
7412
  function normalizeNewProjectName(value) {
7451
7413
  return value.trim().replace(/[\\/]+/gu, "").trim();
7452
7414
  }
7453
- function normalizeLineTarget(value) {
7454
- return Number.isInteger(value) && Number(value) > 0 ? Number(value) : null;
7455
- }
7456
- function buildLocationQuery(options) {
7457
- const query = new URLSearchParams();
7458
- const normalizedName = normalizeNewProjectName(options?.newProjectName ?? "");
7459
- const line = normalizeLineTarget(options?.line);
7460
- const column = line ? normalizeLineTarget(options?.column) : null;
7461
- if (normalizedName) query.set("newProjectName", normalizedName);
7462
- if (line) query.set("line", String(line));
7463
- if (column) query.set("column", String(column));
7464
- const encoded = query.toString();
7465
- return encoded ? `?${encoded}` : "";
7466
- }
7467
- function toBrowseHref(pathValue, options) {
7468
- return `/codex-local-browse${encodeURI(pathValue)}${buildLocationQuery(options)}`;
7469
- }
7470
- function toEditHref(pathValue, options) {
7471
- return `/codex-local-edit${encodeURI(pathValue)}${buildLocationQuery(options)}`;
7415
+ function toBrowseHref(pathValue, newProjectName = "") {
7416
+ const normalizedName = normalizeNewProjectName(newProjectName);
7417
+ const query = normalizedName ? `?newProjectName=${encodeURIComponent(normalizedName)}` : "";
7418
+ return `/codex-local-browse${encodeURI(pathValue)}${query}`;
7472
7419
  }
7473
- function toRawFileHref(pathValue, options) {
7474
- const query = new URLSearchParams({ path: pathValue });
7475
- if (options?.download === true) {
7476
- query.set("download", "1");
7477
- }
7478
- return `/codex-local-file?${query.toString()}`;
7420
+ function toEditHref(pathValue, newProjectName = "") {
7421
+ const normalizedName = normalizeNewProjectName(newProjectName);
7422
+ const query = normalizedName ? `?newProjectName=${encodeURIComponent(normalizedName)}` : "";
7423
+ return `/codex-local-edit${encodeURI(pathValue)}${query}`;
7479
7424
  }
7480
7425
  function escapeForInlineScriptString(value) {
7481
7426
  return JSON.stringify(value).replace(/<\//gu, "<\\/").replace(/<!--/gu, "<\\!--").replace(/\u2028/gu, "\\u2028").replace(/\u2029/gu, "\\u2029");
7482
7427
  }
7483
- function renderStandaloneThemeBootstrapScript() {
7484
- return [
7485
- "(function() {",
7486
- ` const storageKey = ${JSON.stringify(DARK_MODE_STORAGE_KEY)};`,
7487
- ' const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");',
7488
- " function readStoredPreference() {",
7489
- " try {",
7490
- " const value = window.localStorage.getItem(storageKey);",
7491
- ' return value === "light" || value === "dark" ? value : "system";',
7492
- " } catch {",
7493
- ' return "system";',
7494
- " }",
7495
- " }",
7496
- " function resolveTheme(preference) {",
7497
- ' if (preference === "light" || preference === "dark") return preference;',
7498
- ' return mediaQuery.matches ? "dark" : "light";',
7499
- " }",
7500
- " function applyTheme() {",
7501
- " const preference = readStoredPreference();",
7502
- " const resolvedTheme = resolveTheme(preference);",
7503
- " document.documentElement.dataset.theme = resolvedTheme;",
7504
- " document.documentElement.style.colorScheme = resolvedTheme;",
7505
- " window.__codexLocalBrowseTheme = { preference, resolvedTheme };",
7506
- ' window.dispatchEvent(new CustomEvent("codex-local-browse-themechange", { detail: window.__codexLocalBrowseTheme }));',
7507
- " }",
7508
- " applyTheme();",
7509
- " window.__codexApplyLocalBrowseTheme = applyTheme;",
7510
- ' window.addEventListener("storage", function(event) {',
7511
- " if (event.key !== storageKey) return;",
7512
- " applyTheme();",
7513
- " });",
7514
- ' mediaQuery.addEventListener("change", function() {',
7515
- ' if (readStoredPreference() !== "system") return;',
7516
- " applyTheme();",
7517
- " });",
7518
- "})();"
7519
- ].join("\n");
7520
- }
7521
- function renderStandaloneThemeCss() {
7522
- return `
7523
- :root {
7524
- color-scheme: light;
7525
- --lb-bg: #f3f6fb;
7526
- --lb-surface: #ffffff;
7527
- --lb-surface-muted: #eef3fb;
7528
- --lb-surface-strong: #e7edf8;
7529
- --lb-toolbar-bg: rgba(243, 246, 251, 0.96);
7530
- --lb-border: #cfd9ea;
7531
- --lb-border-strong: #b6c4db;
7532
- --lb-text: #172033;
7533
- --lb-text-muted: #52607a;
7534
- --lb-link: #2457b8;
7535
- --lb-button-text: #172033;
7536
- --lb-accent-bg: #dfeafe;
7537
- --lb-accent-border: #9db8ef;
7538
- --lb-primary-bg: linear-gradient(135deg, #2f67d8 0%, #4b88ff 100%);
7539
- --lb-primary-border: #2f67d8;
7540
- --lb-primary-text: #f8fbff;
7541
- --lb-selection: rgba(77, 124, 255, 0.18);
7542
- --lb-selection-strong: rgba(77, 124, 255, 0.24);
7543
- --lb-target-line: rgba(77, 124, 255, 0.14);
7544
- --lb-target-stripe: #4d7cff;
7545
- --lb-warning-text: #8a5a00;
7546
- --lb-warning-bg: rgba(194, 136, 18, 0.12);
7547
- --lb-shadow: 0 16px 40px rgba(31, 49, 82, 0.12);
7548
- }
7549
- :root[data-theme='dark'] {
7550
- color-scheme: dark;
7551
- --lb-bg: #09111f;
7552
- --lb-surface: #0d182b;
7553
- --lb-surface-muted: #101f3a;
7554
- --lb-surface-strong: #13233d;
7555
- --lb-toolbar-bg: rgba(9, 17, 31, 0.96);
7556
- --lb-border: #20324d;
7557
- --lb-border-strong: #36557a;
7558
- --lb-text: #dbe6ff;
7559
- --lb-text-muted: #8fb8ec;
7560
- --lb-link: #8cc2ff;
7561
- --lb-button-text: #dbe6ff;
7562
- --lb-accent-bg: #162643;
7563
- --lb-accent-border: #36557a;
7564
- --lb-primary-bg: linear-gradient(135deg, #2e6ee6 0%, #3d8cff 100%);
7565
- --lb-primary-border: #4f8de0;
7566
- --lb-primary-text: #eef6ff;
7567
- --lb-selection: rgba(140, 194, 255, 0.16);
7568
- --lb-selection-strong: rgba(140, 194, 255, 0.3);
7569
- --lb-target-line: rgba(140, 194, 255, 0.16);
7570
- --lb-target-stripe: #8cc2ff;
7571
- --lb-warning-text: #f0cf78;
7572
- --lb-warning-bg: rgba(240, 207, 120, 0.08);
7573
- --lb-shadow: 0 20px 40px rgba(0, 0, 0, 0.24);
7574
- }
7575
- `;
7576
- }
7577
7428
  async function getDirectoryItems(localPath) {
7578
7429
  const entries = await readdir3(localPath, { withFileTypes: true });
7579
7430
  const withMeta = await Promise.all(entries.map(async (entry) => {
@@ -7623,64 +7474,6 @@ function actionButtonsHtml(localPath, newProjectName) {
7623
7474
  const openButton = `<button class="header-open-btn open-folder-btn" type="button" aria-label="Open current folder in Codex" title="Open folder in Codex" data-path="${escapeHtml(localPath)}" data-label="" data-status="${escapeHtml(openFolderStatusText(normalizedName))}" data-error="${escapeHtml(failureStatusText(normalizedName))}">Open folder in Codex</button>`;
7624
7475
  return `${createButton}${openButton}`;
7625
7476
  }
7626
- function renderTextPreviewToolbar(localPath, options) {
7627
- const newProjectName = normalizeNewProjectName(options?.newProjectName ?? "");
7628
- const line = normalizeLineTarget(options?.line);
7629
- const column = line ? normalizeLineTarget(options?.column) : null;
7630
- const backHref = toBrowseHref(dirname2(localPath), { newProjectName });
7631
- const rawHref = toRawFileHref(localPath);
7632
- const downloadHref = toRawFileHref(localPath, { download: true });
7633
- const lineLocation = line ? { newProjectName, line, column } : { newProjectName };
7634
- return [
7635
- `<a href="${escapeHtml(backHref)}">Back</a>`,
7636
- `<a href="${escapeHtml(rawHref)}" target="_blank" rel="noopener noreferrer">Raw</a>`,
7637
- `<a href="${escapeHtml(downloadHref)}">Download</a>`,
7638
- `<a href="${escapeHtml(toEditHref(localPath, lineLocation))}">Edit</a>`
7639
- ].filter(Boolean).join("");
7640
- }
7641
- function formatLineTargetLabel(line, column) {
7642
- if (!line) return "";
7643
- if (column) return `line ${String(line)}:${String(column)}`;
7644
- return `line ${String(line)}`;
7645
- }
7646
- function renderPlainPreviewContent(content, targetLine) {
7647
- if (!targetLine || targetLine < 1) return escapeHtml(content);
7648
- const trailingNewline = content.endsWith("\n");
7649
- const lines = content.split("\n");
7650
- if (trailingNewline) lines.pop();
7651
- if (targetLine > lines.length) return escapeHtml(content);
7652
- return lines.map((line, index) => {
7653
- const escapedLine = escapeHtml(line || " ");
7654
- if (index + 1 === targetLine) {
7655
- return `<span id="previewTargetLine" class="preview-target-line">${escapedLine}</span>`;
7656
- }
7657
- return escapedLine;
7658
- }).join("\n") + (trailingNewline ? "\n" : "");
7659
- }
7660
- function formatPreviewSize(sizeBytes) {
7661
- if (sizeBytes >= 1024 * 1024) return `${(sizeBytes / (1024 * 1024)).toFixed(1).replace(/\.0$/u, "")} MiB`;
7662
- if (sizeBytes >= 1024) return `${Math.round(sizeBytes / 1024)} KiB`;
7663
- return `${sizeBytes} B`;
7664
- }
7665
- function renderAceLineTargetScript() {
7666
- return [
7667
- "function selectTargetLine(editorInstance, lineNumber, columnNumber) {",
7668
- " if (!lineNumber) return;",
7669
- " const zeroBasedRow = lineNumber - 1;",
7670
- " const zeroBasedColumn = Math.max(0, (columnNumber ?? 1) - 1);",
7671
- " editorInstance.gotoLine(lineNumber, zeroBasedColumn, true);",
7672
- " editorInstance.scrollToLine(lineNumber, true, true, function() {});",
7673
- " editorInstance.selection.moveCursorToPosition({ row: zeroBasedRow, column: zeroBasedColumn });",
7674
- " editorInstance.selection.selectLine();",
7675
- "}",
7676
- "function currentAceThemeName() {",
7677
- ' return document.documentElement.dataset.theme === "light" ? "tomorrow" : "tomorrow_night";',
7678
- "}",
7679
- "function applyAceTheme(editorInstance) {",
7680
- ' editorInstance.setTheme("ace/theme/" + currentAceThemeName());',
7681
- "}"
7682
- ].join("\n");
7683
- }
7684
7477
  async function getLocalDirectoryListing(localPath, options = {}) {
7685
7478
  const entries = await readdir3(localPath, { withFileTypes: true });
7686
7479
  const directories = entries.filter((entry) => entry.isDirectory()).map((entry) => ({
@@ -7704,10 +7497,10 @@ async function createDirectoryListingHtml(localPath, options) {
7704
7497
  const parentPath = dirname2(localPath);
7705
7498
  const rows = items.map((item) => {
7706
7499
  const suffix = item.isDirectory ? "/" : "";
7707
- const editAction = item.editable ? ` <a class="icon-btn" aria-label="Edit ${escapeHtml(item.name)}" href="${escapeHtml(toEditHref(item.path, { newProjectName }))}" title="Edit">\u270F\uFE0F</a>` : "";
7708
- return `<li class="file-row"><a class="file-link" href="${escapeHtml(toBrowseHref(item.path, { newProjectName }))}">${escapeHtml(item.name)}${suffix}</a><span class="row-actions">${editAction}</span></li>`;
7500
+ const editAction = item.editable ? ` <a class="icon-btn" aria-label="Edit ${escapeHtml(item.name)}" href="${escapeHtml(toEditHref(item.path, newProjectName))}" title="Edit">\u270F\uFE0F</a>` : "";
7501
+ return `<li class="file-row"><a class="file-link" href="${escapeHtml(toBrowseHref(item.path, newProjectName))}">${escapeHtml(item.name)}${suffix}</a><span class="row-actions">${editAction}</span></li>`;
7709
7502
  }).join("\n");
7710
- const parentLink = localPath !== parentPath ? `<a class="header-parent-link" href="${escapeHtml(toBrowseHref(parentPath, { newProjectName }))}">..</a>` : "";
7503
+ const parentLink = localPath !== parentPath ? `<a class="header-parent-link" href="${escapeHtml(toBrowseHref(parentPath, newProjectName))}">..</a>` : "";
7711
7504
  const pickerSummary = newProjectName ? `<p class="picker-summary">Browse to the parent folder where you want to create <strong>${escapeHtml(newProjectName)}</strong>, or open the current folder directly.</p>` : "";
7712
7505
  const actionButtons = actionButtonsHtml(localPath, newProjectName);
7713
7506
  return `<!doctype html>
@@ -7716,37 +7509,35 @@ async function createDirectoryListingHtml(localPath, options) {
7716
7509
  <meta charset="utf-8" />
7717
7510
  <meta name="viewport" content="width=device-width, initial-scale=1" />
7718
7511
  <title>Index of ${escapeHtml(localPath)}</title>
7719
- <script>${renderStandaloneThemeBootstrapScript()}</script>
7720
7512
  <style>
7721
- ${renderStandaloneThemeCss()}
7722
- body { font-family: ui-monospace, Menlo, Monaco, monospace; margin: 16px; background: var(--lb-bg); color: var(--lb-text); }
7723
- a { color: var(--lb-link); text-decoration: none; }
7513
+ body { font-family: ui-monospace, Menlo, Monaco, monospace; margin: 16px; background: #0b1020; color: #dbe6ff; }
7514
+ a { color: #8cc2ff; text-decoration: none; }
7724
7515
  a:hover { text-decoration: underline; }
7725
7516
  ul { list-style: none; padding: 0; margin: 12px 0 0; display: flex; flex-direction: column; gap: 8px; }
7726
7517
  .file-row { display: grid; grid-template-columns: minmax(0,1fr) auto; align-items: center; gap: 10px; }
7727
- .file-link { display: block; padding: 10px 12px; border: 1px solid var(--lb-border); border-radius: 10px; background: var(--lb-surface); color: var(--lb-text); overflow-wrap: anywhere; box-shadow: var(--lb-shadow); }
7518
+ .file-link { display: block; padding: 10px 12px; border: 1px solid #28405f; border-radius: 10px; background: #0f1b33; overflow-wrap: anywhere; }
7728
7519
  .header-actions { display: flex; align-items: center; gap: 10px; margin-top: 10px; flex-wrap: wrap; }
7729
- .header-parent-link { color: var(--lb-link); font-size: 14px; padding: 8px 10px; border: 1px solid var(--lb-border); border-radius: 10px; background: var(--lb-surface-muted); }
7520
+ .header-parent-link { color: #9ec8ff; font-size: 14px; padding: 8px 10px; border: 1px solid #2a4569; border-radius: 10px; background: #101f3a; }
7730
7521
  .header-parent-link:hover { text-decoration: none; filter: brightness(1.08); }
7731
7522
  .header-open-btn {
7732
7523
  height: 42px;
7733
7524
  padding: 0 14px;
7734
- border: 1px solid var(--lb-primary-border);
7525
+ border: 1px solid #4f8de0;
7735
7526
  border-radius: 10px;
7736
- background: var(--lb-primary-bg);
7737
- color: var(--lb-primary-text);
7527
+ background: linear-gradient(135deg, #2e6ee6 0%, #3d8cff 100%);
7528
+ color: #eef6ff;
7738
7529
  font-weight: 700;
7739
7530
  letter-spacing: 0.01em;
7740
7531
  cursor: pointer;
7741
- box-shadow: var(--lb-shadow);
7532
+ box-shadow: 0 6px 18px rgba(33, 90, 199, 0.35);
7742
7533
  }
7743
7534
  .header-open-btn:hover { filter: brightness(1.08); }
7744
7535
  .header-open-btn:disabled { opacity: 0.6; cursor: default; }
7745
- .picker-summary { margin: 10px 0 0; color: var(--lb-text-muted); max-width: 60rem; line-height: 1.45; }
7536
+ .picker-summary { margin: 10px 0 0; color: #b8d5ff; max-width: 60rem; line-height: 1.45; }
7746
7537
  .row-actions { display: inline-flex; align-items: center; gap: 8px; min-width: 42px; justify-content: flex-end; }
7747
- .icon-btn { display: inline-flex; align-items: center; justify-content: center; width: 42px; height: 42px; border: 1px solid var(--lb-accent-border); border-radius: 10px; background: var(--lb-accent-bg); color: var(--lb-button-text); text-decoration: none; cursor: pointer; }
7538
+ .icon-btn { display: inline-flex; align-items: center; justify-content: center; width: 42px; height: 42px; border: 1px solid #36557a; border-radius: 10px; background: #162643; color: #dbe6ff; text-decoration: none; cursor: pointer; }
7748
7539
  .icon-btn:hover { filter: brightness(1.08); text-decoration: none; }
7749
- .status { margin: 10px 0 0; color: var(--lb-text-muted); min-height: 1.25em; }
7540
+ .status { margin: 10px 0 0; color: #8cc2ff; min-height: 1.25em; }
7750
7541
  h1 { font-size: 18px; margin: 0; word-break: break-all; }
7751
7542
  @media (max-width: 640px) {
7752
7543
  body { margin: 12px; }
@@ -7807,144 +7598,10 @@ async function createDirectoryListingHtml(localPath, options) {
7807
7598
  </body>
7808
7599
  </html>`;
7809
7600
  }
7810
- async function createTextPreviewHtml(localPath, options) {
7811
- const newProjectName = normalizeNewProjectName(options?.newProjectName ?? "");
7812
- const line = normalizeLineTarget(options?.line);
7813
- const column = line ? normalizeLineTarget(options?.column) : null;
7814
- const metadata = await getLocalTextFileMetadata(localPath);
7815
- if (!metadata) {
7816
- throw new Error("Only text-like files can be previewed inline.");
7817
- }
7818
- const toolbar = renderTextPreviewToolbar(localPath, { newProjectName, line, column });
7819
- const lineTargetLabel = formatLineTargetLabel(line, column);
7820
- const previewMeta = [localPath, metadata.language.label, formatPreviewSize(metadata.sizeBytes), lineTargetLabel].filter(Boolean).join(" \xB7 ");
7821
- const previewUnavailable = metadata.sizeBytes > MAX_INLINE_PREVIEW_BYTES;
7822
- const previewContent = previewUnavailable ? "" : await readFile4(localPath, "utf8");
7823
- const previewPlainHtml = renderPlainPreviewContent(previewContent, line);
7824
- const safePreviewLiteral = escapeForInlineScriptString(previewContent);
7825
- return `<!doctype html>
7826
- <html lang="en">
7827
- <head>
7828
- <meta charset="utf-8" />
7829
- <meta name="viewport" content="width=device-width, initial-scale=1" />
7830
- <title>${escapeHtml(basename4(localPath))}</title>
7831
- <script>${renderStandaloneThemeBootstrapScript()}</script>
7832
- <style>
7833
- ${renderStandaloneThemeCss()}
7834
- html, body { margin: 0; width: 100%; min-height: 100%; }
7835
- body { min-height: 100vh; font-family: ui-monospace, Menlo, Monaco, monospace; background: var(--lb-bg); color: var(--lb-text); display: flex; flex-direction: column; }
7836
- a { color: inherit; text-decoration: none; }
7837
- .toolbar { position: sticky; top: 0; z-index: 10; display: flex; flex-direction: column; gap: 10px; padding: 12px 16px; background: var(--lb-toolbar-bg); backdrop-filter: blur(8px); border-bottom: 1px solid var(--lb-border); }
7838
- .toolbar-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
7839
- .toolbar-row a { display: inline-flex; align-items: center; justify-content: center; min-height: 38px; padding: 0 12px; border: 1px solid var(--lb-accent-border); border-radius: 10px; background: var(--lb-accent-bg); color: var(--lb-button-text); }
7840
- .toolbar-row a:hover { filter: brightness(1.08); }
7841
- .meta { color: var(--lb-text-muted); font-size: 12px; overflow-wrap: anywhere; line-height: 1.5; }
7842
- .preview-shell { flex: 1 1 auto; min-height: 0; display: flex; padding: 18px 16px 24px; }
7843
- .preview-card { flex: 1 1 auto; min-height: 0; max-width: 100%; border: 1px solid var(--lb-border); border-radius: 14px; background: var(--lb-surface); overflow: hidden; box-shadow: var(--lb-shadow); display: flex; flex-direction: column; }
7844
- .preview-notice { margin: 0; padding: 12px 16px; border-bottom: 1px solid var(--lb-border); color: var(--lb-warning-text); background: var(--lb-warning-bg); }
7845
- .preview-unavailable { padding: 26px 20px; }
7846
- .preview-unavailable-title { margin: 0 0 8px; font-size: 15px; font-weight: 700; }
7847
- .preview-unavailable-text { margin: 0; color: var(--lb-text-muted); line-height: 1.6; }
7848
- .preview-plain {
7849
- flex: 1 1 auto;
7850
- box-sizing: border-box;
7851
- margin: 0;
7852
- padding: 18px 20px 24px;
7853
- min-height: 0;
7854
- overflow: auto;
7855
- white-space: pre-wrap;
7856
- overflow-wrap: anywhere;
7857
- tab-size: 2;
7858
- line-height: 1.55;
7859
- color: var(--lb-text);
7860
- background: var(--lb-surface);
7861
- }
7862
- .preview-target-line {
7863
- display: inline-block;
7864
- min-width: 100%;
7865
- margin: 0 -20px;
7866
- padding: 0 20px;
7867
- background: var(--lb-target-line);
7868
- box-shadow: inset 3px 0 0 var(--lb-target-stripe);
7869
- }
7870
- #previewEditor { flex: 1 1 auto; width: 100%; min-height: 0; }
7871
- .ace_editor { width: 100% !important; height: 100% !important; }
7872
- .ace_marker-layer .ace_active-line { background: transparent !important; }
7873
- .ace_marker-layer .ace_selection { background: var(--lb-selection) !important; }
7874
- @media (max-width: 640px) {
7875
- .toolbar { padding: 12px; }
7876
- .preview-shell { padding: 12px; }
7877
- }
7878
- </style>
7879
- </head>
7880
- <body>
7881
- <div class="toolbar">
7882
- <div class="toolbar-row">${toolbar}</div>
7883
- <div class="meta">${escapeHtml(previewMeta)}</div>
7884
- </div>
7885
- <main class="preview-shell">
7886
- <section class="preview-card">
7887
- ${previewUnavailable ? `<div class="preview-unavailable">
7888
- <p class="preview-unavailable-title">Inline preview disabled</p>
7889
- <p class="preview-unavailable-text">This file is larger than ${String(Math.floor(MAX_INLINE_PREVIEW_BYTES / 1024))} KiB. Use <strong>Raw</strong> or <strong>Download</strong> instead.</p>
7890
- </div>` : `<pre id="previewFallback" class="preview-plain">${previewPlainHtml}</pre>
7891
- <div id="previewEditor" hidden></div>`}
7892
- </section>
7893
- </main>
7894
- ${previewUnavailable ? "" : `<script src="${ACE_CDN_BASE}/ace.min.js"></script>
7895
- <script>
7896
- const targetLineNumber = ${line ?? "null"};
7897
- const targetColumnNumber = ${column ?? "null"};
7898
- const previewFallback = document.getElementById('previewFallback');
7899
- const previewTargetLine = document.getElementById('previewTargetLine');
7900
- const previewEditor = document.getElementById('previewEditor');
7901
- ${renderAceLineTargetScript()}
7902
- if (previewTargetLine) {
7903
- previewTargetLine.scrollIntoView({ block: 'center' });
7904
- }
7905
- if (window.ace && previewEditor) {
7906
- previewEditor.hidden = false;
7907
- if (previewFallback) previewFallback.hidden = true;
7908
- ace.config.set('basePath', '${ACE_CDN_BASE}/');
7909
- const editor = ace.edit('previewEditor');
7910
- applyAceTheme(editor);
7911
- editor.session.setMode('ace/mode/${escapeHtml(metadata.language.aceMode)}');
7912
- editor.session.setUseWorker(false);
7913
- editor.setValue(${safePreviewLiteral}, -1);
7914
- editor.setOptions({
7915
- readOnly: true,
7916
- highlightActiveLine: !!targetLineNumber,
7917
- highlightGutterLine: false,
7918
- showPrintMargin: false,
7919
- fontSize: '13px',
7920
- wrap: true,
7921
- behavioursEnabled: false,
7922
- displayIndentGuides: true,
7923
- });
7924
- editor.renderer.setShowGutter(true);
7925
- editor.renderer.$cursorLayer.element.style.display = 'none';
7926
- if (targetLineNumber) {
7927
- selectTargetLine(editor, targetLineNumber, targetColumnNumber);
7928
- }
7929
- window.addEventListener('codex-local-browse-themechange', function() {
7930
- applyAceTheme(editor);
7931
- });
7932
- editor.resize();
7933
- }
7934
- </script>`}
7935
- </body>
7936
- </html>`;
7937
- }
7938
- async function createTextEditorHtml(localPath, options) {
7939
- const newProjectName = normalizeNewProjectName(options?.newProjectName ?? "");
7940
- const line = normalizeLineTarget(options?.line);
7941
- const column = line ? normalizeLineTarget(options?.column) : null;
7942
- const metadata = await getLocalTextFileMetadata(localPath);
7943
- if (!metadata) {
7944
- throw new Error("Only text-like files are editable.");
7945
- }
7601
+ async function createTextEditorHtml(localPath) {
7946
7602
  const content = await readFile4(localPath, "utf8");
7947
7603
  const parentPath = dirname2(localPath);
7604
+ const language = languageForPath(localPath);
7948
7605
  const safeContentLiteral = escapeForInlineScriptString(content);
7949
7606
  return `<!doctype html>
7950
7607
  <html lang="en">
@@ -7952,64 +7609,49 @@ async function createTextEditorHtml(localPath, options) {
7952
7609
  <meta charset="utf-8" />
7953
7610
  <meta name="viewport" content="width=device-width, initial-scale=1" />
7954
7611
  <title>Edit ${escapeHtml(localPath)}</title>
7955
- <script>${renderStandaloneThemeBootstrapScript()}</script>
7956
7612
  <style>
7957
- ${renderStandaloneThemeCss()}
7958
7613
  html, body { width: 100%; height: 100%; margin: 0; }
7959
- body { font-family: ui-monospace, Menlo, Monaco, monospace; background: var(--lb-bg); color: var(--lb-text); display: flex; flex-direction: column; overflow: hidden; }
7960
- .toolbar { position: sticky; top: 0; z-index: 10; display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; background: var(--lb-bg); border-bottom: 1px solid var(--lb-border); }
7614
+ body { font-family: ui-monospace, Menlo, Monaco, monospace; background: #0b1020; color: #dbe6ff; display: flex; flex-direction: column; overflow: hidden; }
7615
+ .toolbar { position: sticky; top: 0; z-index: 10; display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; background: #0b1020; border-bottom: 1px solid #243a5a; }
7961
7616
  .row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
7962
- button, a { background: var(--lb-accent-bg); color: var(--lb-button-text); border: 1px solid var(--lb-accent-border); padding: 6px 10px; border-radius: 6px; text-decoration: none; cursor: pointer; }
7617
+ button, a { background: #1b2a4a; color: #dbe6ff; border: 1px solid #345; padding: 6px 10px; border-radius: 6px; text-decoration: none; cursor: pointer; }
7963
7618
  button:hover, a:hover { filter: brightness(1.08); }
7964
7619
  #editor { flex: 1 1 auto; min-height: 0; width: 100%; border: none; overflow: hidden; }
7965
- #status { margin-left: 8px; color: var(--lb-text-muted); }
7966
- .ace_editor { width: 100% !important; height: 100% !important; }
7967
- .ace_marker-layer .ace_active-line { background: var(--lb-target-line) !important; }
7968
- .ace_marker-layer .ace_selection { background: var(--lb-selection-strong) !important; }
7969
- .meta { opacity: 0.9; font-size: 12px; overflow-wrap: anywhere; color: var(--lb-text-muted); }
7620
+ #status { margin-left: 8px; color: #8cc2ff; }
7621
+ .ace_editor { background: #07101f !important; color: #dbe6ff !important; width: 100% !important; height: 100% !important; }
7622
+ .ace_gutter { background: #07101f !important; color: #6f8eb5 !important; }
7623
+ .ace_marker-layer .ace_active-line { background: #10213c !important; }
7624
+ .ace_marker-layer .ace_selection { background: rgba(140, 194, 255, 0.3) !important; }
7625
+ .meta { opacity: 0.9; font-size: 12px; overflow-wrap: anywhere; }
7970
7626
  </style>
7971
7627
  </head>
7972
7628
  <body>
7973
7629
  <div class="toolbar">
7974
7630
  <div class="row">
7975
- <a href="${escapeHtml(toBrowseHref(parentPath, { newProjectName }))}">Back</a>
7976
- <a href="${escapeHtml(toBrowseHref(localPath, { newProjectName, line, column }))}">Preview</a>
7977
- <a href="${escapeHtml(toRawFileHref(localPath))}" target="_blank" rel="noopener noreferrer">Raw</a>
7978
- <a href="${escapeHtml(toRawFileHref(localPath, { download: true }))}">Download</a>
7631
+ <a href="${escapeHtml(toBrowseHref(parentPath))}">Back</a>
7979
7632
  <button id="saveBtn" type="button">Save</button>
7980
7633
  <span id="status"></span>
7981
7634
  </div>
7982
- <div class="meta">${escapeHtml([localPath, metadata.language.label, formatLineTargetLabel(line, column)].filter(Boolean).join(" \xB7 "))}</div>
7635
+ <div class="meta">${escapeHtml(localPath)} \xB7 ${escapeHtml(language)}</div>
7983
7636
  </div>
7984
7637
  <div id="editor"></div>
7985
- <script src="${ACE_CDN_BASE}/ace.min.js"></script>
7986
- <script>
7987
- const targetLineNumber = ${line ?? "null"};
7988
- const targetColumnNumber = ${column ?? "null"};
7989
- const saveBtn = document.getElementById('saveBtn');
7990
- const status = document.getElementById('status');
7991
- ${renderAceLineTargetScript()}
7992
- ace.config.set('basePath', '${ACE_CDN_BASE}/');
7993
- const editor = ace.edit('editor');
7994
- applyAceTheme(editor);
7995
- editor.session.setMode('ace/mode/${escapeHtml(metadata.language.aceMode)}');
7996
- editor.session.setUseWorker(false);
7997
- editor.setValue(${safeContentLiteral}, -1);
7638
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.36.2/ace.js"></script>
7639
+ <script>
7640
+ const saveBtn = document.getElementById('saveBtn');
7641
+ const status = document.getElementById('status');
7642
+ const editor = ace.edit('editor');
7643
+ editor.setTheme('ace/theme/tomorrow_night');
7644
+ editor.session.setMode('ace/mode/${escapeHtml(language)}');
7645
+ editor.setValue(${safeContentLiteral}, -1);
7998
7646
  editor.setOptions({
7999
7647
  fontSize: '13px',
8000
7648
  wrap: true,
8001
7649
  showPrintMargin: false,
8002
7650
  useSoftTabs: true,
8003
7651
  tabSize: 2,
8004
- behavioursEnabled: true,
8005
- });
8006
- if (targetLineNumber) {
8007
- selectTargetLine(editor, targetLineNumber, targetColumnNumber);
8008
- }
8009
- window.addEventListener('codex-local-browse-themechange', function() {
8010
- applyAceTheme(editor);
8011
- });
8012
- editor.resize();
7652
+ behavioursEnabled: true,
7653
+ });
7654
+ editor.resize();
8013
7655
 
8014
7656
  saveBtn.addEventListener('click', async () => {
8015
7657
  status.textContent = 'Saving...';
@@ -8075,34 +7717,6 @@ function readWildcardPathParam(value) {
8075
7717
  if (Array.isArray(value)) return value.join("/");
8076
7718
  return "";
8077
7719
  }
8078
- function readBooleanQueryFlag(value) {
8079
- return typeof value === "string" && ["1", "true", "yes", "on"].includes(value.toLowerCase());
8080
- }
8081
- function readPositiveIntegerQueryParam(value) {
8082
- if (typeof value !== "string") return null;
8083
- const parsed = Number(value);
8084
- return Number.isInteger(parsed) && parsed > 0 ? parsed : null;
8085
- }
8086
- function localFileErrorResponse(error) {
8087
- const code = typeof error === "object" && error !== null && "code" in error ? String(error.code ?? "") : "";
8088
- const statusCode = typeof error === "object" && error !== null && "statusCode" in error ? Number(error.statusCode) : NaN;
8089
- if (code === "ENOENT" || statusCode === 404) {
8090
- return { status: 404, body: { error: "File not found." } };
8091
- }
8092
- if (code === "EACCES" || code === "EPERM" || statusCode === 403) {
8093
- return { status: 403, body: { error: "Access denied." } };
8094
- }
8095
- return { status: 500, body: { error: "Failed to read file." } };
8096
- }
8097
- function sendLocalFileJsonError(res, error) {
8098
- if (res.headersSent) return;
8099
- const response = localFileErrorResponse(error);
8100
- res.status(response.status).json(response.body);
8101
- }
8102
- function attachmentContentDisposition(pathValue) {
8103
- const fileName = basename5(pathValue).replace(/["\\]/gu, "_");
8104
- return `attachment; filename="${fileName}"`;
8105
- }
8106
7720
  function createServer(options = {}) {
8107
7721
  const app = express();
8108
7722
  const bridge = createCodexBridgeMiddleware();
@@ -8130,87 +7744,19 @@ function createServer(options = {}) {
8130
7744
  if (!res.headersSent) res.status(404).json({ error: "Image file not found." });
8131
7745
  });
8132
7746
  });
8133
- app.post("/codex-api/local-paths/probe", express.json({ limit: "64kb" }), async (req, res) => {
8134
- const body = req.body && typeof req.body === "object" && !Array.isArray(req.body) ? req.body : {};
8135
- const rawPaths = Array.isArray(body.paths) ? body.paths : [];
8136
- const normalizedPaths = [];
8137
- const seen = /* @__PURE__ */ new Set();
8138
- for (const candidate of rawPaths.slice(0, 200)) {
8139
- if (typeof candidate !== "string") continue;
8140
- const normalized = normalizeLocalPath(candidate);
8141
- if (!normalized || seen.has(normalized)) continue;
8142
- seen.add(normalized);
8143
- normalizedPaths.push(normalized);
8144
- }
8145
- const entries = await Promise.all(normalizedPaths.map(async (pathValue) => {
8146
- if (!isAbsolute3(pathValue)) {
8147
- return {
8148
- path: pathValue,
8149
- exists: false,
8150
- isDirectory: false
8151
- };
8152
- }
8153
- try {
8154
- const fileStat = await stat6(pathValue);
8155
- return {
8156
- path: pathValue,
8157
- exists: true,
8158
- isDirectory: fileStat.isDirectory()
8159
- };
8160
- } catch {
8161
- return {
8162
- path: pathValue,
8163
- exists: false,
8164
- isDirectory: false
8165
- };
8166
- }
8167
- }));
8168
- res.status(200).json({ data: { entries } });
8169
- });
8170
- app.get("/codex-local-file", async (req, res) => {
7747
+ app.get("/codex-local-file", (req, res) => {
8171
7748
  const rawPath = typeof req.query.path === "string" ? req.query.path : "";
8172
7749
  const localPath = normalizeLocalPath(rawPath);
8173
- const wantsDownload = readBooleanQueryFlag(req.query.download);
8174
7750
  if (!localPath || !isAbsolute3(localPath)) {
8175
7751
  res.status(400).json({ error: "Expected absolute local file path." });
8176
7752
  return;
8177
7753
  }
8178
- try {
8179
- const fileStat = await stat6(localPath);
8180
- if (!fileStat.isFile()) {
8181
- res.status(400).json({ error: "Expected file path." });
8182
- return;
8183
- }
8184
- const textMetadata = await getLocalTextFileMetadata(localPath);
8185
- res.setHeader("Cache-Control", "private, no-store");
8186
- if (wantsDownload) {
8187
- res.setHeader("Content-Disposition", attachmentContentDisposition(localPath));
8188
- res.sendFile(localPath, { dotfiles: "allow" }, (error) => {
8189
- if (!error) return;
8190
- sendLocalFileJsonError(res, error);
8191
- });
8192
- return;
8193
- }
8194
- if (textMetadata) {
8195
- const stream = createReadStream2(localPath, { encoding: "utf8" });
8196
- stream.on("open", () => {
8197
- res.status(200).type("text/plain; charset=utf-8");
8198
- });
8199
- stream.on("error", (error) => {
8200
- stream.destroy();
8201
- sendLocalFileJsonError(res, error);
8202
- });
8203
- stream.pipe(res);
8204
- return;
8205
- }
8206
- res.setHeader("Content-Disposition", "inline");
8207
- res.sendFile(localPath, { dotfiles: "allow" }, (error) => {
8208
- if (!error) return;
8209
- sendLocalFileJsonError(res, error);
8210
- });
8211
- } catch (error) {
8212
- sendLocalFileJsonError(res, error);
8213
- }
7754
+ res.setHeader("Cache-Control", "private, no-store");
7755
+ res.setHeader("Content-Disposition", "inline");
7756
+ res.sendFile(localPath, { dotfiles: "allow" }, (error) => {
7757
+ if (!error) return;
7758
+ if (!res.headersSent) res.status(404).json({ error: "File not found." });
7759
+ });
8214
7760
  });
8215
7761
  app.get("/codex-local-directories", async (req, res) => {
8216
7762
  const rawPath = typeof req.query.path === "string" ? req.query.path : "";
@@ -8236,8 +7782,6 @@ function createServer(options = {}) {
8236
7782
  const rawPath = readWildcardPathParam(req.params.path);
8237
7783
  const localPath = decodeBrowsePath(`/${rawPath}`);
8238
7784
  const newProjectName = typeof req.query.newProjectName === "string" ? req.query.newProjectName : "";
8239
- const line = readPositiveIntegerQueryParam(req.query.line);
8240
- const column = line ? readPositiveIntegerQueryParam(req.query.column) : null;
8241
7785
  if (!localPath || !isAbsolute3(localPath)) {
8242
7786
  res.status(400).json({ error: "Expected absolute local file path." });
8243
7787
  return;
@@ -8250,13 +7794,6 @@ function createServer(options = {}) {
8250
7794
  res.status(200).type("text/html; charset=utf-8").send(html);
8251
7795
  return;
8252
7796
  }
8253
- const textMetadata = await getLocalTextFileMetadata(localPath);
8254
- if (textMetadata) {
8255
- const html = await createTextPreviewHtml(localPath, { newProjectName, line, column });
8256
- res.status(200).type("text/html; charset=utf-8").send(html);
8257
- return;
8258
- }
8259
- res.setHeader("Content-Disposition", "attachment");
8260
7797
  res.sendFile(localPath, { dotfiles: "allow" }, (error) => {
8261
7798
  if (!error) return;
8262
7799
  if (!res.headersSent) res.status(404).json({ error: "File not found." });
@@ -8268,9 +7805,6 @@ function createServer(options = {}) {
8268
7805
  app.get("/codex-local-edit/*path", async (req, res) => {
8269
7806
  const rawPath = readWildcardPathParam(req.params.path);
8270
7807
  const localPath = decodeBrowsePath(`/${rawPath}`);
8271
- const newProjectName = typeof req.query.newProjectName === "string" ? req.query.newProjectName : "";
8272
- const line = readPositiveIntegerQueryParam(req.query.line);
8273
- const column = line ? readPositiveIntegerQueryParam(req.query.column) : null;
8274
7808
  if (!localPath || !isAbsolute3(localPath)) {
8275
7809
  res.status(400).json({ error: "Expected absolute local file path." });
8276
7810
  return;
@@ -8281,11 +7815,7 @@ function createServer(options = {}) {
8281
7815
  res.status(400).json({ error: "Expected file path." });
8282
7816
  return;
8283
7817
  }
8284
- if (!await isTextEditableFile(localPath)) {
8285
- res.status(415).json({ error: "Only text-like files are editable." });
8286
- return;
8287
- }
8288
- const html = await createTextEditorHtml(localPath, { newProjectName, line, column });
7818
+ const html = await createTextEditorHtml(localPath);
8289
7819
  res.status(200).type("text/html; charset=utf-8").send(html);
8290
7820
  } catch {
8291
7821
  res.status(404).json({ error: "File not found." });