borgmcp 5.2.0 → 5.4.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.
Files changed (82) hide show
  1. package/dist/agent-runtime.d.ts +3 -4
  2. package/dist/agent-runtime.d.ts.map +1 -1
  3. package/dist/agent-runtime.js +9 -5
  4. package/dist/agent-runtime.js.map +1 -1
  5. package/dist/agent-session-identity.d.ts +13 -0
  6. package/dist/agent-session-identity.d.ts.map +1 -0
  7. package/dist/agent-session-identity.js +106 -0
  8. package/dist/agent-session-identity.js.map +1 -0
  9. package/dist/assimilate-cmd.d.ts +1 -11
  10. package/dist/assimilate-cmd.d.ts.map +1 -1
  11. package/dist/assimilate-cmd.js +37 -48
  12. package/dist/assimilate-cmd.js.map +1 -1
  13. package/dist/assimilate-deps.d.ts.map +1 -1
  14. package/dist/assimilate-deps.js +1 -4
  15. package/dist/assimilate-deps.js.map +1 -1
  16. package/dist/claude.d.ts.map +1 -1
  17. package/dist/claude.js +36 -77
  18. package/dist/claude.js.map +1 -1
  19. package/dist/codex-app-server.d.ts +4 -6
  20. package/dist/codex-app-server.d.ts.map +1 -1
  21. package/dist/codex-app-server.js +4 -25
  22. package/dist/codex-app-server.js.map +1 -1
  23. package/dist/codex-app-wake.d.ts +8 -10
  24. package/dist/codex-app-wake.d.ts.map +1 -1
  25. package/dist/codex-app-wake.js +49 -66
  26. package/dist/codex-app-wake.js.map +1 -1
  27. package/dist/codex-launch.d.ts +15 -24
  28. package/dist/codex-launch.d.ts.map +1 -1
  29. package/dist/codex-launch.js +29 -55
  30. package/dist/codex-launch.js.map +1 -1
  31. package/dist/codex-remote.d.ts +15 -8
  32. package/dist/codex-remote.d.ts.map +1 -1
  33. package/dist/codex-remote.js +71 -70
  34. package/dist/codex-remote.js.map +1 -1
  35. package/dist/codex-wake-resolve.d.ts +12 -31
  36. package/dist/codex-wake-resolve.d.ts.map +1 -1
  37. package/dist/codex-wake-resolve.js +21 -38
  38. package/dist/codex-wake-resolve.js.map +1 -1
  39. package/dist/config-utils.js +2 -2
  40. package/dist/config-utils.js.map +1 -1
  41. package/dist/cubes.d.ts +0 -17
  42. package/dist/cubes.d.ts.map +1 -1
  43. package/dist/cubes.js +0 -81
  44. package/dist/cubes.js.map +1 -1
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +10 -5
  47. package/dist/index.js.map +1 -1
  48. package/dist/lifecycle-log-guard.d.ts +6 -8
  49. package/dist/lifecycle-log-guard.d.ts.map +1 -1
  50. package/dist/lifecycle-log-guard.js +74 -22
  51. package/dist/lifecycle-log-guard.js.map +1 -1
  52. package/dist/log-stream.d.ts.map +1 -1
  53. package/dist/log-stream.js +4 -1
  54. package/dist/log-stream.js.map +1 -1
  55. package/dist/opencode-drone.d.ts +2 -0
  56. package/dist/opencode-drone.d.ts.map +1 -1
  57. package/dist/opencode-drone.js +16 -0
  58. package/dist/opencode-drone.js.map +1 -1
  59. package/dist/regen-format.js +1 -1
  60. package/dist/regen-format.js.map +1 -1
  61. package/dist/regen.js +11 -1
  62. package/dist/regen.js.map +1 -1
  63. package/docs/SESSION_IDENTITY.md +15 -0
  64. package/package.json +1 -1
  65. package/src/agent-runtime.ts +9 -5
  66. package/src/agent-session-identity.ts +98 -0
  67. package/src/assimilate-cmd.ts +35 -58
  68. package/src/assimilate-deps.ts +0 -4
  69. package/src/claude.ts +34 -81
  70. package/src/codex-app-server.ts +8 -25
  71. package/src/codex-app-wake.ts +46 -73
  72. package/src/codex-launch.ts +43 -76
  73. package/src/codex-remote.ts +90 -82
  74. package/src/codex-wake-resolve.ts +26 -47
  75. package/src/config-utils.ts +2 -2
  76. package/src/cubes.ts +2 -100
  77. package/src/index.ts +10 -5
  78. package/src/lifecycle-log-guard.ts +70 -26
  79. package/src/log-stream.ts +4 -1
  80. package/src/opencode-drone.ts +14 -0
  81. package/src/regen-format.ts +1 -1
  82. package/src/regen.ts +7 -1
