@dev.fast/whiteboard 0.2.1-preview.20261006.99 → 0.2.1-preview.20261007.102
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/{account-alias-DOHN1RSH.js → account-alias-DLE9XZhi.js} +1 -1
- package/dist/agent-cli-DdfuiyOF.js +2 -0
- package/dist/{agent-cli-ChOq0ZuO.js → agent-cli-d0YJQNrR.js} +6 -6
- package/dist/{agent-client-CPQo7iTI.js → agent-client-DoaODH6I.js} +2 -2
- package/dist/{authoring-tools-Cr6Kpjsx.js → authoring-tools-Bvre8hN2.js} +2 -2
- package/dist/build-info.json +1 -1
- package/dist/{cli-hVgHcdsv.js → cli-DtolttUF.js} +1 -1
- package/dist/{cli-runner-CMmd6o_m.js → cli-runner-CSEH_mQN.js} +11 -11
- package/dist/cli.js +2 -2
- package/dist/{client-DFoh50W3.js → client-D01H2KOV.js} +2 -2
- package/dist/{desktop-discovery-DBO-PM2V.js → desktop-discovery-DK2HoBy5.js} +1 -1
- package/dist/{headless-host-CVMDNmLU.js → headless-host-YxYKMcI5.js} +3 -2
- package/dist/{local-data-CxLk75rx.js → local-data-Dy8AngNb.js} +37 -84
- package/dist/{mcp-QeF8vkdf.js → mcp-DGKhDPMs.js} +3 -3
- package/dist/{process-error-telemetry-CkiiadgB.js → process-error-telemetry-DN5BpZnc.js} +345 -13
- package/dist/{profile-4ry2f3AM.js → profile-B6jrb2QN.js} +1 -1
- package/dist/profile-D8XSrJYI.js +2 -0
- package/dist/{request-origin-D_4QIdoN.js → request-origin-BB2TENZ5.js} +1 -1
- package/dist/{review-telemetry-DEFnQsQ2.js → review-telemetry-2UlsdE4D.js} +2 -2
- package/dist/server/desktop-host.js +14 -303
- package/dist/sharing/index.d.ts +6 -10
- package/dist/sharing/index.js +1 -1
- package/dist/{src-DnwdaQ2r.js → src-DHiDJQDy.js} +7 -14
- package/dist/{stored-document-migration-DHeMpLMb.js → stored-document-migration-T9Uj5MkN.js} +1 -1
- package/dist/{tool-failure-C8zB73HV.js → tool-failure-Djeeax6q.js} +1 -1
- package/package.json +7 -8
- package/src/review-api/comparison-coverage.ts +6 -11
- package/src/review-api/http.ts +31 -4
- package/src/review-api/store.ts +0 -5
- package/src/server/desktop-server.ts +2 -13
- package/src/server/diffr-config.ts +170 -128
- package/src/server/headless-host.ts +3 -0
- package/src/server/structural-diff.ts +12 -39
- package/src/server/test-fixtures/diffr-ui-overrides.toml +38 -0
- package/dist/agent-cli-DzWfZr6G.js +0 -2
- package/dist/profile-Bh5FIrmf.js +0 -2
- package/src/server/diffr-languages.ts +0 -97
|
@@ -1,32 +1,343 @@
|
|
|
1
|
-
import { c as jsonString, n as isJsonObject, u as parseJsonText } from "./src-X9phtB2j.js";
|
|
2
|
-
import { a as sharedReviewId, c as verifyShareRepository, d as StreamLimitError, f as readBoundedStream, l as exportShare, m as shareIdSchema, n as ShareClient, p as parseShareLink, r as SharePreflightError, s as readShareRepository, t as ShareAuthError, u as validateShareSources } from "./client-
|
|
3
|
-
import { d as
|
|
1
|
+
import { c as jsonString, m as isStringValue, n as isJsonObject, u as parseJsonText } from "./src-X9phtB2j.js";
|
|
2
|
+
import { a as sharedReviewId, c as verifyShareRepository, d as StreamLimitError, f as readBoundedStream, l as exportShare, m as shareIdSchema, n as ShareClient, p as parseShareLink, r as SharePreflightError, s as readShareRepository, t as ShareAuthError, u as validateShareSources } from "./client-D01H2KOV.js";
|
|
3
|
+
import { _ as invalidateStructuralComparisons, a as inspectSnapshot, c as askAgentIds, d as askQuestionSchema, f as AgentSelectionSchema, i as commandSchema, l as askChoiceKinds, p as selectionMarkdown, r as SCRATCHPAD_ID, s as applyAskChange, u as askPicksSchema, v as diffrExecutable, y as diffrMissingError } from "./local-data-Dy8AngNb.js";
|
|
4
|
+
import { d as REVIEW_CLIENT_REMOTE, i as parseReviewVerbRequest, r as parseReviewDesktopVerbResult, u as REVIEW_CLIENT_HEADER, v as reviewDiffrSummarizerInputSchema, y as decodeStructuralDiffEvent } from "./src-DHiDJQDy.js";
|
|
4
5
|
import { C as TraceStorageDeniedError, G as readStoreAuth, H as DEFAULT_STORE_ORIGIN, U as clearStoreAuth, W as openUrlInBrowser, _ as isTraceStorageConfigured, b as selectTraceStorage, o as listReviewTraceSessions, q as runStoreLogin, s as loadReviewAgentTrace, y as resolveTraceStorage } from "./review-agent-traces-DNJFYzc8.js";
|
|
5
|
-
import {
|
|
6
|
-
import { $ as unionIntervals, G as selectionKey, H as comparisonKey, I as fileLineRangeSchema, J as coverageSources, N as lensSelections, Q as subtractIntervals, T as selectionReferences, U as formatAnchor, V as anchorSelection, W as resolveDiffSelection, Y as emptyCoverage, Z as scopedCoverage, h as elements, k as UNCATEGORIZED_LENS_ID, u as anchorPins } from "./stored-document-migration-DHeMpLMb.js";
|
|
6
|
+
import { $ as unionIntervals, G as selectionKey, H as comparisonKey, I as fileLineRangeSchema, J as coverageSources, N as lensSelections, Q as subtractIntervals, T as selectionReferences, U as formatAnchor, V as anchorSelection, W as resolveDiffSelection, Y as emptyCoverage, Z as scopedCoverage, h as elements, k as UNCATEGORIZED_LENS_ID, u as anchorPins } from "./stored-document-migration-T9Uj5MkN.js";
|
|
7
7
|
import { t as ReviewInputError } from "./input-error-OLgB_h31.js";
|
|
8
8
|
import { A as devReviewHome, h as TraceConfigurationError, i as isS3MockMode } from "./s3-config-CAxhO9u_.js";
|
|
9
9
|
import { t as errorMessage } from "./error-message-OtiDonty.js";
|
|
10
10
|
import { T as traceMachineEnabled } from "./review-home-paths-6zZH-1c9.js";
|
|
11
11
|
import { i as readReviewPackageVersion, n as readBuildCommit } from "./package-paths-B6-zxvIO.js";
|
|
12
|
-
import { a as REVIEW_APP_SESSION_ID_HEADER, c as sanitizeUiTelemetryEvent, i as BUNDLE_FRAME_PATTERN, l as cleanTelemetryText, r as reviewRequestOrigin, s as isReportableCleanedMessage } from "./request-origin-
|
|
13
|
-
import { a as scratchpadAvailable, c as readQuerySchemas, i as renderInstructions, o as inspectQuerySchema, r as instructionsQuerySchema, s as queryAnchor, t as authoringTools } from "./authoring-tools-
|
|
12
|
+
import { a as REVIEW_APP_SESSION_ID_HEADER, c as sanitizeUiTelemetryEvent, i as BUNDLE_FRAME_PATTERN, l as cleanTelemetryText, r as reviewRequestOrigin, s as isReportableCleanedMessage } from "./request-origin-BB2TENZ5.js";
|
|
13
|
+
import { a as scratchpadAvailable, c as readQuerySchemas, i as renderInstructions, o as inspectQuerySchema, r as instructionsQuerySchema, s as queryAnchor, t as authoringTools } from "./authoring-tools-Bvre8hN2.js";
|
|
14
14
|
import { t as fuzzyRank } from "./fuzzy-match-BoAmcyak.js";
|
|
15
15
|
import { createRequire } from "node:module";
|
|
16
16
|
import crypto$1, { createHash, randomUUID } from "node:crypto";
|
|
17
17
|
import { z } from "zod";
|
|
18
18
|
import { constants, mkdirSync, writeFileSync } from "node:fs";
|
|
19
|
-
import { access, chmod, mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
20
|
-
import path, { posix } from "node:path";
|
|
21
|
-
import { homedir } from "node:os";
|
|
19
|
+
import { access, chmod, mkdir, mkdtemp, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
20
|
+
import path, { join, posix } from "node:path";
|
|
21
|
+
import { homedir, tmpdir } from "node:os";
|
|
22
22
|
import { execFile, spawn } from "node:child_process";
|
|
23
23
|
import { promisify } from "node:util";
|
|
24
24
|
import { pathToFileURL } from "node:url";
|
|
25
25
|
import { Readable, Writable } from "node:stream";
|
|
26
|
+
import { stringify } from "smol-toml";
|
|
26
27
|
import { getRequestListener } from "@hono/node-server";
|
|
27
28
|
import { Hono } from "hono";
|
|
28
29
|
import { PROTOCOL_VERSION, RequestError, client, methods, ndJsonStream } from "@agentclientprotocol/sdk";
|
|
29
30
|
import { streamSSE } from "hono/streaming";
|
|
31
|
+
//#region src/server/diffr-config.ts
|
|
32
|
+
const execFileAsync$2 = promisify(execFile);
|
|
33
|
+
let writes = Promise.resolve();
|
|
34
|
+
let testing = false;
|
|
35
|
+
function serialized(operation) {
|
|
36
|
+
const next = writes.then(operation, operation);
|
|
37
|
+
writes = next.catch(() => {});
|
|
38
|
+
return next;
|
|
39
|
+
}
|
|
40
|
+
function diffrArgv(args) {
|
|
41
|
+
switch (args.command) {
|
|
42
|
+
case "schema": return ["config", "schema"];
|
|
43
|
+
case "show": return [
|
|
44
|
+
"config",
|
|
45
|
+
"show",
|
|
46
|
+
"--json",
|
|
47
|
+
...args.reveal ? ["--reveal"] : []
|
|
48
|
+
];
|
|
49
|
+
case "set": return [
|
|
50
|
+
"config",
|
|
51
|
+
"set",
|
|
52
|
+
"--stdin",
|
|
53
|
+
"--json"
|
|
54
|
+
];
|
|
55
|
+
case "migrate": return [
|
|
56
|
+
"config",
|
|
57
|
+
"migrate",
|
|
58
|
+
"--json"
|
|
59
|
+
];
|
|
60
|
+
case "diff": return [
|
|
61
|
+
"--no-index",
|
|
62
|
+
"--format",
|
|
63
|
+
"ndjson",
|
|
64
|
+
"--",
|
|
65
|
+
args.before,
|
|
66
|
+
args.after
|
|
67
|
+
];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async function diffr(args, rootPath, options = {}) {
|
|
71
|
+
const executable = diffrExecutable();
|
|
72
|
+
try {
|
|
73
|
+
const operation = execFileAsync$2(executable, diffrArgv(args), {
|
|
74
|
+
cwd: rootPath,
|
|
75
|
+
maxBuffer: 16777216,
|
|
76
|
+
signal: options.signal ?? AbortSignal.timeout(3e4),
|
|
77
|
+
env: options.env ?? process.env
|
|
78
|
+
});
|
|
79
|
+
if (args.command === "set") operation.child.stdin?.end(JSON.stringify(args.patch));
|
|
80
|
+
const { stdout } = await operation;
|
|
81
|
+
return stdout;
|
|
82
|
+
} catch (error) {
|
|
83
|
+
const failure = error;
|
|
84
|
+
if (failure.code === "ENOENT") throw diffrMissingError();
|
|
85
|
+
if (failure.name === "AbortError") throw new Error("diffr timed out or was cancelled.");
|
|
86
|
+
if ((args.command === "set" || args.command === "migrate") && failure.stdout) {
|
|
87
|
+
let details;
|
|
88
|
+
try {
|
|
89
|
+
details = parseJsonText(failure.stdout);
|
|
90
|
+
} catch {}
|
|
91
|
+
if (isJsonObject(details) && isJsonObject(details.error) && isStringValue(details.error.message)) {
|
|
92
|
+
const { message, repair_prompt: prompt } = details.error;
|
|
93
|
+
throw new Error(isStringValue(prompt) ? `${message}\n\nCopy this as a prompt to your coding agent:\n${prompt}` : message);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
throw new Error("diffr could not complete the operation. Check its configuration and credentials.");
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async function values(rootPath, reveal = false, signal) {
|
|
100
|
+
return json(await diffr({
|
|
101
|
+
command: "show",
|
|
102
|
+
reveal
|
|
103
|
+
}, rootPath, { signal }));
|
|
104
|
+
}
|
|
105
|
+
function json(output) {
|
|
106
|
+
try {
|
|
107
|
+
const parsed = parseJsonText(output);
|
|
108
|
+
if (isJsonObject(parsed)) return parsed;
|
|
109
|
+
} catch {}
|
|
110
|
+
throw new Error("diffr configuration response is malformed.");
|
|
111
|
+
}
|
|
112
|
+
function valueAt(object, key) {
|
|
113
|
+
let value = object;
|
|
114
|
+
for (const segment of key.split(".")) value = isJsonObject(value) ? value[segment] : void 0;
|
|
115
|
+
return value;
|
|
116
|
+
}
|
|
117
|
+
const prefix = "plugins.shape.bundled.summarize";
|
|
118
|
+
function savedProvider(config) {
|
|
119
|
+
const value = valueAt(config, `${prefix}.provider`);
|
|
120
|
+
return isStringValue(value) ? value : "";
|
|
121
|
+
}
|
|
122
|
+
/** Whether a saved key belongs to a different destination than the draft's. */
|
|
123
|
+
function movesKey(config, draft) {
|
|
124
|
+
const endpoint = valueAt(config, `${prefix}.endpoint`);
|
|
125
|
+
return draft.provider !== savedProvider(config) || draft.endpoint !== (isStringValue(endpoint) ? endpoint : "");
|
|
126
|
+
}
|
|
127
|
+
function environmentKey(providers, id) {
|
|
128
|
+
return providers.find((provider) => provider.id === id)?.keyVariables.map((name) => process.env[name]).find((key) => !!key);
|
|
129
|
+
}
|
|
130
|
+
function keyOptional(providers, id, endpoint) {
|
|
131
|
+
return endpoint !== "" && !!providers.find((provider) => provider.id === id)?.keylessCustomEndpoint;
|
|
132
|
+
}
|
|
133
|
+
function strings(value) {
|
|
134
|
+
return Array.isArray(value) ? value.filter(isStringValue) : [];
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Defaults supplied by diffr's schema for tag hiding and summary controls.
|
|
138
|
+
* If the schema cannot be read, resolved settings still work.
|
|
139
|
+
*/
|
|
140
|
+
async function configDefaults(rootPath) {
|
|
141
|
+
let schema;
|
|
142
|
+
try {
|
|
143
|
+
schema = json(await diffr({ command: "schema" }, rootPath));
|
|
144
|
+
} catch {
|
|
145
|
+
return {};
|
|
146
|
+
}
|
|
147
|
+
const options = valueAt(schema, "properties.plugins.properties.shape.properties.bundled.properties.summarize.properties");
|
|
148
|
+
const defaultHiddenTags = strings(valueAt(schema, "properties.plugins.properties.classify.properties.bundled.properties.hide.default"));
|
|
149
|
+
if (!isJsonObject(options)) return { defaultHiddenTags };
|
|
150
|
+
const option = (name) => isJsonObject(options[name]) ? options[name] : {};
|
|
151
|
+
const provider = option("provider");
|
|
152
|
+
const titles = strings(provider["x-enum-titles"]);
|
|
153
|
+
const models = valueAt(option("model"), "x-default-by.values");
|
|
154
|
+
const details = valueAt(option("provider_details"), "x-default-by.values");
|
|
155
|
+
const providers = strings(provider.enum).map((id, index) => {
|
|
156
|
+
const detail = isJsonObject(details) ? details[id] : void 0;
|
|
157
|
+
const model = isJsonObject(models) ? models[id] : void 0;
|
|
158
|
+
const endpoint = isJsonObject(detail) ? detail.endpoint : void 0;
|
|
159
|
+
return {
|
|
160
|
+
id,
|
|
161
|
+
title: titles[index] ?? id,
|
|
162
|
+
model: isStringValue(model) ? model : "",
|
|
163
|
+
endpoint: isStringValue(endpoint) ? endpoint : "",
|
|
164
|
+
keyVariables: isJsonObject(detail) ? strings(detail.key_variables) : [],
|
|
165
|
+
keylessCustomEndpoint: isJsonObject(detail) && detail.keyless_custom_endpoint === true
|
|
166
|
+
};
|
|
167
|
+
});
|
|
168
|
+
const prompt = option("system_prompt");
|
|
169
|
+
return {
|
|
170
|
+
defaultHiddenTags,
|
|
171
|
+
providers,
|
|
172
|
+
defaultPrompt: isStringValue(prompt.default) ? prompt.default : void 0
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
async function read(rootPath) {
|
|
176
|
+
const config = await values(rootPath);
|
|
177
|
+
const defaults = await configDefaults(rootPath);
|
|
178
|
+
const saved = valueAt(config, `${prefix}.api_key`);
|
|
179
|
+
const credentialSource = isStringValue(saved) && saved.length > 0 ? "config" : environmentKey(defaults.providers ?? [], savedProvider(config)) ? "environment" : "missing";
|
|
180
|
+
const plugins = valueAt(config, "plugins.shape");
|
|
181
|
+
if (isJsonObject(plugins)) {
|
|
182
|
+
const entries = isJsonObject(plugins.bundled) ? [...Object.values(plugins), ...Object.values(plugins.bundled)] : Object.values(plugins);
|
|
183
|
+
for (const plugin of entries) if (isJsonObject(plugin)) delete plugin.api_key;
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
values: config,
|
|
187
|
+
credentialSource,
|
|
188
|
+
...defaults
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function readDiffrConfig(rootPath) {
|
|
192
|
+
return serialized(() => read(rootPath));
|
|
193
|
+
}
|
|
194
|
+
async function migrateDiffrConfig(signal) {
|
|
195
|
+
const result = json(await diffr({ command: "migrate" }, void 0, { signal }));
|
|
196
|
+
if (result.changed === true) invalidateStructuralComparisons();
|
|
197
|
+
return result.changed === true;
|
|
198
|
+
}
|
|
199
|
+
async function writeSettings(patch, rootPath) {
|
|
200
|
+
let changed = false;
|
|
201
|
+
let error;
|
|
202
|
+
try {
|
|
203
|
+
changed = json(await diffr({
|
|
204
|
+
command: "set",
|
|
205
|
+
patch
|
|
206
|
+
}, rootPath)).changed === true;
|
|
207
|
+
if (changed) invalidateStructuralComparisons();
|
|
208
|
+
} catch (cause) {
|
|
209
|
+
error = cause instanceof Error ? cause.message : "diffr could not save the settings.";
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
...await read(rootPath),
|
|
213
|
+
changed,
|
|
214
|
+
error
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function setDiffrConfigValue(key, value, rootPath) {
|
|
218
|
+
if (!/^[A-Za-z0-9_][A-Za-z0-9_-]*(\.[^.\r\n\0]+)*$/u.test(key)) throw new Error("Invalid diffr config key.");
|
|
219
|
+
const parts = key.split(".");
|
|
220
|
+
let patch = { [parts.pop()]: value };
|
|
221
|
+
for (const part of parts.reverse()) patch = { [part]: patch };
|
|
222
|
+
return serialized(() => writeSettings(patch, rootPath));
|
|
223
|
+
}
|
|
224
|
+
function saveDiffrSummarizer(input, rootPath) {
|
|
225
|
+
const parsed = reviewDiffrSummarizerInputSchema.safeParse(input);
|
|
226
|
+
if (!parsed.success) throw new Error("Invalid summary settings.");
|
|
227
|
+
const draft = parsed.data;
|
|
228
|
+
return serialized(async () => {
|
|
229
|
+
const current = await read(rootPath);
|
|
230
|
+
const providers = current.providers ?? [];
|
|
231
|
+
const moving = movesKey(current.values, draft);
|
|
232
|
+
const savedKey = current.credentialSource === "config";
|
|
233
|
+
if (draft.enabled && !draft.apiKey && !(savedKey && !moving) && !environmentKey(providers, draft.provider) && !keyOptional(providers, draft.provider, draft.endpoint)) return {
|
|
234
|
+
...current,
|
|
235
|
+
changed: false,
|
|
236
|
+
error: "Add an API key before enabling summaries."
|
|
237
|
+
};
|
|
238
|
+
const summarize = {
|
|
239
|
+
enabled: draft.enabled,
|
|
240
|
+
provider: draft.provider,
|
|
241
|
+
endpoint: draft.endpoint,
|
|
242
|
+
model: draft.model,
|
|
243
|
+
tests: draft.tests
|
|
244
|
+
};
|
|
245
|
+
if (draft.apiKey) summarize.api_key = draft.apiKey;
|
|
246
|
+
else if (moving && savedKey) summarize.api_key = "";
|
|
247
|
+
if (draft.systemPrompt.trim()) summarize.system_prompt = draft.systemPrompt;
|
|
248
|
+
return writeSettings({ plugins: { shape: { bundled: { summarize } } } }, rootPath);
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
async function testDiffrSummarizer(input, rootPath, signal) {
|
|
252
|
+
const parsed = reviewDiffrSummarizerInputSchema.safeParse(input);
|
|
253
|
+
if (!parsed.success) throw new Error("Invalid summary settings.");
|
|
254
|
+
if (testing) throw new Error("A summary test is already running.");
|
|
255
|
+
testing = true;
|
|
256
|
+
const timeout = AbortSignal.timeout(6e4);
|
|
257
|
+
const deadline = signal ? AbortSignal.any([signal, timeout]) : timeout;
|
|
258
|
+
let directory;
|
|
259
|
+
try {
|
|
260
|
+
const config = await serialized(() => values(rootPath, true, deadline));
|
|
261
|
+
const saved = valueAt(config, prefix);
|
|
262
|
+
if (!isJsonObject(saved)) throw new Error("The summarizer is not available in this configuration.");
|
|
263
|
+
const { provider, endpoint, model, systemPrompt } = parsed.data;
|
|
264
|
+
const providers = (await configDefaults(rootPath)).providers ?? [];
|
|
265
|
+
const variables = providers.find((known) => known.id === provider)?.keyVariables ?? [];
|
|
266
|
+
const apiKey = parsed.data.apiKey || (!movesKey(config, parsed.data) && isStringValue(saved.api_key) ? saved.api_key : "") || environmentKey(providers, provider);
|
|
267
|
+
if (!apiKey && !keyOptional(providers, provider, endpoint)) throw new Error("Add an API key to test summaries.");
|
|
268
|
+
directory = await mkdtemp(join(tmpdir(), "review-summary-"));
|
|
269
|
+
const options = {
|
|
270
|
+
...saved,
|
|
271
|
+
enabled: true,
|
|
272
|
+
provider,
|
|
273
|
+
model,
|
|
274
|
+
...systemPrompt.trim() && { system_prompt: systemPrompt },
|
|
275
|
+
min_lines: 1,
|
|
276
|
+
retries: 0,
|
|
277
|
+
request_timeout_ms: 45e3
|
|
278
|
+
};
|
|
279
|
+
delete options.api_key;
|
|
280
|
+
delete options.provider_details;
|
|
281
|
+
if (endpoint) options.endpoint = endpoint;
|
|
282
|
+
else delete options.endpoint;
|
|
283
|
+
await mkdir(join(directory, "diffr"));
|
|
284
|
+
await writeFile(join(directory, "diffr", "config.toml"), stringify({
|
|
285
|
+
version: 2,
|
|
286
|
+
plugins: { shape: {
|
|
287
|
+
order: ["bundled.summarize"],
|
|
288
|
+
bundled: { summarize: options }
|
|
289
|
+
} }
|
|
290
|
+
}), { mode: 384 });
|
|
291
|
+
const before = join(directory, "before.rs"), after = join(directory, "after.rs");
|
|
292
|
+
await writeFile(before, "");
|
|
293
|
+
await writeFile(after, SUMMARY_SAMPLE);
|
|
294
|
+
const output = await diffr({
|
|
295
|
+
command: "diff",
|
|
296
|
+
before,
|
|
297
|
+
after
|
|
298
|
+
}, directory, {
|
|
299
|
+
env: {
|
|
300
|
+
...process.env,
|
|
301
|
+
...Object.fromEntries(providers.flatMap((known) => known.keyVariables).map((name) => [name, ""])),
|
|
302
|
+
...apiKey && variables[0] && { [variables[0]]: apiKey },
|
|
303
|
+
XDG_CONFIG_HOME: directory
|
|
304
|
+
},
|
|
305
|
+
signal: deadline
|
|
306
|
+
});
|
|
307
|
+
try {
|
|
308
|
+
const events = output.trim().split("\n").map(decodeStructuralDiffEvent);
|
|
309
|
+
const complete = events.at(-1);
|
|
310
|
+
const labels = (region) => [...region.visibility?.label ? [region.visibility.label] : [], ...region.kind === "fold" ? region.children.flatMap(labels) : []];
|
|
311
|
+
const summary = events.flatMap((event) => event.type === "file" && event.diff?.type === "text" ? [event.diff.rhs, event.diff.lhs].flatMap((source) => source ? labels(source.root) : []) : []).find((label) => label.trim());
|
|
312
|
+
if (complete?.type === "complete" && complete.failed === 0 && !complete.aborted && !events.some((event) => event.type === "file" && event.error) && summary) return apiKey ? summary.split(apiKey).join("[redacted]") : summary;
|
|
313
|
+
} catch {}
|
|
314
|
+
throw new Error("No summary was produced. Check the API key, model, and network connection.");
|
|
315
|
+
} finally {
|
|
316
|
+
testing = false;
|
|
317
|
+
if (directory) await rm(directory, {
|
|
318
|
+
recursive: true,
|
|
319
|
+
force: true
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
const SUMMARY_SAMPLE = `pub fn count_values(values: &[i32]) -> (i32, i32) {
|
|
324
|
+
let mut total = 0;
|
|
325
|
+
let mut count = 0;
|
|
326
|
+
for value in values {
|
|
327
|
+
if *value > 0 {
|
|
328
|
+
total += value;
|
|
329
|
+
count += 1;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
let average = if count > 0 {
|
|
333
|
+
total / count
|
|
334
|
+
} else {
|
|
335
|
+
0
|
|
336
|
+
};
|
|
337
|
+
(count, average)
|
|
338
|
+
}
|
|
339
|
+
`;
|
|
340
|
+
//#endregion
|
|
30
341
|
//#region src/server/global-verb-relay.ts
|
|
31
342
|
const DEFAULT_VERB_TIMEOUT_MS = 45e3;
|
|
32
343
|
const DEFAULT_MAX_CLIENTS = 16;
|
|
@@ -3319,9 +3630,9 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
3319
3630
|
return [
|
|
3320
3631
|
`A reviewer is reading "${snapshot.title}" in Whiteboard and has a question about a selection.`,
|
|
3321
3632
|
checkout.live ? "Your working directory is the repository the review describes." : `Your working directory is a checkout of the review's head commit, ${checkout.head}. Answer from this code, not from other branches.`,
|
|
3322
|
-
"Answer the question.",
|
|
3633
|
+
"Answer the question for a staff engineer: lead with the answer and keep it short. Explain at the level of components and data flow before functions, and check each claim about the code against code you have read.",
|
|
3323
3634
|
"Name files by their path from the checkout root, with a line where it helps, as in `src/app.ts:42`; the reviewer can open them from your answer.",
|
|
3324
|
-
...reach?.kind === "mcp" ? [`The whiteboard MCP tools read and change this review: its sessionId is "${reviewId}". Read it with session_get. If the reviewer asks you to change the review, edit it with session_edit; do not write files to do it.`] : reach?.kind === "cli" ? [`Whiteboard's CLI reads and changes this review from your shell: its sessionId is "${reviewId}". Read it with \`${reach.command} api session_get '{"sessionId":"${reviewId}"}'\`. If the reviewer asks you to change the review, edit it with \`${reach.command} api session_edit '<json>'\`; do not write files to do it. \`${reach.command} api tools\` lists each tool's input.`] : [],
|
|
3635
|
+
...reach?.kind === "mcp" ? [`The whiteboard MCP tools read and change this review: its sessionId is "${reviewId}". Read it with session_get. If the reviewer asks you to change the review, first read session_get_instructions({}) for its guidelines and each component's fields (the review exists, so skip creating one), then edit it with session_edit; do not write files to do it.`] : reach?.kind === "cli" ? [`Whiteboard's CLI reads and changes this review from your shell: its sessionId is "${reviewId}". Read it with \`${reach.command} api session_get '{"sessionId":"${reviewId}"}'\`. If the reviewer asks you to change the review, first read \`${reach.command} api session_get_instructions '{}'\` for its guidelines and each component's fields (the review exists, so skip creating one), then edit it with \`${reach.command} api session_edit '<json>'\`; do not write files to do it. \`${reach.command} api tools\` lists each tool's input.`] : [],
|
|
3325
3636
|
"",
|
|
3326
3637
|
await selectionContext(reviewId, selection, version)
|
|
3327
3638
|
].join("\n");
|
|
@@ -3399,6 +3710,27 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
3399
3710
|
readReview(reviewId);
|
|
3400
3711
|
return context.json({ threads: store.askHistory.list(reviewId) });
|
|
3401
3712
|
});
|
|
3713
|
+
app.get("/:id/ask/:threadId", (context) => {
|
|
3714
|
+
const record = store.askHistory.get(context.req.param("threadId"));
|
|
3715
|
+
if (record?.reviewId !== context.req.param("id")) throw new ReviewInputError("This conversation was not found.", 404);
|
|
3716
|
+
const target = record.selection.target;
|
|
3717
|
+
return context.json({
|
|
3718
|
+
id: record.id,
|
|
3719
|
+
agent: record.agent,
|
|
3720
|
+
agentName: askAgents[record.agent].name,
|
|
3721
|
+
status: "idle",
|
|
3722
|
+
readOnly: true,
|
|
3723
|
+
bypass: false,
|
|
3724
|
+
head: record.head,
|
|
3725
|
+
cwd: record.cwd,
|
|
3726
|
+
title: record.title,
|
|
3727
|
+
selection: {
|
|
3728
|
+
title: record.selection.title,
|
|
3729
|
+
quote: target.kind === "text" ? target.quote : void 0
|
|
3730
|
+
},
|
|
3731
|
+
entries: record.entries ?? []
|
|
3732
|
+
});
|
|
3733
|
+
});
|
|
3402
3734
|
app.post("/:id/ask/:threadId/open", async (context) => {
|
|
3403
3735
|
const reviewId = context.req.param("id");
|
|
3404
3736
|
const threadId = context.req.param("threadId");
|
|
@@ -3950,4 +4282,4 @@ async function sendServerError(telemetry, properties) {
|
|
|
3950
4282
|
} catch {}
|
|
3951
4283
|
}
|
|
3952
4284
|
//#endregion
|
|
3953
|
-
export { serverJson as a, recordClientError as c, HttpJsonError as d, ReviewServerError as f, createWhiteboardCore as i, createNodeRequestListener as l, installProcessErrorTelemetry as n, captureSanitizedUiTelemetry as o, GlobalReviewDesktopVerbRelay as p, serverCrashReportPath as r, clientErrorsForSession as s, drainServerCrashReport as t, readBoundedRequestJson as u };
|
|
4285
|
+
export { setDiffrConfigValue as _, serverJson as a, recordClientError as c, HttpJsonError as d, ReviewServerError as f, saveDiffrSummarizer as g, readDiffrConfig as h, createWhiteboardCore as i, createNodeRequestListener as l, migrateDiffrConfig as m, installProcessErrorTelemetry as n, captureSanitizedUiTelemetry as o, GlobalReviewDesktopVerbRelay as p, serverCrashReportPath as r, clientErrorsForSession as s, drainServerCrashReport as t, readBoundedRequestJson as u, testDiffrSummarizer as v };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { o as initializeReviewStoreSchema, t as openLocalReviewStore } from "./local-data-
|
|
1
|
+
import { o as initializeReviewStoreSchema, t as openLocalReviewStore } from "./local-data-Dy8AngNb.js";
|
|
2
2
|
import { O as withFileLock } from "./s3-config-CAxhO9u_.js";
|
|
3
3
|
import "./review-home-paths-6zZH-1c9.js";
|
|
4
4
|
import { access, mkdir } from "node:fs/promises";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as jsonNumber, c as jsonString, i as jsonBoolean, n as isJsonObject } from "./src-X9phtB2j.js";
|
|
2
|
-
import { f as REVIEW_DIFF_LAYOUTS, p as REVIEW_THEME_CHOICES } from "./src-
|
|
2
|
+
import { f as REVIEW_DIFF_LAYOUTS, p as REVIEW_THEME_CHOICES } from "./src-DHiDJQDy.js";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
//#region src/telemetry-clean-text.ts
|
|
5
5
|
const USER_DATA_REGEXES = [
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { c as jsonString, l as jsonValueSchema, o as jsonObject, u as parseJsonText } from "./src-X9phtB2j.js";
|
|
2
|
-
import "./src-
|
|
2
|
+
import "./src-DHiDJQDy.js";
|
|
3
3
|
import { A as devReviewHome, D as processIsAlive, M as writeFileAtomic, O as withFileLock } from "./s3-config-CAxhO9u_.js";
|
|
4
4
|
import "./review-home-paths-6zZH-1c9.js";
|
|
5
5
|
import { i as readReviewPackageVersion, t as findReviewPackageRoot } from "./package-paths-B6-zxvIO.js";
|
|
6
|
-
import "./request-origin-
|
|
6
|
+
import "./request-origin-BB2TENZ5.js";
|
|
7
7
|
import { createHmac, randomUUID } from "node:crypto";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
import { existsSync, readFileSync, rmSync } from "node:fs";
|