Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 64 additions & 5 deletions bin/ocx.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ import {
} from "../src/update/npm-cache-preflight.mjs";
import { handoffWindowsTrayForUpdate, planWindowsTrayUpdate } from "../src/update/tray-update-plan.mjs";
import { bootRestoreProbe, transactionalNpmUpdate } from "../src/update/transactional-install.mjs";
import {
CODEX_CLI_VERSION_MANAGER_ROOT_ENV_SLOTS,
isCodexCliUpdateInspectionArgv,
} from "../src/update/codex-cli-update-launch-policy.mjs";

const PKG = "@bitkyc08/opencodex";
const require = createRequire(import.meta.url);
Expand Down Expand Up @@ -468,7 +472,7 @@ function fail(msg) {
process.exit(1);
}

function resolveBun() {
function resolveBun({ allowInstall = true } = {}) {
// Keep direct npm-launcher starts aligned with durable service/shim installs:
// a valid explicit runtime must win even when the bundled dependency exists.
const override = process.env[BUN_OVERRIDE_ENV]?.trim();
Expand All @@ -493,7 +497,7 @@ function resolveBun() {
// Lazy fallback: --ignore-scripts (or a failed postinstall) leaves the
// ~450-byte placeholder stub. Run the bun package's own installer once.
const installJs = join(bunDir, "install.js");
if (existsSync(installJs)) {
if (allowInstall && existsSync(installJs)) {
const r = spawnSync(process.execPath, [installJs], { stdio: "inherit" });
if (r.status === 0) bin = findBunBinary(bunDir);
}
Expand All @@ -512,14 +516,20 @@ if (updateHelpRequested) {
process.exit(0);
}

const codexCliUpdateInspection = isCodexCliUpdateInspectionArgv(process.argv);
if (codexCliUpdateInspection && typeof process.versions.bun === "string") {
console.error("opencodex: codex-cli-update inspection must use the published Node launcher.");
process.exit(1);
}

if (process.argv[2] === "update" && isNodeModulesInstall() && !isBunGlobalInstall()) {
runNpmSelfUpdate();
}

// #1849 boot probe: a prior update that lost power (or double-faulted) mid-swap leaves a
// backup sibling and a broken live tree. Restore before anything tries to run from the
// broken tree; reap stale backups once the live tree verifies healthy.
if (isNodeModulesInstall() && !isBunGlobalInstall()) {
if (!codexCliUpdateInspection && isNodeModulesInstall() && !isBunGlobalInstall()) {
try {
const probe = bootRestoreProbe(resolve(here, ".."));
if (probe.action === "restored") {
Expand All @@ -530,7 +540,7 @@ if (isNodeModulesInstall() && !isBunGlobalInstall()) {
} catch { /* the probe must never block launch */ }
}

const bunRuntime = resolveBun();
const bunRuntime = resolveBun({ allowInstall: !codexCliUpdateInspection });
const bun = bunRuntime.path;

// Run the Bun child asynchronously and FORWARD termination signals to it, then wait
Expand All @@ -554,20 +564,69 @@ const bun = bunRuntime.path;
// interpolation and provider settings legitimately read the project environment.
const preBunAnthropicSlots = ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN", "ANTHROPIC_BASE_URL"]
.filter(name => typeof process.env[name] === "string" && process.env[name] !== "");
// A configured CODEX_CLI_PATH may legitimately be cwd-relative (`./tools/codex`), which the
// ordinary runtime resolver accepts. Inspection only trusts absolute local paths, so capture
// the absolute form here, in the launcher, while the original cwd is still authoritative;
// resolving it later would silently reinterpret it against a different working directory.
//
// A bare command with no separator (`codex`) is NOT a relative path: the runtime resolver
// deliberately hands those to executable lookup along PATH. Rewriting it to `<cwd>/codex`
// would make the inspector treat it as an explicit path and stop searching PATH entirely.
const configuredCodexCliPath = typeof process.env.CODEX_CLI_PATH === "string" && process.env.CODEX_CLI_PATH !== ""
? process.env.CODEX_CLI_PATH
: null;
const preBunCodexCliPath = configuredCodexCliPath !== null
&& (configuredCodexCliPath.includes("/") || configuredCodexCliPath.includes("\\") || /^[A-Za-z]:/.test(configuredCodexCliPath))
? resolve(configuredCodexCliPath)
: configuredCodexCliPath;
const preBunPath = typeof process.env.PATH === "string" ? process.env.PATH : null;
const preBunPathExt = typeof process.env.PATHEXT === "string" ? process.env.PATHEXT : null;
const preBunCodexCliManagerRoots = Object.fromEntries(
CODEX_CLI_VERSION_MANAGER_ROOT_ENV_SLOTS.flatMap(name => {
const value = process.env[name];
return typeof value === "string" && value !== "" ? [[name, value]] : [];
}),
);
const launchProof = randomBytes(32).toString("base64url");
const launchContext = JSON.stringify({
version: 1,
proof: launchProof,
anthropicEnvSlots: preBunAnthropicSlots,
codexCliInspectionEnv: codexCliUpdateInspection ? {
codexCliPath: preBunCodexCliPath,
path: preBunPath,
Comment thread
luvs01 marked this conversation as resolved.
pathExt: preBunPathExt,
Comment thread
luvs01 marked this conversation as resolved.
managerRoots: preBunCodexCliManagerRoots,
Comment thread
luvs01 marked this conversation as resolved.
configDir: configDir(),
} : null,
});
// The inspection snapshot above already carries PATH, PATHEXT, and the manager-root slots as
// proof-bound values, and `inspectCodexCliInstall` reads them from that snapshot rather than
// from the live environment. Inheriting them again would spend the 32,767-character Windows
// environment block twice, so a large-but-valid shell environment could stop the Bun child
// from spawning and fail the command before it reports anything. Drop the duplicates for the
// one-shot inspection launch only; every other launch inherits the environment unchanged.
// Windows environment names are case-insensitive, but this spread produces an ordinary
// case-sensitive object, and a real Windows environment commonly spells the variable `Path`.
// Deleting only the canonical upper-case spelling would silently leave that copy behind and
// reintroduce the duplication this block exists to prevent, so match on the lowercase form.
const inheritedEnv = { ...process.env };
if (codexCliUpdateInspection) {
const snapshotted = new Set(
["PATH", "PATHEXT", ...CODEX_CLI_VERSION_MANAGER_ROOT_ENV_SLOTS].map(name => name.toLowerCase()),
);
for (const name of Object.keys(inheritedEnv)) {
if (snapshotted.has(name.toLowerCase())) delete inheritedEnv[name];
}
}
const child = spawn(bun, [cliPath, `${NODE_LAUNCH_PROOF_PREFIX}${launchProof}`, ...process.argv.slice(2)], {
stdio: "inherit",
// A headless Windows parent (Task Scheduler, dashboard restart, shortcut) has no
// console to inherit. Without this flag Windows allocates a visible console for
// the long-running Bun child, and closing that window kills the proxy (#1236).
windowsHide: true,
env: {
...process.env,
...inheritedEnv,
[NODE_LAUNCH_CONTEXT_ENV]: launchContext,
[BUN_RUNTIME_SOURCE_ENV]: bunRuntime.source,
[BUN_RUNTIME_PATH_ENV]: bunRuntime.path,
Expand Down
4 changes: 3 additions & 1 deletion docs-site/src/content/docs/fr/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ Exécutez `ocx help` (ou `ocx --help` / `ocx -h`) pour afficher l’aide génér

- [Cycle de vie](/fr/reference/cli/lifecycle/) — configuration initiale, cycle de vie du proxy et du service, état de santé, diagnostics, synchronisation du catalogue, tableau de bord et mises à jour.
- [Fournisseurs, comptes et modèles](/fr/reference/cli/providers-accounts/) — configuration des fournisseurs, authentification, pools d’identifiants, quotas, modèles personnalisés, visibilité, modèles sélectionnés et limites de contexte.
- [Agents, routage et intégrations](/fr/reference/cli/agents/) — contrôles multi-agents, combinaisons, observabilité, clés d’admission, intégrations clientes, paramètres d’exécution et configuration validée.
- [Agents, routage et intégrations](/fr/reference/cli/agents/) — contrôles multi-agents, combinaisons, observabilité, clés d’admission, intégrations clientes, paramètres d’exécution, configuration validée et inspection en lecture seule des mises à jour de la CLI Codex.

## Fonctionnement sans interface interactive

Les commandes de gestion communiquent avec l’API de gestion du proxy actif. Elles s’appuient sur le port d’exécution enregistré et sur des contrôles d’identité, plutôt que sur un second chemin de configuration. Un proxy arrêté ou inaccessible est représenté par une réponse HTTP 503 et entraîne un code de sortie CLI non nul. Les commandes explicitement documentées comme des opérations de configuration hors ligne peuvent, quant à elles, valider et modifier le fichier de configuration sans proxy actif.

`ocx system codex-cli-update check` ne nécessite aucun proxy actif et n’interroge aucun registre de paquets. La commande inspecte, dans des limites strictes, les métadonnées de provenance du candidat d’installation configuré, notamment l’emplacement expurgé de l’exécutable et les preuves de propriété. Le contexte de confiance du lanceur publié authentifie uniquement cet instantané du candidat, et non l’exécution réussie de Codex. Comme cette commande ponctuelle n’exécute jamais Codex, les candidats issus de l’environnement ou de l’état persistant restent purement informatifs (`managed: false`, normalement `selection_unattested`) et `selectionAttested` reste `false`. La sortie JSON contient `candidateAvailable`, `candidateVersion`, `candidateSource` et `selectionAttested: false`. Une exécution directe via Bun ou depuis les sources ne fournit pas la preuve du lanceur, ignore les candidats issus de l’environnement ou de l’état persistant et peut signaler `candidate_unavailable`. Sous Windows, cette première étape n’effectue aucune E/S de système de fichiers sur les chemins du candidat ou de configuration. Seul un candidat d’environnement absolu capturé par le lanceur de confiance peut recevoir une étiquette lexicale de bundle d’application ou de gestionnaire de versions ; tous les autres candidats Windows échouent de manière fermée. La commande n’installe ni ne répare de logiciel, n’exécute ni Codex ni npm, ne contrôle aucun processus actif et n’écrit aucun état de configuration ou de cache.

L’affichage d’une liste ou d’un état est l’action par défaut lorsqu’il n’y a aucune ambiguïté. Utilisez `--json` pour obtenir des instantanés structurés et `ocx observe logs --follow --jsonl` pour suivre un flux de journaux de requêtes. Le thème, la langue, la navigation et les autres états purement visuels du navigateur n’ont pas d’équivalent dans la CLI. La configuration de Cloudflare Tunnel ne fait pas partie de cet ensemble de commandes.

## Codes de sortie et confirmation
Expand Down
10 changes: 9 additions & 1 deletion docs-site/src/content/docs/fr/reference/cli/agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,14 +239,22 @@ le CLI, l’API, et le GUI utilisent les mêmes octets.

## Exécution et configuration

### `ocx system <status|settings|startup|diagnostics|sync|update> ...`
### `ocx system <status|settings|startup|diagnostics|sync|codex-app-server|codex-restart|update|codex-cli-update> ...`

Gérez les paramètres d'exécution sans tête, le démarrage, la synchronisation, les diagnostics et les mises à jour.

```bash
ocx system settings --stream-mode eager-relay
```

`ocx system update` met à jour OpenCodex lui-même. Utilisez cette commande distincte et en lecture seule pour Codex CLI :

```bash
ocx system codex-cli-update check --json
```

`check` n’interroge aucun registre de paquets et inspecte, dans des limites strictes, les éléments de provenance du candidat d’installation configuré, notamment l’emplacement expurgé de l’exécutable et les preuves de propriété. Le contexte de confiance du lanceur publié authentifie uniquement cet instantané du candidat, et non l’exécution réussie de Codex. Comme cette commande ponctuelle n’exécute jamais Codex, les candidats issus de l’environnement ou de l’état persistant restent purement informatifs (`managed: false`, normalement `selection_unattested`) et `selectionAttested` reste `false`. La sortie JSON contient `candidateAvailable`, `candidateVersion`, `candidateSource` et `selectionAttested: false`. Une exécution directe via Bun ou depuis les sources ne fournit pas la preuve du lanceur, ignore les candidats issus de l’environnement ou de l’état persistant et peut signaler `candidate_unavailable`. Sous Windows, cette première étape n’effectue aucune E/S de système de fichiers sur les chemins du candidat ou de configuration. Seul un candidat d’environnement absolu capturé par le lanceur de confiance peut recevoir une étiquette lexicale de bundle d’application ou de gestionnaire de versions ; tous les autres candidats Windows échouent de manière fermée. La commande n’exécute ni Codex ni aucun gestionnaire de paquets, ne répare aucun shim, n’écrit ni dans la configuration ni dans le cache, n’arrête aucun processus et n’installe rien. Les candidats intégrés à une application, issus d’un gestionnaire de versions reconnu, autonomes mais non vérifiés, ou associés à un état de shim ambigu sont signalés comme non gérés ou inconnus et ne sont jamais classés comme gérés.

### `ocx config <show|get|set|unset|validate|export|import> ...`

Inspectez et modifiez en toute sécurité la configuration OpenCodex validée. `show` et `get` masquent les secrets. Importer
Expand Down
4 changes: 3 additions & 1 deletion docs-site/src/content/docs/fr/reference/cli/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ Pendant une mise à niveau, un shim Unix installé qui ne contient pas la garde

L’installation du lanceur ne prouve pas à elle seule que les requêtes Codex passeront par OpenCodex. Après une installation saine, la commande examine le routage Codex actuel et affiche un avertissement plutôt qu’un résultat positif lorsque le routage est externe, appartient à l’utilisateur ou ne peut pas être vérifié. Elle avertit aussi lorsque des variables de proxy sortant n’existent que dans le processus actuel alors que `config.proxy` est absent ou non résolu, car les lanceurs Codex et les services d’arrière-plan peuvent ne pas hériter de cet environnement. Ces contrôles sont en lecture seule et n’affichent jamais la valeur du proxy. Corrigez le transfert signalé et exécutez `ocx doctor` avant de compter sur le démarrage automatique.

Si une mise à jour externe achevée de Codex remplace un shim installé, la prochaine commande `ocx` ordinaire sauvegarde le nouveau lanceur stable et rétablit le shim avant de répartir la commande. Un lanceur encore en cours de modification reste intact et sera réexaminé plus tard. Un échec de réparation produit un avertissement sans faire échouer la commande demandée. Repli manuel : `ocx codex-shim install`. Définissez `codexShimAutoRestore` sur `false`, ou `OPENCODEX_CODEX_SHIM_AUTO_RESTORE=0` pour désactiver ce comportement au niveau du processus.
Si une mise à jour externe achevée de Codex remplace un shim installé, la prochaine commande `ocx` ordinaire sauvegarde le nouveau lanceur stable et rétablit le shim avant de répartir la commande. La commande d’inspection sans effet `ocx system codex-cli-update check` et les invocations mal formées de son espace de noms réservé `ocx system codex-cli-update` n’effectuent jamais cette réparation. Un lanceur encore en cours de modification reste intact et sera réexaminé plus tard. Un échec de réparation produit un avertissement sans faire échouer la commande demandée. Repli manuel : `ocx codex-shim install`. Définissez `codexShimAutoRestore` sur `false`, ou `OPENCODEX_CODEX_SHIM_AUTO_RESTORE=0` pour désactiver ce comportement au niveau du processus.

| Sous-commande | Action |
| --- | --- |
Expand Down Expand Up @@ -264,6 +264,8 @@ Ouvre le [tableau de bord Web](/fr/guides/web-dashboard/) à l’adresse `http:/

## Mise à jour

`ocx update` met à jour OpenCodex lui-même, et non la CLI Codex. Utilisez `ocx system codex-cli-update check` parmi les [commandes d’inspection système](/fr/reference/cli/agents/) pour vérifier, de façon bornée et en lecture seule, la provenance du candidat Codex CLI configuré. Cette commande n’interroge aucun registre de paquets et n’installe aucune mise à jour.

### `ocx update [--tag latest|preview]`

Met à jour opencodex depuis npm. Les installations stables utilisent `@latest` ; les préversions restent sur `@preview`, sauf si vous indiquez `--tag latest|preview`. La commande détecte un dépôt de sources et vous invite alors à exécuter `git pull && bun install`. Elle ne fait rien si la version la plus récente correspondant à cette balise est déjà installée.
Expand Down
6 changes: 4 additions & 2 deletions docs-site/src/content/docs/ja/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ opencodex CLI は `ocx` です。最初のコマンド名でディスパッチ
カタログの同期、ダッシュボード、および更新。
- [プロバイダー、アカウント、モデル](/reference/cli/providers-accounts/) — プロバイダー構成、
認証、資格情報プール、クォータ、カスタム モデル、可視性、選択されたモデル、およびコンテキストの上限。
- [エージェント、ルーティング、統合](/reference/cli/agents/) — マルチエージェント コントロール、コンボ、
可観測性、アドミッション キー、クライアント統合、ランタイム設定、および検証済みの構成
- [エージェント、ルーティング、統合](/ja/reference/cli/agents/) — マルチエージェント コントロール、コンボ、
可観測性、アドミッション キー、クライアント統合、ランタイム設定、検証済みの構成、および Codex CLI 更新の読み取り専用検査

## ヘッドレス動作

管理コマンドは、2 番目の構成パスを維持するのではなく、記録されたランタイム ポートと ID チェックを使用して、稼働中のプロキシの管理 API をラウンドトリップします。停止したプロキシまたは到達不能なプロキシは HTTP 503 として表され、ゼロ以外の CLI 終了が生成されます。オフライン構成操作として明示的に文書化されているコマンドは、代わりに、稼働中のプロキシを使用せずに設定ファイルを検証および編集できます。

`ocx system codex-cli-update check` は稼働中のプロキシを必要とせず、パッケージレジストリにも問い合わせません。設定済みのインストール候補について、秘匿化された実行ファイルの場所や所有権を示す根拠を含む来歴メタデータを、範囲を限定して検査します。公開ランチャー由来の信頼済みコンテキストが真正性を裏付けるのは候補のスナップショットだけであり、Codex が正常に実行されたことではありません。この単発コマンドは Codex を一切実行しないため、環境または永続化された状態から得た候補は報告対象にとどまります(`managed: false`、通常は `selection_unattested`)。`selectionAttested` は常に `false` です。JSON 出力には `candidateAvailable`、`candidateVersion`、`candidateSource`、`selectionAttested: false` が含まれます。Bun またはソースから直接起動するとランチャーの証明がないため、環境由来および永続化された候補を無視し、`candidate_unavailable` を報告することがあります。Windows では、この最初のスライスは候補や構成のパスに対するファイルシステム I/O を一切行いません。信頼済みランチャーが取り込んだ絶対パスの環境候補だけを、アプリ同梱またはバージョンマネージャーとして字句的に報告でき、それ以外の Windows 候補はすべて失敗時閉鎖になります。このコマンドはソフトウェアのインストールや修復、Codex または npm の実行、稼働中プロセスの制御、設定やキャッシュ状態への書き込みを行いません。

リストまたはステータスは、明確なデフォルトです。構造化スナップショットには `--json` を使用し、ストリーミング リクエスト ログ フィードには `ocx observe logs --follow --jsonl` を使用します。テーマ、言語、ナビゲーション、その他の純粋に視覚的なブラウザーの状態には、同等の CLI がありません。 Cloudflare Tunnel のセットアップはこのコマンド セットの外にあります。

## 終了コードと確認
Expand Down
Loading
Loading