@shiyuphan/follow-me 0.5.1 → 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.
Files changed (98) hide show
  1. package/README.md +6 -3
  2. package/dist/src/cli.js +18 -8
  3. package/dist/src/definition.js +226 -0
  4. package/dist/src/git.js +69 -13
  5. package/dist/src/plan.js +12 -1
  6. package/dist/src/prompt.js +22 -0
  7. package/dist/src/server.js +15 -0
  8. package/dist/src/types.js +2 -0
  9. package/dist/ui/dist/assets/{abnfDiagram-WEYOIA3C-8UsLPznO.js → abnfDiagram-WEYOIA3C-fYSYLdMl.js} +1 -1
  10. package/dist/ui/dist/assets/{arc-vovjGalz.js → arc-DGuGSnwa.js} +1 -1
  11. package/dist/ui/dist/assets/{architecture-WOLXFQ4H-BBMK-PUu.js → architecture-WOLXFQ4H-VFox_hV1.js} +1 -1
  12. package/dist/ui/dist/assets/{architectureDiagram-ZHVYKT53-Bw_ehaQk.js → architectureDiagram-ZHVYKT53-CBVK3nHZ.js} +1 -1
  13. package/dist/ui/dist/assets/{blockDiagram-RJAE7QA3-CAmD0wKf.js → blockDiagram-RJAE7QA3-BFdsIWEr.js} +1 -1
  14. package/dist/ui/dist/assets/{c4Diagram-XDPPPE54-DCP-3zgt.js → c4Diagram-XDPPPE54-BGntcPId.js} +1 -1
  15. package/dist/ui/dist/assets/channel-gz6cS9Z1.js +1 -0
  16. package/dist/ui/dist/assets/{chunk-2E7WHVMD-BiHSeJMu.js → chunk-2E7WHVMD-CNMuK9zj.js} +1 -1
  17. package/dist/ui/dist/assets/{chunk-4EMNKR2T-CR3lHKf_.js → chunk-4EMNKR2T-ByeTTJWS.js} +1 -1
  18. package/dist/ui/dist/assets/{chunk-55XCU76K-CtaoloTT.js → chunk-55XCU76K-99xE7cLH.js} +1 -1
  19. package/dist/ui/dist/assets/{chunk-7S6XSTFO-eABdc7fu.js → chunk-7S6XSTFO-ZVmT7eMZ.js} +1 -1
  20. package/dist/ui/dist/assets/{chunk-AQDTSKZB-CPlbJWi-.js → chunk-AQDTSKZB-B981JORL.js} +1 -1
  21. package/dist/ui/dist/assets/{chunk-DSNLSHJZ-YiMuxsb-.js → chunk-DSNLSHJZ-B2z7FX4h.js} +1 -1
  22. package/dist/ui/dist/assets/{chunk-HAGFOTED-1VcdL78a.js → chunk-HAGFOTED-CHFbBS-4.js} +1 -1
  23. package/dist/ui/dist/assets/{chunk-HNE4Q36P-u-sr_0Qu.js → chunk-HNE4Q36P-rq11xv9X.js} +1 -1
  24. package/dist/ui/dist/assets/{chunk-NQOKRVIF-C_QlWSze.js → chunk-NQOKRVIF-BYmg9kSX.js} +1 -1
  25. package/dist/ui/dist/assets/{chunk-UHW7PFBP-CNuZhsbU.js → chunk-UHW7PFBP-JvL9IXWg.js} +1 -1
  26. package/dist/ui/dist/assets/{chunk-VQ5W62QI-DAHWbLqU.js → chunk-VQ5W62QI-CYMQaAKn.js} +1 -1
  27. package/dist/ui/dist/assets/{chunk-WQQL4CDK-DWQnxFCd.js → chunk-WQQL4CDK-CXnR0PHT.js} +1 -1
  28. package/dist/ui/dist/assets/{chunk-XXDRQBXY-B0lGgSOR.js → chunk-XXDRQBXY-CDUWJCXi.js} +1 -1
  29. package/dist/ui/dist/assets/{chunk-YZO67HFG-BDw7efkN.js → chunk-YZO67HFG-mZfXIx0h.js} +1 -1
  30. package/dist/ui/dist/assets/{chunk-ZAUX2LTX-B5wfHsZv.js → chunk-ZAUX2LTX-DBxVTCHX.js} +1 -1
  31. package/dist/ui/dist/assets/{chunk-ZCHMQSOR--rWtYtAG.js → chunk-ZCHMQSOR-DrWA4IBo.js} +1 -1
  32. package/dist/ui/dist/assets/{classDiagram-v2-4MYWR3UA-BKuQ_xoS.js → classDiagram-v2-4MYWR3UA-Beah5uxA.js} +1 -1
  33. package/dist/ui/dist/assets/{cose-bilkent-JH36ORCC-Dk5fIpU0.js → cose-bilkent-JH36ORCC-UaE-jnHk.js} +1 -1
  34. package/dist/ui/dist/assets/{cynefin-EF2NZ3EQ-DIykJb2g.js → cynefin-EF2NZ3EQ-DKfGaCR8.js} +1 -1
  35. package/dist/ui/dist/assets/{cynefinDiagram-WF24UDRP-Cg8tBqUb.js → cynefinDiagram-WF24UDRP-tTUzTs3D.js} +1 -1
  36. package/dist/ui/dist/assets/{dagre-NK4GIZVX-BC_tnnjz.js → dagre-NK4GIZVX-jSn35_T7.js} +1 -1
  37. package/dist/ui/dist/assets/{diagram-CBK3MWTC-B_MQGixU.js → diagram-CBK3MWTC-7W2uw8Zc.js} +1 -1
  38. package/dist/ui/dist/assets/{diagram-I5XIIV2D-DO681pZ5.js → diagram-I5XIIV2D-CcfyQVh9.js} +1 -1
  39. package/dist/ui/dist/assets/{diagram-ODIL2UCW-D14jLzU6.js → diagram-ODIL2UCW-BjGvaLis.js} +1 -1
  40. package/dist/ui/dist/assets/{diagram-PFBEJUXE-cML48gUS.js → diagram-PFBEJUXE-jvdCrt8B.js} +1 -1
  41. package/dist/ui/dist/assets/{diagram-RJA3I4VV-DSoq8jFk.js → diagram-RJA3I4VV-D65_Vpi_.js} +1 -1
  42. package/dist/ui/dist/assets/{diagram-TYUNFSNR-CaJ4pvnl.js → diagram-TYUNFSNR-C52roQBE.js} +1 -1
  43. package/dist/ui/dist/assets/{dist-D3j-DODP.js → dist-BJd4jp9Y.js} +1 -1
  44. package/dist/ui/dist/assets/{ebnfDiagram-V4P3TTPT-CyRpjSix.js → ebnfDiagram-V4P3TTPT-DXysoIBq.js} +1 -1
  45. package/dist/ui/dist/assets/{elk-QONTBCTQ-ICJdzVFL.js → elk-QONTBCTQ-BVZcsgV3.js} +1 -1
  46. package/dist/ui/dist/assets/{erDiagram-KYQIGQAA-B57hNTfw.js → erDiagram-KYQIGQAA-BJnT4fVU.js} +1 -1
  47. package/dist/ui/dist/assets/{eventmodeling-K75KTNOO-BG8tUVIQ.js → eventmodeling-K75KTNOO-C5MzxCMY.js} +1 -1
  48. package/dist/ui/dist/assets/flowDiagram-IUGLLWBU-BqUgZSCz.js +1 -0
  49. package/dist/ui/dist/assets/{ganttDiagram-R7GPNTJY-Czt6Klik.js → ganttDiagram-R7GPNTJY-CZRrnuah.js} +1 -1
  50. package/dist/ui/dist/assets/{gitGraph-VSP46ZUC-De_ZWJLj.js → gitGraph-VSP46ZUC-l58aGSkh.js} +1 -1
  51. package/dist/ui/dist/assets/{gitGraphDiagram-PDYL7XHY-BMCJoOnT.js → gitGraphDiagram-PDYL7XHY-D4ks1WO-.js} +1 -1
  52. package/dist/ui/dist/assets/index-BW95UA5q.css +1 -0
  53. package/dist/ui/dist/assets/index-DOGXgoHF.js +134 -0
  54. package/dist/ui/dist/assets/{info-OHQRW6UA-D75H9kUq.js → info-OHQRW6UA-BSqfzkdk.js} +1 -1
  55. package/dist/ui/dist/assets/{infoDiagram-MVDRKAX5-Bsm_I9dt.js → infoDiagram-MVDRKAX5-B6NgVF_N.js} +1 -1
  56. package/dist/ui/dist/assets/{ishikawaDiagram-HPEHV2GE-98xZAJ9y.js → ishikawaDiagram-HPEHV2GE-DvtfssEZ.js} +1 -1
  57. package/dist/ui/dist/assets/{journeyDiagram-BOSHW7O7-BWVGuc0P.js → journeyDiagram-BOSHW7O7-DM64gT5v.js} +1 -1
  58. package/dist/ui/dist/assets/{kanban-definition-FNSA4HC5-DgUE_KDd.js → kanban-definition-FNSA4HC5-AliyRJHy.js} +1 -1
  59. package/dist/ui/dist/assets/{line-i__8Rvas.js → line-CHncXbKO.js} +1 -1
  60. package/dist/ui/dist/assets/{linear-BXKj0Fip.js → linear-BWEWydI0.js} +1 -1
  61. package/dist/ui/dist/assets/{mermaid-parser.core-DxvaorTa.js → mermaid-parser.core-DGpOP8AM.js} +3 -3
  62. package/dist/ui/dist/assets/{mermaid.core-ujYTsRZz.js → mermaid.core-BJtBFbJx.js} +4 -4
  63. package/dist/ui/dist/assets/{mindmap-definition-6OY57UG3-B7QD6sjk.js → mindmap-definition-6OY57UG3-NjavnWBi.js} +1 -1
  64. package/dist/ui/dist/assets/{packet-JDAUHWVQ-B6aIwfD1.js → packet-JDAUHWVQ-zuhpVsME.js} +1 -1
  65. package/dist/ui/dist/assets/{pegDiagram-ECIUJNBX-_RStHj-a.js → pegDiagram-ECIUJNBX-sL4grM97.js} +1 -1
  66. package/dist/ui/dist/assets/{pie-XZMESJXO-CNLC-pTe.js → pie-XZMESJXO-C9l1Mp09.js} +1 -1
  67. package/dist/ui/dist/assets/{pieDiagram-GNMPY74T-0uT7MT-u.js → pieDiagram-GNMPY74T-rlRBr2U4.js} +1 -1
  68. package/dist/ui/dist/assets/{prism-core-DtxziK1i.js → prism-core-DmuST30i.js} +1 -1
  69. package/dist/ui/dist/assets/{quadrantDiagram-D57K4MC3-CTMKb5hl.js → quadrantDiagram-D57K4MC3-4oQMip2Q.js} +1 -1
  70. package/dist/ui/dist/assets/{radar-ABXABTNO-D53h6I0N.js → radar-ABXABTNO-DvGg96L7.js} +1 -1
  71. package/dist/ui/dist/assets/{railroad-I3PHUGI6-CwjhW4mc.js → railroad-I3PHUGI6-8wdFKMZp.js} +1 -1
  72. package/dist/ui/dist/assets/{railroad-abnf-LNEFI6M7-DDbQ3RmB.js → railroad-abnf-LNEFI6M7-DUtOO0gn.js} +1 -1
  73. package/dist/ui/dist/assets/{railroad-ebnf-DWYD2UWJ-Am7YJAqO.js → railroad-ebnf-DWYD2UWJ-5YCGY1_d.js} +1 -1
  74. package/dist/ui/dist/assets/{railroad-peg-JR7BVNR7-Ci32KoVW.js → railroad-peg-JR7BVNR7-Bwywxjhs.js} +1 -1
  75. package/dist/ui/dist/assets/{railroadDiagram-Y72NRBL7-BPU5A6XW.js → railroadDiagram-Y72NRBL7-CwO6HSNQ.js} +1 -1
  76. package/dist/ui/dist/assets/{requirementDiagram-EQYSW5RA-_0Pq4QdV.js → requirementDiagram-EQYSW5RA-Cp0IbfNr.js} +1 -1
  77. package/dist/ui/dist/assets/{sankeyDiagram-SY24JHO5-c9h-7uf8.js → sankeyDiagram-SY24JHO5-DeQKsO68.js} +1 -1
  78. package/dist/ui/dist/assets/{sequenceDiagram-BLEHNHQU-B9-S4Rc9.js → sequenceDiagram-BLEHNHQU-DTDalCxF.js} +1 -1
  79. package/dist/ui/dist/assets/{src-BZ3kG7lO.js → src-XnrqevnL.js} +1 -1
  80. package/dist/ui/dist/assets/{stateDiagram-v2-A6IESKWZ-py1smSen.js → stateDiagram-v2-A6IESKWZ-2DZ-tKo9.js} +1 -1
  81. package/dist/ui/dist/assets/{swimlanes-B3ENRKFQ-C1E90aH4.js → swimlanes-B3ENRKFQ-66yZJeRU.js} +1 -1
  82. package/dist/ui/dist/assets/swimlanesDiagram-AYQRV4AK-rbX6bYG4.js +8 -0
  83. package/dist/ui/dist/assets/{timeline-definition-JXYKGLGB-DNe1To6B.js → timeline-definition-JXYKGLGB-Dm1xGU-d.js} +1 -1
  84. package/dist/ui/dist/assets/{treeView-D4JQ5SDB-D6MG89i6.js → treeView-D4JQ5SDB-BvgsbSot.js} +1 -1
  85. package/dist/ui/dist/assets/{treemap-SAJKECNS-CZpt7Mlh.js → treemap-SAJKECNS-C3lnbG1a.js} +1 -1
  86. package/dist/ui/dist/assets/{usecaseDiagram-WPOLBNNX-CKsv-03M.js → usecaseDiagram-WPOLBNNX-B6iPNIhZ.js} +1 -1
  87. package/dist/ui/dist/assets/{vennDiagram-Q3Y3IDCW-DGJ1qlyJ.js → vennDiagram-Q3Y3IDCW-D5dgflg9.js} +1 -1
  88. package/dist/ui/dist/assets/{wardley-7MLQ67FV-ClOzBemC.js → wardley-7MLQ67FV-Dn9mLIB4.js} +1 -1
  89. package/dist/ui/dist/assets/{wardleyDiagram-IVAIDKWA-C68ahPyF.js → wardleyDiagram-IVAIDKWA-W1EwzN_X.js} +1 -1
  90. package/dist/ui/dist/assets/{xychartDiagram-4URNHDU4-DWDamCoH.js → xychartDiagram-4URNHDU4-CKRzMUvp.js} +1 -1
  91. package/dist/ui/dist/index.html +2 -2
  92. package/package.json +1 -1
  93. package/skills/follow-me/SKILL.md +3 -1
  94. package/dist/ui/dist/assets/channel-B7CT_oIp.js +0 -1
  95. package/dist/ui/dist/assets/flowDiagram-IUGLLWBU--HPNoVQJ.js +0 -1
  96. package/dist/ui/dist/assets/index-B8TYcxF8.css +0 -1
  97. package/dist/ui/dist/assets/index-CYKbk4QS.js +0 -134
  98. package/dist/ui/dist/assets/swimlanesDiagram-AYQRV4AK-I98Q8AqP.js +0 -8
