@remodex/rmx 1.0.2 → 1.0.4
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/README.md +32 -10
- package/bin/ocx.mjs +73 -14
- package/gui/dist/assets/index-1SDbgh2-.css +1 -0
- package/gui/dist/assets/{index-CkETtt7P.js → index-D3MaPif3.js} +13 -13
- package/gui/dist/index.html +2 -2
- package/package.json +5 -5
- package/src/android-remote/cloudflare-tunnel.ts +30 -8
- package/src/cli/help.ts +28 -6
- package/src/cli/index.ts +47 -74
- package/src/cli/init.ts +7 -1
- package/src/cli/internal-dispatch.ts +0 -6
- package/src/cli/onboard.ts +599 -0
- package/src/cli/system-command.ts +37 -84
- package/src/codex/inject.ts +8 -1
- package/src/codex/sync.ts +3 -0
- package/src/lib/config-ownership.ts +5 -0
- package/src/lib/remodex-home.ts +5 -0
- package/src/server/management/android-remote-routes.ts +1 -1
- package/src/server/management/config-routes.ts +0 -80
- package/src/server/management/context.ts +0 -4
- package/src/tray/windows-tray.ps1 +109 -66
- package/src/tray/windows.ts +7 -1
- package/src/update/auto-scheduler.ts +1671 -0
- package/src/update/job.ts +72 -13
- package/src/update/notify.ts +2 -2
- package/gui/dist/assets/index-CZqebSPQ.css +0 -1
- package/src/update/desktop-release.ts +0 -1620
package/gui/dist/index.html
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
} catch (e) {}
|
|
17
17
|
})();
|
|
18
18
|
</script>
|
|
19
|
-
<script type="module" crossorigin src="/assets/index-
|
|
20
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
19
|
+
<script type="module" crossorigin src="/assets/index-D3MaPif3.js"></script>
|
|
20
|
+
<link rel="stylesheet" crossorigin href="/assets/index-1SDbgh2-.css">
|
|
21
21
|
</head>
|
|
22
22
|
<body>
|
|
23
23
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remodex/rmx",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
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",
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
"./package.json": "./package.json"
|
|
14
14
|
},
|
|
15
15
|
"bin": {
|
|
16
|
-
"rmx": "
|
|
17
|
-
"remodex": "
|
|
18
|
-
"opencodex": "
|
|
19
|
-
"ocx": "
|
|
16
|
+
"rmx": "bin/ocx.mjs",
|
|
17
|
+
"remodex": "bin/ocx.mjs",
|
|
18
|
+
"opencodex": "bin/ocx.mjs",
|
|
19
|
+
"ocx": "bin/ocx.mjs"
|
|
20
20
|
},
|
|
21
21
|
"files": [
|
|
22
22
|
"bin",
|
|
@@ -8,7 +8,23 @@ import { resolveCloudflared, type CloudflaredExecutable } from "./cloudflared";
|
|
|
8
8
|
const QUICK_TUNNEL_URL = /https:\/\/[a-z0-9-]+\.trycloudflare\.com/iu;
|
|
9
9
|
const QUICK_URL_TIMEOUT_MS = 30_000;
|
|
10
10
|
const VERIFY_TIMEOUT_MS = 5_000;
|
|
11
|
-
const
|
|
11
|
+
const PROCESS_RETRY_DELAYS_MS = [1_000, 2_500, 5_000, 10_000, 30_000] as const;
|
|
12
|
+
// A freshly-created Quick Tunnel URL and a newly-written Named Tunnel DNS route
|
|
13
|
+
// can be visible in cloudflared output before Cloudflare's edge can serve it.
|
|
14
|
+
// Keep that expected propagation neutral in the UI for almost two minutes. If
|
|
15
|
+
// it still is not reachable, expose the failure but continue probing the same
|
|
16
|
+
// child and URL so late propagation can recover without generating a new URL.
|
|
17
|
+
const VERIFY_PROPAGATION_DELAYS_MS = [
|
|
18
|
+
1_000,
|
|
19
|
+
2_000,
|
|
20
|
+
3_000,
|
|
21
|
+
5_000,
|
|
22
|
+
8_000,
|
|
23
|
+
13_000,
|
|
24
|
+
20_000,
|
|
25
|
+
30_000,
|
|
26
|
+
30_000,
|
|
27
|
+
] as const;
|
|
12
28
|
|
|
13
29
|
export type AndroidRemoteCloudflareFailure =
|
|
14
30
|
| "cloudflared_unavailable"
|
|
@@ -175,8 +191,8 @@ async function verifiedPublicGateway(
|
|
|
175
191
|
try {
|
|
176
192
|
const signal = AbortSignal.timeout(VERIFY_TIMEOUT_MS);
|
|
177
193
|
const [healthResponse, descriptorResponse] = await Promise.all([
|
|
178
|
-
fetchImpl(new URL("/healthz", baseUrl), { signal }),
|
|
179
|
-
fetchImpl(new URL("/.well-known/t3/environment", baseUrl), { signal }),
|
|
194
|
+
fetchImpl(new URL("/healthz", baseUrl), { signal, cache: "no-store" }),
|
|
195
|
+
fetchImpl(new URL("/.well-known/t3/environment", baseUrl), { signal, cache: "no-store" }),
|
|
180
196
|
]);
|
|
181
197
|
if (!healthResponse.ok || !descriptorResponse.ok) return false;
|
|
182
198
|
const health = await healthResponse.json() as Record<string, unknown>;
|
|
@@ -218,7 +234,9 @@ export class ManagedAndroidRemoteCloudflareTunnel implements AndroidRemoteCloudf
|
|
|
218
234
|
}
|
|
219
235
|
return {
|
|
220
236
|
mode: settings.tunnelMode,
|
|
221
|
-
...(settings.
|
|
237
|
+
...(settings.tunnelMode === "named" && settings.namedTunnelHostname
|
|
238
|
+
? { namedHostname: settings.namedTunnelHostname }
|
|
239
|
+
: {}),
|
|
222
240
|
hasNamedTunnelToken: this.hasNamedTunnelToken,
|
|
223
241
|
};
|
|
224
242
|
}
|
|
@@ -322,7 +340,7 @@ export class ManagedAndroidRemoteCloudflareTunnel implements AndroidRemoteCloudf
|
|
|
322
340
|
publicUrl: null,
|
|
323
341
|
error: result,
|
|
324
342
|
});
|
|
325
|
-
const delay =
|
|
343
|
+
const delay = PROCESS_RETRY_DELAYS_MS[Math.min(attempt, PROCESS_RETRY_DELAYS_MS.length - 1)]!;
|
|
326
344
|
attempt += 1;
|
|
327
345
|
await this.deps.sleep(delay);
|
|
328
346
|
}
|
|
@@ -444,7 +462,7 @@ export class ManagedAndroidRemoteCloudflareTunnel implements AndroidRemoteCloudf
|
|
|
444
462
|
return "tunnel_failed";
|
|
445
463
|
}
|
|
446
464
|
verificationFailures += 1;
|
|
447
|
-
if (verificationFailures
|
|
465
|
+
if (verificationFailures > VERIFY_PROPAGATION_DELAYS_MS.length) {
|
|
448
466
|
this.publish({
|
|
449
467
|
mode,
|
|
450
468
|
status: "error",
|
|
@@ -452,7 +470,9 @@ export class ManagedAndroidRemoteCloudflareTunnel implements AndroidRemoteCloudf
|
|
|
452
470
|
error: "verification_failed",
|
|
453
471
|
});
|
|
454
472
|
}
|
|
455
|
-
const delay =
|
|
473
|
+
const delay = VERIFY_PROPAGATION_DELAYS_MS[
|
|
474
|
+
Math.min(verificationFailures - 1, VERIFY_PROPAGATION_DELAYS_MS.length - 1)
|
|
475
|
+
]!;
|
|
456
476
|
const wait = await Promise.race([
|
|
457
477
|
this.deps.sleep(delay).then(() => "retry" as const),
|
|
458
478
|
child.exited.then(() => "exit" as const),
|
|
@@ -473,7 +493,9 @@ export class DisabledAndroidRemoteCloudflareTunnel implements AndroidRemoteCloud
|
|
|
473
493
|
async configuration(settings: AndroidRemoteSettings): Promise<AndroidRemoteCloudflareConfiguration> {
|
|
474
494
|
return {
|
|
475
495
|
mode: settings.tunnelMode,
|
|
476
|
-
...(settings.
|
|
496
|
+
...(settings.tunnelMode === "named" && settings.namedTunnelHostname
|
|
497
|
+
? { namedHostname: settings.namedTunnelHostname }
|
|
498
|
+
: {}),
|
|
477
499
|
hasNamedTunnelToken: false,
|
|
478
500
|
};
|
|
479
501
|
}
|
package/src/cli/help.ts
CHANGED
|
@@ -20,6 +20,15 @@ function canonicalCommand(value: string): string {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
const helpEntries: Record<string, HelpEntry> = {
|
|
23
|
+
onboard: {
|
|
24
|
+
usage: "rmx onboard [--verbose] [--json] [--no-open]",
|
|
25
|
+
summary: "Configure Codex, Android Remote, the background service, and a verified phone link.",
|
|
26
|
+
details: [
|
|
27
|
+
"Safe to rerun: existing providers and custom-domain tunnels are preserved.",
|
|
28
|
+
"Fresh users get Quick Tunnel; Windows also installs the status tray.",
|
|
29
|
+
"--verbose shows inner command diagnostics; --json implies --no-open.",
|
|
30
|
+
],
|
|
31
|
+
},
|
|
23
32
|
init: { usage: "rmx init", summary: "Interactive setup for providers and Codex config injection." },
|
|
24
33
|
setup: { usage: "rmx setup", summary: "Interactive setup for providers and Codex config injection (alias of init)." },
|
|
25
34
|
start: { usage: "rmx start [--port <port>]", summary: "Start the proxy server and sync models to Codex." },
|
|
@@ -104,10 +113,17 @@ const helpEntries: Record<string, HelpEntry> = {
|
|
|
104
113
|
},
|
|
105
114
|
login: { usage: "rmx login <provider>", summary: "OAuth or API-key login for a provider." },
|
|
106
115
|
logout: { usage: "rmx logout <provider>", summary: "Remove a stored provider login." },
|
|
107
|
-
gui: {
|
|
116
|
+
gui: {
|
|
117
|
+
usage: "rmx gui [--update]",
|
|
118
|
+
summary: "Open the Remodex dashboard; --update opens the npm package updater.",
|
|
119
|
+
},
|
|
108
120
|
update: {
|
|
109
121
|
usage: "rmx update [--tag latest|preview]",
|
|
110
122
|
summary: "Update Remodex. Preview installs stay on the preview tag unless overridden.",
|
|
123
|
+
details: [
|
|
124
|
+
"Automatic updates are enabled by default for global installs.",
|
|
125
|
+
"Use `rmx system update auto off` to disable them, or `rmx system update auto status` to inspect the scheduler.",
|
|
126
|
+
],
|
|
111
127
|
},
|
|
112
128
|
provider: {
|
|
113
129
|
usage: "rmx provider <list|add|edit|test|remove|show|set-default|selected|quota|presets|account-mode>",
|
|
@@ -194,13 +210,15 @@ const helpEntries: Record<string, HelpEntry> = {
|
|
|
194
210
|
grok: { usage: "rmx grok <status|exclude|include|set|clear|apply> ...", summary: "Manage and apply the Grok Build model fence." },
|
|
195
211
|
integration: { usage: "rmx integration <claude|grok|client> ...", summary: "Manage supported client integrations." },
|
|
196
212
|
system: {
|
|
197
|
-
usage: "rmx system <status|settings|startup|diagnostics|sync|update
|
|
213
|
+
usage: "rmx system <status|settings|startup|diagnostics|sync|update> ...",
|
|
198
214
|
summary: "Manage headless runtime settings, startup, sync, diagnostics, and updates.",
|
|
199
215
|
details: [
|
|
200
|
-
"
|
|
201
|
-
"
|
|
202
|
-
"
|
|
203
|
-
"
|
|
216
|
+
"update check [--channel latest|preview] Check the @remodex/rmx package on npm.",
|
|
217
|
+
"update run [--channel latest|preview] --yes Install the npm package update.",
|
|
218
|
+
"update auto on [--channel latest|preview] Enable the daily unattended package updater (enabled by default for global installs).",
|
|
219
|
+
"update auto off Disable unattended package updates.",
|
|
220
|
+
"update auto status Show scheduler, last result, and rollback information.",
|
|
221
|
+
"Changelogs come from the matching GitHub Release (v<version>).",
|
|
204
222
|
],
|
|
205
223
|
},
|
|
206
224
|
config: {
|
|
@@ -295,6 +313,8 @@ export function printUsage(): void {
|
|
|
295
313
|
const canonical = `Remodex (rmx) — Universal provider proxy for Codex
|
|
296
314
|
|
|
297
315
|
Usage:
|
|
316
|
+
rmx Install/update and start the background service
|
|
317
|
+
rmx onboard Complete first-time setup and open the phone pairing QR
|
|
298
318
|
rmx setup Interactive setup (alias: init)
|
|
299
319
|
rmx start [--port <port>] Start the proxy server (auto-syncs models to Codex)
|
|
300
320
|
rmx stop Stop the proxy AND restore native Codex (plain codex works again)
|
|
@@ -340,6 +360,8 @@ Usage:
|
|
|
340
360
|
rmx --version | -v Print version
|
|
341
361
|
|
|
342
362
|
Examples:
|
|
363
|
+
rmx Install/update and start the background service
|
|
364
|
+
rmx onboard Set up Codex, the service, and Android Remote
|
|
343
365
|
rmx init Set up provider and inject into Codex
|
|
344
366
|
rmx start Start on default port (10100)
|
|
345
367
|
rmx start --port 8080 Start on custom port
|
package/src/cli/index.ts
CHANGED
|
@@ -59,15 +59,6 @@ import { maybeShowUpdatePrompt } from "../update/notify";
|
|
|
59
59
|
import { syncModelsToCodex } from "../codex/sync";
|
|
60
60
|
import { setIntegrationEnabled, shouldSyncCodexOnStart, shouldSyncGrokOnStart, syncCodexOnStartIfEnabled } from "../codex/desired-state";
|
|
61
61
|
import { normalizeUpdateChannel, runGuiUpdateWorker } from "../update/job";
|
|
62
|
-
import { currentVersion } from "../update/index";
|
|
63
|
-
import {
|
|
64
|
-
desktopUpdateInstallAction,
|
|
65
|
-
readDesktopUpdateState,
|
|
66
|
-
runAutomaticDesktopUpdateCheck,
|
|
67
|
-
runDesktopUpdateWorker,
|
|
68
|
-
startDesktopUpdateJob,
|
|
69
|
-
type DesktopReleaseChannel,
|
|
70
|
-
} from "../update/desktop-release";
|
|
71
62
|
import { collectOrcaCodexHomeDiagnostic } from "../codex/home";
|
|
72
63
|
import { removeOwnedConfigState } from "../lib/config-ownership";
|
|
73
64
|
import { withProcessRuntimeProvenance } from "../lib/bun-runtime";
|
|
@@ -460,6 +451,10 @@ async function handleStart(options: { block?: boolean } = {}) {
|
|
|
460
451
|
// to explain it. Name the failure and the one command that repairs it.
|
|
461
452
|
console.error(`⚠️ ${grokSyncFailureMessage(err)}`);
|
|
462
453
|
}
|
|
454
|
+
try {
|
|
455
|
+
const { ensureDefaultAutoUpdateScheduler } = await import("../update/auto-scheduler");
|
|
456
|
+
ensureDefaultAutoUpdateScheduler();
|
|
457
|
+
} catch { /* default updater provisioning must never block proxy startup */ }
|
|
463
458
|
if (options.block ?? true) {
|
|
464
459
|
setInterval(() => {}, 60_000);
|
|
465
460
|
await new Promise<void>(() => {});
|
|
@@ -477,6 +472,12 @@ function detachedStartEnvironment(): NodeJS.ProcessEnv {
|
|
|
477
472
|
async function handleEnsure(options: { existingIsSuccess?: boolean } = {}): Promise<boolean> {
|
|
478
473
|
if (!currentExternalCodexModelProvider()) reconcileJournal();
|
|
479
474
|
const config = loadConfig();
|
|
475
|
+
// Provision the daily updater for global installs during the first normal
|
|
476
|
+
// bootstrap. The helper skips service children and the updater worker itself.
|
|
477
|
+
try {
|
|
478
|
+
const { ensureDefaultAutoUpdateScheduler } = await import("../update/auto-scheduler");
|
|
479
|
+
ensureDefaultAutoUpdateScheduler();
|
|
480
|
+
} catch { /* automatic updates must never block proxy startup */ }
|
|
480
481
|
if (!codexAutoStartEnabled(config)) {
|
|
481
482
|
console.log("Codex autostart is disabled.");
|
|
482
483
|
return false;
|
|
@@ -653,56 +654,6 @@ async function handleTrayProxyRestart(): Promise<void> {
|
|
|
653
654
|
await handleProxyRestart(() => handleTrayProxyStart(false));
|
|
654
655
|
}
|
|
655
656
|
|
|
656
|
-
/**
|
|
657
|
-
* Fixed desktop-shell action used by the tray. A first click checks and
|
|
658
|
-
* downloads a verified artifact; once the tray shows "ready", the next click
|
|
659
|
-
* hands it to the platform installer. No caller-selected command or path is
|
|
660
|
-
* accepted here.
|
|
661
|
-
*/
|
|
662
|
-
async function handleDesktopUpdateRequest(requestArgs: string[] = []): Promise<void> {
|
|
663
|
-
let expectedReady: { id: string; channel: DesktopReleaseChannel } | undefined;
|
|
664
|
-
if (requestArgs.length > 0) {
|
|
665
|
-
const [mode, id, channel] = requestArgs;
|
|
666
|
-
if (
|
|
667
|
-
requestArgs.length !== 3
|
|
668
|
-
|| mode !== "--install-ready"
|
|
669
|
-
|| !id
|
|
670
|
-
|| !/^desktop-\d+-[a-z0-9]{1,32}$/.test(id)
|
|
671
|
-
|| (channel !== "latest" && channel !== "preview")
|
|
672
|
-
) {
|
|
673
|
-
console.error("Invalid desktop update request.");
|
|
674
|
-
process.exitCode = 64;
|
|
675
|
-
return;
|
|
676
|
-
}
|
|
677
|
-
expectedReady = { id, channel };
|
|
678
|
-
}
|
|
679
|
-
const previous = readDesktopUpdateState();
|
|
680
|
-
const install = expectedReady !== undefined || desktopUpdateInstallAction(previous);
|
|
681
|
-
const channel: DesktopReleaseChannel = expectedReady?.channel
|
|
682
|
-
?? previous?.channel
|
|
683
|
-
?? (currentVersion().includes("-") ? "preview" : "latest");
|
|
684
|
-
try {
|
|
685
|
-
const job = startDesktopUpdateJob(channel, {
|
|
686
|
-
install,
|
|
687
|
-
...(expectedReady ? { expectedReady } : {}),
|
|
688
|
-
});
|
|
689
|
-
console.log(
|
|
690
|
-
install
|
|
691
|
-
? `Desktop update installation started (${job.latestVersion ?? "latest"}).`
|
|
692
|
-
: "Desktop update check started.",
|
|
693
|
-
);
|
|
694
|
-
} catch (error) {
|
|
695
|
-
console.error(error instanceof Error ? error.message : "Desktop update could not start.");
|
|
696
|
-
process.exitCode = 1;
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
async function handleAutomaticDesktopUpdateCheck(): Promise<void> {
|
|
701
|
-
const channel: DesktopReleaseChannel = currentVersion().includes("-") ? "preview" : "latest";
|
|
702
|
-
const result = await runAutomaticDesktopUpdateCheck(channel);
|
|
703
|
-
console.log(JSON.stringify(result));
|
|
704
|
-
}
|
|
705
|
-
|
|
706
657
|
async function handleRestartStartWhenStopped(): Promise<boolean | "skipped"> {
|
|
707
658
|
if (!codexAutoStartEnabled(loadConfig())) {
|
|
708
659
|
console.log("Codex autostart is disabled; no proxy was started.");
|
|
@@ -872,6 +823,17 @@ async function handleUninstall() {
|
|
|
872
823
|
}
|
|
873
824
|
};
|
|
874
825
|
|
|
826
|
+
await runStep("automatic updater removed", async () => {
|
|
827
|
+
const {
|
|
828
|
+
disableAutoUpdates,
|
|
829
|
+
readAutoUpdateStatus,
|
|
830
|
+
} = await import("../update/auto-scheduler");
|
|
831
|
+
const status = readAutoUpdateStatus();
|
|
832
|
+
if (status.scheduler === "absent" && !status.state) return false;
|
|
833
|
+
disableAutoUpdates();
|
|
834
|
+
return true;
|
|
835
|
+
});
|
|
836
|
+
|
|
875
837
|
await runStep("service stopped", () => stopServiceIfInstalled());
|
|
876
838
|
|
|
877
839
|
await runStep("proxy stopped", async () => {
|
|
@@ -1059,6 +1021,11 @@ async function handleReady(args: ReadyArgs): Promise<never> {
|
|
|
1059
1021
|
}
|
|
1060
1022
|
|
|
1061
1023
|
switch (command) {
|
|
1024
|
+
case "onboard": {
|
|
1025
|
+
const { runOnboardCommand } = await import("./onboard");
|
|
1026
|
+
process.exitCode = await runOnboardCommand(args.slice(1));
|
|
1027
|
+
break;
|
|
1028
|
+
}
|
|
1062
1029
|
case "init":
|
|
1063
1030
|
case "setup": {
|
|
1064
1031
|
const { runInit } = await import("./init");
|
|
@@ -1251,6 +1218,13 @@ switch (command) {
|
|
|
1251
1218
|
break;
|
|
1252
1219
|
}
|
|
1253
1220
|
case "gui": {
|
|
1221
|
+
const guiArgs = args.slice(1);
|
|
1222
|
+
const openUpdate = guiArgs.length === 1 && guiArgs[0] === "--update";
|
|
1223
|
+
if (guiArgs.length > (openUpdate ? 1 : 0)) {
|
|
1224
|
+
console.error("Usage: rmx gui [--update]");
|
|
1225
|
+
process.exitCode = 64;
|
|
1226
|
+
break;
|
|
1227
|
+
}
|
|
1254
1228
|
const cfg = await import("../config");
|
|
1255
1229
|
const config = cfg.loadConfig();
|
|
1256
1230
|
// Identity-checked liveness (not the pid file + a fixed sleep): finds a fallback-port
|
|
@@ -1274,15 +1248,23 @@ switch (command) {
|
|
|
1274
1248
|
// Open the host the proxy actually binds — `localhost` only answers for
|
|
1275
1249
|
// loopback/wildcard binds, not a concrete LAN/IPv6 hostname.
|
|
1276
1250
|
const guiHost = probeHostname(live?.hostname ?? config.hostname);
|
|
1277
|
-
const guiUrl = `http://${guiHost === "127.0.0.1" ? "localhost" : guiHost}:${live?.port ?? config.port}`;
|
|
1251
|
+
const guiUrl = `http://${guiHost === "127.0.0.1" ? "localhost" : guiHost}:${live?.port ?? config.port}${openUpdate ? "/#dashboard/update" : ""}`;
|
|
1278
1252
|
console.log(`Opening ${guiUrl}`);
|
|
1279
1253
|
const { openUrl } = await import("../lib/open-url");
|
|
1280
1254
|
openUrl(guiUrl);
|
|
1281
1255
|
break;
|
|
1282
1256
|
}
|
|
1283
|
-
case "service":
|
|
1257
|
+
case "service": {
|
|
1258
|
+
const serviceSubcommand = args[1] ?? "install";
|
|
1284
1259
|
await serviceCommand(...args.slice(1));
|
|
1260
|
+
if (!["status", "stop", "uninstall", "remove"].includes(serviceSubcommand)) {
|
|
1261
|
+
try {
|
|
1262
|
+
const { ensureDefaultAutoUpdateScheduler } = await import("../update/auto-scheduler");
|
|
1263
|
+
ensureDefaultAutoUpdateScheduler();
|
|
1264
|
+
} catch { /* default updater provisioning must not block service commands */ }
|
|
1265
|
+
}
|
|
1285
1266
|
break;
|
|
1267
|
+
}
|
|
1286
1268
|
case "tray": {
|
|
1287
1269
|
const { windowsTrayCommand } = await import("../tray/windows");
|
|
1288
1270
|
await windowsTrayCommand(args.slice(1));
|
|
@@ -1335,19 +1317,12 @@ switch (command) {
|
|
|
1335
1317
|
await refreshVersionCache(channel);
|
|
1336
1318
|
break;
|
|
1337
1319
|
}
|
|
1338
|
-
case "
|
|
1339
|
-
const
|
|
1340
|
-
const
|
|
1341
|
-
if (!
|
|
1342
|
-
console.error("Invalid desktop update worker arguments.");
|
|
1343
|
-
process.exitCode = 64;
|
|
1344
|
-
break;
|
|
1345
|
-
}
|
|
1346
|
-
await runDesktopUpdateWorker(id, mode === "install");
|
|
1320
|
+
case "__auto-update": {
|
|
1321
|
+
const { runAutomaticUpdateWorker } = await import("../update/auto-scheduler");
|
|
1322
|
+
const result = await runAutomaticUpdateWorker();
|
|
1323
|
+
if (!result.ok) process.exitCode = 1;
|
|
1347
1324
|
break;
|
|
1348
1325
|
}
|
|
1349
|
-
case "__desktop-update":
|
|
1350
|
-
case "__desktop-auto-update-check":
|
|
1351
1326
|
case "__tray-start":
|
|
1352
1327
|
case "__tray-restart":
|
|
1353
1328
|
case "__startup-health":
|
|
@@ -1356,8 +1331,6 @@ switch (command) {
|
|
|
1356
1331
|
await dispatchInternalCliCommand(command as InternalCliCommand, {
|
|
1357
1332
|
trayStart: async () => { await handleTrayProxyStart(); },
|
|
1358
1333
|
trayRestart: handleTrayProxyRestart,
|
|
1359
|
-
desktopUpdate: () => handleDesktopUpdateRequest(args.slice(1)),
|
|
1360
|
-
desktopAutoUpdateCheck: handleAutomaticDesktopUpdateCheck,
|
|
1361
1334
|
startupHealth: async () => {
|
|
1362
1335
|
const { collectStartupHealth } = await import("../codex/autostart-health");
|
|
1363
1336
|
console.log(JSON.stringify(collectStartupHealth(loadConfig())));
|
package/src/cli/init.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as readline from "node:readline";
|
|
2
2
|
import { constants as fsConstants, copyFileSync, existsSync, readFileSync, unlinkSync } from "node:fs";
|
|
3
3
|
import { injectCodexConfig } from "../codex/inject";
|
|
4
|
+
import { CODEX_CONFIG_PATH } from "../codex/paths";
|
|
4
5
|
import { classifyOpenAiTierBackup, getConfigPath, getDefaultConfig, isValidProviderName, saveConfig } from "../config";
|
|
5
6
|
import { enrichProviderFromCatalog } from "../oauth/key-providers";
|
|
6
7
|
import { deriveInitProviders } from "../providers/derive";
|
|
@@ -189,13 +190,18 @@ export async function runInit(): Promise<void> {
|
|
|
189
190
|
// preserved by renaming it out of the collision path (sol review 260722).
|
|
190
191
|
cleanupOpenAiTierBackupAfterInit();
|
|
191
192
|
console.log(`\n✅ Config saved to ${getConfigPath()}`);
|
|
193
|
+
console.log(` Codex config target: ${CODEX_CONFIG_PATH}`);
|
|
192
194
|
if (oauthHint) console.log(`🔐 Authenticate this provider with: rmx login ${providerName}`);
|
|
193
195
|
|
|
194
196
|
const injectAnswer = await prompt.ask("Inject into Codex config.toml? [Y/n]: ");
|
|
195
197
|
if (injectAnswer.trim().toLowerCase() !== "n") {
|
|
196
198
|
console.log("Fetching available models from provider...");
|
|
197
199
|
const result = await injectCodexConfig(port, config);
|
|
198
|
-
|
|
200
|
+
const routed = result.success && result.routingApplied !== false;
|
|
201
|
+
console.log(routed ? `✅ ${result.message}` : `⚠️ ${result.message}`);
|
|
202
|
+
if (!routed) {
|
|
203
|
+
console.log(` Remodex did not take ownership of plain Codex routing. Review the reason above, then run 'rmx sync'.`);
|
|
204
|
+
}
|
|
199
205
|
}
|
|
200
206
|
|
|
201
207
|
const shimAnswer = await prompt.ask("Install Codex autostart shim? [Y/n]: ");
|
|
@@ -2,8 +2,6 @@ export type InternalCliCommand =
|
|
|
2
2
|
| "__tray-start"
|
|
3
3
|
| "__tray-restart"
|
|
4
4
|
| "__startup-health"
|
|
5
|
-
| "__desktop-update"
|
|
6
|
-
| "__desktop-auto-update-check"
|
|
7
5
|
| "__desktop-restart-codex"
|
|
8
6
|
| "__desktop-restart-client";
|
|
9
7
|
|
|
@@ -11,8 +9,6 @@ export interface InternalCliHandlers {
|
|
|
11
9
|
trayStart: () => void | Promise<void>;
|
|
12
10
|
trayRestart: () => void | Promise<void>;
|
|
13
11
|
startupHealth: () => void | Promise<void>;
|
|
14
|
-
desktopUpdate: () => void | Promise<void>;
|
|
15
|
-
desktopAutoUpdateCheck: () => void | Promise<void>;
|
|
16
12
|
desktopRestartCodex: () => void | Promise<void>;
|
|
17
13
|
desktopRestartClient: () => void | Promise<void>;
|
|
18
14
|
}
|
|
@@ -26,8 +22,6 @@ export async function dispatchInternalCliCommand(
|
|
|
26
22
|
case "__tray-start": return void await handlers.trayStart();
|
|
27
23
|
case "__tray-restart": return void await handlers.trayRestart();
|
|
28
24
|
case "__startup-health": return void await handlers.startupHealth();
|
|
29
|
-
case "__desktop-update": return void await handlers.desktopUpdate();
|
|
30
|
-
case "__desktop-auto-update-check": return void await handlers.desktopAutoUpdateCheck();
|
|
31
25
|
case "__desktop-restart-codex": return void await handlers.desktopRestartCodex();
|
|
32
26
|
case "__desktop-restart-client": return void await handlers.desktopRestartClient();
|
|
33
27
|
default: throw new Error(`Unsupported internal CLI command: ${String(command)}`);
|