@shiyuphan/follow-me 0.9.0 → 0.9.2

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 (96) hide show
  1. package/dist/src/cli.js +161 -35
  2. package/dist/src/comments.js +25 -4
  3. package/dist/src/coverage.js +26 -15
  4. package/dist/src/host.js +15 -5
  5. package/dist/src/install.js +11 -1
  6. package/dist/src/plain.js +20 -0
  7. package/dist/src/plan.js +44 -22
  8. package/dist/src/prompt.js +58 -17
  9. package/dist/src/session.js +8 -3
  10. package/dist/ui/dist/assets/{abnfDiagram-WEYOIA3C-DztIEwNE.js → abnfDiagram-WEYOIA3C-BWgk01ve.js} +1 -1
  11. package/dist/ui/dist/assets/{arc-DUYh-EqZ.js → arc-Cg_Qb5c4.js} +1 -1
  12. package/dist/ui/dist/assets/{architecture-WOLXFQ4H-BQYTB92_.js → architecture-WOLXFQ4H-EdfV1etv.js} +1 -1
  13. package/dist/ui/dist/assets/{architectureDiagram-ZHVYKT53-Dl7095A5.js → architectureDiagram-ZHVYKT53-Dz-gytQU.js} +1 -1
  14. package/dist/ui/dist/assets/{blockDiagram-RJAE7QA3-QDZ5kE1J.js → blockDiagram-RJAE7QA3-B7Q5KhYC.js} +1 -1
  15. package/dist/ui/dist/assets/{c4Diagram-XDPPPE54-CKJZ1xOw.js → c4Diagram-XDPPPE54-Cq9IvGR1.js} +1 -1
  16. package/dist/ui/dist/assets/channel-Da0YvuQF.js +1 -0
  17. package/dist/ui/dist/assets/{chunk-2E7WHVMD-BXBjaqd1.js → chunk-2E7WHVMD-BTJB-4C8.js} +1 -1
  18. package/dist/ui/dist/assets/{chunk-4EMNKR2T-DPzfVuke.js → chunk-4EMNKR2T-BILthc2j.js} +1 -1
  19. package/dist/ui/dist/assets/{chunk-55XCU76K-B33Sj3w8.js → chunk-55XCU76K-DH3fYrJH.js} +1 -1
  20. package/dist/ui/dist/assets/{chunk-7S6XSTFO-B_u7dS03.js → chunk-7S6XSTFO-DDIiBvc2.js} +1 -1
  21. package/dist/ui/dist/assets/{chunk-AQDTSKZB-B4EzH5gx.js → chunk-AQDTSKZB-b1EeJ3gb.js} +1 -1
  22. package/dist/ui/dist/assets/{chunk-DSNLSHJZ-CfWeHABr.js → chunk-DSNLSHJZ-DZZ635s5.js} +1 -1
  23. package/dist/ui/dist/assets/{chunk-HAGFOTED-B8G8PjLZ.js → chunk-HAGFOTED-DhhrHTIh.js} +1 -1
  24. package/dist/ui/dist/assets/{chunk-HNE4Q36P-BA-PqoTF.js → chunk-HNE4Q36P-B8wvhc2e.js} +1 -1
  25. package/dist/ui/dist/assets/{chunk-NQOKRVIF-JvhuFcnR.js → chunk-NQOKRVIF-CLtGMwDx.js} +1 -1
  26. package/dist/ui/dist/assets/{chunk-UHW7PFBP-BrfL5CGY.js → chunk-UHW7PFBP-B9fVLGl0.js} +1 -1
  27. package/dist/ui/dist/assets/{chunk-VQ5W62QI-dBJqgdDy.js → chunk-VQ5W62QI-CgPvvMAv.js} +1 -1
  28. package/dist/ui/dist/assets/{chunk-WQQL4CDK-dfqd3k_P.js → chunk-WQQL4CDK-DdqKu6R9.js} +1 -1
  29. package/dist/ui/dist/assets/{chunk-XXDRQBXY-kViWdB9M.js → chunk-XXDRQBXY-GlM07vbp.js} +1 -1
  30. package/dist/ui/dist/assets/{chunk-YZO67HFG-ukfs4wT3.js → chunk-YZO67HFG-YqT6M0W9.js} +1 -1
  31. package/dist/ui/dist/assets/{chunk-ZAUX2LTX-BxZHki81.js → chunk-ZAUX2LTX-DqHK51Gc.js} +1 -1
  32. package/dist/ui/dist/assets/{chunk-ZCHMQSOR-PjluhR_E.js → chunk-ZCHMQSOR-DEeXkjWz.js} +1 -1
  33. package/dist/ui/dist/assets/{classDiagram-v2-4MYWR3UA-Ct89LJec.js → classDiagram-v2-4MYWR3UA-BcKsX4up.js} +1 -1
  34. package/dist/ui/dist/assets/{cose-bilkent-JH36ORCC-BnQceGmB.js → cose-bilkent-JH36ORCC-fu9djgYc.js} +1 -1
  35. package/dist/ui/dist/assets/{cynefin-EF2NZ3EQ-D6WkCVE8.js → cynefin-EF2NZ3EQ-CFJASBsJ.js} +1 -1
  36. package/dist/ui/dist/assets/{cynefinDiagram-WF24UDRP-dn6DUPAb.js → cynefinDiagram-WF24UDRP-BVJD_n0g.js} +1 -1
  37. package/dist/ui/dist/assets/{dagre-NK4GIZVX-BtZSlLk7.js → dagre-NK4GIZVX-Cx8pjz9O.js} +1 -1
  38. package/dist/ui/dist/assets/{diagram-CBK3MWTC-Ds4_tv6X.js → diagram-CBK3MWTC-CVIkEZ1X.js} +1 -1
  39. package/dist/ui/dist/assets/{diagram-I5XIIV2D-DcoVkg45.js → diagram-I5XIIV2D-2rxpF8BZ.js} +1 -1
  40. package/dist/ui/dist/assets/{diagram-ODIL2UCW-T47FAA3k.js → diagram-ODIL2UCW-NJfGHnLk.js} +1 -1
  41. package/dist/ui/dist/assets/{diagram-PFBEJUXE-CRZcaVKP.js → diagram-PFBEJUXE-DZHVJSeM.js} +1 -1
  42. package/dist/ui/dist/assets/{diagram-RJA3I4VV-D6KXeUPg.js → diagram-RJA3I4VV-CQAfOObI.js} +1 -1
  43. package/dist/ui/dist/assets/{diagram-TYUNFSNR-BHEIVyNN.js → diagram-TYUNFSNR-DGGaMOl6.js} +1 -1
  44. package/dist/ui/dist/assets/{dist-DLlKIWBp.js → dist-CW-4NrUq.js} +1 -1
  45. package/dist/ui/dist/assets/{ebnfDiagram-V4P3TTPT-nUDvYRBV.js → ebnfDiagram-V4P3TTPT-92pb2Fcg.js} +1 -1
  46. package/dist/ui/dist/assets/{elk-QONTBCTQ-D21BcRzc.js → elk-QONTBCTQ-vu0Z4rYG.js} +1 -1
  47. package/dist/ui/dist/assets/{erDiagram-KYQIGQAA-CTpHuftU.js → erDiagram-KYQIGQAA-BXnsRzCQ.js} +1 -1
  48. package/dist/ui/dist/assets/{eventmodeling-K75KTNOO-B6JaKuDY.js → eventmodeling-K75KTNOO-bSr88MT1.js} +1 -1
  49. package/dist/ui/dist/assets/flowDiagram-IUGLLWBU-CUH45H9n.js +1 -0
  50. package/dist/ui/dist/assets/{ganttDiagram-R7GPNTJY-D2-pMcnC.js → ganttDiagram-R7GPNTJY-BQzVkGbj.js} +1 -1
  51. package/dist/ui/dist/assets/{gitGraph-VSP46ZUC-B2yxwhEo.js → gitGraph-VSP46ZUC-BegblPQi.js} +1 -1
  52. package/dist/ui/dist/assets/{gitGraphDiagram-PDYL7XHY-DnrhBMH1.js → gitGraphDiagram-PDYL7XHY-BaGlGpEX.js} +1 -1
  53. package/dist/ui/dist/assets/{index-Dnte9tPd.js → index-D8ErIacA.js} +4 -4
  54. package/dist/ui/dist/assets/{info-OHQRW6UA-D8oh6gvs.js → info-OHQRW6UA-D3HVGJDc.js} +1 -1
  55. package/dist/ui/dist/assets/{infoDiagram-MVDRKAX5-BLSZjjgB.js → infoDiagram-MVDRKAX5-Ckcp-D0C.js} +1 -1
  56. package/dist/ui/dist/assets/{ishikawaDiagram-HPEHV2GE-BXiznLSn.js → ishikawaDiagram-HPEHV2GE-CWhd0CTS.js} +1 -1
  57. package/dist/ui/dist/assets/{journeyDiagram-BOSHW7O7-BSYmVcO_.js → journeyDiagram-BOSHW7O7-CrH5cFXY.js} +1 -1
  58. package/dist/ui/dist/assets/{kanban-definition-FNSA4HC5-COthkkzK.js → kanban-definition-FNSA4HC5-CpORMTDZ.js} +1 -1
  59. package/dist/ui/dist/assets/{line-6ND8OaOL.js → line-B3El9R0Z.js} +1 -1
  60. package/dist/ui/dist/assets/{linear-DbWEPFJX.js → linear-DLfthkbB.js} +1 -1
  61. package/dist/ui/dist/assets/{mermaid-parser.core-Btsk294z.js → mermaid-parser.core-QtQjLaoK.js} +3 -3
  62. package/dist/ui/dist/assets/{mermaid.core-B4llDSFO.js → mermaid.core-C2DGgMSc.js} +4 -4
  63. package/dist/ui/dist/assets/{mindmap-definition-6OY57UG3-hv2PfX-x.js → mindmap-definition-6OY57UG3-CW1lSXnX.js} +1 -1
  64. package/dist/ui/dist/assets/{packet-JDAUHWVQ-Dr4vBgjt.js → packet-JDAUHWVQ-Dhu_m_17.js} +1 -1
  65. package/dist/ui/dist/assets/{pegDiagram-ECIUJNBX-DvlFov3N.js → pegDiagram-ECIUJNBX-BGOhbzN4.js} +1 -1
  66. package/dist/ui/dist/assets/{pie-XZMESJXO-C9QsqC4n.js → pie-XZMESJXO-Citt3cMX.js} +1 -1
  67. package/dist/ui/dist/assets/{pieDiagram-GNMPY74T-CrrHOj67.js → pieDiagram-GNMPY74T-DPVZikvz.js} +1 -1
  68. package/dist/ui/dist/assets/{prism-core-Cc8H7LPG.js → prism-core-YgwsYh9d.js} +1 -1
  69. package/dist/ui/dist/assets/{quadrantDiagram-D57K4MC3-DQ7J6-ti.js → quadrantDiagram-D57K4MC3-Bwye1B9e.js} +1 -1
  70. package/dist/ui/dist/assets/{radar-ABXABTNO-BBBPaujh.js → radar-ABXABTNO-DRUb4G6V.js} +1 -1
  71. package/dist/ui/dist/assets/{railroad-I3PHUGI6-C-P6Igaz.js → railroad-I3PHUGI6-x3Ug2mxX.js} +1 -1
  72. package/dist/ui/dist/assets/{railroad-abnf-LNEFI6M7-CAkorRLs.js → railroad-abnf-LNEFI6M7-Dw14XhkZ.js} +1 -1
  73. package/dist/ui/dist/assets/{railroad-ebnf-DWYD2UWJ-D8Hz6gCf.js → railroad-ebnf-DWYD2UWJ-AwoWTWgL.js} +1 -1
  74. package/dist/ui/dist/assets/{railroad-peg-JR7BVNR7-D-XNMkOs.js → railroad-peg-JR7BVNR7-U7MXfciE.js} +1 -1
  75. package/dist/ui/dist/assets/{railroadDiagram-Y72NRBL7-DE9LwxJQ.js → railroadDiagram-Y72NRBL7-BxWlCZYs.js} +1 -1
  76. package/dist/ui/dist/assets/{requirementDiagram-EQYSW5RA-FrKFY6NJ.js → requirementDiagram-EQYSW5RA-TPmnZguV.js} +1 -1
  77. package/dist/ui/dist/assets/{sankeyDiagram-SY24JHO5-BDxI6RDX.js → sankeyDiagram-SY24JHO5-nPGftpl5.js} +1 -1
  78. package/dist/ui/dist/assets/{sequenceDiagram-BLEHNHQU-pV1XcKX7.js → sequenceDiagram-BLEHNHQU-BdctgaWa.js} +1 -1
  79. package/dist/ui/dist/assets/{src-snNJTXXq.js → src-zq235FjH.js} +1 -1
  80. package/dist/ui/dist/assets/{stateDiagram-v2-A6IESKWZ-BSc_5aAf.js → stateDiagram-v2-A6IESKWZ-BK_E6kPg.js} +1 -1
  81. package/dist/ui/dist/assets/{swimlanes-B3ENRKFQ-DC6qUXLh.js → swimlanes-B3ENRKFQ-BY50Ne4l.js} +1 -1
  82. package/dist/ui/dist/assets/swimlanesDiagram-AYQRV4AK-Ctw23I3i.js +8 -0
  83. package/dist/ui/dist/assets/{timeline-definition-JXYKGLGB-C8L0Dxtu.js → timeline-definition-JXYKGLGB-Bg8AXJ2P.js} +1 -1
  84. package/dist/ui/dist/assets/{treeView-D4JQ5SDB-DDyZIG5T.js → treeView-D4JQ5SDB-B4hz6M4l.js} +1 -1
  85. package/dist/ui/dist/assets/{treemap-SAJKECNS-CUaLgge0.js → treemap-SAJKECNS-e_Vc97Ox.js} +1 -1
  86. package/dist/ui/dist/assets/{usecaseDiagram-WPOLBNNX-BHRBd5pV.js → usecaseDiagram-WPOLBNNX-Butu_LCX.js} +1 -1
  87. package/dist/ui/dist/assets/{vennDiagram-Q3Y3IDCW-Du4iwwkh.js → vennDiagram-Q3Y3IDCW-BGIyxlbf.js} +1 -1
  88. package/dist/ui/dist/assets/{wardley-7MLQ67FV-DUgENI0s.js → wardley-7MLQ67FV-Btv95mqq.js} +1 -1
  89. package/dist/ui/dist/assets/{wardleyDiagram-IVAIDKWA-B86zOdke.js → wardleyDiagram-IVAIDKWA-DwTKExJ4.js} +1 -1
  90. package/dist/ui/dist/assets/{xychartDiagram-4URNHDU4-twq9irqO.js → xychartDiagram-4URNHDU4-UmlA5uxc.js} +1 -1
  91. package/dist/ui/dist/index.html +1 -1
  92. package/package.json +1 -1
  93. package/skills/follow-me/SKILL.md +7 -7
  94. package/dist/ui/dist/assets/channel-DF08Hd8f.js +0 -1
  95. package/dist/ui/dist/assets/flowDiagram-IUGLLWBU-BTeOUR-p.js +0 -1
  96. package/dist/ui/dist/assets/swimlanesDiagram-AYQRV4AK-F1HykV3o.js +0 -8
