@shiyuphan/follow-me 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/dist/src/cli.js +35 -11
- package/dist/src/comments.js +62 -9
- package/dist/src/definition.js +226 -0
- package/dist/src/evolve.js +145 -29
- package/dist/src/git.js +69 -13
- package/dist/src/host.js +12 -3
- package/dist/src/plan.js +26 -1
- package/dist/src/prompt.js +122 -12
- package/dist/src/server.js +120 -28
- package/dist/src/session.js +23 -0
- package/dist/src/types.js +2 -0
- package/dist/ui/dist/assets/{abnfDiagram-WEYOIA3C-BXkLs7mV.js → abnfDiagram-WEYOIA3C-fYSYLdMl.js} +1 -1
- package/dist/ui/dist/assets/{arc-DNzjw7Ie.js → arc-DGuGSnwa.js} +1 -1
- package/dist/ui/dist/assets/{architecture-WOLXFQ4H-D66kgJJt.js → architecture-WOLXFQ4H-VFox_hV1.js} +1 -1
- package/dist/ui/dist/assets/{architectureDiagram-ZHVYKT53-D8UWuhQr.js → architectureDiagram-ZHVYKT53-CBVK3nHZ.js} +1 -1
- package/dist/ui/dist/assets/{blockDiagram-RJAE7QA3-BLkmr62i.js → blockDiagram-RJAE7QA3-BFdsIWEr.js} +1 -1
- package/dist/ui/dist/assets/{c4Diagram-XDPPPE54-3rZPYwOc.js → c4Diagram-XDPPPE54-BGntcPId.js} +1 -1
- package/dist/ui/dist/assets/channel-gz6cS9Z1.js +1 -0
- package/dist/ui/dist/assets/{chunk-2E7WHVMD-MMnvAgpB.js → chunk-2E7WHVMD-CNMuK9zj.js} +1 -1
- package/dist/ui/dist/assets/{chunk-4EMNKR2T-D9FGWA3l.js → chunk-4EMNKR2T-ByeTTJWS.js} +1 -1
- package/dist/ui/dist/assets/{chunk-55XCU76K-DuOUaV8F.js → chunk-55XCU76K-99xE7cLH.js} +1 -1
- package/dist/ui/dist/assets/{chunk-7S6XSTFO-p3YWPv0m.js → chunk-7S6XSTFO-ZVmT7eMZ.js} +1 -1
- package/dist/ui/dist/assets/{chunk-AQDTSKZB-DWfKYjwk.js → chunk-AQDTSKZB-B981JORL.js} +1 -1
- package/dist/ui/dist/assets/{chunk-DSNLSHJZ-C3CIwpv0.js → chunk-DSNLSHJZ-B2z7FX4h.js} +1 -1
- package/dist/ui/dist/assets/{chunk-HAGFOTED-Bwfl9gme.js → chunk-HAGFOTED-CHFbBS-4.js} +1 -1
- package/dist/ui/dist/assets/{chunk-HNE4Q36P-0_oeU0le.js → chunk-HNE4Q36P-rq11xv9X.js} +1 -1
- package/dist/ui/dist/assets/{chunk-NQOKRVIF-z_LPPPx5.js → chunk-NQOKRVIF-BYmg9kSX.js} +1 -1
- package/dist/ui/dist/assets/{chunk-UHW7PFBP-BH28V2yu.js → chunk-UHW7PFBP-JvL9IXWg.js} +1 -1
- package/dist/ui/dist/assets/{chunk-VQ5W62QI-BXDajDf7.js → chunk-VQ5W62QI-CYMQaAKn.js} +1 -1
- package/dist/ui/dist/assets/{chunk-WQQL4CDK-BphBlfKj.js → chunk-WQQL4CDK-CXnR0PHT.js} +1 -1
- package/dist/ui/dist/assets/{chunk-XXDRQBXY-BiCT5NwV.js → chunk-XXDRQBXY-CDUWJCXi.js} +1 -1
- package/dist/ui/dist/assets/{chunk-YZO67HFG-Bg5Pu8BX.js → chunk-YZO67HFG-mZfXIx0h.js} +1 -1
- package/dist/ui/dist/assets/{chunk-ZAUX2LTX-C_Tgd8tB.js → chunk-ZAUX2LTX-DBxVTCHX.js} +1 -1
- package/dist/ui/dist/assets/{chunk-ZCHMQSOR-MBRcMi8-.js → chunk-ZCHMQSOR-DrWA4IBo.js} +1 -1
- package/dist/ui/dist/assets/{classDiagram-v2-4MYWR3UA-1wyeCe5y.js → classDiagram-v2-4MYWR3UA-Beah5uxA.js} +1 -1
- package/dist/ui/dist/assets/{cose-bilkent-JH36ORCC-BtOYclF6.js → cose-bilkent-JH36ORCC-UaE-jnHk.js} +1 -1
- package/dist/ui/dist/assets/{cynefin-EF2NZ3EQ-dJmoOG8g.js → cynefin-EF2NZ3EQ-DKfGaCR8.js} +1 -1
- package/dist/ui/dist/assets/{cynefinDiagram-WF24UDRP-AloyqbEN.js → cynefinDiagram-WF24UDRP-tTUzTs3D.js} +1 -1
- package/dist/ui/dist/assets/{dagre-NK4GIZVX-NCZhdnfb.js → dagre-NK4GIZVX-jSn35_T7.js} +1 -1
- package/dist/ui/dist/assets/{diagram-CBK3MWTC-D8w7x5Gb.js → diagram-CBK3MWTC-7W2uw8Zc.js} +1 -1
- package/dist/ui/dist/assets/{diagram-I5XIIV2D-BUFnCGlp.js → diagram-I5XIIV2D-CcfyQVh9.js} +1 -1
- package/dist/ui/dist/assets/{diagram-ODIL2UCW-BULmHKaW.js → diagram-ODIL2UCW-BjGvaLis.js} +1 -1
- package/dist/ui/dist/assets/{diagram-PFBEJUXE-B5MqFo0r.js → diagram-PFBEJUXE-jvdCrt8B.js} +1 -1
- package/dist/ui/dist/assets/{diagram-RJA3I4VV-BIkDLL8E.js → diagram-RJA3I4VV-D65_Vpi_.js} +1 -1
- package/dist/ui/dist/assets/{diagram-TYUNFSNR-Ca4gsQV8.js → diagram-TYUNFSNR-C52roQBE.js} +1 -1
- package/dist/ui/dist/assets/{dist-G85JKY5k.js → dist-BJd4jp9Y.js} +1 -1
- package/dist/ui/dist/assets/{ebnfDiagram-V4P3TTPT-rVjcFFtb.js → ebnfDiagram-V4P3TTPT-DXysoIBq.js} +1 -1
- package/dist/ui/dist/assets/{elk-QONTBCTQ-BWPdvULh.js → elk-QONTBCTQ-BVZcsgV3.js} +1 -1
- package/dist/ui/dist/assets/{erDiagram-KYQIGQAA-BPxJJkRl.js → erDiagram-KYQIGQAA-BJnT4fVU.js} +1 -1
- package/dist/ui/dist/assets/{eventmodeling-K75KTNOO-BSB9WYV3.js → eventmodeling-K75KTNOO-C5MzxCMY.js} +1 -1
- package/dist/ui/dist/assets/flowDiagram-IUGLLWBU-BqUgZSCz.js +1 -0
- package/dist/ui/dist/assets/{ganttDiagram-R7GPNTJY-DKps530K.js → ganttDiagram-R7GPNTJY-CZRrnuah.js} +1 -1
- package/dist/ui/dist/assets/{gitGraph-VSP46ZUC-D1d4UAFV.js → gitGraph-VSP46ZUC-l58aGSkh.js} +1 -1
- package/dist/ui/dist/assets/{gitGraphDiagram-PDYL7XHY-N55yl6hc.js → gitGraphDiagram-PDYL7XHY-D4ks1WO-.js} +1 -1
- package/dist/ui/dist/assets/index-BW95UA5q.css +1 -0
- package/dist/ui/dist/assets/index-DOGXgoHF.js +134 -0
- package/dist/ui/dist/assets/{info-OHQRW6UA-CgxE3gf9.js → info-OHQRW6UA-BSqfzkdk.js} +1 -1
- package/dist/ui/dist/assets/{infoDiagram-MVDRKAX5-DOnUrnMf.js → infoDiagram-MVDRKAX5-B6NgVF_N.js} +1 -1
- package/dist/ui/dist/assets/{ishikawaDiagram-HPEHV2GE-BIY0fFHB.js → ishikawaDiagram-HPEHV2GE-DvtfssEZ.js} +1 -1
- package/dist/ui/dist/assets/{journeyDiagram-BOSHW7O7-CqA2Ern0.js → journeyDiagram-BOSHW7O7-DM64gT5v.js} +1 -1
- package/dist/ui/dist/assets/{kanban-definition-FNSA4HC5-vGrpQKIF.js → kanban-definition-FNSA4HC5-AliyRJHy.js} +1 -1
- package/dist/ui/dist/assets/{line-Brzv3qA6.js → line-CHncXbKO.js} +1 -1
- package/dist/ui/dist/assets/{linear-D9uIlqyh.js → linear-BWEWydI0.js} +1 -1
- package/dist/ui/dist/assets/{mermaid-parser.core-Bz9b-Thu.js → mermaid-parser.core-DGpOP8AM.js} +3 -3
- package/dist/ui/dist/assets/{mermaid.core-BaZipu3b.js → mermaid.core-BJtBFbJx.js} +4 -4
- package/dist/ui/dist/assets/{mindmap-definition-6OY57UG3-D6aie7uH.js → mindmap-definition-6OY57UG3-NjavnWBi.js} +1 -1
- package/dist/ui/dist/assets/{packet-JDAUHWVQ-28r3jVFY.js → packet-JDAUHWVQ-zuhpVsME.js} +1 -1
- package/dist/ui/dist/assets/{pegDiagram-ECIUJNBX-CbGvD4qP.js → pegDiagram-ECIUJNBX-sL4grM97.js} +1 -1
- package/dist/ui/dist/assets/{pie-XZMESJXO-DHpcGnZd.js → pie-XZMESJXO-C9l1Mp09.js} +1 -1
- package/dist/ui/dist/assets/{pieDiagram-GNMPY74T-DuhauwnY.js → pieDiagram-GNMPY74T-rlRBr2U4.js} +1 -1
- package/dist/ui/dist/assets/{prism-core-CbZMOvrb.js → prism-core-DmuST30i.js} +1 -1
- package/dist/ui/dist/assets/{quadrantDiagram-D57K4MC3-BfyNmVca.js → quadrantDiagram-D57K4MC3-4oQMip2Q.js} +1 -1
- package/dist/ui/dist/assets/{radar-ABXABTNO-Xp1TYwaj.js → radar-ABXABTNO-DvGg96L7.js} +1 -1
- package/dist/ui/dist/assets/{railroad-I3PHUGI6-c5FY4wwa.js → railroad-I3PHUGI6-8wdFKMZp.js} +1 -1
- package/dist/ui/dist/assets/{railroad-abnf-LNEFI6M7-RDyWXqcL.js → railroad-abnf-LNEFI6M7-DUtOO0gn.js} +1 -1
- package/dist/ui/dist/assets/{railroad-ebnf-DWYD2UWJ-CLD4jVou.js → railroad-ebnf-DWYD2UWJ-5YCGY1_d.js} +1 -1
- package/dist/ui/dist/assets/{railroad-peg-JR7BVNR7-17EYTA-w.js → railroad-peg-JR7BVNR7-Bwywxjhs.js} +1 -1
- package/dist/ui/dist/assets/{railroadDiagram-Y72NRBL7-C4p2wtKe.js → railroadDiagram-Y72NRBL7-CwO6HSNQ.js} +1 -1
- package/dist/ui/dist/assets/{requirementDiagram-EQYSW5RA-DTYIFN8T.js → requirementDiagram-EQYSW5RA-Cp0IbfNr.js} +1 -1
- package/dist/ui/dist/assets/{sankeyDiagram-SY24JHO5-YDYhRyJU.js → sankeyDiagram-SY24JHO5-DeQKsO68.js} +1 -1
- package/dist/ui/dist/assets/{sequenceDiagram-BLEHNHQU-Crvy6IlU.js → sequenceDiagram-BLEHNHQU-DTDalCxF.js} +1 -1
- package/dist/ui/dist/assets/{src-BPod-Ype.js → src-XnrqevnL.js} +1 -1
- package/dist/ui/dist/assets/{stateDiagram-v2-A6IESKWZ-BWr70YOQ.js → stateDiagram-v2-A6IESKWZ-2DZ-tKo9.js} +1 -1
- package/dist/ui/dist/assets/{swimlanes-B3ENRKFQ-DvbG4I9a.js → swimlanes-B3ENRKFQ-66yZJeRU.js} +1 -1
- package/dist/ui/dist/assets/swimlanesDiagram-AYQRV4AK-rbX6bYG4.js +8 -0
- package/dist/ui/dist/assets/{timeline-definition-JXYKGLGB-CR950Bzb.js → timeline-definition-JXYKGLGB-Dm1xGU-d.js} +1 -1
- package/dist/ui/dist/assets/{treeView-D4JQ5SDB-DSDDXGrk.js → treeView-D4JQ5SDB-BvgsbSot.js} +1 -1
- package/dist/ui/dist/assets/{treemap-SAJKECNS-Ct5w2_RR.js → treemap-SAJKECNS-C3lnbG1a.js} +1 -1
- package/dist/ui/dist/assets/{usecaseDiagram-WPOLBNNX-_eP0371y.js → usecaseDiagram-WPOLBNNX-B6iPNIhZ.js} +1 -1
- package/dist/ui/dist/assets/{vennDiagram-Q3Y3IDCW-Cu-IA57L.js → vennDiagram-Q3Y3IDCW-D5dgflg9.js} +1 -1
- package/dist/ui/dist/assets/{wardley-7MLQ67FV-r8yd6frN.js → wardley-7MLQ67FV-Dn9mLIB4.js} +1 -1
- package/dist/ui/dist/assets/{wardleyDiagram-IVAIDKWA-CBUUiRQm.js → wardleyDiagram-IVAIDKWA-W1EwzN_X.js} +1 -1
- package/dist/ui/dist/assets/{xychartDiagram-4URNHDU4-DEVQjvgG.js → xychartDiagram-4URNHDU4-CKRzMUvp.js} +1 -1
- package/dist/ui/dist/index.html +2 -2
- package/package.json +1 -1
- package/skills/follow-me/SKILL.md +3 -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-B8TYcxF8.css +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,9 @@ 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 { definitionIndex, isIdentifier } from "./definition.js";
|
|
9
|
+
import { isRepoPath } from "./diff.js";
|
|
10
|
+
import { carryConcerns, carrySession } from "./evolve.js";
|
|
8
11
|
import { isConcernId, isPlanVersion } from "./plan.js";
|
|
9
12
|
import { renderReport, reportItems } from "./prompt.js";
|
|
10
13
|
import { isLockToken } from "./session.js";
|
|
@@ -88,6 +91,8 @@ export async function loadDraft(reviewsDir, version) {
|
|
|
88
91
|
resolved: [],
|
|
89
92
|
excluded: { comments: [], concerns: [] },
|
|
90
93
|
earlierReplies: [],
|
|
94
|
+
carried: null,
|
|
95
|
+
carriedConcerns: [],
|
|
91
96
|
};
|
|
92
97
|
}
|
|
93
98
|
throw error;
|
|
@@ -236,7 +241,7 @@ async function readUi(dir, name) {
|
|
|
236
241
|
}
|
|
237
242
|
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
243
|
`;
|
|
239
|
-
function viewOf(registration, loaded, draft) {
|
|
244
|
+
function viewOf(registration, loaded, draft, earlier = loaded.earlier) {
|
|
240
245
|
const { state, reviewsDir } = loaded;
|
|
241
246
|
return {
|
|
242
247
|
registration,
|
|
@@ -247,9 +252,12 @@ function viewOf(registration, loaded, draft) {
|
|
|
247
252
|
excludedComments: new Set(draft.excluded.comments),
|
|
248
253
|
excludedConcerns: new Set(draft.excluded.concerns),
|
|
249
254
|
earlierReplies: new Map(draft.earlierReplies.map((e) => [e.comment, e.replies])),
|
|
255
|
+
earlier: earlier === null ? null : earlier.comments,
|
|
256
|
+
earlierConcerns: earlier === null ? [] : earlier.concerns,
|
|
250
257
|
unitIds: new Set(state.units.map((u) => u.id)),
|
|
251
258
|
hunkRows: new Map(state.units.flatMap((u) => u.kind === "hunk" ? [[u.id, u.body.length]] : [])),
|
|
252
259
|
concernIds: new Set(state.commits.flatMap((c) => (c.concerns ?? []).map((k) => k.id))),
|
|
260
|
+
definitions: definitionIndex(loaded.repo, state.anchor.tip, new Map(state.units.map((u) => [u.id, u])), state.commits),
|
|
253
261
|
draftFile: draftPath(reviewsDir, state.version),
|
|
254
262
|
reviewFile: join(reviewsDir, `v${state.version}.json`),
|
|
255
263
|
};
|
|
@@ -258,7 +266,7 @@ function withReplies(comment, replies) {
|
|
|
258
266
|
const { replies: _dropped, ...rest } = comment;
|
|
259
267
|
return replies === undefined || replies.length === 0 ? rest : { ...rest, replies };
|
|
260
268
|
}
|
|
261
|
-
/** A comment of
|
|
269
|
+
/** A comment of an earlier version with the replies it got during this one. */
|
|
262
270
|
function withEarlier(view, comment) {
|
|
263
271
|
const later = view.earlierReplies.get(comment.id) ?? [];
|
|
264
272
|
return later.length === 0
|
|
@@ -271,8 +279,39 @@ function previousOf(view) {
|
|
|
271
279
|
return null;
|
|
272
280
|
return { ...previous, comments: previous.comments.map((c) => withEarlier(view, c)) };
|
|
273
281
|
}
|
|
282
|
+
/** The session's earlier comments with this version's replies, or null outside a session. */
|
|
283
|
+
function sessionOf(view) {
|
|
284
|
+
return view.earlier === null
|
|
285
|
+
? null
|
|
286
|
+
: view.earlier.map((c) => ({ ...c, comment: withEarlier(view, c.comment) }));
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* What the page shows carried: the session's earlier comments, then those of the review before
|
|
290
|
+
* this version that the session does not hold (a review that ended before this one began).
|
|
291
|
+
*/
|
|
274
292
|
function carriedOf(view) {
|
|
275
|
-
|
|
293
|
+
const session = sessionOf(view) ?? [];
|
|
294
|
+
const held = new Set(session.map((c) => c.comment.id));
|
|
295
|
+
const before = view.loaded.carried
|
|
296
|
+
.filter((c) => !held.has(c.comment.id))
|
|
297
|
+
.map((c) => ({ ...c, comment: withEarlier(view, c.comment) }));
|
|
298
|
+
return [...session, ...before];
|
|
299
|
+
}
|
|
300
|
+
/** The session as stored beside this version: comments by id, concerns whole. */
|
|
301
|
+
function carriedRefs(view) {
|
|
302
|
+
if (view.earlier === null)
|
|
303
|
+
return {};
|
|
304
|
+
const carried = view.earlier.map(({ comment, ...at }) => ({ ...at, comment: comment.id }));
|
|
305
|
+
const concerns = view.earlierConcerns;
|
|
306
|
+
return { carried, ...(concerns.length === 0 ? {} : { carriedConcerns: [...concerns] }) };
|
|
307
|
+
}
|
|
308
|
+
/** A comment said on this version or carried into it, which replies and decisions may name. */
|
|
309
|
+
function findSaid(view, id) {
|
|
310
|
+
if (typeof id !== "string")
|
|
311
|
+
return undefined;
|
|
312
|
+
return (view.comments.get(id) ??
|
|
313
|
+
view.loaded.previous?.comments.find((c) => c.id === id) ??
|
|
314
|
+
view.earlier?.find((c) => c.comment.id === id)?.comment);
|
|
276
315
|
}
|
|
277
316
|
function earlierOf(view) {
|
|
278
317
|
return [...view.earlierReplies].map(([comment, replies]) => ({ comment, replies }));
|
|
@@ -382,6 +421,7 @@ function hostSession(id, registration, loaded, draft, load) {
|
|
|
382
421
|
...(resolved.length === 0 ? {} : { resolved }),
|
|
383
422
|
...(excluded === null ? {} : { excluded }),
|
|
384
423
|
...(earlierReplies.length === 0 ? {} : { earlierReplies }),
|
|
424
|
+
...carriedRefs(view),
|
|
385
425
|
}, null, 2);
|
|
386
426
|
const dir = view.loaded.reviewsDir;
|
|
387
427
|
writes = writes.then(async () => {
|
|
@@ -428,16 +468,19 @@ function hostSession(id, registration, loaded, draft, load) {
|
|
|
428
468
|
...(resolved.length === 0 ? {} : { resolved }),
|
|
429
469
|
...(excluded === null ? {} : { excluded }),
|
|
430
470
|
...(earlierReplies.length === 0 ? {} : { earlierReplies }),
|
|
471
|
+
...carriedRefs(view),
|
|
431
472
|
};
|
|
432
473
|
};
|
|
433
|
-
const
|
|
434
|
-
const
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
branch: state.anchor.branch,
|
|
474
|
+
const reportOptions = () => {
|
|
475
|
+
const comments = sessionOf(view);
|
|
476
|
+
return {
|
|
477
|
+
branch: view.loaded.state.anchor.branch,
|
|
438
478
|
responses: [],
|
|
439
|
-
|
|
479
|
+
...(comments === null ? {} : { earlier: { comments, concerns: view.earlierConcerns } }),
|
|
480
|
+
};
|
|
440
481
|
};
|
|
482
|
+
const unitsOf = () => new Map(view.loaded.state.units.map((u) => [u.id, u]));
|
|
483
|
+
const report = (finished) => renderReport(finished, view.loaded.state.commits, unitsOf(), reportOptions());
|
|
441
484
|
/** Writes reviews/vN.json and its report once, and removes the autosave. */
|
|
442
485
|
const writeReview = async (finished) => {
|
|
443
486
|
await writes;
|
|
@@ -504,19 +547,17 @@ function hostSession(id, registration, loaded, draft, load) {
|
|
|
504
547
|
return waitForEvents(since, timeoutMs, signal);
|
|
505
548
|
},
|
|
506
549
|
report: () => report(review()),
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
const
|
|
510
|
-
return
|
|
511
|
-
branch: state.anchor.branch,
|
|
512
|
-
responses: [],
|
|
513
|
-
});
|
|
550
|
+
/** The page reads a definition the plan shows from its hunk, so only others carry a preview. */
|
|
551
|
+
define: async (name, from) => {
|
|
552
|
+
const found = await view.definitions.lookup(name, from !== null && isRepoPath(from) ? from : null);
|
|
553
|
+
return found.map((c) => (c.unit === null ? c : { ...c, preview: [] }));
|
|
514
554
|
},
|
|
555
|
+
reportItems: () => reportItems(review(), view.loaded.state.commits, unitsOf(), reportOptions()),
|
|
515
556
|
add: async (raw) => {
|
|
516
557
|
open();
|
|
517
558
|
if (!isRecord(raw))
|
|
518
559
|
throw new HttpError(400, "malformed comment");
|
|
519
|
-
const commentId = mintCommentId(new Set(view.comments.keys()));
|
|
560
|
+
const commentId = mintCommentId(new Set([...view.comments.keys(), ...(view.earlier ?? []).map((c) => c.comment.id)]));
|
|
520
561
|
const comment = withReplies(accept(parseComment({ ...raw, id: commentId, createdAt: new Date().toISOString() })), undefined);
|
|
521
562
|
view.comments.set(commentId, comment);
|
|
522
563
|
emit({ type: "comment", comment });
|
|
@@ -545,18 +586,22 @@ function hostSession(id, registration, loaded, draft, load) {
|
|
|
545
586
|
emit({ type: "comment-deleted", id: gone.id });
|
|
546
587
|
await saveDraft();
|
|
547
588
|
},
|
|
548
|
-
/** Replies under a comment of this version, or of
|
|
589
|
+
/** Replies under a comment of this version, or of an earlier one, as after a swap. */
|
|
549
590
|
reply: async (target, raw) => {
|
|
550
591
|
open();
|
|
551
592
|
const comment = view.comments.get(target);
|
|
552
|
-
const
|
|
553
|
-
const
|
|
593
|
+
const owner = findSaid(view, target);
|
|
594
|
+
const earlier = comment === undefined ? owner : undefined;
|
|
554
595
|
if (owner === undefined)
|
|
555
596
|
throw new HttpError(404, "no such comment");
|
|
556
597
|
const parsed = parseNewReply(raw);
|
|
557
598
|
if (typeof parsed === "string")
|
|
558
599
|
throw new HttpError(400, `malformed reply: ${parsed}`);
|
|
559
|
-
const taken = new Set([
|
|
600
|
+
const taken = new Set([
|
|
601
|
+
...view.comments.values(),
|
|
602
|
+
...(previousOf(view)?.comments ?? []),
|
|
603
|
+
...carriedOf(view).map((c) => c.comment),
|
|
604
|
+
]
|
|
560
605
|
.flatMap((c) => c.replies ?? [])
|
|
561
606
|
.map((r) => r.id));
|
|
562
607
|
const reply = {
|
|
@@ -599,16 +644,17 @@ function hostSession(id, registration, loaded, draft, load) {
|
|
|
599
644
|
throw new HttpError(400, "expected { comment } or { concern }, and { excluded: boolean }");
|
|
600
645
|
}
|
|
601
646
|
if (comment !== undefined) {
|
|
602
|
-
|
|
647
|
+
const said = (id) => view.comments.has(id) || (view.earlier ?? []).some((c) => c.comment.id === id);
|
|
648
|
+
if (!isCommentId(comment) || !said(comment))
|
|
603
649
|
throw new HttpError(404, "no such comment");
|
|
604
|
-
}
|
|
605
650
|
if (excluded)
|
|
606
651
|
view.excludedComments.add(comment);
|
|
607
652
|
else
|
|
608
653
|
view.excludedComments.delete(comment);
|
|
609
654
|
}
|
|
610
655
|
else {
|
|
611
|
-
|
|
656
|
+
const carried = view.earlierConcerns.some((c) => c.concern.id === concern);
|
|
657
|
+
if (!isConcernId(concern) || !(view.concernIds.has(concern) || carried)) {
|
|
612
658
|
throw new HttpError(404, "no such concern in this plan");
|
|
613
659
|
}
|
|
614
660
|
if (excluded)
|
|
@@ -632,9 +678,9 @@ function hostSession(id, registration, loaded, draft, load) {
|
|
|
632
678
|
open();
|
|
633
679
|
const body = isRecord(raw) ? raw : {};
|
|
634
680
|
const target = body["comment"];
|
|
635
|
-
const asked = view.
|
|
681
|
+
const asked = view.comments.has(String(target)) ? undefined : findSaid(view, target);
|
|
636
682
|
if (asked === undefined || typeof body["resolved"] !== "boolean") {
|
|
637
|
-
throw new HttpError(400, "expected { comment: <id of a question of
|
|
683
|
+
throw new HttpError(400, "expected { comment: <id of a question of an earlier version>, resolved }");
|
|
638
684
|
}
|
|
639
685
|
if (body["resolved"])
|
|
640
686
|
view.resolved.add(asked.id);
|
|
@@ -647,7 +693,9 @@ function hostSession(id, registration, loaded, draft, load) {
|
|
|
647
693
|
/**
|
|
648
694
|
* Moves the session to a newer frozen plan under the same id and URL. The new version loads
|
|
649
695
|
* 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.
|
|
696
|
+
* review is finalized if anything was said, and the comment set starts fresh. Everything
|
|
697
|
+
* said so far is carried onto the new diff and saved with the new draft at once, so a restart
|
|
698
|
+
* keeps it; decisions, resolutions and exclusions go on applying to what they named.
|
|
651
699
|
*/
|
|
652
700
|
swap: async (version, hash) => {
|
|
653
701
|
open();
|
|
@@ -664,11 +712,31 @@ function hostSession(id, registration, loaded, draft, load) {
|
|
|
664
712
|
try {
|
|
665
713
|
await writes;
|
|
666
714
|
const next = await load({ ...view.registration, version, hash, lockToken: null }, view.loaded.release);
|
|
715
|
+
const earlier = continued(view, next);
|
|
667
716
|
if (hasWork())
|
|
668
717
|
await writeReview(review());
|
|
669
718
|
else
|
|
670
719
|
await rm(view.draftFile, { force: true });
|
|
671
|
-
|
|
720
|
+
const nextIds = new Set(next.state.commits.flatMap((c) => (c.concerns ?? []).map((k) => k.id)));
|
|
721
|
+
const stillNamed = (id) => nextIds.has(id) || earlier.concerns.some((c) => c.concern.id === id);
|
|
722
|
+
const draft = await loadDraft(next.reviewsDir, version);
|
|
723
|
+
view = viewOf({ ...view.registration, version, hash }, next, {
|
|
724
|
+
...draft,
|
|
725
|
+
concerns: [...view.decisions.values()].filter((d) => nextIds.has(d.concern)),
|
|
726
|
+
resolved: [...view.resolved],
|
|
727
|
+
excluded: {
|
|
728
|
+
comments: [...view.excludedComments],
|
|
729
|
+
concerns: [...view.excludedConcerns].filter(stillNamed),
|
|
730
|
+
},
|
|
731
|
+
}, earlier);
|
|
732
|
+
const carrying = earlier.comments.length +
|
|
733
|
+
earlier.concerns.length +
|
|
734
|
+
view.decisions.size +
|
|
735
|
+
view.resolved.size +
|
|
736
|
+
view.excludedComments.size +
|
|
737
|
+
view.excludedConcerns.size;
|
|
738
|
+
if (carrying > 0)
|
|
739
|
+
await saveDraft();
|
|
672
740
|
emit({ type: "version", version, hash, carried: carriedOf(view) });
|
|
673
741
|
}
|
|
674
742
|
finally {
|
|
@@ -692,6 +760,23 @@ function hostSession(id, registration, loaded, draft, load) {
|
|
|
692
760
|
},
|
|
693
761
|
};
|
|
694
762
|
}
|
|
763
|
+
/**
|
|
764
|
+
* What the session carries from the open view into the next version: what it carried already and
|
|
765
|
+
* what was said on this version, and the kept concerns the next plan lost, all on the next diff.
|
|
766
|
+
*/
|
|
767
|
+
function continued(view, next) {
|
|
768
|
+
const { state } = view.loaded;
|
|
769
|
+
const oldUnits = new Map(state.units.map((u) => [u.id, u]));
|
|
770
|
+
const newUnits = new Map(next.state.units.map((u) => [u.id, u]));
|
|
771
|
+
const comments = carrySession(sessionOf(view) ?? [], [...view.comments.values()], state.version, oldUnits, newUnits);
|
|
772
|
+
const kept = state.commits.flatMap((commit, k) => (commit.concerns ?? []).flatMap((concern) => {
|
|
773
|
+
const decision = view.decisions.get(concern.id);
|
|
774
|
+
return decision?.decision === "kept" ? [{ concern, commit: k, decision }] : [];
|
|
775
|
+
}));
|
|
776
|
+
const inNext = new Set(next.state.commits.flatMap((c) => (c.concerns ?? []).map((k) => k.id)));
|
|
777
|
+
const concerns = carryConcerns(view.earlierConcerns, kept, inNext, state.version, oldUnits, newUnits);
|
|
778
|
+
return { comments, concerns };
|
|
779
|
+
}
|
|
695
780
|
function sameRegistration(a, b) {
|
|
696
781
|
return a.dir === b.dir && a.mode === b.mode && a.version === b.version && a.hash === b.hash;
|
|
697
782
|
}
|
|
@@ -866,6 +951,13 @@ export function startServer(opts) {
|
|
|
866
951
|
const timeout = queryInt(url, "timeout", 0, MAX_POLL_MS, DEFAULT_POLL_MS);
|
|
867
952
|
return sendJson(res, 200, await session.poll(since, timeout, abort.signal));
|
|
868
953
|
}
|
|
954
|
+
if (method === "GET" && rest === "/api/definition") {
|
|
955
|
+
const name = url.searchParams.get("name") ?? "";
|
|
956
|
+
if (!isIdentifier(name))
|
|
957
|
+
throw new HttpError(400, "name must be an identifier");
|
|
958
|
+
const candidates = await session.define(name, url.searchParams.get("from"));
|
|
959
|
+
return sendJson(res, 200, { candidates });
|
|
960
|
+
}
|
|
869
961
|
if (method === "GET" && rest === "/api/report" && url.searchParams.get("format") === "json") {
|
|
870
962
|
return sendJson(res, 200, session.reportItems());
|
|
871
963
|
}
|
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/src/types.js
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
* session.ts the .follow-me/<slug>/ layout: session anchor, plans, reviews, draft.
|
|
11
11
|
* comments.ts the wire formats of review state: comments, replies, concern decisions, the
|
|
12
12
|
* review file, the autosaved draft and the server's events. Pure parsers.
|
|
13
|
+
* definition.ts where an identifier is defined at the branch tip, and where that lands in the
|
|
14
|
+
* plan: per-language patterns, ranking, placement and a per-tip cache.
|
|
13
15
|
* prompt.ts the planner prompt for an agent, the feedback and the consolidated report.
|
|
14
16
|
* server.ts the review server: a registry of hosted sessions, their JSON API, and ui/.
|
|
15
17
|
* host.ts the one server per user: its record in the state dir, attach, start, stop.
|
package/dist/ui/dist/assets/{abnfDiagram-WEYOIA3C-BXkLs7mV.js → abnfDiagram-WEYOIA3C-fYSYLdMl.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{m as e,t}from"./mermaid-parser.core-
|
|
1
|
+
import{m as e,t}from"./mermaid-parser.core-DGpOP8AM.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-XnrqevnL.js";import"./chunk-DSNLSHJZ-B2z7FX4h.js";import{n as i,r as a,t as o}from"./chunk-2E7WHVMD-CNMuK9zj.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-BJtBFbJx.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-BJd4jp9Y.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-VFox_hV1.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-DGpOP8AM.js";
|