Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
a05d74e
refactor(state): extract resolveStateRoot for cwd-independent state-r…
hongsu Jun 18, 2026
615cd92
feat(broker): record owning sessionId in broker.json on creation
hongsu Jun 18, 2026
6a1bca3
feat(broker): add teardownBrokersForSession for cwd-independent cleanup
hongsu Jun 18, 2026
8aa56c3
fix(session): tear down brokers by sessionId on SessionEnd (#380)
hongsu Jun 18, 2026
82a372f
Keep session hooks running through symlinked plugin roots
hongsu Jun 18, 2026
a897e88
fix(broker): preserve shared broker ownership across sessions
hongsu Jun 18, 2026
55b5892
Merge branch 'main' into fix/broker-session-cleanup
hongsu Jun 26, 2026
c22bb77
fix(broker): serialize session owner teardown
hongsu Jul 7, 2026
a5321bd
fix(broker): prune dead session owners during broker teardown
hongsu Jul 7, 2026
19a722c
fix(hooks): guard isExecutedDirectly against unresolvable argv[1]
hongsu Jul 7, 2026
da7a24b
fix(broker): revalidate broker state under the lock before reuse
hongsu Jul 7, 2026
60671d2
fix(broker): drop unreliable PID liveness; harden teardown/spawn conc…
hongsu Jul 7, 2026
ee60490
fix(broker): bound SessionEnd cleanup and don't strand the ending owner
hongsu Jul 8, 2026
9d56a2b
fix(broker): best-effort shutdown on bad endpoints; atomic state writes
hongsu Jul 8, 2026
67cad78
Merge branch 'main' into fix/broker-session-cleanup
hongsu Jul 10, 2026
ab2d491
fix(broker): clean cross-worktree session jobs safely
hongsu Jul 16, 2026
3cb8e20
[COMMON] Serialize session teardown state transitions
hongsu Jul 20, 2026
45d45e8
[COMMON] Terminate session jobs before cleanup
hongsu Jul 20, 2026
e74ed59
[COMMON] Preserve brokers before job cleanup starts
hongsu Jul 20, 2026
1eac442
[COMMON] Close broker cleanup race windows
hongsu Jul 20, 2026
01c70f5
[COMMON] Track ready broker joiners during cleanup
hongsu Jul 20, 2026
937fe5d
[COMMON] Make ended broker sessions monotonic
hongsu Jul 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 34 additions & 6 deletions plugins/codex/scripts/lib/app-server.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ import process from "node:process";
import { spawn } from "node:child_process";
import readline from "node:readline";
import { parseBrokerEndpoint } from "./broker-endpoint.mjs";
import { ensureBrokerSession, loadBrokerSession } from "./broker-lifecycle.mjs";
import {
assertBrokerSessionActive,
ensureBrokerSession,
resolveSessionId,
reuseBrokerSession
} from "./broker-lifecycle.mjs";
import { terminateProcessTree } from "./process.mjs";

const PLUGIN_MANIFEST_URL = new URL("../../.claude-plugin/plugin.json", import.meta.url);
Expand Down Expand Up @@ -334,21 +339,44 @@ class BrokerCodexAppServerClient extends AppServerClientBase {

export class CodexAppServerClient {
static async connect(cwd, options = {}) {
const sessionId = resolveSessionId({ env: options.env });
let brokerEndpoint = null;
if (!options.disableBroker) {
if (options.disableBroker) {
assertBrokerSessionActive(sessionId);
} else {
brokerEndpoint = options.brokerEndpoint ?? options.env?.[BROKER_ENDPOINT_ENV] ?? process.env[BROKER_ENDPOINT_ENV] ?? null;
if (!brokerEndpoint && options.reuseExistingBroker) {
brokerEndpoint = loadBrokerSession(cwd)?.endpoint ?? null;
if (brokerEndpoint) {
// A supplied endpoint bypasses the lifecycle functions that normally
// perform admission under the broker-state lock.
assertBrokerSessionActive(sessionId);
}
if (!brokerEndpoint && !options.reuseExistingBroker) {
const brokerSession = await ensureBrokerSession(cwd, { env: options.env });
if (!brokerEndpoint && sessionId && options.reuseExistingBroker) {
const brokerSession = await reuseBrokerSession(cwd, {
...options.brokerOptions,
env: options.env,
killProcess: terminateProcessTree
});
brokerEndpoint = brokerSession?.endpoint ?? null;
}
if (!brokerEndpoint && sessionId && !options.reuseExistingBroker) {
const brokerSession = await ensureBrokerSession(cwd, {
...options.brokerOptions,
env: options.env,
killProcess: terminateProcessTree
});
brokerEndpoint = brokerSession?.endpoint ?? null;
}
}
const client = brokerEndpoint
? new BrokerCodexAppServerClient(cwd, { ...options, brokerEndpoint })
: new SpawnedCodexAppServerClient(cwd, options);
await client.initialize();
try {
assertBrokerSessionActive(sessionId);
} catch (error) {
await client.close();
throw error;
}
return client;
}
}
Loading