package/dist/src/plan.js CHANGED
@@ -556,12 +556,13 @@ function deriveConcernId(unit, c) {
556
556
  }
557
557
  /**
558
558
  * Gives every concern its id and checks where it sits: lines must be change lines the commit
559
- * takes, and a unit carries at most one concern across the whole plan.
559
+ * takes, and a unit carries at most one concern in each commit, so each slice of a hunk split
560
+ * across commits may carry its own.
560
561
  */
561
562
  function placeConcerns(diff, file, claims, issues) {
562
563
  const ids = new Set();
563
- const holders = new Map();
564
564
  const placedPerCommit = file.commits.map((commit, k) => {
565
+ const held = new Map();
565
566
  const placed = [];
566
567
  const add = (c, unit) => {
567
568
  const id = deriveConcernId(unit, c);
@@ -578,7 +579,7 @@ function placeConcerns(diff, file, claims, issues) {
578
579
  const concerns = ref.concerns ?? [];
579
580
  if (concerns.length === 0)
580
581
  return;
581
- holders.set(ref.unit, [...(holders.get(ref.unit) ?? []), ...concerns.map(() => k)]);
582
+ held.set(ref.unit, (held.get(ref.unit) ?? 0) + concerns.length);
582
583
  const taken = claims.resolved[k]?.[j]?.select;
583
584
  const unit = diff.units.get(ref.unit);
584
585
  for (const c of concerns) {
@@ -591,25 +592,25 @@ function placeConcerns(diff, file, claims, issues) {
591
592
  });
592
593
  continue;
593
594
  }
594
- const outside = taken?.kind === "lines" ? lines.filter((n) => !taken.changes.includes(n)) : [];
595
- if (outside.length > 0) {
595
+ const takes = taken?.kind === "lines" ? taken : null;
596
+ const outside = takes === null ? [] : lines.filter((n) => !takes.changes.includes(n));
597
+ if (takes !== null && outside.length > 0) {
596
598
  issues.push({
597
599
  kind: "bad-concern",
598
600
  commit: k,
599
- reason: `${ref.unit}: concern lines ${outside.join(", ")} are not change lines this commit takes`,
601
+ reason: `${ref.unit}: concern lines ${outside.join(", ")} are not change lines this commit takes; \`lines\` are the hunk's [n] as prompt.md shows them, on a slice too, and this commit takes ${formatUnitRef({ unit: ref.unit, select: takes })}`,
600
602
  });
601
603
  }
602
604
  else
603
605
  add(c, ref.unit);
604
606
  }
605
607
  });
608
+ for (const [unit, count] of held) {
609
+ if (count > 1)
610
+ issues.push({ kind: "too-many-concerns", unit, commit: k, count });
611
+ }
606
612
  return placed;
607
613
  });