package/README.md CHANGED
@@ -69,8 +69,11 @@ If the hashes differ, `apply` exits with code 1. The commits are signed when you
69
69
 
70
70
  The red blob in the party hat is your branch tip. Nothing follow-me does moves it.
71
71
 
72
- ![The review page: one scrolling document of commits with the stack dropdown in the sticky header, a picked line with its Ask box, and an inline thread where the agent answers in Markdown with a diagram](assets/screenshots/review.png)
73
- *The review page. Pick any line, changed or not, or a range; Ask or Flag opens right under it. The agent answers inline in Markdown.*
72
+ ![The review page: the index on the left groups commits by section in top-down order, and commit 2 shows a question on a line with the agent's answer inline](assets/screenshots/review.png)
73
+ *The review page. The index groups the commits the way they read: the story first, then the steps it calls, then the details. Pick any line, changed or not, and Ask or Flag right under it; the agent answers inline.*
74
+
75
+ ![Cmd-clicking format in pow opens a peek of its definition, which lives outside this branch](assets/screenshots/definition.png)
76
+ *Cmd-click a name to jump to where it is defined, even in a later commit, and Alt+Left to come back. A definition the branch does not change opens as a peek.*
74
77
 
75
78
  ![A diagram opened in the lightbox at full size](assets/screenshots/diagram.png)
76
79
  *Diagrams sit full width under the commit or reply they explain, and open full size on click.*
@@ -78,7 +81,7 @@ The red blob in the party hat is your branch tip. Nothing follow-me does moves i
78
81
  ![The hand-off page: every kept item with its original-branch path and line, an include checkbox, and copy buttons](assets/screenshots/handoff.png)
79
82
  *Submit review. Each item carries the original branch's path and line, so your agent can post it to the merge request as is.*
80
83
 
81
- Keys: `j` and `k` move between commits, arrows and Shift+arrows pick rows inside a hunk, `c` comments on the pick, `v` marks a commit viewed, `?` lists the rest. An unfinished review autosaves and comes back when the page is opened again.
84
+ Keys: `[` shows or hides the index, `j` and `k` move between commits, Cmd-click (Ctrl-click) goes to a definition and Alt+Left comes back, arrows and Shift+arrows pick rows inside a hunk, `c` comments on the pick, `v` marks a commit viewed, `?` lists the rest. An unfinished review autosaves and comes back when the page is opened again.
82
85
 
83
86
  ### Reviewing someone else's branch
84
87
 
package/dist/src/cli.js CHANGED
@@ -3,13 +3,14 @@ import { readFileSync, writeFileSync } from "node:fs";
3
3
  import { homedir } from "node:os";
4
4
  import { dirname, join, relative } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
+ import { definitionIndex, isIdentifier } from "./definition.js";
6
7
  import { DiffParseError, formatUnitRef, isUnitId } from "./diff.js";
7
8
  import { BranchRefusedError, branchHead, GitError, isOwnWork, signing, treeOf, writeBranch, } from "./git.js";
8
9
  import { fetchCarried, fetchComments, fetchReport, findServer, followEvents, idleMs, listSessions, openBrowser, pollEvents, portFallbackMessage, postComment, postReply, probeHealth, readServerRecord, registerWith, sessionUrl, spawnDetached, startOrAttach, stateDir, stillHosted, stopServer, swapVersion, } from "./host.js";
9
10
  import { findSkillDir, InstallError, runInstall, runUninstall, syncSkills, } from "./install.js";
10
11
  import { naiveDraft } from "./naive.js";
11
12
  import { isCommentId, isConcernId, isFields, serializePlanFile, validatePlan, } from "./plan.js";
12
- import { renderEvents, renderPrompt, renderReport, renderShownComment, renderShownConcern, renderShownUnit, reportItems, } from "./prompt.js";
13
+ import { renderEvents, renderPrompt, renderReport, renderShownComment, renderShownConcern, renderShownDefinitions, renderShownUnit, reportItems, } from "./prompt.js";
13
14
  import { RegistrationError, sessionIdOf } from "./server.js";
14
15
  import { BranchMovedError, cleanSessions, extractSession, MissingDraftError, NotARepositoryError, openSession, SessionFileError, SessionLockedError, sessionComments, sinceLastPlan, } from "./session.js";
15
16
  import { checkSyntax } from "./syntax.js";
@@ -30,9 +31,10 @@ Other commands:
30
31
  Mermaid source
31
32
  explain [--commit <n>] [--unit <id>] [--lines <a-b>] --body <text> [--diagram <file>]
32
33
  start a thread on the page without being asked
33
- show <h_…|c_…|k_…|path:line[@n|@base]> print a unit, a comment's thread, a concern, or the
34
- lines around path:line in commit n, instead of
35
- reading files
34
+ show <h_…|c_…|k_…|path:line[@n|@base]|name>
35
+ print a unit, a comment's thread, a concern, the
36
+ lines around path:line in commit n, or where a name
37
+ is defined, instead of reading files
36
38
  report [--json] [--markdown] print the report of the latest review; --json lists
37
39
  the items to post to a merge request
38
40
 
@@ -85,11 +87,13 @@ Interactive loop (while the review page is open):
85
87
  --lines are change lines of the unit, commits count
86
88
  from 1; with no target it is about the whole plan.
87
89
  watch leaves these out like your replies
88
- show <h_…|c_…|k_…|path:line[@n|@base]> [--branch <name>]
90
+ show <h_…|c_…|k_…|path:line[@n|@base]|name> [--branch <name>]
89
91
  print a unit with the commits that take it, a
90
92
  comment with its rows and thread, a concern with its
91
- lines, or the lines around path:line at the tip, in
92
- commit n of the plan, or in the base
93
+ lines, the lines around path:line at the tip, in
94
+ commit n of the plan, or in the base, or each place
95
+ a name is defined at the tip with the commit it
96
+ lands in
93
97
  report [--json] [--markdown] [--branch <name>]
94
98
  print the report of the open review, or of the last
95
99
  one that ended. Markdown lists issues by file and
@@ -1516,7 +1520,7 @@ async function explain(cwd, args) {
1516
1520
  next(`run follow-me again; ${STILL_WORKING}`);
1517
1521
  return 0;
1518
1522
  }
1519
- const SHOW_USAGE = "usage: follow-me show <h_…|c_…|k_…|path:line[@<commit>|@base]>";
1523
+ const SHOW_USAGE = "usage: follow-me show <h_…|c_…|k_…|path:line[@<commit>|@base]|name>";
1520
1524
  /** Every comment the session has, with the plan version it was made on: live ones first. */
1521
1525
  async function knownComments(session) {
1522
1526
  const open = await openOnServer(session, null);
@@ -1629,6 +1633,12 @@ async function showRef(cwd, args) {
1629
1633
  }
1630
1634
  throw new UsageError(`no concern ${ref} in a plan that fits the branch`);
1631
1635
  }
1636
+ if (isIdentifier(ref)) {
1637
+ const commits = latest === undefined ? [] : projectedCommits(session, latest.version);
1638
+ const index = definitionIndex(session.root, session.diff.tip, units, commits);
1639
+ process.stdout.write(renderShownDefinitions(ref, await index.lookup(ref, null)));
1640
+ return 0;
1641
+ }
1632
1642
  process.stdout.write(showLines(session, ref));
1633
1643
  return 0;
1634
1644
  }
