@gemslibe/rbo 0.2.0 → 0.4.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 +11 -0
- package/config/agent.json +34 -0
- package/config/controller.json +20 -0
- package/dist/rbo-mcp-stdio.js +71 -16
- package/dist/rbo.js +965 -306
- package/package.json +8 -3
- package/scripts/stop-running-rbo.mjs +306 -0
package/README.md
CHANGED
|
@@ -10,6 +10,17 @@ npm install -g @gemslibe/rbo
|
|
|
10
10
|
|
|
11
11
|
Requires Node.js ≥ 22.14. See the monorepo [`docs/ops/getting-started.md`](../../docs/ops/getting-started.md) for Controller/Agent setup and MCP client wiring.
|
|
12
12
|
|
|
13
|
+
Global reinstall/uninstall runs `scripts/stop-running-rbo.mjs` (`preinstall` /
|
|
14
|
+
`preuninstall`) to stop live Controller/Agent processes so native deps can be replaced on
|
|
15
|
+
Windows. Only global installs trigger the stop (`npm_config_global=true`). Set
|
|
16
|
+
`RBO_SKIP_INSTALL_STOP=1` to disable.
|
|
17
|
+
|
|
18
|
+
`rbo controller init` / `rbo agent init` write live operator configs
|
|
19
|
+
(`~/.rbo/controller.json` and `~/.rbo/agent/agent.json`). Daemons load those files on start;
|
|
20
|
+
environment variables override the file when set. The package also ships matching templates at
|
|
21
|
+
`config/controller.json` and `config/agent.json`. Use `--force` on init to rewrite a config back
|
|
22
|
+
to defaults.
|
|
23
|
+
|
|
13
24
|
## Binaries
|
|
14
25
|
|
|
15
26
|
| Command | Purpose |
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"initialized_at": "1970-01-01T00:00:00.000Z",
|
|
4
|
+
"controller_url": "",
|
|
5
|
+
"controller_fingerprint": "",
|
|
6
|
+
"display_name": "rbo-agent",
|
|
7
|
+
"max_jobs": 1,
|
|
8
|
+
"repo_cache_dir": null,
|
|
9
|
+
"secret_map": null,
|
|
10
|
+
"git_allowlist": {
|
|
11
|
+
"schemes": ["https", "ssh"],
|
|
12
|
+
"hosts": ["github.com"]
|
|
13
|
+
},
|
|
14
|
+
"repo_cache": {
|
|
15
|
+
"max_size_gb": 100,
|
|
16
|
+
"min_free_disk_gb": 30,
|
|
17
|
+
"retention_days": 30
|
|
18
|
+
},
|
|
19
|
+
"build_cache": {
|
|
20
|
+
"enabled_kinds": ["ccache", "sccache", "npm", "pnpm", "pip"],
|
|
21
|
+
"max_size_gb": 20,
|
|
22
|
+
"min_free_disk_gb": 5,
|
|
23
|
+
"retention_days": 14,
|
|
24
|
+
"allow_read_risk_levels": ["safe", "normal"],
|
|
25
|
+
"allow_write_risk_levels": ["safe", "normal"]
|
|
26
|
+
},
|
|
27
|
+
"log_spool_max_bytes": 536870912,
|
|
28
|
+
"log_send_queue_max": 64,
|
|
29
|
+
"disconnect_grace_seconds": 60,
|
|
30
|
+
"orphan_timeout_seconds": 300,
|
|
31
|
+
"reconcile_deadline_seconds": 120,
|
|
32
|
+
"disk_min_free_bytes": null,
|
|
33
|
+
"configured_priority": null
|
|
34
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mcp_host": "127.0.0.1",
|
|
3
|
+
"mcp_port": 7410,
|
|
4
|
+
"agent_plane_port": 7411,
|
|
5
|
+
"controller_public_host": "127.0.0.1",
|
|
6
|
+
"data_plane_base_url": null,
|
|
7
|
+
"allowed_project_roots": [],
|
|
8
|
+
"allowed_artifact_destinations": [],
|
|
9
|
+
"git_allowlist": {
|
|
10
|
+
"schemes": ["https", "ssh"],
|
|
11
|
+
"hosts": ["github.com"]
|
|
12
|
+
},
|
|
13
|
+
"local_max_concurrent_jobs": 1,
|
|
14
|
+
"disconnect_grace_seconds": 60,
|
|
15
|
+
"orphan_timeout_seconds": 300,
|
|
16
|
+
"reconcile_deadline_seconds": 120,
|
|
17
|
+
"allow_local_fallback": true,
|
|
18
|
+
"max_git_bundle_bytes": 536870912,
|
|
19
|
+
"local_fallback_max_host_cpu_percent": 80
|
|
20
|
+
}
|
package/dist/rbo-mcp-stdio.js
CHANGED
|
@@ -7,7 +7,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
7
7
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8
8
|
|
|
9
9
|
// ../../packages/shared/dist/versions.js
|
|
10
|
-
var RBO_STDIO_ADAPTER_VERSION = "0.
|
|
10
|
+
var RBO_STDIO_ADAPTER_VERSION = "0.4.0";
|
|
11
11
|
|
|
12
12
|
// ../../packages/shared/dist/errors.js
|
|
13
13
|
import { z } from "zod";
|
|
@@ -686,6 +686,21 @@ var ARTIFACT_MATERIALIZE_INPUT = {
|
|
|
686
686
|
var AGENT_PROBE_INPUT = {
|
|
687
687
|
agent_id: z4.string().min(1)
|
|
688
688
|
};
|
|
689
|
+
var JOB_RUN_INPUT = {
|
|
690
|
+
command: z4.string().min(1).optional(),
|
|
691
|
+
project_root: z4.string().min(1).optional(),
|
|
692
|
+
job_id: z4.string().min(1).optional(),
|
|
693
|
+
cwd: z4.string().default("."),
|
|
694
|
+
timeout_seconds: z4.number().positive().max(3600).default(3600),
|
|
695
|
+
wait_seconds: z4.number().int().min(0).max(3600).optional(),
|
|
696
|
+
/** Max seconds this MCP response blocks; default keeps typical 60s clients safe. */
|
|
697
|
+
mcp_wait_slice_seconds: z4.number().int().min(1).max(55).default(50),
|
|
698
|
+
artifacts: JobRequestSchema.shape.artifacts,
|
|
699
|
+
risk_level: JobRequestSchema.shape.risk_level,
|
|
700
|
+
client_request_id: z4.string().min(1).optional(),
|
|
701
|
+
name: z4.string().optional(),
|
|
702
|
+
include_log_tail_lines: z4.number().int().min(0).max(1e3).default(80)
|
|
703
|
+
};
|
|
689
704
|
var MCP_TOOL_DEFS = [
|
|
690
705
|
{
|
|
691
706
|
name: "agents_list",
|
|
@@ -697,6 +712,11 @@ var MCP_TOOL_DEFS = [
|
|
|
697
712
|
description: "Submit a build/test job and capture an immutable workspace snapshot.",
|
|
698
713
|
inputShape: JOB_SUBMIT_INPUT
|
|
699
714
|
},
|
|
715
|
+
{
|
|
716
|
+
name: "job_run",
|
|
717
|
+
description: "Run a command remotely (snapshot + execute). Waits up to mcp_wait_slice_seconds (default 50). If still running, returns resume:true \u2014 call again with the same job_id. Preferred for interactive AI clients.",
|
|
718
|
+
inputShape: JOB_RUN_INPUT
|
|
719
|
+
},
|
|
700
720
|
{
|
|
701
721
|
name: "job_confirm",
|
|
702
722
|
description: "Confirm a destructive or hardware-risk job after snapshot capture.",
|
|
@@ -761,6 +781,32 @@ var CompatibilityMatrixSchema = z5.object({
|
|
|
761
781
|
});
|
|
762
782
|
|
|
763
783
|
// ../mcp-stdio/src/proxy.ts
|
|
784
|
+
var STDIO_JOB_RUN_HEARTBEAT_MS = 5e3;
|
|
785
|
+
function startProgressHeartbeat(input) {
|
|
786
|
+
const { progressToken, sendNotification } = input;
|
|
787
|
+
if (progressToken === void 0) {
|
|
788
|
+
return { stop: () => void 0 };
|
|
789
|
+
}
|
|
790
|
+
let progress = 0;
|
|
791
|
+
const prefix = input.messagePrefix ?? "job_run";
|
|
792
|
+
const timer = setInterval(() => {
|
|
793
|
+
progress += 1;
|
|
794
|
+
void sendNotification({
|
|
795
|
+
method: "notifications/progress",
|
|
796
|
+
params: {
|
|
797
|
+
progressToken,
|
|
798
|
+
progress,
|
|
799
|
+
message: `${prefix} waiting (heartbeat ${progress})`
|
|
800
|
+
}
|
|
801
|
+
}).catch(() => void 0);
|
|
802
|
+
}, input.intervalMs ?? STDIO_JOB_RUN_HEARTBEAT_MS);
|
|
803
|
+
timer.unref?.();
|
|
804
|
+
return {
|
|
805
|
+
stop: () => {
|
|
806
|
+
clearInterval(timer);
|
|
807
|
+
}
|
|
808
|
+
};
|
|
809
|
+
}
|
|
764
810
|
function createStdioProxyServer(options) {
|
|
765
811
|
const server = new McpServer({
|
|
766
812
|
name: "rbo-mcp-stdio",
|
|
@@ -771,21 +817,30 @@ function createStdioProxyServer(options) {
|
|
|
771
817
|
server.registerTool(
|
|
772
818
|
def.name,
|
|
773
819
|
{ description: def.description, inputSchema: def.inputShape },
|
|
774
|
-
async (args) => {
|
|
775
|
-
const
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
820
|
+
async (args, extra) => {
|
|
821
|
+
const heartbeat = def.name === "job_run" ? startProgressHeartbeat({
|
|
822
|
+
progressToken: extra._meta?.progressToken,
|
|
823
|
+
sendNotification: (notification) => extra.sendNotification(notification)
|
|
824
|
+
}) : { stop: () => void 0 };
|
|
825
|
+
try {
|
|
826
|
+
const response = await fetch(`${baseUrl}/internal/v1/tools/${def.name}`, {
|
|
827
|
+
method: "POST",
|
|
828
|
+
headers: {
|
|
829
|
+
"content-type": "application/json",
|
|
830
|
+
"x-rbo-client-id": options.clientId,
|
|
831
|
+
"x-rbo-client-transport": "stdio"
|
|
832
|
+
},
|
|
833
|
+
body: JSON.stringify(args ?? {}),
|
|
834
|
+
signal: extra.signal
|
|
835
|
+
});
|
|
836
|
+
const text = await response.text();
|
|
837
|
+
return {
|
|
838
|
+
content: [{ type: "text", text }],
|
|
839
|
+
isError: !response.ok
|
|
840
|
+
};
|
|
841
|
+
} finally {
|
|
842
|
+
heartbeat.stop();
|
|
843
|
+
}
|
|
789
844
|
}
|
|
790
845
|
);
|
|
791
846
|
}
|