@miraland-labs/conduit-bridge 0.16.11 → 0.16.13
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/cli.js +9 -1
- package/dist/ops.js +47 -5
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -205,6 +205,7 @@ async function enroll() {
|
|
|
205
205
|
token: { type: "string" },
|
|
206
206
|
fuel: { type: "string" },
|
|
207
207
|
machine: { type: "string" },
|
|
208
|
+
"managed-root": { type: "string" },
|
|
208
209
|
},
|
|
209
210
|
});
|
|
210
211
|
if (!values.url || !values.token) {
|
|
@@ -216,7 +217,14 @@ async function enroll() {
|
|
|
216
217
|
const response = await fetch(`${baseUrl}/runner/v1/connect/enroll-fast`, {
|
|
217
218
|
method: "POST",
|
|
218
219
|
headers: { "content-type": "application/json" },
|
|
219
|
-
body: JSON.stringify({
|
|
220
|
+
body: JSON.stringify({
|
|
221
|
+
code: values.token,
|
|
222
|
+
installation_id: installationId,
|
|
223
|
+
machine_name: machineName,
|
|
224
|
+
// Managed mode is declared here so the control plane can derive a workspace for a later
|
|
225
|
+
// switch — that is what lets a project be assigned from a phone with no path and no terminal.
|
|
226
|
+
...(values["managed-root"]?.trim() ? { managed_workspace_root: values["managed-root"].trim() } : {}),
|
|
227
|
+
}),
|
|
220
228
|
});
|
|
221
229
|
if (!response.ok) {
|
|
222
230
|
const errorText = await response.text();
|
package/dist/ops.js
CHANGED
|
@@ -19,6 +19,11 @@ export const OPS_VERBS = [
|
|
|
19
19
|
"connect", "enroll", "install", "switch", "online", "offline", "status", "doctor", "disconnect", "uninstall",
|
|
20
20
|
];
|
|
21
21
|
const LOCAL_FUEL_DRIVERS = new Set(["cursor", "pi", "kiro", "antigravity", "grok"]);
|
|
22
|
+
/**
|
|
23
|
+
* Where Conduit checks out projects on a managed computer. Deliberately not `~/conduit`, which is
|
|
24
|
+
* where operators keep the Conduit product checkout itself. Keep in step with the console default.
|
|
25
|
+
*/
|
|
26
|
+
const DEFAULT_MANAGED_ROOT = "~/conduit-workspaces";
|
|
22
27
|
function bridgeVersionAtLeast(value, minimum) {
|
|
23
28
|
const parse = (input) => {
|
|
24
29
|
const match = /^(\d+)\.(\d+)\.(\d+)/.exec(input);
|
|
@@ -95,6 +100,7 @@ export function loadOpsEnv(home = homedir(), cwd = process.cwd()) {
|
|
|
95
100
|
CONDUIT_REPO: pick("CONDUIT_REPO", ""),
|
|
96
101
|
CONDUIT_DRIVERS: pick("CONDUIT_DRIVERS", ""),
|
|
97
102
|
CONDUIT_ROLES: pick("CONDUIT_ROLES", "implement research review"),
|
|
103
|
+
CONDUIT_MANAGED_ROOT: pick("CONDUIT_MANAGED_ROOT", ""),
|
|
98
104
|
loadedFrom,
|
|
99
105
|
};
|
|
100
106
|
}
|
|
@@ -113,7 +119,7 @@ export function splitOpsList(value) {
|
|
|
113
119
|
/** Update keys in an existing ops.env (or create from current values). Preserves comments/unknown keys when possible. */
|
|
114
120
|
export function writeOpsEnvFile(path, patch, existingText) {
|
|
115
121
|
mkdirSync(dirname(path), { recursive: true });
|
|
116
|
-
const keys = ["CONDUIT_URL", "CONDUIT_ORG", "CONDUIT_WORKSPACE", "CONDUIT_REPO", "CONDUIT_DRIVERS", "CONDUIT_ROLES"];
|
|
122
|
+
const keys = ["CONDUIT_URL", "CONDUIT_ORG", "CONDUIT_WORKSPACE", "CONDUIT_REPO", "CONDUIT_DRIVERS", "CONDUIT_ROLES", "CONDUIT_MANAGED_ROOT"];
|
|
117
123
|
const current = existingText ?? (existsSync(path) ? readFileSync(path, "utf8") : "");
|
|
118
124
|
const lines = current ? current.split(/\r?\n/) : [];
|
|
119
125
|
const seen = new Set();
|
|
@@ -443,28 +449,64 @@ export async function runOps(verb, argv = [], deps = {}) {
|
|
|
443
449
|
repo: { type: "string" },
|
|
444
450
|
machine: { type: "string" },
|
|
445
451
|
"no-install": { type: "boolean" },
|
|
452
|
+
managed: { type: "string" },
|
|
446
453
|
},
|
|
447
454
|
allowPositionals: true,
|
|
448
455
|
});
|
|
449
456
|
const url = (values.url?.trim() || env.CONDUIT_URL).trim();
|
|
450
457
|
const token = values.token?.trim();
|
|
451
458
|
if (!url || !token) {
|
|
452
|
-
throw new Error("Usage: ops enroll --url <url> --token <token> [--workspace <path>] [--repo <url>] [--machine <name>]");
|
|
459
|
+
throw new Error("Usage: ops enroll --url <url> --token <token> [--managed[=<root>] | --workspace <path>] [--repo <url>] [--machine <name>]");
|
|
453
460
|
}
|
|
454
|
-
|
|
455
|
-
|
|
461
|
+
/**
|
|
462
|
+
* Managed mode is the one-command kick-off: the operator grants Conduit one folder and never
|
|
463
|
+
* touches a terminal again. There is no repository yet, so the runner starts against the root
|
|
464
|
+
* itself and simply waits — the first project assignment (from a phone) arrives as on-shift
|
|
465
|
+
* intent and Bridge clones into <root>/<owner>/<repo> and restarts on it.
|
|
466
|
+
*/
|
|
467
|
+
const managed = values.managed !== undefined;
|
|
468
|
+
const managedRoot = managed ? (values.managed?.trim() || DEFAULT_MANAGED_ROOT) : "";
|
|
469
|
+
const workspace = managed ? managedRoot : (values.workspace?.trim() || env.CONDUIT_WORKSPACE);
|
|
470
|
+
const repo = managed ? "" : (values.repo?.trim() || env.CONDUIT_REPO);
|
|
456
471
|
const machine = values.machine?.trim();
|
|
457
472
|
const envPath = env.loadedFrom ?? defaultOpsEnvPath();
|
|
458
473
|
writeOpsEnvFile(envPath, {
|
|
459
474
|
CONDUIT_URL: url,
|
|
460
475
|
...(workspace ? { CONDUIT_WORKSPACE: workspace } : {}),
|
|
461
476
|
...(repo ? { CONDUIT_REPO: repo } : {}),
|
|
477
|
+
...(managed ? { CONDUIT_MANAGED_ROOT: managedRoot } : {}),
|
|
462
478
|
});
|
|
463
479
|
const args = ["enroll", "--url", url, "--token", token];
|
|
464
480
|
if (machine)
|
|
465
481
|
args.push("--machine", machine);
|
|
482
|
+
if (managed)
|
|
483
|
+
args.push("--managed-root", managedRoot);
|
|
466
484
|
runBridge(args);
|
|
467
|
-
if (
|
|
485
|
+
if (values["no-install"])
|
|
486
|
+
return;
|
|
487
|
+
if (managed) {
|
|
488
|
+
const root = resolve(expandOpsValue(managedRoot));
|
|
489
|
+
mkdirSync(root, { recursive: true });
|
|
490
|
+
// Bring lanes online and install the resident runner, but skip `ops install`'s doctor gate:
|
|
491
|
+
// an empty managed root is legitimately not a checkout yet, and failing here would leave the
|
|
492
|
+
// computer with no background process — exactly the terminal round-trip this removes.
|
|
493
|
+
// Same lane resolution as `ops install` (honours CONDUIT_DRIVERS and the one-lane default)
|
|
494
|
+
// rather than a second copy of detection — and it keeps the seam tests inject through.
|
|
495
|
+
const drivers = await (deps.resolveInstallDrivers ?? resolveInstallDrivers)(loadOpsEnv(), []);
|
|
496
|
+
if (drivers.length === 0) {
|
|
497
|
+
throw new Error("No coding agent detected. Install one (Claude Code, Codex, Cursor, …), then re-run this command.");
|
|
498
|
+
}
|
|
499
|
+
for (const id of drivers) {
|
|
500
|
+
if (LOCAL_FUEL_DRIVERS.has(id))
|
|
501
|
+
runBridge(["drivers", "fuel", id, "local"]);
|
|
502
|
+
}
|
|
503
|
+
runBridge(["drivers", "online", ...drivers]);
|
|
504
|
+
applyRunnerToolPath();
|
|
505
|
+
runBridge(["install-service", "--workspace", root]);
|
|
506
|
+
console.log(`Conduit manages checkouts under ${root}. Assign this computer to a project from the console — it clones and switches on its own.`);
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
if (workspace) {
|
|
468
510
|
const refreshedEnv = loadOpsEnv();
|
|
469
511
|
await runOps("install", [], { ...deps, env: refreshedEnv });
|
|
470
512
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miraland-labs/conduit-bridge",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.13",
|
|
4
4
|
"description": "Conduit Bridge CLI — join, connect, disconnect, multi-driver lanes, and run Claude Code / Codex / Cursor / OpenCode / Pi / Kiro / Antigravity / Grok Build agents for a Conduit organization",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|