@@ -0,0 +1,226 @@
1
+ import { posix } from "node:path";
2
+ import { splitLines, tipStartOf } from "./diff.js";
3
+ import { blobsAt, grepTip } from "./git.js";
4
+ export const MAX_CANDIDATES = 10;
5
+ const PREVIEW_LINES = 8;
6
+ /** An ASCII identifier as JS, Python, Go, Rust, JVM languages, Ruby and C spell one. */
7
+ export function isIdentifier(s) {
8
+ return /^[A-Za-z_$][A-Za-z0-9_$]{0,127}$/.test(s);
9
+ }
10
+ const JS_MODS = "((static|async|public|private|protected|readonly|override|get|set)\\s+)*";
11
+ const RUST_VIS = "(pub([(][^)]*[)])?\\s+)?";
12
+ const JAVA_MODS = "((public|private|protected|static|final|abstract|synchronized|native|default|strictfp)\\s+)*";
13
+ const JVM_CLASS_MODS = "((public|private|protected|static|final|abstract|sealed|data|open|internal|inner|enum|annotation)\\s+)*";
14
+ const KOTLIN_MODS = "((public|private|protected|internal|override|open|abstract|suspend|inline|operator|infix|tailrec|external|actual|expect)\\s+)*";
15
+ const STATEMENT = /^\s*(return|new|throw|else|case|yield|await|typedef|delete|goto)\b/;
16
+ const LANGUAGES = [
17
+ {
18
+ extensions: [".js", ".jsx", ".mjs", ".cjs", ".ts", ".tsx", ".mts", ".cts"],
19
+ patterns: [
20
+ {
21
+ kind: "function",
22
+ source: "^\\s*(export\\s+)?(default\\s+)?(async\\s+)?function\\s*[*]?\\s*NAME\\s*[(<]",
23
+ },
24
+ {
25
+ kind: "const",
26
+ source: "^\\s*(export\\s+)?(declare\\s+)?(const|let|var)\\s+NAME\\s*(:[^=]*)?=",
27
+ },
28
+ {
29
+ kind: "class",
30
+ source: "^\\s*(export\\s+)?(default\\s+)?(declare\\s+)?(abstract\\s+)?class\\s+NAMEEND",
31
+ },
32
+ {
33
+ kind: "type",
34
+ source: "^\\s*(export\\s+)?(declare\\s+)?(interface|type|(const\\s+)?enum)\\s+NAMEEND",
35
+ },
36
+ {
37
+ kind: "method",
38
+ source: `^\\s+${JS_MODS}[*]?NAME\\s*(<[^>]*>)?[(].*[)]\\s*(:[^={;]+)?[{]\\s*$`,
39
+ reject: /^\s*(if|for|while|switch|catch|return)\b/,
40
+ },
41
+ ],
42
+ },
43
+ {
44
+ extensions: [".py", ".pyi"],
45
+ patterns: [
46
+ { kind: "function", source: "^(async\\s+)?def\\s+NAME\\s*[(]" },
47
+ { kind: "method", source: "^\\s+(async\\s+)?def\\s+NAME\\s*[(]" },
48
+ { kind: "class", source: "^\\s*class\\s+NAME\\s*[(:]" },
49
+ ],
50
+ },
51
+ {
52
+ extensions: [".go"],
53
+ patterns: [
54
+ { kind: "function", source: "^func\\s+NAME\\s*[[(]" },
55
+ { kind: "method", source: "^func\\s*[(][^)]*[)]\\s*NAME\\s*[[(]" },
56
+ { kind: "type", source: "^\\s*type\\s+NAMEEND" },
57
+ ],
58
+ },
59
+ {
60
+ extensions: [".rs"],
61
+ patterns: [
62
+ {
63
+ kind: "function",
64
+ source: `^${RUST_VIS}((const|async|unsafe|extern)\\s+("[^"]*"\\s+)?)*fn\\s+NAME\\s*[<(]`,
65
+ },
66
+ {
67
+ kind: "method",
68
+ source: `^\\s+${RUST_VIS}((const|async|unsafe|extern)\\s+("[^"]*"\\s+)?)*fn\\s+NAME\\s*[<(]`,
69
+ },
70
+ { kind: "class", source: `^\\s*${RUST_VIS}struct\\s+NAMEEND` },
71
+ { kind: "type", source: `^\\s*${RUST_VIS}(enum|trait|type)\\s+NAMEEND` },
72
+ { kind: "other", source: "^\\s*impl(<[^>]*>)?\\s+([A-Za-z0-9_:<>, ]+\\s+for\\s+)?NAMEEND" },
73
+ ],
74
+ },
75
+ {
76
+ extensions: [".java", ".kt", ".kts"],
77
+ patterns: [
78
+ { kind: "class", source: `^\\s*${JVM_CLASS_MODS}(class|object|record)\\s+NAMEEND` },
79
+ { kind: "type", source: `^\\s*${JVM_CLASS_MODS}(interface|enum|@interface)\\s+NAMEEND` },
80
+ {
81
+ kind: "function",
82
+ source: `^\\s*${KOTLIN_MODS}fun\\s+(<[^>]*>\\s*)?([A-Za-z0-9_.<>]+[.])?NAME\\s*[(]`,
83
+ },
84
+ {
85
+ kind: "method",
86
+ source: `^\\s*${JAVA_MODS}(<[^>]*>\\s+)?[A-Za-z_][A-Za-z0-9_<>,.?]*(\\[\\])*\\s+NAME\\s*[(][^;]*$`,
87
+ reject: STATEMENT,
88
+ },
89
+ ],
90
+ },
91
+ {
92
+ extensions: [".rb"],
93
+ patterns: [
94
+ { kind: "method", source: "^\\s*def\\s+(self[.])?NAMEEND" },
95
+ { kind: "class", source: "^\\s*class\\s+NAMEEND" },
96
+ { kind: "other", source: "^\\s*module\\s+NAMEEND" },
97
+ ],
98
+ },
99
+ {
100
+ extensions: [".c", ".h", ".cc", ".cpp", ".cxx", ".hh", ".hpp", ".hxx"],
101
+ patterns: [
102
+ {
103
+ kind: "function",
104
+ source: "^[A-Za-z_][A-Za-z0-9_ *&<>,:~]*[ *&]([A-Za-z_][A-Za-z0-9_]*::)*NAME\\s*[(][^;]*$",
105
+ reject: STATEMENT,
106
+ },
107
+ { kind: "function", source: "^NAME\\s*[(][^;]*$" },
108
+ { kind: "class", source: "^\\s*(typedef\\s+)?(struct|class|union)\\s+NAME\\s*([{:]|$)" },
109
+ { kind: "type", source: "^\\s*(typedef\\s+)?enum\\s+(class\\s+)?NAME\\s*([{:]|$)" },
110
+ ],
111
+ },
112
+ ];
113
+ const END = "([^A-Za-z0-9_$]|$)";
114
+ function spell(source, name) {
115
+ return source
116
+ .replaceAll("NAMEEND", `${name.replaceAll("$", "[$]")}${END}`)
117
+ .replaceAll("NAME", name.replaceAll("$", "[$]"));
118
+ }
119
+ function toEre(source) {
120
+ return source.replaceAll("\\s", "[[:space:]]");
121
+ }
122
+ function languageOf(path) {
123
+ const ext = posix.extname(path).toLowerCase();
124
+ return LANGUAGES.find((l) => l.extensions.includes(ext)) ?? null;
125
+ }
126
+ /** What the match defines by the patterns of its file's language, or null when it is no definition. */
127
+ function kindOf(match, name) {
128
+ const language = languageOf(match.path);
129
+ if (language === null)
130
+ return null;
131
+ const hit = language.patterns.find((p) => new RegExp(spell(p.source, name)).test(match.text) && !p.reject?.test(match.text));
132
+ return hit?.kind ?? null;
133
+ }
134
+ /** Same file as `from` first, then the same directory, then the rest, each in path and line order. */
135
+ export function rank(found, from) {
136
+ const tier = (path) => {
137
+ if (from === null)
138
+ return 2;
139
+ if (path === from)
140
+ return 0;
141
+ return posix.dirname(path) === posix.dirname(from) ? 1 : 2;
142
+ };
143
+ return found
144
+ .map((f, i) => ({ f, i, t: tier(f.path) }))
145
+ .sort((a, b) => a.t - b.t || a.i - b.i)
146
+ .map(({ f }) => f);
147
+ }
148
+ const NOWHERE = { unit: null, row: null, commit: null };
149
+ /**
150
+ * The hunk row that holds tip line `line` of `path`, and the commit that writes it: the owner of a
151
+ * change row, or the first commit taking the unit for a context row.
152
+ */
153
+ export function place(units, commits, path, line) {
154
+ for (const unit of units.values()) {
155
+ if (unit.kind !== "hunk" || unit.path !== path)
156
+ continue;
157
+ const row = rowAt(unit, tipStartOf(unit, units), line);
158
+ if (row === null)
159
+ continue;
160
+ const body = unit.body[row];
161
+ const change = body !== undefined && body.op !== " " ? body.change : null;
162
+ const takes = (c) => c.refs.some((r) => r.unit === unit.id &&
163
+ (change === null || r.select.kind === "rest" || r.select.changes.includes(change)));
164
+ const k = commits.findIndex(takes);
165
+ return { unit: unit.id, row, commit: k === -1 ? null : k };
166
+ }
167
+ return NOWHERE;
168
+ }
169
+ function rowAt(hunk, tipStart, line) {
170
+ let tipLine = tipStart;
171
+ for (const [row, body] of hunk.body.entries()) {
172
+ if (body.op === "-")
173
+ continue;
174
+ if (tipLine === line)
175
+ return row;
176
+ tipLine += 1;
177
+ }
178
+ return null;
179
+ }
180
+ function stripEol(line) {
181
+ return line.replace(/\r?\n$/, "");
182
+ }
183
+ /**
184
+ * Where names are defined at one branch tip and where each lands in the plan. Built per hosted
185
+ * version, so a swap starts a fresh one; matches are cached per name and file lines per path.
186
+ */
187
+ export function definitionIndex(repo, tip, units, commits) {
188
+ const foundByName = new Map();
189
+ const linesByPath = new Map();
190
+ const find = (name) => {
191
+ const cached = foundByName.get(name);
192
+ if (cached !== undefined)
193
+ return cached;
194
+ const patterns = [
195
+ ...new Set(LANGUAGES.flatMap((l) => l.patterns.map((p) => toEre(spell(p.source, name))))),
196
+ ];
197
+ const pathspecs = LANGUAGES.flatMap((l) => l.extensions.map((e) => `*${e}`));
198
+ const found = grepTip(repo, tip, patterns, pathspecs).then((matches) => matches.flatMap((m) => {
199
+ const kind = kindOf(m, name);
200
+ return kind === null ? [] : [{ path: m.path, newLine: m.line, kind }];
201
+ }));
202
+ foundByName.set(name, found);
203
+ // A failed grep is not an answer; the next request tries again.
204
+ found.catch(() => foundByName.delete(name));
205
+ return found;
206
+ };
207
+ const load = async (paths) => {
208
+ const missing = [...new Set(paths)].filter((p) => !linesByPath.has(p));
209
+ if (missing.length === 0)
210
+ return;
211
+ for (const [path, bytes] of await blobsAt(repo, tip, missing)) {
212
+ linesByPath.set(path, splitLines(bytes).map(stripEol));
213
+ }
214
+ };
215
+ return {
216
+ lookup: async (name, from) => {
217
+ const ranked = rank(await find(name), from).slice(0, MAX_CANDIDATES);
218
+ await load(ranked.map((f) => f.path));
219
+ return ranked.map((f) => ({
220
+ ...f,
221
+ ...place(units, commits, f.path, f.newLine),
222
+ preview: (linesByPath.get(f.path) ?? []).slice(f.newLine - 1, f.newLine - 1 + PREVIEW_LINES),
223
+ }));
224
+ },
225
+ };
226
+ }
package/dist/src/git.js CHANGED
@@ -1,13 +1,16 @@
1
1
  import { execFile } from "node:child_process";
