@miraland-labs/conduit-bridge 0.9.9 → 0.9.11
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 +1 -1
- package/dist/driver.js +33 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Local Bridge CLI for [Conduit](https://github.com/miralandlabs/conduit). Connects a computer to one organization, claims work, and drives a local agent.
|
|
4
4
|
|
|
5
|
-
**Package version:** `0.9.
|
|
5
|
+
**Package version:** `0.9.11` — heartbeat protocol 2 requires a clean workspace plus a ready, versioned driver lane before dispatch. Cursor assignments with `external_network` allow-list `WebFetch(*)` and pass `--force` (required for headless fetch); research-only networked runs also deny `Shell(*)` / `Write(**)`. Attempt worktrees fetch/start from the initiative base when the source tip is behind or history was rewritten, without resetting the source checkout. Also includes **ops** helpers for macOS / Linux / Windows, LaunchAgent/systemd **PATH** for `~/.local/bin`, disconnect/disengage, multi-driver lanes, shared slots **1–4**, worktrees, and optional `--ensure-checkout`. Protocol 1 heartbeats remain compatible for presence but cannot receive work.
|
|
6
6
|
|
|
7
7
|
## Prerequisites
|
|
8
8
|
|
package/dist/driver.js
CHANGED
|
@@ -142,6 +142,7 @@ export function buildAssignmentPrompt(context) {
|
|
|
142
142
|
...(context.grants.includes("branch_create") ? branchCreateCommands : []),
|
|
143
143
|
...(context.grants.includes("pr_create") ? prCreateCommands : []),
|
|
144
144
|
];
|
|
145
|
+
const hasExternalNetwork = (spec.required_capabilities ?? []).includes("external_network");
|
|
145
146
|
const languageRule = deliveryLanguageRule(packageContext?.working_language ?? spec.working_language);
|
|
146
147
|
lines.push("", "RULES", "- Stay within the change scope and boundaries.", ...(languageRule ? [languageRule] : []),
|
|
147
148
|
// Name the executable commands. The shell allow-list is exact, so an agent that guesses at
|
|
@@ -152,7 +153,12 @@ export function buildAssignmentPrompt(context) {
|
|
|
152
153
|
? [
|
|
153
154
|
`- These are the ONLY shell commands you may run: ${runnableCommands.join("; ")}. Anything else is rejected — do not try variations, wrappers, or \`echo\`. Run the relevant ones and report their real output.`,
|
|
154
155
|
]
|
|
155
|
-
: ["- You have no shell authority for this assignment. Do not attempt shell commands; verify by reading files and report what you could not verify as unknown."]),
|
|
156
|
+
: ["- You have no shell authority for this assignment. Do not attempt shell commands; verify by reading files and report what you could not verify as unknown."]),
|
|
157
|
+
// Mirror .cursor/cli.json WebFetch(*) — without naming it, agents fall back to WebSearch (not
|
|
158
|
+
// allow-listable) or invent status/title after "User Rejected" on unlisted fetches.
|
|
159
|
+
...(hasExternalNetwork
|
|
160
|
+
? ["- This assignment includes external_network: WebFetch is allow-listed. Use WebFetch for live HTTP status and page content; do not invent origin responses. Prefer WebFetch over WebSearch."]
|
|
161
|
+
: []), ...(mustCommit
|
|
156
162
|
? [
|
|
157
163
|
"- Your working branch is already checked out. Commit your repository changes on the current branch (git add + git commit) — do not create a new branch — and report the resulting sha as head_commit. A delivery that changed files without a commit is rejected.",
|
|
158
164
|
...(mustOpenPr
|
|
@@ -430,11 +436,18 @@ export const codexDriver = {
|
|
|
430
436
|
},
|
|
431
437
|
};
|
|
432
438
|
/**
|
|
433
|
-
* Grants → Cursor CLI permissions (project .cursor/cli.json).
|
|
439
|
+
* Grants + capabilities → Cursor CLI permissions (project .cursor/cli.json).
|
|
434
440
|
* Current Cursor Agent schema accepts only `permissions.{allow,deny}` (no
|
|
435
441
|
* `version` / `approvalMode`). Outside the allow list is denied without --force.
|
|
442
|
+
*
|
|
443
|
+
* `external_network` maps to WebFetch(*) plus `--force` on the run (see
|
|
444
|
+
* cursorRunArgs). Field evidence: allow-listing WebFetch alone still yields
|
|
445
|
+
* "User Rejected" under headless `-p`; `--force` is required for fetch to
|
|
446
|
+
* succeed. Because `--force` auto-allows unlisted tools, research-only
|
|
447
|
+
* networked assignments also deny Shell(*) and Write(**). Codex's parallel is
|
|
448
|
+
* sandbox_workspace_write.network_access=true.
|
|
436
449
|
*/
|
|
437
|
-
export function cursorPermissionsForGrants(grants, verificationCommands = []) {
|
|
450
|
+
export function cursorPermissionsForGrants(grants, verificationCommands = [], capabilities = []) {
|
|
438
451
|
const allow = [];
|
|
439
452
|
if (grants.includes("test_run")) {
|
|
440
453
|
allow.push(...verificationCommands.filter(isBoundedVerificationCommand).map((command) => `Shell(${command})`));
|
|
@@ -443,7 +456,19 @@ export function cursorPermissionsForGrants(grants, verificationCommands = []) {
|
|
|
443
456
|
allow.push(...branchCreateCommands.map((command) => `Shell(${command})`));
|
|
444
457
|
if (grants.includes("pr_create"))
|
|
445
458
|
allow.push(...prCreateCommands.map((command) => `Shell(${command})`));
|
|
446
|
-
|
|
459
|
+
// Cursor docs: WebFetch(domainOrPattern); WebFetch(*) auto-approves any domain.
|
|
460
|
+
if (capabilities.includes("external_network"))
|
|
461
|
+
allow.push("WebFetch(*)");
|
|
462
|
+
const deny = deniedCommands.map((command) => `Shell(${command})`);
|
|
463
|
+
// --force opens anything not denied; lock shell/write when the assignment has no mutate/shell grants.
|
|
464
|
+
if (capabilities.includes("external_network")
|
|
465
|
+
&& !grants.includes("repo_write")
|
|
466
|
+
&& !grants.includes("test_run")
|
|
467
|
+
&& !grants.includes("branch_create")
|
|
468
|
+
&& !grants.includes("pr_create")) {
|
|
469
|
+
deny.push("Shell(*)", "Write(**)");
|
|
470
|
+
}
|
|
471
|
+
return { allow, deny };
|
|
447
472
|
}
|
|
448
473
|
/**
|
|
449
474
|
* Cursor CLI arguments. Deliberately no `--mode plan` for read-only assignments: plan mode is not an
|
|
@@ -461,6 +486,9 @@ export function cursorRunArgs(input) {
|
|
|
461
486
|
const args = ["-p", "--output-format", "json", "--workspace", input.workspace];
|
|
462
487
|
if (input.trustWorkspace)
|
|
463
488
|
args.push("--trust");
|
|
489
|
+
// Headless WebFetch requires --force even when WebFetch(*) is allow-listed (Cursor CLI 2026.07+).
|
|
490
|
+
if (input.capabilities?.includes("external_network"))
|
|
491
|
+
args.push("--force");
|
|
464
492
|
if (input.model)
|
|
465
493
|
args.push("--model", input.model);
|
|
466
494
|
if (input.resumeSessionId)
|
|
@@ -538,7 +566,7 @@ export const cursorDriver = {
|
|
|
538
566
|
// local contract instead of making either version fail every attempt worktree.
|
|
539
567
|
const help = await execute(executable, ["--help"], input.workspace, 15_000, undefined, "local");
|
|
540
568
|
const trustWorkspace = help.code === 0 && cursorSupportsWorkspaceTrust(`${help.stdout}\n${help.stderr}`);
|
|
541
|
-
const configured = await withCursorPermissions(input.workspace, cursorPermissionsForGrants(input.grants, input.verificationCommands), () => execute(executable, cursorRunArgs({ ...input, trustWorkspace }), input.workspace, input.timeoutMs ?? 20 * 60_000, undefined, "local"));
|
|
569
|
+
const configured = await withCursorPermissions(input.workspace, cursorPermissionsForGrants(input.grants, input.verificationCommands, input.capabilities ?? []), () => execute(executable, cursorRunArgs({ ...input, trustWorkspace }), input.workspace, input.timeoutMs ?? 20 * 60_000, undefined, "local"));
|
|
542
570
|
const { code, stdout, stderr } = configured;
|
|
543
571
|
const parsed = parseCursorOutput(stdout);
|
|
544
572
|
if (code !== 0 || parsed.isError) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miraland-labs/conduit-bridge",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.11",
|
|
4
4
|
"description": "Conduit Bridge CLI — join, connect, disconnect, multi-driver lanes, and run Claude Code / Codex / Cursor / OpenCode / Kiro / Antigravity agents for a Conduit organization",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|