package/dist/regen.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"regen.js","sourceRoot":"","sources":["../src/regen.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"regen.js","sourceRoot":"","sources":["../src/regen.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ # Agent Session Identity
2
+
3
+ ARRIVAL is announced once for each known agent session and cube/drone pair, using local lifecycle state. Changing the ARRIVAL wording or reconnecting the MCP transport does not create another announcement for that identity. A different session announces immediately, without a time window. Resuming an already announced session remains suppressed. This state does not affect credentials, authorization, stream ownership, or liveness.
4
+
5
+ The startup instruction itself remains process-local: reconnecting may display it again. Calling `borg_log` with ARRIVAL applies the persistent identity check. Unknown identity always announces rather than concealing a possible restart. READY suppression is unchanged.
6
+
7
+ ## Harness Coverage
8
+
9
+ - **Claude Code:** the latest SessionStart hook observed for this launch. Borg puts a random correlation in the launch environment. `borg-regen` stores that correlation, the hook's `session_id`, and its observation time in the worktree's `.borgmcp/claude-session.json`. A reconnect with the same correlation reads the same observation; a successful hook on resume replaces it. Missing, invalid, unreadable, or prior-launch state is unknown. Claude identity can be stale after a resume whose SessionStart hook failed.
10
+ - **Codex:** exactly one non-ephemeral user thread, excluding subagents, in this launch's Borg-owned app-server. Zero or multiple candidates, an unreadable thread, or an unavailable socket is unknown. No recency guess identifies a session.
11
+ - **OpenCode:** the existing launch-correlation binding, rechecked against session metadata. Missing or changed binding, an unseen root session, duplicated launch metadata, or failed inspection is unknown. The identity reader does not follow the wake injector's `/new` selection heuristic.
12
+
13
+ `borg_stream-status` reports the identity source, the harness-prefixed session id, and the age of the observation in its text response. For Claude this age is measured from the hook, not the MCP child's start. Age is diagnostic only: there is no expiry heuristic. For Codex and OpenCode the observation is a fresh query. Unknown results report their reason.
14
+
15
+ These identifiers denote harness conversations, not operating-system processes. Restarting a harness into a new conversation produces a new identity; explicitly resuming the same conversation retains its identity when ownership is known. Session identifiers are not secrets or authorization inputs.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "borgmcp",
3
- "version": "5.2.0",
3
+ "version": "5.4.0",
4
4
  "description": "Coordinate AI coding agents in shared cubes. Works with Claude Code, Codex, and OpenCode.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -6,11 +6,13 @@
6
6
  */
7
7
 
8
8
  import { BORG_STATE_ROOT_ENV } from './private-root.js';
9
+ import { randomBytes } from 'node:crypto';
9
10
 
10
11
  export type AgentKind = 'claude' | 'codex' | 'opencode';
11
12
 
12
13
  /** Pinned into MCP-child environments by Borg launch paths. */
13
14
  export const BORG_AGENT_KIND_ENV = 'BORG_AGENT_KIND';
15
+ export const BORG_CLAUDE_LAUNCH_CORRELATION_ENV = 'BORG_CLAUDE_LAUNCH_CORRELATION';
14
16
  /** Transport capability only — never use it as the primary CLI identity. */
15
17
  export const BORG_CODEX_REMOTE_WAKE_ENV = 'BORG_CODEX_REMOTE_WAKE';
16
18
  /** Legacy OpenCode runtime marker, retained for installed-config compatibility. */
@@ -52,7 +54,11 @@ export function withAgentRuntimeEnv(
52
54
  delete next[BORG_AGENT_KIND_ENV];
53
55
  delete next[BORG_CODEX_REMOTE_WAKE_ENV];
54
56
  delete next[BORG_OPENCODE_ENV];
57
+ delete next[BORG_CLAUDE_LAUNCH_CORRELATION_ENV];
55
58
  next[BORG_AGENT_KIND_ENV] = agentKind;
59
+ if (agentKind === 'claude') {
60
+ next[BORG_CLAUDE_LAUNCH_CORRELATION_ENV] = randomBytes(32).toString('base64url');
61
+ }
56
62
  if (agentKind === 'opencode') next[BORG_OPENCODE_ENV] = '1';
57
63
  return next;
58
64
  }
@@ -66,14 +72,12 @@ export function codexAgentKindConfigArgs(): string[] {
66
72
  * Pin the remote-wake transport capability separately from the CLI identity.
67
73
  *
68
74
  * Codex MCP children read their configured env rather than the wrapper's
69
- * inherited process env. Explicitly pinning "0" on a no-socket launch is
70
- * therefore necessary to override legacy static configs that used to persist
71
- * BORG_CODEX_REMOTE_WAKE="1" as an identity marker.
75
+ * inherited process env. Every Borg Codex launch owns a remote socket.
72
76
  */
73
- export function codexRemoteWakeConfigArgs(enabled: boolean = true): string[] {
77
+ export function codexRemoteWakeConfigArgs(): string[] {
74
78
  return [
75
79
  '-c',
76
- `mcp_servers.borg.env.${BORG_CODEX_REMOTE_WAKE_ENV}="${enabled ? '1' : '0'}"`,
80
+ `mcp_servers.borg.env.${BORG_CODEX_REMOTE_WAKE_ENV}="1"`,
77
81
  ];
78
82
  }
79
83
 
@@ -0,0 +1,98 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import { readFile, rename, unlink, writeFile } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { BORG_CLAUDE_LAUNCH_CORRELATION_ENV, resolveReportableSessionAgentKind } from './agent-runtime.js';
5
+ import { findProjectRoot } from './cubes.js';
6
+ import { ensurePrivateBorgConfigRoot } from './private-root.js';
7
+ import { CodexAppServerClient } from './codex-app-server.js';
8
+ import { codexAppServerSocketFromEnv, isCodexSubagentSource } from './codex-wake-resolve.js';
9
+ import { resolveOpenCodeAgentSessionId } from './opencode-drone.js';
10
+
11
+ export type AgentSessionIdentity =
12
+ | { kind: 'known'; id: string; source: string; observedAt: string }
13
+ | { kind: 'unknown'; reason: string };
14
+
15
+ function validId(value: unknown): value is string {
16
+ return typeof value === 'string' && value.length > 0 && value.length <= 512 && !/[\s\x00-\x1f\x7f]/.test(value);
17
+ }
18
+
19
+ function claudeCorrelation(env: NodeJS.ProcessEnv): string | null {
20
+ const value = env[BORG_CLAUDE_LAUNCH_CORRELATION_ENV];
21
+ if (!value || !/^[A-Za-z0-9_-]{43}$/.test(value)) return null;
22
+ return Buffer.from(value, 'base64url').toString('base64url') === value ? value : null;
23
+ }
24
+
25
+ /** Identity only: no credential, authorization, liveness, or expiry semantics. */
26
+ export async function recordClaudeSessionStart(
27
+ payload: string,
28
+ env: NodeJS.ProcessEnv = process.env,
29
+ worktree = findProjectRoot(),
30
+ ): Promise<void> {
31
+ const correlation = claudeCorrelation(env);
32
+ if (!correlation) return;
33
+ let sessionId: unknown;
34
+ try { sessionId = JSON.parse(payload)?.session_id; } catch { /* Persist unknown rather than retain an old id. */ }
35
+ const root = join(worktree, '.borgmcp');
36
+ await ensurePrivateBorgConfigRoot(root);
37
+ try { await writeFile(join(root, '.gitignore'), '*\n', { flag: 'wx', mode: 0o600 }); }
38
+ catch (error) { if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error; }
39
+ const path = join(root, 'claude-session.json');
40
+ const temporary = `${path}.${randomBytes(16).toString('hex')}.tmp`;
41
+ try {
42
+ await writeFile(temporary, JSON.stringify({
43
+ correlation, session_id: validId(sessionId) ? sessionId : null,
44
+ observedAt: new Date().toISOString(),
45
+ }) + '\n', { flag: 'wx', mode: 0o600 });
46
+ await rename(temporary, path);
47
+ } finally {
48
+ await unlink(temporary).catch((error: NodeJS.ErrnoException) => { if (error.code !== 'ENOENT') throw error; });
49
+ }
50
+ }
51
+
52
+ export async function resolveAgentSessionIdentity(
53
+ env: NodeJS.ProcessEnv = process.env,
54
+ worktree = findProjectRoot(),
55
+ ): Promise<AgentSessionIdentity> {
56
+ const kind = resolveReportableSessionAgentKind(env);
57
+ try {
58
+ if (kind === 'claude') {
59
+ const correlation = claudeCorrelation(env);
60
+ if (!correlation) return { kind: 'unknown', reason: 'claude-launch-correlation-missing' };
61
+ const record = JSON.parse(await readFile(join(worktree, '.borgmcp', 'claude-session.json'), 'utf8'));
62
+ if (record?.correlation !== correlation) return { kind: 'unknown', reason: 'claude-launch-correlation-mismatch' };
63
+ if (!validId(record.session_id) || typeof record.observedAt !== 'string' || !Number.isFinite(Date.parse(record.observedAt))) {
64
+ return { kind: 'unknown', reason: 'claude-session-start-invalid' };
65
+ }
66
+ // Last observed hook, not proof of freshness: a skipped resume hook is
67
+ // undetectable without a future per-call harness session handoff.
68
+ return { kind: 'known', id: `claude:${record.session_id}`, source: 'claude-session-start', observedAt: record.observedAt };
69
+ }
70
+ if (kind === 'codex') {
71
+ const socket = codexAppServerSocketFromEnv(env);
72
+ if (!socket) return { kind: 'unknown', reason: 'codex-launch-socket-missing' };
73
+ const client = new CodexAppServerClient(socket);
74
+ try {
75
+ await client.connect();
76
+ const candidates: string[] = [];
77
+ for (const id of await client.loadedThreadIds()) {
78
+ const thread = await client.readThread(id);
79
+ // An unreadable candidate could be another user thread; do not guess.
80
+ if (!thread) return { kind: 'unknown', reason: 'codex-thread-unreadable' };
81
+ if (thread.ephemeral !== true && !isCodexSubagentSource(thread.source) &&
82
+ (thread.threadSource === undefined || thread.threadSource === 'user')) candidates.push(thread.id);
83
+ }
84
+ if (candidates.length !== 1 || !validId(candidates[0])) return { kind: 'unknown', reason: 'codex-user-thread-not-unique' };
85
+ return { kind: 'known', id: `codex:${candidates[0]}`, source: 'codex-launch-thread', observedAt: new Date().toISOString() };
86
+ } finally { client.close(); }
87
+ }
88
+ if (kind === 'opencode') {
89
+ const id = await resolveOpenCodeAgentSessionId();
90
+ return validId(id)
91
+ ? { kind: 'known', id: `opencode:${id}`, source: 'opencode-launch-binding', observedAt: new Date().toISOString() }
92
+ : { kind: 'unknown', reason: 'opencode-launch-binding-unavailable-or-changed' };
93
+ }
94
+ return { kind: 'unknown', reason: 'agent-harness-unknown' };
95
+ } catch {
96
+ return { kind: 'unknown', reason: `${kind ?? 'agent'}-session-source-unavailable` };
97
+ }
98
+ }
@@ -10,20 +10,15 @@ import {
10
10
  import { validateName } from './name-validator.js';
11
11
  import { renderAssimilationWelcome } from './assimilate-welcome.js';
12
12
  import { shellEscape } from './shell-escape.js';
13
- import { withCodexCwdArg, type CodexRemoteLaunch } from './codex-remote.js';
13
+ import { type CodexRemoteLaunch } from './codex-remote.js';
14
14
  import {
15
15
  buildAgentKickoffPrompt,
16
16
  buildKickoffWakePathClause,
17
- recordCodexWakeTarget,
18
- socketPathFromRemoteArgs,
17
+ buildCodexLaunchArgs,
19
18
  } from './codex-launch.js';
20
19
  import { perWorktreeBranchName, computeWorktreePath, localBranchExists, isMerged } from './worktree-lifecycle.js';
21
20
  import { DroneEvictedError } from './drone-lifecycle.js';
22
- import { codexBorgSessionConfigArgs } from './launch-gate.js';
23
21
  import {
24
- codexAgentKindConfigArgs,
25
- codexRemoteWakeConfigArgs,
26
- codexStateRootConfigArgs,
27
22
  withAgentRuntimeEnv,
28
23
  } from './agent-runtime.js';
29
24
  import {
@@ -405,13 +400,6 @@ export interface AssimilateDeps {
405
400
  setCliPreferenceForWorktree: (cli: BorgCli, worktree: string) => Promise<void>;
406
401
  resolveCli: (explicit?: BorgCli) => Promise<BorgCli>;
407
402
  prepareCodexRemoteLaunch: () => Promise<CodexRemoteLaunch>;
408
- setCodexWakeTarget: (cubeId: string, droneId: string, target: { threadId: string; socketPath: string }) => Promise<void>;
409
- findLoadedCodexThread: (options: {
410
- socketPath: string;
411
- cwd: string;
412
- previewIncludes: string;
413
- updatedAfter: number;
414
- }) => Promise<string | null>;
415
403
 
416
404
  }
417
405
 
@@ -952,13 +940,11 @@ export async function finalizeAssimilationSeat(
952
940
  export type LaunchDeps = Pick<
953
941
  AssimilateDeps,
954
942
  | 'exec'
955
- | 'findLoadedCodexThread'
956
943
  | 'getInboxPath'
957
944
  | 'isTTY'
958
945
  | 'prepareCodexRemoteLaunch'
959
946
  | 'probeMcpReady'
960
947
  | 'resolveCliApprovals'
961
- | 'setCodexWakeTarget'
962
948
  | 'setTerminalTitle'
963
949
  | 'stderr'
964
950
  | 'stdout'
@@ -1019,17 +1005,14 @@ export async function launchAssimilatedAgent(
1019
1005
  );
1020
1006
  }
1021
1007
  const inboxPath = deps.getInboxPath(result.cube_id, result.drone_id);
1022
- const codexWakeNonce = cli === 'codex' ? `borg-wake-${randomUUID()}` : null;
1023
1008
  const monitorClause = buildKickoffWakePathClause(
1024
1009
  cli,
1025
1010
  cli === 'claude' ? inboxPath : null,
1026
1011
  cli === 'claude' ? monitorStateRoot : null,
1027
1012
  );
1028
- let codexWakePathClause: string | undefined;
1029
- let remoteArgs: string[] = [];
1030
1013
  let launchArgs: string[];
1031
- let codexSocketPath: string | null = null;
1032
1014
  let codexServerCleanup: (() => void) | null = null;
1015
+ let codexRemote: CodexRemoteLaunch | null = null;
1033
1016
  const launchApproval = deps.resolveCliApprovals
1034
1017
  ? await deps.resolveCliApprovals(cli, agentCwd, { skipOverride: flags.noBorgApprovalOverride })
1035
1018
  : { codexArgs: [] };
@@ -1050,39 +1033,36 @@ export async function launchAssimilatedAgent(
1050
1033
  for (const key of modelEnv.unset) delete childEnv[key];
1051
1034
 
1052
1035
  if (cli === 'codex') {
1053
- const remote = await deps.prepareCodexRemoteLaunch();
1054
- if (remote.warning) {
1055
- deps.stderr(`warning: ${remote.warning}\n`);
1056
- codexWakePathClause =
1057
- '⚠ Codex wake-path capability check failed: remote-control is unavailable for this session. Run borg_regen manually whenever you return, and expect only fallback wakeups until relaunch.';
1058
- } else {
1059
- codexWakePathClause = 'Codex wake-path capability check passed: remote-control socket established for this session.';
1036
+ codexRemote = await deps.prepareCodexRemoteLaunch();
1037
+ if (!codexRemote.ready) {
1038
+ const stderr = codexRemote.stderr ? `\n${codexRemote.stderr}` : '';
1039
+ deps.stderr(`Codex launch refused: ${codexRemote.reason}${stderr}\n`);
1040
+ return 1;
1060
1041
  }
1061
- remoteArgs = remote.args;
1062
- if (Object.keys(remote.env).length > 0) Object.assign(childEnv, remote.env);
1063
- codexSocketPath = socketPathFromRemoteArgs(remote.args);
1064
- codexServerCleanup = remote.server?.cleanup ?? null;
1042
+ Object.assign(childEnv, codexRemote.env);
1043
+ codexServerCleanup = codexRemote.server.cleanup;
1065
1044
  }
1066
1045
  const kickoff = buildAgentKickoffPrompt({
1067
1046
  cli,
1068
- codexWakeNonce,
1069
1047
  monitorClause,
1070
- codexWakePathClause,
1071
1048
  });
1072
1049
  let openCodeKickoff: ReturnType<typeof createOpenCodeLaunchKickoff> | null = null;
1073
1050
  let dronePort: number | undefined;
1074
1051
  launchArgs = [kickoff];
1075
1052
  if (cli === 'codex') {
1076
- launchArgs = [
1077
- ...codexLaunchDirectoryArgs(launchAccessPaths),
1078
- ...launchApproval.codexArgs,
1079
- ...codexBorgSessionConfigArgs(),
1080
- ...codexAgentKindConfigArgs(),
1081
- ...codexRemoteWakeConfigArgs(codexSocketPath !== null),
1082
- ...codexStateRootConfigArgs(),
1083
- ...remoteArgs,
1084
- ...withCodexCwdArg(launchArgs, agentCwd),
1085
- ];
1053
+ const plan = buildCodexLaunchArgs({
1054
+ remote: codexRemote!,
1055
+ cwd: agentCwd,
1056
+ kickoff,
1057
+ approvalArgs: launchApproval.codexArgs,
1058
+ accessArgs: codexLaunchDirectoryArgs(launchAccessPaths),
1059
+ });
1060
+ if (!plan.ready) {
1061
+ codexServerCleanup?.();
1062
+ deps.stderr(`Codex launch refused: ${plan.reason}\n`);
1063
+ return 1;
1064
+ }
1065
+ launchArgs = plan.args;
1086
1066
  } else if (cli === 'opencode') {
1087
1067
  dronePort = await allocateOpenCodePort();
1088
1068
  childEnv.BORG_OPENCODE_PORT = String(dronePort);
@@ -1094,17 +1074,12 @@ export async function launchAssimilatedAgent(
1094
1074
  launchArgs = buildOpenCodeLaunchArgs(agentCwd, dronePort, openCodeKickoff.prompt);
1095
1075
  }
1096
1076
 
1097
- const exitPromise = deps.exec(cli, launchArgs, agentCwd, childEnv);
1098
- if (cli === 'codex' && codexSocketPath && codexWakeNonce) {
1099
- void recordCodexWakeTarget({
1100
- deps,
1101
- cubeId: result.cube_id,
1102
- droneId: result.drone_id,
1103
- socketPath: codexSocketPath,
1104
- cwd: agentCwd,
1105
- previewNeedle: codexWakeNonce,
1106
- launchedAtSeconds: Math.floor(Date.now() / 1000),
1107
- });
1077
+ let exitPromise: Promise<number>;
1078
+ try {
1079
+ exitPromise = deps.exec(cli, launchArgs, agentCwd, childEnv);
1080
+ } catch (error) {
1081
+ codexServerCleanup?.();
1082
+ throw error;
1108
1083
  }
1109
1084
  if (cli === 'opencode' && openCodeKickoff) {
1110
1085
  const launchKickoff = openCodeKickoff;
@@ -1117,12 +1092,14 @@ export async function launchAssimilatedAgent(
1117
1092
  launchIdentity: launchKickoff.correlationIdentity,
1118
1093
  }).then(() => injectInitialKickoff(launchKickoff)).catch(() => {});
1119
1094
  }
1120
- const exitCode = await exitPromise;
1121
- if (codexServerCleanup) {
1095
+ let exitCode: number;
1096
+ try {
1097
+ exitCode = await exitPromise;
1098
+ } finally {
1122
1099
  try {
1123
- codexServerCleanup();
1100
+ codexServerCleanup?.();
1124
1101
  } catch {
1125
- // Best-effort cleanup after a normal Codex exit.
1102
+ // Best-effort cleanup after Codex exits or fails to spawn.
1126
1103
  }
1127
1104
  }
1128
1105
  if (spawnedWorktreePath && originalCwd !== spawnedWorktreePath) {
@@ -61,7 +61,6 @@ import {
61
61
  hasPersistedActiveCube as cubesHasPersistedActive,
62
62
  inboxPathForDrone,
63
63
  setProjectCliPreference,
64
- setCodexWakeTarget,
65
64
  } from './cubes.js';
66
65
  import {
67
66
  addProjectSessionStartHook,
@@ -71,7 +70,6 @@ import { findPendingServerEnrollment, listServerCredentialOrigins } from './conf
71
70
  import { setTerminalTitle as setTitle } from './terminal-title.js';
72
71
  import { defaultCliChoiceDeps, resolveCliChoice } from './cli-platform.js';
73
72
  import { prepareCodexRemoteLaunch, defaultCodexRemoteDeps } from './codex-remote.js';
74
- import { findLoadedCodexThread } from './codex-app-server.js';
75
73
  import { defaultApprovalIo, resolveLaunchBorgApprovals } from './cli-tool-approval.js';
76
74
  import { ensurePrivateBorgConfigRoot } from './private-root.js';
77
75
  import {
@@ -577,7 +575,5 @@ export function buildDefaultAssimilateDeps(
577
575
  ),
578
576
  setCliPreferenceForWorktree: (cli, worktree) => setProjectCliPreference(cli, worktree),
579
577
  prepareCodexRemoteLaunch: () => prepareCodexRemoteLaunch(defaultCodexRemoteDeps()),
580
- setCodexWakeTarget,
581
- findLoadedCodexThread,
582
578
  };
583
579
  }
package/src/claude.ts CHANGED
@@ -16,7 +16,6 @@
16
16
  */
17
17
 
18
18
  import { spawn } from 'child_process';
19
- import { randomUUID } from 'node:crypto';
20
19
  import { realpathSync } from 'node:fs';
21
20
  import { homedir } from 'node:os';
22
21
  import { basename } from 'node:path';
@@ -30,8 +29,6 @@ import {
30
29
  getActiveCube,
31
30
  inboxPathForDrone,
32
31
  LaunchSeatIdentityChangedError,
33
- setCodexWakeTarget,
34
- pruneDeadCodexWakeTargets,
35
32
  type ActiveCube,
36
33
  type BorgCli,
37
34
  } from './cubes.js';
@@ -82,22 +79,15 @@ import { setTerminalTitle } from './terminal-title.js';
82
79
  import { initConsolePrefix, consolePrefix } from './console-prefix.js';
83
80
  import { initDebugFromArgv } from './debug.js';
84
81
  import { configuredCliNames, defaultCliChoiceDeps, detectCliAvailability, detectCliConfiguration, parseCliFlag, resolveCliChoice } from './cli-platform.js';
85
- import { prepareCodexRemoteLaunch, resolveCodexLaunchCwd, withCodexCwdArg, defaultCodexRemoteDeps, checkCodexBridgeHealthy } from './codex-remote.js';
82
+ import { prepareCodexRemoteLaunch, resolveCodexLaunchCwd, defaultCodexRemoteDeps } from './codex-remote.js';
86
83
  import {
87
- BORG_CODEX_REMOTE_WAKE_ENV,
88
- codexAgentKindConfigArgs,
89
- codexRemoteWakeConfigArgs,
90
- codexStateRootConfigArgs,
91
84
  withAgentRuntimeEnv,
92
85
  } from './agent-runtime.js';
93
- import { findLoadedCodexThread } from './codex-app-server.js';
94
86
  import {
95
87
  buildAgentKickoffPrompt,
96
88
  buildKickoffWakePathClause,
97
- recordCodexWakeTarget,
98
- socketPathFromRemoteArgs,
89
+ buildCodexLaunchArgs,
99
90
  } from './codex-launch.js';
100
- import { codexBorgSessionConfigArgs } from './launch-gate.js';
101
91
  import {
102
92
  addCodexSessionStartHook,
103
93
  addCodexUserPromptSubmitHook,
@@ -639,9 +629,6 @@ async function main() {
639
629
  : null
640
630
  );
641
631
 
642
- const codexWakeNonce = cli === 'codex' ? `borg-wake-${randomUUID()}` : null;
643
- let codexWakePathClause: string | undefined;
644
- let remoteArgs: string[] = [];
645
632
  // gh#673 P1: mark the agent session as borg-launched. Claude Code's MCP
646
633
  // child + hook commands inherit this env, gating the borg activation
647
634
  // surface (launch-gate.ts). ACTIVATION-only — never a security gate.
@@ -654,45 +641,33 @@ async function main() {
654
641
  if (cli === 'opencode' && launchApproval.openCodePermission) {
655
642
  launchEnv.OPENCODE_PERMISSION = launchApproval.openCodePermission;
656
643
  }
657
- let codexSocketPath: string | null = null;
658
644
  let codexServerCleanup: (() => void) | null = null;
659
- if (cli === 'codex' && !passthroughArgs.includes('--remote')) {
645
+ let codexRemote: Awaited<ReturnType<typeof prepareCodexRemoteLaunch>> | null = null;
646
+ if (cli === 'codex') {
647
+ if (passthroughArgs.some((arg) => arg === '--remote' || arg.startsWith('--remote='))) {
648
+ console.error(`${consolePrefix()}${chalk.red('Codex launch refused: Borg owns Codex remote control; remove the passthrough --remote option and retry.')}`);
649
+ process.exit(1);
650
+ return;
651
+ }
660
652
  console.error(`${consolePrefix()}${chalk.gray('◼ Starting Codex remote-wake app-server…')}`);
661
- const remote = await prepareCodexRemoteLaunch(defaultCodexRemoteDeps());
662
- if (remote.warning) {
663
- console.error(`${consolePrefix()}${chalk.yellow(`warning: ${remote.warning}`)}`);
664
- codexWakePathClause =
665
- `⚠ Codex wake-path capability check failed: remote-control is unavailable for this session. Run borg_regen manually whenever you return, and expect only fallback wakeups until relaunch.`;
666
- } else {
667
- codexWakePathClause =
668
- `Codex wake-path capability check passed: remote-control socket established for this session.`;
653
+ codexRemote = await prepareCodexRemoteLaunch(defaultCodexRemoteDeps());
654
+ if (!codexRemote.ready) {
655
+ const stderr = codexRemote.stderr ? `\n${codexRemote.stderr}` : '';
656
+ console.error(`${consolePrefix()}${chalk.red(`Codex launch refused: ${codexRemote.reason}${stderr}`)}`);
657
+ process.exit(1);
658
+ return;
669
659
  }
670
- remoteArgs = remote.args;
671
660
  launchEnv = {
672
661
  ...withAgentRuntimeEnv(process.env, cli),
673
- ...remote.env,
662
+ ...codexRemote.env,
674
663
  BORG_SESSION: '1',
675
664
  };
676
- codexSocketPath = socketPathFromRemoteArgs(remote.args);
677
- codexServerCleanup = remote.server?.cleanup ?? null;
678
- } else if (cli === 'codex' && passthroughArgs.includes('--remote')) {
679
- codexWakePathClause =
680
- `Codex wake-path capability check: using caller-provided --remote socket; if no wake arrives, run borg_regen manually when returning to the session.`;
681
- codexSocketPath = socketPathFromRemoteArgs(passthroughArgs);
682
- if (codexSocketPath) {
683
- launchEnv = {
684
- ...withAgentRuntimeEnv(process.env, cli),
685
- [BORG_CODEX_REMOTE_WAKE_ENV]: '1',
686
- BORG_SESSION: '1',
687
- };
688
- }
665
+ codexServerCleanup = codexRemote.server.cleanup;
689
666
  }
690
667
 
691
668
  const kickoff = buildAgentKickoffPrompt({
692
669
  cli,
693
- codexWakeNonce,
694
670
  monitorClause,
695
- codexWakePathClause,
696
671
  });
697
672
  // This stays separate from the shared kickoff so OpenCode can carry
698
673
  // launch-only API and correlation identities outside argv and prompt text.
@@ -700,29 +675,26 @@ async function main() {
700
675
  let openCodePort: number | undefined;
701
676
  let launchArgs: string[];
702
677
  if (cli === 'codex') {
703
- // gh#673 P1-codex: codex MCP children only see the pinned
704
- // [mcp_servers.borg.env], never inherited env (V2 probe) — deliver
705
- // the borg-launch marker and selected CLI identity via per-invocation
706
- // -c overrides instead (V2b-proven). Remote wake remains a separate
707
- // transport capability, explicitly disabled when this launch has no
708
- // socket so legacy static config cannot spuriously arm a bridge.
709
- // client#20: the exact approval overrides above are launch-scoped and
710
- // consented. They remain separate from activation/identity/wake config.
711
- launchArgs = [
712
- ...launchApproval.codexArgs,
713
- ...codexBorgSessionConfigArgs(),
714
- ...codexAgentKindConfigArgs(),
715
- ...codexRemoteWakeConfigArgs(codexSocketPath !== null),
716
- ...codexStateRootConfigArgs(),
717
- ...codexLaunchSeatExpectationConfigArgs(),
718
- ...remoteArgs,
719
- ...withCodexCwdArg([...passthroughArgs, kickoff], process.cwd()),
720
- ];
678
+ const plan = buildCodexLaunchArgs({
679
+ remote: codexRemote!,
680
+ cwd: process.cwd(),
681
+ kickoff,
682
+ approvalArgs: launchApproval.codexArgs,
683
+ seatExpectationArgs: codexLaunchSeatExpectationConfigArgs(),
684
+ passthroughArgs,
685
+ });
686
+ if (!plan.ready) {
687
+ codexServerCleanup?.();
688
+ console.error(`${consolePrefix()}${chalk.red(`Codex launch refused: ${plan.reason}`)}`);
689
+ process.exit(1);
690
+ return;
691
+ }
692
+ launchArgs = plan.args;
721
693
  } else if (cli === 'opencode') {
722
694
  // OpenCode launch: start TUI with the kickoff passed via --prompt
723
695
  // (auto-submits it as the first message). BORG_SESSION is pinned in
724
- // opencode.json. The OS-selected loopback port lets the MCP child connect
725
- // to OpenCode's local HTTP API without a shared deterministic collision space.
696
+ // opencode.json. Wake delivery uses HTTP entry injection through OpenCode's local HTTP API;
697
+ // the OS-selected port avoids a deterministic collision space.
726
698
  openCodePort = await allocateOpenCodePort();
727
699
  installBorgPlugin();
728
700
  openCodeKickoff = createOpenCodeLaunchKickoff(kickoff);
@@ -749,25 +721,6 @@ async function main() {
749
721
  })).process
750
722
  : spawn(cli, launchArgs, { stdio: 'inherit', shell: false, env: launchEnv });
751
723
 
752
- // gh#857 WI-2: wake-target recording is codex-only (app-server bridge).
753
- // OpenCode uses HTTP entry injection; Claude uses the inbox Monitor.
754
- if (cli === 'codex' && active && codexSocketPath) {
755
- void recordCodexWakeTarget({
756
- deps: { setCodexWakeTarget, findLoadedCodexThread },
757
- cubeId: active.cubeId,
758
- droneId: active.droneId,
759
- socketPath: codexSocketPath,
760
- passthroughArgs,
761
- previewNeedle: codexWakeNonce ?? kickoff.slice(0, 120),
762
- cwd: process.cwd(),
763
- launchedAtSeconds: Math.floor(Date.now() / 1000),
764
- });
765
- // gh#855: self-heal the wake-target file — drop entries whose app-server
766
- // socket is positively dead (crashed prior launches), mirroring the
767
- // socket-dir pruneStaleSockets. Best-effort; never blocks the launch.
768
- void pruneDeadCodexWakeTargets((sock) => checkCodexBridgeHealthy(sock));
769
- }
770
-
771
724
  agentProcess.on('error', (err: NodeJS.ErrnoException) => {
772
725
  if (codexServerCleanup) {
773
726
  try {
@@ -7,6 +7,10 @@ export interface CodexThreadSummary {
7
7
  preview: string;
8
8
  status: { type: string };
9
9
  updatedAt: number;
10
+ source?: unknown;
11
+ ephemeral?: boolean;
12
+ threadSource?: string;
13
+ turns?: unknown[];
10
14
  }
11
15
 
12
16
  interface PendingRequest {
@@ -85,6 +89,10 @@ export class CodexAppServerClient {
85
89
  preview: thread.preview,
86
90
  status: thread.status,
87
91
  updatedAt: thread.updatedAt,
92
+ source: thread.source,
93
+ ephemeral: thread.ephemeral,
94
+ threadSource: thread.threadSource,
95
+ turns: thread.turns,
88
96
  };
89
97
  }
90
98
 
@@ -159,31 +167,6 @@ export class CodexAppServerClient {
159
167
  }
160
168
  }
161
169
 
162
- export async function findLoadedCodexThread(options: {
163
- socketPath: string;
164
- cwd: string;
165
- previewIncludes: string;
166
- updatedAfter: number;
167
- }): Promise<string | null> {
168
- const client = new CodexAppServerClient(options.socketPath);
169
- await client.connect();
170
- try {
171
- const ids = await client.loadedThreadIds();
172
- let best: CodexThreadSummary | null = null;
173
- for (const id of ids) {
174
- const thread = await client.readThread(id);
175
- if (!thread) continue;
176
- if (thread.cwd !== options.cwd) continue;
177
- if (!thread.preview.includes(options.previewIncludes)) continue;
178
- if (thread.updatedAt < options.updatedAfter) continue;
179
- if (!best || thread.updatedAt > best.updatedAt) best = thread;
180
- }
181
- return best?.id ?? null;
182
- } finally {
183
- client.close();
184
- }
185
- }
186
-
187
170
  function encodeWebSocketTextFrame(text: string): Buffer {
188
171
  const payload = Buffer.from(text);
189
172
  let header: Buffer;