borgmcp 2.14.2 → 2.16.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/dist/agent-runtime.d.ts +5 -0
- package/dist/agent-runtime.d.ts.map +1 -1
- package/dist/agent-runtime.js +14 -0
- package/dist/agent-runtime.js.map +1 -1
- package/dist/assimilate-cmd.d.ts +5 -0
- package/dist/assimilate-cmd.d.ts.map +1 -1
- package/dist/assimilate-cmd.js +53 -14
- package/dist/assimilate-cmd.js.map +1 -1
- package/dist/assimilate-deps.d.ts.map +1 -1
- package/dist/assimilate-deps.js +19 -4
- package/dist/assimilate-deps.js.map +1 -1
- package/dist/bare-launch-menu.d.ts +8 -0
- package/dist/bare-launch-menu.d.ts.map +1 -1
- package/dist/bare-launch-menu.js +12 -0
- package/dist/bare-launch-menu.js.map +1 -1
- package/dist/claude.d.ts.map +1 -1
- package/dist/claude.js +28 -40
- package/dist/claude.js.map +1 -1
- package/dist/cleanup-cmd.d.ts.map +1 -1
- package/dist/cleanup-cmd.js +2 -2
- package/dist/cleanup-cmd.js.map +1 -1
- package/dist/cli-tool-approval.d.ts.map +1 -1
- package/dist/cli-tool-approval.js +3 -2
- package/dist/cli-tool-approval.js.map +1 -1
- package/dist/codex-remote.d.ts.map +1 -1
- package/dist/codex-remote.js +4 -3
- package/dist/codex-remote.js.map +1 -1
- package/dist/config-utils.d.ts +16 -1
- package/dist/config-utils.d.ts.map +1 -1
- package/dist/config-utils.js +176 -17
- package/dist/config-utils.js.map +1 -1
- package/dist/credential-paths.d.ts.map +1 -1
- package/dist/credential-paths.js +2 -3
- package/dist/credential-paths.js.map +1 -1
- package/dist/cubes.d.ts +6 -1
- package/dist/cubes.d.ts.map +1 -1
- package/dist/cubes.js +9 -4
- package/dist/cubes.js.map +1 -1
- package/dist/foreign-path-reminder.d.ts +12 -0
- package/dist/foreign-path-reminder.d.ts.map +1 -0
- package/dist/foreign-path-reminder.js +122 -0
- package/dist/foreign-path-reminder.js.map +1 -0
- package/dist/launch-access.d.ts +22 -0
- package/dist/launch-access.d.ts.map +1 -0
- package/dist/launch-access.js +27 -0
- package/dist/launch-access.js.map +1 -0
- package/dist/launch-all-deps.d.ts.map +1 -1
- package/dist/launch-all-deps.js +2 -2
- package/dist/launch-all-deps.js.map +1 -1
- package/dist/lifecycle-log-guard.js +2 -2
- package/dist/lifecycle-log-guard.js.map +1 -1
- package/dist/local-server-cursor.js +2 -2
- package/dist/local-server-cursor.js.map +1 -1
- package/dist/opencode-plugin.js +2 -2
- package/dist/opencode-plugin.js.map +1 -1
- package/dist/parse-assimilate-args.d.ts.map +1 -1
- package/dist/parse-assimilate-args.js +6 -1
- package/dist/parse-assimilate-args.js.map +1 -1
- package/dist/private-root.d.ts +17 -0
- package/dist/private-root.d.ts.map +1 -1
- package/dist/private-root.js +62 -2
- package/dist/private-root.js.map +1 -1
- package/dist/regen-format.js +1 -1
- package/dist/regen-format.js.map +1 -1
- package/dist/resolved-cli-config.d.ts +16 -0
- package/dist/resolved-cli-config.d.ts.map +1 -0
- package/dist/resolved-cli-config.js +26 -0
- package/dist/resolved-cli-config.js.map +1 -0
- package/dist/seat-store.d.ts.map +1 -1
- package/dist/seat-store.js +4 -3
- package/dist/seat-store.js.map +1 -1
- package/dist/seats.d.ts.map +1 -1
- package/dist/seats.js +2 -2
- package/dist/seats.js.map +1 -1
- package/dist/self-path.d.ts +2 -0
- package/dist/self-path.d.ts.map +1 -1
- package/dist/self-path.js +4 -0
- package/dist/self-path.js.map +1 -1
- package/dist/server-trust.d.ts.map +1 -1
- package/dist/server-trust.js +3 -3
- package/dist/server-trust.js.map +1 -1
- package/dist/setup-confirm.d.ts +1 -1
- package/dist/setup-confirm.js +1 -1
- package/dist/setup-selection.d.ts +38 -0
- package/dist/setup-selection.d.ts.map +1 -0
- package/dist/setup-selection.js +51 -0
- package/dist/setup-selection.js.map +1 -0
- package/dist/setup.js +80 -21
- package/dist/setup.js.map +1 -1
- package/dist/stream-owner.js +2 -2
- package/dist/stream-owner.js.map +1 -1
- package/docs/EXTRACTION_PROVENANCE.md +3 -3
- package/docs/LOCAL_SERVER.md +23 -0
- package/docs/RELEASING.md +130 -282
- package/package.json +9 -9
- package/src/agent-runtime.ts +17 -0
- package/src/assimilate-cmd.ts +73 -14
- package/src/assimilate-deps.ts +23 -3
- package/src/bare-launch-menu.ts +17 -0
- package/src/claude.ts +31 -37
- package/src/cleanup-cmd.ts +2 -2
- package/src/cli-tool-approval.ts +3 -2
- package/src/codex-remote.ts +4 -2
- package/src/config-utils.ts +186 -18
- package/src/credential-paths.ts +2 -3
- package/src/cubes.ts +9 -4
- package/src/foreign-path-reminder.ts +141 -0
- package/src/launch-access.ts +40 -0
- package/src/launch-all-deps.ts +2 -2
- package/src/lifecycle-log-guard.ts +2 -2
- package/src/local-server-cursor.ts +2 -2
- package/src/opencode-plugin.ts +2 -2
- package/src/parse-assimilate-args.ts +7 -1
- package/src/private-root.ts +62 -2
- package/src/regen-format.ts +1 -1
- package/src/resolved-cli-config.ts +40 -0
- package/src/seat-store.ts +4 -3
- package/src/seats.ts +2 -2
- package/src/self-path.ts +5 -0
- package/src/server-trust.ts +3 -3
- package/src/setup-confirm.ts +1 -1
- package/src/setup-selection.ts +87 -0
- package/src/setup.ts +98 -24
- package/src/stream-owner.ts +2 -2
package/src/assimilate-cmd.ts
CHANGED
|
@@ -23,6 +23,7 @@ import { codexBorgSessionConfigArgs } from './launch-gate.js';
|
|
|
23
23
|
import {
|
|
24
24
|
codexAgentKindConfigArgs,
|
|
25
25
|
codexRemoteWakeConfigArgs,
|
|
26
|
+
codexStateRootConfigArgs,
|
|
26
27
|
withAgentRuntimeEnv,
|
|
27
28
|
} from './agent-runtime.js';
|
|
28
29
|
import type { BorgCli } from './cubes.js';
|
|
@@ -74,6 +75,14 @@ import type { SeatBinding, BindPendingSeatOutcome } from './seats.js';
|
|
|
74
75
|
import { createHash } from 'node:crypto';
|
|
75
76
|
import { buildOpenCodeLaunchArgs, type LaunchApprovalDecision } from './cli-tool-approval.js';
|
|
76
77
|
import { resolveWorkingRepo, type WorkingRepo } from './working-repo.js';
|
|
78
|
+
import {
|
|
79
|
+
BORG_LAUNCH_CLI_ENV,
|
|
80
|
+
BORG_LAUNCH_SCRATCH_ENV,
|
|
81
|
+
BORG_LAUNCH_WORKTREE_ENV,
|
|
82
|
+
codexLaunchDirectoryArgs,
|
|
83
|
+
scratchRootForSeat,
|
|
84
|
+
type LaunchAccessPaths,
|
|
85
|
+
} from './launch-access.js';
|
|
77
86
|
import type {
|
|
78
87
|
AssociateRepositoryCubeResponse,
|
|
79
88
|
CreateCubeRepository,
|
|
@@ -287,6 +296,12 @@ export interface AssimilateDeps {
|
|
|
287
296
|
// launch root's .claude/settings.local.json (project-local; idempotent).
|
|
288
297
|
// Real wiring = config-utils addProjectSessionStartHook.
|
|
289
298
|
installProjectSessionHook: (projectRoot: string) => void;
|
|
299
|
+
/** Pre-authorize only the launched seat's worktree + scratch paths. */
|
|
300
|
+
provisionLaunchAccess?: (
|
|
301
|
+
cli: BorgCli,
|
|
302
|
+
projectRoot: string,
|
|
303
|
+
paths: LaunchAccessPaths,
|
|
304
|
+
) => void;
|
|
290
305
|
|
|
291
306
|
/** gh#27: optional test seam — when set, selectAssimilationAuthority uses
|
|
292
307
|
* this instead of prompting/failing. Not wired in production. */
|
|
@@ -373,6 +388,8 @@ export interface AssimilateDeps {
|
|
|
373
388
|
// on healthy hosts; degraded-path surfaces a stderr warning and
|
|
374
389
|
// still launches claude (never blocks).
|
|
375
390
|
probeMcpReady: () => Promise<boolean>;
|
|
391
|
+
/** Save the resolved CLI for a newly-created sibling worktree. */
|
|
392
|
+
setCliPreferenceForWorktree: (cli: BorgCli, worktree: string) => Promise<void>;
|
|
376
393
|
resolveCli: (explicit?: BorgCli) => Promise<BorgCli>;
|
|
377
394
|
prepareCodexRemoteLaunch: () => Promise<CodexRemoteLaunch>;
|
|
378
395
|
setCodexWakeTarget: (cubeId: string, droneId: string, target: { threadId: string; socketPath: string }) => Promise<void>;
|
|
@@ -693,13 +710,10 @@ export async function runAssimilate(
|
|
|
693
710
|
): Promise<number> {
|
|
694
711
|
const mode = args.mode ?? 'assimilate';
|
|
695
712
|
// ----- Input validation (before any subprocess work) -----
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
return 1;
|
|
701
|
-
}
|
|
702
|
-
}
|
|
713
|
+
// A role is a lookup key, not a path component. matchRoleByName() below
|
|
714
|
+
// applies the shared roleSlug() normalization, so displayed names such as
|
|
715
|
+
// "Builder" and "Code Reviewer" must reach that resolver. Keep the strict
|
|
716
|
+
// identifier validator for worktree names, which do become path components.
|
|
703
717
|
if (args.flags.worktree !== undefined) {
|
|
704
718
|
const v = validateName(args.flags.worktree);
|
|
705
719
|
if (!v.ok) {
|
|
@@ -1807,6 +1821,22 @@ export async function runAssimilate(
|
|
|
1807
1821
|
spawnedWorktreePath = deps.cwd();
|
|
1808
1822
|
}
|
|
1809
1823
|
|
|
1824
|
+
// ----- Step 7b: provision launch access before persisting/launching -----
|
|
1825
|
+
// The launched process gets exactly its current worktree plus a stable,
|
|
1826
|
+
// disposable per-seat scratch root. Provision this before FINALIZE so a
|
|
1827
|
+
// failed config write cannot produce a saved seat that launches without
|
|
1828
|
+
// its promised path grants.
|
|
1829
|
+
const agentCwd = deps.cwd(); // post-chdir if step 3 spawned a worktree
|
|
1830
|
+
const seatWorktree = deps.findProjectRoot(agentCwd);
|
|
1831
|
+
const monitorStateRoot = monitorStateRootForWorktree(seatWorktree);
|
|
1832
|
+
const scratchRoot = scratchRootForSeat(deps.homedir(), result.drone_label, result.drone_id);
|
|
1833
|
+
const launchAccessPaths: LaunchAccessPaths = {
|
|
1834
|
+
// Access is granted at the repository root even when the harness starts in
|
|
1835
|
+
// a nested package. The launch cwd remains the operator's chosen subdir.
|
|
1836
|
+
worktree: seatWorktree,
|
|
1837
|
+
scratch: scratchRoot,
|
|
1838
|
+
};
|
|
1839
|
+
|
|
1810
1840
|
// ----- Step 8: persist the binding (narrow rollback — worktree exists if spawned) -----
|
|
1811
1841
|
const activeCube: ActiveCube = {
|
|
1812
1842
|
cubeId: result.cube_id,
|
|
@@ -1836,6 +1866,37 @@ export async function runAssimilate(
|
|
|
1836
1866
|
}
|
|
1837
1867
|
};
|
|
1838
1868
|
|
|
1869
|
+
// CLI resolution happens before the server attach because agent_kind is part
|
|
1870
|
+
// of that request. The resolver therefore saved the preference against the
|
|
1871
|
+
// invoking checkout. Once a sibling exists, save the same choice under its
|
|
1872
|
+
// own project key so a later --here launch in that worktree can read it.
|
|
1873
|
+
if (spawnedWorktreePath) {
|
|
1874
|
+
try {
|
|
1875
|
+
await deps.setCliPreferenceForWorktree(cli, spawnedWorktreePath);
|
|
1876
|
+
} catch (err) {
|
|
1877
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1878
|
+
deps.stderr(
|
|
1879
|
+
`Borg could not save the ${cli} preference for sibling worktree ${spawnedWorktreePath}: ${message}. ` +
|
|
1880
|
+
'The worktree was removed; correct the local configuration and retry.\n',
|
|
1881
|
+
);
|
|
1882
|
+
rollbackWorktree();
|
|
1883
|
+
return 1;
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
try {
|
|
1888
|
+
deps.mkdirp(scratchRoot);
|
|
1889
|
+
deps.provisionLaunchAccess?.(cli, seatWorktree, launchAccessPaths);
|
|
1890
|
+
} catch (err) {
|
|
1891
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1892
|
+
deps.stderr(
|
|
1893
|
+
`Borg could not pre-authorize the ${cli} launch paths: ${message}. ` +
|
|
1894
|
+
'No agent was launched; correct the local configuration and retry.\n',
|
|
1895
|
+
);
|
|
1896
|
+
rollbackWorktree();
|
|
1897
|
+
return 1;
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1839
1900
|
// Local-server authority: drive the COMPOSITE cube-owned FINALIZE (Race 2).
|
|
1840
1901
|
// The cube lock is held OUTER across revalidate → binding-write → activate; the
|
|
1841
1902
|
// typed expectation is declared HERE at the orchestration layer (reattach =
|
|
@@ -1945,13 +2006,6 @@ export async function runAssimilate(
|
|
|
1945
2006
|
}
|
|
1946
2007
|
}
|
|
1947
2008
|
|
|
1948
|
-
// The worktree, not a reminted drone UUID, is the stable local seat identity
|
|
1949
|
-
// for monitor runtime state. Capture it once before the lazy GC and launch
|
|
1950
|
-
// paths so both use the exact same explicit root.
|
|
1951
|
-
const agentCwd = deps.cwd(); // post-chdir if step 3 spawned a worktree
|
|
1952
|
-
const seatWorktree = deps.findProjectRoot(agentCwd);
|
|
1953
|
-
const monitorStateRoot = monitorStateRootForWorktree(seatWorktree);
|
|
1954
|
-
|
|
1955
2009
|
// gh#793: best-effort GC of orphaned inbox files (evicted/dead drones) in the
|
|
1956
2010
|
// cube just joined — lazy-on-assimilate, no cron/new command. NEVER blocks or
|
|
1957
2011
|
// fails the assimilate (whole call swallowed). Local-only signal (CubeDetail
|
|
@@ -2082,6 +2136,9 @@ export async function runAssimilate(
|
|
|
2082
2136
|
...(withAgentRuntimeEnv(process.env, cli) as Record<string, string>),
|
|
2083
2137
|
...modelEnv.set,
|
|
2084
2138
|
BORG_SESSION: '1',
|
|
2139
|
+
[BORG_LAUNCH_CLI_ENV]: cli,
|
|
2140
|
+
[BORG_LAUNCH_WORKTREE_ENV]: seatWorktree,
|
|
2141
|
+
[BORG_LAUNCH_SCRATCH_ENV]: scratchRoot,
|
|
2085
2142
|
};
|
|
2086
2143
|
if (cli === 'opencode' && launchApproval.openCodePermission) {
|
|
2087
2144
|
childEnv.OPENCODE_PERMISSION = launchApproval.openCodePermission;
|
|
@@ -2127,10 +2184,12 @@ export async function runAssimilate(
|
|
|
2127
2184
|
// off when no socket is available, overriding legacy static configs that
|
|
2128
2185
|
// formerly used this transport marker as Codex identity.
|
|
2129
2186
|
launchArgs = [
|
|
2187
|
+
...codexLaunchDirectoryArgs(launchAccessPaths),
|
|
2130
2188
|
...launchApproval.codexArgs,
|
|
2131
2189
|
...codexBorgSessionConfigArgs(),
|
|
2132
2190
|
...codexAgentKindConfigArgs(),
|
|
2133
2191
|
...codexRemoteWakeConfigArgs(codexSocketPath !== null),
|
|
2192
|
+
...codexStateRootConfigArgs(),
|
|
2134
2193
|
...remoteArgs,
|
|
2135
2194
|
...withCodexCwdArg(launchArgs, agentCwd),
|
|
2136
2195
|
];
|
package/src/assimilate-deps.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import { spawnSync, spawn as spawnChild } from 'node:child_process';
|
|
12
12
|
import { randomBytes } from 'node:crypto';
|
|
13
13
|
import { existsSync, mkdirSync } from 'node:fs';
|
|
14
|
-
import { hostname as osHostname
|
|
14
|
+
import { hostname as osHostname } from 'node:os';
|
|
15
15
|
import { createInterface } from 'node:readline/promises';
|
|
16
16
|
import prompts from 'prompts';
|
|
17
17
|
import { readinessProbeEnv } from './readiness-probe.js';
|
|
@@ -60,9 +60,16 @@ import {
|
|
|
60
60
|
hasPersistedActiveCube as cubesHasPersistedActive,
|
|
61
61
|
setActiveCube as cubesSetActive,
|
|
62
62
|
inboxPathForDrone,
|
|
63
|
+
setProjectCliPreference,
|
|
63
64
|
setCodexWakeTarget,
|
|
64
65
|
} from './cubes.js';
|
|
65
|
-
import {
|
|
66
|
+
import {
|
|
67
|
+
addClaudeLaunchAccess,
|
|
68
|
+
addCodexForeignPathReminderHook,
|
|
69
|
+
addOpenCodeLaunchAccess,
|
|
70
|
+
addProjectSessionStartHook,
|
|
71
|
+
} from './config-utils.js';
|
|
72
|
+
import type { LaunchAccessPaths } from './launch-access.js';
|
|
66
73
|
import { findPendingServerEnrollment } from './config.js';
|
|
67
74
|
import { setTerminalTitle as setTitle } from './terminal-title.js';
|
|
68
75
|
import { defaultCliChoiceDeps, resolveCliChoice } from './cli-platform.js';
|
|
@@ -77,6 +84,7 @@ import {
|
|
|
77
84
|
saveRepositoryAssociation,
|
|
78
85
|
} from './repository-identity.js';
|
|
79
86
|
import { PromptInterruptedError } from './repository-cube-init.js';
|
|
87
|
+
import { borgHomeRoot } from './private-root.js';
|
|
80
88
|
|
|
81
89
|
/**
|
|
82
90
|
* Wraps the readline question operation with the production interruption
|
|
@@ -126,7 +134,7 @@ export function buildDefaultAssimilateDeps(
|
|
|
126
134
|
// gh#556 Part 1: ~/.borg/worktrees relocation. homedir seams $HOME;
|
|
127
135
|
// mkdirp is a plain recursive create (NO chmod of existing parents — the
|
|
128
136
|
// ~/.borg credentials file's perms stay untouched).
|
|
129
|
-
homedir: () =>
|
|
137
|
+
homedir: () => borgHomeRoot(),
|
|
130
138
|
mkdirp: (dir) => mkdirSync(dir, { recursive: true }),
|
|
131
139
|
preparePrivateRoot: () => ensurePrivateBorgConfigRoot(),
|
|
132
140
|
exec: (cmd, args, cwd, env) =>
|
|
@@ -235,6 +243,17 @@ export function buildDefaultAssimilateDeps(
|
|
|
235
243
|
installProjectSessionHook: (projectRoot) => {
|
|
236
244
|
addProjectSessionStartHook(projectRoot);
|
|
237
245
|
},
|
|
246
|
+
provisionLaunchAccess: (cli, projectRoot, paths: LaunchAccessPaths) => {
|
|
247
|
+
if (cli === 'claude') {
|
|
248
|
+
addClaudeLaunchAccess(projectRoot, paths);
|
|
249
|
+
} else if (cli === 'codex') {
|
|
250
|
+
// Codex receives the path grant on the launch command itself. Its
|
|
251
|
+
// native PreToolUse hook is global but reads this launch's scoped env.
|
|
252
|
+
addCodexForeignPathReminderHook();
|
|
253
|
+
} else {
|
|
254
|
+
addOpenCodeLaunchAccess(projectRoot, paths);
|
|
255
|
+
}
|
|
256
|
+
},
|
|
238
257
|
|
|
239
258
|
// #1015: discovery is advisory but still verifies the server-owned CA.
|
|
240
259
|
detectLocalServer: async () =>
|
|
@@ -557,6 +576,7 @@ export function buildDefaultAssimilateDeps(
|
|
|
557
576
|
}
|
|
558
577
|
}, () => process.stdin.isTTY === true)
|
|
559
578
|
),
|
|
579
|
+
setCliPreferenceForWorktree: (cli, worktree) => setProjectCliPreference(cli, worktree),
|
|
560
580
|
prepareCodexRemoteLaunch: () => prepareCodexRemoteLaunch(defaultCodexRemoteDeps()),
|
|
561
581
|
setCodexWakeTarget,
|
|
562
582
|
findLoadedCodexThread,
|
package/src/bare-launch-menu.ts
CHANGED
|
@@ -39,6 +39,23 @@ export interface LaunchMenuInputs {
|
|
|
39
39
|
hasLaunchAllTargets: boolean;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Resolve and configure the CLI that will actually launch.
|
|
44
|
+
*
|
|
45
|
+
* This callback deliberately runs after the one-shot menu choice. A bare
|
|
46
|
+
* launch may resolve one default CLI first and then launch a different
|
|
47
|
+
* installed CLI for this invocation; only the final CLI may be self-healed.
|
|
48
|
+
*/
|
|
49
|
+
export function configureSelectedLaunchCli(
|
|
50
|
+
defaultCli: BorgCli,
|
|
51
|
+
action: LaunchMenuAction | undefined,
|
|
52
|
+
configure: (cli: BorgCli) => void,
|
|
53
|
+
): BorgCli {
|
|
54
|
+
const cli = action?.kind === 'launch' ? action.cli : defaultCli;
|
|
55
|
+
configure(cli);
|
|
56
|
+
return cli;
|
|
57
|
+
}
|
|
58
|
+
|
|
42
59
|
const PRETTY: Record<BorgCli, string> = { claude: 'Claude', codex: 'Codex', opencode: 'OpenCode' };
|
|
43
60
|
|
|
44
61
|
/**
|
package/src/claude.ts
CHANGED
|
@@ -24,7 +24,7 @@ import { basename } from 'node:path';
|
|
|
24
24
|
import { createInterface } from 'node:readline/promises';
|
|
25
25
|
import { fileURLToPath } from 'node:url';
|
|
26
26
|
import chalk from 'chalk';
|
|
27
|
-
import { findProjectRoot, getActiveCube, inboxPathForDrone, setCodexWakeTarget, pruneDeadCodexWakeTargets } from './cubes.js';
|
|
27
|
+
import { findProjectRoot, getActiveCube, inboxPathForDrone, setCodexWakeTarget, pruneDeadCodexWakeTargets, type BorgCli } from './cubes.js';
|
|
28
28
|
import { monitorStateRootForWorktree } from './inbox-monitor.js';
|
|
29
29
|
import { formatSeatReattachRefusal, inspectLiveInboxMonitor } from './seat-reattach-guard.js';
|
|
30
30
|
import { handleVersionFlag, getPackageVersion } from './version.js';
|
|
@@ -48,10 +48,12 @@ import { runLaunchAll } from './launch-all-cmd.js';
|
|
|
48
48
|
import { buildDefaultLaunchAllDeps } from './launch-all-deps.js';
|
|
49
49
|
import { discoverDroneCandidates } from './launch-all-discovery.js';
|
|
50
50
|
import {
|
|
51
|
+
configureSelectedLaunchCli,
|
|
51
52
|
explicitCliLaunchHint,
|
|
52
53
|
runBareLaunchMenu,
|
|
53
54
|
shouldResolveExplicitCliLaunchHintTargets,
|
|
54
55
|
shouldShowLaunchMenu,
|
|
56
|
+
type LaunchMenuAction,
|
|
55
57
|
} from './bare-launch-menu.js';
|
|
56
58
|
import { setTerminalTitle } from './terminal-title.js';
|
|
57
59
|
import { initConsolePrefix, consolePrefix } from './console-prefix.js';
|
|
@@ -62,6 +64,7 @@ import {
|
|
|
62
64
|
BORG_CODEX_REMOTE_WAKE_ENV,
|
|
63
65
|
codexAgentKindConfigArgs,
|
|
64
66
|
codexRemoteWakeConfigArgs,
|
|
67
|
+
codexStateRootConfigArgs,
|
|
65
68
|
withAgentRuntimeEnv,
|
|
66
69
|
} from './agent-runtime.js';
|
|
67
70
|
import { findLoadedCodexThread } from './codex-app-server.js';
|
|
@@ -80,6 +83,7 @@ import {
|
|
|
80
83
|
removeSessionStartHook,
|
|
81
84
|
} from './config-utils.js';
|
|
82
85
|
import { ensureCliMcpConfigured } from './ensure-mcp-config.js';
|
|
86
|
+
import { configureResolvedCli } from './resolved-cli-config.js';
|
|
83
87
|
import { installBorgPlugin } from './opencode-plugin.js';
|
|
84
88
|
import { allocateOpenCodePort, connectOpenCodeDrone, createOpenCodeLaunchKickoff, injectInitialKickoff, openCodeLaunchBinding } from './opencode-drone.js';
|
|
85
89
|
import { buildOpenCodeLaunchArgs, defaultApprovalIo, resolveLaunchBorgApprovals } from './cli-tool-approval.js';
|
|
@@ -321,7 +325,7 @@ async function main() {
|
|
|
321
325
|
parsedCli.cli,
|
|
322
326
|
defaultCliChoiceDeps(prompt, () => process.stdin.isTTY === true)
|
|
323
327
|
);
|
|
324
|
-
|
|
328
|
+
let launchAction: LaunchMenuAction | undefined;
|
|
325
329
|
|
|
326
330
|
// Active cube for this directory — needed for the launch menu's option-3
|
|
327
331
|
// availability, the terminal title, and the inbox-Monitor clause below.
|
|
@@ -382,9 +386,13 @@ async function main() {
|
|
|
382
386
|
// option 1 → configured default; option 2 → the other agent, ONE-SHOT
|
|
383
387
|
// (we deliberately do NOT call setProjectCliPreference — the saved
|
|
384
388
|
// preference is changed only via `borg --cli <agent>`).
|
|
385
|
-
|
|
389
|
+
launchAction = action;
|
|
386
390
|
}
|
|
387
391
|
|
|
392
|
+
// Configure only the CLI that will actually launch. This must follow the
|
|
393
|
+
// one-shot menu: the resolved default can differ from the menu selection.
|
|
394
|
+
cli = configureSelectedLaunchCli(cli, launchAction, ensureResolvedCliConfigured);
|
|
395
|
+
|
|
388
396
|
if (active && !parsedCli.force) {
|
|
389
397
|
const inboxPath = inboxPathForDrone(active.cubeId, active.droneId);
|
|
390
398
|
const stateRoot = monitorStateRootForWorktree(findProjectRoot(process.cwd()));
|
|
@@ -531,6 +539,7 @@ async function main() {
|
|
|
531
539
|
...codexBorgSessionConfigArgs(),
|
|
532
540
|
...codexAgentKindConfigArgs(),
|
|
533
541
|
...codexRemoteWakeConfigArgs(codexSocketPath !== null),
|
|
542
|
+
...codexStateRootConfigArgs(),
|
|
534
543
|
...remoteArgs,
|
|
535
544
|
...withCodexCwdArg([...passthroughArgs, kickoff], process.cwd()),
|
|
536
545
|
];
|
|
@@ -614,40 +623,25 @@ async function main() {
|
|
|
614
623
|
});
|
|
615
624
|
}
|
|
616
625
|
|
|
617
|
-
function
|
|
618
|
-
const
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
ensureCliMcpConfigured
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
if (found.codex) {
|
|
637
|
-
try {
|
|
638
|
-
ensureCliMcpConfigured('codex');
|
|
639
|
-
addCodexSessionStartHook();
|
|
640
|
-
addCodexUserPromptSubmitHook();
|
|
641
|
-
} catch (err: any) {
|
|
642
|
-
console.error(`${consolePrefix()}${chalk.yellow(`warning: Codex integration check failed: ${err?.message ?? err}`)}`);
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
if (found.opencode) {
|
|
646
|
-
try {
|
|
647
|
-
ensureCliMcpConfigured('opencode');
|
|
648
|
-
} catch (err: any) {
|
|
649
|
-
console.error(`${consolePrefix()}${chalk.yellow(`warning: OpenCode integration check failed: ${err?.message ?? err}`)}`);
|
|
650
|
-
}
|
|
626
|
+
function ensureResolvedCliConfigured(cli: BorgCli): void {
|
|
627
|
+
const label = cli === 'claude' ? 'Claude Code' : cli === 'codex' ? 'Codex' : 'OpenCode';
|
|
628
|
+
try {
|
|
629
|
+
configureResolvedCli(cli, {
|
|
630
|
+
ensureMcp: ensureCliMcpConfigured,
|
|
631
|
+
addClaudeProjectSessionStartHook: () => {
|
|
632
|
+
// gh#673 P2 (WI-1): the orientation hook lives PROJECT-LOCAL in
|
|
633
|
+
// <root>/.claude/settings.local.json — ensured on every bare
|
|
634
|
+
// `borg` launch so pre-P2 worktrees self-heal. The legacy GLOBAL
|
|
635
|
+
// hook is then removed after the local hook is in place.
|
|
636
|
+
addProjectSessionStartHook(findProjectRoot(process.cwd()));
|
|
637
|
+
},
|
|
638
|
+
removeClaudeGlobalSessionStartHook: removeSessionStartHook,
|
|
639
|
+
addClaudeUserPromptSubmitHook: addUserPromptSubmitHook,
|
|
640
|
+
addCodexSessionStartHook,
|
|
641
|
+
addCodexUserPromptSubmitHook,
|
|
642
|
+
});
|
|
643
|
+
} catch (err: any) {
|
|
644
|
+
console.error(`${consolePrefix()}${chalk.yellow(`warning: ${label} integration check failed: ${err?.message ?? err}`)}`);
|
|
651
645
|
}
|
|
652
646
|
}
|
|
653
647
|
|
package/src/cleanup-cmd.ts
CHANGED
|
@@ -36,7 +36,6 @@
|
|
|
36
36
|
import { spawnSync } from 'node:child_process';
|
|
37
37
|
import { realpathSync } from 'node:fs';
|
|
38
38
|
import { sep, basename, dirname } from 'node:path';
|
|
39
|
-
import { homedir } from 'node:os';
|
|
40
39
|
import chalk from 'chalk';
|
|
41
40
|
import {
|
|
42
41
|
classifyDirty,
|
|
@@ -51,6 +50,7 @@ import {
|
|
|
51
50
|
type ActiveCube,
|
|
52
51
|
} from './cubes.js';
|
|
53
52
|
import { defaultProbeSeat, type SeatStatus } from './seat-probe.js';
|
|
53
|
+
import { borgHomeRoot } from './private-root.js';
|
|
54
54
|
|
|
55
55
|
// ------------------------------------------------------------------
|
|
56
56
|
// Types
|
|
@@ -208,7 +208,7 @@ const defaultDeps: Required<CleanupDeps> = {
|
|
|
208
208
|
const r = spawnSync(cmd, args, { cwd, encoding: 'utf-8' });
|
|
209
209
|
return { status: r.status, stdout: r.stdout ?? '', stderr: r.stderr ?? '' };
|
|
210
210
|
},
|
|
211
|
-
homeDir: () =>
|
|
211
|
+
homeDir: () => borgHomeRoot(),
|
|
212
212
|
cwd: () => process.cwd(),
|
|
213
213
|
listSeats: () => readAllProjectIdentities(),
|
|
214
214
|
probeSeat: defaultProbeSeat,
|
package/src/cli-tool-approval.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { spawn, spawnSync } from 'node:child_process';
|
|
2
2
|
import { chmod, copyFile, mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
3
|
-
import {
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
4
|
import { dirname, join, resolve } from 'node:path';
|
|
5
5
|
import type { BorgCli } from './cubes.js';
|
|
6
|
+
import { borgHomeRoot } from './private-root.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Client #20: the narrow coordination surface a borg-launched agent needs
|
|
@@ -360,7 +361,7 @@ async function withNativeCodexProfileLayer<T>(
|
|
|
360
361
|
env: NodeJS.ProcessEnv,
|
|
361
362
|
query: (profileCwd: string, trustOverride: string) => Promise<CodexConfigSnapshot>
|
|
362
363
|
): Promise<T> {
|
|
363
|
-
const codexHome = resolve(env.CODEX_HOME || join(
|
|
364
|
+
const codexHome = resolve(env.CODEX_HOME || join(borgHomeRoot(), '.codex'));
|
|
364
365
|
const profilePath = resolve(codexHome, `${profile}.config.toml`);
|
|
365
366
|
if (dirname(profilePath) !== codexHome) {
|
|
366
367
|
throw new Error('Codex profile path was invalid');
|
package/src/codex-remote.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { mkdirSync, chmodSync, readdirSync, rmSync, writeFileSync, readFileSync } from 'node:fs';
|
|
2
|
-
import { homedir } from 'node:os';
|
|
3
2
|
import { join, resolve } from 'node:path';
|
|
4
3
|
import { randomBytes } from 'node:crypto';
|
|
5
4
|
import { spawn } from 'node:child_process';
|
|
@@ -11,7 +10,9 @@ import {
|
|
|
11
10
|
BORG_CODEX_REMOTE_WAKE_ENV,
|
|
12
11
|
codexAgentKindConfigArgs,
|
|
13
12
|
codexRemoteWakeConfigArgs,
|
|
13
|
+
codexStateRootConfigArgs,
|
|
14
14
|
} from './agent-runtime.js';
|
|
15
|
+
import { borgConfigRoot } from './private-root.js';
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* gh#528 — npm-managed Codex remote-wake.
|
|
@@ -75,7 +76,7 @@ export interface PrepareCodexRemoteDeps {
|
|
|
75
76
|
isAlive?: (pid: number) => boolean;
|
|
76
77
|
}
|
|
77
78
|
|
|
78
|
-
export const DEFAULT_CODEX_REMOTE_DIR = join(
|
|
79
|
+
export const DEFAULT_CODEX_REMOTE_DIR = join(borgConfigRoot(), 'codex-remote');
|
|
79
80
|
const DEFAULT_CODEX_REMOTE_READY_TIMEOUT_MS = 30_000;
|
|
80
81
|
const MAX_CODEX_APP_SERVER_STDERR_CHARS = 16_384;
|
|
81
82
|
|
|
@@ -426,6 +427,7 @@ export function defaultCodexRemoteDeps(): Pick<
|
|
|
426
427
|
...codexBorgSessionConfigArgs(),
|
|
427
428
|
...codexAgentKindConfigArgs(),
|
|
428
429
|
...codexRemoteWakeConfigArgs(),
|
|
430
|
+
...codexStateRootConfigArgs(),
|
|
429
431
|
...codexAppServerSocketConfigArgs(socketPath),
|
|
430
432
|
'--listen',
|
|
431
433
|
`unix://${socketPath}`,
|