2
2
  import { link, mkdir, mkdtemp, readdir, rm } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
- import { isSha, neededBlobs, parseDiff } from "./diff.js";
4
+ import { isRepoPath, isSha, neededBlobs, parseDiff } from "./diff.js";
5
5
  export class GitError extends Error {
6
6
  name = "GitError";
7
7
  args;
8
- constructor(args, stderr) {
8
+ /** git's exit status, or null when it did not run or was killed. */
9
+ status;
10
+ constructor(args, stderr, status = null) {
9
11
  super(`git ${args.join(" ")}: ${stderr}`);
10
12
  this.args = args;
13
+ this.status = status;
11
14
  }
12
15
  }
13
16
  function git(repo, args, opts = {}) {
@@ -18,8 +21,10 @@ function git(repo, args, opts = {}) {
18
21
  maxBuffer: 1 << 30,
19
22
  env: { ...process.env, ...opts.env },
20
23
  }, (error, stdout, stderr) => {
21
- if (error)
22
- reject(new GitError(args, stderr.toString("utf8").trim() || error.message));
24
+ if (error) {
25
+ const status = typeof error.code === "number" ? error.code : null;
26
+ reject(new GitError(args, stderr.toString("utf8").trim() || error.message, status));
27
+ }
23
28
  else
24
29
  resolve(stdout);
25
30
  });
@@ -97,25 +102,76 @@ export async function defaultBaseRef(repo) {
97
102
  }
98
103
  throw new Error("neither main nor master exists; pass --base <ref>");
99
104
  }
