@miraland-labs/conduit-bridge 0.1.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/README.md +33 -0
- package/dist/brief.js +85 -0
- package/dist/cli.js +332 -0
- package/dist/client.js +66 -0
- package/dist/config.js +87 -0
- package/dist/detect.js +31 -0
- package/dist/driver.js +201 -0
- package/dist/execution.js +264 -0
- package/dist/mcp.js +54 -0
- package/dist/service.js +153 -0
- package/package.json +36 -0
package/dist/service.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { mkdir, readFile, unlink, writeFile } from "node:fs/promises";
|
|
2
|
+
import { homedir, platform } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { realpathSync } from "node:fs";
|
|
5
|
+
import { spawnSync } from "node:child_process";
|
|
6
|
+
export const SERVICE_LABEL = "io.miraland.conduit-runner";
|
|
7
|
+
function configDir() {
|
|
8
|
+
return join(homedir(), ".config", "conduit");
|
|
9
|
+
}
|
|
10
|
+
function serviceStatePath() {
|
|
11
|
+
return join(configDir(), "service.json");
|
|
12
|
+
}
|
|
13
|
+
function logPath() {
|
|
14
|
+
return join(homedir(), "Library", "Logs", "conduit-runner.log");
|
|
15
|
+
}
|
|
16
|
+
function linuxLogDir() {
|
|
17
|
+
return join(homedir(), ".local", "state", "conduit");
|
|
18
|
+
}
|
|
19
|
+
/** Resolve node + cli.js (+ runner args) for the installed binary. */
|
|
20
|
+
export function runnerProgramArguments(options = {}) {
|
|
21
|
+
const cli = process.argv[1] ? realpathSync(process.argv[1]) : "";
|
|
22
|
+
if (!cli)
|
|
23
|
+
throw new Error("Unable to resolve the conduit CLI path");
|
|
24
|
+
const args = [process.execPath, cli, "runner"];
|
|
25
|
+
if (options.agent)
|
|
26
|
+
args.push("--agent", options.agent);
|
|
27
|
+
if (options.workspace)
|
|
28
|
+
args.push("--workspace", options.workspace);
|
|
29
|
+
if (options.interval)
|
|
30
|
+
args.push("--interval", options.interval);
|
|
31
|
+
if (options.agentTimeoutMinutes)
|
|
32
|
+
args.push("--agent-timeout-minutes", options.agentTimeoutMinutes);
|
|
33
|
+
return args;
|
|
34
|
+
}
|
|
35
|
+
export function launchdPlist(programArguments, stdoutPath) {
|
|
36
|
+
const argsXml = programArguments.map((arg) => ` <string>${escapeXml(arg)}</string>`).join("\n");
|
|
37
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
38
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
39
|
+
<plist version="1.0">
|
|
40
|
+
<dict>
|
|
41
|
+
<key>Label</key>
|
|
42
|
+
<string>${SERVICE_LABEL}</string>
|
|
43
|
+
<key>ProgramArguments</key>
|
|
44
|
+
<array>
|
|
45
|
+
${argsXml}
|
|
46
|
+
</array>
|
|
47
|
+
<key>RunAtLoad</key>
|
|
48
|
+
<true/>
|
|
49
|
+
<key>KeepAlive</key>
|
|
50
|
+
<true/>
|
|
51
|
+
<key>StandardOutPath</key>
|
|
52
|
+
<string>${escapeXml(stdoutPath)}</string>
|
|
53
|
+
<key>StandardErrorPath</key>
|
|
54
|
+
<string>${escapeXml(stdoutPath)}</string>
|
|
55
|
+
</dict>
|
|
56
|
+
</plist>
|
|
57
|
+
`;
|
|
58
|
+
}
|
|
59
|
+
export function systemdUserUnit(programArguments, workingDirectory) {
|
|
60
|
+
const execStart = programArguments.map(escapeSystemd).join(" ");
|
|
61
|
+
return `[Unit]
|
|
62
|
+
Description=Conduit Bridge runner
|
|
63
|
+
After=network-online.target
|
|
64
|
+
Wants=network-online.target
|
|
65
|
+
|
|
66
|
+
[Service]
|
|
67
|
+
Type=simple
|
|
68
|
+
WorkingDirectory=${workingDirectory}
|
|
69
|
+
ExecStart=${execStart}
|
|
70
|
+
Restart=always
|
|
71
|
+
RestartSec=5
|
|
72
|
+
|
|
73
|
+
[Install]
|
|
74
|
+
WantedBy=default.target
|
|
75
|
+
`;
|
|
76
|
+
}
|
|
77
|
+
function escapeXml(value) {
|
|
78
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """);
|
|
79
|
+
}
|
|
80
|
+
function escapeSystemd(value) {
|
|
81
|
+
if (/[\s"'\\]/.test(value))
|
|
82
|
+
return `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
function launchAgentsPath() {
|
|
86
|
+
return join(homedir(), "Library", "LaunchAgents", `${SERVICE_LABEL}.plist`);
|
|
87
|
+
}
|
|
88
|
+
function systemdUnitPath() {
|
|
89
|
+
return join(homedir(), ".config", "systemd", "user", "conduit-runner.service");
|
|
90
|
+
}
|
|
91
|
+
function run(command, args) {
|
|
92
|
+
const result = spawnSync(command, args, { encoding: "utf8" });
|
|
93
|
+
if (result.status !== 0) {
|
|
94
|
+
const detail = (result.stderr || result.stdout || `exit ${result.status}`).trim();
|
|
95
|
+
throw new Error(`${command} ${args.join(" ")} failed: ${detail}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
export async function installRunnerService(options = {}) {
|
|
99
|
+
const host = platform();
|
|
100
|
+
if (host !== "darwin" && host !== "linux") {
|
|
101
|
+
throw new Error(`install-service is supported on macOS and Linux only (got ${host})`);
|
|
102
|
+
}
|
|
103
|
+
const programArguments = runnerProgramArguments(options);
|
|
104
|
+
if (host === "darwin") {
|
|
105
|
+
const plistPath = launchAgentsPath();
|
|
106
|
+
await mkdir(dirname(plistPath), { recursive: true });
|
|
107
|
+
await mkdir(dirname(logPath()), { recursive: true });
|
|
108
|
+
await writeFile(plistPath, launchdPlist(programArguments, logPath()), { mode: 0o644 });
|
|
109
|
+
// Prefer modern bootout/bootstrap; fall back to load for older macOS.
|
|
110
|
+
spawnSync("launchctl", ["bootout", `gui/${process.getuid?.() ?? 501}/${SERVICE_LABEL}`], { encoding: "utf8" });
|
|
111
|
+
const boot = spawnSync("launchctl", ["bootstrap", `gui/${process.getuid?.() ?? 501}`, plistPath], { encoding: "utf8" });
|
|
112
|
+
if (boot.status !== 0) {
|
|
113
|
+
run("launchctl", ["load", "-w", plistPath]);
|
|
114
|
+
}
|
|
115
|
+
await writeFile(serviceStatePath(), `${JSON.stringify({ platform: "darwin", programArguments, options, installed_at: new Date().toISOString() }, null, 2)}\n`, { mode: 0o600 });
|
|
116
|
+
return { path: plistPath, platform: "darwin" };
|
|
117
|
+
}
|
|
118
|
+
const unitPath = systemdUnitPath();
|
|
119
|
+
await mkdir(dirname(unitPath), { recursive: true });
|
|
120
|
+
await mkdir(linuxLogDir(), { recursive: true });
|
|
121
|
+
await writeFile(unitPath, systemdUserUnit(programArguments, configDir()), { mode: 0o644 });
|
|
122
|
+
run("systemctl", ["--user", "daemon-reload"]);
|
|
123
|
+
run("systemctl", ["--user", "enable", "--now", "conduit-runner.service"]);
|
|
124
|
+
await writeFile(serviceStatePath(), `${JSON.stringify({ platform: "linux", programArguments, options, installed_at: new Date().toISOString() }, null, 2)}\n`, { mode: 0o600 });
|
|
125
|
+
return { path: unitPath, platform: "linux" };
|
|
126
|
+
}
|
|
127
|
+
export async function uninstallRunnerService() {
|
|
128
|
+
const host = platform();
|
|
129
|
+
if (host !== "darwin" && host !== "linux") {
|
|
130
|
+
throw new Error(`uninstall-service is supported on macOS and Linux only (got ${host})`);
|
|
131
|
+
}
|
|
132
|
+
let stored = null;
|
|
133
|
+
try {
|
|
134
|
+
stored = JSON.parse(await readFile(serviceStatePath(), "utf8"));
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
stored = null;
|
|
138
|
+
}
|
|
139
|
+
if (host === "darwin") {
|
|
140
|
+
const plistPath = launchAgentsPath();
|
|
141
|
+
spawnSync("launchctl", ["bootout", `gui/${process.getuid?.() ?? 501}/${SERVICE_LABEL}`], { encoding: "utf8" });
|
|
142
|
+
spawnSync("launchctl", ["unload", "-w", plistPath], { encoding: "utf8" });
|
|
143
|
+
await unlink(plistPath).catch(() => undefined);
|
|
144
|
+
await unlink(serviceStatePath()).catch(() => undefined);
|
|
145
|
+
return { path: plistPath, platform: stored?.platform ?? "darwin" };
|
|
146
|
+
}
|
|
147
|
+
const unitPath = systemdUnitPath();
|
|
148
|
+
spawnSync("systemctl", ["--user", "disable", "--now", "conduit-runner.service"], { encoding: "utf8" });
|
|
149
|
+
await unlink(unitPath).catch(() => undefined);
|
|
150
|
+
spawnSync("systemctl", ["--user", "daemon-reload"], { encoding: "utf8" });
|
|
151
|
+
await unlink(serviceStatePath()).catch(() => undefined);
|
|
152
|
+
return { path: unitPath, platform: stored?.platform ?? "linux" };
|
|
153
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@miraland-labs/conduit-bridge",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Conduit Bridge CLI — join, connect, and run local agent work for a Conduit organization",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"conduit": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=20"
|
|
15
|
+
},
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/miralandlabs/conduit.git",
|
|
22
|
+
"directory": "packages/conduit-bridge"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsc -p tsconfig.json",
|
|
26
|
+
"prepublishOnly": "npm run build",
|
|
27
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
31
|
+
"zod": "^3.25.76"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^26.1.1"
|
|
35
|
+
}
|
|
36
|
+
}
|