@dev.fast/whiteboard 0.4.1-preview.20261027.141 → 0.4.1-preview.20261028.142
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-AJ6miBT5.js → account-alias-D1iIc7j5.js} +4 -5
- package/dist/{agent-cli-DIC2tBpL.js → agent-cli-B_gSzrhA.js} +8 -9
- package/dist/agent-cli-DtjnkDSL.js +2 -0
- package/dist/{agent-client-DyNmSHfO.js → agent-client-DudPjH3I.js} +3 -3
- package/dist/{authoring-tools-B9MhiKw4.js → authoring-tools-B-OyXmtR.js} +5 -5
- package/dist/{background-server-CZaB8zFH.js → background-server-CORnMQmu.js} +1 -1
- package/dist/{background-server-DlgbnDVt.js → background-server-CesuMV6N.js} +7 -6
- package/dist/build-info.json +1 -1
- package/dist/{cli-D7Lpc4ws.js → cli-CIP_-Fvm.js} +1 -1
- package/dist/{cli-runner-JPkbHD7I.js → cli-runner-dHnKnyNw.js} +22 -23
- package/dist/cli.js +2 -2
- package/dist/{fuzzy-match-rWIeloqo.js → fuzzy-match-CTvayutE.js} +3 -3
- package/dist/{headless-host-Cn6WDmaL.js → headless-host-CWuFw-CO.js} +118 -218
- package/dist/{headless-host-DmuAjcgt.js → headless-host-Cnu-o0xk.js} +1 -1
- package/dist/{import-CUNdl3NP.js → import-FOpJL22V.js} +198 -505
- package/dist/{lens-selection-BQxqiuWY.js → lens-selection-B_LTVyTB.js} +1 -1
- package/dist/{local-data-DxkQXCNG.js → local-data-BhNZ1Yep.js} +72 -91
- package/dist/{mcp-B154Vpj0.js → mcp-2bWqlJNW.js} +3 -3
- package/dist/{package-paths-LcO6HNp_.js → package-paths-Cg6fnaGp.js} +1 -1
- package/dist/profile-BmtFpq8d.js +2 -0
- package/dist/{profile-hC1iAoRB.js → profile-DnwIJvlh.js} +2 -2
- package/dist/{remote-attach-DhvNHMe1.js → remote-attach-C79X5M2Z.js} +4 -4
- package/dist/{remote-extensions-VLpt_4Tn.js → remote-extensions-Bw029iIS.js} +1 -1
- package/dist/{remote-extensions-DMKyDjAs.js → remote-extensions-MUUgbLJn.js} +2 -2
- package/dist/{remote-language-server-zgvAe8wb.js → remote-language-server-Dw1o27aF.js} +4 -4
- package/dist/{remote-uninstall-BR-rIuvK.js → remote-uninstall-Aza0u1_3.js} +5 -5
- package/dist/{request-origin-BnA7Nnca.js → request-origin-DEQd09Db.js} +3 -3
- package/dist/{review-app-launcher-B0Z4B8By.js → review-app-launcher-L7xKjTLQ.js} +2 -2
- package/dist/{src-KTjWplV9.js → review-home-paths-LdGS4SpR.js} +48 -8
- package/dist/{review-telemetry-yuCLNpDu.js → review-telemetry-lmK8HPLI.js} +4 -5
- package/dist/{runtime-5WG8rRgg.js → runtime-Bhk5L_SN.js} +1 -1
- package/dist/runtime.js +1 -1
- package/dist/server/desktop-host.js +34 -48
- package/dist/{server-discovery-Dj_xSDSa.js → server-discovery-D-2vz5gG.js} +2 -3
- package/dist/sharing/index.d.ts +51 -144
- package/dist/sharing/index.js +2 -2
- package/dist/{src-BJ_MeEmN.js → src-Bew3mW9I.js} +1 -1
- package/dist/{src-BTCRHmRM.js → src-Y30gweiK.js} +7 -1
- package/dist/{stored-document-migration-fQWLDqDx.js → stored-document-migration-CZe65mkx.js} +20 -6
- package/dist/{thread-state-BburMvgn.js → thread-state-XgVKaQ3-.js} +1 -1
- package/dist/{tool-failure-BuvwfVeF.js → tool-failure-Bi_-Zck-.js} +2 -2
- package/instructions/animation.md +18 -68
- package/instructions/authoring.md +1 -1
- package/package.json +5 -5
- package/src/review-api/README.md +5 -5
- package/src/review-api/ask-history.ts +3 -13
- package/src/review-api/authoring-tools.ts +2 -2
- package/src/review-api/blocks/animation.ts +50 -0
- package/src/review-api/http.ts +213 -383
- package/src/review-api/local-data.ts +24 -53
- package/src/review-api/review-progress.ts +1 -5
- package/src/review-api/store.ts +95 -16
- package/src/review-api/workspaces.ts +17 -48
- package/src/review-checkout-paths.ts +2 -5
- package/src/review-head-checkout.ts +3 -14
- package/src/server/background-server.ts +4 -2
- package/src/server/desktop-host.ts +17 -9
- package/src/server/desktop-server.ts +4 -6
- package/src/server/json-review-reporting.ts +4 -23
- package/src/server/review-gateway-pushes.ts +1 -10
- package/src/server/review-server-core.ts +8 -13
- package/src/sharing/client.ts +86 -2
- package/src/sharing/host.ts +111 -88
- package/src/sharing/import.ts +173 -710
- package/src/sharing/index.ts +1 -7
- package/src/sharing/repository.ts +18 -49
- package/dist/agent-cli-BDcF54b3.js +0 -2
- package/dist/profile-BLToeYh6.js +0 -2
- package/dist/review-home-paths-CjHB5c8m.js +0 -39
- package/src/sharing/routes.ts +0 -35
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
import { b as resolveRepoContext, d as git, r as defaultBranch, w as runVcs } from "./src-
|
|
1
|
+
import { b as resolveRepoContext, d as git, r as defaultBranch, w as runVcs } from "./src-Y30gweiK.js";
|
|
2
2
|
import { c as jsonString, m as isStringValue, n as isJsonObject, p as isObjectValue, u as parseJsonText } from "./src-X9phtB2j.js";
|
|
3
|
-
import { _ as
|
|
4
|
-
import { d as invalidateStructuralComparisons, f as diffrExecutable, i as inspectSnapshot, m as readGitHubPullRequests, p as diffrMissingError, r as commandSchema } from "./local-data-
|
|
5
|
-
import { I as decodeStructuralDiffEvent, N as reviewDiffrLoginsSchema, O as ReviewFeedbackContactSchema, P as reviewDiffrSummarizerInputSchema, a as parseReviewVerbRequest, c as boardIconKind, i as parseReviewDesktopVerbResult, j as ReviewOnboardingRunRequestSchema, k as ReviewFeedbackSchema, l as boardTitle, m as REVIEW_CLIENT_REMOTE, p as REVIEW_CLIENT_HEADER, y as REVIEW_HOST_HEADER } from "./src-
|
|
6
|
-
import {
|
|
7
|
-
import { _ as scopedCoverage, s as formatAnchor, u as selectionKey } from "./lens-selection-
|
|
8
|
-
import {
|
|
3
|
+
import { _ as parseShareLink, a as readShareRepository, c as exportShare, d as lensReport, f as progressUpdateSchema, g as readBoundedStream, h as StreamLimitError, i as forgetSharedCommits, l as validateShareSources, m as uncategorizedReport, n as shareKey, o as ShareAuthError, p as reviewProgress, s as ShareClient, t as importShare, u as legacyModeSchema, v as shareIdSchema } from "./import-FOpJL22V.js";
|
|
4
|
+
import { d as invalidateStructuralComparisons, f as diffrExecutable, i as inspectSnapshot, m as readGitHubPullRequests, p as diffrMissingError, r as commandSchema } from "./local-data-BhNZ1Yep.js";
|
|
5
|
+
import { I as decodeStructuralDiffEvent, N as reviewDiffrLoginsSchema, O as ReviewFeedbackContactSchema, P as reviewDiffrSummarizerInputSchema, a as parseReviewVerbRequest, c as boardIconKind, i as parseReviewDesktopVerbResult, j as ReviewOnboardingRunRequestSchema, k as ReviewFeedbackSchema, l as boardTitle, m as REVIEW_CLIENT_REMOTE, p as REVIEW_CLIENT_HEADER, y as REVIEW_HOST_HEADER } from "./src-Bew3mW9I.js";
|
|
6
|
+
import { B as TraceStorageDeniedError, D as listReviewTraceSessions, I as isTraceStorageConfigured, O as loadReviewAgentTrace, R as resolveTraceStorage, T as traceMachineEnabled, at as readStoreAuth, et as shellQuote, it as clearStoreAuth, ot as runStoreLogin, rt as DEFAULT_STORE_ORIGIN, z as selectTraceStorage } from "./review-home-paths-LdGS4SpR.js";
|
|
7
|
+
import { _ as scopedCoverage, s as formatAnchor, u as selectionKey } from "./lens-selection-B_LTVyTB.js";
|
|
8
|
+
import { K as selectionReferences, M as elements, O as boardRepositoryId, Z as stepSources, f as sourceBranchName, l as pullRequestKey, p as pullRequestProvider, w as anchorPins } from "./stored-document-migration-CZe65mkx.js";
|
|
9
9
|
import { t as ReviewInputError } from "./input-error-OLgB_h31.js";
|
|
10
10
|
import { A as processStartIdentity, L as writePrivateJsonAtomic, N as devReviewHome, h as TraceConfigurationError, i as isS3MockMode, j as withFileLock } from "./s3-config-CjcLyFV5.js";
|
|
11
11
|
import { t as errorMessage } from "./error-message-OtiDonty.js";
|
|
12
|
-
import { i as readReviewPackageVersion, n as readBuildCommit, t as findReviewPackageRoot } from "./package-paths-
|
|
13
|
-
import "./
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { t as
|
|
17
|
-
import {
|
|
18
|
-
import { a as
|
|
19
|
-
import { a as
|
|
20
|
-
import { a as headlessServerOwner, c as stopBackgroundServer, o as recordedBackgroundServer } from "./background-server-DlgbnDVt.js";
|
|
12
|
+
import { i as readReviewPackageVersion, n as readBuildCommit, t as findReviewPackageRoot } from "./package-paths-Cg6fnaGp.js";
|
|
13
|
+
import { _ as reviewInstanceIdentity, n as desktopOwnsHome, o as reviewServerDiscoveryPath, p as desktopUsesHome, r as headlessServerLockPath, t as DESKTOP_TAKEOVER_SIGNAL } from "./server-discovery-D-2vz5gG.js";
|
|
14
|
+
import { c as askPicksSchema, d as selectionMarkdown, l as askQuestionSchema, n as askAgentIds, r as askChoiceKinds, s as askPermissionsSchema, t as applyAskChange, u as AgentSelectionSchema } from "./thread-state-XgVKaQ3-.js";
|
|
15
|
+
import { t as openReviewProfile } from "./profile-DnwIJvlh.js";
|
|
16
|
+
import { c as REVIEW_APP_SESSION_ID_HEADER, d as sanitizeUiTelemetryEvent, f as cleanTelemetryText, o as reviewRequestOrigin, r as REVIEW_PERSON_HEADER, s as BUNDLE_FRAME_PATTERN, t as ASK_THREAD_ENV, u as isReportableCleanedMessage } from "./request-origin-DEQd09Db.js";
|
|
17
|
+
import { a as defaultAskPermissions, i as askAgents, l as launchAskAgent, n as askAgentSettings, o as detectAskAgents, r as askAgentTakesMcp, t as fuzzyRank } from "./fuzzy-match-CTvayutE.js";
|
|
18
|
+
import { a as inspectQuerySchema, i as renderInstructions, o as queryAnchor, r as instructionsQuerySchema, s as readQuerySchemas, t as authoringTools } from "./authoring-tools-B-OyXmtR.js";
|
|
19
|
+
import { a as headlessServerOwner, c as stopBackgroundServer, o as recordedBackgroundServer } from "./background-server-CesuMV6N.js";
|
|
21
20
|
import crypto$1, { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
22
21
|
import { z } from "zod";
|
|
23
22
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
@@ -2610,18 +2609,30 @@ const publishSchema = z.strictObject({
|
|
|
2610
2609
|
requestId: z.uuid().optional()
|
|
2611
2610
|
});
|
|
2612
2611
|
/** Mounted behind local host authentication. Account credentials never enter the renderer. */
|
|
2613
|
-
function mountSharingHost(app, store, data,
|
|
2612
|
+
function mountSharingHost(app, store, data, options = {}) {
|
|
2614
2613
|
const startLogin = options.login ?? runStoreLogin;
|
|
2615
2614
|
let login = { pending: false };
|
|
2616
|
-
|
|
2615
|
+
let warmedAt = 0;
|
|
2616
|
+
const readAccount = async () => {
|
|
2617
2617
|
const account = await readStoreAuth();
|
|
2618
|
-
|
|
2618
|
+
if (account && Date.now() - warmedAt > 6e4) {
|
|
2619
|
+
warmedAt = Date.now();
|
|
2620
|
+
new ShareClient(account.origin, account.token, options.fetch).warm().catch(() => {});
|
|
2621
|
+
}
|
|
2622
|
+
return {
|
|
2619
2623
|
account: account ? {
|
|
2620
2624
|
login: account.login,
|
|
2621
|
-
origin: account.origin
|
|
2625
|
+
origin: account.origin,
|
|
2626
|
+
email: account.email,
|
|
2627
|
+
githubLogin: account.githubLogin
|
|
2622
2628
|
} : null,
|
|
2623
2629
|
...login
|
|
2624
|
-
}
|
|
2630
|
+
};
|
|
2631
|
+
};
|
|
2632
|
+
app.get("/sharing/account", async (context) => context.json(await readAccount()));
|
|
2633
|
+
app.post("/sharing/logout", async (context) => {
|
|
2634
|
+
await clearStoreAuth();
|
|
2635
|
+
return context.json(await readAccount());
|
|
2625
2636
|
});
|
|
2626
2637
|
app.post("/sharing/login", async (context) => {
|
|
2627
2638
|
if (!login.pending) {
|
|
@@ -2654,52 +2665,61 @@ function mountSharingHost(app, store, data, shared, options = {}) {
|
|
|
2654
2665
|
});
|
|
2655
2666
|
mountSharingPublisher(app, store, data, options);
|
|
2656
2667
|
const imports = /* @__PURE__ */ new Map();
|
|
2668
|
+
let importing = Promise.resolve();
|
|
2657
2669
|
app.get("/sharing/import/:id", (context) => {
|
|
2658
2670
|
const id = context.req.param("id");
|
|
2659
|
-
const status =
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
...status
|
|
2671
|
+
const { reviewId = id, ...status } = imports.get(id) ?? {
|
|
2672
|
+
stage: "error",
|
|
2673
|
+
error: "Shared review is not available."
|
|
2663
2674
|
};
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2675
|
+
return context.json({
|
|
2676
|
+
reviewId,
|
|
2677
|
+
...status,
|
|
2678
|
+
...status.stage === "ready" && { title: store.read(reviewId).title }
|
|
2667
2679
|
});
|
|
2668
|
-
return context.json(result);
|
|
2669
2680
|
});
|
|
2670
2681
|
app.post("/sharing/import", async (context) => {
|
|
2671
2682
|
const { url } = z.strictObject({ url: z.string().max(2048) }).parse(await readBoundedRequestJson(context.req.raw));
|
|
2672
2683
|
const parsed = parseShareLink(url);
|
|
2673
2684
|
const account = await readStoreAuth();
|
|
2674
2685
|
if (parsed.origin !== DEFAULT_STORE_ORIGIN && parsed.origin !== account?.origin) throw new ReviewInputError("This share uses an untrusted service. Sign in to that service before opening its links.", 400);
|
|
2675
|
-
const id =
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
const
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2686
|
+
const id = shareKey(parsed.origin, parsed.capability);
|
|
2687
|
+
const known = imports.get(id)?.stage;
|
|
2688
|
+
if (!known || known === "ready" || known === "error") {
|
|
2689
|
+
const copy = store.copyOf(id);
|
|
2690
|
+
const status = copy ? {
|
|
2691
|
+
stage: "ready",
|
|
2692
|
+
reviewId: copy
|
|
2693
|
+
} : { stage: "downloading" };
|
|
2694
|
+
imports.set(id, status);
|
|
2695
|
+
if (!copy) importing = importing.then(async () => {
|
|
2683
2696
|
const { bundle, attribution } = await new ShareClient(parsed.origin).download(parsed.capability);
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2697
|
+
status.reviewId = await importShare({
|
|
2698
|
+
store,
|
|
2699
|
+
data,
|
|
2700
|
+
fetchRepository: options.fetchRepository,
|
|
2701
|
+
cloneRepository: options.cloneRepository,
|
|
2702
|
+
onStage: (stage) => {
|
|
2703
|
+
status.stage = stage;
|
|
2704
|
+
}
|
|
2705
|
+
}, id, bundle, attribution);
|
|
2706
|
+
status.stage = "ready";
|
|
2707
|
+
}).catch((error) => {
|
|
2708
|
+
status.stage = "error";
|
|
2709
|
+
status.error = error instanceof ReviewInputError ? error.message : "This share is unavailable, revoked, or needs a newer Whiteboard version.";
|
|
2710
|
+
});
|
|
2690
2711
|
}
|
|
2712
|
+
const { reviewId: _reviewId, ...status } = imports.get(id);
|
|
2691
2713
|
return context.json({
|
|
2692
2714
|
reviewId: id,
|
|
2693
|
-
...
|
|
2715
|
+
...status
|
|
2694
2716
|
}, 202);
|
|
2695
2717
|
});
|
|
2696
2718
|
}
|
|
2697
2719
|
/** Publishing needs only an authored store, never Desktop or recipient workspaces. */
|
|
2698
2720
|
function mountSharingPublisher(app, store, data, options = {}) {
|
|
2699
|
-
const verifyRepository = options.verifyRepository ?? verifyShareRepository;
|
|
2700
2721
|
app.post("/sharing/publish", async (context) => {
|
|
2701
2722
|
const input = publishSchema.parse(await readBoundedRequestJson(context.req.raw));
|
|
2702
|
-
if (input.reviewId.startsWith("shared-")) throw new ReviewInputError("Only the authoring review can be shared.", 409);
|
|
2703
2723
|
const snapshot = store.read(input.reviewId, input.version);
|
|
2704
2724
|
if (snapshot.target?.kind === "worktree") throw new ReviewInputError("Pin this review to commits before sharing it.");
|
|
2705
2725
|
validateShareSources(snapshot);
|
|
@@ -2707,18 +2727,7 @@ function mountSharingPublisher(app, store, data, options = {}) {
|
|
|
2707
2727
|
if (!account) throw new ReviewInputError("Set DEV_REVIEW_SHARE_TOKEN for CI, or run whiteboard login before sharing.", 409);
|
|
2708
2728
|
const repositoryId = snapshot.pins?.repositoryId ?? snapshot.target?.repositoryId;
|
|
2709
2729
|
const root = repositoryId ? store.repositoryPath(repositoryId) : void 0;
|
|
2710
|
-
const
|
|
2711
|
-
const commits = referenceCommits(snapshot);
|
|
2712
|
-
const repository = (async () => {
|
|
2713
|
-
if (!root) return void 0;
|
|
2714
|
-
try {
|
|
2715
|
-
const repository = await readRepository(root);
|
|
2716
|
-
if (snapshot.pins || commits.length) await verifyRepository(root, snapshot.pins, commits);
|
|
2717
|
-
return repository;
|
|
2718
|
-
} catch {
|
|
2719
|
-
return;
|
|
2720
|
-
}
|
|
2721
|
-
})();
|
|
2730
|
+
const repository = root ? (options.readRepository ?? readShareRepository)(root).catch(() => void 0) : void 0;
|
|
2722
2731
|
const bundle = await exportShare({
|
|
2723
2732
|
store,
|
|
2724
2733
|
data,
|
|
@@ -2762,32 +2771,6 @@ function mountSharingPublisher(app, store, data, options = {}) {
|
|
|
2762
2771
|
});
|
|
2763
2772
|
}
|
|
2764
2773
|
//#endregion
|
|
2765
|
-
//#region src/sharing/routes.ts
|
|
2766
|
-
/** Snapshot-backed reads used by the same HTTP routes as local reviews. */
|
|
2767
|
-
var SharedReviewData = class {
|
|
2768
|
-
store;
|
|
2769
|
-
constructor(store) {
|
|
2770
|
-
this.store = store;
|
|
2771
|
-
}
|
|
2772
|
-
map(id, resourceId) {
|
|
2773
|
-
const { maps } = this.store.get(id);
|
|
2774
|
-
if (!Object.hasOwn(maps, resourceId)) throw new ReviewInputError("Map is not included in this share.", 404);
|
|
2775
|
-
return maps[resourceId];
|
|
2776
|
-
}
|
|
2777
|
-
async resource(id, resourceId) {
|
|
2778
|
-
const { bundle } = this.store.get(id);
|
|
2779
|
-
if (Object.hasOwn(bundle.images, resourceId)) return {
|
|
2780
|
-
data: Buffer.from(bundle.images[resourceId].png, "base64"),
|
|
2781
|
-
mimeType: "image/png"
|
|
2782
|
-
};
|
|
2783
|
-
if (Object.hasOwn(bundle.traces, resourceId)) return {
|
|
2784
|
-
data: Buffer.from(JSON.stringify(bundle.traces[resourceId])),
|
|
2785
|
-
mimeType: "application/json"
|
|
2786
|
-
};
|
|
2787
|
-
throw new ReviewInputError("Resource is not included in this share.", 404);
|
|
2788
|
-
}
|
|
2789
|
-
};
|
|
2790
|
-
//#endregion
|
|
2791
2774
|
//#region src/review-api/anchor-quotes.ts
|
|
2792
2775
|
const QUOTE_LIMIT = 20;
|
|
2793
2776
|
const clip = (line) => line.trim() === "" ? "(blank line)" : line.length > 120 ? `${line.slice(0, 119)}…` : line;
|
|
@@ -3494,7 +3477,7 @@ const PERSON_EDIT_MAX_BYTES = 16777216;
|
|
|
3494
3477
|
/** A request the gateway forwarded from another machine. */
|
|
3495
3478
|
const remoteCaller = (context) => context.req.header(REVIEW_CLIENT_HEADER) === REVIEW_CLIENT_REMOTE;
|
|
3496
3479
|
/** Both hosts mount this behind their token authentication. */
|
|
3497
|
-
function createReviewApi(store, data, open,
|
|
3480
|
+
function createReviewApi(store, data, open, sharing = false, capabilities = () => ({
|
|
3498
3481
|
desktopAvailable: Boolean(open),
|
|
3499
3482
|
softwareMapEnabled: false
|
|
3500
3483
|
}), traceEnabled = async () => false, status = () => ({}), hooks = {}, ask, animationsEnabled = () => false) {
|
|
@@ -3513,38 +3496,12 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
3513
3496
|
if (context.req.method === "GET" && !context.req.query("version")) await store.refreshWorktrees();
|
|
3514
3497
|
await next();
|
|
3515
3498
|
});
|
|
3516
|
-
const
|
|
3517
|
-
|
|
3518
|
-
const assertWritable = (id) => {
|
|
3519
|
-
if (isShared(id)) shared?.assertWritable(id);
|
|
3520
|
-
else store.assertWritable(id);
|
|
3521
|
-
};
|
|
3522
|
-
const reviewAccess = (access) => async (context, next) => {
|
|
3523
|
-
const id = context.req.param("id");
|
|
3524
|
-
if (access !== "read") assertWritable(id);
|
|
3525
|
-
if (access === "edit" && isShared(id)) throw new ReviewInputError("Shared reviews are read-only.", 409);
|
|
3499
|
+
const writable = async (context, next) => {
|
|
3500
|
+
store.assertWritable(context.req.param("id"));
|
|
3526
3501
|
await next();
|
|
3527
3502
|
};
|
|
3528
|
-
|
|
3529
|
-
const
|
|
3530
|
-
const id = context.req.param("id");
|
|
3531
|
-
if (!id || !isShared(id)) return next();
|
|
3532
|
-
const query = readQuerySchemas.get.parse({ version: context.req.query("version") });
|
|
3533
|
-
readReview(id, query.version);
|
|
3534
|
-
return next();
|
|
3535
|
-
};
|
|
3536
|
-
app.use("/:id", sharedGuard);
|
|
3537
|
-
app.use("/:id/*", sharedGuard);
|
|
3538
|
-
if (shared && data) {
|
|
3539
|
-
shared.connect(store, data);
|
|
3540
|
-
mountSharingHost(app, store, data, shared, hooks.sharing);
|
|
3541
|
-
}
|
|
3542
|
-
const readReview = (id, version) => {
|
|
3543
|
-
if (!id.startsWith("shared-")) return store.read(id, version);
|
|
3544
|
-
const snapshot = shared?.get(id).snapshot;
|
|
3545
|
-
if (!snapshot || version !== void 0 && version !== snapshot.version) throw new ReviewInputError("Shared review version is unavailable.", 404);
|
|
3546
|
-
return snapshot;
|
|
3547
|
-
};
|
|
3503
|
+
if (sharing && data) mountSharingHost(app, store, data, hooks.sharing);
|
|
3504
|
+
const readReview = (id, version) => store.read(id, version);
|
|
3548
3505
|
/** Adds a PR board's state, as this host last read it from GitHub. */
|
|
3549
3506
|
const withPullRequestState = (board) => {
|
|
3550
3507
|
const state = data?.pullRequestState(board.origin?.pullRequestUrl ?? board.pullRequestUrl);
|
|
@@ -3553,11 +3510,11 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
3553
3510
|
pullRequestState: state
|
|
3554
3511
|
} : board;
|
|
3555
3512
|
};
|
|
3556
|
-
const catalog = () =>
|
|
3513
|
+
const catalog = () => store.list().map(withPullRequestState);
|
|
3557
3514
|
/** Where a board sits among its project's, and its PR's facts, for the
|
|
3558
3515
|
* board's header. */
|
|
3559
3516
|
const placeOf = (id) => {
|
|
3560
|
-
if (
|
|
3517
|
+
if (!store.has(id)) return { siblings: [] };
|
|
3561
3518
|
const { board, parent, siblings, children } = store.place(id);
|
|
3562
3519
|
const url = board.origin?.pullRequestUrl;
|
|
3563
3520
|
const state = data?.pullRequestState(url);
|
|
@@ -3614,7 +3571,7 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
3614
3571
|
}
|
|
3615
3572
|
return context.json(await reviewProgress(store, data, snapshot, context.req.raw.signal));
|
|
3616
3573
|
});
|
|
3617
|
-
app.post("/:id/progress",
|
|
3574
|
+
app.post("/:id/progress", writable, async (context) => {
|
|
3618
3575
|
if (!data) throw new ReviewInputError("Source data is unavailable.", 409);
|
|
3619
3576
|
const input = progressUpdateSchema.parse(await readBoundedRequestJson(context.req.raw));
|
|
3620
3577
|
const id = context.req.param("id");
|
|
@@ -3655,16 +3612,13 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
3655
3612
|
app.get("/:id/activity", (context) => {
|
|
3656
3613
|
const id = context.req.param("id");
|
|
3657
3614
|
readReview(id);
|
|
3658
|
-
return context.json(
|
|
3659
|
-
workingCount: 0,
|
|
3660
|
-
expiresAt: null
|
|
3661
|
-
} : store.activity.read(id));
|
|
3615
|
+
return context.json(store.activity.read(id));
|
|
3662
3616
|
});
|
|
3663
3617
|
for (const action of [
|
|
3664
3618
|
"begin",
|
|
3665
3619
|
"update",
|
|
3666
3620
|
"end"
|
|
3667
|
-
]) app.post(`/:id/activity/${action}`,
|
|
3621
|
+
]) app.post(`/:id/activity/${action}`, writable, async (context) => {
|
|
3668
3622
|
const input = await readBoundedRequestJson(context.req.raw);
|
|
3669
3623
|
const id = context.req.param("id");
|
|
3670
3624
|
store.assertExists(id);
|
|
@@ -3694,13 +3648,13 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
3694
3648
|
let sentList;
|
|
3695
3649
|
const linksRevision = /* @__PURE__ */ new Map();
|
|
3696
3650
|
const linksKey = (id) => {
|
|
3697
|
-
if (!data ||
|
|
3651
|
+
if (!data || !store.has(id)) return "";
|
|
3698
3652
|
const { outgoing, backlinks } = store.links(id);
|
|
3699
3653
|
return JSON.stringify([...outgoing, ...backlinks].map((link) => link.pullRequestUrl && data.pullRequestState(link.pullRequestUrl, { seen: false })));
|
|
3700
3654
|
};
|
|
3701
3655
|
const linksKeys = new Map([...reviewIds].map((reviewId) => [reviewId, linksKey(reviewId)]));
|
|
3702
3656
|
const placeKey = (id) => {
|
|
3703
|
-
const project =
|
|
3657
|
+
const project = store.summary(id)?.project;
|
|
3704
3658
|
const branches = project ? store.listProject(project.id).filter(({ origin }) => origin?.branch).map(({ reviewId, origin, trashedAt }) => [
|
|
3705
3659
|
reviewId,
|
|
3706
3660
|
origin,
|
|
@@ -3800,9 +3754,6 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
3800
3754
|
}
|
|
3801
3755
|
if (marked) notify();
|
|
3802
3756
|
}) ?? (() => {}),
|
|
3803
|
-
shared?.subscribe(() => {
|
|
3804
|
-
if (markLists()) notify();
|
|
3805
|
-
}) ?? (() => {}),
|
|
3806
3757
|
store.subscribeCatalog(() => {
|
|
3807
3758
|
const marked = refreshPlaces();
|
|
3808
3759
|
if (markLists() || marked) notify();
|
|
@@ -3820,7 +3771,7 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
3820
3771
|
});
|
|
3821
3772
|
let environmentIssues;
|
|
3822
3773
|
try {
|
|
3823
|
-
if (review.target?.kind === "commits" && review.pins) data?.workspaces.
|
|
3774
|
+
if (review.target?.kind === "commits" && review.pins) data?.workspaces.source(review.reviewId, review.pins).catch(() => {});
|
|
3824
3775
|
environmentIssues = data?.currentEnvironmentIssues(review);
|
|
3825
3776
|
} catch (error) {
|
|
3826
3777
|
environmentIssues = [{ message: `Could not check language checkouts: ${errorMessage(error)}. Recheck with review_environment.` }];
|
|
@@ -3848,12 +3799,10 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
3848
3799
|
};
|
|
3849
3800
|
}
|
|
3850
3801
|
};
|
|
3851
|
-
app.post("/:id/open",
|
|
3852
|
-
const id = context.req.param("id");
|
|
3853
|
-
if (isShared(id)) await shared?.assertReady(id);
|
|
3802
|
+
app.post("/:id/open", writable, async (context) => {
|
|
3854
3803
|
return context.json({
|
|
3855
3804
|
ok: true,
|
|
3856
|
-
...await openReview(readReview(id))
|
|
3805
|
+
...await openReview(readReview(context.req.param("id")))
|
|
3857
3806
|
});
|
|
3858
3807
|
});
|
|
3859
3808
|
if (data) {
|
|
@@ -3880,9 +3829,8 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
3880
3829
|
}, result.status);
|
|
3881
3830
|
return context.json(result);
|
|
3882
3831
|
});
|
|
3883
|
-
app.post("/:id/navigator",
|
|
3884
|
-
const input = readQuerySchemas.file.extend({
|
|
3885
|
-
side: z.enum(["base", "head"]).default("head"),
|
|
3832
|
+
app.post("/:id/navigator", writable, async (context) => {
|
|
3833
|
+
const input = readQuerySchemas.file.omit({ side: true }).extend({
|
|
3886
3834
|
file: z.string().min(1).optional(),
|
|
3887
3835
|
empty: z.literal("true").optional()
|
|
3888
3836
|
}).parse(context.req.query());
|
|
@@ -3908,7 +3856,6 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
3908
3856
|
app.get("/:id/maps/:resourceId", async (context) => {
|
|
3909
3857
|
const query = readQuerySchemas.maps.parse(context.req.query());
|
|
3910
3858
|
const id = context.req.param("id");
|
|
3911
|
-
if (id && isShared(id)) return context.json(sharedData.map(id, z.string().parse(context.req.param("resourceId"))));
|
|
3912
3859
|
return context.json(await data.map(await data.sourcePins(readReview(id, query.version)), z.string().parse(context.req.param("resourceId"))));
|
|
3913
3860
|
});
|
|
3914
3861
|
app.post("/repositories", async (context) => {
|
|
@@ -3928,10 +3875,7 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
3928
3875
|
app.get("/:id/resources/:resourceId", async (context) => {
|
|
3929
3876
|
const id = context.req.param("id");
|
|
3930
3877
|
const snapshot = readReview(id);
|
|
3931
|
-
const resource =
|
|
3932
|
-
...await sharedData.resource(id, z.string().parse(context.req.param("resourceId"))),
|
|
3933
|
-
repositoryId: snapshot.pins?.repositoryId ?? ""
|
|
3934
|
-
} : store.resource(z.string().parse(context.req.param("resourceId")));
|
|
3878
|
+
const resource = store.resource(z.string().parse(context.req.param("resourceId")));
|
|
3935
3879
|
if (snapshot.pins && resource.repositoryId !== snapshot.pins.repositoryId) throw new ReviewInputError("Resource is outside this repository.", 404);
|
|
3936
3880
|
return new Response(Buffer.from(resource.data), { headers: {
|
|
3937
3881
|
"content-type": resource.mimeType,
|
|
@@ -3940,14 +3884,13 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
3940
3884
|
});
|
|
3941
3885
|
app.get("/:id/language-context", async (context) => {
|
|
3942
3886
|
const input = readQuerySchemas.maps.extend({
|
|
3943
|
-
side: z.enum(["base", "head"]).default("head"),
|
|
3944
3887
|
commit: z.string().optional(),
|
|
3945
3888
|
repositoryId: z.string().optional(),
|
|
3946
3889
|
head: z.string().optional(),
|
|
3947
3890
|
base: z.string().optional()
|
|
3948
3891
|
}).parse(context.req.query());
|
|
3949
3892
|
const snapshot = readReview(context.req.param("id"), input.version);
|
|
3950
|
-
const environment = await data.languageEnvironment(snapshot, input.
|
|
3893
|
+
const environment = await data.languageEnvironment(snapshot, input.commit, false, queryAnchor(input));
|
|
3951
3894
|
if (context.req.header("x-review-client") !== "remote") return context.json(environment);
|
|
3952
3895
|
const { rootPath, ...rest } = environment;
|
|
3953
3896
|
return context.json({
|
|
@@ -3956,7 +3899,7 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
3956
3899
|
serverId: store.serverId()
|
|
3957
3900
|
});
|
|
3958
3901
|
});
|
|
3959
|
-
app.post("/:id/environment",
|
|
3902
|
+
app.post("/:id/environment", writable, async (context) => {
|
|
3960
3903
|
const input = z.strictObject({ retry: z.boolean().optional() }).parse(await readBoundedRequestJson(context.req.raw));
|
|
3961
3904
|
return context.json({ issues: await data.environmentIssues(readReview(context.req.param("id")), input.retry) });
|
|
3962
3905
|
});
|
|
@@ -3969,7 +3912,7 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
3969
3912
|
readReview(context.req.param("id"));
|
|
3970
3913
|
return context.json(data.workspaces.list(context.req.param("id")));
|
|
3971
3914
|
});
|
|
3972
|
-
app.post("/:id/workspaces/:workspaceId/retry",
|
|
3915
|
+
app.post("/:id/workspaces/:workspaceId/retry", writable, async (context) => {
|
|
3973
3916
|
return context.json(await data.workspaces.retry(context.req.param("id"), context.req.param("workspaceId")));
|
|
3974
3917
|
});
|
|
3975
3918
|
app.get("/:id/file", async (context) => {
|
|
@@ -4041,7 +3984,7 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
4041
3984
|
return context.json(await data.commits((await data.resolveSource(readReview(context.req.param("id"), input.version))).pins));
|
|
4042
3985
|
});
|
|
4043
3986
|
}
|
|
4044
|
-
app.post("/:id/copy-context",
|
|
3987
|
+
app.post("/:id/copy-context", async (context) => {
|
|
4045
3988
|
const query = readQuerySchemas.get.pick({ version: true }).extend({ mode: legacyModeSchema }).parse(context.req.query());
|
|
4046
3989
|
const selection = AgentSelectionSchema.parse(await readBoundedRequestJson(context.req.raw));
|
|
4047
3990
|
return context.json({ text: await selectionContext(context.req.param("id"), selection, query.version) });
|
|
@@ -4083,7 +4026,7 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
4083
4026
|
].join("\n");
|
|
4084
4027
|
}
|
|
4085
4028
|
if (ask && data) {
|
|
4086
|
-
const projectOf = (reviewId) =>
|
|
4029
|
+
const projectOf = (reviewId) => store.has(reviewId) ? store.projectOf(reviewId) : void 0;
|
|
4087
4030
|
const readThread = (reviewId, threadId) => {
|
|
4088
4031
|
const thread = ask.threads.get(threadId);
|
|
4089
4032
|
if (!thread) throw new ReviewInputError("This conversation has ended.", 404);
|
|
@@ -4179,7 +4122,7 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
4179
4122
|
const files = fuzzyRank(query, await mentionableFiles(cwd), (file) => [file, file.slice(file.lastIndexOf("/") + 1)]);
|
|
4180
4123
|
return context.json({ paths: files.slice(0, MENTION_LIMIT) });
|
|
4181
4124
|
});
|
|
4182
|
-
app.post("/:id/ask",
|
|
4125
|
+
app.post("/:id/ask", writable, async (context) => {
|
|
4183
4126
|
const reviewId = context.req.param("id");
|
|
4184
4127
|
const { version } = readQuerySchemas.get.pick({ version: true }).parse(context.req.query());
|
|
4185
4128
|
const input = askStartSchema.parse(await readBoundedRequestJson(context.req.raw, ASK_REQUEST_MAX_BYTES));
|
|
@@ -4190,7 +4133,7 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
4190
4133
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4191
4134
|
const permissions = input.permissions ?? defaultAskPermissions(input.agent);
|
|
4192
4135
|
const initialContext = await askContext(id, input.agent, snapshot, checkout, input.selection, version);
|
|
4193
|
-
assertWritable(reviewId);
|
|
4136
|
+
store.assertWritable(reviewId);
|
|
4194
4137
|
store.askHistory.markViewed(id, createdAt);
|
|
4195
4138
|
const thread = ask.threads.open({
|
|
4196
4139
|
id,
|
|
@@ -4308,7 +4251,7 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
4308
4251
|
board: reviewId
|
|
4309
4252
|
});
|
|
4310
4253
|
});
|
|
4311
|
-
app.post("/:id/ask/watch",
|
|
4254
|
+
app.post("/:id/ask/watch", async (context) => {
|
|
4312
4255
|
const reviewId = context.req.param("id");
|
|
4313
4256
|
readReview(reviewId);
|
|
4314
4257
|
const { threads } = askWatchSchema.parse(await readBoundedRequestJson(context.req.raw));
|
|
@@ -4343,7 +4286,7 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
4343
4286
|
entries: record.entries ?? []
|
|
4344
4287
|
});
|
|
4345
4288
|
});
|
|
4346
|
-
app.post("/:id/ask/:threadId/open",
|
|
4289
|
+
app.post("/:id/ask/:threadId/open", writable, async (context) => {
|
|
4347
4290
|
const reviewId = context.req.param("id");
|
|
4348
4291
|
const threadId = context.req.param("threadId");
|
|
4349
4292
|
if (ask.threads.get(threadId)) return context.json({ threadId });
|
|
@@ -4355,7 +4298,7 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
4355
4298
|
const checkout = await data.agentCheckout(snapshot);
|
|
4356
4299
|
const target = record.selection.target;
|
|
4357
4300
|
const initialContext = await askContext(record.id, record.agent, snapshot, checkout, record.selection, record.version);
|
|
4358
|
-
assertWritable(reviewId);
|
|
4301
|
+
store.assertWritable(reviewId);
|
|
4359
4302
|
ask.threads.open({
|
|
4360
4303
|
id: record.id,
|
|
4361
4304
|
reviewId: anchor,
|
|
@@ -4377,7 +4320,7 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
4377
4320
|
});
|
|
4378
4321
|
return context.json({ threadId: record.id });
|
|
4379
4322
|
});
|
|
4380
|
-
app.post("/:id/ask/:threadId/prompt",
|
|
4323
|
+
app.post("/:id/ask/:threadId/prompt", writable, async (context) => {
|
|
4381
4324
|
const thread = readThread(context.req.param("id"), context.req.param("threadId"));
|
|
4382
4325
|
const { question } = askFollowUpSchema.parse(await readBoundedRequestJson(context.req.raw, ASK_REQUEST_MAX_BYTES));
|
|
4383
4326
|
const refusal = thread.askRefusal();
|
|
@@ -4385,13 +4328,13 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
4385
4328
|
thread.ask(question);
|
|
4386
4329
|
return context.json({ ok: true });
|
|
4387
4330
|
});
|
|
4388
|
-
app.post("/:id/ask/:threadId/permission",
|
|
4331
|
+
app.post("/:id/ask/:threadId/permission", writable, async (context) => {
|
|
4389
4332
|
const thread = readThread(context.req.param("id"), context.req.param("threadId"));
|
|
4390
4333
|
const decision = askDecisionSchema.parse(await readBoundedRequestJson(context.req.raw));
|
|
4391
4334
|
if (!thread.decide(decision.permissionId, decision.optionId)) throw new ReviewInputError("This request was already answered.", 409);
|
|
4392
4335
|
return context.json({ ok: true });
|
|
4393
4336
|
});
|
|
4394
|
-
app.post("/:id/ask/:threadId/files",
|
|
4337
|
+
app.post("/:id/ask/:threadId/files", writable, async (context) => {
|
|
4395
4338
|
const thread = readThread(context.req.param("id"), context.req.param("threadId"));
|
|
4396
4339
|
const { paths } = askFilesSchema.parse(await readBoundedRequestJson(context.req.raw));
|
|
4397
4340
|
const { cwd, entries } = thread.read();
|
|
@@ -4402,7 +4345,7 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
4402
4345
|
file
|
|
4403
4346
|
})) });
|
|
4404
4347
|
});
|
|
4405
|
-
app.post("/:id/ask/:threadId/choice",
|
|
4348
|
+
app.post("/:id/ask/:threadId/choice", writable, async (context) => {
|
|
4406
4349
|
const thread = readThread(context.req.param("id"), context.req.param("threadId"));
|
|
4407
4350
|
const { kind, value } = askChoiceSchema.parse(await readBoundedRequestJson(context.req.raw));
|
|
4408
4351
|
if (thread.read().status !== "idle") throw new ReviewInputError("Settings can change once the agent finishes answering.", 409);
|
|
@@ -4413,7 +4356,7 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
4413
4356
|
}
|
|
4414
4357
|
return context.json({ ok: true });
|
|
4415
4358
|
});
|
|
4416
|
-
app.post("/:id/ask/:threadId/permissions",
|
|
4359
|
+
app.post("/:id/ask/:threadId/permissions", writable, async (context) => {
|
|
4417
4360
|
const thread = readThread(context.req.param("id"), context.req.param("threadId"));
|
|
4418
4361
|
const { permissions } = askPermitSchema.parse(await readBoundedRequestJson(context.req.raw));
|
|
4419
4362
|
if (thread.read().status !== "idle") throw new ReviewInputError("Settings can change once the agent finishes answering.", 409);
|
|
@@ -4424,13 +4367,13 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
4424
4367
|
}
|
|
4425
4368
|
return context.json({ ok: true });
|
|
4426
4369
|
});
|
|
4427
|
-
app.post("/:id/ask/:threadId/retry",
|
|
4370
|
+
app.post("/:id/ask/:threadId/retry", writable, (context) => {
|
|
4428
4371
|
const thread = readThread(context.req.param("id"), context.req.param("threadId"));
|
|
4429
4372
|
if (thread.read().status !== "failed") throw new ReviewInputError("Only a conversation that failed can try again.", 409);
|
|
4430
4373
|
thread.retry();
|
|
4431
4374
|
return context.json({ ok: true });
|
|
4432
4375
|
});
|
|
4433
|
-
app.post("/:id/ask/:threadId/cancel",
|
|
4376
|
+
app.post("/:id/ask/:threadId/cancel", async (context) => {
|
|
4434
4377
|
await readThread(context.req.param("id"), context.req.param("threadId")).cancel();
|
|
4435
4378
|
return context.json({ ok: true });
|
|
4436
4379
|
});
|
|
@@ -4440,12 +4383,12 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
4440
4383
|
store.askHistory.markViewed(threadId);
|
|
4441
4384
|
return context.json({ ok: true });
|
|
4442
4385
|
});
|
|
4443
|
-
app.post("/:id/ask/:threadId/close",
|
|
4386
|
+
app.post("/:id/ask/:threadId/close", (context) => {
|
|
4444
4387
|
readThread(context.req.param("id"), context.req.param("threadId"));
|
|
4445
4388
|
ask.threads.close(context.req.param("threadId"), !readReview(context.req.param("id")).trashedAt);
|
|
4446
4389
|
return context.json({ ok: true });
|
|
4447
4390
|
});
|
|
4448
|
-
app.delete("/:id/ask/:threadId",
|
|
4391
|
+
app.delete("/:id/ask/:threadId", writable, (context) => {
|
|
4449
4392
|
context.req.param("id");
|
|
4450
4393
|
const threadId = context.req.param("threadId");
|
|
4451
4394
|
if (!store.askHistory.get(threadId)) throw new ReviewInputError("This conversation was not found.", 404);
|
|
@@ -4456,14 +4399,14 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
4456
4399
|
}
|
|
4457
4400
|
app.get("/:id/place", (context) => {
|
|
4458
4401
|
const id = context.req.param("id");
|
|
4459
|
-
|
|
4402
|
+
store.assertExists(id);
|
|
4460
4403
|
return context.json(placeOf(id));
|
|
4461
4404
|
});
|
|
4462
4405
|
app.get("/:id/stack", async (context) => {
|
|
4463
4406
|
const query = readQuerySchemas.get.parse(context.req.query());
|
|
4464
4407
|
const id = context.req.param("id");
|
|
4465
4408
|
let snapshot = readReview(id, query.version);
|
|
4466
|
-
if (
|
|
4409
|
+
if (!snapshot.pins) return context.json({ layers: [] });
|
|
4467
4410
|
if (data) snapshot = await data.discoverPullRequest(snapshot);
|
|
4468
4411
|
const repositoryPath = store.repositories().find((repository) => repository.id === snapshot.pins.repositoryId)?.path;
|
|
4469
4412
|
const layers = await resolveReviewStackLayers(snapshot, store.list(), { repositoryPath });
|
|
@@ -4481,10 +4424,6 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
4481
4424
|
});
|
|
4482
4425
|
app.get("/:id/project", (context) => {
|
|
4483
4426
|
const id = context.req.param("id");
|
|
4484
|
-
if (isShared(id)) return context.json({
|
|
4485
|
-
project: null,
|
|
4486
|
-
boards: []
|
|
4487
|
-
});
|
|
4488
4427
|
const project = store.summary(id)?.project ?? null;
|
|
4489
4428
|
return context.json({
|
|
4490
4429
|
project,
|
|
@@ -4493,15 +4432,6 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
4493
4432
|
});
|
|
4494
4433
|
app.get("/:id/links", (context) => {
|
|
4495
4434
|
const id = context.req.param("id");
|
|
4496
|
-
if (isShared(id)) return context.json({
|
|
4497
|
-
outgoing: boardLinks(id, readReview(id).document).map(({ from, to }) => ({
|
|
4498
|
-
from,
|
|
4499
|
-
to,
|
|
4500
|
-
missing: true,
|
|
4501
|
-
elsewhere: true
|
|
4502
|
-
})),
|
|
4503
|
-
backlinks: []
|
|
4504
|
-
});
|
|
4505
4435
|
const { version } = readQuerySchemas.get.pick({ version: true }).parse({ version: context.req.query("version") });
|
|
4506
4436
|
const { outgoing, backlinks } = store.links(id, version);
|
|
4507
4437
|
return context.json({
|
|
@@ -4511,7 +4441,6 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
4511
4441
|
});
|
|
4512
4442
|
app.get("/:id/links/peek", (context) => {
|
|
4513
4443
|
const id = context.req.param("id");
|
|
4514
|
-
if (isShared(id)) return context.json({});
|
|
4515
4444
|
const { version } = readQuerySchemas.get.pick({ version: true }).parse({ version: context.req.query("version") });
|
|
4516
4445
|
const board = context.req.query("board");
|
|
4517
4446
|
const block = context.req.query("block");
|
|
@@ -4522,15 +4451,7 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
4522
4451
|
}, version));
|
|
4523
4452
|
});
|
|
4524
4453
|
app.get("/:id/history", (context) => {
|
|
4525
|
-
|
|
4526
|
-
if (!isShared(id)) return context.json(store.history(id));
|
|
4527
|
-
const snapshot = readReview(id);
|
|
4528
|
-
return context.json([{
|
|
4529
|
-
version: snapshot.version,
|
|
4530
|
-
title: snapshot.title,
|
|
4531
|
-
createdAt: snapshot.createdAt,
|
|
4532
|
-
author: "agent"
|
|
4533
|
-
}]);
|
|
4454
|
+
return context.json(store.history(context.req.param("id")));
|
|
4534
4455
|
});
|
|
4535
4456
|
/** A board's relations as session_list reports them: only those it has. */
|
|
4536
4457
|
const listedRelations = ({ parentId, children, dependsOn }) => {
|
|
@@ -4557,15 +4478,15 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
4557
4478
|
const query = inspectQuerySchema.parse(context.req.query());
|
|
4558
4479
|
const id = context.req.param("id");
|
|
4559
4480
|
const snapshot = readReview(id, query.version);
|
|
4560
|
-
return context.json(query.format === "text" ? documentText(snapshot, query.targetId, Boolean(query.full),
|
|
4481
|
+
return context.json(query.format === "text" ? documentText(snapshot, query.targetId, Boolean(query.full), relatedBoards(id)) : query.targetId !== void 0 ? inspectSnapshot(snapshot, query.targetId) : {
|
|
4561
4482
|
...query.full ? snapshot : inspectSnapshot(snapshot),
|
|
4562
|
-
|
|
4483
|
+
...listedRelations(store.relations(id))
|
|
4563
4484
|
});
|
|
4564
4485
|
});
|
|
4565
4486
|
app.get("/:id", async (context) => {
|
|
4566
4487
|
const query = readQuerySchemas.get.parse(context.req.query());
|
|
4567
4488
|
let snapshot = { ...readReview(context.req.param("id"), query.version) };
|
|
4568
|
-
if (data && query.full && query.version === void 0
|
|
4489
|
+
if (data && query.full && query.version === void 0) snapshot = await data.discoverPullRequest(snapshot);
|
|
4569
4490
|
if (data && query.full) try {
|
|
4570
4491
|
const pins = await data.sourcePins(snapshot);
|
|
4571
4492
|
if (pins) snapshot.pins = pins;
|
|
@@ -4597,35 +4518,16 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
4597
4518
|
const target = "targetId" in edit ? elements(readReview(reviewId).document).find((element) => element.id === edit.targetId) : void 0;
|
|
4598
4519
|
if (incoming.some((element) => element.type === "animation") || target?.type === "animation") throw new ReviewInputError("Animation authoring is disabled. Enable Animations in Settings under Experimental Features to edit animations. Existing animations can still be viewed.", 409);
|
|
4599
4520
|
}
|
|
4600
|
-
const command = sharedCommandSchema.safeParse(input);
|
|
4601
|
-
if (command.success && command.data.operation.reviewId?.startsWith("shared-")) {
|
|
4602
|
-
const parsed = commandSchema.parse(input);
|
|
4603
|
-
if (shared && parsed.operation.type === "delete") {
|
|
4604
|
-
if (!shared.get(parsed.operation.reviewId).snapshot.trashedAt) throw new ReviewInputError("Move this whiteboard to Trash before deleting it.", 409);
|
|
4605
|
-
await shared.removeLocal(parsed.operation.reviewId);
|
|
4606
|
-
return context.json({
|
|
4607
|
-
reviewId: parsed.operation.reviewId,
|
|
4608
|
-
version: 0,
|
|
4609
|
-
deleted: true
|
|
4610
|
-
});
|
|
4611
|
-
}
|
|
4612
|
-
if (shared && (parsed.operation.type === "attention" || parsed.operation.type === "lifecycle")) {
|
|
4613
|
-
if (parsed.operation.type === "lifecycle") await shared.setLifecycle(parsed.operation.reviewId, parsed.operation.state);
|
|
4614
|
-
else await shared.setAttention(parsed.operation.reviewId);
|
|
4615
|
-
return context.json({
|
|
4616
|
-
reviewId: parsed.operation.reviewId,
|
|
4617
|
-
version: shared.get(parsed.operation.reviewId).snapshot.version,
|
|
4618
|
-
attention: true
|
|
4619
|
-
});
|
|
4620
|
-
}
|
|
4621
|
-
throw new ReviewInputError("Shared reviews are read-only.", 409);
|
|
4622
|
-
}
|
|
4623
4521
|
const threadId = remoteCaller(context) ? void 0 : context.req.header("x-review-thread")?.trim() || void 0;
|
|
4624
4522
|
const author = !remoteCaller(context) && context.req.header("x-review-person") !== void 0 ? { kind: "person" } : {
|
|
4625
4523
|
kind: "agent",
|
|
4626
4524
|
...threadId && { threadId }
|
|
4627
4525
|
};
|
|
4526
|
+
const copy = input.operation.type === "delete" && store.has(input.operation.reviewId) ? store.read(input.operation.reviewId) : void 0;
|
|
4628
4527
|
const result = await store.execute(input, void 0, author);
|
|
4528
|
+
const key = copy?.shared?.key;
|
|
4529
|
+
const kept = copy && boardRepositoryId(copy);
|
|
4530
|
+
if (result.deleted && key && kept) await Promise.resolve().then(() => forgetSharedCommits(store.repositoryPath(kept), key)).catch((error) => console.error("Could not drop a copy's kept commits:", error));
|
|
4629
4531
|
if (input.operation.type === "edit" && data && !result.deleted) {
|
|
4630
4532
|
const { quotes, unquoted } = await anchorQuotes(result.version > 0 ? store.read(result.reviewId, result.version - 1) : void 0, store.read(result.reviewId, result.version), async (pins, side, file) => (await data.file(pins, side, file)).text);
|
|
4631
4533
|
return context.json({
|
|
@@ -4947,7 +4849,7 @@ function answerErrorsAsJson(app) {
|
|
|
4947
4849
|
});
|
|
4948
4850
|
}
|
|
4949
4851
|
function createWhiteboardCore(input) {
|
|
4950
|
-
const { store, data
|
|
4852
|
+
const { store, data } = input.profile;
|
|
4951
4853
|
const app = createReviewServerApp({
|
|
4952
4854
|
token: input.token,
|
|
4953
4855
|
instanceId: input.instanceId,
|
|
@@ -4964,22 +4866,20 @@ function createWhiteboardCore(input) {
|
|
|
4964
4866
|
takesMcp: async (agent) => askAgentTakesMcp(agent, await ask.env),
|
|
4965
4867
|
...ask.tools
|
|
4966
4868
|
});
|
|
4967
|
-
const closeDeletedThreads = () => askThreads?.closeDeletedReviews((id) =>
|
|
4869
|
+
const closeDeletedThreads = () => askThreads?.closeDeletedReviews((id) => !store.has(id) || Boolean(store.read(id).trashedAt));
|
|
4968
4870
|
const stopLocal = askThreads && store.subscribe((result) => {
|
|
4969
4871
|
if (result.deleted || result.lifecycle) closeDeletedThreads();
|
|
4970
4872
|
});
|
|
4971
|
-
const
|
|
4972
|
-
const api = createReviewApi(store, data, callbacks.open, shared, callbacks.capabilities, () => traceMachineEnabled(), input.status, input.hooks, askThreads && {
|
|
4873
|
+
const api = createReviewApi(store, data, callbacks.open, input.sharing, callbacks.capabilities, () => traceMachineEnabled(), input.status, input.hooks, askThreads && {
|
|
4973
4874
|
threads: askThreads,
|
|
4974
4875
|
agents: async () => detectAskAgents(await ask?.env)
|
|
4975
4876
|
}, input.animations);
|
|
4976
|
-
if (!
|
|
4877
|
+
if (!input.sharing) mountSharingPublisher(api, store, data);
|
|
4977
4878
|
return {
|
|
4978
4879
|
app,
|
|
4979
4880
|
api,
|
|
4980
4881
|
close: () => {
|
|
4981
4882
|
stopLocal?.();
|
|
4982
|
-
stopShared?.();
|
|
4983
4883
|
closeDeletedThreads();
|
|
4984
4884
|
askThreads?.closeAll();
|
|
4985
4885
|
}
|