@gemslibe/rbo 0.2.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/LICENSE +644 -0
- package/README.md +33 -0
- package/dist/rbo-mcp-stdio.js +814 -0
- package/dist/rbo.js +14222 -0
- package/package.json +45 -0
|
@@ -0,0 +1,814 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// ../mcp-stdio/src/main.ts
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
|
|
6
|
+
// ../mcp-stdio/src/proxy.ts
|
|
7
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8
|
+
|
|
9
|
+
// ../../packages/shared/dist/versions.js
|
|
10
|
+
var RBO_STDIO_ADAPTER_VERSION = "0.2.0";
|
|
11
|
+
|
|
12
|
+
// ../../packages/shared/dist/errors.js
|
|
13
|
+
import { z } from "zod";
|
|
14
|
+
var ErrorCategorySchema = z.enum([
|
|
15
|
+
"validation",
|
|
16
|
+
"no_matching_agent",
|
|
17
|
+
"no_capacity",
|
|
18
|
+
"source_scan",
|
|
19
|
+
"secret_blocked",
|
|
20
|
+
"repo_clone",
|
|
21
|
+
"repo_fetch",
|
|
22
|
+
"base_commit_missing",
|
|
23
|
+
"bundle_import",
|
|
24
|
+
"snapshot_transfer",
|
|
25
|
+
"snapshot_hash",
|
|
26
|
+
"materialization",
|
|
27
|
+
"workspace_changed",
|
|
28
|
+
"shell_missing",
|
|
29
|
+
"process_spawn",
|
|
30
|
+
"process_exit",
|
|
31
|
+
"timeout",
|
|
32
|
+
"cancelled",
|
|
33
|
+
"agent_lost",
|
|
34
|
+
"artifact_collection",
|
|
35
|
+
"artifact_upload",
|
|
36
|
+
"cleanup",
|
|
37
|
+
"secret_missing",
|
|
38
|
+
"toolchain_changed",
|
|
39
|
+
"agent_disconnected",
|
|
40
|
+
"lease_expired",
|
|
41
|
+
"log_spool_limit",
|
|
42
|
+
"internal"
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
// ../../packages/shared/dist/ids.js
|
|
46
|
+
import { ulid } from "ulid";
|
|
47
|
+
|
|
48
|
+
// ../../packages/shared/dist/paths.js
|
|
49
|
+
var WINDOWS_RESERVED_NAMES = /* @__PURE__ */ new Set([
|
|
50
|
+
"CON",
|
|
51
|
+
"PRN",
|
|
52
|
+
"AUX",
|
|
53
|
+
"NUL",
|
|
54
|
+
"COM1",
|
|
55
|
+
"COM2",
|
|
56
|
+
"COM3",
|
|
57
|
+
"COM4",
|
|
58
|
+
"COM5",
|
|
59
|
+
"COM6",
|
|
60
|
+
"COM7",
|
|
61
|
+
"COM8",
|
|
62
|
+
"COM9",
|
|
63
|
+
"LPT1",
|
|
64
|
+
"LPT2",
|
|
65
|
+
"LPT3",
|
|
66
|
+
"LPT4",
|
|
67
|
+
"LPT5",
|
|
68
|
+
"LPT6",
|
|
69
|
+
"LPT7",
|
|
70
|
+
"LPT8",
|
|
71
|
+
"LPT9"
|
|
72
|
+
]);
|
|
73
|
+
function containsWindowsReservedName(pathStr) {
|
|
74
|
+
const normalized = pathStr.replace(/\\/g, "/");
|
|
75
|
+
for (const segment of normalized.split("/")) {
|
|
76
|
+
if (!segment)
|
|
77
|
+
continue;
|
|
78
|
+
const base = segment.includes(".") ? segment.slice(0, segment.indexOf(".")) : segment;
|
|
79
|
+
if (WINDOWS_RESERVED_NAMES.has(base.toUpperCase())) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
function isSafeRelativePath(value, options) {
|
|
86
|
+
const normalized = value.replace(/\\/g, "/");
|
|
87
|
+
if (normalized === "" || normalized === ".") {
|
|
88
|
+
return options?.allowDot === true;
|
|
89
|
+
}
|
|
90
|
+
if (normalized.startsWith("/") || normalized.startsWith("//") || normalized.startsWith("\\\\") || /^[a-zA-Z]:/.test(normalized) || normalized.includes("://")) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
const parts = normalized.split("/");
|
|
94
|
+
if (parts.some((part) => part === "" || part === "." || part === "..")) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
if (containsWindowsReservedName(normalized)) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ../../packages/shared/dist/controller-identity.js
|
|
104
|
+
import selfsigned from "selfsigned";
|
|
105
|
+
import { ulid as ulid2 } from "ulid";
|
|
106
|
+
|
|
107
|
+
// ../../packages/shared/dist/host-load.js
|
|
108
|
+
var DEFAULT_REFERENCE_CAPACITY_SCORE = 8 * 3e3;
|
|
109
|
+
|
|
110
|
+
// ../../packages/protocol/dist/schemas.js
|
|
111
|
+
import { z as z2 } from "zod";
|
|
112
|
+
var StructuredErrorSchema = z2.object({
|
|
113
|
+
category: ErrorCategorySchema,
|
|
114
|
+
message: z2.string(),
|
|
115
|
+
retryable: z2.boolean(),
|
|
116
|
+
details: z2.record(z2.string(), z2.unknown()).optional()
|
|
117
|
+
});
|
|
118
|
+
var JobStateSchema = z2.enum([
|
|
119
|
+
"created",
|
|
120
|
+
"awaiting_confirmation",
|
|
121
|
+
"queued",
|
|
122
|
+
"matching",
|
|
123
|
+
"leased",
|
|
124
|
+
"preparing_source",
|
|
125
|
+
"transferring_source",
|
|
126
|
+
"materializing",
|
|
127
|
+
"starting",
|
|
128
|
+
"running",
|
|
129
|
+
"orphaned",
|
|
130
|
+
"collecting_artifacts",
|
|
131
|
+
"cleaning",
|
|
132
|
+
"completed"
|
|
133
|
+
]);
|
|
134
|
+
var JobOutcomeSchema = z2.enum(["succeeded", "failed", "timed_out", "cancelled", "lost"]);
|
|
135
|
+
var RiskLevelSchema = z2.enum(["safe", "normal", "destructive", "hardware"]);
|
|
136
|
+
var QueuePolicySchema = z2.enum(["local_fallback", "wait", "fail_fast"]);
|
|
137
|
+
var CompletionPolicySchema = z2.discriminatedUnion("type", [
|
|
138
|
+
z2.object({ type: z2.literal("run_to_exit") }),
|
|
139
|
+
z2.object({ type: z2.literal("run_for_duration"), duration_seconds: z2.number().positive() }),
|
|
140
|
+
z2.object({
|
|
141
|
+
type: z2.literal("run_until_log_match"),
|
|
142
|
+
success_pattern: z2.string().min(1),
|
|
143
|
+
failure_pattern: z2.string().min(1).optional(),
|
|
144
|
+
max_duration_seconds: z2.number().positive()
|
|
145
|
+
})
|
|
146
|
+
]);
|
|
147
|
+
var ShellIdSchema = z2.enum(["bash", "zsh", "sh", "powershell", "pwsh", "cmd", "direct"]);
|
|
148
|
+
var ExecutionConfigSchema = z2.object({
|
|
149
|
+
shell: ShellIdSchema.default("bash"),
|
|
150
|
+
script: z2.string().min(1),
|
|
151
|
+
env: z2.record(z2.string(), z2.string()).default({}),
|
|
152
|
+
// §13.4: values come from the Agent-side named secret store, never through MCP.
|
|
153
|
+
secret_refs: z2.record(z2.string(), z2.string()).optional(),
|
|
154
|
+
timeout_seconds: z2.number().positive().default(3600),
|
|
155
|
+
idle_timeout_seconds: z2.number().positive().optional(),
|
|
156
|
+
cancel_grace_seconds: z2.number().positive().default(10),
|
|
157
|
+
cleanup_script: z2.string().optional(),
|
|
158
|
+
cleanup_timeout_seconds: z2.number().positive().default(60),
|
|
159
|
+
tty: z2.boolean().default(false),
|
|
160
|
+
completion: CompletionPolicySchema.default({ type: "run_to_exit" })
|
|
161
|
+
});
|
|
162
|
+
var JobAdditionalRootSchema = z2.object({
|
|
163
|
+
source_path: z2.string().min(1),
|
|
164
|
+
mount_path: z2.string().min(1).refine((value) => isSafeRelativePath(value), {
|
|
165
|
+
message: "mount_path must be a relative path without '..', absolute, or UNC segments"
|
|
166
|
+
}),
|
|
167
|
+
include: z2.array(z2.string()).default(["**/*"]),
|
|
168
|
+
exclude: z2.array(z2.string()).default([]),
|
|
169
|
+
mode: z2.enum(["read_only", "read_write"]).default("read_only")
|
|
170
|
+
});
|
|
171
|
+
var SourceConfigSchema = z2.object({
|
|
172
|
+
project_root: z2.string().min(1),
|
|
173
|
+
// Relative path only — no absolute paths or `..` segments (§28.2 isolation).
|
|
174
|
+
cwd: z2.string().default(".").refine((value) => isSafeRelativePath(value, { allowDot: true }), {
|
|
175
|
+
message: "cwd must be a relative path without '..' or absolute segments"
|
|
176
|
+
}),
|
|
177
|
+
additional_roots: z2.array(JobAdditionalRootSchema).default([])
|
|
178
|
+
});
|
|
179
|
+
var SourcePolicySchema = z2.object({
|
|
180
|
+
include_untracked: z2.boolean().default(true),
|
|
181
|
+
include_ignored: z2.array(z2.string()).default([]),
|
|
182
|
+
secret_policy: z2.enum(["block", "warn", "allow"]).default("block")
|
|
183
|
+
});
|
|
184
|
+
var RequirementsConfigSchema = z2.object({
|
|
185
|
+
os: z2.array(z2.string()).optional(),
|
|
186
|
+
arch: z2.array(z2.string()).optional(),
|
|
187
|
+
tools: z2.record(z2.string(), z2.string()).optional(),
|
|
188
|
+
labels: z2.record(z2.string(), z2.string()).optional(),
|
|
189
|
+
secret_refs: z2.array(z2.string()).optional(),
|
|
190
|
+
min_memory_mb: z2.number().positive().optional(),
|
|
191
|
+
min_disk_mb: z2.number().positive().optional()
|
|
192
|
+
});
|
|
193
|
+
var PreferencesConfigSchema = z2.object({
|
|
194
|
+
agent_ids: z2.array(z2.string()).optional(),
|
|
195
|
+
os_order: z2.array(z2.string()).optional(),
|
|
196
|
+
prefer_repo_cache: z2.boolean().default(true),
|
|
197
|
+
prefer_build_cache: z2.boolean().default(true),
|
|
198
|
+
allow_local_fallback: z2.boolean().default(true)
|
|
199
|
+
});
|
|
200
|
+
var ArtifactRuleSchema = z2.object({
|
|
201
|
+
glob: z2.string().min(1),
|
|
202
|
+
required: z2.boolean().default(false)
|
|
203
|
+
});
|
|
204
|
+
var JobRequestSchema = z2.object({
|
|
205
|
+
client_request_id: z2.string().min(1),
|
|
206
|
+
name: z2.string().optional(),
|
|
207
|
+
source: SourceConfigSchema,
|
|
208
|
+
execution: ExecutionConfigSchema,
|
|
209
|
+
requirements: RequirementsConfigSchema.optional(),
|
|
210
|
+
preferences: PreferencesConfigSchema.optional(),
|
|
211
|
+
queue_policy: QueuePolicySchema.default("local_fallback"),
|
|
212
|
+
risk_level: RiskLevelSchema.default("normal"),
|
|
213
|
+
intent: z2.string().nullable().optional(),
|
|
214
|
+
source_policy: SourcePolicySchema.optional(),
|
|
215
|
+
artifacts: z2.array(ArtifactRuleSchema).optional()
|
|
216
|
+
});
|
|
217
|
+
var jobEventBase = {
|
|
218
|
+
sequence: z2.number().int().positive(),
|
|
219
|
+
created_at: z2.string().min(1),
|
|
220
|
+
job_id: z2.string().min(1),
|
|
221
|
+
attempt_id: z2.string().min(1)
|
|
222
|
+
};
|
|
223
|
+
var JobEventSchema = z2.discriminatedUnion("type", [
|
|
224
|
+
z2.object({
|
|
225
|
+
type: z2.literal("state_transition"),
|
|
226
|
+
...jobEventBase,
|
|
227
|
+
from_state: JobStateSchema,
|
|
228
|
+
to_state: JobStateSchema
|
|
229
|
+
}),
|
|
230
|
+
z2.object({
|
|
231
|
+
type: z2.literal("snapshot_captured"),
|
|
232
|
+
...jobEventBase,
|
|
233
|
+
snapshot_id: z2.string().min(1),
|
|
234
|
+
content_id: z2.string().min(1)
|
|
235
|
+
}),
|
|
236
|
+
z2.object({
|
|
237
|
+
type: z2.literal("materialized"),
|
|
238
|
+
...jobEventBase,
|
|
239
|
+
workspace: z2.string().min(1)
|
|
240
|
+
}),
|
|
241
|
+
z2.object({
|
|
242
|
+
type: z2.literal("process_started"),
|
|
243
|
+
...jobEventBase,
|
|
244
|
+
workspace: z2.string().min(1),
|
|
245
|
+
pid: z2.number().int().positive().optional()
|
|
246
|
+
}),
|
|
247
|
+
z2.object({
|
|
248
|
+
type: z2.literal("artifact_collected"),
|
|
249
|
+
...jobEventBase,
|
|
250
|
+
artifact_id: z2.string().min(1),
|
|
251
|
+
path: z2.string().min(1),
|
|
252
|
+
sha256: z2.string().min(1)
|
|
253
|
+
}),
|
|
254
|
+
z2.object({
|
|
255
|
+
type: z2.literal("artifact_skipped"),
|
|
256
|
+
...jobEventBase,
|
|
257
|
+
path: z2.string().min(1),
|
|
258
|
+
reason: z2.string().min(1)
|
|
259
|
+
}),
|
|
260
|
+
z2.object({
|
|
261
|
+
type: z2.literal("artifact_limit_exceeded"),
|
|
262
|
+
...jobEventBase,
|
|
263
|
+
reason: z2.enum(["file_count", "total_bytes"]),
|
|
264
|
+
limit: z2.number().int().positive(),
|
|
265
|
+
actual: z2.number().int().positive()
|
|
266
|
+
}),
|
|
267
|
+
z2.object({
|
|
268
|
+
type: z2.literal("secret_warning"),
|
|
269
|
+
...jobEventBase,
|
|
270
|
+
path: z2.string().min(1),
|
|
271
|
+
reason: z2.string().min(1)
|
|
272
|
+
}),
|
|
273
|
+
z2.object({
|
|
274
|
+
type: z2.literal("env_override_ignored"),
|
|
275
|
+
...jobEventBase,
|
|
276
|
+
name: z2.string().min(1),
|
|
277
|
+
reason: z2.string().min(1)
|
|
278
|
+
}),
|
|
279
|
+
z2.object({
|
|
280
|
+
type: z2.literal("cancel_requested"),
|
|
281
|
+
...jobEventBase,
|
|
282
|
+
reason: z2.string().optional(),
|
|
283
|
+
signalled: z2.boolean()
|
|
284
|
+
}),
|
|
285
|
+
z2.object({
|
|
286
|
+
type: z2.literal("cleanup_error"),
|
|
287
|
+
...jobEventBase,
|
|
288
|
+
exit_code: z2.number().int().nullable(),
|
|
289
|
+
timed_out: z2.boolean(),
|
|
290
|
+
message: z2.string().min(1)
|
|
291
|
+
}),
|
|
292
|
+
z2.object({
|
|
293
|
+
type: z2.literal("error"),
|
|
294
|
+
...jobEventBase,
|
|
295
|
+
category: ErrorCategorySchema,
|
|
296
|
+
message: z2.string().min(1)
|
|
297
|
+
})
|
|
298
|
+
]);
|
|
299
|
+
var ToolchainProfileSchema = z2.object({
|
|
300
|
+
id: z2.string(),
|
|
301
|
+
kind: z2.string(),
|
|
302
|
+
version: z2.string(),
|
|
303
|
+
platform: z2.string(),
|
|
304
|
+
activation: z2.object({
|
|
305
|
+
type: z2.enum(["source_script", "environment_variables", "path_prepend"]),
|
|
306
|
+
path: z2.string().optional(),
|
|
307
|
+
env: z2.record(z2.string(), z2.string()).optional()
|
|
308
|
+
}),
|
|
309
|
+
environment_fingerprint: z2.string()
|
|
310
|
+
});
|
|
311
|
+
var BuildCacheKindSchema = z2.enum(["ccache", "sccache", "npm", "pnpm", "pip"]);
|
|
312
|
+
var AgentCapabilityReportSchema = z2.object({
|
|
313
|
+
agent_id: z2.string(),
|
|
314
|
+
display_name: z2.string(),
|
|
315
|
+
hostname: z2.string(),
|
|
316
|
+
os: z2.object({
|
|
317
|
+
family: z2.enum(["macos", "windows", "linux"]),
|
|
318
|
+
version: z2.string(),
|
|
319
|
+
arch: z2.string()
|
|
320
|
+
}),
|
|
321
|
+
resources: z2.object({
|
|
322
|
+
cpu_logical: z2.number(),
|
|
323
|
+
memory_total_mb: z2.number(),
|
|
324
|
+
memory_free_mb: z2.number(),
|
|
325
|
+
disk_free_mb: z2.number(),
|
|
326
|
+
/**
|
|
327
|
+
* Agent-reported CPU busy fraction in [0, 1] for §19.2 scheduler scoring.
|
|
328
|
+
* Missing at schedule time is treated as 1 (pessimistic) by the Controller.
|
|
329
|
+
*/
|
|
330
|
+
cpu_load: z2.number().min(0).max(1).optional(),
|
|
331
|
+
/** Additive Phase 6 capacity fields (bytes). */
|
|
332
|
+
disk_free_bytes: z2.number().nonnegative().optional(),
|
|
333
|
+
disk_min_free_bytes: z2.number().nonnegative().optional(),
|
|
334
|
+
disk_pressure: z2.boolean().optional(),
|
|
335
|
+
/**
|
|
336
|
+
* Primary-core clock speed (MHz) from os.cpus()[0].speed, for host-aware scheduling's
|
|
337
|
+
* capacity score (cpu_logical * cpu_speed_mhz). Optional — missing is treated as an
|
|
338
|
+
* unknown/lowest-priority capacity by the Controller, same spirit as cpu_load's pessimistic
|
|
339
|
+
* default above.
|
|
340
|
+
*/
|
|
341
|
+
cpu_speed_mhz: z2.number().nonnegative().optional()
|
|
342
|
+
}),
|
|
343
|
+
execution: z2.object({
|
|
344
|
+
max_jobs: z2.number(),
|
|
345
|
+
shells: z2.array(z2.string()),
|
|
346
|
+
supports_tty: z2.boolean(),
|
|
347
|
+
supports_process_tree_kill: z2.boolean()
|
|
348
|
+
}),
|
|
349
|
+
tools: z2.record(z2.string(), z2.array(z2.string())),
|
|
350
|
+
toolchain_profiles: z2.array(ToolchainProfileSchema),
|
|
351
|
+
labels: z2.record(z2.string(), z2.string()),
|
|
352
|
+
secret_refs: z2.array(z2.string()),
|
|
353
|
+
/**
|
|
354
|
+
* Optional Phase 5 repository-cache advertisement for scheduler affinity (§19.2).
|
|
355
|
+
* Agents may report canonical ids (and optionally known commits) present in mirrors.
|
|
356
|
+
*/
|
|
357
|
+
repository_cache: z2.array(z2.object({
|
|
358
|
+
canonical_id: z2.string().min(1),
|
|
359
|
+
/** Optional known commits present in the mirror (best-effort). */
|
|
360
|
+
commits: z2.array(z2.string().min(1)).optional()
|
|
361
|
+
})).optional(),
|
|
362
|
+
/**
|
|
363
|
+
* Optional Phase 7 named build-cache advertisement for scheduler affinity.
|
|
364
|
+
* Opaque cache identity keys currently present (hashes only — no secrets).
|
|
365
|
+
*/
|
|
366
|
+
build_caches: z2.array(z2.object({
|
|
367
|
+
kind: BuildCacheKindSchema,
|
|
368
|
+
keys: z2.array(z2.string().min(1)).optional()
|
|
369
|
+
})).optional(),
|
|
370
|
+
/** Phase 6: false under disk/spool pressure — Agent also lease_rejects. */
|
|
371
|
+
accepting_jobs: z2.boolean().optional(),
|
|
372
|
+
/**
|
|
373
|
+
* Operator-configured scheduling priority (§19.2 / §19.3). When unset, the
|
|
374
|
+
* Controller applies OS-family defaults at schedule time.
|
|
375
|
+
*/
|
|
376
|
+
configured_priority: z2.number().optional()
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
// ../../packages/protocol/dist/messages.js
|
|
380
|
+
import { z as z3 } from "zod";
|
|
381
|
+
var AgentMessageTypeSchema = z3.enum([
|
|
382
|
+
"hello",
|
|
383
|
+
"pairing_request",
|
|
384
|
+
"capabilities",
|
|
385
|
+
"heartbeat",
|
|
386
|
+
"lease_accept",
|
|
387
|
+
"lease_reject",
|
|
388
|
+
"source_need",
|
|
389
|
+
"source_ready",
|
|
390
|
+
"job_started",
|
|
391
|
+
"log_chunk",
|
|
392
|
+
"job_exit",
|
|
393
|
+
"artifact_manifest",
|
|
394
|
+
"cleanup_complete",
|
|
395
|
+
"agent_error",
|
|
396
|
+
"recovery_report"
|
|
397
|
+
]);
|
|
398
|
+
var ControllerMessageTypeSchema = z3.enum([
|
|
399
|
+
"hello_ack",
|
|
400
|
+
"pairing_challenge",
|
|
401
|
+
"lease_offer",
|
|
402
|
+
"prepare_source",
|
|
403
|
+
"snapshot_download",
|
|
404
|
+
"bundle_download",
|
|
405
|
+
"run_job",
|
|
406
|
+
"cancel_job",
|
|
407
|
+
"artifact_upload_grant",
|
|
408
|
+
"pause",
|
|
409
|
+
"resume",
|
|
410
|
+
"refresh_capabilities",
|
|
411
|
+
"shutdown",
|
|
412
|
+
"log_ack",
|
|
413
|
+
"reconcile_decision"
|
|
414
|
+
]);
|
|
415
|
+
var ProtocolMessageTypeSchema = z3.enum([
|
|
416
|
+
...AgentMessageTypeSchema.options,
|
|
417
|
+
...ControllerMessageTypeSchema.options
|
|
418
|
+
]);
|
|
419
|
+
var JOB_SCOPED_MESSAGE_TYPES = /* @__PURE__ */ new Set([
|
|
420
|
+
"lease_offer",
|
|
421
|
+
"lease_accept",
|
|
422
|
+
"lease_reject",
|
|
423
|
+
"prepare_source",
|
|
424
|
+
"snapshot_download",
|
|
425
|
+
"bundle_download",
|
|
426
|
+
"run_job",
|
|
427
|
+
"cancel_job",
|
|
428
|
+
"source_need",
|
|
429
|
+
"source_ready",
|
|
430
|
+
"job_started",
|
|
431
|
+
"log_chunk",
|
|
432
|
+
"job_exit",
|
|
433
|
+
"artifact_manifest",
|
|
434
|
+
"artifact_upload_grant",
|
|
435
|
+
"cleanup_complete",
|
|
436
|
+
"log_ack",
|
|
437
|
+
"recovery_report",
|
|
438
|
+
"reconcile_decision"
|
|
439
|
+
]);
|
|
440
|
+
var LeaseOfferPayloadSchema = z3.object({
|
|
441
|
+
attempt_id: z3.string().min(1),
|
|
442
|
+
lease_id: z3.string().min(1),
|
|
443
|
+
lease_epoch: z3.number().int().positive(),
|
|
444
|
+
/** Controller-assigned job id — injected as RBO_JOB_ID on the Agent. */
|
|
445
|
+
job_id: z3.string().min(1),
|
|
446
|
+
job_request: JobRequestSchema,
|
|
447
|
+
snapshot_metadata: z3.object({
|
|
448
|
+
snapshot_id: z3.string().min(1),
|
|
449
|
+
content_id: z3.string().min(1),
|
|
450
|
+
size_bytes: z3.number().int().nonnegative(),
|
|
451
|
+
sha256: z3.string().min(1)
|
|
452
|
+
}),
|
|
453
|
+
selected_toolchain_profiles: z3.array(ToolchainProfileSchema).optional(),
|
|
454
|
+
lease_ttl_seconds: z3.number().positive()
|
|
455
|
+
});
|
|
456
|
+
var LeaseAcceptPayloadSchema = z3.object({
|
|
457
|
+
attempt_id: z3.string().min(1),
|
|
458
|
+
lease_id: z3.string().min(1),
|
|
459
|
+
lease_epoch: z3.number().int().positive()
|
|
460
|
+
});
|
|
461
|
+
var LeaseRejectPayloadSchema = z3.object({
|
|
462
|
+
attempt_id: z3.string().min(1),
|
|
463
|
+
lease_id: z3.string().min(1),
|
|
464
|
+
lease_epoch: z3.number().int().positive(),
|
|
465
|
+
reason: z3.string().min(1)
|
|
466
|
+
});
|
|
467
|
+
var SourceNeedReasonSchema = z3.enum([
|
|
468
|
+
"base_present",
|
|
469
|
+
"base_commit_missing",
|
|
470
|
+
"bundle_required",
|
|
471
|
+
"full_snapshot_required",
|
|
472
|
+
"repo_fetch_failed"
|
|
473
|
+
]);
|
|
474
|
+
var DataTransferDescriptorSchema = z3.object({
|
|
475
|
+
download_url: z3.string().min(1),
|
|
476
|
+
data_token: z3.string().min(1),
|
|
477
|
+
expected_size_bytes: z3.number().int().nonnegative(),
|
|
478
|
+
expected_sha256: z3.string().min(1)
|
|
479
|
+
});
|
|
480
|
+
var PrepareSourceRepoSchema = z3.object({
|
|
481
|
+
url: z3.string().min(1),
|
|
482
|
+
canonical_id: z3.string().min(1),
|
|
483
|
+
branch: z3.string().nullable(),
|
|
484
|
+
base_commit: z3.string().min(1),
|
|
485
|
+
fetch_refs: z3.array(z3.string().min(1)).default([])
|
|
486
|
+
});
|
|
487
|
+
var PrepareSourceFullPayloadSchema = z3.object({
|
|
488
|
+
source_mode: z3.literal("full"),
|
|
489
|
+
attempt_id: z3.string().min(1),
|
|
490
|
+
lease_id: z3.string().min(1),
|
|
491
|
+
lease_epoch: z3.number().int().positive(),
|
|
492
|
+
download_url: z3.string().min(1),
|
|
493
|
+
data_token: z3.string().min(1),
|
|
494
|
+
expected_size_bytes: z3.number().int().nonnegative(),
|
|
495
|
+
expected_sha256: z3.string().min(1),
|
|
496
|
+
manifest: z3.unknown().optional()
|
|
497
|
+
});
|
|
498
|
+
var PrepareSourceGitOverlayPayloadSchema = z3.object({
|
|
499
|
+
source_mode: z3.literal("git_overlay"),
|
|
500
|
+
attempt_id: z3.string().min(1),
|
|
501
|
+
lease_id: z3.string().min(1),
|
|
502
|
+
lease_epoch: z3.number().int().positive(),
|
|
503
|
+
repo: PrepareSourceRepoSchema,
|
|
504
|
+
overlay: DataTransferDescriptorSchema,
|
|
505
|
+
manifest: z3.unknown().optional()
|
|
506
|
+
});
|
|
507
|
+
var PrepareSourcePayloadSchema = z3.discriminatedUnion("source_mode", [
|
|
508
|
+
PrepareSourceFullPayloadSchema,
|
|
509
|
+
PrepareSourceGitOverlayPayloadSchema
|
|
510
|
+
]);
|
|
511
|
+
var SourceNeedPayloadSchema = z3.object({
|
|
512
|
+
attempt_id: z3.string().min(1),
|
|
513
|
+
lease_id: z3.string().min(1),
|
|
514
|
+
lease_epoch: z3.number().int().positive(),
|
|
515
|
+
reason: SourceNeedReasonSchema,
|
|
516
|
+
detail: z3.string().optional()
|
|
517
|
+
});
|
|
518
|
+
var BundleDownloadPayloadSchema = z3.object({
|
|
519
|
+
attempt_id: z3.string().min(1),
|
|
520
|
+
lease_id: z3.string().min(1),
|
|
521
|
+
lease_epoch: z3.number().int().positive(),
|
|
522
|
+
download_url: z3.string().min(1),
|
|
523
|
+
data_token: z3.string().min(1),
|
|
524
|
+
expected_size_bytes: z3.number().int().nonnegative(),
|
|
525
|
+
expected_sha256: z3.string().min(1)
|
|
526
|
+
});
|
|
527
|
+
var SourceReadyPayloadSchema = z3.object({
|
|
528
|
+
attempt_id: z3.string().min(1),
|
|
529
|
+
lease_id: z3.string().min(1),
|
|
530
|
+
lease_epoch: z3.number().int().positive()
|
|
531
|
+
});
|
|
532
|
+
var RunJobPayloadSchema = z3.object({
|
|
533
|
+
attempt_id: z3.string().min(1),
|
|
534
|
+
lease_id: z3.string().min(1),
|
|
535
|
+
lease_epoch: z3.number().int().positive()
|
|
536
|
+
});
|
|
537
|
+
var CancelJobPayloadSchema = z3.object({
|
|
538
|
+
attempt_id: z3.string().min(1),
|
|
539
|
+
lease_id: z3.string().min(1),
|
|
540
|
+
lease_epoch: z3.number().int().positive(),
|
|
541
|
+
grace_seconds: z3.number().positive().default(10),
|
|
542
|
+
reason: z3.string().optional()
|
|
543
|
+
});
|
|
544
|
+
var JobStartedPayloadSchema = z3.object({
|
|
545
|
+
attempt_id: z3.string().min(1),
|
|
546
|
+
lease_id: z3.string().min(1),
|
|
547
|
+
lease_epoch: z3.number().int().positive(),
|
|
548
|
+
pid: z3.number().int().positive().optional()
|
|
549
|
+
});
|
|
550
|
+
var LogChunkPayloadSchema = z3.object({
|
|
551
|
+
attempt_id: z3.string().min(1),
|
|
552
|
+
lease_id: z3.string().min(1),
|
|
553
|
+
lease_epoch: z3.number().int().positive(),
|
|
554
|
+
stream: z3.enum(["stdout", "stderr"]),
|
|
555
|
+
sequence: z3.number().int().positive(),
|
|
556
|
+
bytes: z3.string()
|
|
557
|
+
});
|
|
558
|
+
var JobExitPayloadSchema = z3.object({
|
|
559
|
+
attempt_id: z3.string().min(1),
|
|
560
|
+
lease_id: z3.string().min(1),
|
|
561
|
+
lease_epoch: z3.number().int().positive(),
|
|
562
|
+
exit_code: z3.number().int().nullable(),
|
|
563
|
+
outcome: JobOutcomeSchema,
|
|
564
|
+
failure_category: ErrorCategorySchema.optional(),
|
|
565
|
+
failure_message: z3.string().optional()
|
|
566
|
+
});
|
|
567
|
+
var ArtifactManifestPayloadSchema = z3.object({
|
|
568
|
+
attempt_id: z3.string().min(1),
|
|
569
|
+
lease_id: z3.string().min(1),
|
|
570
|
+
lease_epoch: z3.number().int().positive(),
|
|
571
|
+
artifacts: z3.array(z3.object({
|
|
572
|
+
logical_name: z3.string().min(1),
|
|
573
|
+
path: z3.string().min(1),
|
|
574
|
+
size_bytes: z3.number().int().nonnegative(),
|
|
575
|
+
sha256: z3.string().min(1)
|
|
576
|
+
}))
|
|
577
|
+
});
|
|
578
|
+
var ArtifactUploadGrantPayloadSchema = z3.object({
|
|
579
|
+
attempt_id: z3.string().min(1),
|
|
580
|
+
lease_id: z3.string().min(1),
|
|
581
|
+
lease_epoch: z3.number().int().positive(),
|
|
582
|
+
artifacts: z3.array(z3.object({
|
|
583
|
+
logical_name: z3.string().min(1),
|
|
584
|
+
path: z3.string().min(1),
|
|
585
|
+
size_bytes: z3.number().int().nonnegative(),
|
|
586
|
+
sha256: z3.string().min(1),
|
|
587
|
+
upload_url: z3.string().min(1),
|
|
588
|
+
upload_token: z3.string().min(1)
|
|
589
|
+
}))
|
|
590
|
+
});
|
|
591
|
+
var CleanupCompletePayloadSchema = z3.object({
|
|
592
|
+
attempt_id: z3.string().min(1),
|
|
593
|
+
lease_id: z3.string().min(1),
|
|
594
|
+
lease_epoch: z3.number().int().positive(),
|
|
595
|
+
exit_code: z3.number().int().nullable(),
|
|
596
|
+
timed_out: z3.boolean(),
|
|
597
|
+
message: z3.string().optional()
|
|
598
|
+
});
|
|
599
|
+
var LogAckPayloadSchema = z3.object({
|
|
600
|
+
attempt_id: z3.string().min(1),
|
|
601
|
+
lease_id: z3.string().min(1),
|
|
602
|
+
lease_epoch: z3.number().int().positive(),
|
|
603
|
+
sequence: z3.number().int().positive()
|
|
604
|
+
});
|
|
605
|
+
var RecoveryReportStatusSchema = z3.enum([
|
|
606
|
+
"running",
|
|
607
|
+
"completed_awaiting_upload",
|
|
608
|
+
"orphaned"
|
|
609
|
+
]);
|
|
610
|
+
var RecoveryReportPayloadSchema = z3.object({
|
|
611
|
+
attempt_id: z3.string().min(1),
|
|
612
|
+
lease_id: z3.string().min(1),
|
|
613
|
+
lease_epoch: z3.number().int().positive(),
|
|
614
|
+
status: RecoveryReportStatusSchema,
|
|
615
|
+
process_identity: z3.string().min(1),
|
|
616
|
+
last_sent_sequence: z3.number().int().nonnegative(),
|
|
617
|
+
last_acked_sequence: z3.number().int().nonnegative(),
|
|
618
|
+
artifact_upload_pending: z3.boolean()
|
|
619
|
+
});
|
|
620
|
+
var ReconcileDecisionPayloadSchema = z3.object({
|
|
621
|
+
attempt_id: z3.string().min(1),
|
|
622
|
+
lease_id: z3.string().min(1),
|
|
623
|
+
lease_epoch: z3.number().int().positive(),
|
|
624
|
+
action: z3.enum(["adopt", "terminate_stale"]),
|
|
625
|
+
resume_from_sequence: z3.number().int().nonnegative().optional(),
|
|
626
|
+
reason: z3.string().optional()
|
|
627
|
+
});
|
|
628
|
+
var WireMessageEnvelopeSchema = z3.object({
|
|
629
|
+
protocol: z3.number().int().positive(),
|
|
630
|
+
type: ProtocolMessageTypeSchema,
|
|
631
|
+
message_id: z3.string(),
|
|
632
|
+
sent_at: z3.string(),
|
|
633
|
+
attempt_id: z3.string().nullable(),
|
|
634
|
+
lease_id: z3.string().nullable(),
|
|
635
|
+
lease_epoch: z3.number().nullable(),
|
|
636
|
+
payload: z3.record(z3.string(), z3.unknown())
|
|
637
|
+
}).superRefine((msg, ctx) => {
|
|
638
|
+
if (JOB_SCOPED_MESSAGE_TYPES.has(msg.type)) {
|
|
639
|
+
if (msg.attempt_id === null || msg.lease_id === null || msg.lease_epoch === null) {
|
|
640
|
+
ctx.addIssue({
|
|
641
|
+
code: z3.ZodIssueCode.custom,
|
|
642
|
+
message: `job-scoped message '${msg.type}' requires attempt_id, lease_id and lease_epoch (\xA720.2)`
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
// ../../packages/protocol/dist/mcp-tools.js
|
|
649
|
+
import { z as z4 } from "zod";
|
|
650
|
+
var JOB_SUBMIT_INPUT = JobRequestSchema.shape;
|
|
651
|
+
var JOB_CONFIRM_INPUT = {
|
|
652
|
+
job_id: z4.string().min(1),
|
|
653
|
+
confirmation_token: z4.string().min(1)
|
|
654
|
+
};
|
|
655
|
+
var AGENTS_LIST_INPUT = {
|
|
656
|
+
include_offline: z4.boolean().default(false)
|
|
657
|
+
};
|
|
658
|
+
var JOB_GET_INPUT = {
|
|
659
|
+
job_id: z4.string().min(1)
|
|
660
|
+
};
|
|
661
|
+
var JOB_WAIT_INPUT = {
|
|
662
|
+
job_id: z4.string().min(1),
|
|
663
|
+
wait_seconds: z4.number().int().min(0).max(300).default(30),
|
|
664
|
+
include_log_tail_lines: z4.number().int().min(0).max(1e3).default(0)
|
|
665
|
+
};
|
|
666
|
+
var JOB_LOGS_INPUT = {
|
|
667
|
+
job_id: z4.string().min(1),
|
|
668
|
+
// null means "current active attempt, or terminal attempt for a terminal job" (§23.5)
|
|
669
|
+
attempt_id: z4.string().nullable().default(null),
|
|
670
|
+
cursor: z4.number().int().min(0).default(0),
|
|
671
|
+
max_bytes: z4.number().int().positive().max(1024 * 1024).default(65536),
|
|
672
|
+
streams: z4.array(z4.enum(["stdout", "stderr", "events"])).default(["stdout", "stderr"])
|
|
673
|
+
};
|
|
674
|
+
var JOB_CANCEL_INPUT = {
|
|
675
|
+
job_id: z4.string().min(1),
|
|
676
|
+
reason: z4.string().optional()
|
|
677
|
+
};
|
|
678
|
+
var JOB_ARTIFACTS_INPUT = {
|
|
679
|
+
job_id: z4.string().min(1)
|
|
680
|
+
};
|
|
681
|
+
var ARTIFACT_MATERIALIZE_INPUT = {
|
|
682
|
+
artifact_id: z4.string().min(1),
|
|
683
|
+
destination_path: z4.string().min(1),
|
|
684
|
+
overwrite: z4.boolean().default(false)
|
|
685
|
+
};
|
|
686
|
+
var AGENT_PROBE_INPUT = {
|
|
687
|
+
agent_id: z4.string().min(1)
|
|
688
|
+
};
|
|
689
|
+
var MCP_TOOL_DEFS = [
|
|
690
|
+
{
|
|
691
|
+
name: "agents_list",
|
|
692
|
+
description: "List registered worker agents and their capabilities.",
|
|
693
|
+
inputShape: AGENTS_LIST_INPUT
|
|
694
|
+
},
|
|
695
|
+
{
|
|
696
|
+
name: "job_submit",
|
|
697
|
+
description: "Submit a build/test job and capture an immutable workspace snapshot.",
|
|
698
|
+
inputShape: JOB_SUBMIT_INPUT
|
|
699
|
+
},
|
|
700
|
+
{
|
|
701
|
+
name: "job_confirm",
|
|
702
|
+
description: "Confirm a destructive or hardware-risk job after snapshot capture.",
|
|
703
|
+
inputShape: JOB_CONFIRM_INPUT
|
|
704
|
+
},
|
|
705
|
+
{
|
|
706
|
+
name: "job_get",
|
|
707
|
+
description: "Get current state and metadata of a job.",
|
|
708
|
+
inputShape: JOB_GET_INPUT
|
|
709
|
+
},
|
|
710
|
+
{
|
|
711
|
+
name: "job_wait",
|
|
712
|
+
description: "Wait up to wait_seconds for a job to reach a terminal state; returns current state otherwise.",
|
|
713
|
+
inputShape: JOB_WAIT_INPUT
|
|
714
|
+
},
|
|
715
|
+
{
|
|
716
|
+
name: "job_logs",
|
|
717
|
+
description: "Read incremental job logs from an attempt-scoped cursor.",
|
|
718
|
+
inputShape: JOB_LOGS_INPUT
|
|
719
|
+
},
|
|
720
|
+
{
|
|
721
|
+
name: "job_cancel",
|
|
722
|
+
description: "Cancel a running or queued job.",
|
|
723
|
+
inputShape: JOB_CANCEL_INPUT
|
|
724
|
+
},
|
|
725
|
+
{
|
|
726
|
+
name: "job_artifacts",
|
|
727
|
+
description: "List collected artifacts of a job, grouped by attempt.",
|
|
728
|
+
inputShape: JOB_ARTIFACTS_INPUT
|
|
729
|
+
},
|
|
730
|
+
{
|
|
731
|
+
name: "artifact_materialize",
|
|
732
|
+
description: "Copy one stored artifact into an allowed local destination path on the development PC.",
|
|
733
|
+
inputShape: ARTIFACT_MATERIALIZE_INPUT
|
|
734
|
+
},
|
|
735
|
+
{
|
|
736
|
+
name: "agent_probe",
|
|
737
|
+
description: "Trigger a capability re-probe of one agent.",
|
|
738
|
+
inputShape: AGENT_PROBE_INPUT
|
|
739
|
+
}
|
|
740
|
+
];
|
|
741
|
+
|
|
742
|
+
// ../../packages/protocol/dist/compatibility-matrix.js
|
|
743
|
+
import { z as z5 } from "zod";
|
|
744
|
+
var CompatibilityCellSchema = z5.object({
|
|
745
|
+
client: z5.string().min(1),
|
|
746
|
+
transport: z5.enum(["stdio", "streamable_http"]),
|
|
747
|
+
status: z5.enum(["verified", "not_verified"]),
|
|
748
|
+
revision: z5.string().min(1),
|
|
749
|
+
os: z5.string().min(1),
|
|
750
|
+
client_version: z5.string().min(1),
|
|
751
|
+
config_ref: z5.string().min(1),
|
|
752
|
+
workflow: z5.string().min(1),
|
|
753
|
+
limitation: z5.string().optional(),
|
|
754
|
+
evidence_path: z5.string().optional()
|
|
755
|
+
});
|
|
756
|
+
var CompatibilityMatrixSchema = z5.object({
|
|
757
|
+
schema_version: z5.literal(1),
|
|
758
|
+
generated_at: z5.string().min(1),
|
|
759
|
+
policy: z5.string().min(1),
|
|
760
|
+
cells: z5.array(CompatibilityCellSchema).min(1)
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
// ../mcp-stdio/src/proxy.ts
|
|
764
|
+
function createStdioProxyServer(options) {
|
|
765
|
+
const server = new McpServer({
|
|
766
|
+
name: "rbo-mcp-stdio",
|
|
767
|
+
version: RBO_STDIO_ADAPTER_VERSION
|
|
768
|
+
});
|
|
769
|
+
const baseUrl = options.controllerUrl.replace(/\/+$/, "");
|
|
770
|
+
for (const def of MCP_TOOL_DEFS) {
|
|
771
|
+
server.registerTool(
|
|
772
|
+
def.name,
|
|
773
|
+
{ description: def.description, inputSchema: def.inputShape },
|
|
774
|
+
async (args) => {
|
|
775
|
+
const response = await fetch(`${baseUrl}/internal/v1/tools/${def.name}`, {
|
|
776
|
+
method: "POST",
|
|
777
|
+
headers: {
|
|
778
|
+
"content-type": "application/json",
|
|
779
|
+
"x-rbo-client-id": options.clientId,
|
|
780
|
+
"x-rbo-client-transport": "stdio"
|
|
781
|
+
},
|
|
782
|
+
body: JSON.stringify(args ?? {})
|
|
783
|
+
});
|
|
784
|
+
const text = await response.text();
|
|
785
|
+
return {
|
|
786
|
+
content: [{ type: "text", text }],
|
|
787
|
+
isError: !response.ok
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
);
|
|
791
|
+
}
|
|
792
|
+
return server;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// ../mcp-stdio/src/main.ts
|
|
796
|
+
function argValue(flag) {
|
|
797
|
+
const index = process.argv.indexOf(flag);
|
|
798
|
+
if (index === -1 || index + 1 >= process.argv.length) {
|
|
799
|
+
return void 0;
|
|
800
|
+
}
|
|
801
|
+
return process.argv[index + 1];
|
|
802
|
+
}
|
|
803
|
+
async function main() {
|
|
804
|
+
const controllerUrl = argValue("--controller") ?? process.env.RBO_CONTROLLER_URL ?? "http://127.0.0.1:7410";
|
|
805
|
+
const clientId = argValue("--client-id") ?? process.env.RBO_CLIENT_ID ?? `mcp-stdio-${process.pid}`;
|
|
806
|
+
const server = createStdioProxyServer({ controllerUrl, clientId });
|
|
807
|
+
const transport = new StdioServerTransport();
|
|
808
|
+
await server.connect(transport);
|
|
809
|
+
console.error(`rbo mcp-stdio connected to ${controllerUrl} as ${clientId}`);
|
|
810
|
+
}
|
|
811
|
+
main().catch((error) => {
|
|
812
|
+
console.error(`rbo mcp-stdio failed: ${String(error)}`);
|
|
813
|
+
process.exit(1);
|
|
814
|
+
});
|