@bitkyc08/opencodex 1.9.4 → 2.0.0

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/src/service.ts CHANGED
@@ -107,9 +107,13 @@ export function buildWindowsServiceScript(): string {
107
107
  windowsBatchSet("OCX_SERVICE", "1"),
108
108
  windowsBatchSet("PATH", path),
109
109
  windowsBatchSet("CODEX_HOME", process.env.CODEX_HOME?.trim()),
110
+ ":loop",
110
111
  `"${bun}" "${cli}" start`,
111
- "set \"OCX_EXIT=%ERRORLEVEL%\"",
112
- "endlocal & exit /b %OCX_EXIT%",
112
+ "if %ERRORLEVEL% NEQ 0 (",
113
+ " timeout /t 5 /nobreak >nul",
114
+ " goto loop",
115
+ ")",
116
+ "endlocal",
113
117
  ].filter((line): line is string => Boolean(line));
114
118
  return `${lines.join("\r\n")}\r\n`;
115
119
  }
@@ -232,6 +236,26 @@ function platformOps(): ServiceOps | null {
232
236
  return null;
233
237
  }
234
238
 
239
+ /**
240
+ * If a service is installed, stop it so the process manager doesn't respawn after `ocx stop`.
241
+ * Returns true if a service was found and stopped.
242
+ */
243
+ export function stopServiceIfInstalled(): boolean {
244
+ if (process.platform === "darwin") {
245
+ if (existsSync(plistPath())) {
246
+ try { stopLaunchd(); return true; } catch { return false; }
247
+ }
248
+ } else if (process.platform === "win32") {
249
+ try {
250
+ const q = sh(`schtasks /query /tn ${TASK} 2>nul`);
251
+ if (q.includes(TASK)) { stopWindows(); return true; }
252
+ } catch { /* task not found */ }
253
+ } else if (process.platform === "linux" && isSystemd() && existsSync(unitPath())) {
254
+ try { stopSystemd(); return true; } catch { return false; }
255
+ }
256
+ return false;
257
+ }
258
+
235
259
  export function serviceCommand(sub?: string): void {
236
260
  const ops = platformOps();
237
261
  if (!ops) {
@@ -5,7 +5,7 @@ import { createInterface } from "node:readline/promises";
5
5
  import { getConfigDir } from "./config";
6
6
 
7
7
  const REPO = "lidge-jun/opencodex";
8
- /** Shared with scripts/postinstall.mjs so the prompt fires exactly once across install + first start. */
8
+ /** Fires exactly once from the first interactive `ocx start`. */
9
9
  const MARKER = ".star-prompted";
10
10
 
11
11
  function ghAvailable(): boolean {
@@ -22,9 +22,10 @@ function starRepo(): { ok: boolean; error?: string } {
22
22
  }
23
23
 
24
24
  /**
25
- * First interactive `ocx start`: a one-time `[Y/n]` "star on GitHub?" prompt. On yes, stars the repo
26
- * via the user's `gh` auth (same approach as the npm postinstall). No-op under the background service,
27
- * for non-TTY/piped runs, when already prompted, or when `gh` is unavailable. Never throws.
25
+ * First interactive `ocx start`: a one-time `[Y/n]` "star on GitHub?" prompt.
26
+ * On yes, stars the repo via the user's `gh` auth. No-op under the background
27
+ * service, for non-TTY/piped runs, when already prompted, or when `gh` is
28
+ * unavailable. Never throws.
28
29
  */
29
30
  export async function maybeShowStarPrompt(): Promise<void> {
30
31
  try {
package/src/types.ts CHANGED
@@ -221,11 +221,33 @@ export interface OcxProviderConfig {
221
221
  * Only the openai-responses adapter implements "forward"; openai-chat uses its own key/token.
222
222
  */
223
223
  authMode?: "key" | "forward" | "oauth";
224
+ /**
225
+ * Provider-wide Codex-visible reasoning tiers for routed models. Use only Codex-supported labels
226
+ * here (`low`, `medium`, `high`, `xhigh`); translate to provider-specific wire values with
227
+ * `reasoningEffortMap` / `modelReasoningEffortMap` below.
228
+ */
229
+ reasoningEfforts?: string[];
230
+ /** Model-specific Codex-visible reasoning tiers. An empty array means “do not expose effort”. */
231
+ modelReasoningEfforts?: Record<string, string[]>;
232
+ /** Provider-wide mapping from Codex effort labels to upstream `reasoning_effort` values. */
233
+ reasoningEffortMap?: Record<string, string>;
234
+ /** Model-specific mapping from Codex effort labels to upstream `reasoning_effort` values. */
235
+ modelReasoningEffortMap?: Record<string, Record<string, string>>;
224
236
  /**
225
237
  * Model ids that do NOT support a reasoning/thinking parameter. The openai-chat adapter drops
226
238
  * reasoning_effort for these even when Codex selects a reasoning level (e.g. xAI grok-build-0.1).
227
239
  */
228
240
  noReasoningModels?: string[];
241
+ /** Model ids that reject caller-specified temperature. */
242
+ noTemperatureModels?: string[];
243
+ /** Model ids that reject caller-specified top_p. */
244
+ noTopPModels?: string[];
245
+ /** Model ids that reject caller-specified presence/frequency penalty values. */
246
+ noPenaltyModels?: string[];
247
+ /** Model ids whose tool_choice only accepts `auto` or `none`; forced/named choices are downgraded. */
248
+ autoToolChoiceOnlyModels?: string[];
249
+ /** Model ids that expect prior assistant `reasoning_content` to be preserved in chat history. */
250
+ preserveReasoningContentModels?: string[];
229
251
  /**
230
252
  * Model ids that do NOT accept image inputs. The proxy gives them "eyes" via the vision sidecar:
231
253
  * attached images are described by a gpt vision model and replaced with text before the call.
package/src/ws-bridge.ts CHANGED
@@ -219,9 +219,12 @@ export function sendResponsesJsonAsEvents(
219
219
  item,
220
220
  });
221
221
  });
222
+ const finalStatus = response.status === "failed" || response.status === "incomplete"
223
+ ? response.status
224
+ : "completed";
222
225
  sendJsonFrame(ws, {
223
- type: "response.completed",
224
- response: { ...response, status: "completed" },
226
+ type: finalStatus === "failed" ? "response.failed" : "response.completed",
227
+ response: { ...response, status: finalStatus },
225
228
  });
226
229
  }
227
230
 
@@ -1 +0,0 @@
1
- :root{--bg:#0b0b0f;--surface:#14141a;--raised:#1c1c25;--raised-hover:#232330;--border:#2a2a35;--border-soft:#20202a;--text:#e9e9ee;--muted:#9a9aa6;--faint:#6a6a76;--accent:#7c5cff;--accent-hover:#9077ff;--accent-ink:#fff;--accent-soft:#7c5cff24;--accent-ring:#7c5cff73;--green:#34d399;--green-soft:#34d39921;--red:#f87171;--red-soft:#f8717121;--amber:#fbbf24;--amber-soft:#fbbf2421;--radius:12px;--radius-sm:8px;--radius-xs:6px;--font:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui, "Helvetica Neue", sans-serif;--mono:ui-monospace, "SF Mono", "JetBrains Mono", "Cascadia Code", Menlo, Consolas, monospace;--shadow:0 1px 2px #00000080, 0 12px 32px #00000047;--shadow-sm:0 1px 2px #0006;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}*{box-sizing:border-box}html,body,#root{height:100%}body{background:var(--bg);color:var(--text);font-family:var(--font);-webkit-font-smoothing:antialiased;text-rendering:optimizelegibility;background-image:radial-gradient(1200px 600px at 18% -10%,#7c5cff14,#0000 60%);margin:0;font-size:14px;line-height:1.5}a{color:var(--accent-hover);text-decoration:none}a:hover{text-decoration:underline}code,.mono{font-family:var(--mono);font-size:.92em}h1,h2,h3,h4{letter-spacing:-.01em;margin:0;font-weight:650}::selection{background:var(--accent-soft)}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-thumb{background:var(--border);border:2px solid var(--bg);border-radius:99px}::-webkit-scrollbar-thumb:hover{background:#353542}:focus-visible{outline:2px solid var(--accent-ring);outline-offset:2px;border-radius:4px}.app{grid-template-columns:232px 1fr;min-height:100dvh;display:grid}.sidebar{border-right:1px solid var(--border-soft);background:linear-gradient(#ffffff04,#0000);flex-direction:column;align-self:start;gap:4px;height:100dvh;padding:18px 14px;display:flex;position:sticky;top:0}.brand{align-items:center;gap:10px;padding:6px 8px 14px;display:flex}.brand img{width:26px;height:26px}.brand .name{letter-spacing:-.02em;font-size:15px;font-weight:700}.brand .ver{font-family:var(--mono);color:var(--muted);background:var(--raised);border:1px solid var(--border);border-radius:99px;padding:1px 6px;font-size:10px}.nav-item{border-radius:var(--radius-sm);text-align:left;cursor:pointer;width:100%;color:var(--muted);font:inherit;background:0 0;border:none;align-items:center;gap:10px;padding:8px 10px;font-size:13.5px;font-weight:500;transition:background .12s,color .12s;display:flex}.nav-item:hover{background:var(--raised);color:var(--text)}.nav-item.active{background:var(--accent-soft);color:var(--text)}.nav-item svg{width:17px;height:17px;color:var(--faint);flex-shrink:0}.nav-item.active svg{color:var(--accent)}.sidebar-foot{margin-top:auto;padding-top:12px}.sidebar-link{color:var(--muted);border-radius:var(--radius-sm);align-items:center;gap:9px;padding:8px 10px;font-size:13px;display:flex}.sidebar-link:hover{background:var(--raised);color:var(--text);text-decoration:none}.sidebar-link svg{width:16px;height:16px}.main{min-width:0}.main-inner{max-width:980px;margin:0 auto;padding:32px 36px 64px}.page-head{justify-content:space-between;align-items:center;gap:16px;margin-bottom:6px;display:flex}.page-head h2{font-size:19px}.page-sub{color:var(--muted);max-width:70ch;margin:4px 0 22px;font-size:13.5px}.page-sub b{color:var(--text);font-weight:600}.btn{border-radius:var(--radius-sm);font:inherit;cursor:pointer;white-space:nowrap;border:1px solid #0000;justify-content:center;align-items:center;gap:7px;padding:7px 14px;font-size:13px;font-weight:550;transition:background .12s,border-color .12s,opacity .12s;display:inline-flex}.btn svg{width:15px;height:15px}.btn:disabled{opacity:.55;cursor:default}.btn-primary{background:var(--accent);color:var(--accent-ink)}.btn-primary:hover:not(:disabled){background:var(--accent-hover)}.btn-ghost{background:var(--raised);color:var(--text);border-color:var(--border)}.btn-ghost:hover:not(:disabled){background:var(--raised-hover)}.btn-danger{color:var(--red);background:0 0;border-color:#f871714d}.btn-danger:hover:not(:disabled){background:var(--red-soft)}.btn-sm{border-radius:var(--radius-xs);padding:4px 9px;font-size:12px}.btn-icon{padding:5px}.card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius)}.panel{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:18px}.panel-accent{background:linear-gradient(180deg, var(--accent-soft), transparent 120%), var(--surface);border-color:#7c5cff47}.stat-row{grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:28px;display:grid}.stat{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:15px 16px}.stat .label{color:var(--muted);align-items:center;gap:6px;margin-bottom:7px;font-size:12px;display:flex}.stat .label svg{width:14px;height:14px}.stat .value{letter-spacing:-.02em;font-size:23px;font-weight:700;line-height:1.1}.stat .value.mono{font-family:var(--mono);font-size:19px}.badge{font-size:11px;font-weight:600;font-family:var(--mono);letter-spacing:.01em;border-radius:99px;align-items:center;gap:5px;padding:2px 8px;display:inline-flex}.badge-accent{background:var(--accent-soft);color:var(--accent-hover)}.badge-green{background:var(--green-soft);color:var(--green)}.badge-amber{background:var(--amber-soft);color:var(--amber)}.badge-muted{background:var(--raised);color:var(--muted);border:1px solid var(--border)}.dot{border-radius:50%;flex-shrink:0;width:7px;height:7px}.dot-green{background:var(--green);box-shadow:0 0 0 3px var(--green-soft)}.dot-red{background:var(--red);box-shadow:0 0 0 3px var(--red-soft)}.tbl{border-collapse:collapse;width:100%;font-size:13px}.tbl thead th{text-align:left;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;border-bottom:1px solid var(--border);padding:9px 12px;font-size:11.5px;font-weight:600}.tbl tbody td{border-bottom:1px solid var(--border-soft);padding:10px 12px}.tbl tbody tr:last-child td{border-bottom:none}.tbl tbody tr:hover td{background:#ffffff05}.tbl .num{text-align:right;font-family:var(--mono)}.tbl-wrap{border:1px solid var(--border);border-radius:var(--radius);overflow:hidden}.input,textarea.input{border-radius:var(--radius-sm);background:var(--raised);border:1px solid var(--border);width:100%;color:var(--text);font:inherit;padding:8px 11px;font-size:13px;transition:border-color .12s}.input::placeholder{color:var(--faint)}.input:focus{border-color:var(--accent);outline:none}textarea.input{resize:vertical;font-family:var(--mono);line-height:1.55}.field-label{color:var(--muted);margin-bottom:5px;font-size:12px;font-weight:500;display:block}select.input{appearance:none}.switch{cursor:pointer;background:var(--border);border:none;border-radius:99px;flex-shrink:0;width:34px;height:19px;padding:0;transition:background .15s;position:relative}.switch.on{background:var(--accent)}.switch:disabled{opacity:.6;cursor:default}.switch .knob{background:#fff;border-radius:50%;width:15px;height:15px;transition:left .15s;position:absolute;top:2px;left:2px}.switch.on .knob{left:17px}.muted{color:var(--muted)}.faint{color:var(--faint)}.row{align-items:center;gap:10px;display:flex}.spread{justify-content:space-between;align-items:center;gap:12px;display:flex}.stack{flex-direction:column;display:flex}.chip{font-family:var(--mono);background:var(--raised);border:1px solid var(--border);border-radius:var(--radius-xs);color:var(--text);padding:1px 7px;font-size:12px}.empty{text-align:center;border:1px dashed var(--border);border-radius:var(--radius);color:var(--muted);padding:56px 20px}.empty svg{width:30px;height:30px;color:var(--faint);margin-bottom:12px}.empty .title{color:var(--text);margin-bottom:6px;font-weight:600}.notice{border-radius:var(--radius-sm);align-items:center;gap:8px;margin-bottom:14px;padding:9px 12px;font-size:13px;display:flex}.notice svg{flex-shrink:0;width:15px;height:15px}.notice-ok{background:var(--green-soft);color:var(--green)}.notice-err{background:var(--red-soft);color:var(--red)}.h-section{color:var(--text);align-items:center;gap:8px;margin:30px 0 12px;font-size:13px;font-weight:600;display:flex}.h-section .count{color:var(--muted);font-weight:500;font-family:var(--mono);font-size:12px}.spin{border:2px solid var(--border);border-top-color:var(--accent);border-radius:50%;width:14px;height:14px;animation:.7s linear infinite spin;display:inline-block}@keyframes spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}.modal-overlay{-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);z-index:50;background:#0009;justify-content:center;align-items:flex-start;padding:8vh 16px;display:flex;position:fixed;inset:0}.modal-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);width:100%;max-width:520px;box-shadow:var(--shadow);max-height:84vh;padding:20px;overflow-y:auto}.modal-head{justify-content:space-between;align-items:center;margin-bottom:16px;display:flex}.modal-head h3{font-size:16px}.list-row{text-align:left;border-radius:var(--radius-sm);border:1px solid var(--border);background:var(--raised);cursor:pointer;width:100%;color:var(--text);font:inherit;justify-content:space-between;align-items:center;gap:10px;padding:11px 13px;transition:background .12s,border-color .12s;display:flex}.list-row:hover{background:var(--raised-hover);border-color:#34343f}.list-row .title{font-size:14px;font-weight:600}.list-row .sub{color:var(--muted);margin-top:2px;font-size:12px}.prov-card{justify-content:space-between;align-items:flex-start;gap:12px;padding:15px 16px;display:flex}.link-btn{color:var(--accent-hover);font:inherit;cursor:pointer;background:0 0;border:none;padding:6px 2px;font-size:13px;text-decoration:underline}@media (width<=760px){.app{grid-template-columns:1fr}.sidebar{border-right:none;border-bottom:1px solid var(--border-soft);flex-flow:wrap;align-items:center;height:auto;position:static}.brand{width:100%;padding:6px 8px}.nav-item{width:auto}.sidebar-foot{margin:0;padding:0}.main-inner{padding:22px 18px 48px}.stat-row{grid-template-columns:repeat(2,1fr)}}