@h-rig/server 0.0.6-alpha.22 → 0.0.6-alpha.23
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/src/index.js +313 -57
- package/dist/src/server-helpers/http-router.js +157 -6
- package/dist/src/server-helpers/pi-session-proxy.js +84 -0
- package/dist/src/server-helpers/run-io.js +17 -1
- package/dist/src/server-helpers/run-mutations.js +134 -59
- package/dist/src/server-helpers/run-writers.js +7 -0
- package/dist/src/server-helpers/ws-router.js +9 -5
- package/dist/src/server.js +313 -57
- package/package.json +4 -4
|
@@ -174,14 +174,29 @@ function summarizeUsefulRunError(projectRoot, runId, fallback) {
|
|
|
174
174
|
const nonGeneric = errorLines.at(-1);
|
|
175
175
|
return nonGeneric ?? (typeof fallback === "string" ? fallback : null);
|
|
176
176
|
}
|
|
177
|
+
function readRunPiSessionMetadata(projectRoot, runId) {
|
|
178
|
+
const run = readAuthorityRun(projectRoot, runId);
|
|
179
|
+
const metadata = run?.piSessionPrivate;
|
|
180
|
+
if (!metadata || typeof metadata !== "object" || Array.isArray(metadata))
|
|
181
|
+
return null;
|
|
182
|
+
const record = metadata;
|
|
183
|
+
const publicMetadata = record.public;
|
|
184
|
+
const daemonConnection = record.daemonConnection;
|
|
185
|
+
if (!publicMetadata || typeof publicMetadata !== "object" || Array.isArray(publicMetadata))
|
|
186
|
+
return null;
|
|
187
|
+
if (!daemonConnection || typeof daemonConnection !== "object" || Array.isArray(daemonConnection))
|
|
188
|
+
return null;
|
|
189
|
+
return metadata;
|
|
190
|
+
}
|
|
177
191
|
function readRunDetails(projectRoot, runId) {
|
|
178
192
|
const run = readAuthorityRun(projectRoot, runId);
|
|
179
193
|
if (!run) {
|
|
180
194
|
return null;
|
|
181
195
|
}
|
|
182
196
|
const usefulErrorText = isGenericRunFailure(run.errorText) ? summarizeUsefulRunError(projectRoot, runId, run.errorText) : null;
|
|
197
|
+
const { piSessionPrivate: _piSessionPrivate, ...publicRun } = run;
|
|
183
198
|
return {
|
|
184
|
-
run: usefulErrorText ? { ...
|
|
199
|
+
run: usefulErrorText ? { ...publicRun, errorText: usefulErrorText } : publicRun,
|
|
185
200
|
timeline: readJsonlFile(resolve(resolveAuthorityRunDir(projectRoot, runId), "timeline.jsonl")),
|
|
186
201
|
approvals: readApprovals(projectRoot, { runId }),
|
|
187
202
|
userInputs: readUserInputs(projectRoot, { runId })
|
|
@@ -1275,6 +1290,7 @@ var TERMINAL_RUN_STATUSES2 = new Set([
|
|
|
1275
1290
|
"stopped"
|
|
1276
1291
|
]);
|
|
1277
1292
|
var RESUMABLE_SERVER_CLOSEOUT_STATUSES = new Set(["pending", "running"]);
|
|
1293
|
+
var EXPLICIT_RESUMABLE_SERVER_CLOSEOUT_STATUSES = new Set(["pending", "running", "needs_attention"]);
|
|
1278
1294
|
var ACTIVE_LOCAL_RUN_STATUSES = new Set(["created", "preparing", "running", "validating", "reviewing"]);
|
|
1279
1295
|
|
|
1280
1296
|
// packages/server/src/server-helpers/ws-router.ts
|
|
@@ -1436,7 +1452,7 @@ if (false) {}
|
|
|
1436
1452
|
// packages/server/src/server-helpers/http-router.ts
|
|
1437
1453
|
import {
|
|
1438
1454
|
listAuthorityRuns as listAuthorityRuns7,
|
|
1439
|
-
readAuthorityRun as
|
|
1455
|
+
readAuthorityRun as readAuthorityRun9,
|
|
1440
1456
|
resolveAuthorityPaths,
|
|
1441
1457
|
writeJsonFile as writeJsonFile4
|
|
1442
1458
|
} from "@rig/runtime/control-plane/authority-files";
|
|
@@ -1456,10 +1472,64 @@ import {
|
|
|
1456
1472
|
RemoteWsClient as RemoteWsClient2
|
|
1457
1473
|
} from "@rig/runtime/control-plane/remote";
|
|
1458
1474
|
|
|
1475
|
+
// packages/server/src/server-helpers/pi-session-proxy.ts
|
|
1476
|
+
import { readAuthorityRun as readAuthorityRun7 } from "@rig/runtime/control-plane/authority-files";
|
|
1477
|
+
function resolveRunPiSessionProxy(projectRoot, runId) {
|
|
1478
|
+
const run = readAuthorityRun7(projectRoot, runId);
|
|
1479
|
+
if (!run)
|
|
1480
|
+
return null;
|
|
1481
|
+
const privateMetadata = readRunPiSessionMetadata(projectRoot, runId);
|
|
1482
|
+
if (!privateMetadata)
|
|
1483
|
+
return { pending: true, runId, status: typeof run.status === "string" ? run.status : undefined };
|
|
1484
|
+
const connection = privateMetadata.daemonConnection;
|
|
1485
|
+
if (connection.mode !== "http")
|
|
1486
|
+
throw new Error("Only loopback HTTP Rig Pi session daemon connections are supported");
|
|
1487
|
+
const token = tokenFromRef(connection.tokenRef);
|
|
1488
|
+
if (!token)
|
|
1489
|
+
throw new Error("Rig Pi session daemon token is unavailable");
|
|
1490
|
+
return {
|
|
1491
|
+
runId,
|
|
1492
|
+
sessionId: privateMetadata.public.sessionId,
|
|
1493
|
+
metadata: privateMetadata.public,
|
|
1494
|
+
privateMetadata,
|
|
1495
|
+
baseUrl: connection.baseUrl.replace(/\/+$/, ""),
|
|
1496
|
+
token
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
async function proxyRunPiHttp(projectRoot, runId, input) {
|
|
1500
|
+
const resolved = resolveRunPiSessionProxy(projectRoot, runId);
|
|
1501
|
+
if (resolved === null)
|
|
1502
|
+
return { status: 404, payload: { ok: false, error: "Run not found" } };
|
|
1503
|
+
if ("pending" in resolved)
|
|
1504
|
+
return { status: 409, payload: { ready: false, runId, status: resolved.status, retryAfterMs: 500 } };
|
|
1505
|
+
const response = await fetch(`${resolved.baseUrl}${input.daemonPath}`, {
|
|
1506
|
+
method: input.method,
|
|
1507
|
+
headers: {
|
|
1508
|
+
authorization: `Bearer ${resolved.token}`,
|
|
1509
|
+
...input.body === undefined ? {} : { "content-type": "application/json" }
|
|
1510
|
+
},
|
|
1511
|
+
body: input.body === undefined ? undefined : JSON.stringify(input.body)
|
|
1512
|
+
});
|
|
1513
|
+
const text = await response.text();
|
|
1514
|
+
const payload = text.trim() ? JSON.parse(text) : null;
|
|
1515
|
+
return { status: response.status, payload };
|
|
1516
|
+
}
|
|
1517
|
+
function buildRunPiDaemonWebSocketUrl(resolved) {
|
|
1518
|
+
const url = new URL(`${resolved.baseUrl}/sessions/${encodeURIComponent(resolved.sessionId)}/events`);
|
|
1519
|
+
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
1520
|
+
url.searchParams.set("token", resolved.token);
|
|
1521
|
+
return url.toString();
|
|
1522
|
+
}
|
|
1523
|
+
function tokenFromRef(ref) {
|
|
1524
|
+
if (ref.startsWith("inline:"))
|
|
1525
|
+
return ref.slice("inline:".length) || null;
|
|
1526
|
+
return null;
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1459
1529
|
// packages/server/src/server-helpers/run-steering.ts
|
|
1460
1530
|
import { dirname as dirname4, resolve as resolve8 } from "path";
|
|
1461
1531
|
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync3 } from "fs";
|
|
1462
|
-
import { appendJsonlRecord as appendJsonlRecord2, readAuthorityRun as
|
|
1532
|
+
import { appendJsonlRecord as appendJsonlRecord2, readAuthorityRun as readAuthorityRun8, resolveAuthorityRunDir as resolveAuthorityRunDir4 } from "@rig/runtime/control-plane/authority-files";
|
|
1463
1533
|
var steeringSequence = 0;
|
|
1464
1534
|
function runSteeringPath(projectRoot, runId) {
|
|
1465
1535
|
return resolve8(resolveAuthorityRunDir4(projectRoot, runId), "steering.jsonl");
|
|
@@ -1528,7 +1598,7 @@ function markQueuedRunSteeringMessagesDelivered(projectRoot, runId, ids) {
|
|
|
1528
1598
|
return delivered;
|
|
1529
1599
|
}
|
|
1530
1600
|
function queueRunSteeringMessage(projectRoot, runId, input) {
|
|
1531
|
-
const run =
|
|
1601
|
+
const run = readAuthorityRun8(projectRoot, runId);
|
|
1532
1602
|
if (!run)
|
|
1533
1603
|
throw new Error(`Run not found: ${runId}`);
|
|
1534
1604
|
const text = input.message.trim();
|
|
@@ -2416,7 +2486,8 @@ function isAuthorizedInspectorStreamRequest(req, authToken) {
|
|
|
2416
2486
|
}
|
|
2417
2487
|
function buildDeploymentStatus(projectRoot) {
|
|
2418
2488
|
const envCommit = normalizeCommit(process.env.RIG_COMMIT_SHA ?? process.env.GITHUB_SHA ?? process.env.VERCEL_GIT_COMMIT_SHA ?? process.env.RAILWAY_GIT_COMMIT_SHA ?? process.env.COMMIT_SHA);
|
|
2419
|
-
const
|
|
2489
|
+
const deploymentRoot = normalizeString(process.env.RIG_HOST_PROJECT_ROOT) ?? projectRoot;
|
|
2490
|
+
const gitCommit = envCommit ?? readGitHeadCommit(deploymentRoot) ?? readGitHeadCommit(projectRoot);
|
|
2420
2491
|
return {
|
|
2421
2492
|
currentCommit: gitCommit,
|
|
2422
2493
|
commitSource: envCommit ? "env" : gitCommit ? "git" : null,
|
|
@@ -3006,7 +3077,7 @@ function redactSecretFields(value) {
|
|
|
3006
3077
|
return redacted;
|
|
3007
3078
|
}
|
|
3008
3079
|
function validateRemoteLease(deps, state, input) {
|
|
3009
|
-
const run =
|
|
3080
|
+
const run = readAuthorityRun9(state.projectRoot, input.runId);
|
|
3010
3081
|
if (!run) {
|
|
3011
3082
|
return { ok: false, response: deps.jsonResponse({ ok: false, error: "Remote run not found" }, 404) };
|
|
3012
3083
|
}
|
|
@@ -3026,6 +3097,43 @@ function createRigServerFetch(state, deps) {
|
|
|
3026
3097
|
return deps.withServerPathEnv(state.projectRoot, async () => {
|
|
3027
3098
|
const browserOrigin = deps.resolveAllowedBrowserOrigin(req);
|
|
3028
3099
|
const finalizeResponse = (response) => deps.withCorsHeaders(response, req, browserOrigin);
|
|
3100
|
+
const earlyUrl = new URL(req.url);
|
|
3101
|
+
const piEventsWsMatch = earlyUrl.pathname.match(/^\/api\/runs\/([^/]+)\/pi\/events$/);
|
|
3102
|
+
if (piEventsWsMatch && req.headers.get("upgrade")?.toLowerCase() === "websocket") {
|
|
3103
|
+
const queryToken = earlyUrl.searchParams.get("token");
|
|
3104
|
+
const authHeaders = new Headers(req.headers);
|
|
3105
|
+
if (queryToken && !authHeaders.has("authorization")) {
|
|
3106
|
+
authHeaders.set("authorization", `Bearer ${queryToken}`);
|
|
3107
|
+
}
|
|
3108
|
+
const legacyAuthorized = Boolean(state.authToken && queryToken === state.authToken);
|
|
3109
|
+
const requestAuth = authorizeRigHttpRequest({
|
|
3110
|
+
req: new Request(req.url, { method: req.method, headers: authHeaders }),
|
|
3111
|
+
pathname: earlyUrl.pathname,
|
|
3112
|
+
projectRoot: state.projectRoot,
|
|
3113
|
+
serverAuthToken: state.authToken,
|
|
3114
|
+
legacyAuthorized
|
|
3115
|
+
});
|
|
3116
|
+
if (!requestAuth.authorized) {
|
|
3117
|
+
return deps.jsonResponse({ ok: false, error: "Unauthorized WebSocket connection", reason: requestAuth.reason }, 401);
|
|
3118
|
+
}
|
|
3119
|
+
const runId = decodeURIComponent(piEventsWsMatch[1]);
|
|
3120
|
+
const resolved = resolveRunPiSessionProxy(state.projectRoot, runId);
|
|
3121
|
+
if (resolved === null)
|
|
3122
|
+
return deps.jsonResponse({ ok: false, error: "Run not found" }, 404);
|
|
3123
|
+
if ("pending" in resolved)
|
|
3124
|
+
return deps.jsonResponse({ ready: false, runId, status: resolved.status, retryAfterMs: 500 }, 202);
|
|
3125
|
+
if (!server)
|
|
3126
|
+
return deps.jsonResponse({ ok: false, error: "WebSocket upgrade unavailable" }, 400);
|
|
3127
|
+
const upgraded = server.upgrade(req, {
|
|
3128
|
+
data: {
|
|
3129
|
+
kind: "pi-session-proxy",
|
|
3130
|
+
connectedAt: new Date().toISOString(),
|
|
3131
|
+
upstreamUrl: buildRunPiDaemonWebSocketUrl(resolved),
|
|
3132
|
+
runId
|
|
3133
|
+
}
|
|
3134
|
+
});
|
|
3135
|
+
return upgraded ? new Response(null) : deps.jsonResponse({ ok: false, error: "WebSocket upgrade failed" }, 400);
|
|
3136
|
+
}
|
|
3029
3137
|
const upgradeResponse = handleWebSocketUpgrade({
|
|
3030
3138
|
req,
|
|
3031
3139
|
server,
|
|
@@ -4764,6 +4872,49 @@ data: ${JSON.stringify({ connectedAt: new Date().toISOString() })}
|
|
|
4764
4872
|
return deps.jsonResponse({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);
|
|
4765
4873
|
}
|
|
4766
4874
|
}
|
|
4875
|
+
const runPiMatch = url.pathname.match(/^\/api\/runs\/([^/]+)\/pi(?:\/(.*))?$/);
|
|
4876
|
+
if (runPiMatch) {
|
|
4877
|
+
const runId = decodeURIComponent(runPiMatch[1]);
|
|
4878
|
+
const action = runPiMatch[2] || "";
|
|
4879
|
+
const resolved = resolveRunPiSessionProxy(state.projectRoot, runId);
|
|
4880
|
+
if (resolved === null)
|
|
4881
|
+
return deps.notFound();
|
|
4882
|
+
if ("pending" in resolved) {
|
|
4883
|
+
if (action === "" && req.method === "GET") {
|
|
4884
|
+
return deps.jsonResponse({ ready: false, runId, status: resolved.status, retryAfterMs: 500 }, 202);
|
|
4885
|
+
}
|
|
4886
|
+
return deps.jsonResponse({ ready: false, runId, status: resolved.status, retryAfterMs: 500, error: "Pi session is not ready" }, 409);
|
|
4887
|
+
}
|
|
4888
|
+
if (action === "" && req.method === "GET")
|
|
4889
|
+
return deps.jsonResponse({ ready: true, metadata: resolved.metadata });
|
|
4890
|
+
const body = req.method === "GET" ? undefined : await deps.readJsonBody(req);
|
|
4891
|
+
const sessionPath = `/sessions/${encodeURIComponent(resolved.sessionId)}`;
|
|
4892
|
+
const daemonPath = (() => {
|
|
4893
|
+
if (action === "messages" && req.method === "GET")
|
|
4894
|
+
return `${sessionPath}/messages`;
|
|
4895
|
+
if (action === "status" && req.method === "GET")
|
|
4896
|
+
return `${sessionPath}/status`;
|
|
4897
|
+
if (action === "commands" && req.method === "GET")
|
|
4898
|
+
return `${sessionPath}/commands`;
|
|
4899
|
+
if (action === "prompt" && req.method === "POST")
|
|
4900
|
+
return `${sessionPath}/prompt`;
|
|
4901
|
+
if (action === "shell" && req.method === "POST")
|
|
4902
|
+
return `${sessionPath}/shell`;
|
|
4903
|
+
if (action === "commands/run" && req.method === "POST")
|
|
4904
|
+
return `${sessionPath}/commands/run`;
|
|
4905
|
+
if (action === "commands/respond" && req.method === "POST")
|
|
4906
|
+
return `${sessionPath}/commands/respond`;
|
|
4907
|
+
if (action === "extension-ui/respond" && req.method === "POST")
|
|
4908
|
+
return `${sessionPath}/extension-ui/respond`;
|
|
4909
|
+
if (action === "abort" && req.method === "POST")
|
|
4910
|
+
return `${sessionPath}/abort`;
|
|
4911
|
+
return null;
|
|
4912
|
+
})();
|
|
4913
|
+
if (!daemonPath)
|
|
4914
|
+
return deps.notFound();
|
|
4915
|
+
const proxied = await proxyRunPiHttp(state.projectRoot, runId, { method: req.method, daemonPath, body });
|
|
4916
|
+
return deps.jsonResponse(proxied.payload, proxied.status);
|
|
4917
|
+
}
|
|
4767
4918
|
const runSteeringAckMatch = url.pathname.match(/^\/api\/runs\/([^/]+)\/steering\/ack$/);
|
|
4768
4919
|
if (runSteeringAckMatch && req.method === "POST") {
|
|
4769
4920
|
const runId = decodeURIComponent(runSteeringAckMatch[1]);
|
|
@@ -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
|
+
};
|
|
@@ -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 })
|
|
@@ -265,6 +280,7 @@ export {
|
|
|
265
280
|
readUserInputsForRuns,
|
|
266
281
|
readUserInputs,
|
|
267
282
|
readRunTimelinePage,
|
|
283
|
+
readRunPiSessionMetadata,
|
|
268
284
|
readRunLogsPage,
|
|
269
285
|
readRunDetails,
|
|
270
286
|
readRawRunLogs,
|