@ccdd/project 2.0.2 → 3.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/LICENSE +21 -0
- package/README.md +5 -1
- package/dist/monitor-ui/assets/{GraphView-0hRu9REg.js → GraphView-CzM-UdPe.js} +3 -3
- package/dist/monitor-ui/assets/{ValidationView-BuT1XOPJ.js → ValidationView-C3G5cwXp.js} +1 -1
- package/dist/monitor-ui/assets/{elk-api-U8zu3SUU.js → elk-api-DDn2L4-3.js} +1 -1
- package/dist/monitor-ui/assets/{elk.bundled-B5v2hKp_.js → elk.bundled-Bmx50hLH.js} +1 -1
- package/dist/monitor-ui/assets/{index-rUSYOSt7.js → index-B4RYcPAo.js} +3 -3
- package/dist/monitor-ui/index.html +1 -1
- package/dist/src/broker/human-claims.d.ts +26 -0
- package/dist/src/broker/human-claims.js +104 -0
- package/dist/src/broker/human-claims.js.map +1 -0
- package/dist/src/broker/index.d.ts +23 -1
- package/dist/src/broker/index.js +87 -14
- package/dist/src/broker/index.js.map +1 -1
- package/dist/src/cli.js +2 -1
- package/dist/src/cli.js.map +1 -1
- package/dist/src/contracts.d.ts +3 -0
- package/dist/src/executors/human-preparation.d.ts +18 -0
- package/dist/src/executors/human-preparation.js +47 -0
- package/dist/src/executors/human-preparation.js.map +1 -0
- package/dist/src/executors/index.js +3 -2
- package/dist/src/executors/index.js.map +1 -1
- package/dist/src/monitor/actions.d.ts +1 -1
- package/dist/src/monitor/actions.js +2 -2
- package/dist/src/monitor/actions.js.map +1 -1
- package/dist/src/monitor/server.js +21 -3
- package/dist/src/monitor/server.js.map +1 -1
- package/dist/src/monitor/store.js +5 -0
- package/dist/src/monitor/store.js.map +1 -1
- package/dist/src/monitor/types.d.ts +5 -0
- package/dist/src/node-version.d.ts +3 -0
- package/dist/src/node-version.js +14 -0
- package/dist/src/node-version.js.map +1 -0
- package/dist/src/project/cli.js +6 -1
- package/dist/src/project/cli.js.map +1 -1
- package/dist/src/project/identity.js +5 -1
- package/dist/src/project/identity.js.map +1 -1
- package/dist/src/project/index.d.ts +3 -0
- package/dist/src/project/index.js +2 -0
- package/dist/src/project/index.js.map +1 -1
- package/dist/src/review/cli.d.ts +8 -0
- package/dist/src/review/cli.js +136 -0
- package/dist/src/review/cli.js.map +1 -0
- package/dist/src/review/client.d.ts +30 -0
- package/dist/src/review/client.js +191 -0
- package/dist/src/review/client.js.map +1 -0
- package/dist/src/review/local-claim.d.ts +5 -0
- package/dist/src/review/local-claim.js +16 -0
- package/dist/src/review/local-claim.js.map +1 -0
- package/dist/src/review/server.d.ts +11 -0
- package/dist/src/review/server.js +248 -0
- package/dist/src/review/server.js.map +1 -0
- package/dist/src/review/types.d.ts +10 -0
- package/dist/src/review/types.js +17 -0
- package/dist/src/review/types.js.map +1 -0
- package/dist/src/tools/contracts.d.ts +22 -0
- package/dist/src/tools/environment-host.d.ts +1 -0
- package/dist/src/tools/environment-host.js +32 -0
- package/dist/src/tools/environment-host.js.map +1 -0
- package/dist/src/tools/environment.d.ts +18 -0
- package/dist/src/tools/environment.js +116 -0
- package/dist/src/tools/environment.js.map +1 -0
- package/dist/src/tools/inputs.d.ts +7 -0
- package/dist/src/tools/inputs.js +64 -0
- package/dist/src/tools/inputs.js.map +1 -0
- package/dist/src/tools/manifest.d.ts +4 -0
- package/dist/src/tools/manifest.js +28 -0
- package/dist/src/tools/manifest.js.map +1 -0
- package/dist/src/tools/runner.js +4 -2
- package/dist/src/tools/runner.js.map +1 -1
- package/dist/src/tools/runtime-host.js +27 -3
- package/dist/src/tools/runtime-host.js.map +1 -1
- package/dist/src/tools/schema.d.ts +3 -1
- package/dist/src/tools/schema.js +33 -1
- package/dist/src/tools/schema.js.map +1 -1
- package/dist/src/workspaces/index.d.ts +27 -0
- package/dist/src/workspaces/index.js +2 -0
- package/dist/src/workspaces/index.js.map +1 -1
- package/dist/src/workspaces/transfer.d.ts +52 -0
- package/dist/src/workspaces/transfer.js +372 -0
- package/dist/src/workspaces/transfer.js.map +1 -0
- package/package.json +5 -4
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
+
import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join, resolve } from 'node:path';
|
|
4
|
+
import { materializeWorkspace, validateWorkspaceManifest } from '../workspaces/transfer.js';
|
|
5
|
+
import { reopenWorkspace } from '../workspaces/index.js';
|
|
6
|
+
import { prepareHumanReview } from '../executors/human-preparation.js';
|
|
7
|
+
import { createReviewTools, describeReviewTools } from '../tools/runner.js';
|
|
8
|
+
import { packageVersion } from '../runtime-paths.js';
|
|
9
|
+
const requestId = (id) => { if (!/^[A-Za-z0-9_-]{1,128}$/.test(id))
|
|
10
|
+
throw new Error('Invalid review request identifier.'); return id; };
|
|
11
|
+
function transport(options) {
|
|
12
|
+
const server = new URL(options.server);
|
|
13
|
+
if (!['http:', 'https:'].includes(server.protocol) || server.username || server.password || server.search || server.hash || !['', '/'].includes(server.pathname)) {
|
|
14
|
+
throw new Error('Use the HTTP(S) origin of the review server without credentials or a path.');
|
|
15
|
+
}
|
|
16
|
+
if (!/^[A-Za-z0-9_-]{32,256}$/.test(options.token))
|
|
17
|
+
throw new Error('Invalid reviewer token format.');
|
|
18
|
+
const timeoutMs = options.timeoutMs ?? 900_000;
|
|
19
|
+
if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 86_400_000)
|
|
20
|
+
throw new Error('Review request timeout must be between 1 and 86400000 ms.');
|
|
21
|
+
const send = async (route, input, signal = options.signal) => {
|
|
22
|
+
signal?.throwIfAborted();
|
|
23
|
+
const response = await fetch(new URL(route, server), { method: input === undefined ? 'GET' : 'POST',
|
|
24
|
+
headers: { authorization: `Bearer ${options.token}`, ...(input === undefined ? {} : { 'content-type': 'application/json' }) },
|
|
25
|
+
...(input === undefined ? {} : { body: JSON.stringify(input) }),
|
|
26
|
+
signal: signal ? AbortSignal.any([signal, AbortSignal.timeout(timeoutMs)]) : AbortSignal.timeout(timeoutMs), redirect: 'error' });
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
const message = await response.json().catch(() => ({}));
|
|
29
|
+
throw new Error(message.error ?? `Review server returned HTTP ${response.status}.`);
|
|
30
|
+
}
|
|
31
|
+
return response;
|
|
32
|
+
};
|
|
33
|
+
return { server: server.origin, send,
|
|
34
|
+
async json(route, input, signal) { return await (await send(route, input, signal)).json(); },
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async function connect(options) {
|
|
38
|
+
const api = transport(options);
|
|
39
|
+
const identity = await api.json('/session');
|
|
40
|
+
if (identity.packageVersion !== packageVersion)
|
|
41
|
+
throw new Error(`Use @ccdd/project ${identity.packageVersion} to match the review server (this client is ${packageVersion}).`);
|
|
42
|
+
if (!/^[A-Za-z0-9_-]{1,128}$/.test(identity.reviewerId))
|
|
43
|
+
throw new Error('Invalid reviewer identity from server.');
|
|
44
|
+
const root = resolve(options.stateDir);
|
|
45
|
+
const sessionPath = (id) => join(root, 'review-sessions', createHash('sha256').update(JSON.stringify([api.server, identity.reviewerId, requestId(id)])).digest('hex') + '.json');
|
|
46
|
+
const readSession = async (id) => {
|
|
47
|
+
const stored = JSON.parse(await readFile(sessionPath(id), 'utf8'));
|
|
48
|
+
if (stored.version !== 1 || stored.server !== api.server || stored.reviewerId !== identity.reviewerId || stored.request?.id !== id || stored.request.packageVersion !== packageVersion || stored.workspace?.hash !== stored.request.snapshotHash || stored.workspace.stateDir !== root)
|
|
49
|
+
throw new Error('Prepared review session does not match this client. Claim this review again.');
|
|
50
|
+
requestId(stored.request.runId);
|
|
51
|
+
requestId(stored.attemptId);
|
|
52
|
+
return stored;
|
|
53
|
+
};
|
|
54
|
+
const saveSession = async (session) => {
|
|
55
|
+
const directory = join(root, 'review-sessions');
|
|
56
|
+
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
57
|
+
const temporary = join(directory, `.${randomUUID()}.json`);
|
|
58
|
+
await writeFile(temporary, JSON.stringify(session), { mode: 0o600, flag: 'wx' });
|
|
59
|
+
await rename(temporary, sessionPath(session.request.id));
|
|
60
|
+
};
|
|
61
|
+
return { ...api, root, reviewerId: identity.reviewerId, readSession, saveSession };
|
|
62
|
+
}
|
|
63
|
+
export async function listRemoteReviews(options, { limit = 100, offset = 0 } = {}) {
|
|
64
|
+
const api = await connect(options);
|
|
65
|
+
return api.json(`/requests?limit=${limit}&offset=${offset}`);
|
|
66
|
+
}
|
|
67
|
+
export async function showRemoteReview(id, options) {
|
|
68
|
+
const api = await connect(options);
|
|
69
|
+
const { request, status } = await api.json(`/requests/${requestId(id)}`);
|
|
70
|
+
return { id: request.id, title: request.title, status, claimedBy: request.claimedBy,
|
|
71
|
+
instruction: request.payload.instruction, artifacts: request.artifacts,
|
|
72
|
+
...(request.artifactGroups ? { artifactGroups: request.artifactGroups } : {}),
|
|
73
|
+
environmentRequirements: request.configManifest?.envRequirements ?? {},
|
|
74
|
+
tools: request.configManifest ? describeReviewTools({ artifacts: request.artifacts, configManifest: request.configManifest, audience: 'human' }) : [],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
export async function claimRemoteReview(id, options) {
|
|
78
|
+
requestId(id);
|
|
79
|
+
const api = await connect(options);
|
|
80
|
+
const route = `/requests/${id}`;
|
|
81
|
+
const current = await api.json(route);
|
|
82
|
+
if (current.status !== 'WAITING_HUMAN')
|
|
83
|
+
throw new Error('Request is not waiting for a Human review.');
|
|
84
|
+
if (current.request.claimedBy) {
|
|
85
|
+
if (current.request.claimedBy !== api.reviewerId)
|
|
86
|
+
throw new Error('This review is already claimed by another reviewer.');
|
|
87
|
+
const session = await api.readSession(id);
|
|
88
|
+
if (session.attemptId !== current.request.claimAttemptId)
|
|
89
|
+
throw new Error('This Claim was prepared by another local session.');
|
|
90
|
+
const handle = await reopenWorkspace(session.workspace, { signal: options.signal });
|
|
91
|
+
try {
|
|
92
|
+
await handle.assertUnchanged();
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
await handle.close();
|
|
96
|
+
}
|
|
97
|
+
return { requestId: id, reviewerId: api.reviewerId, snapshotHash: session.request.snapshotHash, workspacePath: session.workspace.path, downloadedFiles: 0, downloadedBytes: 0, reusedFiles: 0 };
|
|
98
|
+
}
|
|
99
|
+
const { attempt, request } = await api.json(`${route}/try-claim`, {});
|
|
100
|
+
const controller = new AbortController();
|
|
101
|
+
const signal = options.signal ? AbortSignal.any([options.signal, controller.signal]) : controller.signal;
|
|
102
|
+
const renewalController = new AbortController();
|
|
103
|
+
let renewal;
|
|
104
|
+
const heartbeat = setInterval(() => {
|
|
105
|
+
if (renewal)
|
|
106
|
+
return;
|
|
107
|
+
renewal = api.json(`${route}/renew`, { attemptId: attempt.id }, AbortSignal.any([signal, renewalController.signal, AbortSignal.timeout(15_000)]))
|
|
108
|
+
.catch(error => { if (!renewalController.signal.aborted)
|
|
109
|
+
controller.abort(error); }).finally(() => { renewal = undefined; });
|
|
110
|
+
}, 20_000);
|
|
111
|
+
try {
|
|
112
|
+
if (request.id !== id || request.packageVersion !== packageVersion || attempt.reviewerId !== api.reviewerId)
|
|
113
|
+
throw new Error('Invalid Try Claim response.');
|
|
114
|
+
requestId(request.runId);
|
|
115
|
+
requestId(attempt.id);
|
|
116
|
+
const manifest = validateWorkspaceManifest(await api.json(`${route}/snapshot`, undefined, signal));
|
|
117
|
+
if (manifest.hash !== request.snapshotHash)
|
|
118
|
+
throw new Error('Downloaded manifest does not match this review.');
|
|
119
|
+
options.onProgress?.({ phase: 'download' });
|
|
120
|
+
const imported = await materializeWorkspace({ manifest, stateDir: api.root, signal,
|
|
121
|
+
fetchBlob: async (hash, downloadSignal) => {
|
|
122
|
+
const response = await api.send(`${route}/blobs/${hash}`, undefined, downloadSignal);
|
|
123
|
+
if (!response.body)
|
|
124
|
+
throw new Error('Missing snapshot file body.');
|
|
125
|
+
return response.body;
|
|
126
|
+
}, onProgress: transfer => options.onProgress?.({ phase: 'download', transfer }),
|
|
127
|
+
});
|
|
128
|
+
options.onProgress?.({ phase: 'environment' });
|
|
129
|
+
const preparation = await prepareHumanReview(request, imported.descriptor, join(api.root, 'runs', request.runId, id, 'preparation', attempt.id), signal);
|
|
130
|
+
const session = { version: 1, server: api.server, reviewerId: api.reviewerId, attemptId: attempt.id, request, workspace: imported.descriptor };
|
|
131
|
+
// Keep the prepared session before confirmation, so a lost confirmation response
|
|
132
|
+
// can be recovered by checking the authoritative Claim with the same attempt ID.
|
|
133
|
+
await api.saveSession(session);
|
|
134
|
+
signal.throwIfAborted();
|
|
135
|
+
await api.json(`${route}/confirm`, { attemptId: attempt.id, preparation }, signal);
|
|
136
|
+
options.onProgress?.({ phase: 'claimed' });
|
|
137
|
+
return { requestId: id, reviewerId: api.reviewerId, snapshotHash: request.snapshotHash, workspacePath: imported.descriptor.path,
|
|
138
|
+
downloadedFiles: imported.downloadedFiles, downloadedBytes: imported.downloadedBytes, reusedFiles: imported.reusedFiles };
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
// Best-effort release is conditional on the attempt; loss of network is covered
|
|
142
|
+
// by lease expiry, and cannot release another reviewer's newer reservation.
|
|
143
|
+
await api.json(`${route}/release`, { attemptId: attempt.id }, AbortSignal.timeout(5_000)).catch(() => { });
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
finally {
|
|
147
|
+
clearInterval(heartbeat);
|
|
148
|
+
renewalController.abort();
|
|
149
|
+
await renewal;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
export async function executeRemoteHumanTool(id, toolName, args, options) {
|
|
153
|
+
const api = await connect(options), session = await api.readSession(requestId(id));
|
|
154
|
+
const action = { attemptId: session.attemptId, toolName, arguments: args };
|
|
155
|
+
await api.json(`/requests/${id}/authorize-tool`, action);
|
|
156
|
+
const handle = await reopenWorkspace(session.workspace, { signal: options.signal });
|
|
157
|
+
try {
|
|
158
|
+
await handle.assertUnchanged();
|
|
159
|
+
const request = session.request;
|
|
160
|
+
const registry = await createReviewTools({ worktreePath: session.workspace.path, artifacts: request.artifacts,
|
|
161
|
+
artifactGroups: request.artifactGroups, artifactTypes: request.artifactTypes, configManifest: request.configManifest,
|
|
162
|
+
criticId: request.criticId, audience: 'human', runDir: join(api.root, 'runs', request.runId, id, 'human-tools'), signal: handle.signal });
|
|
163
|
+
try {
|
|
164
|
+
registry.validateArguments(toolName, args);
|
|
165
|
+
const result = await registry.call(toolName, args);
|
|
166
|
+
await handle.assertUnchanged();
|
|
167
|
+
handle.signal.throwIfAborted();
|
|
168
|
+
await api.json(`/requests/${id}/tool-receipt`, action);
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
171
|
+
finally {
|
|
172
|
+
await registry.close();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
finally {
|
|
176
|
+
await handle.close();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
export async function submitRemoteHumanReview(id, result, options) {
|
|
180
|
+
const api = await connect(options), session = await api.readSession(requestId(id));
|
|
181
|
+
const handle = await reopenWorkspace(session.workspace, { signal: options.signal });
|
|
182
|
+
try {
|
|
183
|
+
await handle.assertUnchanged();
|
|
184
|
+
handle.signal.throwIfAborted();
|
|
185
|
+
return await api.json(`/requests/${id}/submit`, { attemptId: session.attemptId, result });
|
|
186
|
+
}
|
|
187
|
+
finally {
|
|
188
|
+
await handle.close();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/review/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Broker } from '../broker/index.js';
|
|
2
|
+
/** Keep the local CLI alive long enough to release Try Claim and stop its checks. */
|
|
3
|
+
export declare function claimHumanFromCli(broker: Broker, requestId: string, reviewerId: string, stderr: {
|
|
4
|
+
write(value: string): unknown;
|
|
5
|
+
}): Promise<import("../contracts.js").ReviewRequest>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Keep the local CLI alive long enough to release Try Claim and stop its checks. */
|
|
2
|
+
export async function claimHumanFromCli(broker, requestId, reviewerId, stderr) {
|
|
3
|
+
const controller = new AbortController();
|
|
4
|
+
const cancel = () => controller.abort(new Error('Human claim preparation cancelled.'));
|
|
5
|
+
process.once('SIGINT', cancel);
|
|
6
|
+
process.once('SIGTERM', cancel);
|
|
7
|
+
try {
|
|
8
|
+
stderr.write('Try Claim: preparing the review input and checking the local environment.\n');
|
|
9
|
+
return await broker.claimHuman(requestId, reviewerId, { signal: controller.signal });
|
|
10
|
+
}
|
|
11
|
+
finally {
|
|
12
|
+
process.off('SIGINT', cancel);
|
|
13
|
+
process.off('SIGTERM', cancel);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=local-claim.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-claim.js","sourceRoot":"","sources":["../../../src/review/local-claim.ts"],"names":[],"mappings":"AAEA,qFAAqF;AACrF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAAc,EAAE,SAAiB,EAAE,UAAkB,EAAE,MAAyC;IACtI,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC,CAAC;IACvF,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAAC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAChE,IAAI,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,6EAA6E,CAAC,CAAC;QAC5F,OAAO,MAAM,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;IACvF,CAAC;YAAS,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAAC,CAAC;AAC9E,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface ReviewServerOptions {
|
|
2
|
+
stateDir: string;
|
|
3
|
+
reviewers: Record<string, string>;
|
|
4
|
+
host?: string;
|
|
5
|
+
port?: number;
|
|
6
|
+
}
|
|
7
|
+
/** A download/action transport. Only explicit POST actions open the Broker. */
|
|
8
|
+
export declare function startReviewServer(options: ReviewServerOptions): Promise<{
|
|
9
|
+
url: string;
|
|
10
|
+
close(): Promise<void>;
|
|
11
|
+
}>;
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { createHash, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
import { createServer } from 'node:http';
|
|
3
|
+
import { pipeline } from 'node:stream/promises';
|
|
4
|
+
import { createBroker, readStateContext } from '../broker/index.js';
|
|
5
|
+
import { activeTryClaim } from '../broker/human-claims.js';
|
|
6
|
+
import { withProjectStore } from '../project/store.js';
|
|
7
|
+
import { createWorkspaceManifest, openWorkspaceBlob } from '../workspaces/transfer.js';
|
|
8
|
+
import { ensureRunWorker } from '../worker-client.js';
|
|
9
|
+
import { packageVersion } from '../runtime-paths.js';
|
|
10
|
+
import { portableReview } from './types.js';
|
|
11
|
+
class HttpError extends Error {
|
|
12
|
+
status;
|
|
13
|
+
constructor(status, message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.status = status;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const object = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
19
|
+
const digest = (value) => createHash('sha256').update(value).digest();
|
|
20
|
+
const identifier = (value) => { if (!/^[A-Za-z0-9_-]{1,128}$/.test(value))
|
|
21
|
+
throw new HttpError(400, 'Invalid request identifier.'); return value; };
|
|
22
|
+
function json(response, value, status = 200) {
|
|
23
|
+
response.writeHead(status, { 'content-type': 'application/json; charset=utf-8' });
|
|
24
|
+
response.end(JSON.stringify(value));
|
|
25
|
+
}
|
|
26
|
+
function shape(value, keys) {
|
|
27
|
+
if (!object(value) || Object.keys(value).some(key => !keys.includes(key)))
|
|
28
|
+
throw new HttpError(400, 'Invalid request body.');
|
|
29
|
+
}
|
|
30
|
+
function string(value) {
|
|
31
|
+
if (typeof value !== 'string' || !value || value.length > 256)
|
|
32
|
+
throw new HttpError(400, 'Missing or invalid action identifier.');
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
async function readBody(request) {
|
|
36
|
+
if (!/^application\/json(?:;\s*charset=utf-8)?$/i.test(request.headers['content-type'] ?? ''))
|
|
37
|
+
throw new HttpError(415, 'Send an application/json body.');
|
|
38
|
+
let size = 0;
|
|
39
|
+
const chunks = [];
|
|
40
|
+
for await (const chunk of request) {
|
|
41
|
+
size += chunk.length;
|
|
42
|
+
if (size > 128 * 1024)
|
|
43
|
+
throw new HttpError(413, 'Action body exceeds 128 KiB.');
|
|
44
|
+
chunks.push(chunk);
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
return JSON.parse(Buffer.concat(chunks).toString('utf8'));
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
throw new HttpError(400, 'Invalid JSON body.');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** A download/action transport. Only explicit POST actions open the Broker. */
|
|
54
|
+
export async function startReviewServer(options) {
|
|
55
|
+
const context = readStateContext(options.stateDir);
|
|
56
|
+
if (!object(options.reviewers) || !Object.keys(options.reviewers).length)
|
|
57
|
+
throw new Error('At least one reviewer credential is required.');
|
|
58
|
+
const credentials = Object.entries(options.reviewers).map(([id, token]) => {
|
|
59
|
+
if (!/^[A-Za-z0-9_-]{1,128}$/.test(id) || typeof token !== 'string' || !/^[A-Za-z0-9_-]{32,256}$/.test(token))
|
|
60
|
+
throw new Error('Reviewer credentials require an ID and a random base64url token of at least 32 characters.');
|
|
61
|
+
return { id, hash: digest(token) };
|
|
62
|
+
});
|
|
63
|
+
if (new Set(credentials.map(entry => entry.hash.toString('hex'))).size !== credentials.length)
|
|
64
|
+
throw new Error('Each reviewer needs a distinct credential.');
|
|
65
|
+
const requestedPort = options.port ?? 4320;
|
|
66
|
+
if (!Number.isInteger(requestedPort) || requestedPort < 0 || requestedPort > 65535)
|
|
67
|
+
throw new Error('Invalid review server port.');
|
|
68
|
+
const host = options.host ?? '127.0.0.1';
|
|
69
|
+
const jobs = new Set(), active = new Set();
|
|
70
|
+
const manifests = new Map();
|
|
71
|
+
let closing = false;
|
|
72
|
+
const readRequest = (id) => withProjectStore(context.stateDir, db => {
|
|
73
|
+
const row = db.prepare('SELECT data FROM requests WHERE id=?').get(id);
|
|
74
|
+
return row ? JSON.parse(String(row.data)) : null;
|
|
75
|
+
}, null);
|
|
76
|
+
const authenticate = (request) => {
|
|
77
|
+
if (request.headers.origin || request.headers['sec-fetch-site'])
|
|
78
|
+
throw new HttpError(403, 'Use the CCDD review client for authenticated remote actions.');
|
|
79
|
+
const authorization = request.headers.authorization;
|
|
80
|
+
if (!authorization?.startsWith('Bearer ') || authorization.length > 264)
|
|
81
|
+
throw new HttpError(401, 'A reviewer credential is required.');
|
|
82
|
+
const hash = digest(authorization.slice(7));
|
|
83
|
+
const credential = credentials.find(entry => timingSafeEqual(entry.hash, hash));
|
|
84
|
+
if (!credential)
|
|
85
|
+
throw new HttpError(401, 'Invalid reviewer credential.');
|
|
86
|
+
return credential.id;
|
|
87
|
+
};
|
|
88
|
+
const manifestFor = (request) => {
|
|
89
|
+
let pending = manifests.get(request.snapshotHash);
|
|
90
|
+
if (!pending) {
|
|
91
|
+
// This reads immutable snapshot files and verifies their identity; it never
|
|
92
|
+
// evaluates configuration or modifies review state.
|
|
93
|
+
pending = createWorkspaceManifest(request.workspace);
|
|
94
|
+
manifests.set(request.snapshotHash, pending);
|
|
95
|
+
pending.catch(() => { manifests.delete(request.snapshotHash); });
|
|
96
|
+
if (manifests.size > 16)
|
|
97
|
+
manifests.delete(manifests.keys().next().value);
|
|
98
|
+
}
|
|
99
|
+
return pending;
|
|
100
|
+
};
|
|
101
|
+
const server = createServer({ maxHeaderSize: 16_384 }, (request, response) => {
|
|
102
|
+
response.setHeader('Cache-Control', 'no-store');
|
|
103
|
+
response.setHeader('X-Content-Type-Options', 'nosniff');
|
|
104
|
+
response.setHeader('Content-Security-Policy', "default-src 'none'; frame-ancestors 'none'");
|
|
105
|
+
const controller = new AbortController();
|
|
106
|
+
active.add(controller);
|
|
107
|
+
const disconnect = () => { if (!response.writableEnded)
|
|
108
|
+
controller.abort(new Error('Review client disconnected.')); };
|
|
109
|
+
response.once('close', disconnect);
|
|
110
|
+
const job = (async () => {
|
|
111
|
+
if (closing)
|
|
112
|
+
throw new HttpError(503, 'Review server is stopping.');
|
|
113
|
+
if (active.size > 32)
|
|
114
|
+
throw new HttpError(429, 'Too many concurrent review transfers.');
|
|
115
|
+
const reviewerId = authenticate(request);
|
|
116
|
+
if (!request.url?.startsWith('/') || request.url.startsWith('//'))
|
|
117
|
+
throw new HttpError(400, 'Invalid review route.');
|
|
118
|
+
const url = new URL(request.url, 'http://review.local');
|
|
119
|
+
if (request.method === 'GET' && url.pathname === '/session') {
|
|
120
|
+
json(response, { reviewerId, packageVersion });
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (request.method === 'GET' && url.pathname === '/requests') {
|
|
124
|
+
if ([...url.searchParams.keys()].some(key => !['limit', 'offset'].includes(key)))
|
|
125
|
+
throw new HttpError(400, 'Unknown query parameter.');
|
|
126
|
+
const limit = Number(url.searchParams.get('limit') ?? 100), offset = Number(url.searchParams.get('offset') ?? 0);
|
|
127
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 200 || !Number.isSafeInteger(offset) || offset < 0)
|
|
128
|
+
throw new HttpError(400, 'Invalid pagination.');
|
|
129
|
+
const result = withProjectStore(context.stateDir, db => db.prepare("SELECT data FROM requests WHERE json_extract(data,'$.profile.kind')='human' ORDER BY json_extract(data,'$.createdAt') DESC, rowid DESC LIMIT ? OFFSET ?").all(limit, offset).map(row => {
|
|
130
|
+
const stored = JSON.parse(String(row.data));
|
|
131
|
+
const preparation = activeTryClaim(stored);
|
|
132
|
+
return { id: stored.id, runId: stored.runId, title: stored.title, status: stored.status,
|
|
133
|
+
claimedBy: stored.claimedBy ?? null, preparation: preparation ? { reviewerId: preparation.reviewerId, expiresAt: preparation.expiresAt } : null,
|
|
134
|
+
remoteSupported: stored.workspace.mode === 'copy' && Boolean(stored.configManifest) };
|
|
135
|
+
}), []);
|
|
136
|
+
json(response, result);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const match = /^\/requests\/([^/]+)(?:\/(snapshot|blobs\/([a-f0-9]{64})|try-claim|renew|release|confirm|authorize-tool|tool-receipt|submit))?$/.exec(url.pathname);
|
|
140
|
+
if (!match || url.search)
|
|
141
|
+
throw new HttpError(404, 'Unknown review route.');
|
|
142
|
+
const id = identifier(match[1]), action = match[2];
|
|
143
|
+
const stored = readRequest(id);
|
|
144
|
+
if (!stored)
|
|
145
|
+
throw new HttpError(404, 'Unknown review request.');
|
|
146
|
+
const portable = portableReview(stored);
|
|
147
|
+
if (request.method === 'GET') {
|
|
148
|
+
if (!action) {
|
|
149
|
+
json(response, { request: portable, status: stored.status });
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const reservation = activeTryClaim(stored);
|
|
153
|
+
if (stored.status !== 'WAITING_HUMAN' || (stored.claimedBy !== reviewerId && reservation?.reviewerId !== reviewerId))
|
|
154
|
+
throw new HttpError(403, 'Reserve this review before downloading its input.');
|
|
155
|
+
if (action === 'snapshot') {
|
|
156
|
+
json(response, await manifestFor(stored));
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (match[3]) {
|
|
160
|
+
const manifest = await manifestFor(stored);
|
|
161
|
+
const blob = await openWorkspaceBlob(stored.workspace, manifest, match[3], { signal: controller.signal });
|
|
162
|
+
response.writeHead(200, { 'content-type': 'application/octet-stream', 'content-length': blob.size });
|
|
163
|
+
await pipeline(blob.stream, response, { signal: controller.signal });
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
throw new HttpError(405, 'This route requires POST.');
|
|
167
|
+
}
|
|
168
|
+
if (request.method !== 'POST')
|
|
169
|
+
throw new HttpError(405, 'Use GET or POST.');
|
|
170
|
+
const input = await readBody(request);
|
|
171
|
+
const broker = createBroker(context);
|
|
172
|
+
try {
|
|
173
|
+
if (action === 'try-claim') {
|
|
174
|
+
shape(input, []);
|
|
175
|
+
const attempt = broker.tryClaimHuman(id, reviewerId);
|
|
176
|
+
json(response, { attempt, request: portable });
|
|
177
|
+
}
|
|
178
|
+
else if (action === 'renew' || action === 'release') {
|
|
179
|
+
shape(input, ['attemptId']);
|
|
180
|
+
const attemptId = string(input.attemptId);
|
|
181
|
+
json(response, action === 'renew' ? broker.renewHumanTryClaim(id, reviewerId, attemptId) : { released: broker.releaseHumanTryClaim(id, reviewerId, attemptId) });
|
|
182
|
+
}
|
|
183
|
+
else if (action === 'confirm') {
|
|
184
|
+
shape(input, ['attemptId', 'preparation']);
|
|
185
|
+
const confirmed = broker.confirmHumanClaim(id, reviewerId, string(input.attemptId), input.preparation);
|
|
186
|
+
json(response, { request: portableReview(confirmed) });
|
|
187
|
+
}
|
|
188
|
+
else if (action === 'authorize-tool' || action === 'tool-receipt') {
|
|
189
|
+
shape(input, ['attemptId', 'toolName', 'arguments']);
|
|
190
|
+
const args = { reviewerId, attemptId: string(input.attemptId), toolName: string(input.toolName), arguments: input.arguments ?? {} };
|
|
191
|
+
if (action === 'authorize-tool')
|
|
192
|
+
json(response, { tool: broker.authorizeRemoteHumanTool(id, args) });
|
|
193
|
+
else {
|
|
194
|
+
broker.recordRemoteHumanTool(id, args);
|
|
195
|
+
json(response, { ok: true });
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
else if (action === 'submit') {
|
|
199
|
+
shape(input, ['attemptId', 'result']);
|
|
200
|
+
const current = broker.getRequest(id);
|
|
201
|
+
if (!current || current.claimedBy !== reviewerId || current.claimAttemptId !== string(input.attemptId))
|
|
202
|
+
throw new HttpError(409, 'This Claim no longer belongs to this attempt.');
|
|
203
|
+
const completed = await broker.completeHuman(id, { reviewerId, result: input.result });
|
|
204
|
+
if (!completed)
|
|
205
|
+
throw new HttpError(404, 'The completed request is unavailable.');
|
|
206
|
+
const run = broker.getRun(completed.runId);
|
|
207
|
+
if (run.status === 'QUEUED')
|
|
208
|
+
await ensureRunWorker({ broker, context, run });
|
|
209
|
+
json(response, { id, status: completed.status, result: completed.result });
|
|
210
|
+
}
|
|
211
|
+
else
|
|
212
|
+
throw new HttpError(404, 'Unknown review action.');
|
|
213
|
+
}
|
|
214
|
+
finally {
|
|
215
|
+
await broker.close();
|
|
216
|
+
}
|
|
217
|
+
})().catch(error => {
|
|
218
|
+
if (response.headersSent) {
|
|
219
|
+
response.destroy();
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
json(response, { error: error instanceof Error ? error.message : 'Review action failed.' }, error instanceof HttpError ? error.status : 409);
|
|
223
|
+
}).finally(() => { active.delete(controller); response.off('close', disconnect); jobs.delete(job); });
|
|
224
|
+
jobs.add(job);
|
|
225
|
+
});
|
|
226
|
+
server.requestTimeout = 30_000;
|
|
227
|
+
server.headersTimeout = 10_000;
|
|
228
|
+
await new Promise((resolve, reject) => {
|
|
229
|
+
server.once('error', reject);
|
|
230
|
+
server.listen(requestedPort, host, () => { server.off('error', reject); resolve(); });
|
|
231
|
+
});
|
|
232
|
+
const address = server.address();
|
|
233
|
+
if (!address || typeof address === 'string')
|
|
234
|
+
throw new Error('Cannot determine review server address.');
|
|
235
|
+
let closePromise;
|
|
236
|
+
return { url: `http://${host.includes(':') ? `[${host}]` : host}:${address.port}`,
|
|
237
|
+
close() {
|
|
238
|
+
return closePromise ??= (async () => {
|
|
239
|
+
closing = true;
|
|
240
|
+
for (const controller of active)
|
|
241
|
+
controller.abort(new Error('Review server stopped.'));
|
|
242
|
+
await new Promise((resolve, reject) => { server.close(error => error ? reject(error) : resolve()); server.closeAllConnections(); });
|
|
243
|
+
await Promise.allSettled([...jobs]);
|
|
244
|
+
})();
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/review/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ReviewEnvelope, ReviewRequest } from '../contracts.js';
|
|
2
|
+
/** Portable review data contains no publisher paths, credentials or worker state. */
|
|
3
|
+
export interface PortableReview extends ReviewEnvelope {
|
|
4
|
+
id: string;
|
|
5
|
+
runId: string;
|
|
6
|
+
packageVersion: string;
|
|
7
|
+
claimedBy: string | null;
|
|
8
|
+
claimAttemptId?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function portableReview(request: ReviewRequest): PortableReview;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { packageVersion } from '../runtime-paths.js';
|
|
2
|
+
export function portableReview(request) {
|
|
3
|
+
if (request.profile.kind !== 'human' || request.workspace.mode !== 'copy' || !request.configManifest) {
|
|
4
|
+
throw new Error('Remote review requires a copy-mode Human request with a TypeScript tool manifest.');
|
|
5
|
+
}
|
|
6
|
+
return {
|
|
7
|
+
id: request.id, runId: request.runId, repoId: request.repoId,
|
|
8
|
+
snapshotHash: request.snapshotHash, criticId: request.criticId, title: request.title,
|
|
9
|
+
target: request.target, deps: request.deps, artifacts: request.artifacts,
|
|
10
|
+
...(request.artifactGroups ? { artifactGroups: request.artifactGroups } : {}),
|
|
11
|
+
artifactTypes: request.artifactTypes, configManifest: request.configManifest,
|
|
12
|
+
payload: { instruction: request.payload.instruction }, profile: { kind: 'human' },
|
|
13
|
+
packageVersion, claimedBy: request.claimedBy ?? null,
|
|
14
|
+
...(request.claimAttemptId ? { claimAttemptId: request.claimAttemptId } : {}),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/review/types.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAWrD,MAAM,UAAU,cAAc,CAAC,OAAsB;IACnD,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO,IAAI,OAAO,CAAC,SAAS,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;QACrG,MAAM,IAAI,KAAK,CAAC,mFAAmF,CAAC,CAAC;IACvG,CAAC;IACD,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM;QAC5D,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK;QACpF,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS;QACxE,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7E,aAAa,EAAE,OAAO,CAAC,aAAa,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc;QAC5E,OAAO,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;QACjF,cAAc,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,IAAI;QACpD,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9E,CAAC;AACJ,CAAC"}
|
|
@@ -11,6 +11,8 @@ export interface ToolMetadata {
|
|
|
11
11
|
observation: 'content' | 'none';
|
|
12
12
|
artifactKind?: 'file' | 'directory' | 'any';
|
|
13
13
|
timeoutMs?: number;
|
|
14
|
+
/** Project-relative runtime files or directories whose bytes affect this tool. */
|
|
15
|
+
executionPaths?: string[];
|
|
14
16
|
}
|
|
15
17
|
export interface ToolContext {
|
|
16
18
|
artifactId: string;
|
|
@@ -20,6 +22,8 @@ export interface ToolContext {
|
|
|
20
22
|
tmpDir: string;
|
|
21
23
|
signal: AbortSignal;
|
|
22
24
|
resolvePath(path?: string): Promise<string>;
|
|
25
|
+
/** Resolve only paths explicitly registered in metadata.executionPaths. */
|
|
26
|
+
resolveExecutionPath?(path: string): Promise<string>;
|
|
23
27
|
}
|
|
24
28
|
export type ToolContent = {
|
|
25
29
|
type: 'text';
|
|
@@ -61,10 +65,19 @@ export interface ArtifactToolsConfig {
|
|
|
61
65
|
agentTools?: Record<string, ToolDefinition<any>>;
|
|
62
66
|
humanTools?: Record<string, ToolDefinition<any>>;
|
|
63
67
|
}
|
|
68
|
+
export interface EnvironmentRequirement {
|
|
69
|
+
description: string;
|
|
70
|
+
/** Project-relative Node script; a zero exit status confirms readiness. */
|
|
71
|
+
script: string;
|
|
72
|
+
timeoutMs?: number;
|
|
73
|
+
/** Additional project files or directories used by the check. */
|
|
74
|
+
inputs?: string[];
|
|
75
|
+
}
|
|
64
76
|
export interface Config {
|
|
65
77
|
artifacts: Record<string, ArtifactEntryDefinition>;
|
|
66
78
|
artifactTypes: Record<string, ArtifactToolsConfig>;
|
|
67
79
|
critics: CriticDefinition[];
|
|
80
|
+
envRequirements?: Record<string, EnvironmentRequirement>;
|
|
68
81
|
}
|
|
69
82
|
export type ConfigFactory = () => Config | Promise<Config>;
|
|
70
83
|
export interface ConfigManifest {
|
|
@@ -78,6 +91,15 @@ export interface ConfigManifest {
|
|
|
78
91
|
agentTools: Record<string, ToolMetadata>;
|
|
79
92
|
humanTools: Record<string, ToolMetadata>;
|
|
80
93
|
}>;
|
|
94
|
+
envRequirements?: Record<string, EnvironmentRequirement>;
|
|
95
|
+
environmentInputs?: {
|
|
96
|
+
path: string;
|
|
97
|
+
hash: string;
|
|
98
|
+
}[];
|
|
99
|
+
executionInputs?: {
|
|
100
|
+
path: string;
|
|
101
|
+
hash: string;
|
|
102
|
+
}[];
|
|
81
103
|
}
|
|
82
104
|
type Properties<S> = S extends {
|
|
83
105
|
properties: infer P;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|