@h-rig/server 0.0.6-alpha.3 → 0.0.6-alpha.31
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 +23 -0
- package/dist/src/index.js +1688 -351
- package/dist/src/server-helpers/github-api-session-index.js +107 -0
- package/dist/src/server-helpers/github-auth-store.js +68 -24
- package/dist/src/server-helpers/github-project-status-sync.js +3 -0
- package/dist/src/server-helpers/github-user-namespace.js +102 -0
- package/dist/src/server-helpers/http-router.js +1040 -200
- package/dist/src/server-helpers/inspector-jobs.js +1 -12
- package/dist/src/server-helpers/issue-analysis.js +26 -10
- package/dist/src/server-helpers/pi-session-proxy.js +84 -0
- package/dist/src/server-helpers/project-registry.js +5 -0
- package/dist/src/server-helpers/run-io.js +30 -1
- package/dist/src/server-helpers/run-mutations.js +679 -123
- package/dist/src/server-helpers/run-writers.js +8 -2
- package/dist/src/server-helpers/ws-router.js +16 -6
- package/dist/src/server.js +1687 -351
- package/package.json +4 -4
|
@@ -3973,21 +3973,10 @@ async function runInspectorLocalReview(projectRoot, input) {
|
|
|
3973
3973
|
details: null
|
|
3974
3974
|
};
|
|
3975
3975
|
}
|
|
3976
|
-
const
|
|
3977
|
-
import("@rig/runtime/control-plane/runtime/events"),
|
|
3978
|
-
import("@rig/runtime/control-plane/runtime/plugins"),
|
|
3979
|
-
import("@rig/runtime/control-plane/native/verifier")
|
|
3980
|
-
]);
|
|
3981
|
-
const eventBus = new RuntimeEventBus({ projectRoot, runId: `inspector-review:${taskId}` });
|
|
3982
|
-
const plugins = await PluginManager.load({
|
|
3983
|
-
projectRoot,
|
|
3984
|
-
runId: `inspector-review:${taskId}`,
|
|
3985
|
-
eventBus
|
|
3986
|
-
});
|
|
3976
|
+
const { verifyTask } = await import("@rig/runtime/control-plane/native/verifier");
|
|
3987
3977
|
const outcome = await verifyTask({
|
|
3988
3978
|
projectRoot,
|
|
3989
3979
|
taskId,
|
|
3990
|
-
plugins,
|
|
3991
3980
|
skipAiReview: true
|
|
3992
3981
|
});
|
|
3993
3982
|
return {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/server/src/server-helpers/issue-analysis.ts
|
|
3
|
-
import { execFile } from "child_process";
|
|
4
3
|
import { createHash } from "crypto";
|
|
5
4
|
function stableIssueHash(issue) {
|
|
6
5
|
const labels = Array.isArray(issue.labels) ? [...issue.labels].map(String).sort() : [];
|
|
@@ -134,16 +133,33 @@ function parseIssueAnalysisResult(raw) {
|
|
|
134
133
|
return result;
|
|
135
134
|
}
|
|
136
135
|
function createDefaultPiIssueAnalysisCommandRunner() {
|
|
137
|
-
return (command, args, options) =>
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const exitCode = typeof error?.code === "number" ? error.code : error ? 1 : 0;
|
|
144
|
-
resolve({ exitCode, stdout: String(stdout ?? ""), stderr: String(stderr ?? "") });
|
|
136
|
+
return async (command, args, options) => {
|
|
137
|
+
const env = options.env ? { ...process.env, ...options.env } : process.env;
|
|
138
|
+
const proc = Bun.spawn([command, ...args], {
|
|
139
|
+
stdout: "pipe",
|
|
140
|
+
stderr: "pipe",
|
|
141
|
+
env
|
|
145
142
|
});
|
|
146
|
-
|
|
143
|
+
let timedOut = false;
|
|
144
|
+
const timer = setTimeout(() => {
|
|
145
|
+
timedOut = true;
|
|
146
|
+
proc.kill();
|
|
147
|
+
}, options.timeoutMs);
|
|
148
|
+
try {
|
|
149
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
150
|
+
new Response(proc.stdout).text(),
|
|
151
|
+
new Response(proc.stderr).text(),
|
|
152
|
+
proc.exited
|
|
153
|
+
]);
|
|
154
|
+
return {
|
|
155
|
+
exitCode: timedOut && exitCode === 0 ? 1 : exitCode,
|
|
156
|
+
stdout,
|
|
157
|
+
stderr: timedOut && stderr.trim().length === 0 ? `Pi issue analysis timed out after ${options.timeoutMs}ms` : stderr
|
|
158
|
+
};
|
|
159
|
+
} finally {
|
|
160
|
+
clearTimeout(timer);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
147
163
|
}
|
|
148
164
|
function createPiIssueAnalyzer(input = {}) {
|
|
149
165
|
const piBinary = input.piBinary ?? process.env.RIG_ISSUE_ANALYSIS_PI_BINARY ?? "pi";
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/server/src/server-helpers/pi-session-proxy.ts
|
|
3
|
+
import { readAuthorityRun as readAuthorityRun2 } from "@rig/runtime/control-plane/authority-files";
|
|
4
|
+
|
|
5
|
+
// packages/server/src/server-helpers/run-io.ts
|
|
6
|
+
import {
|
|
7
|
+
listAuthorityRuns,
|
|
8
|
+
readAuthorityRun,
|
|
9
|
+
readJsonlFile,
|
|
10
|
+
resolveAuthorityRunDir
|
|
11
|
+
} from "@rig/runtime/control-plane/authority-files";
|
|
12
|
+
function readRunPiSessionMetadata(projectRoot, runId) {
|
|
13
|
+
const run = readAuthorityRun(projectRoot, runId);
|
|
14
|
+
const metadata = run?.piSessionPrivate;
|
|
15
|
+
if (!metadata || typeof metadata !== "object" || Array.isArray(metadata))
|
|
16
|
+
return null;
|
|
17
|
+
const record = metadata;
|
|
18
|
+
const publicMetadata = record.public;
|
|
19
|
+
const daemonConnection = record.daemonConnection;
|
|
20
|
+
if (!publicMetadata || typeof publicMetadata !== "object" || Array.isArray(publicMetadata))
|
|
21
|
+
return null;
|
|
22
|
+
if (!daemonConnection || typeof daemonConnection !== "object" || Array.isArray(daemonConnection))
|
|
23
|
+
return null;
|
|
24
|
+
return metadata;
|
|
25
|
+
}
|
|
26
|
+
var INITIAL_RUN_LOG_TAIL_MAX_BYTES = 8 * 1024 * 1024;
|
|
27
|
+
|
|
28
|
+
// packages/server/src/server-helpers/pi-session-proxy.ts
|
|
29
|
+
function resolveRunPiSessionProxy(projectRoot, runId) {
|
|
30
|
+
const run = readAuthorityRun2(projectRoot, runId);
|
|
31
|
+
if (!run)
|
|
32
|
+
return null;
|
|
33
|
+
const privateMetadata = readRunPiSessionMetadata(projectRoot, runId);
|
|
34
|
+
if (!privateMetadata)
|
|
35
|
+
return { pending: true, runId, status: typeof run.status === "string" ? run.status : undefined };
|
|
36
|
+
const connection = privateMetadata.daemonConnection;
|
|
37
|
+
if (connection.mode !== "http")
|
|
38
|
+
throw new Error("Only loopback HTTP Rig Pi session daemon connections are supported");
|
|
39
|
+
const token = tokenFromRef(connection.tokenRef);
|
|
40
|
+
if (!token)
|
|
41
|
+
throw new Error("Rig Pi session daemon token is unavailable");
|
|
42
|
+
return {
|
|
43
|
+
runId,
|
|
44
|
+
sessionId: privateMetadata.public.sessionId,
|
|
45
|
+
metadata: privateMetadata.public,
|
|
46
|
+
privateMetadata,
|
|
47
|
+
baseUrl: connection.baseUrl.replace(/\/+$/, ""),
|
|
48
|
+
token
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
async function proxyRunPiHttp(projectRoot, runId, input) {
|
|
52
|
+
const resolved = resolveRunPiSessionProxy(projectRoot, runId);
|
|
53
|
+
if (resolved === null)
|
|
54
|
+
return { status: 404, payload: { ok: false, error: "Run not found" } };
|
|
55
|
+
if ("pending" in resolved)
|
|
56
|
+
return { status: 409, payload: { ready: false, runId, status: resolved.status, retryAfterMs: 500 } };
|
|
57
|
+
const response = await fetch(`${resolved.baseUrl}${input.daemonPath}`, {
|
|
58
|
+
method: input.method,
|
|
59
|
+
headers: {
|
|
60
|
+
authorization: `Bearer ${resolved.token}`,
|
|
61
|
+
...input.body === undefined ? {} : { "content-type": "application/json" }
|
|
62
|
+
},
|
|
63
|
+
body: input.body === undefined ? undefined : JSON.stringify(input.body)
|
|
64
|
+
});
|
|
65
|
+
const text = await response.text();
|
|
66
|
+
const payload = text.trim() ? JSON.parse(text) : null;
|
|
67
|
+
return { status: response.status, payload };
|
|
68
|
+
}
|
|
69
|
+
function buildRunPiDaemonWebSocketUrl(resolved) {
|
|
70
|
+
const url = new URL(`${resolved.baseUrl}/sessions/${encodeURIComponent(resolved.sessionId)}/events`);
|
|
71
|
+
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
72
|
+
url.searchParams.set("token", resolved.token);
|
|
73
|
+
return url.toString();
|
|
74
|
+
}
|
|
75
|
+
function tokenFromRef(ref) {
|
|
76
|
+
if (ref.startsWith("inline:"))
|
|
77
|
+
return ref.slice("inline:".length) || null;
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
export {
|
|
81
|
+
resolveRunPiSessionProxy,
|
|
82
|
+
proxyRunPiHttp,
|
|
83
|
+
buildRunPiDaemonWebSocketUrl
|
|
84
|
+
};
|
|
@@ -115,8 +115,13 @@ function upsertProjectRecord(projectRoot, input) {
|
|
|
115
115
|
function linkProjectCheckout(projectRoot, repoSlug, checkout) {
|
|
116
116
|
return upsertProjectRecord(projectRoot, { repoSlug, checkout });
|
|
117
117
|
}
|
|
118
|
+
function projectRegistryContainsCheckout(projectRoot, checkoutPath) {
|
|
119
|
+
const target = resolve(checkoutPath);
|
|
120
|
+
return Object.values(readRegistry(projectRoot)).some((project) => project.checkouts.some((checkout) => checkout.path ? resolve(checkout.path) === target : false));
|
|
121
|
+
}
|
|
118
122
|
export {
|
|
119
123
|
upsertProjectRecord,
|
|
124
|
+
projectRegistryContainsCheckout,
|
|
120
125
|
normalizeRepoSlug,
|
|
121
126
|
linkProjectCheckout,
|
|
122
127
|
getProjectRecord,
|
|
@@ -114,14 +114,29 @@ function summarizeUsefulRunError(projectRoot, runId, fallback) {
|
|
|
114
114
|
const nonGeneric = errorLines.at(-1);
|
|
115
115
|
return nonGeneric ?? (typeof fallback === "string" ? fallback : null);
|
|
116
116
|
}
|
|
117
|
+
function readRunPiSessionMetadata(projectRoot, runId) {
|
|
118
|
+
const run = readAuthorityRun(projectRoot, runId);
|
|
119
|
+
const metadata = run?.piSessionPrivate;
|
|
120
|
+
if (!metadata || typeof metadata !== "object" || Array.isArray(metadata))
|
|
121
|
+
return null;
|
|
122
|
+
const record = metadata;
|
|
123
|
+
const publicMetadata = record.public;
|
|
124
|
+
const daemonConnection = record.daemonConnection;
|
|
125
|
+
if (!publicMetadata || typeof publicMetadata !== "object" || Array.isArray(publicMetadata))
|
|
126
|
+
return null;
|
|
127
|
+
if (!daemonConnection || typeof daemonConnection !== "object" || Array.isArray(daemonConnection))
|
|
128
|
+
return null;
|
|
129
|
+
return metadata;
|
|
130
|
+
}
|
|
117
131
|
function readRunDetails(projectRoot, runId) {
|
|
118
132
|
const run = readAuthorityRun(projectRoot, runId);
|
|
119
133
|
if (!run) {
|
|
120
134
|
return null;
|
|
121
135
|
}
|
|
122
136
|
const usefulErrorText = isGenericRunFailure(run.errorText) ? summarizeUsefulRunError(projectRoot, runId, run.errorText) : null;
|
|
137
|
+
const { piSessionPrivate: _piSessionPrivate, ...publicRun } = run;
|
|
123
138
|
return {
|
|
124
|
-
run: usefulErrorText ? { ...
|
|
139
|
+
run: usefulErrorText ? { ...publicRun, errorText: usefulErrorText } : publicRun,
|
|
125
140
|
timeline: readJsonlFile(resolve(resolveAuthorityRunDir(projectRoot, runId), "timeline.jsonl")),
|
|
126
141
|
approvals: readApprovals(projectRoot, { runId }),
|
|
127
142
|
userInputs: readUserInputs(projectRoot, { runId })
|
|
@@ -167,6 +182,18 @@ function readJsonlFileTail(path, options) {
|
|
|
167
182
|
function readRawRunLogs(projectRoot, runId) {
|
|
168
183
|
return readJsonlFile(runLogsPath(projectRoot, runId)).filter((entry) => Boolean(entry && typeof entry === "object"));
|
|
169
184
|
}
|
|
185
|
+
async function readRunTimelinePage(projectRoot, runId, options = {}) {
|
|
186
|
+
const limit = Math.max(1, Math.min(Math.trunc(options.limit ?? 200), 500));
|
|
187
|
+
const cursor = options.cursor == null ? 0 : Number.parseInt(options.cursor, 10);
|
|
188
|
+
const entries = readJsonlFile(runTimelinePath(projectRoot, runId)).filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry)));
|
|
189
|
+
const startInclusive = Number.isFinite(cursor) ? Math.max(0, Math.min(cursor, entries.length)) : 0;
|
|
190
|
+
const endExclusive = Math.min(entries.length, startInclusive + limit);
|
|
191
|
+
return {
|
|
192
|
+
entries: entries.slice(startInclusive, endExclusive).map((entry, offset) => ({ ...entry, cursor: startInclusive + offset + 1 })),
|
|
193
|
+
nextCursor: String(endExclusive),
|
|
194
|
+
hasMore: endExclusive < entries.length
|
|
195
|
+
};
|
|
196
|
+
}
|
|
170
197
|
var INITIAL_RUN_LOG_TAIL_MAX_BYTES = 8 * 1024 * 1024;
|
|
171
198
|
async function readRunLogsPage(projectRoot, runId, options = {}) {
|
|
172
199
|
const limit = Math.max(1, Math.min(Math.trunc(options.limit ?? 200), 500));
|
|
@@ -252,6 +279,8 @@ export {
|
|
|
252
279
|
remoteArtifactsRoot,
|
|
253
280
|
readUserInputsForRuns,
|
|
254
281
|
readUserInputs,
|
|
282
|
+
readRunTimelinePage,
|
|
283
|
+
readRunPiSessionMetadata,
|
|
255
284
|
readRunLogsPage,
|
|
256
285
|
readRunDetails,
|
|
257
286
|
readRawRunLogs,
|