clawdex-mobile 5.1.3-internal.7 → 5.1.3-internal.9
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/docs/setup-and-operations.md +7 -6
- package/docs/troubleshooting.md +4 -3
- package/package.json +1 -1
- package/scripts/start-bridge-secure.js +59 -28
- package/services/rust-bridge/Cargo.lock +1 -1
- package/services/rust-bridge/Cargo.toml +1 -1
- package/services/rust-bridge/src/main.rs +70 -25
- package/vendor/bridge-binaries/darwin-arm64/codex-rust-bridge +0 -0
- package/vendor/bridge-binaries/darwin-x64/codex-rust-bridge +0 -0
- package/vendor/bridge-binaries/linux-arm64/codex-rust-bridge +0 -0
- package/vendor/bridge-binaries/linux-armv7l/codex-rust-bridge +0 -0
- package/vendor/bridge-binaries/linux-x64/codex-rust-bridge +0 -0
- package/vendor/bridge-binaries/win32-x64/codex-rust-bridge.exe +0 -0
|
@@ -84,10 +84,11 @@ gh codespace ports visibility 8787:public 8788:public
|
|
|
84
84
|
|
|
85
85
|
### Codespaces Bootstrap
|
|
86
86
|
|
|
87
|
-
The repo devcontainer now includes:
|
|
87
|
+
The source repo devcontainer now includes:
|
|
88
88
|
|
|
89
|
-
- `
|
|
90
|
-
- `postStartCommand`: `npm run codespaces:bootstrap`
|
|
89
|
+
- `updateContentCommand`: `npm install --include=dev --prefer-offline --no-audit --fund=false && npm run codespaces:bootstrap -- --prepare-only`
|
|
90
|
+
- `postStartCommand`: fire-and-forget `npm run codespaces:bootstrap`, writing setup output to `.bridge-bootstrap.log`
|
|
91
|
+
- `waitFor`: `updateContentCommand`
|
|
91
92
|
|
|
92
93
|
`npm run codespaces:bootstrap` does the following:
|
|
93
94
|
|
|
@@ -99,9 +100,9 @@ The repo devcontainer now includes:
|
|
|
99
100
|
|
|
100
101
|
Clawdex-created Codespaces request a 45-minute idle timeout. The bridge emits a lightweight active-turn keepalive while a Codex, OpenCode, or Cursor turn is running, so active work has activity even if a long step is otherwise quiet. When no turn is running, the keepalive stops and GitHub can pause the Codespace normally to save cost.
|
|
101
102
|
|
|
102
|
-
That means
|
|
103
|
+
That means prebuild-enabled Codespaces can snapshot the expensive dependency install and bridge compile during `updateContentCommand`. The later `postStartCommand` starts the runtime bridge asynchronously so Codespaces does not block editor/app access while the bridge finishes warming up.
|
|
103
104
|
|
|
104
|
-
The same bootstrap script is included in the published `clawdex-mobile` npm package. That lets the `clawdex-codespace` template stay minimal: it
|
|
105
|
+
The same bootstrap script is included in the published `clawdex-mobile` npm package. That lets the `clawdex-codespace` template stay minimal: it installs `clawdex-mobile@internal` globally in `updateContentCommand` and invokes the packaged bootstrap against the current workspace instead of copying `scripts/*` and `services/rust-bridge/*` into the template repo. Because the published package ships Linux bridge binaries, the template does not need Rust, Cargo, or a local bridge compile.
|
|
105
106
|
|
|
106
107
|
Manual examples:
|
|
107
108
|
|
|
@@ -115,7 +116,7 @@ CLAWDEX_CODESPACES_ENGINES=codex,opencode,cursor npm run codespaces:bootstrap
|
|
|
115
116
|
Minimal template equivalent:
|
|
116
117
|
|
|
117
118
|
```bash
|
|
118
|
-
npm install -g clawdex-mobile@
|
|
119
|
+
npm install -g --no-fund --no-audit clawdex-mobile@internal @openai/codex
|
|
119
120
|
CLAWDEX_WORKSPACE_ROOT="$PWD" node "$(npm root -g)/clawdex-mobile/scripts/codespaces-bootstrap.js" --prepare-only
|
|
120
121
|
CLAWDEX_WORKSPACE_ROOT="$PWD" node "$(npm root -g)/clawdex-mobile/scripts/codespaces-bootstrap.js"
|
|
121
122
|
```
|
package/docs/troubleshooting.md
CHANGED
|
@@ -60,7 +60,7 @@ gh codespace ports visibility 8787:public 8788:public
|
|
|
60
60
|
|
|
61
61
|
## GitHub Codespaces bootstrap did not start the bridge
|
|
62
62
|
|
|
63
|
-
- Check the post-start
|
|
63
|
+
- Check `.bridge-bootstrap.log` for the post-start bootstrap and `.bridge.log` for the bridge process, or rerun the bootstrap manually:
|
|
64
64
|
|
|
65
65
|
```bash
|
|
66
66
|
npm run codespaces:bootstrap -- --prepare-only
|
|
@@ -81,8 +81,9 @@ CLAWDEX_WORKSPACE_ROOT="$PWD" node "$(npm root -g)/clawdex-mobile/scripts/codesp
|
|
|
81
81
|
- Bridge startup logs and runtime state live in the Codespace repo root:
|
|
82
82
|
|
|
83
83
|
```bash
|
|
84
|
+
tail -n 200 .bridge-bootstrap.log
|
|
84
85
|
tail -n 200 .bridge.log
|
|
85
|
-
ls -la .bridge.pid .bridge.log .env.secure
|
|
86
|
+
ls -la .bridge.pid .bridge.log .bridge-bootstrap.log .env.secure
|
|
86
87
|
```
|
|
87
88
|
|
|
88
89
|
- To only rewrite `.env.secure` without starting the bridge:
|
|
@@ -102,7 +103,7 @@ npm run codespaces:bootstrap -- --no-start
|
|
|
102
103
|
|
|
103
104
|
- The bridge can transcribe with `OPENAI_API_KEY`, `BRIDGE_CHATGPT_ACCESS_TOKEN`, a legacy bridge token cache, or the Codex-managed ChatGPT token in `$CODEX_HOME/auth.json`.
|
|
104
105
|
- In GitHub Codespaces, finish the Codex login step from the app first. Codex writes the login to `$HOME/.codex/auth.json`, and `.env.secure` sets `CODEX_HOME` to that persistent location.
|
|
105
|
-
-
|
|
106
|
+
- Current app builds automatically restart the Codespace Codex app-server after the Codex login step so it reloads the Codex auth home. On older builds, restart the bridge once after logging in:
|
|
106
107
|
|
|
107
108
|
```bash
|
|
108
109
|
npm run secure:bridge
|
package/package.json
CHANGED
|
@@ -16,6 +16,7 @@ const {
|
|
|
16
16
|
} = require("./bridge-binary");
|
|
17
17
|
|
|
18
18
|
const DEFAULT_HEALTH_TIMEOUT_MS = 15000;
|
|
19
|
+
const CODESPACES_HEALTH_TIMEOUT_MS = 60000;
|
|
19
20
|
const DEV_HEALTH_TIMEOUT_MS = 60000;
|
|
20
21
|
let qrcodeTerminal = null;
|
|
21
22
|
let qrcodeTerminalLoaded = false;
|
|
@@ -346,6 +347,13 @@ function formatCodespacesVisibilityCommand(env, ports) {
|
|
|
346
347
|
return ["gh", "codespace", "ports", "visibility", ...visibilityArgs, ...selectionArgs].join(" ");
|
|
347
348
|
}
|
|
348
349
|
|
|
350
|
+
function sleepSync(ms) {
|
|
351
|
+
if (!Number.isFinite(ms) || ms <= 0) {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
355
|
+
}
|
|
356
|
+
|
|
349
357
|
function updateCodespacesBrowseUrls(env, ports) {
|
|
350
358
|
if (!commandExists("gh")) {
|
|
351
359
|
return;
|
|
@@ -416,38 +424,57 @@ function ensureCodespacesPortsArePublic(env, ports) {
|
|
|
416
424
|
return notes;
|
|
417
425
|
}
|
|
418
426
|
|
|
419
|
-
const
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
427
|
+
const publishedPorts = [];
|
|
428
|
+
const failedPorts = [];
|
|
429
|
+
const selectionArgs = codespaceSelectionArgs(env);
|
|
430
|
+
|
|
431
|
+
for (const port of uniquePorts) {
|
|
432
|
+
let lastDetail = "";
|
|
433
|
+
for (let attempt = 1; attempt <= 8; attempt += 1) {
|
|
434
|
+
const result = spawnSync(
|
|
435
|
+
"gh",
|
|
436
|
+
["codespace", "ports", "visibility", `${port}:public`, ...selectionArgs],
|
|
437
|
+
{
|
|
438
|
+
encoding: "utf8",
|
|
439
|
+
env: ghAuthEnv(env),
|
|
440
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
441
|
+
}
|
|
442
|
+
);
|
|
443
|
+
|
|
444
|
+
if ((result.status ?? 1) === 0) {
|
|
445
|
+
publishedPorts.push(port);
|
|
446
|
+
lastDetail = "";
|
|
447
|
+
break;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
lastDetail = (result.stderr || result.stdout || "").trim();
|
|
451
|
+
if (attempt < 8) {
|
|
452
|
+
sleepSync(1_500);
|
|
453
|
+
}
|
|
432
454
|
}
|
|
433
|
-
);
|
|
434
455
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
456
|
+
if (lastDetail) {
|
|
457
|
+
failedPorts.push({ port, detail: lastDetail });
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
if (publishedPorts.length > 0) {
|
|
462
|
+
updateCodespacesBrowseUrls(env, publishedPorts);
|
|
438
463
|
notes.push(
|
|
439
|
-
`
|
|
464
|
+
`Codespaces forwarded ports are set to public for bridge access: ${publishedPorts.join(", ")}.`
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
for (const failure of failedPorts) {
|
|
469
|
+
const suffix = failure.detail ? ` (${failure.detail.split(/\r?\n/, 1)[0]})` : "";
|
|
470
|
+
notes.push(
|
|
471
|
+
`Could not set Codespaces forwarded port ${failure.port} public automatically${suffix}. Run '${formatCodespacesVisibilityCommand(
|
|
440
472
|
env,
|
|
441
|
-
|
|
473
|
+
[failure.port]
|
|
442
474
|
)}' or update the Ports panel manually.`
|
|
443
475
|
);
|
|
444
|
-
return notes;
|
|
445
476
|
}
|
|
446
477
|
|
|
447
|
-
updateCodespacesBrowseUrls(env, uniquePorts);
|
|
448
|
-
notes.push(
|
|
449
|
-
`Codespaces forwarded ports are set to public for bridge access: ${uniquePorts.join(", ")}.`
|
|
450
|
-
);
|
|
451
478
|
return notes;
|
|
452
479
|
}
|
|
453
480
|
|
|
@@ -752,6 +779,10 @@ function buildBridgeFromSource(packageDir, env, profile) {
|
|
|
752
779
|
}
|
|
753
780
|
|
|
754
781
|
function resolveLaunch(workspaceDir, packageDir, env, { devMode, forceSourceBuild }) {
|
|
782
|
+
const defaultHealthTimeoutMs = isCodespacesMode(env)
|
|
783
|
+
? CODESPACES_HEALTH_TIMEOUT_MS
|
|
784
|
+
: DEFAULT_HEALTH_TIMEOUT_MS;
|
|
785
|
+
|
|
755
786
|
if (devMode) {
|
|
756
787
|
if (!commandExists("cargo")) {
|
|
757
788
|
console.error("error: missing Rust/Cargo toolchain for dev bridge mode.");
|
|
@@ -779,7 +810,7 @@ function resolveLaunch(workspaceDir, packageDir, env, { devMode, forceSourceBuil
|
|
|
779
810
|
args: [],
|
|
780
811
|
cwd: workspaceDir,
|
|
781
812
|
env,
|
|
782
|
-
healthTimeoutMs:
|
|
813
|
+
healthTimeoutMs: defaultHealthTimeoutMs,
|
|
783
814
|
};
|
|
784
815
|
}
|
|
785
816
|
|
|
@@ -792,7 +823,7 @@ function resolveLaunch(workspaceDir, packageDir, env, { devMode, forceSourceBuil
|
|
|
792
823
|
args: [],
|
|
793
824
|
cwd: workspaceDir,
|
|
794
825
|
env,
|
|
795
|
-
healthTimeoutMs:
|
|
826
|
+
healthTimeoutMs: defaultHealthTimeoutMs,
|
|
796
827
|
};
|
|
797
828
|
}
|
|
798
829
|
|
|
@@ -804,7 +835,7 @@ function resolveLaunch(workspaceDir, packageDir, env, { devMode, forceSourceBuil
|
|
|
804
835
|
args: [],
|
|
805
836
|
cwd: workspaceDir,
|
|
806
837
|
env,
|
|
807
|
-
healthTimeoutMs:
|
|
838
|
+
healthTimeoutMs: defaultHealthTimeoutMs,
|
|
808
839
|
};
|
|
809
840
|
}
|
|
810
841
|
|
|
@@ -833,7 +864,7 @@ function resolveLaunch(workspaceDir, packageDir, env, { devMode, forceSourceBuil
|
|
|
833
864
|
args: [],
|
|
834
865
|
cwd: workspaceDir,
|
|
835
866
|
env,
|
|
836
|
-
healthTimeoutMs:
|
|
867
|
+
healthTimeoutMs: defaultHealthTimeoutMs,
|
|
837
868
|
};
|
|
838
869
|
}
|
|
839
870
|
|
|
@@ -1266,7 +1266,7 @@ impl BrowserPreviewService {
|
|
|
1266
1266
|
#[derive(Clone)]
|
|
1267
1267
|
struct RuntimeBackend {
|
|
1268
1268
|
preferred_engine: BridgeRuntimeEngine,
|
|
1269
|
-
codex: Option<Arc<AppServerBridge
|
|
1269
|
+
codex: Arc<StdRwLock<Option<Arc<AppServerBridge>>>>,
|
|
1270
1270
|
opencode: Option<Arc<OpencodeBackend>>,
|
|
1271
1271
|
cursor: Arc<StdRwLock<Option<Arc<AppServerBridge>>>>,
|
|
1272
1272
|
}
|
|
@@ -1281,7 +1281,7 @@ impl RuntimeBackend {
|
|
|
1281
1281
|
let cursor_enabled = config
|
|
1282
1282
|
.enabled_engines
|
|
1283
1283
|
.contains(&BridgeRuntimeEngine::Cursor);
|
|
1284
|
-
let
|
|
1284
|
+
let codex = Arc::new(StdRwLock::new(None));
|
|
1285
1285
|
let mut opencode = None;
|
|
1286
1286
|
let cursor = Arc::new(StdRwLock::new(None));
|
|
1287
1287
|
|
|
@@ -1291,7 +1291,7 @@ impl RuntimeBackend {
|
|
|
1291
1291
|
let app_server =
|
|
1292
1292
|
AppServerBridge::start_codex(&config.cli_bin, hub.clone()).await?;
|
|
1293
1293
|
spawn_rollout_live_sync(hub.clone());
|
|
1294
|
-
codex
|
|
1294
|
+
Self::store_codex_backend(&codex, app_server);
|
|
1295
1295
|
}
|
|
1296
1296
|
|
|
1297
1297
|
if opencode_enabled {
|
|
@@ -1327,7 +1327,7 @@ impl RuntimeBackend {
|
|
|
1327
1327
|
{
|
|
1328
1328
|
Ok(app_server) => {
|
|
1329
1329
|
spawn_rollout_live_sync(hub.clone());
|
|
1330
|
-
codex
|
|
1330
|
+
Self::store_codex_backend(&codex, app_server);
|
|
1331
1331
|
}
|
|
1332
1332
|
Err(error) => eprintln!(
|
|
1333
1333
|
"codex backend unavailable; continuing with selected harnesses only: {error}"
|
|
@@ -1358,7 +1358,7 @@ impl RuntimeBackend {
|
|
|
1358
1358
|
match AppServerBridge::start_codex(&config.cli_bin, hub.clone()).await {
|
|
1359
1359
|
Ok(app_server) => {
|
|
1360
1360
|
spawn_rollout_live_sync(hub.clone());
|
|
1361
|
-
codex
|
|
1361
|
+
Self::store_codex_backend(&codex, app_server);
|
|
1362
1362
|
}
|
|
1363
1363
|
Err(error) => eprintln!(
|
|
1364
1364
|
"codex backend unavailable; continuing with selected harnesses only: {error}"
|
|
@@ -1389,6 +1389,19 @@ impl RuntimeBackend {
|
|
|
1389
1389
|
self.cursor.read().ok().and_then(|guard| guard.clone())
|
|
1390
1390
|
}
|
|
1391
1391
|
|
|
1392
|
+
fn codex_backend(&self) -> Option<Arc<AppServerBridge>> {
|
|
1393
|
+
self.codex.read().ok().and_then(|guard| guard.clone())
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
fn store_codex_backend(
|
|
1397
|
+
codex_slot: &Arc<StdRwLock<Option<Arc<AppServerBridge>>>>,
|
|
1398
|
+
bridge: Arc<AppServerBridge>,
|
|
1399
|
+
) {
|
|
1400
|
+
if let Ok(mut guard) = codex_slot.write() {
|
|
1401
|
+
*guard = Some(bridge);
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1392
1405
|
fn store_cursor_backend(
|
|
1393
1406
|
cursor_slot: &Arc<StdRwLock<Option<Arc<AppServerBridge>>>>,
|
|
1394
1407
|
bridge: Arc<AppServerBridge>,
|
|
@@ -1398,8 +1411,31 @@ impl RuntimeBackend {
|
|
|
1398
1411
|
}
|
|
1399
1412
|
}
|
|
1400
1413
|
|
|
1414
|
+
async fn restart_codex_app_server(
|
|
1415
|
+
&self,
|
|
1416
|
+
config: &Arc<BridgeConfig>,
|
|
1417
|
+
hub: Arc<ClientHub>,
|
|
1418
|
+
) -> Result<(), String> {
|
|
1419
|
+
if !config.enabled_engines.contains(&BridgeRuntimeEngine::Codex) {
|
|
1420
|
+
return Err("codex backend is not enabled".to_string());
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
let next_backend = AppServerBridge::start_codex(&config.cli_bin, hub).await?;
|
|
1424
|
+
let previous_backend = self
|
|
1425
|
+
.codex
|
|
1426
|
+
.write()
|
|
1427
|
+
.map(|mut guard| guard.replace(next_backend))
|
|
1428
|
+
.map_err(|_| "codex backend lock is unavailable".to_string())?;
|
|
1429
|
+
|
|
1430
|
+
if let Some(previous_backend) = previous_backend {
|
|
1431
|
+
previous_backend.request_shutdown().await;
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
Ok(())
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1401
1437
|
async fn shutdown(&self) {
|
|
1402
|
-
if let Some(codex) =
|
|
1438
|
+
if let Some(codex) = self.codex_backend() {
|
|
1403
1439
|
codex.request_shutdown().await;
|
|
1404
1440
|
}
|
|
1405
1441
|
if let Some(opencode) = &self.opencode {
|
|
@@ -1416,7 +1452,7 @@ impl RuntimeBackend {
|
|
|
1416
1452
|
|
|
1417
1453
|
fn available_engines(&self) -> Vec<BridgeRuntimeEngine> {
|
|
1418
1454
|
let mut engines = Vec::new();
|
|
1419
|
-
if self.
|
|
1455
|
+
if self.codex_backend().is_some() {
|
|
1420
1456
|
engines.push(BridgeRuntimeEngine::Codex);
|
|
1421
1457
|
}
|
|
1422
1458
|
if self.opencode.is_some() {
|
|
@@ -1469,8 +1505,7 @@ impl RuntimeBackend {
|
|
|
1469
1505
|
) -> Result<RuntimeBackendRef<'_>, String> {
|
|
1470
1506
|
match engine {
|
|
1471
1507
|
BridgeRuntimeEngine::Codex => self
|
|
1472
|
-
.
|
|
1473
|
-
.as_ref()
|
|
1508
|
+
.codex_backend()
|
|
1474
1509
|
.map(RuntimeBackendRef::Codex)
|
|
1475
1510
|
.ok_or_else(|| "codex backend is unavailable".to_string()),
|
|
1476
1511
|
BridgeRuntimeEngine::Opencode => self
|
|
@@ -1576,7 +1611,7 @@ impl RuntimeBackend {
|
|
|
1576
1611
|
let bridge_cursor = extract_thread_list_cursor(params.as_ref())
|
|
1577
1612
|
.and_then(|cursor| decode_bridge_thread_list_cursor(&cursor));
|
|
1578
1613
|
|
|
1579
|
-
if let Some(codex) =
|
|
1614
|
+
if let Some(codex) = self.codex_backend() {
|
|
1580
1615
|
if let Some(cursor_map) = bridge_cursor.as_ref() {
|
|
1581
1616
|
if let Some(cursor) = cursor_map.get(&BridgeRuntimeEngine::Codex) {
|
|
1582
1617
|
results.push((
|
|
@@ -1660,7 +1695,7 @@ impl RuntimeBackend {
|
|
|
1660
1695
|
async fn aggregate_loaded_thread_ids(&self) -> Result<Value, String> {
|
|
1661
1696
|
let mut results = Vec::new();
|
|
1662
1697
|
|
|
1663
|
-
if let Some(codex) =
|
|
1698
|
+
if let Some(codex) = self.codex_backend() {
|
|
1664
1699
|
results.push((
|
|
1665
1700
|
BridgeRuntimeEngine::Codex,
|
|
1666
1701
|
codex.request_internal("thread/loaded/list", None).await?,
|
|
@@ -1688,7 +1723,7 @@ impl RuntimeBackend {
|
|
|
1688
1723
|
|
|
1689
1724
|
async fn list_pending_approvals(&self) -> Vec<PendingApproval> {
|
|
1690
1725
|
let mut approvals = Vec::new();
|
|
1691
|
-
if let Some(codex) =
|
|
1726
|
+
if let Some(codex) = self.codex_backend() {
|
|
1692
1727
|
approvals.extend(codex.list_pending_approvals().await);
|
|
1693
1728
|
}
|
|
1694
1729
|
if let Some(opencode) = &self.opencode {
|
|
@@ -1703,7 +1738,7 @@ impl RuntimeBackend {
|
|
|
1703
1738
|
|
|
1704
1739
|
async fn list_pending_user_inputs(&self) -> Vec<PendingUserInputRequest> {
|
|
1705
1740
|
let mut requests = Vec::new();
|
|
1706
|
-
if let Some(codex) =
|
|
1741
|
+
if let Some(codex) = self.codex_backend() {
|
|
1707
1742
|
requests.extend(codex.list_pending_user_inputs().await);
|
|
1708
1743
|
}
|
|
1709
1744
|
if let Some(opencode) = &self.opencode {
|
|
@@ -1721,7 +1756,7 @@ impl RuntimeBackend {
|
|
|
1721
1756
|
approval_id: &str,
|
|
1722
1757
|
decision: &Value,
|
|
1723
1758
|
) -> Result<Option<PendingApproval>, String> {
|
|
1724
|
-
if let Some(codex) =
|
|
1759
|
+
if let Some(codex) = self.codex_backend() {
|
|
1725
1760
|
if let Some(approval) = codex.resolve_approval(approval_id, decision).await? {
|
|
1726
1761
|
return Ok(Some(approval));
|
|
1727
1762
|
}
|
|
@@ -1747,7 +1782,7 @@ impl RuntimeBackend {
|
|
|
1747
1782
|
request_id: &str,
|
|
1748
1783
|
answers: &HashMap<String, UserInputAnswerPayload>,
|
|
1749
1784
|
) -> Result<Option<PendingUserInputRequest>, String> {
|
|
1750
|
-
if let Some(codex) =
|
|
1785
|
+
if let Some(codex) = self.codex_backend() {
|
|
1751
1786
|
if let Some(request) = codex.resolve_user_input(request_id, answers).await? {
|
|
1752
1787
|
return Ok(Some(request));
|
|
1753
1788
|
}
|
|
@@ -1792,7 +1827,7 @@ impl RuntimeBackend {
|
|
|
1792
1827
|
}
|
|
1793
1828
|
}),
|
|
1794
1829
|
};
|
|
1795
|
-
if let Some(codex) =
|
|
1830
|
+
if let Some(codex) = self.codex_backend() {
|
|
1796
1831
|
codex.hub.send_json(client_id, payload).await;
|
|
1797
1832
|
} else if let Some(opencode) = &self.opencode {
|
|
1798
1833
|
opencode.hub.send_json(client_id, payload).await;
|
|
@@ -1892,7 +1927,7 @@ async fn terminate_process_tree_windows(pid: u32, label: &str) {
|
|
|
1892
1927
|
}
|
|
1893
1928
|
|
|
1894
1929
|
enum RuntimeBackendRef<'a> {
|
|
1895
|
-
Codex(
|
|
1930
|
+
Codex(Arc<AppServerBridge>),
|
|
1896
1931
|
Opencode(&'a Arc<OpencodeBackend>),
|
|
1897
1932
|
Cursor(Arc<AppServerBridge>),
|
|
1898
1933
|
}
|
|
@@ -7468,6 +7503,17 @@ async fn handle_bridge_method(
|
|
|
7468
7503
|
.map_err(|error| BridgeError::invalid_params(&error.to_string()))?;
|
|
7469
7504
|
forward_codex_auth_callback(state, &request.callback_url).await
|
|
7470
7505
|
}
|
|
7506
|
+
"bridge/codex/app-server/restart" => {
|
|
7507
|
+
state
|
|
7508
|
+
.backend
|
|
7509
|
+
.restart_codex_app_server(&state.config, state.hub.clone())
|
|
7510
|
+
.await
|
|
7511
|
+
.map_err(|error| BridgeError::server(&error))?;
|
|
7512
|
+
Ok(json!({
|
|
7513
|
+
"ok": true,
|
|
7514
|
+
"message": "Codex app-server restarted."
|
|
7515
|
+
}))
|
|
7516
|
+
}
|
|
7471
7517
|
"bridge/update/start" => {
|
|
7472
7518
|
let request: BridgeUpdateStartRequest =
|
|
7473
7519
|
serde_json::from_value(params.unwrap_or_else(|| json!({})))
|
|
@@ -8156,7 +8202,7 @@ fn thread_list_stream_request_params(include_sub_agents: bool, limit: usize) ->
|
|
|
8156
8202
|
json!({
|
|
8157
8203
|
"cursor": Value::Null,
|
|
8158
8204
|
"limit": limit,
|
|
8159
|
-
"sortKey":
|
|
8205
|
+
"sortKey": "updated_at",
|
|
8160
8206
|
"modelProviders": Value::Null,
|
|
8161
8207
|
"sourceKinds": source_kinds,
|
|
8162
8208
|
"archived": false,
|
|
@@ -8212,7 +8258,7 @@ async fn list_workspace_roots(
|
|
|
8212
8258
|
Some(json!({
|
|
8213
8259
|
"cursor": Value::Null,
|
|
8214
8260
|
"limit": limit,
|
|
8215
|
-
"sortKey":
|
|
8261
|
+
"sortKey": "updated_at",
|
|
8216
8262
|
"modelProviders": Value::Null,
|
|
8217
8263
|
"sourceKinds": ["cli", "vscode", "exec", "appServer", "unknown"],
|
|
8218
8264
|
"archived": false,
|
|
@@ -13586,16 +13632,15 @@ mod tests {
|
|
|
13586
13632
|
let _ = child.wait().await;
|
|
13587
13633
|
}
|
|
13588
13634
|
|
|
13589
|
-
fn test_codex_backend(backend: &Arc<RuntimeBackend>) ->
|
|
13635
|
+
fn test_codex_backend(backend: &Arc<RuntimeBackend>) -> Arc<AppServerBridge> {
|
|
13590
13636
|
backend
|
|
13591
|
-
.
|
|
13592
|
-
.as_ref()
|
|
13637
|
+
.codex_backend()
|
|
13593
13638
|
.expect("expected codex backend in test")
|
|
13594
13639
|
}
|
|
13595
13640
|
|
|
13596
13641
|
async fn shutdown_test_backend(backend: &Arc<RuntimeBackend>) {
|
|
13597
|
-
if let Some(codex) =
|
|
13598
|
-
shutdown_test_bridge(codex).await;
|
|
13642
|
+
if let Some(codex) = backend.codex_backend() {
|
|
13643
|
+
shutdown_test_bridge(&codex).await;
|
|
13599
13644
|
}
|
|
13600
13645
|
if let Some(opencode) = &backend.opencode {
|
|
13601
13646
|
shutdown_test_opencode_backend(opencode).await;
|
|
@@ -13610,7 +13655,7 @@ mod tests {
|
|
|
13610
13655
|
preferred_engine: BridgeRuntimeEngine,
|
|
13611
13656
|
include_opencode: bool,
|
|
13612
13657
|
) -> Arc<RuntimeBackend> {
|
|
13613
|
-
let codex = Some(build_test_bridge(hub.clone()).await);
|
|
13658
|
+
let codex = Arc::new(StdRwLock::new(Some(build_test_bridge(hub.clone()).await)));
|
|
13614
13659
|
let opencode = if include_opencode {
|
|
13615
13660
|
Some(build_test_opencode_backend(hub).await)
|
|
13616
13661
|
} else {
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|