608
- for (const [unit, commits] of holders) {
609
- if (commits.length > 1) {
610
- issues.push({ kind: "too-many-concerns", unit, commits: [...new Set(commits)] });
611
- }
612
- }
613
614
  return placedPerCommit;
614
615
  }
615
616
  /** "o_" + 8 hex over the unit and the label: stable while the offer stays at its place. */
@@ -744,6 +745,36 @@ function answerProblem(file, r, isQuestion) {
744
745
  * Parses and checks a draft against the diff: every change line used exactly once, every
745
746
  * commit's tree valid, and the last commit equal to the tip. Collects all issues at once.
746
747
  */
748
+ /**
749
+ * Sections read top-down: story, steps, details, wiring. A later section never comes back, so a
750
+ * commit whose section ranks below an earlier commit's must move ahead of the first such commit.
751
+ */
752
+ function sectionOrder(file) {
753
+ const issues = [];
754
+ const placed = [];
755
+ file.commits.forEach((c, commit) => {
756
+ if (c.section === undefined)
757
+ return;
758
+ const rank = SECTIONS.indexOf(c.section);
759
+ const first = placed.find((p) => p.rank > rank);
760
+ if (first !== undefined) {
761
+ issues.push({
762
+ kind: "section-order",
763
+ commit,
764
+ section: c.section,
765
+ before: first.commit,
766
+ beforeSection: first.section,
767
+ });
768
+ }
769
+ else
770
+ placed.push({ commit, rank, section: c.section });
771
+ });
772
+ return issues;
773
+ }
774
+ /**
775
+ * Judges a draft against the diff. `frozen` re-checks a plan that already passed when it was
776
+ * frozen: section order is a rule for drafts, so a plan frozen before it was one still fits.
777
+ */
747
778
  export function validatePlan(diff, draft, opts = {}) {
748
779
  const parsed = parsePlanFile(draft);
749
780
  if (Array.isArray(parsed))
@@ -766,6 +797,8 @@ export function validatePlan(diff, draft, opts = {}) {
766
797
  issues.push({ kind: "empty-commit", commit: k });
767
798
  });
768
799
  issues.push(...offerLimits(file));
800
+ if (opts.frozen !== true)
801
+ issues.push(...sectionOrder(file));
769
802
  const assignment = [];
770
803
  const claims = claim(diff, file, assignment);
771
804
  issues.push(...assignment);
@@ -788,17 +821,6 @@ export function validatePlan(diff, draft, opts = {}) {
788
821
  if (length > LONG_TITLE)
789
822
  warnings.push({ kind: "long-title", commit, length });
790
823
  });
