@remodex/rmx 1.0.2 → 1.0.3

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.
@@ -16,7 +16,7 @@
16
16
  } catch (e) {}
17
17
  })();
18
18
  </script>
19
- <script type="module" crossorigin src="/assets/index-CkETtt7P.js"></script>
19
+ <script type="module" crossorigin src="/assets/index-Cy432rMC.js"></script>
20
20
  <link rel="stylesheet" crossorigin href="/assets/index-CZqebSPQ.css">
21
21
  </head>
22
22
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remodex/rmx",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "Remodex universal provider proxy for OpenAI Codex & Claude Code — use any LLM with Codex CLI/App/SDK and Claude Code",
5
5
  "displayName": "Remodex",
6
6
  "type": "module",
package/src/cli/help.ts CHANGED
@@ -108,6 +108,10 @@ const helpEntries: Record<string, HelpEntry> = {
108
108
  update: {
109
109
  usage: "rmx update [--tag latest|preview]",
110
110
  summary: "Update Remodex. Preview installs stay on the preview tag unless overridden.",
111
+ details: [
112
+ "Automatic updates are enabled by default for global installs.",
113
+ "Use `rmx system update auto off` to disable them, or `rmx system update auto status` to inspect the scheduler.",
114
+ ],
111
115
  },
112
116
  provider: {
113
117
  usage: "rmx provider <list|add|edit|test|remove|show|set-default|selected|quota|presets|account-mode>",
@@ -197,6 +201,9 @@ const helpEntries: Record<string, HelpEntry> = {
197
201
  usage: "rmx system <status|settings|startup|diagnostics|sync|update|desktop-update> ...",
198
202
  summary: "Manage headless runtime settings, startup, sync, diagnostics, and updates.",
199
203
  details: [
204
+ "update auto on [--channel latest|preview] Enable the daily unattended package updater (enabled by default for global installs).",
205
+ "update auto off Disable unattended package updates.",
206
+ "update auto status Show scheduler, last result, and rollback information.",
200
207
  "desktop-update check [--channel latest|preview] Check the native desktop release manifest.",
201
208
  "desktop-update run [--channel latest|preview] Download and verify a native desktop update.",
202
209
  "desktop-update status Show shared tray/dashboard update state.",
@@ -295,6 +302,7 @@ export function printUsage(): void {
295
302
  const canonical = `Remodex (rmx) — Universal provider proxy for Codex
296
303
 
297
304
  Usage:
305
+ rmx Install/update and start the background service
298
306
  rmx setup Interactive setup (alias: init)
299
307
  rmx start [--port <port>] Start the proxy server (auto-syncs models to Codex)
300
308
  rmx stop Stop the proxy AND restore native Codex (plain codex works again)
@@ -340,6 +348,7 @@ Usage:
340
348
  rmx --version | -v Print version
341
349
 
342
350
  Examples:
351
+ rmx Install/update and start the background service
343
352
  rmx init Set up provider and inject into Codex
344
353
  rmx start Start on default port (10100)
345
354
  rmx start --port 8080 Start on custom port
package/src/cli/index.ts CHANGED
@@ -460,6 +460,10 @@ async function handleStart(options: { block?: boolean } = {}) {
460
460
  // to explain it. Name the failure and the one command that repairs it.
461
461
  console.error(`⚠️ ${grokSyncFailureMessage(err)}`);
462
462
  }
463
+ try {
464
+ const { ensureDefaultAutoUpdateScheduler } = await import("../update/auto-scheduler");
465
+ ensureDefaultAutoUpdateScheduler();
466
+ } catch { /* default updater provisioning must never block proxy startup */ }
463
467
  if (options.block ?? true) {
464
468
  setInterval(() => {}, 60_000);
465
469
  await new Promise<void>(() => {});
@@ -477,6 +481,12 @@ function detachedStartEnvironment(): NodeJS.ProcessEnv {
477
481
  async function handleEnsure(options: { existingIsSuccess?: boolean } = {}): Promise<boolean> {
478
482
  if (!currentExternalCodexModelProvider()) reconcileJournal();
479
483
  const config = loadConfig();
484
+ // Provision the daily updater for global installs during the first normal
485
+ // bootstrap. The helper skips service children and the updater worker itself.
486
+ try {
487
+ const { ensureDefaultAutoUpdateScheduler } = await import("../update/auto-scheduler");
488
+ ensureDefaultAutoUpdateScheduler();
489
+ } catch { /* automatic updates must never block proxy startup */ }
480
490
  if (!codexAutoStartEnabled(config)) {
481
491
  console.log("Codex autostart is disabled.");
482
492
  return false;
@@ -872,6 +882,17 @@ async function handleUninstall() {
872
882
  }
873
883
  };
874
884
 
885
+ await runStep("automatic updater removed", async () => {
886
+ const {
887
+ disableAutoUpdates,
888
+ readAutoUpdateStatus,
889
+ } = await import("../update/auto-scheduler");
890
+ const status = readAutoUpdateStatus();
891
+ if (status.scheduler === "absent" && !status.state) return false;
892
+ disableAutoUpdates();
893
+ return true;
894
+ });
895
+
875
896
  await runStep("service stopped", () => stopServiceIfInstalled());
876
897
 
877
898
  await runStep("proxy stopped", async () => {
@@ -1280,9 +1301,17 @@ switch (command) {
1280
1301
  openUrl(guiUrl);
1281
1302
  break;
1282
1303
  }
1283
- case "service":
1304
+ case "service": {
1305
+ const serviceSubcommand = args[1] ?? "install";
1284
1306
  await serviceCommand(...args.slice(1));
1307
+ if (!["status", "stop", "uninstall", "remove"].includes(serviceSubcommand)) {
1308
+ try {
1309
+ const { ensureDefaultAutoUpdateScheduler } = await import("../update/auto-scheduler");
1310
+ ensureDefaultAutoUpdateScheduler();
1311
+ } catch { /* default updater provisioning must not block service commands */ }
1312
+ }
1285
1313
  break;
1314
+ }
1286
1315
  case "tray": {
1287
1316
  const { windowsTrayCommand } = await import("../tray/windows");
1288
1317
  await windowsTrayCommand(args.slice(1));
@@ -1335,6 +1364,12 @@ switch (command) {
1335
1364
  await refreshVersionCache(channel);
1336
1365
  break;
1337
1366
  }
1367
+ case "__auto-update": {
1368
+ const { runAutomaticUpdateWorker } = await import("../update/auto-scheduler");
1369
+ const result = await runAutomaticUpdateWorker();
1370
+ if (!result.ok) process.exitCode = 1;
1371
+ break;
1372
+ }
1338
1373
  case "__desktop-update-worker": {
1339
1374
  const id = args[1];
1340
1375
  const mode = args[2];
@@ -20,6 +20,7 @@ const USAGE = `Usage:
20
20
  rmx system update check [--channel <latest|preview>] [--json]
21
21
  rmx system update run [--channel <latest|preview>] [--restart <on|off>] --yes [--json]
22
22
  rmx system update status <job-id> [--json]
23
+ rmx system update auto <on|off|status> [--channel <latest|preview>] [--json]
23
24
  rmx system desktop-update check [--channel <latest|preview>] [--json]
24
25
  rmx system desktop-update run [--channel <latest|preview>] [--json]
25
26
  rmx system desktop-update status [--json]`;
@@ -72,6 +73,42 @@ async function update(argv: string[], deps: RuntimeApiDeps): Promise<void> {
72
73
  const args = [...argv];
73
74
  const action = (args.shift() ?? "check").toLowerCase();
74
75
  const wantsJson = takeFlag(args, "--json");
76
+ if (action === "auto") {
77
+ const autoAction = (args.shift() ?? "status").toLowerCase();
78
+ const channel = takeOption(args, "--channel");
79
+ if (channel !== undefined && channel !== "latest" && channel !== "preview") {
80
+ throw new CliUsageError("--channel must be latest or preview", USAGE);
81
+ }
82
+ rejectArgs(args, USAGE);
83
+ const {
84
+ disableAutoUpdates,
85
+ enableAutoUpdates,
86
+ formatAutoUpdateStatus,
87
+ readAutoUpdateStatus,
88
+ } = await import("../update/auto-scheduler");
89
+ if (autoAction === "status") {
90
+ if (channel !== undefined) throw new CliUsageError("--channel applies to `auto on` only", USAGE);
91
+ const result = readAutoUpdateStatus();
92
+ printData(result, wantsJson, formatAutoUpdateStatus(result));
93
+ return;
94
+ }
95
+ if (autoAction === "on") {
96
+ const state = enableAutoUpdates(channel as "latest" | "preview" | undefined);
97
+ printData(
98
+ state,
99
+ wantsJson,
100
+ [`Automatic updates enabled (${state.channel}; daily at ${String(state.schedule.hour).padStart(2, "0")}:${String(state.schedule.minute).padStart(2, "0")} local time).`],
101
+ );
102
+ return;
103
+ }
104
+ if (autoAction === "off") {
105
+ if (channel !== undefined) throw new CliUsageError("--channel applies to `auto on` only", USAGE);
106
+ const state = disableAutoUpdates();
107
+ printData(state, wantsJson, ["Automatic updates disabled."]);
108
+ return;
109
+ }
110
+ throw new CliUsageError(`unknown automatic-update action ${autoAction}`, USAGE);
111
+ }
75
112
  if (action === "status") {
76
113
  const jobId = args.shift();
77
114
  if (!jobId) throw new CliUsageError("update job id is required", USAGE);
@@ -41,6 +41,11 @@ const INITIAL_OWNED_PATHS = [
41
41
  "artifacts",
42
42
  "auth.json",
43
43
  "auth.store.lock",
44
+ "auto-update.cmd",
45
+ "auto-update-task.xml",
46
+ "auto-update.json",
47
+ "auto-update.lock",
48
+ "auto-update.log",
44
49
  "catalog-backup.json",
45
50
  "claude-env.sh",
46
51
  "codex-accounts.json",
@@ -23,6 +23,11 @@ export const REMODEX_STATE_EVIDENCE_FILES = [
23
23
  ".opencodex-uninstall.json",
24
24
  "admin-api-token",
25
25
  "android-remote.json",
26
+ "auto-update.cmd",
27
+ "auto-update-task.xml",
28
+ "auto-update.json",
29
+ "auto-update.lock",
30
+ "auto-update.log",
26
31
  "catalog-backup.json",
27
32
  "codex-runtime-clamp.json",
28
33
  "codex-runtime.json",