@dev.fast/whiteboard 0.3.4 → 0.3.5-preview.20261020.130

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.
Files changed (115) hide show
  1. package/dist/{account-alias-CprZojXd.js → account-alias-CMyXCuuq.js} +13 -8
  2. package/dist/{agent-cli-CThN7Q59.js → agent-cli-CahKfDT0.js} +15 -10
  3. package/dist/agent-cli-CvYV2R6c.js +2 -0
  4. package/dist/{agent-client-BOOi7EUR.js → agent-client-D2RmE9NL.js} +13 -3
  5. package/dist/{authoring-tools-BNwuMnz6.js → authoring-tools-BLhYKrNN.js} +34 -27
  6. package/dist/{background-server-DLSDogkI.js → background-server-CFUU4VtN.js} +1 -1
  7. package/dist/{background-server-CkvxA-6O.js → background-server-k4K_Hvh1.js} +5 -5
  8. package/dist/build-info.json +1 -1
  9. package/dist/{cli-R4yfa5DT.js → cli-BUVSMGud.js} +1 -1
  10. package/dist/{cli-runner-Cuc9FSzu.js → cli-runner-C7W6VA94.js} +26 -26
  11. package/dist/cli.js +4 -3
  12. package/dist/{client-BN_FDxFr.js → client-B0f4EJ7v.js} +253 -47
  13. package/dist/{fuzzy-match-BO9bK37N.js → fuzzy-match-BbaX-dGh.js} +6 -4
  14. package/dist/{headless-host-Cog6SpS9.js → headless-host-C7xYMe74.js} +513 -140
  15. package/dist/{headless-host-CVBOQyRS.js → headless-host-cYdlRYPB.js} +1 -1
  16. package/dist/lens-selection-CAtsGaym.js +214 -0
  17. package/dist/{local-data-D_9tvdsp.js → local-data-DrNSaiS5.js} +2416 -320
  18. package/dist/{mcp-D1hziANa.js → mcp-yXnjUkOV.js} +6 -10
  19. package/dist/{package-paths-C--__jEv.js → package-paths-BWxO-UEL.js} +1 -1
  20. package/dist/{profile-DokFw782.js → profile-BlqZlCPZ.js} +20 -8
  21. package/dist/profile-CGxNfeYQ.js +2 -0
  22. package/dist/{remote-attach-CEJ-kvDY.js → remote-attach-CZTrtWIk.js} +4 -4
  23. package/dist/{remote-extensions-Blcjr9Ze.js → remote-extensions-CNXwqK0D.js} +3 -3
  24. package/dist/{remote-extensions-GN8Gf_qG.js → remote-extensions-VP-kfq0C.js} +1 -1
  25. package/dist/{remote-language-server-BTKBQ7x4.js → remote-language-server-BiPzol99.js} +5 -5
  26. package/dist/{remote-uninstall-DW7Gdryh.js → remote-uninstall-CFTkoioA.js} +6 -6
  27. package/dist/{request-origin-Zcn_CjX4.js → request-origin--8lLCclv.js} +55 -14
  28. package/dist/{review-app-launcher-CkwLclzR.js → review-app-launcher-KA2_mOeo.js} +2 -2
  29. package/dist/{review-home-paths-j2BRAaNv.js → review-home-paths-D8AoCdd2.js} +19 -17
  30. package/dist/{review-telemetry-BLNwYnLV.js → review-telemetry-B2JniTIs.js} +5 -5
  31. package/dist/runtime-Bj2tD33R.js +27 -0
  32. package/dist/runtime.d.ts +1 -1
  33. package/dist/runtime.js +1 -1
  34. package/dist/{s3-DtJFWC0G.js → s3-CsG2EWED.js} +1 -1
  35. package/dist/{s3-config-BTO12tCC.js → s3-config-CjcLyFV5.js} +4 -2
  36. package/dist/{s3-config-CSy3fx8H.js → s3-config-zz4GWh2T.js} +1 -1
  37. package/dist/server/desktop-host.js +29 -76
  38. package/dist/{server-discovery-Bey8IqXH.js → server-discovery-CRXG48Uz.js} +3 -3
  39. package/dist/sharing/index.d.ts +484 -70
  40. package/dist/sharing/index.js +1 -1
  41. package/dist/{src-DsM3jO8G.js → src-CyYCvVHx.js} +90 -17
  42. package/dist/{src-BMPuxWv4.js → src-WPaQn75m.js} +208 -73
  43. package/dist/{stored-document-migration-CChxtFAy.js → stored-document-migration-B_BijGHF.js} +270 -269
  44. package/dist/{thread-state-5pYr6_zM.js → thread-state-D6MlnGv7.js} +7 -2
  45. package/dist/{tool-failure-C9MpbXJJ.js → tool-failure-_makh_Sr.js} +10 -3
  46. package/instructions/authoring.md +18 -5
  47. package/package.json +6 -6
  48. package/src/ask/agents.ts +13 -1
  49. package/src/ask/checkout-files.ts +2 -5
  50. package/src/ask/thread-state.ts +4 -0
  51. package/src/ask/thread.ts +16 -0
  52. package/src/ask/threads.ts +24 -3
  53. package/src/cli-install.ts +13 -2
  54. package/src/cli-runner.ts +4 -1
  55. package/src/cli.ts +4 -1
  56. package/src/diff-selection-migration.ts +48 -34
  57. package/src/heading-anchors.ts +42 -0
  58. package/src/lens-selection.ts +38 -2
  59. package/src/review-api/README.md +52 -13
  60. package/src/review-api/activity.ts +1 -4
  61. package/src/review-api/agent-cli.ts +9 -1
  62. package/src/review-api/anchor-quotes.ts +14 -7
  63. package/src/review-api/ask-history.ts +137 -51
  64. package/src/review-api/authoring-tools.ts +45 -30
  65. package/src/review-api/blocks/definition.ts +1 -1
  66. package/src/review-api/blocks/markdown.ts +2 -2
  67. package/src/review-api/board-order.ts +144 -0
  68. package/src/review-api/checkout-groups.ts +560 -0
  69. package/src/review-api/document-headings.ts +58 -27
  70. package/src/review-api/document-text.ts +31 -2
  71. package/src/review-api/document.ts +281 -34
  72. package/src/review-api/foreign-references.ts +328 -0
  73. package/src/review-api/github-provider.ts +51 -13
  74. package/src/review-api/http.ts +702 -123
  75. package/src/review-api/instructions.ts +0 -19
  76. package/src/review-api/link-preview.ts +113 -0
  77. package/src/review-api/local-data.ts +310 -46
  78. package/src/review-api/mcp.ts +4 -12
  79. package/src/review-api/onboarding.ts +1 -1
  80. package/src/review-api/profile.ts +37 -6
  81. package/src/review-api/public-tools.ts +24 -2
  82. package/src/review-api/pull-request.ts +82 -49
  83. package/src/review-api/request-origin.ts +10 -0
  84. package/src/review-api/review-progress.ts +61 -27
  85. package/src/review-api/scratchpad-plan-upgrade.ts +250 -0
  86. package/src/review-api/store-migrations.ts +357 -0
  87. package/src/review-api/store-schema.ts +38 -29
  88. package/src/review-api/store.ts +2144 -480
  89. package/src/review-api/worktree-events.ts +3 -5
  90. package/src/review-api/worktree-source.ts +3 -7
  91. package/src/review-api/worktree-structural.integration.ts +72 -0
  92. package/src/review-stack.ts +15 -23
  93. package/src/runtime.ts +4 -30
  94. package/src/server/desktop-host.ts +6 -1
  95. package/src/server/desktop-server.ts +1 -31
  96. package/src/server/headless-host.ts +0 -2
  97. package/src/server/hono-http.ts +2 -1
  98. package/src/server/legacy-tutorial-cleanup.ts +2 -3
  99. package/src/server/review-gateway-list.ts +3 -5
  100. package/src/server/review-gateway-memory.ts +1 -1
  101. package/src/server/review-lifecycle-telemetry.ts +2 -2
  102. package/src/server/review-server-core.ts +1 -5
  103. package/src/server/structural-comparisons.ts +47 -0
  104. package/src/sharing/export.ts +36 -7
  105. package/src/sharing/host.ts +34 -14
  106. package/src/sharing/import.ts +156 -24
  107. package/src/sharing/repository.ts +128 -20
  108. package/src/startup-trace.ts +3 -3
  109. package/src/stored-document-migration.ts +110 -19
  110. package/src/ui-telemetry-events.ts +44 -14
  111. package/dist/agent-cli-C6SPSII0.js +0 -2
  112. package/dist/profile-CYPmvBoA.js +0 -2
  113. package/dist/runtime-CKiWhGrf.js +0 -52
  114. package/instructions/scratchpad.md +0 -23
  115. package/src/review-preferences.ts +0 -88
