@shiyuphan/follow-me 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/cli.js +17 -3
- package/dist/src/comments.js +62 -9
- package/dist/src/evolve.js +145 -29
- package/dist/src/host.js +12 -3
- package/dist/src/plan.js +14 -0
- package/dist/src/prompt.js +100 -12
- package/dist/src/server.js +106 -29
- package/dist/src/session.js +23 -0
- package/dist/ui/dist/assets/{abnfDiagram-WEYOIA3C-BXkLs7mV.js → abnfDiagram-WEYOIA3C-8UsLPznO.js} +1 -1
- package/dist/ui/dist/assets/{arc-DNzjw7Ie.js → arc-vovjGalz.js} +1 -1
- package/dist/ui/dist/assets/{architecture-WOLXFQ4H-D66kgJJt.js → architecture-WOLXFQ4H-BBMK-PUu.js} +1 -1
- package/dist/ui/dist/assets/{architectureDiagram-ZHVYKT53-D8UWuhQr.js → architectureDiagram-ZHVYKT53-Bw_ehaQk.js} +1 -1
- package/dist/ui/dist/assets/{blockDiagram-RJAE7QA3-BLkmr62i.js → blockDiagram-RJAE7QA3-CAmD0wKf.js} +1 -1
- package/dist/ui/dist/assets/{c4Diagram-XDPPPE54-3rZPYwOc.js → c4Diagram-XDPPPE54-DCP-3zgt.js} +1 -1
- package/dist/ui/dist/assets/channel-B7CT_oIp.js +1 -0
- package/dist/ui/dist/assets/{chunk-2E7WHVMD-MMnvAgpB.js → chunk-2E7WHVMD-BiHSeJMu.js} +1 -1
- package/dist/ui/dist/assets/{chunk-4EMNKR2T-D9FGWA3l.js → chunk-4EMNKR2T-CR3lHKf_.js} +1 -1
- package/dist/ui/dist/assets/{chunk-55XCU76K-DuOUaV8F.js → chunk-55XCU76K-CtaoloTT.js} +1 -1
- package/dist/ui/dist/assets/{chunk-7S6XSTFO-p3YWPv0m.js → chunk-7S6XSTFO-eABdc7fu.js} +1 -1
- package/dist/ui/dist/assets/{chunk-AQDTSKZB-DWfKYjwk.js → chunk-AQDTSKZB-CPlbJWi-.js} +1 -1
- package/dist/ui/dist/assets/{chunk-DSNLSHJZ-C3CIwpv0.js → chunk-DSNLSHJZ-YiMuxsb-.js} +1 -1
- package/dist/ui/dist/assets/{chunk-HAGFOTED-Bwfl9gme.js → chunk-HAGFOTED-1VcdL78a.js} +1 -1
- package/dist/ui/dist/assets/{chunk-HNE4Q36P-0_oeU0le.js → chunk-HNE4Q36P-u-sr_0Qu.js} +1 -1
- package/dist/ui/dist/assets/{chunk-NQOKRVIF-z_LPPPx5.js → chunk-NQOKRVIF-C_QlWSze.js} +1 -1
- package/dist/ui/dist/assets/{chunk-UHW7PFBP-BH28V2yu.js → chunk-UHW7PFBP-CNuZhsbU.js} +1 -1
- package/dist/ui/dist/assets/{chunk-VQ5W62QI-BXDajDf7.js → chunk-VQ5W62QI-DAHWbLqU.js} +1 -1
- package/dist/ui/dist/assets/{chunk-WQQL4CDK-BphBlfKj.js → chunk-WQQL4CDK-DWQnxFCd.js} +1 -1
- package/dist/ui/dist/assets/{chunk-XXDRQBXY-BiCT5NwV.js → chunk-XXDRQBXY-B0lGgSOR.js} +1 -1
- package/dist/ui/dist/assets/{chunk-YZO67HFG-Bg5Pu8BX.js → chunk-YZO67HFG-BDw7efkN.js} +1 -1
- package/dist/ui/dist/assets/{chunk-ZAUX2LTX-C_Tgd8tB.js → chunk-ZAUX2LTX-B5wfHsZv.js} +1 -1
- package/dist/ui/dist/assets/{chunk-ZCHMQSOR-MBRcMi8-.js → chunk-ZCHMQSOR--rWtYtAG.js} +1 -1
- package/dist/ui/dist/assets/{classDiagram-v2-4MYWR3UA-1wyeCe5y.js → classDiagram-v2-4MYWR3UA-BKuQ_xoS.js} +1 -1
- package/dist/ui/dist/assets/{cose-bilkent-JH36ORCC-BtOYclF6.js → cose-bilkent-JH36ORCC-Dk5fIpU0.js} +1 -1
- package/dist/ui/dist/assets/{cynefin-EF2NZ3EQ-dJmoOG8g.js → cynefin-EF2NZ3EQ-DIykJb2g.js} +1 -1
- package/dist/ui/dist/assets/{cynefinDiagram-WF24UDRP-AloyqbEN.js → cynefinDiagram-WF24UDRP-Cg8tBqUb.js} +1 -1
- package/dist/ui/dist/assets/{dagre-NK4GIZVX-NCZhdnfb.js → dagre-NK4GIZVX-BC_tnnjz.js} +1 -1
- package/dist/ui/dist/assets/{diagram-CBK3MWTC-D8w7x5Gb.js → diagram-CBK3MWTC-B_MQGixU.js} +1 -1
- package/dist/ui/dist/assets/{diagram-I5XIIV2D-BUFnCGlp.js → diagram-I5XIIV2D-DO681pZ5.js} +1 -1
- package/dist/ui/dist/assets/{diagram-ODIL2UCW-BULmHKaW.js → diagram-ODIL2UCW-D14jLzU6.js} +1 -1
- package/dist/ui/dist/assets/{diagram-PFBEJUXE-B5MqFo0r.js → diagram-PFBEJUXE-cML48gUS.js} +1 -1
- package/dist/ui/dist/assets/{diagram-RJA3I4VV-BIkDLL8E.js → diagram-RJA3I4VV-DSoq8jFk.js} +1 -1
- package/dist/ui/dist/assets/{diagram-TYUNFSNR-Ca4gsQV8.js → diagram-TYUNFSNR-CaJ4pvnl.js} +1 -1
- package/dist/ui/dist/assets/{dist-G85JKY5k.js → dist-D3j-DODP.js} +1 -1
- package/dist/ui/dist/assets/{ebnfDiagram-V4P3TTPT-rVjcFFtb.js → ebnfDiagram-V4P3TTPT-CyRpjSix.js} +1 -1
- package/dist/ui/dist/assets/{elk-QONTBCTQ-BWPdvULh.js → elk-QONTBCTQ-ICJdzVFL.js} +1 -1
- package/dist/ui/dist/assets/{erDiagram-KYQIGQAA-BPxJJkRl.js → erDiagram-KYQIGQAA-B57hNTfw.js} +1 -1
- package/dist/ui/dist/assets/{eventmodeling-K75KTNOO-BSB9WYV3.js → eventmodeling-K75KTNOO-BG8tUVIQ.js} +1 -1
- package/dist/ui/dist/assets/flowDiagram-IUGLLWBU--HPNoVQJ.js +1 -0
- package/dist/ui/dist/assets/{ganttDiagram-R7GPNTJY-DKps530K.js → ganttDiagram-R7GPNTJY-Czt6Klik.js} +1 -1
- package/dist/ui/dist/assets/{gitGraph-VSP46ZUC-D1d4UAFV.js → gitGraph-VSP46ZUC-De_ZWJLj.js} +1 -1
- package/dist/ui/dist/assets/{gitGraphDiagram-PDYL7XHY-N55yl6hc.js → gitGraphDiagram-PDYL7XHY-BMCJoOnT.js} +1 -1
- package/dist/ui/dist/assets/index-CYKbk4QS.js +134 -0
- package/dist/ui/dist/assets/{info-OHQRW6UA-CgxE3gf9.js → info-OHQRW6UA-D75H9kUq.js} +1 -1
- package/dist/ui/dist/assets/{infoDiagram-MVDRKAX5-DOnUrnMf.js → infoDiagram-MVDRKAX5-Bsm_I9dt.js} +1 -1
- package/dist/ui/dist/assets/{ishikawaDiagram-HPEHV2GE-BIY0fFHB.js → ishikawaDiagram-HPEHV2GE-98xZAJ9y.js} +1 -1
- package/dist/ui/dist/assets/{journeyDiagram-BOSHW7O7-CqA2Ern0.js → journeyDiagram-BOSHW7O7-BWVGuc0P.js} +1 -1
- package/dist/ui/dist/assets/{kanban-definition-FNSA4HC5-vGrpQKIF.js → kanban-definition-FNSA4HC5-DgUE_KDd.js} +1 -1
- package/dist/ui/dist/assets/{line-Brzv3qA6.js → line-i__8Rvas.js} +1 -1
- package/dist/ui/dist/assets/{linear-D9uIlqyh.js → linear-BXKj0Fip.js} +1 -1
- package/dist/ui/dist/assets/{mermaid-parser.core-Bz9b-Thu.js → mermaid-parser.core-DxvaorTa.js} +3 -3
- package/dist/ui/dist/assets/{mermaid.core-BaZipu3b.js → mermaid.core-ujYTsRZz.js} +4 -4
- package/dist/ui/dist/assets/{mindmap-definition-6OY57UG3-D6aie7uH.js → mindmap-definition-6OY57UG3-B7QD6sjk.js} +1 -1
- package/dist/ui/dist/assets/{packet-JDAUHWVQ-28r3jVFY.js → packet-JDAUHWVQ-B6aIwfD1.js} +1 -1
- package/dist/ui/dist/assets/{pegDiagram-ECIUJNBX-CbGvD4qP.js → pegDiagram-ECIUJNBX-_RStHj-a.js} +1 -1
- package/dist/ui/dist/assets/{pie-XZMESJXO-DHpcGnZd.js → pie-XZMESJXO-CNLC-pTe.js} +1 -1
- package/dist/ui/dist/assets/{pieDiagram-GNMPY74T-DuhauwnY.js → pieDiagram-GNMPY74T-0uT7MT-u.js} +1 -1
- package/dist/ui/dist/assets/{prism-core-CbZMOvrb.js → prism-core-DtxziK1i.js} +1 -1
- package/dist/ui/dist/assets/{quadrantDiagram-D57K4MC3-BfyNmVca.js → quadrantDiagram-D57K4MC3-CTMKb5hl.js} +1 -1
- package/dist/ui/dist/assets/{radar-ABXABTNO-Xp1TYwaj.js → radar-ABXABTNO-D53h6I0N.js} +1 -1
- package/dist/ui/dist/assets/{railroad-I3PHUGI6-c5FY4wwa.js → railroad-I3PHUGI6-CwjhW4mc.js} +1 -1
- package/dist/ui/dist/assets/{railroad-abnf-LNEFI6M7-RDyWXqcL.js → railroad-abnf-LNEFI6M7-DDbQ3RmB.js} +1 -1
- package/dist/ui/dist/assets/{railroad-ebnf-DWYD2UWJ-CLD4jVou.js → railroad-ebnf-DWYD2UWJ-Am7YJAqO.js} +1 -1
- package/dist/ui/dist/assets/{railroad-peg-JR7BVNR7-17EYTA-w.js → railroad-peg-JR7BVNR7-Ci32KoVW.js} +1 -1
- package/dist/ui/dist/assets/{railroadDiagram-Y72NRBL7-C4p2wtKe.js → railroadDiagram-Y72NRBL7-BPU5A6XW.js} +1 -1
- package/dist/ui/dist/assets/{requirementDiagram-EQYSW5RA-DTYIFN8T.js → requirementDiagram-EQYSW5RA-_0Pq4QdV.js} +1 -1
- package/dist/ui/dist/assets/{sankeyDiagram-SY24JHO5-YDYhRyJU.js → sankeyDiagram-SY24JHO5-c9h-7uf8.js} +1 -1
- package/dist/ui/dist/assets/{sequenceDiagram-BLEHNHQU-Crvy6IlU.js → sequenceDiagram-BLEHNHQU-B9-S4Rc9.js} +1 -1
- package/dist/ui/dist/assets/{src-BPod-Ype.js → src-BZ3kG7lO.js} +1 -1
- package/dist/ui/dist/assets/{stateDiagram-v2-A6IESKWZ-BWr70YOQ.js → stateDiagram-v2-A6IESKWZ-py1smSen.js} +1 -1
- package/dist/ui/dist/assets/{swimlanes-B3ENRKFQ-DvbG4I9a.js → swimlanes-B3ENRKFQ-C1E90aH4.js} +1 -1
- package/dist/ui/dist/assets/swimlanesDiagram-AYQRV4AK-I98Q8AqP.js +8 -0
- package/dist/ui/dist/assets/{timeline-definition-JXYKGLGB-CR950Bzb.js → timeline-definition-JXYKGLGB-DNe1To6B.js} +1 -1
- package/dist/ui/dist/assets/{treeView-D4JQ5SDB-DSDDXGrk.js → treeView-D4JQ5SDB-D6MG89i6.js} +1 -1
- package/dist/ui/dist/assets/{treemap-SAJKECNS-Ct5w2_RR.js → treemap-SAJKECNS-CZpt7Mlh.js} +1 -1
- package/dist/ui/dist/assets/{usecaseDiagram-WPOLBNNX-_eP0371y.js → usecaseDiagram-WPOLBNNX-CKsv-03M.js} +1 -1
- package/dist/ui/dist/assets/{vennDiagram-Q3Y3IDCW-Cu-IA57L.js → vennDiagram-Q3Y3IDCW-DGJ1qlyJ.js} +1 -1
- package/dist/ui/dist/assets/{wardley-7MLQ67FV-r8yd6frN.js → wardley-7MLQ67FV-ClOzBemC.js} +1 -1
- package/dist/ui/dist/assets/{wardleyDiagram-IVAIDKWA-CBUUiRQm.js → wardleyDiagram-IVAIDKWA-C68ahPyF.js} +1 -1
- package/dist/ui/dist/assets/{xychartDiagram-4URNHDU4-DEVQjvgG.js → xychartDiagram-4URNHDU4-DWDamCoH.js} +1 -1
- package/dist/ui/dist/index.html +1 -1
- package/package.json +1 -1
- package/dist/ui/dist/assets/channel-B9JVdOBZ.js +0 -1
- package/dist/ui/dist/assets/flowDiagram-IUGLLWBU-N-Spyk2o.js +0 -1
- package/dist/ui/dist/assets/index-BKtWBS7Z.js +0 -134
- package/dist/ui/dist/assets/swimlanesDiagram-AYQRV4AK-D2wU-jW6.js +0 -8
package/dist/src/server.js
CHANGED
|
@@ -5,6 +5,7 @@ import { homedir } from "node:os";
|
|
|
5
5
|
import { basename, isAbsolute, join } from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
import { isReplyId, parseComment, parseDraft, parseNewDecision, parseNewReply, } from "./comments.js";
|
|
8
|
+
import { carryConcerns, carrySession } from "./evolve.js";
|
|
8
9
|
import { isConcernId, isPlanVersion } from "./plan.js";
|
|
9
10
|
import { renderReport, reportItems } from "./prompt.js";
|
|
10
11
|
import { isLockToken } from "./session.js";
|
|
@@ -88,6 +89,8 @@ export async function loadDraft(reviewsDir, version) {
|
|
|
88
89
|
resolved: [],
|
|
89
90
|
excluded: { comments: [], concerns: [] },
|
|
90
91
|
earlierReplies: [],
|
|
92
|
+
carried: null,
|
|
93
|
+
carriedConcerns: [],
|
|
91
94
|
};
|
|
92
95
|
}
|
|
93
96
|
throw error;
|
|
@@ -236,7 +239,7 @@ async function readUi(dir, name) {
|
|
|
236
239
|
}
|
|
237
240
|
const NOT_BUILT = `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="color-scheme" content="light dark" /><title>follow-me</title></head><body style="font-family: system-ui; max-width: 40rem; margin: 4rem auto; padding: 0 1rem"><h1>The review page is not built</h1><p>This follow-me runs from a checkout without <code>ui/dist</code>. Run <code>npm run build</code> (or <code>npm run ui:build</code>) in the checkout, then reload.</p></body></html>
|
|
238
241
|
`;
|
|
239
|
-
function viewOf(registration, loaded, draft) {
|
|
242
|
+
function viewOf(registration, loaded, draft, earlier = loaded.earlier) {
|
|
240
243
|
const { state, reviewsDir } = loaded;
|
|
241
244
|
return {
|
|
242
245
|
registration,
|
|
@@ -247,6 +250,8 @@ function viewOf(registration, loaded, draft) {
|
|
|
247
250
|
excludedComments: new Set(draft.excluded.comments),
|
|
248
251
|
excludedConcerns: new Set(draft.excluded.concerns),
|
|
249
252
|
earlierReplies: new Map(draft.earlierReplies.map((e) => [e.comment, e.replies])),
|
|
253
|
+
earlier: earlier === null ? null : earlier.comments,
|
|
254
|
+
earlierConcerns: earlier === null ? [] : earlier.concerns,
|
|
250
255
|
unitIds: new Set(state.units.map((u) => u.id)),
|
|
251
256
|
hunkRows: new Map(state.units.flatMap((u) => u.kind === "hunk" ? [[u.id, u.body.length]] : [])),
|
|
252
257
|
concernIds: new Set(state.commits.flatMap((c) => (c.concerns ?? []).map((k) => k.id))),
|
|
@@ -258,7 +263,7 @@ function withReplies(comment, replies) {
|
|
|
258
263
|
const { replies: _dropped, ...rest } = comment;
|
|
259
264
|
return replies === undefined || replies.length === 0 ? rest : { ...rest, replies };
|
|
260
265
|
}
|
|
261
|
-
/** A comment of
|
|
266
|
+
/** A comment of an earlier version with the replies it got during this one. */
|
|
262
267
|
function withEarlier(view, comment) {
|
|
263
268
|
const later = view.earlierReplies.get(comment.id) ?? [];
|
|
264
269
|
return later.length === 0
|
|
@@ -271,8 +276,39 @@ function previousOf(view) {
|
|
|
271
276
|
return null;
|
|
272
277
|
return { ...previous, comments: previous.comments.map((c) => withEarlier(view, c)) };
|
|
273
278
|
}
|
|
279
|
+
/** The session's earlier comments with this version's replies, or null outside a session. */
|
|
280
|
+
function sessionOf(view) {
|
|
281
|
+
return view.earlier === null
|
|
282
|
+
? null
|
|
283
|
+
: view.earlier.map((c) => ({ ...c, comment: withEarlier(view, c.comment) }));
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* What the page shows carried: the session's earlier comments, then those of the review before
|
|
287
|
+
* this version that the session does not hold (a review that ended before this one began).
|
|
288
|
+
*/
|
|
274
289
|
function carriedOf(view) {
|
|
275
|
-
|
|
290
|
+
const session = sessionOf(view) ?? [];
|
|
291
|
+
const held = new Set(session.map((c) => c.comment.id));
|
|
292
|
+
const before = view.loaded.carried
|
|
293
|
+
.filter((c) => !held.has(c.comment.id))
|
|
294
|
+
.map((c) => ({ ...c, comment: withEarlier(view, c.comment) }));
|
|
295
|
+
return [...session, ...before];
|
|
296
|
+
}
|
|
297
|
+
/** The session as stored beside this version: comments by id, concerns whole. */
|
|
298
|
+
function carriedRefs(view) {
|
|
299
|
+
if (view.earlier === null)
|
|
300
|
+
return {};
|
|
301
|
+
const carried = view.earlier.map(({ comment, ...at }) => ({ ...at, comment: comment.id }));
|
|
302
|
+
const concerns = view.earlierConcerns;
|
|
303
|
+
return { carried, ...(concerns.length === 0 ? {} : { carriedConcerns: [...concerns] }) };
|
|
304
|
+
}
|
|
305
|
+
/** A comment said on this version or carried into it, which replies and decisions may name. */
|
|
306
|
+
function findSaid(view, id) {
|
|
307
|
+
if (typeof id !== "string")
|
|
308
|
+
return undefined;
|
|
309
|
+
return (view.comments.get(id) ??
|
|
310
|
+
view.loaded.previous?.comments.find((c) => c.id === id) ??
|
|
311
|
+
view.earlier?.find((c) => c.comment.id === id)?.comment);
|
|
276
312
|
}
|
|
277
313
|
function earlierOf(view) {
|
|
278
314
|
return [...view.earlierReplies].map(([comment, replies]) => ({ comment, replies }));
|
|
@@ -382,6 +418,7 @@ function hostSession(id, registration, loaded, draft, load) {
|
|
|
382
418
|
...(resolved.length === 0 ? {} : { resolved }),
|
|
383
419
|
...(excluded === null ? {} : { excluded }),
|
|
384
420
|
...(earlierReplies.length === 0 ? {} : { earlierReplies }),
|
|
421
|
+
...carriedRefs(view),
|
|
385
422
|
}, null, 2);
|
|
386
423
|
const dir = view.loaded.reviewsDir;
|
|
387
424
|
writes = writes.then(async () => {
|
|
@@ -428,16 +465,19 @@ function hostSession(id, registration, loaded, draft, load) {
|
|
|
428
465
|
...(resolved.length === 0 ? {} : { resolved }),
|
|
429
466
|
...(excluded === null ? {} : { excluded }),
|
|
430
467
|
...(earlierReplies.length === 0 ? {} : { earlierReplies }),
|
|
468
|
+
...carriedRefs(view),
|
|
431
469
|
};
|
|
432
470
|
};
|
|
433
|
-
const
|
|
434
|
-
const
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
branch: state.anchor.branch,
|
|
471
|
+
const reportOptions = () => {
|
|
472
|
+
const comments = sessionOf(view);
|
|
473
|
+
return {
|
|
474
|
+
branch: view.loaded.state.anchor.branch,
|
|
438
475
|
responses: [],
|
|
439
|
-
|
|
476
|
+
...(comments === null ? {} : { earlier: { comments, concerns: view.earlierConcerns } }),
|
|
477
|
+
};
|
|
440
478
|
};
|
|
479
|
+
const unitsOf = () => new Map(view.loaded.state.units.map((u) => [u.id, u]));
|
|
480
|
+
const report = (finished) => renderReport(finished, view.loaded.state.commits, unitsOf(), reportOptions());
|
|
441
481
|
/** Writes reviews/vN.json and its report once, and removes the autosave. */
|
|
442
482
|
const writeReview = async (finished) => {
|
|
443
483
|
await writes;
|
|
@@ -504,19 +544,12 @@ function hostSession(id, registration, loaded, draft, load) {
|
|
|
504
544
|
return waitForEvents(since, timeoutMs, signal);
|
|
505
545
|
},
|
|
506
546
|
report: () => report(review()),
|
|
507
|
-
reportItems: () =>
|
|
508
|
-
const { state } = view.loaded;
|
|
509
|
-
const units = new Map(state.units.map((u) => [u.id, u]));
|
|
510
|
-
return reportItems(review(), state.commits, units, {
|
|
511
|
-
branch: state.anchor.branch,
|
|
512
|
-
responses: [],
|
|
513
|
-
});
|
|
514
|
-
},
|
|
547
|
+
reportItems: () => reportItems(review(), view.loaded.state.commits, unitsOf(), reportOptions()),
|
|
515
548
|
add: async (raw) => {
|
|
516
549
|
open();
|
|
517
550
|
if (!isRecord(raw))
|
|
518
551
|
throw new HttpError(400, "malformed comment");
|
|
519
|
-
const commentId = mintCommentId(new Set(view.comments.keys()));
|
|
552
|
+
const commentId = mintCommentId(new Set([...view.comments.keys(), ...(view.earlier ?? []).map((c) => c.comment.id)]));
|
|
520
553
|
const comment = withReplies(accept(parseComment({ ...raw, id: commentId, createdAt: new Date().toISOString() })), undefined);
|
|
521
554
|
view.comments.set(commentId, comment);
|
|
522
555
|
emit({ type: "comment", comment });
|
|
@@ -545,18 +578,22 @@ function hostSession(id, registration, loaded, draft, load) {
|
|
|
545
578
|
emit({ type: "comment-deleted", id: gone.id });
|
|
546
579
|
await saveDraft();
|
|
547
580
|
},
|
|
548
|
-
/** Replies under a comment of this version, or of
|
|
581
|
+
/** Replies under a comment of this version, or of an earlier one, as after a swap. */
|
|
549
582
|
reply: async (target, raw) => {
|
|
550
583
|
open();
|
|
551
584
|
const comment = view.comments.get(target);
|
|
552
|
-
const
|
|
553
|
-
const
|
|
585
|
+
const owner = findSaid(view, target);
|
|
586
|
+
const earlier = comment === undefined ? owner : undefined;
|
|
554
587
|
if (owner === undefined)
|
|
555
588
|
throw new HttpError(404, "no such comment");
|
|
556
589
|
const parsed = parseNewReply(raw);
|
|
557
590
|
if (typeof parsed === "string")
|
|
558
591
|
throw new HttpError(400, `malformed reply: ${parsed}`);
|
|
559
|
-
const taken = new Set([
|
|
592
|
+
const taken = new Set([
|
|
593
|
+
...view.comments.values(),
|
|
594
|
+
...(previousOf(view)?.comments ?? []),
|
|
595
|
+
...carriedOf(view).map((c) => c.comment),
|
|
596
|
+
]
|
|
560
597
|
.flatMap((c) => c.replies ?? [])
|
|
561
598
|
.map((r) => r.id));
|
|
562
599
|
const reply = {
|
|
@@ -599,16 +636,17 @@ function hostSession(id, registration, loaded, draft, load) {
|
|
|
599
636
|
throw new HttpError(400, "expected { comment } or { concern }, and { excluded: boolean }");
|
|
600
637
|
}
|
|
601
638
|
if (comment !== undefined) {
|
|
602
|
-
|
|
639
|
+
const said = (id) => view.comments.has(id) || (view.earlier ?? []).some((c) => c.comment.id === id);
|
|
640
|
+
if (!isCommentId(comment) || !said(comment))
|
|
603
641
|
throw new HttpError(404, "no such comment");
|
|
604
|
-
}
|
|
605
642
|
if (excluded)
|
|
606
643
|
view.excludedComments.add(comment);
|
|
607
644
|
else
|
|
608
645
|
view.excludedComments.delete(comment);
|
|
609
646
|
}
|
|
610
647
|
else {
|
|
611
|
-
|
|
648
|
+
const carried = view.earlierConcerns.some((c) => c.concern.id === concern);
|
|
649
|
+
if (!isConcernId(concern) || !(view.concernIds.has(concern) || carried)) {
|
|
612
650
|
throw new HttpError(404, "no such concern in this plan");
|
|
613
651
|
}
|
|
614
652
|
if (excluded)
|
|
@@ -632,9 +670,9 @@ function hostSession(id, registration, loaded, draft, load) {
|
|
|
632
670
|
open();
|
|
633
671
|
const body = isRecord(raw) ? raw : {};
|
|
634
672
|
const target = body["comment"];
|
|
635
|
-
const asked = view.
|
|
673
|
+
const asked = view.comments.has(String(target)) ? undefined : findSaid(view, target);
|
|
636
674
|
if (asked === undefined || typeof body["resolved"] !== "boolean") {
|
|
637
|
-
throw new HttpError(400, "expected { comment: <id of a question of
|
|
675
|
+
throw new HttpError(400, "expected { comment: <id of a question of an earlier version>, resolved }");
|
|
638
676
|
}
|
|
639
677
|
if (body["resolved"])
|
|
640
678
|
view.resolved.add(asked.id);
|
|
@@ -647,7 +685,9 @@ function hostSession(id, registration, loaded, draft, load) {
|
|
|
647
685
|
/**
|
|
648
686
|
* Moves the session to a newer frozen plan under the same id and URL. The new version loads
|
|
649
687
|
* first, so a plan that no longer fits leaves the old one untouched; then the old version's
|
|
650
|
-
* review is finalized if anything was said, and the comment set starts fresh.
|
|
688
|
+
* review is finalized if anything was said, and the comment set starts fresh. Everything
|
|
689
|
+
* said so far is carried onto the new diff and saved with the new draft at once, so a restart
|
|
690
|
+
* keeps it; decisions, resolutions and exclusions go on applying to what they named.
|
|
651
691
|
*/
|
|
652
692
|
swap: async (version, hash) => {
|
|
653
693
|
open();
|
|
@@ -664,11 +704,31 @@ function hostSession(id, registration, loaded, draft, load) {
|
|
|
664
704
|
try {
|
|
665
705
|
await writes;
|
|
666
706
|
const next = await load({ ...view.registration, version, hash, lockToken: null }, view.loaded.release);
|
|
707
|
+
const earlier = continued(view, next);
|
|
667
708
|
if (hasWork())
|
|
668
709
|
await writeReview(review());
|
|
669
710
|
else
|
|
670
711
|
await rm(view.draftFile, { force: true });
|
|
671
|
-
|
|
712
|
+
const nextIds = new Set(next.state.commits.flatMap((c) => (c.concerns ?? []).map((k) => k.id)));
|
|
713
|
+
const stillNamed = (id) => nextIds.has(id) || earlier.concerns.some((c) => c.concern.id === id);
|
|
714
|
+
const draft = await loadDraft(next.reviewsDir, version);
|
|
715
|
+
view = viewOf({ ...view.registration, version, hash }, next, {
|
|
716
|
+
...draft,
|
|
717
|
+
concerns: [...view.decisions.values()].filter((d) => nextIds.has(d.concern)),
|
|
718
|
+
resolved: [...view.resolved],
|
|
719
|
+
excluded: {
|
|
720
|
+
comments: [...view.excludedComments],
|
|
721
|
+
concerns: [...view.excludedConcerns].filter(stillNamed),
|
|
722
|
+
},
|
|
723
|
+
}, earlier);
|
|
724
|
+
const carrying = earlier.comments.length +
|
|
725
|
+
earlier.concerns.length +
|
|
726
|
+
view.decisions.size +
|
|
727
|
+
view.resolved.size +
|
|
728
|
+
view.excludedComments.size +
|
|
729
|
+
view.excludedConcerns.size;
|
|
730
|
+
if (carrying > 0)
|
|
731
|
+
await saveDraft();
|
|
672
732
|
emit({ type: "version", version, hash, carried: carriedOf(view) });
|
|
673
733
|
}
|
|
674
734
|
finally {
|
|
@@ -692,6 +752,23 @@ function hostSession(id, registration, loaded, draft, load) {
|
|
|
692
752
|
},
|
|
693
753
|
};
|
|
694
754
|
}
|
|
755
|
+
/**
|
|
756
|
+
* What the session carries from the open view into the next version: what it carried already and
|
|
757
|
+
* what was said on this version, and the kept concerns the next plan lost, all on the next diff.
|
|
758
|
+
*/
|
|
759
|
+
function continued(view, next) {
|
|
760
|
+
const { state } = view.loaded;
|
|
761
|
+
const oldUnits = new Map(state.units.map((u) => [u.id, u]));
|
|
762
|
+
const newUnits = new Map(next.state.units.map((u) => [u.id, u]));
|
|
763
|
+
const comments = carrySession(sessionOf(view) ?? [], [...view.comments.values()], state.version, oldUnits, newUnits);
|
|
764
|
+
const kept = state.commits.flatMap((commit, k) => (commit.concerns ?? []).flatMap((concern) => {
|
|
765
|
+
const decision = view.decisions.get(concern.id);
|
|
766
|
+
return decision?.decision === "kept" ? [{ concern, commit: k, decision }] : [];
|
|
767
|
+
}));
|
|
768
|
+
const inNext = new Set(next.state.commits.flatMap((c) => (c.concerns ?? []).map((k) => k.id)));
|
|
769
|
+
const concerns = carryConcerns(view.earlierConcerns, kept, inNext, state.version, oldUnits, newUnits);
|
|
770
|
+
return { comments, concerns };
|
|
771
|
+
}
|
|
695
772
|
function sameRegistration(a, b) {
|
|
696
773
|
return a.dir === b.dir && a.mode === b.mode && a.version === b.version && a.hash === b.hash;
|
|
697
774
|
}
|
package/dist/src/session.js
CHANGED
|
@@ -449,6 +449,29 @@ export async function sinceLastPlan(session) {
|
|
|
449
449
|
const oldDiff = await loadDiff(session.root, latest.file.base, latest.file.tip);
|
|
450
450
|
return { since: latest.version, ...evolvePlan(latest.file, oldDiff, session.diff) };
|
|
451
451
|
}
|
|
452
|
+
/**
|
|
453
|
+
* Pure. The comments a review's `carried` names, whole, from the reviews that hold them: each
|
|
454
|
+
* from the review of its version, its thread completed with the replies later versions stored
|
|
455
|
+
* as earlierReplies. `reviews` are the session's reviews up to the one asking; a ref whose review
|
|
456
|
+
* is missing is skipped, so a damaged session still reports the rest.
|
|
457
|
+
*/
|
|
458
|
+
export function sessionComments(refs, reviews) {
|
|
459
|
+
return refs.flatMap(({ comment: id, ...at }) => {
|
|
460
|
+
const comment = reviews
|
|
461
|
+
.find((r) => r.planVersion === at.version)
|
|
462
|
+
?.comments.find((c) => c.id === id);
|
|
463
|
+
if (comment === undefined)
|
|
464
|
+
return [];
|
|
465
|
+
const later = reviews
|
|
466
|
+
.filter((r) => r.planVersion > at.version)
|
|
467
|
+
.sort((a, b) => a.planVersion - b.planVersion)
|
|
468
|
+
.flatMap((r) => (r.earlierReplies ?? []).filter((e) => e.comment === id))
|
|
469
|
+
.flatMap((e) => e.replies);
|
|
470
|
+
const seen = new Set((comment.replies ?? []).map((r) => r.id));
|
|
471
|
+
const replies = [...(comment.replies ?? []), ...later.filter((r) => !seen.has(r.id))];
|
|
472
|
+
return [{ ...at, comment: replies.length === 0 ? comment : { ...comment, replies } }];
|
|
473
|
+
});
|
|
474
|
+
}
|
|
452
475
|
/** "<name>.<pid>.<random>.tmp" as written by writeJson, the lock and the review server. */
|
|
453
476
|
function abandonedTemps(dir) {
|
|
454
477
|
if (!existsSync(dir))
|
package/dist/ui/dist/assets/{abnfDiagram-WEYOIA3C-BXkLs7mV.js → abnfDiagram-WEYOIA3C-8UsLPznO.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{m as e,t}from"./mermaid-parser.core-
|
|
1
|
+
import{m as e,t}from"./mermaid-parser.core-DxvaorTa.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-BZ3kG7lO.js";import"./chunk-DSNLSHJZ-YiMuxsb-.js";import{n as i,r as a,t as o}from"./chunk-2E7WHVMD-BiHSeJMu.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-ujYTsRZz.js";var c=e().RailroadAbnf.parser.LangiumParser,l=n(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=n(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=n(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=n(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=n(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=n(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=n(e=>{s(e,o),e.title&&o.setTitle(e.title),e.rules.map(e=>o.addRule(m(e)))},`populateDb`),g={parser:{parse:n(e=>{o.clear(),r.debug(`[ABNF Parser] Starting Langium parse`);let n=c.parse(e);if(n.lexerErrors.length>0||n.parserErrors.length>0)throw new t(n);let i=n.value;r.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),r.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:o}},db:o,renderer:a,styles:i};export{g as diagram};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e,t}from"./path-fybaL0A-.js";import{a as n,c as r,d as i,f as a,i as o,l as s,m as c,n as l,o as u,p as d,r as f,u as p}from"./dist-
|
|
1
|
+
import{n as e,t}from"./path-fybaL0A-.js";import{a as n,c as r,d as i,f as a,i as o,l as s,m as c,n as l,o as u,p as d,r as f,u as p}from"./dist-D3j-DODP.js";function m(e){return e.innerRadius}function h(e){return e.outerRadius}function g(e){return e.startAngle}function _(e){return e.endAngle}function v(e){return e&&e.padAngle}function y(e,t,n,r,i,a,o,s){var c=n-e,l=r-t,u=o-i,d=s-a,f=d*c-u*l;if(!(f*f<1e-12))return f=(u*(t-a)-d*(e-i))/f,[e+f*c,t+f*l]}function b(e,t,n,r,i,a,o){var c=e-n,l=t-r,u=(o?a:-a)/d(c*c+l*l),f=u*l,p=-u*c,m=e+f,h=t+p,g=n+f,_=r+p,v=(m+g)/2,y=(h+_)/2,b=g-m,x=_-h,S=b*b+x*x,C=i-a,w=m*_-g*h,T=(x<0?-1:1)*d(s(0,C*C*S-w*w)),E=(w*x-b*T)/S,D=(-w*b-x*T)/S,O=(w*x+b*T)/S,k=(-w*b+x*T)/S,A=E-v,j=D-y,M=O-v,N=k-y;return A*A+j*j>M*M+N*N&&(E=O,D=k),{cx:E,cy:D,x01:-f,y01:-p,x11:E*(i/C-1),y11:D*(i/C-1)}}function x(){var s=m,x=h,S=e(0),C=null,w=g,T=_,E=v,D=null,O=t(k);function k(){var e,t,m=+s.apply(this,arguments),h=+x.apply(this,arguments),g=w.apply(this,arguments)-r,_=T.apply(this,arguments)-r,v=l(_-g),k=_>g;if(D||=e=O(),h<m&&(t=h,h=m,m=t),!(h>1e-12))D.moveTo(0,0);else if(v>c-1e-12)D.moveTo(h*u(g),h*a(g)),D.arc(0,0,h,g,_,!k),m>1e-12&&(D.moveTo(m*u(_),m*a(_)),D.arc(0,0,m,_,g,k));else{var A=g,j=_,M=g,N=_,P=v,F=v,I=E.apply(this,arguments)/2,L=I>1e-12&&(C?+C.apply(this,arguments):d(m*m+h*h)),R=p(l(h-m)/2,+S.apply(this,arguments)),z=R,B=R,V,H;if(L>1e-12){var U=o(L/m*a(I)),W=o(L/h*a(I));(P-=U*2)>1e-12?(U*=k?1:-1,M+=U,N-=U):(P=0,M=N=(g+_)/2),(F-=W*2)>1e-12?(W*=k?1:-1,A+=W,j-=W):(F=0,A=j=(g+_)/2)}var G=h*u(A),K=h*a(A),q=m*u(N),J=m*a(N);if(R>1e-12){var Y=h*u(j),X=h*a(j),Z=m*u(M),Q=m*a(M),$;if(v<i){if($=y(G,K,Z,Q,Y,X,q,J)){var ee=G-$[0],te=K-$[1],ne=Y-$[0],re=X-$[1],ie=1/a(f((ee*ne+te*re)/(d(ee*ee+te*te)*d(ne*ne+re*re)))/2),ae=d($[0]*$[0]+$[1]*$[1]);z=p(R,(m-ae)/(ie-1)),B=p(R,(h-ae)/(ie+1))}else z=B=0}}F>1e-12?B>1e-12?(V=b(Z,Q,G,K,h,B,k),H=b(Y,X,q,J,h,B,k),D.moveTo(V.cx+V.x01,V.cy+V.y01),B<R?D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,h,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),!k),D.arc(H.cx,H.cy,B,n(H.y11,H.x11),n(H.y01,H.x01),!k))):(D.moveTo(G,K),D.arc(0,0,h,A,j,!k)):D.moveTo(G,K),!(m>1e-12)||!(P>1e-12)?D.lineTo(q,J):z>1e-12?(V=b(q,J,Y,X,m,-z,k),H=b(G,K,Z,Q,m,-z,k),D.lineTo(V.cx+V.x01,V.cy+V.y01),z<R?D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,m,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),k),D.arc(H.cx,H.cy,z,n(H.y11,H.x11),n(H.y01,H.x01),!k))):D.arc(0,0,m,N,M,k)}if(D.closePath(),e)return D=null,e+``||null}return k.centroid=function(){var e=(+s.apply(this,arguments)+ +x.apply(this,arguments))/2,t=(+w.apply(this,arguments)+ +T.apply(this,arguments))/2-i/2;return[u(t)*e,a(t)*e]},k.innerRadius=function(t){return arguments.length?(s=typeof t==`function`?t:e(+t),k):s},k.outerRadius=function(t){return arguments.length?(x=typeof t==`function`?t:e(+t),k):x},k.cornerRadius=function(t){return arguments.length?(S=typeof t==`function`?t:e(+t),k):S},k.padRadius=function(t){return arguments.length?(C=t==null?null:typeof t==`function`?t:e(+t),k):C},k.startAngle=function(t){return arguments.length?(w=typeof t==`function`?t:e(+t),k):w},k.endAngle=function(t){return arguments.length?(T=typeof t==`function`?t:e(+t),k):T},k.padAngle=function(t){return arguments.length?(E=typeof t==`function`?t:e(+t),k):E},k.context=function(e){return arguments.length?(D=e??null,k):D},k}export{x as t};
|
package/dist/ui/dist/assets/{architecture-WOLXFQ4H-D66kgJJt.js → architecture-WOLXFQ4H-BBMK-PUu.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./chunk-NGNAAXSQ-C2Wy9Xmz.js";export{M as createArchitectureServices}from"./mermaid-parser.core-
|
|
1
|
+
import"./chunk-NGNAAXSQ-C2Wy9Xmz.js";export{M as createArchitectureServices}from"./mermaid-parser.core-DxvaorTa.js";
|