@miraland-labs/conduit-bridge 0.16.11 → 0.16.12

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 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({ code: values.token, installation_id: installationId, machine_name: machineName }),
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,63 @@ 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
- const workspace = values.workspace?.trim() || env.CONDUIT_WORKSPACE;
455
- const repo = values.repo?.trim() || env.CONDUIT_REPO;
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 (!values["no-install"] && workspace) {
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
+ const detected = await detectInstalledClients();
494
+ const drivers = driverIdsFromDetectedLabels(detected);
495
+ if (drivers.length === 0) {
496
+ throw new Error("No coding agent detected. Install one (Claude Code, Codex, Cursor, …), then re-run this command.");
497
+ }
498
+ for (const id of drivers) {
499
+ if (LOCAL_FUEL_DRIVERS.has(id))
500
+ runBridge(["drivers", "fuel", id, "local"]);
501
+ }
502
+ runBridge(["drivers", "online", ...drivers]);
503
+ applyRunnerToolPath();
504
+ runBridge(["install-service", "--workspace", root]);
505
+ console.log(`Conduit manages checkouts under ${root}. Assign this computer to a project from the console — it clones and switches on its own.`);
506
+ return;
507
+ }
508
+ if (workspace) {
468
509
  const refreshedEnv = loadOpsEnv();
469
510
  await runOps("install", [], { ...deps, env: refreshedEnv });
470
511
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miraland-labs/conduit-bridge",
3
- "version": "0.16.11",
3
+ "version": "0.16.12",
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": {