codex-team 0.0.10 → 0.0.11

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/main.js CHANGED
@@ -1,15 +1,15 @@
1
+ import { chmod, copyFile, mkdir, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
1
2
  import { stderr, stdin, stdout as external_node_process_stdout } from "node:process";
3
+ import { basename, dirname, join } from "node:path";
2
4
  import dayjs from "dayjs";
3
5
  import timezone from "dayjs/plugin/timezone.js";
4
6
  import utc from "dayjs/plugin/utc.js";
5
7
  import { createHash } from "node:crypto";
6
- import { chmod, copyFile, mkdir, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
7
8
  import { homedir } from "node:os";
8
- import { basename, dirname, join } from "node:path";
9
9
  import { execFile } from "node:child_process";
10
10
  import { promisify } from "node:util";
11
11
  var package_namespaceObject = {
12
- rE: "0.0.10"
12
+ rE: "0.0.11"
13
13
  };
14
14
  function isRecord(value) {
15
15
  return "object" == typeof value && null !== value && !Array.isArray(value);
@@ -502,7 +502,6 @@ async function fetchQuotaSnapshot(snapshot, options = {}) {
502
502
  };
503
503
  }
504
504
  }
505
- const account_store_execFile = promisify(execFile);
506
505
  const DIRECTORY_MODE = 448;
507
506
  const FILE_MODE = 384;
508
507
  const SCHEMA_VERSION = 1;
@@ -575,25 +574,6 @@ function canAutoMigrateLegacyChatGPTMeta(meta, snapshot) {
575
574
  if (!snapshotUserId) return false;
576
575
  return meta.account_id === getSnapshotAccountId(snapshot);
577
576
  }
578
- async function detectRunningCodexProcesses() {
579
- try {
580
- const { stdout } = await account_store_execFile("ps", [
581
- "-Ao",
582
- "pid=,command="
583
- ]);
584
- const pids = [];
585
- for (const line of stdout.split("\n")){
586
- const match = line.trim().match(/^(\d+)\s+(.+)$/);
587
- if (!match) continue;
588
- const pid = Number(match[1]);
589
- const command = match[2];
590
- if (pid !== process.pid && /(^|\s|\/)codex(\s|$)/.test(command) && !command.includes("codex-team")) pids.push(pid);
591
- }
592
- return pids;
593
- } catch {
594
- return [];
595
- }
596
- }
597
577
  class AccountStore {
598
578
  paths;
599
579
  fetchImpl;
@@ -889,8 +869,6 @@ class AccountStore {
889
869
  last_switched_account: name,
890
870
  last_backup_path: backupPath
891
871
  });
892
- const runningCodexPids = await detectRunningCodexProcesses();
893
- if (runningCodexPids.length > 0) warnings.push(`Detected running codex processes (${runningCodexPids.join(", ")}). Existing sessions may still hold the previous login state.`);
894
872
  return {
895
873
  account: await this.readManagedAccount(name),
896
874
  warnings,
@@ -1064,6 +1042,250 @@ function createAccountStore(homeDir, options) {
1064
1042
  fetchImpl: options?.fetchImpl
1065
1043
  });
1066
1044
  }