@@ -1,2 +1,2 @@
1
- import { i as withHeadlessServerLock, n as runHeadlessServer, r as takeOverServerHome, t as HeadlessServerBusyError } from "./headless-host-Cog6SpS9.js";
1
+ import { i as withHeadlessServerLock, n as runHeadlessServer, r as takeOverServerHome, t as HeadlessServerBusyError } from "./headless-host-C7xYMe74.js";
2
2
  export { HeadlessServerBusyError, runHeadlessServer, takeOverServerHome, withHeadlessServerLock };
@@ -0,0 +1,214 @@
1
+ import "./src-CyYCvVHx.js";
2
+ import { z } from "zod";
3
+ //#region src/viewed-coverage.ts
4
+ const coverageSchema = z.object({
5
+ base: z.array(z.tuple([z.number().int().nonnegative(), z.number().int().nonnegative()])),
6
+ head: z.array(z.tuple([z.number().int().nonnegative(), z.number().int().nonnegative()]))
7
+ });
8
+ const emptyCoverage = () => ({
9
+ base: [],
10
+ head: []
11
+ });
12
+ function unionIntervals(ranges) {
13
+ const result = [];
14
+ for (const [start, end] of [...ranges].sort((a, b) => a[0] - b[0])) {
15
+ if (end <= start) continue;
16
+ const last = result.at(-1);
17
+ if (last && start <= last[1]) last[1] = Math.max(last[1], end);
18
+ else result.push([start, end]);
19
+ }
20
+ return result;
21
+ }
22
+ function intersectIntervals(left, right) {
23
+ const result = [];
24
+ const a = unionIntervals(left), b = unionIntervals(right);
25
+ let i = 0, j = 0;
26
+ while (i < a.length && j < b.length) {
27
+ const start = Math.max(a[i][0], b[j][0]), end = Math.min(a[i][1], b[j][1]);
28
+ if (start < end) result.push([start, end]);
29
+ if (a[i][1] < b[j][1]) i++;
30
+ else j++;
31
+ }
32
+ return result;
33
+ }
34
+ function subtractIntervals(left, right) {
35
+ const result = [];
36
+ const removed = unionIntervals(right);
37
+ for (const [start, end] of unionIntervals(left)) {
38
+ let cursor = start;
39
+ for (const [from, to] of removed) {
40
+ if (to <= cursor) continue;
41
+ if (from >= end) break;
42
+ if (from > cursor) result.push([cursor, from]);
43
+ cursor = Math.min(end, Math.max(cursor, to));
44
+ }
45
+ if (cursor < end) result.push([cursor, end]);
46
+ }
47
+ return result;
48
+ }
49
+ function updateCoverage(current, scope, viewed) {
50
+ const apply = (side) => viewed ? unionIntervals([...current[side], ...scope[side]]) : subtractIntervals(current[side], scope[side]);
51
+ return {
52
+ base: apply("base"),
53
+ head: apply("head")
54
+ };
55
+ }
56
+ function scopedCoverage(file, sources) {
57
+ if (!sources) return file.changed;
58
+ const side = (side) => intersectIntervals(file.changed[side], sources.flatMap((source) => source.side === side && source.file === (side === "base" ? file.previousPath ?? file.path : file.path) ? [[source.fromLine - 1, source.toLine]] : []));
59
+ return {
60
+ base: side("base"),
61
+ head: side("head")
62
+ };
63
+ }
64
+ function coverageSources(file, coverage = file.viewed) {
65
+ return ["base", "head"].flatMap((side) => coverage[side].map(([start, end]) => ({
66
+ side,
67
+ file: side === "base" ? file.previousPath ?? file.path : file.path,
68
+ fromLine: start + 1,
69
+ toLine: end
70
+ })));
71
+ }
72
+ //#endregion
73
+ //#region src/lens-selection.ts
74
+ const ANCHOR_FORMS = "\"head/path#L10-L24\" or \"base/path#L7\" (one side, lines 10–24 or line 7); across sides, GitHub diff style \"diff/path#L84-R90\" (L = base line, R = head line)";
75
+ const sameSideAnchor = /^(head|base)\/(.+)#L(\d+)(?:-L(\d+))?$/;
76
+ const crossSideAnchor = /^diff\/(.+)#([LR])(\d+)-([LR])(\d+)$/;
77
+ const commitLinkAnchor = /^([0-9a-f]{7,40})\/(.+#L\d+(?:-L\d+)?)$/i;
78
+ /** A source link's commit form, "<sha>/path#L10-L24" (without its
79
+ * `whiteboard:source/` prefix): lines of that commit of the board's own
80
+ * repository, read as their head side. Undefined for any other form. */
81
+ function commitLinkTarget(target) {
82
+ const match = commitLinkAnchor.exec(target);
83
+ return match ? {
84
+ commit: match[1].toLowerCase(),
85
+ anchor: `head/${match[2]}`
86
+ } : void 0;
87
+ }
88
+ /** An anchor's selection, as markdown source links write it too (without
89
+ * their `whiteboard:source/` prefix). Undefined when it isn't one. */
90
+ function parseAnchor(text) {
91
+ const same = sameSideAnchor.exec(text);
92
+ if (same) {
93
+ const side = same[1] === "base" ? "base" : "head";
94
+ return {
95
+ file: same[2],
96
+ start: {
97
+ side,
98
+ line: Number(same[3])
99
+ },
100
+ end: {
101
+ side,
102
+ line: Number(same[4] ?? same[3])
103
+ }
104
+ };
105
+ }
106
+ const cross = crossSideAnchor.exec(text);
107
+ if (!cross || cross[2] === cross[4]) return void 0;
108
+ const side = (letter) => letter === "L" ? "base" : "head";
109
+ return {
110
+ file: cross[1],
111
+ start: {
112
+ side: side(cross[2]),
113
+ line: Number(cross[3])
114
+ },
115
+ end: {
116
+ side: side(cross[4]),
117
+ line: Number(cross[5])
118
+ }
119
+ };
120
+ }
121
+ /** Why a parsed selection can't be quoted, or undefined when it can. */
122
+ function selectionProblem(selection) {
123
+ if (selection.start.line < 1 || selection.end.line < 1) return "Source lines count from 1.";
124
+ if (selection.start.side === selection.end.side && selection.start.line > selection.end.line) return "Source range ends before it starts.";
125
+ if (selection.pins && selection.pins.base === void 0 && (selection.start.side === "base" || selection.end.side === "base")) return "A base-side anchor needs base pins.";
126
+ }
127
+ const anchorSchema = z.string({ error: `Expected a source anchor: ${ANCHOR_FORMS}.` }).superRefine((text, context) => {
128
+ const selection = parseAnchor(text);
129
+ const problem = selection ? selectionProblem(selection) : `Use ${ANCHOR_FORMS} for a source anchor.`;
130
+ if (problem) context.addIssue({
131
+ code: "custom",
132
+ message: problem
133
+ });
134
+ }).describe("head/path#L10-L24, base/path#L7, or diff/path#L84-R90");
135
+ /** A stored anchor's selection, read at the pins of whatever holds it. */
136
+ function anchorSelection(anchor, pins) {
137
+ const selection = parseAnchor(anchor);
138
+ if (!selection) throw new Error(`Not a source anchor: ${anchor}`);
139
+ return pins ? {
140
+ ...selection,
141
+ pins
142
+ } : selection;
143
+ }
144
+ /** The anchor that writes a selection; its pins belong to its holder. */
145
+ function formatAnchor(selection) {
146
+ const { file, start, end } = selection;
147
+ if (start.side === end.side) return start.line === end.line ? `${start.side}/${file}#L${start.line}` : `${start.side}/${file}#L${start.line}-L${end.line}`;
148
+ const letter = (side) => side === "base" ? "L" : "R";
149
+ return `diff/${file}#${letter(start.side)}${start.line}-${letter(end.side)}${end.line}`;
150
+ }
151
+ /** Pins-less selections keep the key they always had. */
152
+ function selectionKey(source) {
153
+ return JSON.stringify([
154
+ source.file,
155
+ source.start.side,
156
+ source.start.line,
157
+ source.end.side,
158
+ source.end.line,
159
+ ...source.pins ? [sourcePinsKey(source.pins)] : []
160
+ ]);
161
+ }
162
+ function sourcePinsKey(pins) {
163
+ return `${pins.repositoryId}:${pins.base ?? ""}:${pins.head}`;
164
+ }
165
+ /** The comparison a source's pins name: head alone means head against
166
+ * itself. Reference coverage is grouped under this key on both sides. */
167
+ function comparisonKey(pins) {
168
+ return `${pins.repositoryId}:${pins.base ?? pins.head}:${pins.head}`;
169
+ }
170
+ /** Navigation/quote anchors only; never use these as lens coverage. */
171
+ function sourceAnchors(source) {
172
+ return ["head", "base"].flatMap((side) => {
173
+ const lines = [source.start, source.end].flatMap((endpoint) => endpoint.side === side ? [endpoint.line] : []);
174
+ if (!lines.length) return [];
175
+ const anchor = {
176
+ file: source.file,
177
+ side,
178
+ fromLine: Math.min(...lines),
179
+ toLine: Math.max(...lines)
180
+ };
181
+ if (source.pins) anchor.pins = source.pins;
182
+ return [anchor];
183
+ });
184
+ }
185
+ /** Why a selection cannot be resolved at its pins, as telemetry reports it. */
186
+ const SELECTION_UNAVAILABLE_REASONS = [
187
+ "missing_file",
188
+ "no_alignment",
189
+ "outside_lines",
190
+ "other"
191
+ ];
192
+ var SelectionUnavailableError = class extends Error {
193
+ reason;
194
+ constructor(reason, message) {
195
+ super(message);
196
+ this.reason = reason;
197
+ }
198
+ };
199
+ /** Resolve once against the renderer's rows. No matching or context expansion. */
200
+ function resolveDiffSelection(source, rows, file) {
201
+ const locate = (endpoint) => rows.findIndex((row) => row[endpoint.side === "base" ? 0 : 1] === endpoint.line - 1);
202
+ const start = locate(source.start);
203
+ const end = locate(source.end);
204
+ if (start < 0 || end < start) throw new SelectionUnavailableError("outside_lines", "Lens endpoints do not identify an ordered interval in this diff.");
205
+ const selected = rows.slice(start, end + 1);
206
+ return ["base", "head"].flatMap((side, index) => unionIntervals(selected.flatMap((row) => row[index] === null ? [] : [[row[index], row[index] + 1]])).map(([from, to]) => ({
207
+ file: side === "base" ? file.previousPath ?? file.path : file.path,
208
+ side,
209
+ fromLine: from + 1,
210
+ toLine: to
211
+ })));
212
+ }
213
+ //#endregion
214
+ export { scopedCoverage as _, commitLinkTarget as a, updateCoverage as b, parseAnchor as c, selectionProblem as d, sourceAnchors as f, intersectIntervals as g, emptyCoverage as h, anchorSelection as i, resolveDiffSelection as l, coverageSources as m, SelectionUnavailableError as n, comparisonKey as o, coverageSchema as p, anchorSchema as r, formatAnchor as s, SELECTION_UNAVAILABLE_REASONS as t, selectionKey as u, subtractIntervals as v, unionIntervals as y };