@ccpocket/bridge 1.57.1 → 1.58.0
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 +37 -0
- package/dist/cli.js +20 -0
- package/dist/cli.js.map +1 -1
- package/dist/codex-app-server-config.d.ts +10 -0
- package/dist/codex-app-server-config.js +45 -0
- package/dist/codex-app-server-config.js.map +1 -0
- package/dist/codex-process.d.ts +4 -11
- package/dist/codex-process.js +87 -46
- package/dist/codex-process.js.map +1 -1
- package/dist/codex-transport.d.ts +25 -0
- package/dist/codex-transport.js +252 -0
- package/dist/codex-transport.js.map +1 -0
- package/dist/parser.d.ts +5 -0
- package/dist/parser.js.map +1 -1
- package/dist/session.d.ts +14 -0
- package/dist/session.js +176 -37
- package/dist/session.js.map +1 -1
- package/dist/sessions-index.d.ts +1 -0
- package/dist/sessions-index.js +3 -0
- package/dist/sessions-index.js.map +1 -1
- package/dist/setup-launchd.d.ts +6 -0
- package/dist/setup-launchd.js +28 -0
- package/dist/setup-launchd.js.map +1 -1
- package/dist/setup-systemd.d.ts +6 -0
- package/dist/setup-systemd.js +24 -0
- package/dist/setup-systemd.js.map +1 -1
- package/dist/websocket.js +2 -0
- package/dist/websocket.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -36,6 +36,8 @@ ccpocket-bridge
|
|
|
36
36
|
| `BRIDGE_API_KEY` | (none) | API key authentication (enabled when set) |
|
|
37
37
|
| `BRIDGE_ALLOWED_DIRS` | `$HOME` | Comma-separated list of project directories the Bridge may access |
|
|
38
38
|
| `BRIDGE_PUBLIC_WS_URL` | (none) | Public `ws://` / `wss://` URL used for startup deep link and QR code |
|
|
39
|
+
| `BRIDGE_CODEX_APP_SERVER_MODE` | `private` | Experimental Codex app-server mode: `private`, `managed`, or `external` |
|
|
40
|
+
| `BRIDGE_CODEX_SHARED_APP_SERVER_URL` | `ws://127.0.0.1:8767` in `managed` mode | Experimental shared Codex app-server URL for Codex CLI co-presence |
|
|
39
41
|
| `BRIDGE_DEMO_MODE` | (none) | Demo mode: hide Tailscale IPs and API key from QR code / logs |
|
|
40
42
|
| `BRIDGE_RECORDING` | (none) | Enable session recording for debugging (enabled when set) |
|
|
41
43
|
| `BRIDGE_DISABLE_MDNS` | (none) | Disable mDNS auto-discovery advertisement (enabled when set) |
|
|
@@ -79,6 +81,41 @@ is reachable through a reverse proxy, tunnel, or public domain.
|
|
|
79
81
|
Without it, the printed QR code is LAN-oriented by default and typically encodes
|
|
80
82
|
something like `ws://192.168.x.x:8765`.
|
|
81
83
|
|
|
84
|
+
## Experimental: Join a CC Pocket Codex Session from Codex CLI
|
|
85
|
+
|
|
86
|
+
By default, each Codex session uses a private app-server. To let Codex CLI join
|
|
87
|
+
the same live thread that CC Pocket started, run the Bridge with shared
|
|
88
|
+
app-server mode:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
BRIDGE_CODEX_APP_SERVER_MODE=managed \
|
|
92
|
+
BRIDGE_CODEX_SHARED_APP_SERVER_URL=ws://127.0.0.1:8767 \
|
|
93
|
+
npx @ccpocket/bridge@latest
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Then start or resume a Codex session from CC Pocket. When the session is ready,
|
|
97
|
+
the session screen can copy a session-specific command like:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
codex resume <thread-id> --remote ws://127.0.0.1:8767
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Run that command in a terminal on the same machine as the Bridge. The
|
|
104
|
+
`127.0.0.1` address is for the Mac/Linux machine running the Bridge and Codex
|
|
105
|
+
CLI, not for the phone.
|
|
106
|
+
|
|
107
|
+
Modes:
|
|
108
|
+
|
|
109
|
+
- `private`: default behavior. No Codex CLI co-presence.
|
|
110
|
+
- `managed`: Bridge starts one local WebSocket Codex app-server and shares it
|
|
111
|
+
with Codex CLI.
|
|
112
|
+
- `external`: Bridge connects to an already-running app-server. In this mode,
|
|
113
|
+
`BRIDGE_CODEX_SHARED_APP_SERVER_URL` is required.
|
|
114
|
+
|
|
115
|
+
This is experimental and currently targets Codex CLI co-presence only. Codex App
|
|
116
|
+
compatibility is not guaranteed and may use a different integration model in the
|
|
117
|
+
future.
|
|
118
|
+
|
|
82
119
|
## Requirements
|
|
83
120
|
|
|
84
121
|
- Node.js v18+
|
package/dist/cli.js
CHANGED
|
@@ -41,6 +41,10 @@ else if (subcommand === "setup") {
|
|
|
41
41
|
host: parseFlag("host"),
|
|
42
42
|
apiKey: parseFlag("api-key"),
|
|
43
43
|
publicWsUrl: parseFlag("public-ws-url"),
|
|
44
|
+
codexAppServerMode: parseFlag("codex-app-server-mode"),
|
|
45
|
+
codexSharedAppServerUrl: parseFlag("codex-shared-app-server-url"),
|
|
46
|
+
codexAppServerPort: parseFlag("codex-app-server-port"),
|
|
47
|
+
codexAppServerUrl: parseFlag("codex-app-server-url"),
|
|
44
48
|
};
|
|
45
49
|
if (platform() === "darwin") {
|
|
46
50
|
import("./setup-launchd.js")
|
|
@@ -73,6 +77,10 @@ else {
|
|
|
73
77
|
const host = parseFlag("host");
|
|
74
78
|
const apiKey = parseFlag("api-key");
|
|
75
79
|
const publicWsUrl = parseFlag("public-ws-url");
|
|
80
|
+
const codexAppServerMode = parseFlag("codex-app-server-mode");
|
|
81
|
+
const codexSharedAppServerUrl = parseFlag("codex-shared-app-server-url");
|
|
82
|
+
const codexAppServerPort = parseFlag("codex-app-server-port");
|
|
83
|
+
const codexAppServerUrl = parseFlag("codex-app-server-url");
|
|
76
84
|
if (port)
|
|
77
85
|
process.env.BRIDGE_PORT = port;
|
|
78
86
|
if (host)
|
|
@@ -81,6 +89,18 @@ else {
|
|
|
81
89
|
process.env.BRIDGE_API_KEY = apiKey;
|
|
82
90
|
if (publicWsUrl)
|
|
83
91
|
process.env.BRIDGE_PUBLIC_WS_URL = publicWsUrl;
|
|
92
|
+
if (codexAppServerMode) {
|
|
93
|
+
process.env.BRIDGE_CODEX_APP_SERVER_MODE = codexAppServerMode;
|
|
94
|
+
}
|
|
95
|
+
if (codexAppServerPort) {
|
|
96
|
+
process.env.BRIDGE_CODEX_APP_SERVER_PORT = codexAppServerPort;
|
|
97
|
+
}
|
|
98
|
+
if (codexSharedAppServerUrl) {
|
|
99
|
+
process.env.BRIDGE_CODEX_SHARED_APP_SERVER_URL = codexSharedAppServerUrl;
|
|
100
|
+
}
|
|
101
|
+
else if (codexAppServerUrl) {
|
|
102
|
+
process.env.BRIDGE_CODEX_APP_SERVER_URL = codexAppServerUrl;
|
|
103
|
+
}
|
|
84
104
|
if (hasFlag("no-mdns"))
|
|
85
105
|
process.env.BRIDGE_DISABLE_MDNS = "1";
|
|
86
106
|
startServer();
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,wDAAwD;AACxD,UAAU,EAAE,CAAC;AAEb,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,uBAAuB;AACvB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AAExD,SAAS,SAAS,CAAC,IAAY;IAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IACtC,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC3D,OAAO,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;AACvB,CAAC;AAED,SAAS,OAAO,CAAC,IAAY;IAC3B,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;AACpC,CAAC;AAED,IAAI,UAAU,KAAK,QAAQ,EAAE,CAAC;IAC5B,8CAA8C;IAC9C,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACnC,MAAM,CAAC,aAAa,CAAC;SAClB,IAAI,CAAC,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,EAAE,CACnC,SAAS,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;QAC1B,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;QACtC,CAAC;aAAM,CAAC;YACN,WAAW,CAAC,MAAM,CAAC,CAAC;QACtB,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC,CACH;SACA,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACb,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACP,CAAC;KAAM,IAAI,UAAU,KAAK,OAAO,EAAE,CAAC;IAClC,+CAA+C;IAC/C,MAAM,IAAI,GAAG;QACX,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC;QACvB,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC;QACvB,MAAM,EAAE,SAAS,CAAC,SAAS,CAAC;QAC5B,WAAW,EAAE,SAAS,CAAC,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type CodexAppServerMode = "private" | "managed" | "external";
|
|
2
|
+
export declare function defaultCodexAppServerPort(bridgePort?: string): string;
|
|
3
|
+
export declare function defaultCodexSharedAppServerUrl(bridgePort?: string): string;
|
|
4
|
+
export declare function readCodexSharedAppServerUrl(env?: NodeJS.ProcessEnv): string | undefined;
|
|
5
|
+
export declare function readCodexAppServerMode(env?: NodeJS.ProcessEnv): CodexAppServerMode;
|
|
6
|
+
export declare function resolveCodexSharedAppServerUrl(mode: CodexAppServerMode, env?: NodeJS.ProcessEnv): string | undefined;
|
|
7
|
+
export declare function codexCliJoinTarget(threadId: string, env?: NodeJS.ProcessEnv): {
|
|
8
|
+
url: string;
|
|
9
|
+
command: string;
|
|
10
|
+
} | undefined;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const DEFAULT_CODEX_APP_SERVER_PORT = "8767";
|
|
2
|
+
const FALLBACK_CODEX_APP_SERVER_PORT = "8768";
|
|
3
|
+
export function defaultCodexAppServerPort(bridgePort) {
|
|
4
|
+
return bridgePort?.trim() === DEFAULT_CODEX_APP_SERVER_PORT
|
|
5
|
+
? FALLBACK_CODEX_APP_SERVER_PORT
|
|
6
|
+
: DEFAULT_CODEX_APP_SERVER_PORT;
|
|
7
|
+
}
|
|
8
|
+
export function defaultCodexSharedAppServerUrl(bridgePort) {
|
|
9
|
+
return `ws://127.0.0.1:${defaultCodexAppServerPort(bridgePort)}`;
|
|
10
|
+
}
|
|
11
|
+
export function readCodexSharedAppServerUrl(env = process.env) {
|
|
12
|
+
return (env.BRIDGE_CODEX_SHARED_APP_SERVER_URL?.trim() ||
|
|
13
|
+
env.BRIDGE_CODEX_APP_SERVER_URL?.trim() ||
|
|
14
|
+
undefined);
|
|
15
|
+
}
|
|
16
|
+
export function readCodexAppServerMode(env = process.env) {
|
|
17
|
+
const raw = env.BRIDGE_CODEX_APP_SERVER_MODE;
|
|
18
|
+
if (raw === "managed" || raw === "external")
|
|
19
|
+
return raw;
|
|
20
|
+
return "private";
|
|
21
|
+
}
|
|
22
|
+
export function resolveCodexSharedAppServerUrl(mode, env = process.env) {
|
|
23
|
+
const explicit = readCodexSharedAppServerUrl(env);
|
|
24
|
+
if (explicit)
|
|
25
|
+
return explicit;
|
|
26
|
+
if (mode !== "managed")
|
|
27
|
+
return undefined;
|
|
28
|
+
const legacyPort = env.BRIDGE_CODEX_APP_SERVER_PORT?.trim();
|
|
29
|
+
if (legacyPort)
|
|
30
|
+
return `ws://127.0.0.1:${legacyPort}`;
|
|
31
|
+
return defaultCodexSharedAppServerUrl(env.BRIDGE_PORT);
|
|
32
|
+
}
|
|
33
|
+
export function codexCliJoinTarget(threadId, env = process.env) {
|
|
34
|
+
const mode = readCodexAppServerMode(env);
|
|
35
|
+
if (mode === "private")
|
|
36
|
+
return undefined;
|
|
37
|
+
const url = resolveCodexSharedAppServerUrl(mode, env);
|
|
38
|
+
if (!url)
|
|
39
|
+
return undefined;
|
|
40
|
+
return {
|
|
41
|
+
url,
|
|
42
|
+
command: `codex resume ${threadId} --remote ${url}`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=codex-app-server-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-app-server-config.js","sourceRoot":"","sources":["../src/codex-app-server-config.ts"],"names":[],"mappings":"AAAA,MAAM,6BAA6B,GAAG,MAAM,CAAC;AAC7C,MAAM,8BAA8B,GAAG,MAAM,CAAC;AAI9C,MAAM,UAAU,yBAAyB,CAAC,UAAmB;IAC3D,OAAO,UAAU,EAAE,IAAI,EAAE,KAAK,6BAA6B;QACzD,CAAC,CAAC,8BAA8B;QAChC,CAAC,CAAC,6BAA6B,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,8BAA8B,CAAC,UAAmB;IAChE,OAAO,kBAAkB,yBAAyB,CAAC,UAAU,CAAC,EAAE,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,2BAA2B,CACzC,MAAyB,OAAO,CAAC,GAAG;IAEpC,OAAO,CACL,GAAG,CAAC,kCAAkC,EAAE,IAAI,EAAE;QAC9C,GAAG,CAAC,2BAA2B,EAAE,IAAI,EAAE;QACvC,SAAS,CACV,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,MAAyB,OAAO,CAAC,GAAG;IAEpC,MAAM,GAAG,GAAG,GAAG,CAAC,4BAA4B,CAAC;IAC7C,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,UAAU;QAAE,OAAO,GAAG,CAAC;IACxD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,8BAA8B,CAC5C,IAAwB,EACxB,MAAyB,OAAO,CAAC,GAAG;IAEpC,MAAM,QAAQ,GAAG,2BAA2B,CAAC,GAAG,CAAC,CAAC;IAClD,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAEzC,MAAM,UAAU,GAAG,GAAG,CAAC,4BAA4B,EAAE,IAAI,EAAE,CAAC;IAC5D,IAAI,UAAU;QAAE,OAAO,kBAAkB,UAAU,EAAE,CAAC;IAEtD,OAAO,8BAA8B,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,QAAgB,EAChB,MAAyB,OAAO,CAAC,GAAG;IAEpC,MAAM,IAAI,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;IACzC,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAEzC,MAAM,GAAG,GAAG,8BAA8B,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACtD,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAE3B,OAAO;QACL,GAAG;QACH,OAAO,EAAE,gBAAgB,QAAQ,aAAa,GAAG,EAAE;KACpD,CAAC;AACJ,CAAC"}
|
package/dist/codex-process.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { EventEmitter } from "node:events";
|
|
2
2
|
import type { ServerMessage, ProcessStatus } from "./parser.js";
|
|
3
|
+
import { buildCodexSpawnSpec } from "./codex-transport.js";
|
|
4
|
+
export { buildCodexSpawnSpec };
|
|
3
5
|
export interface CodexStartOptions {
|
|
4
6
|
threadId?: string;
|
|
5
7
|
profile?: string;
|
|
@@ -72,18 +74,8 @@ export interface CodexProfileConfig {
|
|
|
72
74
|
profiles: string[];
|
|
73
75
|
defaultProfile?: string;
|
|
74
76
|
}
|
|
75
|
-
export declare function buildCodexSpawnSpec(projectPath: string, platform?: NodeJS.Platform): {
|
|
76
|
-
command: string;
|
|
77
|
-
args: string[];
|
|
78
|
-
options: {
|
|
79
|
-
cwd: string;
|
|
80
|
-
stdio: "pipe";
|
|
81
|
-
env: NodeJS.ProcessEnv;
|
|
82
|
-
windowsVerbatimArguments?: boolean;
|
|
83
|
-
};
|
|
84
|
-
};
|
|
85
77
|
export declare class CodexProcess extends EventEmitter<CodexProcessEvents> {
|
|
86
|
-
private
|
|
78
|
+
private transport;
|
|
87
79
|
private _status;
|
|
88
80
|
private _threadId;
|
|
89
81
|
private _agentNickname;
|
|
@@ -265,6 +257,7 @@ export declare class CodexProcess extends EventEmitter<CodexProcessEvents> {
|
|
|
265
257
|
private handleRpcResponse;
|
|
266
258
|
private handleServerRequest;
|
|
267
259
|
private handleNotification;
|
|
260
|
+
private isForeignThreadNotification;
|
|
268
261
|
private handleTurnCompleted;
|
|
269
262
|
private cleanupSteerTempPaths;
|
|
270
263
|
private processItemStarted;
|
package/dist/codex-process.js
CHANGED
|
@@ -3,36 +3,14 @@ import { randomUUID } from "node:crypto";
|
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { rm, writeFile } from "node:fs/promises";
|
|
6
|
-
import {
|
|
6
|
+
import { createCodexTransport, buildCodexSpawnSpec, } from "./codex-transport.js";
|
|
7
|
+
import { codexCliJoinTarget } from "./codex-app-server-config.js";
|
|
7
8
|
import { resolvePlatformPath } from "./path-utils.js";
|
|
9
|
+
export { buildCodexSpawnSpec };
|
|
8
10
|
const DEFAULT_CODEX_MODEL = "gpt-5.5";
|
|
9
11
|
const COMPLETION_FETCH_COOLDOWN_MS = 1000;
|
|
10
|
-
export function buildCodexSpawnSpec(projectPath, platform = process.platform) {
|
|
11
|
-
const cwd = resolvePlatformPath(projectPath, platform);
|
|
12
|
-
if (platform === "win32") {
|
|
13
|
-
return {
|
|
14
|
-
command: "cmd.exe",
|
|
15
|
-
args: ["/d", "/s", "/c", "codex app-server --listen stdio://"],
|
|
16
|
-
options: {
|
|
17
|
-
cwd,
|
|
18
|
-
stdio: "pipe",
|
|
19
|
-
env: process.env,
|
|
20
|
-
windowsVerbatimArguments: true,
|
|
21
|
-
},
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
return {
|
|
25
|
-
command: "codex",
|
|
26
|
-
args: ["app-server", "--listen", "stdio://"],
|
|
27
|
-
options: {
|
|
28
|
-
cwd,
|
|
29
|
-
stdio: "pipe",
|
|
30
|
-
env: process.env,
|
|
31
|
-
},
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
12
|
export class CodexProcess extends EventEmitter {
|
|
35
|
-
|
|
13
|
+
transport = null;
|
|
36
14
|
_status = "starting";
|
|
37
15
|
_threadId = null;
|
|
38
16
|
_agentNickname = null;
|
|
@@ -100,7 +78,7 @@ export class CodexProcess extends EventEmitter {
|
|
|
100
78
|
return this._agentRole;
|
|
101
79
|
}
|
|
102
80
|
get isRunning() {
|
|
103
|
-
return this.
|
|
81
|
+
return this.transport?.isRunning ?? false;
|
|
104
82
|
}
|
|
105
83
|
get approvalPolicy() {
|
|
106
84
|
return this._approvalPolicy;
|
|
@@ -259,7 +237,7 @@ export class CodexProcess extends EventEmitter {
|
|
|
259
237
|
return models;
|
|
260
238
|
}
|
|
261
239
|
start(projectPath, options) {
|
|
262
|
-
if (this.
|
|
240
|
+
if (this.transport) {
|
|
263
241
|
this.stop();
|
|
264
242
|
}
|
|
265
243
|
this.prepareLaunch(projectPath, options);
|
|
@@ -267,7 +245,7 @@ export class CodexProcess extends EventEmitter {
|
|
|
267
245
|
void this.bootstrap(projectPath, options);
|
|
268
246
|
}
|
|
269
247
|
async initializeOnly(projectPath) {
|
|
270
|
-
if (this.
|
|
248
|
+
if (this.transport) {
|
|
271
249
|
this.stop();
|
|
272
250
|
}
|
|
273
251
|
this.prepareLaunch(projectPath);
|
|
@@ -285,9 +263,9 @@ export class CodexProcess extends EventEmitter {
|
|
|
285
263
|
this.pendingUserInputs.clear();
|
|
286
264
|
this.cleanupSteerTempPaths();
|
|
287
265
|
this.rejectAllPending(new Error("stopped"));
|
|
288
|
-
if (this.
|
|
289
|
-
this.
|
|
290
|
-
this.
|
|
266
|
+
if (this.transport) {
|
|
267
|
+
this.transport.stop();
|
|
268
|
+
this.transport = null;
|
|
291
269
|
}
|
|
292
270
|
this.setStatus("idle");
|
|
293
271
|
console.log("[codex-process] Stopped");
|
|
@@ -314,22 +292,19 @@ export class CodexProcess extends EventEmitter {
|
|
|
314
292
|
this._projectPath = projectPath;
|
|
315
293
|
}
|
|
316
294
|
launchAppServer(projectPath, options) {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
child.stdout.setEncoding("utf8");
|
|
322
|
-
child.stdout.on("data", (chunk) => {
|
|
295
|
+
console.log(`[codex-process] Starting app-server (cwd: ${projectPath}, sandbox: ${options?.sandboxMode ?? "workspace-write"}, approval: ${options?.approvalPolicy ?? "never"}, reviewer: ${this.approvalsReviewer}, model: ${options?.model ?? "default"}, collaboration: ${this._collaborationMode})`);
|
|
296
|
+
const transport = createCodexTransport(projectPath, this.platform);
|
|
297
|
+
this.transport = transport;
|
|
298
|
+
transport.on("data", (chunk) => {
|
|
323
299
|
this.handleStdoutChunk(chunk);
|
|
324
300
|
});
|
|
325
|
-
|
|
326
|
-
child.stderr.on("data", (chunk) => {
|
|
301
|
+
transport.on("log", (chunk) => {
|
|
327
302
|
const line = chunk.trim();
|
|
328
303
|
if (line) {
|
|
329
304
|
console.log(`[codex-process] stderr: ${line}`);
|
|
330
305
|
}
|
|
331
306
|
});
|
|
332
|
-
|
|
307
|
+
transport.on("error", (err) => {
|
|
333
308
|
if (this.stopped)
|
|
334
309
|
return;
|
|
335
310
|
console.error("[codex-process] app-server process error:", err);
|
|
@@ -340,9 +315,9 @@ export class CodexProcess extends EventEmitter {
|
|
|
340
315
|
this.setStatus("idle");
|
|
341
316
|
this.emit("exit", 1);
|
|
342
317
|
});
|
|
343
|
-
|
|
318
|
+
transport.on("exit", (code) => {
|
|
344
319
|
const exitCode = code ?? 0;
|
|
345
|
-
this.
|
|
320
|
+
this.transport = null;
|
|
346
321
|
this.rejectAllPending(new Error("codex app-server exited"));
|
|
347
322
|
if (!this.stopped && exitCode !== 0) {
|
|
348
323
|
this.emitMessage({
|
|
@@ -353,6 +328,7 @@ export class CodexProcess extends EventEmitter {
|
|
|
353
328
|
this.setStatus("idle");
|
|
354
329
|
this.emit("exit", code);
|
|
355
330
|
});
|
|
331
|
+
transport.start(projectPath);
|
|
356
332
|
}
|
|
357
333
|
interrupt() {
|
|
358
334
|
if (!this._threadId || !this.pendingTurnId)
|
|
@@ -713,6 +689,9 @@ export class CodexProcess extends EventEmitter {
|
|
|
713
689
|
this.startModel = resolvedSettings.model;
|
|
714
690
|
}
|
|
715
691
|
this._threadId = threadId;
|
|
692
|
+
this._agentNickname = stringOrNull(thread?.agentNickname);
|
|
693
|
+
this._agentRole = stringOrNull(thread?.agentRole);
|
|
694
|
+
const cliJoin = codexCliJoinTarget(threadId);
|
|
716
695
|
this.emitMessage({
|
|
717
696
|
type: "system",
|
|
718
697
|
subtype: "init",
|
|
@@ -750,6 +729,7 @@ export class CodexProcess extends EventEmitter {
|
|
|
750
729
|
...(options?.additionalWritableRoots?.length
|
|
751
730
|
? { additionalWritableRoots: options.additionalWritableRoots }
|
|
752
731
|
: {}),
|
|
732
|
+
...(cliJoin ? { codexCliJoin: cliJoin } : {}),
|
|
753
733
|
});
|
|
754
734
|
this.setStatus("idle");
|
|
755
735
|
// Fetch skills/apps in background (non-blocking)
|
|
@@ -1278,6 +1258,8 @@ export class CodexProcess extends EventEmitter {
|
|
|
1278
1258
|
}
|
|
1279
1259
|
}
|
|
1280
1260
|
handleNotification(method, params) {
|
|
1261
|
+
if (this.isForeignThreadNotification(method, params))
|
|
1262
|
+
return;
|
|
1281
1263
|
switch (method) {
|
|
1282
1264
|
case "thread/started": {
|
|
1283
1265
|
const thread = params.thread;
|
|
@@ -1394,6 +1376,20 @@ export class CodexProcess extends EventEmitter {
|
|
|
1394
1376
|
break;
|
|
1395
1377
|
}
|
|
1396
1378
|
}
|
|
1379
|
+
isForeignThreadNotification(method, params) {
|
|
1380
|
+
if (!isThreadScopedNotification(method))
|
|
1381
|
+
return false;
|
|
1382
|
+
const threadId = notificationThreadId(params);
|
|
1383
|
+
if (!threadId)
|
|
1384
|
+
return false;
|
|
1385
|
+
// Thread binding comes from the thread/start or thread/resume response.
|
|
1386
|
+
// In shared app-server modes, early notifications can belong to another
|
|
1387
|
+
// client, so explicit-thread notifications are ignored until this process
|
|
1388
|
+
// has its own authoritative thread id.
|
|
1389
|
+
if (!this._threadId)
|
|
1390
|
+
return true;
|
|
1391
|
+
return threadId !== this._threadId;
|
|
1392
|
+
}
|
|
1397
1393
|
handleTurnCompleted(turn) {
|
|
1398
1394
|
const status = String(turn?.status ?? "completed");
|
|
1399
1395
|
const usage = this.lastTokenUsage;
|
|
@@ -1617,6 +1613,22 @@ export class CodexProcess extends EventEmitter {
|
|
|
1617
1613
|
});
|
|
1618
1614
|
break;
|
|
1619
1615
|
}
|
|
1616
|
+
case "user":
|
|
1617
|
+
case "usermessage":
|
|
1618
|
+
case "userinput": {
|
|
1619
|
+
const text = extractUserText(item);
|
|
1620
|
+
if (!text)
|
|
1621
|
+
return;
|
|
1622
|
+
this.emitMessage({
|
|
1623
|
+
type: "user_input",
|
|
1624
|
+
text,
|
|
1625
|
+
userMessageUuid: itemId,
|
|
1626
|
+
...(typeof item.timestamp === "string"
|
|
1627
|
+
? { timestamp: item.timestamp }
|
|
1628
|
+
: {}),
|
|
1629
|
+
});
|
|
1630
|
+
break;
|
|
1631
|
+
}
|
|
1620
1632
|
case "reasoning": {
|
|
1621
1633
|
const text = extractReasoningText(item);
|
|
1622
1634
|
if (text) {
|
|
@@ -1845,11 +1857,10 @@ export class CodexProcess extends EventEmitter {
|
|
|
1845
1857
|
}
|
|
1846
1858
|
}
|
|
1847
1859
|
writeEnvelope(envelope) {
|
|
1848
|
-
if (!this.
|
|
1860
|
+
if (!this.transport || !this.transport.isRunning) {
|
|
1849
1861
|
throw new Error("codex app-server is not running");
|
|
1850
1862
|
}
|
|
1851
|
-
|
|
1852
|
-
this.child.stdin.write(line);
|
|
1863
|
+
this.transport.write(envelope);
|
|
1853
1864
|
}
|
|
1854
1865
|
rejectAllPending(error) {
|
|
1855
1866
|
for (const pending of this.pendingRpc.values()) {
|
|
@@ -2080,6 +2091,29 @@ function normalizeItemType(raw) {
|
|
|
2080
2091
|
return "";
|
|
2081
2092
|
return raw.replace(/[_\s-]/g, "").toLowerCase();
|
|
2082
2093
|
}
|
|
2094
|
+
function isThreadScopedNotification(method) {
|
|
2095
|
+
return (method.startsWith("thread/") ||
|
|
2096
|
+
method.startsWith("turn/") ||
|
|
2097
|
+
method.startsWith("item/") ||
|
|
2098
|
+
method === "serverRequest/resolved");
|
|
2099
|
+
}
|
|
2100
|
+
function notificationThreadId(params) {
|
|
2101
|
+
if (typeof params.threadId === "string")
|
|
2102
|
+
return params.threadId;
|
|
2103
|
+
const thread = params.thread;
|
|
2104
|
+
if (thread && typeof thread === "object") {
|
|
2105
|
+
const id = thread.id;
|
|
2106
|
+
if (typeof id === "string")
|
|
2107
|
+
return id;
|
|
2108
|
+
}
|
|
2109
|
+
const turn = params.turn;
|
|
2110
|
+
if (turn && typeof turn === "object") {
|
|
2111
|
+
const id = turn.threadId;
|
|
2112
|
+
if (typeof id === "string")
|
|
2113
|
+
return id;
|
|
2114
|
+
}
|
|
2115
|
+
return null;
|
|
2116
|
+
}
|
|
2083
2117
|
function numberOrUndefined(value) {
|
|
2084
2118
|
return typeof value === "number" && Number.isFinite(value)
|
|
2085
2119
|
? value
|
|
@@ -2328,6 +2362,13 @@ function extractAgentText(item) {
|
|
|
2328
2362
|
}
|
|
2329
2363
|
return "";
|
|
2330
2364
|
}
|
|
2365
|
+
function extractUserText(item) {
|
|
2366
|
+
if (typeof item.text === "string")
|
|
2367
|
+
return item.text;
|
|
2368
|
+
if (typeof item.message === "string")
|
|
2369
|
+
return item.message;
|
|
2370
|
+
return extractAgentText(item);
|
|
2371
|
+
}
|
|
2331
2372
|
function extractReasoningText(item) {
|
|
2332
2373
|
if (typeof item.text === "string")
|
|
2333
2374
|
return item.text;
|