791
- // Sections read top-down: story, steps, details, wiring. A later section never comes back.
792
- let reached = null;
793
- file.commits.forEach((c, commit) => {
794
- if (c.section === undefined)
795
- return;
796
- if (reached !== null && SECTIONS.indexOf(c.section) < SECTIONS.indexOf(reached)) {
797
- warnings.push({ kind: "section-order", commit, section: c.section, after: reached });
798
- }
799
- else
800
- reached = c.section;
801
- });
802
824
  const asked = new Map(review?.comments.map((c) => [c.id, c.kind === "question"]));
803
825
  for (const r of file.responses) {
804
826
  const isQuestion = asked.get(r.comment);
@@ -24,13 +24,34 @@ function formatSelection(unit, select) {
24
24
  function stripEol(text) {
25
25
  return text.replace(/\r?\n$/, "");
26
26
  }
27
- /** Under a "### path" heading the path is left out of each hunk's own line. */
28
- function renderHunk(hunk, withPath = true) {
29
- const lines = hunk.body.map((line) => line.op === " "
30
- ? ` ${stripEol(line.text)}`
31
- : `[${line.change}]${line.op} ${stripEol(line.text)}`);
32
- const where = withPath ? ` ${hunk.path}` : "";
33
- return [`${hunk.id}${where} (${hunk.changeCount} change lines)`, ...lines].join("\n");
27
+ /**
28
+ * Where a hunk's rows sit: "tip lines a-b", or "base lines a-b" when the tip keeps none of them.
29
+ * The header says it so `[n]`, a change index counted from 0, is not read as a line number.
30
+ */
31
+ function hunkSpan(hunk, tipStart) {
32
+ const kept = hunk.body.filter((line) => line.op !== "-").length;
33
+ const span = (side, from, count) => count === 1 ? `${side} line ${from}` : `${side} lines ${from}-${from + count - 1}`;
34
+ return kept > 0 ? span("tip", tipStart, kept) : span("base", hunk.oldStart + 1, hunk.body.length);
35
+ }
36
+ /**
37
+ * A hunk as `[n]+ text` and `[n]- text` rows, context indented. Under a "### path" heading the
38
+ * path is left out of the hunk's own line. With `gutter`, each row the tip keeps leads with its
39
+ * tip line number, which is what a `path:a-b` ref takes.
40
+ */
41
+ function renderHunk(hunk, units, opts = {}) {
42
+ const tipStart = tipStartOf(hunk, units);
43
+ let tipLine = tipStart;
44
+ const lines = hunk.body.map((line) => {
45
+ const row = line.op === " "
46
+ ? ` ${stripEol(line.text)}`
47
+ : `[${line.change}]${line.op} ${stripEol(line.text)}`;
48
+ if (!opts.gutter)
49
+ return row;
50
+ const number = line.op === "-" ? "" : `${tipLine++}`;
51
+ return `${number.padStart(5)} ${row}`;
52
+ });
53
+ const where = opts.withPath === false ? "" : ` ${hunk.path}`;
54
+ return [`${hunk.id}${where} ${hunkSpan(hunk, tipStart)}`, ...lines].join("\n");
34
55
  }
35
56
  function renderOtherUnit(unit) {
36
57
  if (unit.kind === "mode") {
@@ -44,8 +65,10 @@ function renderUnits(diff) {
44
65
  for (const unit of diff.units.values()) {
45
66
  byPath.set(unit.path, [...(byPath.get(unit.path) ?? []), unit]);
46
67
  }
47
- const files = [...byPath].map(([path, units]) => {
48
- const rendered = units.map((unit) => unit.kind === "hunk" ? renderHunk(unit, false) : renderOtherUnit(unit));
68
+ const files = [...byPath].map(([path, ofPath]) => {
69
+ const rendered = ofPath.map((unit) => unit.kind === "hunk"
70
+ ? renderHunk(unit, diff.units, { withPath: false })
71
+ : renderOtherUnit(unit));
49
72
  return [`### ${path}`, ...rendered].join("\n\n");
50
73
  });
51
74
  return files.join("\n\n");
@@ -208,8 +231,8 @@ function sessionLines(input) {
208
231
  `- check: ${input.checkCommand}`,
209
232
  ].join("\n");
210
233
  }
211
- function renderUnit(unit) {
212
- return unit.kind === "hunk" ? renderHunk(unit) : renderOtherUnit(unit);
234
+ function renderUnit(unit, units, gutter = false) {
235
+ return unit.kind === "hunk" ? renderHunk(unit, units, { gutter }) : renderOtherUnit(unit);
213
236
  }
214
237
  const QUOTE_LINES = 6;
215
238
  const QUOTE_WIDTH = 160;
@@ -268,7 +291,7 @@ function renderMoved(input, changes, head) {
268
291
  ].join("\n"));
269
292
  }
270
293
  if (added.length > 0) {
271
- sections.push(`## New units, in no commit yet\n\n${added.map(renderUnit).join("\n\n")}`);
294
+ sections.push(`## New units, in no commit yet\n\n${added.map((u) => renderUnit(u, units)).join("\n\n")}`);
272
295
  }
273
296
  const kept = draft.commits.flatMap((commit, k) => commit.units.map((ref) => {
274
297
  const path = units.get(ref.unit)?.path ?? "";
@@ -948,9 +971,10 @@ function folded(review, commits, units, opts) {
948
971
  export function renderReport(full, commits, units, opts) {
949
972
  const session = folded(full, commits, units, opts);
950
973
  const { ctx } = session;
974
+ const unkept = renderUnkept(session.review, ctx.commits);
951
975
  const excluded = session.review.excluded;
952
976
  if (excluded === undefined)
953
- return renderIncluded(session.review, ctx, opts);
977
+ return `${renderIncluded(session.review, ctx, opts)}${unkept}`;
954
978
  const noComments = new Set(excluded.comments);
955
979
  const noConcerns = new Set(excluded.concerns);
956
980
  const review = {
@@ -959,9 +983,26 @@ export function renderReport(full, commits, units, opts) {
959
983
  concerns: (session.review.concerns ?? []).filter((d) => !noConcerns.has(d.concern)),
960
984
  };
961
985
  const tail = renderExcluded(collectItems(session.review, ctx, opts.responses));
962
- const main = renderIncluded(review, ctx, opts);
986
+ const main = `${renderIncluded(review, ctx, opts)}${unkept}`;
963
987
  return tail.length === 0 ? main : `${main}${main.endsWith("\n") ? "" : "\n"}${tail.join("\n")}`;
964
988
  }
989
+ /**
990
+ * The agent's concerns the reviewer did not keep, by id, so the agent knows what the report left
991
+ * out: undecided ones (the page lists them at Submit) and dismissed ones. Empty when none.
992
+ */
993
+ function renderUnkept(review, commits) {
994
+ const decisions = new Map((review.concerns ?? []).map((d) => [d.concern, d.decision]));
995
+ const all = commits.flatMap((c) => c.concerns ?? []);
996
+ const undecided = all.filter((k) => !decisions.has(k.id)).map((k) => k.id);
997
+ const dismissed = all.filter((k) => decisions.get(k.id) === "dismissed").map((k) => k.id);
998
+ const parts = [
999
+ ...(undecided.length === 0 ? [] : [`${undecided.join(", ")} (undecided)`]),
1000
+ ...(dismissed.length === 0 ? [] : [`${dismissed.join(", ")} (dismissed)`]),
1001
+ ];
1002
+ if (parts.length === 0)
1003
+ return "";
1004
+ return `\nYour concerns the reviewer did not keep, left out of this report: ${parts.join("; ")}.\n`;
1005
+ }
965
1006
  function renderIncluded(review, ctx, opts) {
966
1007
  const { commits, units } = ctx;
967
1008
  const walk = review.mode === "walk";
@@ -1001,7 +1042,7 @@ function renderIncluded(review, ctx, opts) {
1001
1042
  if (started.length > 0)
1002
1043
  out.push(...renderThreads(ctx, started));
1003
1044
  if (walk && items.length > 0) {
1004
- out.push("Address each issue above in the code on this branch, then tell the reviewer what you changed and what you chose not to change and why.", "");
1045
+ out.push("This branch is someone else's, so leave its code alone. When the user asks, post this review to the merge request as porting.md beside the skill says.", "");
1005
1046
  }
1006
1047
  if (!walk && (feedback.length > 0 || questions.length > 0)) {
1007
1048
  out.push("Answer every comment id above in `responses` of the next draft, then run `follow-me check` and `follow-me apply`.", "");
@@ -1092,12 +1133,12 @@ export function renderEvents(events, ctx = null) {
1092
1133
  return `${events.flatMap((event) => renderEvent(event, ctx)).join("\n")}\n`;
1093
1134
  }
1094
1135
  /** A unit as prompt.md prints it, and which commits of the plan take its lines. */
1095
- export function renderShownUnit(unit, commits) {
1136
+ export function renderShownUnit(unit, units, commits) {
1096
1137
  const taken = commits.flatMap((commit, k) => commit.refs
1097
1138
  .filter((ref) => ref.unit === unit.id)
1098
1139
  .map((ref) => `commit ${k + 1} takes ${formatSelection(ref.unit, ref.select)}`));
1099
1140
  const where = taken.length === 0 ? "in no commit of the plan" : taken.join("; ");
1100
- return `${renderUnit(unit)}\n${where}\n`;
1141
+ return `${renderUnit(unit, units, true)}\n${where}\n`;
1101
1142
  }
1102
1143
  /** A comment with every row it was made on, its words and the whole thread under it. */
1103
1144
  export function renderShownComment(c, ctx, version) {
@@ -385,9 +385,14 @@ async function locate(repo, branch) {
385
385
  throw new Error("HEAD is detached; pass --branch <name>");
386
386
  const top = join(root, ".follow-me");
387
387
  mkdirSync(top, { recursive: true });
388
- const ignore = join(top, ".gitignore");
389
- if (!existsSync(ignore))
390
- writeFileSync(ignore, "*\n");
388
+ try {
389
+ // "wx" creates the file only if it is not there, so no check can go stale before the write.
390
+ writeFileSync(join(top, ".gitignore"), "*\n", { flag: "wx" });
391
+ }
392
+ catch (error) {
393
+ if (!(error instanceof Error && "code" in error && error.code === "EEXIST"))
394
+ throw error;
395
+ }
391
396
  return { root, branch: name, dir: join(top, slugOf(name)) };
392
397
  }
393
398
  function readAnchorIn(dir) {
@@ -1 +1 @@
1
- import{m as e,t}from"./mermaid-parser.core-Btsk294z.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-snNJTXXq.js";import"./chunk-DSNLSHJZ-CfWeHABr.js";import{n as i,r as a,t as o}from"./chunk-2E7WHVMD-BXBjaqd1.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-B4llDSFO.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
+ import{m as e,t}from"./mermaid-parser.core-QtQjLaoK.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-zq235FjH.js";import"./chunk-DSNLSHJZ-DZZ635s5.js";import{n as i,r as a,t as o}from"./chunk-2E7WHVMD-BTJB-4C8.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-C2DGgMSc.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-DLlKIWBp.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};
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-CW-4NrUq.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};
@@ -1 +1 @@
1
- import"./chunk-NGNAAXSQ-C2Wy9Xmz.js";export{M as createArchitectureServices}from"./mermaid-parser.core-Btsk294z.js";
1
+ import"./chunk-NGNAAXSQ-C2Wy9Xmz.js";export{M as createArchitectureServices}from"./mermaid-parser.core-QtQjLaoK.js";