1045
+ const codex_desktop_launch_execFile = promisify(execFile);
1046
+ const DEFAULT_CODEX_REMOTE_DEBUGGING_PORT = 9223;
1047
+ const DEFAULT_CODEX_DESKTOP_STATE_PATH = join(homedir(), ".codex-team", "desktop-state.json");
1048
+ const CODEX_BINARY_SUFFIX = "/Contents/MacOS/Codex";
1049
+ const CODEX_APP_NAME = "Codex";
1050
+ const CODEX_LOCAL_HOST_ID = "local";
1051
+ const CODEX_APP_SERVER_RESTART_EXPRESSION = 'window.electronBridge.sendMessageFromView({ type: "codex-app-server-restart", hostId: "local" })';
1052
+ const DEVTOOLS_REQUEST_TIMEOUT_MS = 5000;
1053
+ function codex_desktop_launch_isRecord(value) {
1054
+ return "object" == typeof value && null !== value && !Array.isArray(value);
1055
+ }
1056
+ function isNonEmptyString(value) {
1057
+ return "string" == typeof value && "" !== value.trim();
1058
+ }
1059
+ async function codex_desktop_launch_delay(ms) {
1060
+ await new Promise((resolve)=>setTimeout(resolve, ms));
1061
+ }
1062
+ async function pathExistsViaStat(execFileImpl, path) {
1063
+ try {
1064
+ await execFileImpl("stat", [
1065
+ "-f",
1066
+ "%N",
1067
+ path
1068
+ ]);
1069
+ return true;
1070
+ } catch {
1071
+ return false;
1072
+ }
1073
+ }
1074
+ function parseManagedState(raw) {
1075
+ if ("" === raw.trim()) return null;
1076
+ let parsed;
1077
+ try {
1078
+ parsed = JSON.parse(raw);
1079
+ } catch {
1080
+ return null;
1081
+ }
1082
+ if (!codex_desktop_launch_isRecord(parsed)) return null;
1083
+ const pid = parsed.pid;
1084
+ const appPath = parsed.app_path;
1085
+ const remoteDebuggingPort = parsed.remote_debugging_port;
1086
+ const managedByCodexm = parsed.managed_by_codexm;
1087
+ const startedAt = parsed.started_at;
1088
+ if ("number" != typeof pid || !Number.isInteger(pid) || pid <= 0 || !isNonEmptyString(appPath) || "number" != typeof remoteDebuggingPort || !Number.isInteger(remoteDebuggingPort) || remoteDebuggingPort <= 0 || true !== managedByCodexm || !isNonEmptyString(startedAt)) return null;
1089
+ return {
1090
+ pid,
1091
+ app_path: appPath,
1092
+ remote_debugging_port: remoteDebuggingPort,
1093
+ managed_by_codexm: true,
1094
+ started_at: startedAt
1095
+ };
1096
+ }
1097
+ async function ensureStateDirectory(statePath) {
1098
+ await mkdir(dirname(statePath), {
1099
+ recursive: true,
1100
+ mode: 448
1101
+ });
1102
+ }
1103
+ function createDefaultWebSocket(url) {
1104
+ return new WebSocket(url);
1105
+ }
1106
+ function isDevtoolsTarget(value) {
1107
+ return codex_desktop_launch_isRecord(value);
1108
+ }
1109
+ function isManagedDesktopProcess(runningApps, state) {
1110
+ const expectedBinaryPath = `${state.app_path}${CODEX_BINARY_SUFFIX}`;
1111
+ const expectedPort = `--remote-debugging-port=${state.remote_debugging_port}`;
1112
+ return runningApps.some((entry)=>entry.pid === state.pid && entry.command.includes(expectedBinaryPath) && entry.command.includes(expectedPort));
1113
+ }
1114
+ async function evaluateDevtoolsExpression(createWebSocketImpl, webSocketDebuggerUrl, expression) {
1115
+ const socket = createWebSocketImpl(webSocketDebuggerUrl);
1116
+ await new Promise((resolve, reject)=>{
1117
+ const requestId = 1;
1118
+ const timeout = setTimeout(()=>{
1119
+ cleanup();
1120
+ reject(new Error("Timed out waiting for Codex Desktop devtools response."));
1121
+ }, DEVTOOLS_REQUEST_TIMEOUT_MS);
1122
+ const cleanup = ()=>{
1123
+ clearTimeout(timeout);
1124
+ socket.onopen = null;
1125
+ socket.onmessage = null;
1126
+ socket.onerror = null;
1127
+ socket.onclose = null;
1128
+ socket.close();
1129
+ };
1130
+ socket.onopen = ()=>{
1131
+ socket.send(JSON.stringify({
1132
+ id: requestId,
1133
+ method: "Runtime.evaluate",
1134
+ params: {
1135
+ expression,
1136
+ awaitPromise: true
1137
+ }
1138
+ }));
1139
+ };
1140
+ socket.onmessage = (event)=>{
1141
+ if ("string" != typeof event.data) return;
1142
+ let payload;
1143
+ try {
1144
+ payload = JSON.parse(event.data);
1145
+ } catch {
1146
+ return;
1147
+ }
1148
+ if (!codex_desktop_launch_isRecord(payload) || payload.id !== requestId) return;
1149
+ if (codex_desktop_launch_isRecord(payload.error)) {
1150
+ cleanup();
1151
+ reject(new Error(String(payload.error.message ?? "Codex Desktop devtools request failed.")));
1152
+ return;
1153
+ }
1154
+ const result = codex_desktop_launch_isRecord(payload.result) ? payload.result : null;
1155
+ if (result && codex_desktop_launch_isRecord(result.exceptionDetails)) {
1156
+ cleanup();
1157
+ reject(new Error("Codex Desktop rejected the app-server restart request."));
1158
+ return;
1159
+ }
1160
+ cleanup();
1161
+ resolve();
1162
+ };
1163
+ socket.onerror = ()=>{
1164
+ cleanup();
1165
+ reject(new Error("Failed to communicate with Codex Desktop devtools."));
1166
+ };
1167
+ socket.onclose = ()=>{
1168
+ cleanup();
1169
+ reject(new Error("Codex Desktop devtools connection closed before replying."));
1170
+ };
1171
+ });
1172
+ }
1173
+ function createCodexDesktopLauncher(options = {}) {
1174
+ const execFileImpl = options.execFileImpl ?? codex_desktop_launch_execFile;
1175
+ const statePath = options.statePath ?? DEFAULT_CODEX_DESKTOP_STATE_PATH;
1176
+ const readFileImpl = options.readFileImpl ?? (async (path)=>readFile(path, "utf8"));
1177
+ const writeFileImpl = options.writeFileImpl ?? writeFile;
1178
+ const fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
1179
+ const createWebSocketImpl = options.createWebSocketImpl ?? createDefaultWebSocket;
1180
+ async function findInstalledApp() {
1181
+ const candidates = [
1182
+ "/Applications/Codex.app",
1183
+ join(homedir(), "Applications", "Codex.app")
1184
+ ];
1185
+ for (const candidate of candidates)if (await pathExistsViaStat(execFileImpl, candidate)) return candidate;
1186
+ try {
1187
+ const { stdout } = await execFileImpl("mdfind", [
1188
+ 'kMDItemFSName == "Codex.app"'
1189
+ ]);
1190
+ for (const line of stdout.split("\n")){
1191
+ const candidate = line.trim();
1192
+ if ("" !== candidate) {
1193
+ if (await pathExistsViaStat(execFileImpl, candidate)) return candidate;
1194
+ }
1195
+ }
1196
+ } catch {}
1197
+ return null;
1198
+ }
1199
+ async function listRunningApps() {
1200
+ const { stdout } = await execFileImpl("ps", [
1201
+ "-Ao",
1202
+ "pid=,command="
1203
+ ]);
1204
+ const running = [];
1205
+ for (const line of stdout.split("\n")){
1206
+ const match = line.trim().match(/^(\d+)\s+(.+)$/);
1207
+ if (!match) continue;
1208
+ const pid = Number(match[1]);
1209
+ const command = match[2];
1210
+ if (pid !== process.pid && command.includes(CODEX_BINARY_SUFFIX)) running.push({
1211
+ pid,
1212
+ command
1213
+ });
1214
+ }
1215
+ return running;
1216
+ }
1217
+ async function quitRunningApps() {
1218
+ const running = await listRunningApps();
1219
+ if (0 === running.length) return;
1220
+ await execFileImpl("osascript", [
1221
+ "-e",
1222
+ `tell application "${CODEX_APP_NAME}" to quit`
1223
+ ]);
1224
+ for(let attempt = 0; attempt < 10; attempt += 1){
1225
+ const remaining = await listRunningApps();
1226
+ if (0 === remaining.length) return;
1227
+ await codex_desktop_launch_delay(300);
1228
+ }
1229
+ throw new Error("Timed out waiting for Codex Desktop to quit.");
1230
+ }
1231
+ async function launch(appPath) {
1232
+ await execFileImpl("open", [
1233
+ "-na",
1234
+ appPath,
1235
+ "--args",
1236
+ `--remote-debugging-port=${DEFAULT_CODEX_REMOTE_DEBUGGING_PORT}`
1237
+ ]);
1238
+ }
1239
+ async function readManagedState() {
1240
+ try {
1241
+ return parseManagedState(await readFileImpl(statePath));
1242
+ } catch {
1243
+ return null;
1244
+ }
1245
+ }
1246
+ async function writeManagedState(state) {
1247
+ await ensureStateDirectory(statePath);
1248
+ await writeFileImpl(statePath, `${JSON.stringify(state, null, 2)}\n`);
1249
+ }
1250
+ async function clearManagedState() {
1251
+ await ensureStateDirectory(statePath);
1252
+ await writeFileImpl(statePath, "");
1253
+ }
1254
+ async function isManagedDesktopRunning() {
1255
+ const state = await readManagedState();
1256
+ if (!state) return false;
1257
+ const runningApps = await listRunningApps();
1258
+ return isManagedDesktopProcess(runningApps, state);
1259
+ }
1260
+ async function restartManagedAppServer() {
1261
+ const state = await readManagedState();
1262
+ if (!state) return false;
1263
+ const runningApps = await listRunningApps();
1264
+ if (!isManagedDesktopProcess(runningApps, state)) return false;
1265
+ const response = await fetchImpl(`http://127.0.0.1:${state.remote_debugging_port}/json/list`);
1266
+ if (!response.ok) throw new Error(`Failed to query Codex Desktop devtools targets (HTTP ${response.status}).`);
1267
+ const targets = await response.json();
1268
+ if (!Array.isArray(targets)) throw new Error("Codex Desktop devtools target list was not an array.");
1269
+ const localTarget = targets.find((target)=>{
1270
+ if (!isDevtoolsTarget(target)) return false;
1271
+ return "page" === target.type && target.url === `app://-/index.html?hostId=${CODEX_LOCAL_HOST_ID}` && isNonEmptyString(target.webSocketDebuggerUrl);
1272
+ });
1273
+ if (!localTarget || !isNonEmptyString(localTarget.webSocketDebuggerUrl)) throw new Error("Could not find the local Codex Desktop devtools target.");
1274
+ await evaluateDevtoolsExpression(createWebSocketImpl, localTarget.webSocketDebuggerUrl, CODEX_APP_SERVER_RESTART_EXPRESSION);
1275
+ return true;
1276
+ }
1277
+ return {
1278
+ findInstalledApp,
1279
+ listRunningApps,
1280
+ quitRunningApps,
1281
+ launch,
1282
+ readManagedState,
1283
+ writeManagedState,
1284
+ clearManagedState,
1285
+ isManagedDesktopRunning,
1286
+ restartManagedAppServer
1287
+ };
1288
+ }
1067
1289
  dayjs.extend(utc);