100
- async function catBlobs(repo, shas) {
101
- const blobs = new Map();
102
- if (shas.length === 0)
103
- return blobs;
104
- const out = await git(repo, ["cat-file", "--batch"], { input: `${shas.join("\n")}\n` });
105
+ /** The blob named by each object spec, in order, as latin1; throws when one is not a blob. */
106
+ async function catBatch(repo, specs) {
107
+ if (specs.length === 0)
108
+ return [];
109
+ const input = Buffer.from(`${specs.join("\n")}\n`, "latin1");
110
+ const out = await git(repo, ["cat-file", "--batch"], { input });
111
+ const blobs = [];
105
112
  let at = 0;
106
- for (const sha of shas) {
113
+ for (const spec of specs) {
107
114
  const nl = out.indexOf(0x0a, at);
108
115
  const header = out.subarray(at, nl).toString("latin1");
109
116
  const m = /^([0-9a-f]+) blob (\d+)$/.exec(header);
110
- if (nl === -1 || m === null || m[1] !== sha) {
111
- throw new Error(`cat-file returned "${header}" for ${sha}`);
117
+ if (nl === -1 || m === null || (isSha(spec) && m[1] !== spec)) {
118
+ throw new Error(`cat-file returned "${header}" for ${spec}`);
112
119
  }
113
120
  const size = Number(m[2]);
114
- blobs.set(sha, out.subarray(nl + 1, nl + 1 + size).toString("latin1"));
121
+ blobs.push(out.subarray(nl + 1, nl + 1 + size).toString("latin1"));
115
122
  at = nl + 1 + size + 1;
116
123
  }
117
124
  return blobs;
118
125
  }
126
+ async function catBlobs(repo, shas) {
127
+ const blobs = await catBatch(repo, shas);
128
+ return new Map(shas.map((sha, i) => [sha, blobs[i] ?? ""]));
129
+ }
130
+ /** Each path's bytes at the commit, as latin1. */
131
+ export async function blobsAt(repo, commit, paths) {
132
+ const blobs = await catBatch(repo, paths.map((p) => `${commit}:${p}`));
133
+ return new Map(paths.map((p, i) => [p, blobs[i] ?? ""]));
134
+ }
135
+ /**
136
+ * Lines of the commit's tree, not the working tree, that match any of the POSIX extended
137
+ * patterns, in files matching the pathspecs. Binary files are skipped.
138
+ */
139
+ export async function grepTip(repo, commit, patterns, pathspecs) {
140
+ const args = [
141
+ "grep",
142
+ "-n",
143
+ "-E",
144
+ "-I",
145
+ "-z",
146
+ "--no-color",
147
+ "--no-column",
148
+ ...patterns.flatMap((p) => ["-e", p]),
149
+ commit,
150
+ "--",
151
+ ...pathspecs,
152
+ ];
153
+ let out;
154
+ try {
155
+ out = await git(repo, args);
156
+ }
157
+ catch (error) {
158
+ // grep exits 1 when nothing matched.
159
+ if (error instanceof GitError && error.status === 1)
160
+ return [];
161
+ throw error;
162
+ }
163
+ const prefix = `${commit}:`;
164
+ return out
165
+ .toString("latin1")
166
+ .split("\n")
167
+ .flatMap((record) => {
168
+ const [name = "", line = "", ...text] = record.split("\0");
169
+ const path = name.slice(prefix.length);
170
+ if (!name.startsWith(prefix) || !isRepoPath(path) || !/^\d+$/.test(line))
171
+ return [];
172
+ return [{ path, line: Number(line), text: text.join("\0") }];
173
+ });
174
+ }
119
175
  const DIFF_FLAGS = ["--no-renames", "--full-index", "--no-color", "--no-ext-diff", "--no-textconv"];
120
176
  export async function loadDiff(repo, baseRef, tipRef) {
121
177
  const [tip, baseCommit] = await Promise.all([
package/dist/src/plan.js CHANGED
@@ -17,6 +17,10 @@ const STATUSES = ["addressed", "declined", "deferred", "answered"];
17
17
  function isResponseStatus(s) {
18
18
  return STATUSES.some((x) => x === s);
19
19
  }
20
+ const SECTIONS = ["story", "steps", "details", "wiring"];
21
+ function isCommitSection(s) {
22
+ return SECTIONS.some((x) => x === s);
23
+ }
20
24
  const SEVERITIES = ["blocker", "major", "minor"];
21
25
  const CONCERN_KINDS = ["bug", "missing-test", "naming", "risk"];
22
26
  export function isSeverity(s) {
@@ -223,6 +227,10 @@ export function parsePlanFile(draft) {
223
227
  }
224
228
  if (typeof c.message !== "string")
225
229
  bad(`${at}.message`, "expected a string");
230
+ const section = c.section ?? null;
231
+ if (section !== null && !isCommitSection(section)) {
232
+ bad(`${at}.section`, `expected one of ${SECTIONS.join(", ")}`);
233
+ }
226
234
  const extras = parseExtras(c, false);
227
235
  if ("error" in extras)
228
236
  bad(`${at}.${extras.field}`, extras.error);
@@ -239,7 +247,8 @@ export function parsePlanFile(draft) {
239
247
  }
240
248
  }
241
249
  if (typeof c.message === "string" && !("error" in extras)) {
242
- commits.push({ message: c.message, ...extras, units });
250
+ const placed = isCommitSection(section) ? { section } : {};
251
+ commits.push({ message: c.message, ...placed, ...extras, units });
243
252
  }
244
253
  }
245
254
  }
@@ -287,6 +296,7 @@ export function serializePlanFile(file) {
287
296
  tip: file.tip,
288
297
  commits: file.commits.map((c) => ({
289
298
  message: c.message,
299
+ ...(c.section === undefined ? {} : { section: c.section }),
290
300
  ...serializeExtras(c),
291
301
  units: c.units.map((ref) => ref.narration === undefined && ref.diagram === undefined && ref.concerns === undefined
292
302
  ? formatUnitRef(ref)
@@ -578,6 +588,7 @@ function project(diff, file, claims, issues) {
578
588
  return {
579
589
  index: k,
580
590
  message: commit.message,
591
+ ...(commit.section === undefined ? {} : { section: commit.section }),
581
592
  ...withText(commit.narration ?? null, commit.diagram ?? null),
582
593
  ...(mine.length === 0 ? {} : { concerns: mine }),
583
594
  refs,
@@ -1065,3 +1065,25 @@ export function renderShownConcern(concern, commit, ctx) {
1065
1065
  "",
1066
1066
  ].join("\n");
1067
1067
  }
1068
+ function utf8(latin1) {
1069
+ return Buffer.from(latin1, "latin1").toString("utf8");
1070
+ }
1071
+ /** Where a name is defined, each with the commit it lands in and its first lines at the tip. */
1072
+ export function renderShownDefinitions(name, candidates) {
1073
+ if (candidates.length === 0)
1074
+ return `no definition of ${name} at the tip\n`;
1075
+ return `${candidates
1076
+ .flatMap((c) => {
1077
+ const where = c.commit !== null
1078
+ ? `in commit ${c.commit + 1}`
1079
+ : c.unit !== null
1080
+ ? `in ${c.unit}, which no commit of the plan takes`
1081
+ : "unchanged by the branch";
1082
+ const width = String(c.newLine + c.preview.length - 1).length;
1083
+ return [
1084
+ `${utf8(c.path)}:${c.newLine} ${c.kind}, ${where}`,
1085
+ ...c.preview.map((l, i) => ` ${String(c.newLine + i).padStart(width)} ${utf8(l)}`),
1086
+ ];
1087
+ })
1088
+ .join("\n")}\n`;
1089
+ }
@@ -5,6 +5,8 @@ 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";
8
10
  import { carryConcerns, carrySession } from "./evolve.js";
9
11
  import { isConcernId, isPlanVersion } from "./plan.js";
10
12
  import { renderReport, reportItems } from "./prompt.js";
@@ -255,6 +257,7 @@ function viewOf(registration, loaded, draft, earlier = loaded.earlier) {
255
257
  unitIds: new Set(state.units.map((u) => u.id)),
256
258
  hunkRows: new Map(state.units.flatMap((u) => u.kind === "hunk" ? [[u.id, u.body.length]] : [])),
257
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),
258
261
  draftFile: draftPath(reviewsDir, state.version),
259
262
  reviewFile: join(reviewsDir, `v${state.version}.json`),
260
263
  };
@@ -544,6 +547,11 @@ function hostSession(id, registration, loaded, draft, load) {
544
547
  return waitForEvents(since, timeoutMs, signal);
545
548
  },
546
549
  report: () => report(review()),
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: [] }));
554
+ },
547
555
  reportItems: () => reportItems(review(), view.loaded.state.commits, unitsOf(), reportOptions()),
548
556
  add: async (raw) => {
549
557
  open();
@@ -943,6 +951,13 @@ export function startServer(opts) {
943
951
  const timeout = queryInt(url, "timeout", 0, MAX_POLL_MS, DEFAULT_POLL_MS);
944
952
  return sendJson(res, 200, await session.poll(since, timeout, abort.signal));
945
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
+ }
946
961
  if (method === "GET" && rest === "/api/report" && url.searchParams.get("format") === "json") {
947
962
  return sendJson(res, 200, session.reportItems());
948
963
  }
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.
@@ -1 +1 @@
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
+ 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-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};
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};
@@ -1 +1 @@
1
- import"./chunk-NGNAAXSQ-C2Wy9Xmz.js";export{M as createArchitectureServices}from"./mermaid-parser.core-DxvaorTa.js";
1
+ import"./chunk-NGNAAXSQ-C2Wy9Xmz.js";export{M as createArchitectureServices}from"./mermaid-parser.core-DGpOP8AM.js";