@kevin0181/rcodex 0.0.1

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.
Files changed (127) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +160 -0
  3. package/dist/commands/doctor.d.ts +2 -0
  4. package/dist/commands/doctor.d.ts.map +1 -0
  5. package/dist/commands/doctor.js +114 -0
  6. package/dist/commands/doctor.js.map +1 -0
  7. package/dist/commands/gateway-daemon.d.ts +2 -0
  8. package/dist/commands/gateway-daemon.d.ts.map +1 -0
  9. package/dist/commands/gateway-daemon.js +22 -0
  10. package/dist/commands/gateway-daemon.js.map +1 -0
  11. package/dist/commands/launch.d.ts +2 -0
  12. package/dist/commands/launch.d.ts.map +1 -0
  13. package/dist/commands/launch.js +129 -0
  14. package/dist/commands/launch.js.map +1 -0
  15. package/dist/commands/migrate.d.ts +4 -0
  16. package/dist/commands/migrate.d.ts.map +1 -0
  17. package/dist/commands/migrate.js +137 -0
  18. package/dist/commands/migrate.js.map +1 -0
  19. package/dist/commands/setup.d.ts +2 -0
  20. package/dist/commands/setup.d.ts.map +1 -0
  21. package/dist/commands/setup.js +78 -0
  22. package/dist/commands/setup.js.map +1 -0
  23. package/dist/commands/stop.d.ts +2 -0
  24. package/dist/commands/stop.d.ts.map +1 -0
  25. package/dist/commands/stop.js +20 -0
  26. package/dist/commands/stop.js.map +1 -0
  27. package/dist/commands/switch.d.ts +4 -0
  28. package/dist/commands/switch.d.ts.map +1 -0
  29. package/dist/commands/switch.js +78 -0
  30. package/dist/commands/switch.js.map +1 -0
  31. package/dist/commands/sync.d.ts +3 -0
  32. package/dist/commands/sync.d.ts.map +1 -0
  33. package/dist/commands/sync.js +107 -0
  34. package/dist/commands/sync.js.map +1 -0
  35. package/dist/core/codex.d.ts +6 -0
  36. package/dist/core/codex.d.ts.map +1 -0
  37. package/dist/core/codex.js +123 -0
  38. package/dist/core/codex.js.map +1 -0
  39. package/dist/core/config.d.ts +6 -0
  40. package/dist/core/config.d.ts.map +1 -0
  41. package/dist/core/config.js +68 -0
  42. package/dist/core/config.js.map +1 -0
  43. package/dist/core/constants.d.ts +4 -0
  44. package/dist/core/constants.d.ts.map +1 -0
  45. package/dist/core/constants.js +7 -0
  46. package/dist/core/constants.js.map +1 -0
  47. package/dist/core/ollama.d.ts +3 -0
  48. package/dist/core/ollama.d.ts.map +1 -0
  49. package/dist/core/ollama.js +20 -0
  50. package/dist/core/ollama.js.map +1 -0
  51. package/dist/gateway/auth.d.ts +58 -0
  52. package/dist/gateway/auth.d.ts.map +1 -0
  53. package/dist/gateway/auth.js +248 -0
  54. package/dist/gateway/auth.js.map +1 -0
  55. package/dist/gateway/providers/anthropic.d.ts +15 -0
  56. package/dist/gateway/providers/anthropic.d.ts.map +1 -0
  57. package/dist/gateway/providers/anthropic.js +122 -0
  58. package/dist/gateway/providers/anthropic.js.map +1 -0
  59. package/dist/gateway/providers/antigravity-oauth-flow.d.ts +21 -0
  60. package/dist/gateway/providers/antigravity-oauth-flow.d.ts.map +1 -0
  61. package/dist/gateway/providers/antigravity-oauth-flow.js +231 -0
  62. package/dist/gateway/providers/antigravity-oauth-flow.js.map +1 -0
  63. package/dist/gateway/providers/antigravity.d.ts +5 -0
  64. package/dist/gateway/providers/antigravity.d.ts.map +1 -0
  65. package/dist/gateway/providers/antigravity.js +111 -0
  66. package/dist/gateway/providers/antigravity.js.map +1 -0
  67. package/dist/gateway/providers/claude-oauth-flow.d.ts +16 -0
  68. package/dist/gateway/providers/claude-oauth-flow.d.ts.map +1 -0
  69. package/dist/gateway/providers/claude-oauth-flow.js +178 -0
  70. package/dist/gateway/providers/claude-oauth-flow.js.map +1 -0
  71. package/dist/gateway/providers/copilot.d.ts +19 -0
  72. package/dist/gateway/providers/copilot.d.ts.map +1 -0
  73. package/dist/gateway/providers/copilot.js +141 -0
  74. package/dist/gateway/providers/copilot.js.map +1 -0
  75. package/dist/gateway/providers/google.d.ts +12 -0
  76. package/dist/gateway/providers/google.d.ts.map +1 -0
  77. package/dist/gateway/providers/google.js +58 -0
  78. package/dist/gateway/providers/google.js.map +1 -0
  79. package/dist/gateway/providers/ollama.d.ts +6 -0
  80. package/dist/gateway/providers/ollama.d.ts.map +1 -0
  81. package/dist/gateway/providers/ollama.js +54 -0
  82. package/dist/gateway/providers/ollama.js.map +1 -0
  83. package/dist/gateway/providers/openai-oauth-flow.d.ts +15 -0
  84. package/dist/gateway/providers/openai-oauth-flow.d.ts.map +1 -0
  85. package/dist/gateway/providers/openai-oauth-flow.js +149 -0
  86. package/dist/gateway/providers/openai-oauth-flow.js.map +1 -0
  87. package/dist/gateway/providers/openai.d.ts +8 -0
  88. package/dist/gateway/providers/openai.d.ts.map +1 -0
  89. package/dist/gateway/providers/openai.js +193 -0
  90. package/dist/gateway/providers/openai.js.map +1 -0
  91. package/dist/gateway/proxy.d.ts +119 -0
  92. package/dist/gateway/proxy.d.ts.map +1 -0
  93. package/dist/gateway/proxy.js +1949 -0
  94. package/dist/gateway/proxy.js.map +1 -0
  95. package/dist/gateway/server.d.ts +6 -0
  96. package/dist/gateway/server.d.ts.map +1 -0
  97. package/dist/gateway/server.js +890 -0
  98. package/dist/gateway/server.js.map +1 -0
  99. package/dist/gateway/ui.d.ts +2 -0
  100. package/dist/gateway/ui.d.ts.map +1 -0
  101. package/dist/gateway/ui.js +1748 -0
  102. package/dist/gateway/ui.js.map +1 -0
  103. package/dist/index.d.ts +3 -0
  104. package/dist/index.d.ts.map +1 -0
  105. package/dist/index.js +78 -0
  106. package/dist/index.js.map +1 -0
  107. package/dist/types/index.d.ts +26 -0
  108. package/dist/types/index.d.ts.map +1 -0
  109. package/dist/types/index.js +2 -0
  110. package/dist/types/index.js.map +1 -0
  111. package/dist/utils/logger.d.ts +10 -0
  112. package/dist/utils/logger.d.ts.map +1 -0
  113. package/dist/utils/logger.js +25 -0
  114. package/dist/utils/logger.js.map +1 -0
  115. package/dist/utils/paths.d.ts +4 -0
  116. package/dist/utils/paths.d.ts.map +1 -0
  117. package/dist/utils/paths.js +22 -0
  118. package/dist/utils/paths.js.map +1 -0
  119. package/dist/utils/shell.d.ts +8 -0
  120. package/dist/utils/shell.d.ts.map +1 -0
  121. package/dist/utils/shell.js +27 -0
  122. package/dist/utils/shell.js.map +1 -0
  123. package/dist/utils/updates.d.ts +2 -0
  124. package/dist/utils/updates.d.ts.map +1 -0
  125. package/dist/utils/updates.js +83 -0
  126. package/dist/utils/updates.js.map +1 -0
  127. package/package.json +61 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 neneee0181
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,160 @@
1
+ # rcodex
2
+
3
+ A local AI gateway that lets [Codex](https://github.com/openai/codex) talk to Claude, OpenAI, Gemini, Ollama, Antigravity, and GitHub Copilot through one local Responses-compatible proxy with a visual routing UI.
4
+
5
+ ![Node graph UI](https://raw.githubusercontent.com/neneee0181/rcodex/main/docs/ui-preview.png)
6
+
7
+ ## Features
8
+
9
+ - Multi-provider routing for Anthropic Claude, OpenAI, Google Gemini, Ollama, Antigravity, and GitHub Copilot.
10
+ - Visual node graph for selecting models and ordering fallback chains.
11
+ - Automatic fallback when a provider fails, rate-limits, or returns an error.
12
+ - Local request monitor with logs, request history, token usage, latency, and fallback details.
13
+ - Automatic Codex config sync using the stable provider key `rcodex`.
14
+ - Thread migration helper for existing Codex conversations.
15
+ - Update gate on `rcodex`: if a newer npm version exists, rcodex asks the user to approve the global update before launching.
16
+
17
+ ## Requirements
18
+
19
+ - Node.js 20 or newer.
20
+ - Codex CLI or Codex desktop app installed.
21
+ - Provider credentials for the services you want to use.
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ npm install -g @kevin0181/rcodex
27
+ ```
28
+
29
+ Then launch rcodex:
30
+
31
+ ```bash
32
+ rcodex
33
+ ```
34
+
35
+ The first launch starts the gateway, updates `~/.codex/config.toml`, launches Codex, and opens the gateway UI. The default gateway port is `3141`; if that port is busy, rcodex picks the next free port and updates Codex config automatically.
36
+
37
+ ## Updates
38
+
39
+ When users run `rcodex`, the CLI checks the latest published npm version. If a newer version is available, rcodex prompts:
40
+
41
+ ```text
42
+ rcodex 0.0.2 is available (installed: 0.0.1). Update now? [y/N]
43
+ ```
44
+
45
+ If the user accepts, rcodex runs:
46
+
47
+ ```bash
48
+ npm install -g @kevin0181/rcodex@latest
49
+ ```
50
+
51
+ After the update completes, run `rcodex` again. If the user declines, rcodex exits instead of launching the older version. If the npm registry cannot be reached, rcodex allows the installed version to run so offline users are not blocked.
52
+
53
+ ## Gateway UI
54
+
55
+ Open the UI at the URL printed by `rcodex`, usually:
56
+
57
+ ```text
58
+ http://localhost:3141
59
+ ```
60
+
61
+ Use the sidebar to add accounts and model slots. Drag model slots onto the canvas, connect them from the `Out` node, and order multiple slots to create fallback chains.
62
+
63
+ Supported account types:
64
+
65
+ - Claude with Anthropic API key.
66
+ - OpenAI API key or OAuth flow.
67
+ - Google Gemini API key.
68
+ - Antigravity OAuth, using Gemini / Cloud Code routing.
69
+ - GitHub Copilot OAuth device login.
70
+ - Ollama local endpoint, defaulting to `http://localhost:11434`.
71
+
72
+ ## Commands
73
+
74
+ | Command | Description |
75
+ | --- | --- |
76
+ | `rcodex` | Start/restart the gateway, sync Codex config, launch Codex, and open the UI |
77
+ | `rcodex setup` | Run first-time setup in foreground mode |
78
+ | `rcodex stop` | Stop the background gateway |
79
+ | `rcodex gateway` | Switch Codex config to rcodex gateway mode |
80
+ | `rcodex openai` | Switch Codex config back to native OpenAI |
81
+ | `rcodex doctor` | Check installation, gateway status, and provider setup |
82
+ | `rcodex sync` | Re-register the gateway in Codex config and migrate threads |
83
+ | `rcodex migrate` | Migrate existing Codex threads to the `rcodex` provider |
84
+
85
+ ## Provider Notes
86
+
87
+ ### Claude
88
+
89
+ rcodex supports Anthropic API-key accounts. Older unofficial Claude.ai session auth is not supported for direct inference; use an Anthropic API key for Claude model access.
90
+
91
+ ### Ollama
92
+
93
+ Start Ollama before adding an Ollama account:
94
+
95
+ ```bash
96
+ ollama serve
97
+ ```
98
+
99
+ rcodex discovers local models from `http://localhost:11434/v1/models`.
100
+
101
+ ### GitHub Copilot
102
+
103
+ Copilot uses GitHub device-code OAuth. After approval, rcodex stores the GitHub OAuth token locally and exchanges it for short-lived Copilot API tokens when requests are sent.
104
+
105
+ ### Antigravity
106
+
107
+ Antigravity OAuth needs app credentials. If bundled credentials are not available in the package, place credentials at:
108
+
109
+ ```text
110
+ ~/.rcodex/antigravity-app.json
111
+ ```
112
+
113
+ Run `rcodex doctor` to diagnose and auto-fix supported setup issues.
114
+
115
+ ## Data and Privacy
116
+
117
+ - Gateway config is stored at `~/.rcodex/gateway.json`.
118
+ - Request history is stored at `~/.rcodex/requests.jsonl`.
119
+ - Gateway logs are stored at `~/.rcodex/gateway.log`.
120
+ - API keys and OAuth tokens stay local and are only sent to their corresponding provider APIs.
121
+
122
+ ## Publishing
123
+
124
+ npm is the distribution channel for the `rcodex` command. GitHub Releases are useful for release notes and source archives, but users receive updates from npm because they install the package with `npm install -g @kevin0181/rcodex`.
125
+
126
+ For the first release:
127
+
128
+ ```bash
129
+ npm login
130
+ npm run build
131
+ npm publish --access public
132
+ git tag v0.0.1
133
+ git push origin v0.0.1
134
+ ```
135
+
136
+ Then create a GitHub Release from tag `v0.0.1` and paste the release notes. For later versions:
137
+
138
+ ```bash
139
+ npm version patch
140
+ npm publish --access public
141
+ git push origin main --tags
142
+ ```
143
+
144
+ Use `npm version minor` or `npm version major` when the change is larger than a patch release.
145
+
146
+ ## Development
147
+
148
+ ```bash
149
+ git clone https://github.com/neneee0181/rcodex.git
150
+ cd rcodex
151
+ npm install
152
+ npm run dev
153
+ npm run build
154
+ ```
155
+
156
+ There is no automated test script yet; use `npm run build` as the baseline verification.
157
+
158
+ ## License
159
+
160
+ MIT
@@ -0,0 +1,2 @@
1
+ export declare function runDoctor(): Promise<void>;
2
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAYA,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAmG/C"}
@@ -0,0 +1,114 @@
1
+ import { logger } from "../utils/logger.js";
2
+ import { displayPath, getCodexConfigPath } from "../utils/paths.js";
3
+ import { isCodexInstalled } from "../core/codex.js";
4
+ import { isOllamaInstalled, getOllamaModels } from "../core/ollama.js";
5
+ import { readCodexConfig } from "../core/config.js";
6
+ import { loadConfig } from "../gateway/auth.js";
7
+ import { MANAGED_PROVIDER_KEY } from "../core/constants.js";
8
+ import { existsSync, writeFileSync, mkdirSync } from "fs";
9
+ import { join } from "path";
10
+ import { homedir } from "os";
11
+ import { hasAppCredentials, getAppCredentials } from "../gateway/providers/antigravity-oauth-flow.js";
12
+ export async function runDoctor() {
13
+ logger.header();
14
+ logger.info("Doctor: checking installation and configuration...");
15
+ logger.separator();
16
+ // Codex
17
+ const codexOk = await isCodexInstalled();
18
+ if (codexOk)
19
+ logger.success("Codex installed");
20
+ else
21
+ logger.warn("Codex NOT found ??https://github.com/openai/codex");
22
+ // Gateway
23
+ const gw = loadConfig();
24
+ try {
25
+ const res = await fetch(`http://localhost:${gw.port}/api/status`, {
26
+ signal: AbortSignal.timeout(1500),
27
+ });
28
+ if (res.ok) {
29
+ const data = await res.json();
30
+ logger.success(`rcodex Gateway running on :${data.port} (${data.accountCount ?? 0} accounts)`);
31
+ }
32
+ else {
33
+ logger.warn(`rcodex Gateway not running (port: ${gw.port}) ??run: rcodex`);
34
+ }
35
+ }
36
+ catch {
37
+ logger.warn(`rcodex Gateway not running (port: ${gw.port}) ??run: rcodex`);
38
+ }
39
+ // Connected accounts
40
+ const accounts = gw.accounts ?? [];
41
+ if (accounts.length === 0) {
42
+ logger.warn("No accounts connected ??open the Gateway UI to add providers");
43
+ }
44
+ else {
45
+ logger.success(`Accounts: ${accounts.map(a => `${a.provider}(${a.label})`).join(", ")}`);
46
+ }
47
+ // Ollama
48
+ const ollamaOk = await isOllamaInstalled();
49
+ if (ollamaOk) {
50
+ const models = await getOllamaModels();
51
+ if (models.length === 0)
52
+ logger.warn("Ollama installed but no models ??run: ollama pull <model>");
53
+ else
54
+ logger.success(`Ollama: ${models.length} model(s) ??${models.slice(0, 3).join(", ")}${models.length > 3 ? "..." : ""}`);
55
+ }
56
+ else {
57
+ logger.warn("Ollama NOT found ??https://ollama.com (optional)");
58
+ }
59
+ // Antigravity credentials check + auto-fix
60
+ logger.separator();
61
+ logger.info("Checking Antigravity (Google Cloud Code) credentials...");
62
+ const rcodexDir = join(homedir(), ".rcodex");
63
+ const userCredsPath = join(rcodexDir, "antigravity-app.json");
64
+ if (hasAppCredentials()) {
65
+ logger.success("Antigravity credentials available");
66
+ }
67
+ else {
68
+ logger.warn("Antigravity credentials not found ??attempting auto-fix...");
69
+ // Try to extract bundled credentials and write to user path
70
+ try {
71
+ const creds = getAppCredentials(); // will throw if bundled also missing
72
+ mkdirSync(rcodexDir, { recursive: true });
73
+ writeFileSync(userCredsPath, JSON.stringify(creds, null, 2), "utf-8");
74
+ logger.success(`Created ${userCredsPath}`);
75
+ }
76
+ catch {
77
+ logger.warn("Could not auto-fix. Manually create ~/.rcodex/antigravity-app.json:\n" +
78
+ ' { "clientId": "<your-client-id>", "clientSecret": "<your-client-secret>" }');
79
+ }
80
+ }
81
+ // Codex config
82
+ logger.separator();
83
+ let configPath;
84
+ try {
85
+ configPath = getCodexConfigPath();
86
+ logger.success(`Codex config: ${displayPath(configPath)}`);
87
+ }
88
+ catch {
89
+ logger.warn("Codex config path not found");
90
+ logger.done();
91
+ return;
92
+ }
93
+ if (!existsSync(configPath)) {
94
+ logger.warn("config.toml not found ??run: rcodex to create it");
95
+ logger.done();
96
+ return;
97
+ }
98
+ try {
99
+ const config = readCodexConfig(configPath);
100
+ const activeProvider = config.model_provider ?? "(none)";
101
+ const providers = Object.keys(config.model_providers ?? {});
102
+ const gatewayRegistered = providers.includes(MANAGED_PROVIDER_KEY);
103
+ logger.info(` Active provider: ${activeProvider}`);
104
+ if (gatewayRegistered)
105
+ logger.success(" Gateway registered in Codex config");
106
+ else
107
+ logger.warn(" Gateway NOT registered ??run: rcodex");
108
+ }
109
+ catch {
110
+ logger.warn("config.toml parse failed ??file may be corrupted");
111
+ }
112
+ logger.done();
113
+ }
114
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function runGatewayDaemon(): Promise<void>;
2
+ //# sourceMappingURL=gateway-daemon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateway-daemon.d.ts","sourceRoot":"","sources":["../../src/commands/gateway-daemon.ts"],"names":[],"mappings":"AAIA,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAoBtD"}
@@ -0,0 +1,22 @@
1
+ import { createGatewayServer } from "../gateway/server.js";
2
+ // Internal entry point ??spawned as a detached background process by `rcodex` (no args).
3
+ // Not intended for direct user invocation.
4
+ export async function runGatewayDaemon() {
5
+ const server = createGatewayServer();
6
+ try {
7
+ await server.start();
8
+ }
9
+ catch (err) {
10
+ process.stderr.write(`Gateway daemon failed to start: ${err}\n`);
11
+ process.exit(1);
12
+ }
13
+ const shutdown = async () => {
14
+ await server.stop();
15
+ process.exit(0);
16
+ };
17
+ process.on("SIGTERM", shutdown);
18
+ process.on("SIGINT", shutdown);
19
+ // Keep the process alive
20
+ setInterval(() => { }, 1000);
21
+ }
22
+ //# sourceMappingURL=gateway-daemon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateway-daemon.js","sourceRoot":"","sources":["../../src/commands/gateway-daemon.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D,yFAAyF;AACzF,2CAA2C;AAC3C,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,MAAM,GAAG,mBAAmB,EAAE,CAAC;IAErC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mCAAmC,GAAG,IAAI,CAAC,CAAC;QACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QAC1B,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAE/B,yBAAyB;IACzB,WAAW,CAAC,GAAG,EAAE,GAAE,CAAC,EAAE,IAAI,CAAC,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function runLaunch(): Promise<void>;
2
+ //# sourceMappingURL=launch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launch.d.ts","sourceRoot":"","sources":["../../src/commands/launch.ts"],"names":[],"mappings":"AA4DA,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CA6E/C"}
@@ -0,0 +1,129 @@
1
+ import { spawn } from "child_process";
2
+ import { openSync, mkdirSync, existsSync } from "fs";
3
+ import { join } from "path";
4
+ import { homedir, platform } from "os";
5
+ import { logger } from "../utils/logger.js";
6
+ import { getCodexConfigPath } from "../utils/paths.js";
7
+ import { readCodexConfig, writeCodexConfig, backupCodexConfig } from "../core/config.js";
8
+ import { MANAGED_PROVIDER_KEY } from "../core/constants.js";
9
+ import { loadConfig, killExistingGateway } from "../gateway/auth.js";
10
+ import { isCodexRunning, killCodex, openCodexApp } from "../core/codex.js";
11
+ import { hasUnmigratedThreads, migrateThreads } from "./migrate.js";
12
+ const RCODEX_DIR = join(homedir(), ".rcodex");
13
+ const DAEMON_LOG = join(RCODEX_DIR, "gateway.log");
14
+ // Poll until gateway responds or timeout. Re-reads gateway.json each tick so we
15
+ // pick up the actual port if the daemon had to use a different one.
16
+ async function waitForGateway(initialPort, timeoutMs = 6000) {
17
+ const deadline = Date.now() + timeoutMs;
18
+ let port = initialPort;
19
+ while (Date.now() < deadline) {
20
+ await new Promise((r) => setTimeout(r, 250));
21
+ port = loadConfig().port; // daemon may have updated this
22
+ try {
23
+ const res = await fetch(`http://localhost:${port}/api/status`, {
24
+ signal: AbortSignal.timeout(400),
25
+ });
26
+ if (res.ok)
27
+ return port;
28
+ }
29
+ catch { /* keep waiting */ }
30
+ }
31
+ return null;
32
+ }
33
+ function getCodexConfigPort(configPath) {
34
+ try {
35
+ const config = readCodexConfig(configPath);
36
+ const baseUrl = config.model_providers?.[MANAGED_PROVIDER_KEY]?.base_url;
37
+ if (!baseUrl)
38
+ return null;
39
+ const match = baseUrl.match(/:(\d+)\/v1/);
40
+ return match ? parseInt(match[1], 10) : null;
41
+ }
42
+ catch {
43
+ return null;
44
+ }
45
+ }
46
+ function syncCodexConfigPort(configPath, port) {
47
+ backupCodexConfig(configPath);
48
+ const config = readCodexConfig(configPath);
49
+ if (!config.model_providers)
50
+ config.model_providers = {};
51
+ config.model_providers[MANAGED_PROVIDER_KEY] = {
52
+ name: "rcodex Gateway",
53
+ base_url: `http://localhost:${port}/v1`,
54
+ wire_api: "responses",
55
+ };
56
+ config.model_provider = MANAGED_PROVIDER_KEY;
57
+ writeCodexConfig(configPath, config);
58
+ }
59
+ export async function runLaunch() {
60
+ logger.header();
61
+ // 1. Stop any existing gateway and restart fresh
62
+ const killed = killExistingGateway();
63
+ if (killed) {
64
+ logger.info("Restarting gateway...");
65
+ await new Promise((r) => setTimeout(r, 600));
66
+ }
67
+ const configuredPort = loadConfig().port;
68
+ // 2. Spawn gateway as a detached background daemon
69
+ logger.info("Starting gateway in background...");
70
+ if (!existsSync(RCODEX_DIR))
71
+ mkdirSync(RCODEX_DIR, { recursive: true });
72
+ const logFd = openSync(DAEMON_LOG, "a");
73
+ const child = spawn(process.execPath, [process.argv[1], "_gateway"], {
74
+ detached: true,
75
+ stdio: ["ignore", logFd, logFd],
76
+ windowsHide: true,
77
+ });
78
+ child.unref();
79
+ // 3. Wait until the gateway responds
80
+ const port = await waitForGateway(configuredPort);
81
+ if (port === null) {
82
+ logger.error("Gateway did not start in time. Run 'rcodex setup' to reconfigure.");
83
+ return;
84
+ }
85
+ const actualPort = port;
86
+ // 4. Keep Codex config in sync with the actual running port
87
+ const configPath = getCodexConfigPath();
88
+ const codexPort = getCodexConfigPort(configPath);
89
+ if (codexPort !== actualPort) {
90
+ syncCodexConfigPort(configPath, actualPort);
91
+ logger.success(`Config updated: ${MANAGED_PROVIDER_KEY} ??http://localhost:${actualPort}/v1` +
92
+ (codexPort ? ` (was :${codexPort})` : " (new)"));
93
+ }
94
+ else {
95
+ logger.success(`Config OK: ${MANAGED_PROVIDER_KEY} ??http://localhost:${actualPort}/v1`);
96
+ }
97
+ // 5. Migrate threads if needed (only when there's something to do)
98
+ if (hasUnmigratedThreads(MANAGED_PROVIDER_KEY)) {
99
+ logger.separator();
100
+ logger.info("Unmigrated threads found ??migrating to rcodex Gateway...");
101
+ const codexRunning = await isCodexRunning();
102
+ if (codexRunning) {
103
+ await killCodex();
104
+ await new Promise((r) => setTimeout(r, 800));
105
+ }
106
+ await migrateThreads(MANAGED_PROVIDER_KEY, false);
107
+ }
108
+ // 6. Restart Codex if running, otherwise just launch it
109
+ if (await isCodexRunning()) {
110
+ logger.info("Restarting Codex...");
111
+ await killCodex();
112
+ await new Promise((r) => setTimeout(r, 800));
113
+ }
114
+ await openCodexApp();
115
+ logger.success("Codex launched");
116
+ // Open gateway UI in the default browser
117
+ const uiUrl = `http://localhost:${actualPort}`;
118
+ if (platform() === "win32") {
119
+ spawn("cmd.exe", ["/c", "start", "", uiUrl], { detached: true, stdio: "ignore", windowsHide: true }).unref();
120
+ }
121
+ else {
122
+ const opener = platform() === "darwin" ? "open" : "xdg-open";
123
+ spawn(opener, [uiUrl], { detached: true, stdio: "ignore" }).unref();
124
+ }
125
+ logger.success(`Gateway UI: ${uiUrl}`);
126
+ logger.info("Run 'rcodex stop' to shut down the gateway.");
127
+ process.exit(0);
128
+ }
129
+ //# sourceMappingURL=launch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launch.js","sourceRoot":"","sources":["../../src/commands/launch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function hasUnmigratedThreads(targetProvider: string): boolean;
2
+ export declare function migrateThreads(targetProvider: string, dryRun: boolean): Promise<void>;
3
+ export declare function runMigrate(dryRun?: boolean, showHeader?: boolean): Promise<void>;
4
+ //# sourceMappingURL=migrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":"AAqDA,wBAAgB,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAepE;AAID,wBAAsB,cAAc,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAgD3F;AAED,wBAAsB,UAAU,CAAC,MAAM,UAAQ,EAAE,UAAU,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBjF"}
@@ -0,0 +1,137 @@
1
+ import Database from "better-sqlite3";
2
+ import { existsSync, copyFileSync, readFileSync, writeFileSync, readdirSync, statSync } from "fs";
3
+ import { join } from "path";
4
+ import { homedir } from "os";
5
+ import { logger } from "../utils/logger.js";
6
+ import { displayPath } from "../utils/paths.js";
7
+ import { MANAGED_PROVIDER_KEY } from "../core/constants.js";
8
+ import { isCodexRunning } from "../core/codex.js";
9
+ const CODEX_DIR = join(homedir(), ".codex");
10
+ const DB_PATH = join(CODEX_DIR, "state_5.sqlite");
11
+ const SESSIONS_DIR = join(CODEX_DIR, "sessions");
12
+ // rollout .jsonl ?뚯씪??泥?以?session_meta)?먯꽌 model_provider瑜??⑥튂?쒕떎.
13
+ function patchRolloutFile(filePath, targetProvider, dryRun) {
14
+ try {
15
+ const content = readFileSync(filePath, "utf-8");
16
+ const lines = content.split("\n");
17
+ if (lines.length === 0)
18
+ return false;
19
+ const firstLine = JSON.parse(lines[0]);
20
+ if (firstLine.type !== "session_meta")
21
+ return false;
22
+ const currentProvider = firstLine.payload?.model_provider;
23
+ if (!currentProvider || currentProvider === targetProvider)
24
+ return false;
25
+ if (!dryRun) {
26
+ firstLine.payload.model_provider = targetProvider;
27
+ lines[0] = JSON.stringify(firstLine);
28
+ writeFileSync(filePath, lines.join("\n"), "utf-8");
29
+ }
30
+ return true;
31
+ }
32
+ catch {
33
+ return false;
34
+ }
35
+ }
36
+ // sessions ?섏쐞 紐⑤뱺 .jsonl ?뚯씪???ш? ?먯깋
37
+ function findRolloutFiles(dir) {
38
+ if (!existsSync(dir))
39
+ return [];
40
+ const results = [];
41
+ for (const entry of readdirSync(dir)) {
42
+ const full = join(dir, entry);
43
+ if (statSync(full).isDirectory()) {
44
+ results.push(...findRolloutFiles(full));
45
+ }
46
+ else if (entry.endsWith(".jsonl")) {
47
+ results.push(full);
48
+ }
49
+ }
50
+ return results;
51
+ }
52
+ // Returns true if any threads exist that are not already on targetProvider
53
+ export function hasUnmigratedThreads(targetProvider) {
54
+ if (!existsSync(DB_PATH))
55
+ return false;
56
+ try {
57
+ const db = new Database(DB_PATH, { readonly: true });
58
+ try {
59
+ const row = db
60
+ .prepare(`SELECT COUNT(*) as n FROM threads WHERE model_provider != ?`)
61
+ .get(targetProvider);
62
+ return row.n > 0;
63
+ }
64
+ finally {
65
+ db.close();
66
+ }
67
+ }
68
+ catch {
69
+ return false;
70
+ }
71
+ }
72
+ // Core migration logic ??moves all threads to targetProvider (SQLite + .jsonl)
73
+ // Caller must ensure Codex is not running before calling this.
74
+ export async function migrateThreads(targetProvider, dryRun) {
75
+ if (!existsSync(DB_PATH)) {
76
+ logger.warn(`DB not found: ${displayPath(DB_PATH)}`);
77
+ logger.info("Run Codex once to create the database, then try again.");
78
+ return;
79
+ }
80
+ // ?€?€ 1. SQLite ?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€
81
+ if (!dryRun) {
82
+ copyFileSync(DB_PATH, `${DB_PATH}.backup-${Date.now()}`);
83
+ }
84
+ let db;
85
+ try {
86
+ db = new Database(DB_PATH, { readonly: dryRun });
87
+ }
88
+ catch (err) {
89
+ logger.error(`DB open failed: ${err}`);
90
+ return;
91
+ }
92
+ let dbChanged = 0;
93
+ try {
94
+ const targets = db
95
+ .prepare(`SELECT id, model_provider, title FROM threads WHERE model_provider != ?`)
96
+ .all(targetProvider);
97
+ if (targets.length > 0) {
98
+ if (!dryRun) {
99
+ const res = db
100
+ .prepare(`UPDATE threads SET model_provider = ? WHERE model_provider != ?`)
101
+ .run(targetProvider, targetProvider);
102
+ dbChanged = res.changes;
103
+ }
104
+ else {
105
+ dbChanged = targets.length;
106
+ }
107
+ }
108
+ }
109
+ finally {
110
+ db.close();
111
+ }
112
+ // ?€?€ 2. Rollout .jsonl ?뚯씪 ?⑥튂 ?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€?€
113
+ const rolloutFiles = findRolloutFiles(SESSIONS_DIR);
114
+ let fileChanged = 0;
115
+ for (const f of rolloutFiles) {
116
+ if (patchRolloutFile(f, targetProvider, dryRun))
117
+ fileChanged++;
118
+ }
119
+ logger.success(`Threads migrated ??"${targetProvider}": ${dbChanged} DB rows, ${fileChanged} session files`);
120
+ }
121
+ export async function runMigrate(dryRun = false, showHeader = true) {
122
+ if (showHeader)
123
+ logger.header();
124
+ logger.info(`Migrating Codex threads ??"${MANAGED_PROVIDER_KEY}"...`);
125
+ logger.separator();
126
+ if (await isCodexRunning()) {
127
+ logger.error("Codex is running. Close it completely and try again.");
128
+ return;
129
+ }
130
+ await migrateThreads(MANAGED_PROVIDER_KEY, dryRun);
131
+ logger.separator();
132
+ if (dryRun) {
133
+ logger.info("[DRY RUN] No changes written. Run 'rcodex migrate' to apply.");
134
+ }
135
+ logger.done();
136
+ }
137
+ //# sourceMappingURL=migrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function runSetup(): Promise<void>;
2
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"AAmBA,wBAAsB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAoE9C"}