1068
1290
  dayjs.extend(timezone);
1069
1291
  function parseArgs(argv) {
@@ -1107,12 +1329,29 @@ Usage:
1107
1329
  codexm update [--json]
1108
1330
  codexm switch <name> [--json]
1109
1331
  codexm switch --auto [--dry-run] [--json]
1332
+ codexm launch [name] [--json]
1110
1333
  codexm remove <name> [--yes] [--json]
1111
1334
  codexm rename <old> <new> [--json]
1112
1335
 
1113
1336
  Account names must match /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.
1114
1337
  `);
1115
1338
  }
1339
+ function stripManagedDesktopWarning(warnings) {
1340
+ return warnings.filter((warning)=>!warning.startsWith("Detected running codex processes (") || !warning.endsWith("Existing sessions may still hold the previous login state."));
1341
+ }
1342
+ async function refreshManagedDesktopAfterSwitch(warnings, desktopLauncher) {
1343
+ try {
1344
+ if (await desktopLauncher.restartManagedAppServer()) return;
1345
+ } catch (error) {
1346
+ warnings.push(`Failed to refresh the running codexm-managed Codex Desktop session: ${error.message}`);
1347
+ return;
1348
+ }
1349
+ try {
1350
+ const runningApps = await desktopLauncher.listRunningApps();
1351
+ if (0 === runningApps.length) return;
1352
+ warnings.push(`Detected running codex processes (${runningApps.map((app)=>app.pid).join(", ")}). Existing sessions may still hold the previous login state.`);
1353
+ } catch {}
1354
+ }
1116
1355
  function describeCurrentStatus(status) {
1117
1356
  const lines = [];
1118
1357
  if (status.exists) {
@@ -1307,6 +1546,67 @@ async function confirmRemoval(name, streams) {
1307
1546
  streams.stdin.on("data", onData);
1308
1547
  });
1309
1548
  }
1549
+ async function confirmDesktopRelaunch(streams) {
1550
+ if (!streams.stdin.isTTY) throw new Error("Refusing to relaunch Codex Desktop in a non-interactive terminal.");
1551
+ streams.stdout.write("Codex Desktop is already running. Close it and relaunch with the selected auth? [y/N] ");
1552
+ return await new Promise((resolve)=>{
1553
+ const cleanup = ()=>{
1554
+ streams.stdin.off("data", onData);
1555
+ streams.stdin.pause();
1556
+ };
1557
+ const onData = (buffer)=>{
1558
+ const answer = buffer.toString("utf8").trim().toLowerCase();
1559
+ cleanup();
1560
+ streams.stdout.write("\n");
1561
+ resolve("y" === answer || "yes" === answer);
1562
+ };
1563
+ streams.stdin.resume();
1564
+ streams.stdin.on("data", onData);
1565
+ });
1566
+ }
1567
+ async function sleep(ms) {
1568
+ await new Promise((resolve)=>setTimeout(resolve, ms));
1569
+ }
1570
+ async function main_pathExists(path) {
1571
+ try {
1572
+ await stat(path);
1573
+ return true;
1574
+ } catch (error) {
1575
+ const nodeError = error;
1576
+ if ("ENOENT" === nodeError.code) return false;
1577
+ throw error;
1578
+ }
1579
+ }
1580
+ function isRunningDesktopFromApp(app, appPath) {
1581
+ return app.command.includes(`${appPath}/Contents/MacOS/Codex`);
1582
+ }
1583
+ async function resolveManagedDesktopState(desktopLauncher, appPath, existingApps) {
1584
+ const existingPids = new Set(existingApps.map((app)=>app.pid));
1585
+ for(let attempt = 0; attempt < 10; attempt += 1){
1586
+ const runningApps = await desktopLauncher.listRunningApps();
1587
+ const launchedApp = runningApps.filter((app)=>isRunningDesktopFromApp(app, appPath) && !existingPids.has(app.pid)).sort((left, right)=>right.pid - left.pid)[0] ?? runningApps.filter((app)=>isRunningDesktopFromApp(app, appPath)).sort((left, right)=>right.pid - left.pid)[0] ?? null;
1588
+ if (launchedApp) return {
1589
+ pid: launchedApp.pid,
1590
+ app_path: appPath,
1591
+ remote_debugging_port: DEFAULT_CODEX_REMOTE_DEBUGGING_PORT,
1592
+ managed_by_codexm: true,
1593
+ started_at: new Date().toISOString()
1594
+ };
1595
+ await sleep(300);
1596
+ }
1597
+ return null;
1598
+ }
1599
+ async function restoreLaunchBackup(store, backupPath) {
1600
+ if (backupPath && await main_pathExists(backupPath)) await copyFile(backupPath, store.paths.currentAuthPath);
1601
+ else await rm(store.paths.currentAuthPath, {
1602
+ force: true
1603
+ });
1604
+ const configBackupPath = join(store.paths.backupsDir, "last-active-config.toml");
1605
+ if (await main_pathExists(configBackupPath)) await copyFile(configBackupPath, store.paths.currentConfigPath);
1606
+ else await rm(store.paths.currentConfigPath, {
1607
+ force: true
1608
+ });
1609
+ }
1310
1610
  async function runCli(argv, options = {}) {
1311
1611
  const streams = {
1312
1612
  stdin: options.stdin ?? stdin,
@@ -1314,6 +1614,7 @@ async function runCli(argv, options = {}) {
1314
1614
  stderr: options.stderr ?? stderr
1315
1615
  };
1316
1616
  const store = options.store ?? createAccountStore();
1617
+ const desktopLauncher = options.desktopLauncher ?? createCodexDesktopLauncher();
1317
1618
  const parsed = parseArgs(argv);
1318
1619
  const json = parsed.flags.has("--json");
1319
1620
  try {
@@ -1446,6 +1747,8 @@ async function runCli(argv, options = {}) {
1446
1747
  }
1447
1748
  const result = await store.switchAccount(selected.name);
1448
1749
  for (const warning of warnings)result.warnings.push(warning);
1750
+ result.warnings = stripManagedDesktopWarning(result.warnings);
1751
+ await refreshManagedDesktopAfterSwitch(result.warnings, desktopLauncher);
1449
1752
  const payload = {
1450
1753
  ok: true,
1451
1754
  action: "switch",
@@ -1469,6 +1772,8 @@ async function runCli(argv, options = {}) {
1469
1772
  }
1470
1773
  if (!name) throw new Error("Usage: codexm switch <name>");
1471
1774
  const result = await store.switchAccount(name);
1775
+ result.warnings = stripManagedDesktopWarning(result.warnings);
1776
+ await refreshManagedDesktopAfterSwitch(result.warnings, desktopLauncher);
1472
1777
  let quota = null;
1473
1778
  try {
1474
1779
  await store.refreshQuotaForAccount(result.account.name);
@@ -1500,6 +1805,70 @@ async function runCli(argv, options = {}) {
1500
1805
  }
1501
1806
  return 0;
1502
1807
  }
1808
+ case "launch":
1809
+ {
1810
+ const name = parsed.positionals[0] ?? null;
1811
+ if (parsed.positionals.length > 1) throw new Error("Usage: codexm launch [name] [--json]");
1812
+ const warnings = [];
1813
+ const appPath = await desktopLauncher.findInstalledApp();
1814
+ if (!appPath) throw new Error("Codex Desktop not found at /Applications/Codex.app.");
1815
+ const runningApps = await desktopLauncher.listRunningApps();
1816
+ if (runningApps.length > 0) {
1817
+ const confirmed = await confirmDesktopRelaunch(streams);
1818
+ if (!confirmed) {
1819
+ if (json) writeJson(streams.stdout, {
1820
+ ok: false,
1821
+ action: "launch",
1822
+ cancelled: true
1823
+ });
1824
+ else streams.stdout.write("Aborted.\n");
1825
+ return 1;
1826
+ }
1827
+ await desktopLauncher.quitRunningApps();
1828
+ }
1829
+ let switchedAccount = null;
1830
+ let switchBackupPath = null;
1831
+ if (name) {
1832
+ const switchResult = await store.switchAccount(name);
1833
+ warnings.push(...stripManagedDesktopWarning(switchResult.warnings));
1834
+ switchedAccount = switchResult.account;
1835
+ switchBackupPath = switchResult.backup_path;
1836
+ }
1837
+ try {
1838
+ await desktopLauncher.launch(appPath);
1839
+ const managedState = await resolveManagedDesktopState(desktopLauncher, appPath, runningApps);
1840
+ if (!managedState) {
1841
+ await desktopLauncher.clearManagedState().catch(()=>void 0);
1842
+ throw new Error("Failed to confirm the newly launched Codex Desktop process for managed-session tracking.");
1843
+ }
1844
+ await desktopLauncher.writeManagedState(managedState);
1845
+ } catch (error) {
1846
+ if (switchedAccount) await restoreLaunchBackup(store, switchBackupPath).catch(()=>void 0);
1847
+ throw error;
1848
+ }
1849
+ if (json) writeJson(streams.stdout, {
1850
+ ok: true,
1851
+ action: "launch",
1852
+ account: switchedAccount ? {
1853
+ name: switchedAccount.name,
1854
+ account_id: switchedAccount.account_id,
1855
+ user_id: switchedAccount.user_id ?? null,
1856
+ identity: switchedAccount.identity,
1857
+ auth_mode: switchedAccount.auth_mode
1858
+ } : null,
1859
+ launched_with_current_auth: null === switchedAccount,
1860
+ app_path: appPath,
1861
+ relaunched: runningApps.length > 0,
1862
+ warnings
1863
+ });
1864
+ else {
1865
+ if (switchedAccount) streams.stdout.write(`Switched to "${switchedAccount.name}" (${maskAccountId(switchedAccount.identity)}).\n`);
1866
+ if (runningApps.length > 0) streams.stdout.write("Closed existing Codex Desktop instance and launched a new one.\n");
1867
+ streams.stdout.write(switchedAccount ? `Launched Codex Desktop with "${switchedAccount.name}" (${maskAccountId(switchedAccount.identity)}).\n` : "Launched Codex Desktop with current auth.\n");
1868
+ for (const warning of warnings)streams.stdout.write(`Warning: ${warning}\n`);
1869
+ }
1870
+ return 0;
1871
+ }
1503
1872
  case "remove":
1504
1873
  {
1505
1874
  const name = parsed.positionals[0];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-team",
3
- "version": "0.0.10",
3
+ "version": "0.0.11",
4
4
  "description": "Manage multiple Codex ChatGPT auth snapshots and quota usage from the command line.",
5
5
  "license": "MIT",
6
6
  "type": "module",