@diffohq/diffo 0.9.0 → 0.10.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 (95) hide show
  1. package/dist/cli.mjs +163 -39
  2. package/dist/client/assets/{abnfDiagram-O67JEVCF-Dh4is2Nj.js → abnfDiagram-O67JEVCF-DBlSJW53.js} +1 -1
  3. package/dist/client/assets/{arc-CMN0Gb1g.js → arc-BZZ_ET2N.js} +1 -1
  4. package/dist/client/assets/architecture-7GRP2DOG-Cds-sOVr.js +1 -0
  5. package/dist/client/assets/{architectureDiagram-NJMV4G6O-DxVGDSE1.js → architectureDiagram-NJMV4G6O-CmS7e2K4.js} +1 -1
  6. package/dist/client/assets/{blockDiagram-BEXU5L5S-T1F9hSwZ.js → blockDiagram-BEXU5L5S-Kj8H2ODF.js} +1 -1
  7. package/dist/client/assets/{c4Diagram-YGBWAQC7-DC6zwYuX.js → c4Diagram-YGBWAQC7-CixbFJxb.js} +1 -1
  8. package/dist/client/assets/channel-BI4dhOPo.js +1 -0
  9. package/dist/client/assets/{chunk-3FUC2YCW-D0PAoCRl.js → chunk-3FUC2YCW-CRdo0Gw5.js} +1 -1
  10. package/dist/client/assets/{chunk-5DYCD2WN-NqHzOtt0.js → chunk-5DYCD2WN-Bw9n6qPh.js} +1 -1
  11. package/dist/client/assets/{chunk-742MDFTN-B9Y5HHB7.js → chunk-742MDFTN-BsvOSyDz.js} +1 -1
  12. package/dist/client/assets/{chunk-7INBJB4K-CBOWlj91.js → chunk-7INBJB4K-ie7EoCoW.js} +1 -1
  13. package/dist/client/assets/{chunk-7M6MHVWA-D2dZ_rQI.js → chunk-7M6MHVWA-DJlbYDLH.js} +1 -1
  14. package/dist/client/assets/{chunk-7PRAP22T-7dilu8x-.js → chunk-7PRAP22T-Hs5y39V8.js} +1 -1
  15. package/dist/client/assets/{chunk-GTNCS2PH-at0ENjhB.js → chunk-GTNCS2PH-DNq6Ojc7.js} +1 -1
  16. package/dist/client/assets/{chunk-GWA4HPMP-C06n_37U.js → chunk-GWA4HPMP-vgn0kxbp.js} +1 -1
  17. package/dist/client/assets/{chunk-MBY4JIJT-DuowBunG.js → chunk-MBY4JIJT-C7fMuqSl.js} +1 -1
  18. package/dist/client/assets/{chunk-NETBCI7D-ClNA7QFH.js → chunk-NETBCI7D-ZJtjvGwt.js} +1 -1
  19. package/dist/client/assets/{chunk-O7XYJQB3-BjcjInBL.js → chunk-O7XYJQB3-DESjnZZT.js} +1 -1
  20. package/dist/client/assets/{chunk-UA2S7LBM-B-PAn1hd.js → chunk-UA2S7LBM-Cmf087s8.js} +1 -1
  21. package/dist/client/assets/{chunk-WEXAMYUT-Br84uK4B.js → chunk-WEXAMYUT-U1TW5ZAF.js} +1 -1
  22. package/dist/client/assets/{chunk-XXDRQBXY-BbBZykgX.js → chunk-XXDRQBXY-D1B1IYm1.js} +1 -1
  23. package/dist/client/assets/{chunk-Z7XXMR3K-CQ-grwfe.js → chunk-Z7XXMR3K-D3BUH0qv.js} +1 -1
  24. package/dist/client/assets/{chunk-ZIGJFQKS-CLwfE-hs.js → chunk-ZIGJFQKS-Bx6yZhwg.js} +1 -1
  25. package/dist/client/assets/{classDiagram-v2-NBCMYWYE-DD-bcOHO.js → classDiagram-v2-NBCMYWYE-sjiBGJdD.js} +1 -1
  26. package/dist/client/assets/{core-BADyutHL.js → core-6IJUkucC.js} +1 -1
  27. package/dist/client/assets/{cose-bilkent-JH36ORCC-fuMg3J_l.js → cose-bilkent-JH36ORCC-xaMCCs4V.js} +1 -1
  28. package/dist/client/assets/{cynefin-OW5HDTMX-DwFXJ_x8.js → cynefin-OW5HDTMX-C5k9L5NF.js} +1 -1
  29. package/dist/client/assets/{cynefinDiagram-VND7K2PF-cGL_k8gj.js → cynefinDiagram-VND7K2PF-BqiILl4G.js} +1 -1
  30. package/dist/client/assets/{dagre-6A5THRUB-BetgCBn9.js → dagre-6A5THRUB-BtgX5KvU.js} +1 -1
  31. package/dist/client/assets/{diagram-22UHCM2B-C7qT2Ix2.js → diagram-22UHCM2B-BcDIKY8C.js} +1 -1
  32. package/dist/client/assets/{diagram-3UASUU5V-DGUO9DWV.js → diagram-3UASUU5V-C-DrBJ6K.js} +1 -1
  33. package/dist/client/assets/{diagram-ATOU4E4O-f520gjx5.js → diagram-ATOU4E4O-B0W6FX6y.js} +1 -1
  34. package/dist/client/assets/{diagram-CDSNMT55-Dhrm4GzB.js → diagram-CDSNMT55-D1O9NYQ3.js} +1 -1
  35. package/dist/client/assets/{diagram-MLGK6HIB-Di0aRiuU.js → diagram-MLGK6HIB-WC8izmk2.js} +1 -1
  36. package/dist/client/assets/{diagram-MPIPVDR6-BHhVZUxI.js → diagram-MPIPVDR6-D5ko9V-k.js} +1 -1
  37. package/dist/client/assets/{dist-Cezvykkn.js → dist-BBmACywa.js} +1 -1
  38. package/dist/client/assets/{dist-CbdYocyN.js → dist-Bss8uvIz.js} +1 -1
  39. package/dist/client/assets/{ebnfDiagram-ZINNZB2B-CQA0eib_.js → ebnfDiagram-ZINNZB2B-BFIYDkrv.js} +1 -1
  40. package/dist/client/assets/{elk-276RUBZZ-CZKKVSu0.js → elk-276RUBZZ-WsSc0CyB.js} +1 -1
  41. package/dist/client/assets/{engine-oniguruma-B68c_YAs.js → engine-oniguruma-DmL6leO7.js} +1 -1
  42. package/dist/client/assets/{erDiagram-OPXOYQCR-DcNnfq_S.js → erDiagram-OPXOYQCR-CjaKeGKh.js} +1 -1
  43. package/dist/client/assets/eventmodeling-NTZA5JFV-DE5ql6lo.js +1 -0
  44. package/dist/client/assets/flowDiagram-KWPJA3E3-CObKVtKJ.js +1 -0
  45. package/dist/client/assets/{ganttDiagram-FUAMR5RP-Dteh33ci.js → ganttDiagram-FUAMR5RP-22OFMoat.js} +1 -1
  46. package/dist/client/assets/{gitGraph-4MIJSDKK-DMTE1jTV.js → gitGraph-4MIJSDKK-BP0idayz.js} +1 -1
  47. package/dist/client/assets/{gitGraphDiagram-X574FWY7-EV_0IPok.js → gitGraphDiagram-X574FWY7-Cx5rPzjc.js} +1 -1
  48. package/dist/client/assets/{index-B__poZ2b.js → index-DXMhk4ok.js} +11 -11
  49. package/dist/client/assets/{info-A6RAGUB7-WkHzxEDS.js → info-A6RAGUB7-BvZZu8IY.js} +1 -1
  50. package/dist/client/assets/{infoDiagram-VRGFBTTK-BcH5U5G2.js → infoDiagram-VRGFBTTK-Bbk1aZco.js} +1 -1
  51. package/dist/client/assets/{ishikawaDiagram-OU5B5YK6-Z8vZnj1l.js → ishikawaDiagram-OU5B5YK6-DbyWrUBY.js} +1 -1
  52. package/dist/client/assets/{journeyDiagram-ZHPQQLJL-Cn-m-UYg.js → journeyDiagram-ZHPQQLJL-Ka7zlagO.js} +1 -1
  53. package/dist/client/assets/{kanban-definition-PNTS6WVX-DLOrUOML.js → kanban-definition-PNTS6WVX-Q_NAEdRt.js} +1 -1
  54. package/dist/client/assets/{line-DhKwT3E3.js → line-SDAA9fEr.js} +1 -1
  55. package/dist/client/assets/{linear-DvwuMCFu.js → linear-BPf2OGUv.js} +1 -1
  56. package/dist/client/assets/{mermaid-parser.core-CwcOI9nG.js → mermaid-parser.core-BjLzFSoy.js} +3 -3
  57. package/dist/client/assets/{mermaid.core-BabKb2iQ.js → mermaid.core-vvUsQbpX.js} +4 -4
  58. package/dist/client/assets/{mindmap-definition-NLK3R4M7-D7wpNtz6.js → mindmap-definition-NLK3R4M7-DuVzu_4M.js} +1 -1
  59. package/dist/client/assets/{packet-AYTQ26CC-BJablqte.js → packet-AYTQ26CC-A66za-wc.js} +1 -1
  60. package/dist/client/assets/{pegDiagram-GJSIUBJH-EAlXAkUz.js → pegDiagram-GJSIUBJH-ClH92MDY.js} +1 -1
  61. package/dist/client/assets/{pie-WAS4IAKB-BAAbtIiO.js → pie-WAS4IAKB-sJ2H2jF4.js} +1 -1
  62. package/dist/client/assets/{pieDiagram-5QR66LMP-b1pYP4ES.js → pieDiagram-5QR66LMP-BmlcB4fD.js} +1 -1
  63. package/dist/client/assets/{quadrantDiagram-O4NWA36T-B_LJNNdE.js → quadrantDiagram-O4NWA36T-BUdNHhtc.js} +1 -1
  64. package/dist/client/assets/{radar-RG4KPBEZ-BKldNRRC.js → radar-RG4KPBEZ-B3MRkz7l.js} +1 -1
  65. package/dist/client/assets/{railroad-74A4TZTK-LvULpHpQ.js → railroad-74A4TZTK-CPQddZw9.js} +1 -1
  66. package/dist/client/assets/railroad-abnf-HS5TGJTU-CijG3JBn.js +1 -0
  67. package/dist/client/assets/railroad-ebnf-LZEXJU2U-CNgXgJgc.js +1 -0
  68. package/dist/client/assets/railroad-peg-WCYAUIDC-BkwGmMtj.js +1 -0
  69. package/dist/client/assets/{railroadDiagram-XR7U4H2S-kp6LeaeM.js → railroadDiagram-XR7U4H2S-B2wicmNk.js} +1 -1
  70. package/dist/client/assets/{requirementDiagram-PLB6GJNP-Br-OgP6b.js → requirementDiagram-PLB6GJNP-4fGmNry2.js} +1 -1
  71. package/dist/client/assets/{sankeyDiagram-IPEJSGJF-DSIbAxcK.js → sankeyDiagram-IPEJSGJF-ByuhL9nO.js} +1 -1
  72. package/dist/client/assets/{sequenceDiagram-PO4LG4MO-uVv8u8VI.js → sequenceDiagram-PO4LG4MO-CHeFXNrS.js} +1 -1
  73. package/dist/client/assets/{src-Bmfs-TFn.js → src-DuEx6MBc.js} +1 -1
  74. package/dist/client/assets/{stateDiagram-v2-GCMORJYK-Crql1z4d.js → stateDiagram-v2-GCMORJYK-Dsfly8rU.js} +1 -1
  75. package/dist/client/assets/{swimlanes-2SLR337P-CnpU7AM-.js → swimlanes-2SLR337P-DDb1xXAV.js} +1 -1
  76. package/dist/client/assets/swimlanesDiagram-TC7HE7FX-DXpYpXP-.js +8 -0
  77. package/dist/client/assets/{timeline-definition-EJHVYXUP-CqzGi-Sd.js → timeline-definition-EJHVYXUP-iC4lxMiK.js} +1 -1
  78. package/dist/client/assets/{treeView-Q6P3EWNA-N_EzEUvg.js → treeView-Q6P3EWNA-zXF3RWVa.js} +1 -1
  79. package/dist/client/assets/{treemap-WGGIJYW6-BYeVgP-v.js → treemap-WGGIJYW6-BvA719M0.js} +1 -1
  80. package/dist/client/assets/{usecaseDiagram-POWQR4AR-Dyeq2Zcy.js → usecaseDiagram-POWQR4AR-CXzh5cdW.js} +1 -1
  81. package/dist/client/assets/{vennDiagram-UO4OBE2U-CuCjJaOo.js → vennDiagram-UO4OBE2U-BuMQeNKp.js} +1 -1
  82. package/dist/client/assets/{wardley-WFR3VGLG-AV0-dO_Z.js → wardley-WFR3VGLG-m1zZI6-6.js} +1 -1
  83. package/dist/client/assets/{wardleyDiagram-VNRHLVJA-f0dVm2LA.js → wardleyDiagram-VNRHLVJA-DiB2QtGU.js} +1 -1
  84. package/dist/client/assets/{xychartDiagram-PMCCYNJV-BNjSW7P1.js → xychartDiagram-PMCCYNJV-CKRPoaV8.js} +1 -1
  85. package/dist/client/index.html +1 -1
  86. package/package.json +8 -8
  87. package/plugin.json +1 -1
  88. package/dist/client/assets/architecture-7GRP2DOG-DaIFNiR2.js +0 -1
  89. package/dist/client/assets/channel-Ci5ZF5xD.js +0 -1
  90. package/dist/client/assets/eventmodeling-NTZA5JFV-C61pKQjq.js +0 -1
  91. package/dist/client/assets/flowDiagram-KWPJA3E3-BolWtw3C.js +0 -1
  92. package/dist/client/assets/railroad-abnf-HS5TGJTU-CORGw4Le.js +0 -1
  93. package/dist/client/assets/railroad-ebnf-LZEXJU2U-BXCX4hkl.js +0 -1
  94. package/dist/client/assets/railroad-peg-WCYAUIDC-C6BQUpjn.js +0 -1
  95. package/dist/client/assets/swimlanesDiagram-TC7HE7FX-Crca2YKi.js +0 -8
package/dist/cli.mjs CHANGED
@@ -1959,7 +1959,6 @@ query($owner: String!, $name: String!, $number: Int!) {
1959
1959
  messageHeadline
1960
1960
  committedDate
1961
1961
  author { name user { login avatarUrl } }
1962
- statusCheckRollup { state }
1963
1962
  }
1964
1963
  }
1965
1964
  }
@@ -1974,6 +1973,24 @@ query($owner: String!, $name: String!, $number: Int!) {
1974
1973
  }
1975
1974
  }
1976
1975
  }`;
1976
+ /**
1977
+ * CI status, asked for on its own. Reading it needs the checks and statuses
1978
+ * scopes, which a fine-grained or SAML-limited token may lack while reading
1979
+ * everything else about the pull request; GraphQL answers that with a
1980
+ * FORBIDDEN error on this one field, and `gh` turns any error into a failed
1981
+ * call. Kept out of the PR query so a token that cannot see CI still opens
1982
+ * the review.
1983
+ */
1984
+ const CHECKS_QUERY = `
1985
+ query($owner: String!, $name: String!, $number: Int!) {
1986
+ repository(owner: $owner, name: $name) {
1987
+ pullRequest(number: $number) {
1988
+ commits(last: 1) {
1989
+ nodes { commit { statusCheckRollup { state } } }
1990
+ }
1991
+ }
1992
+ }
1993
+ }`;
1977
1994
  /** The pages after the first of each connection the PR query opens. */
1978
1995
  const REVIEWS_QUERY = `
1979
1996
  query($owner: String!, $name: String!, $number: Int!, $cursor: String) {
@@ -2220,18 +2237,32 @@ var GhClient = class {
2220
2237
  reviewNodes
2221
2238
  };
2222
2239
  }
2240
+ /** CI on the head commit, best effort: a token without the checks scope
2241
+ * gets `unknown` and the review opens anyway. Never throws. */
2242
+ async checks(ref) {
2243
+ try {
2244
+ const rollup = ((await this.graphql(ref.host, CHECKS_QUERY, {
2245
+ owner: ref.owner,
2246
+ name: ref.repo,
2247
+ number: ref.number
2248
+ })).repository?.pullRequest?.commits.nodes.at(-1)?.commit)?.statusCheckRollup;
2249
+ return checkState(rollup?.state);
2250
+ } catch {
2251
+ return "unknown";
2252
+ }
2253
+ }
2223
2254
  async getPr(ref) {
2224
- const { viewer, pr, reviewNodes } = await this.head(ref);
2225
- return prInfo(ref, viewer, pr, reviewNodes);
2255
+ const [{ viewer, pr, reviewNodes }, checks] = await Promise.all([this.head(ref), this.checks(ref)]);
2256
+ return prInfo(ref, viewer, pr, reviewNodes, checks);
2226
2257
  }
2227
2258
  async listThreads(ref) {
2228
2259
  const { pr, reviewNodes } = await this.head(ref);
2229
2260
  return this.conversation(ref, pr, reviewNodes);
2230
2261
  }
2231
2262
  async fetchPr(ref) {
2232
- const { viewer, pr, reviewNodes } = await this.head(ref);
2263
+ const [{ viewer, pr, reviewNodes }, checks] = await Promise.all([this.head(ref), this.checks(ref)]);
2233
2264
  return {
2234
- pr: prInfo(ref, viewer, pr, reviewNodes),
2265
+ pr: prInfo(ref, viewer, pr, reviewNodes, checks),
2235
2266
  threads: await this.conversation(ref, pr, reviewNodes)
2236
2267
  };
2237
2268
  }
@@ -2345,9 +2376,8 @@ var GhClient = class {
2345
2376
  }
2346
2377
  };
2347
2378
  /** The PR query's answer as a PrInfo, with every review page in hand. */
2348
- function prInfo(ref, viewer, pr, reviewNodes) {
2349
- const commitNodes = pr.commits.nodes ?? [];
2350
- const commits = commitNodes.map((n) => {
2379
+ function prInfo(ref, viewer, pr, reviewNodes, checks) {
2380
+ const commits = (pr.commits.nodes ?? []).map((n) => {
2351
2381
  const c = n.commit;
2352
2382
  const author = c.author;
2353
2383
  return {
@@ -2357,7 +2387,6 @@ function prInfo(ref, viewer, pr, reviewNodes) {
2357
2387
  at: String(c.committedDate ?? "")
2358
2388
  };
2359
2389
  });
2360
- const rollup = (commitNodes.at(-1)?.commit)?.statusCheckRollup;
2361
2390
  const reviews = reviewNodes.map((r) => ({
2362
2391
  id: String(r.id),
2363
2392
  author: user(r.author),
@@ -2390,7 +2419,7 @@ function prInfo(ref, viewer, pr, reviewNodes) {
2390
2419
  sha: String(pr.headRefOid)
2391
2420
  },
2392
2421
  commits,
2393
- checks: { state: checkState(rollup?.state) },
2422
+ checks: { state: checks },
2394
2423
  reviews: reviews.filter((r) => r.state !== "PENDING"),
2395
2424
  approvals: [...latest.values()].filter((s) => s === "APPROVED").length,
2396
2425
  changesRequested: [...latest.values()].filter((s) => s === "CHANGES_REQUESTED").length,
@@ -2608,6 +2637,25 @@ function branchExists(root, branch) {
2608
2637
  return err.status !== 1;
2609
2638
  }
2610
2639
  }
2640
+ /** {@link branchExists}, off the event loop, for the daemon's background sweep
2641
+ * over every repo it has ever reviewed. Same lean: true unless git said no. */
2642
+ async function branchExistsAsync(root, branch) {
2643
+ try {
2644
+ await execFileAsync("git", [
2645
+ "show-ref",
2646
+ "--verify",
2647
+ "--quiet",
2648
+ `refs/heads/${branch}`
2649
+ ], {
2650
+ cwd: root,
2651
+ encoding: "utf-8",
2652
+ maxBuffer: MAX_BUFFER
2653
+ });
2654
+ return true;
2655
+ } catch (err) {
2656
+ return err.code !== 1;
2657
+ }
2658
+ }
2611
2659
  /**
2612
2660
  * The name of the linked worktree we're in, or null in the main one. A linked
2613
2661
  * worktree's git dir is `<main>/.git/worktrees/<name>`, while the main worktree's
@@ -3242,7 +3290,17 @@ const SCHEMA_VERSION = 3;
3242
3290
  const REVIEWS_RESHAPED_AT = 2;
3243
3291
  var DiffoDb = class {
3244
3292
  db;
3293
+ closed = false;
3245
3294
  path;
3295
+ /**
3296
+ * Opening is cheap on purpose: the schema, and one SQL statement for the TTL.
3297
+ * Nothing here touches the filesystem beyond the database file, and nothing
3298
+ * asks git. It used to: every open checked every review's branch with a
3299
+ * `git show-ref`, across every repo this machine ever reviewed — 73 git
3300
+ * processes, 1.5s, on a database a few weeks old, and an open constructs
3301
+ * this five times. The checks live in {@link pruneRepo} (one repo, before its
3302
+ * review loads) and {@link maintain} (everything, in the daemon's background).
3303
+ */
3246
3304
  constructor(path = defaultDbPath()) {
3247
3305
  this.path = path;
3248
3306
  mkdirSync(dirname(path), {
@@ -3254,7 +3312,7 @@ var DiffoDb = class {
3254
3312
  chmodSync(path, 384);
3255
3313
  this.db.exec("PRAGMA journal_mode = WAL; PRAGMA busy_timeout = 3000; PRAGMA journal_size_limit = 4194304;");
3256
3314
  this.ensureSchema();
3257
- this.pruneVanishedRepos();
3315
+ this.pruneExpiredReviews();
3258
3316
  }
3259
3317
  /**
3260
3318
  * Creates what is missing and retires what is unknown. Runs at open, and
@@ -3323,38 +3381,69 @@ var DiffoDb = class {
3323
3381
  }
3324
3382
  }
3325
3383
  /**
3326
- * Rows about a worktree that is gone can never be reached again — the path *is*
3327
- * the key. An unmounted volume looks the same as a deleted worktree, so its rows
3328
- * go too; the `servers` row needs its process dead as well, or a live server's
3329
- * claim could be dropped over a moment of unreachability.
3384
+ * Reviews untouched for `REVIEW_TTL_DAYS` go on every open: one statement,
3385
+ * no git, and the backstop for everything the two targeted sweeps below leave
3386
+ * for later.
3387
+ */
3388
+ pruneExpiredReviews() {
3389
+ const cutoff = (/* @__PURE__ */ new Date(Date.now() - 5184e6)).toISOString();
3390
+ const stale = this.db.prepare("DELETE FROM reviews WHERE updated_at < ?").run(cutoff);
3391
+ if (Number(stale.changes) > 0) this.checkpoint();
3392
+ }
3393
+ /**
3394
+ * Retire this one repo's reviews for branches it no longer has. The server
3395
+ * runs it before loading the review it is about to serve, so a branch
3396
+ * deleted since the last server start is forgotten before a namesake could
3397
+ * inherit its threads. Only this repo's branches are asked about, so the
3398
+ * cost is a handful of `git show-ref`s, once per server start, never per CLI
3399
+ * call. Branch existence is asked of git rather than assumed — when git can't
3400
+ * answer the row is kept, because guessing here deletes threads.
3401
+ */
3402
+ pruneRepo(repoPath) {
3403
+ const rows = this.db.prepare("SELECT DISTINCT branch FROM reviews WHERE repo_path = ?").all(repoPath);
3404
+ let dropped = 0;
3405
+ for (const { branch } of rows) {
3406
+ if (branch === "" || branchExists(repoPath, branch)) continue;
3407
+ dropped += this.dropReviews(repoPath, branch);
3408
+ }
3409
+ return dropped;
3410
+ }
3411
+ /**
3412
+ * The full sweep, for a long-lived process with time on its hands: rows about
3413
+ * repos that are gone, and reviews for branches that are. The daemon runs it
3414
+ * once, a few seconds after it is serving; `diffo clean` runs it on demand.
3415
+ * Git is asked asynchronously and one repo at a time, so a sweep over every
3416
+ * repo this machine ever reviewed never blocks a request. A `close()` midway
3417
+ * ends it quietly between steps.
3418
+ *
3419
+ * Rows about a worktree that is gone can never be reached again — the path
3420
+ * *is* the key. An unmounted volume looks the same as a deleted worktree, so
3421
+ * its rows go too; the `servers` row needs its process dead as well, or a live
3422
+ * server's claim could be dropped over a moment of unreachability.
3330
3423
  */
3331
- pruneVanishedRepos() {
3332
- for (const { repo_path } of this.distinctRepoPaths("reviews")) if (!existsSync(repo_path)) this.db.prepare("DELETE FROM reviews WHERE repo_path = ?").run(repo_path);
3424
+ async maintain() {
3425
+ const report = { reviews: 0 };
3426
+ if (this.closed) return report;
3427
+ for (const { repo_path } of this.distinctRepoPaths("reviews")) if (!existsSync(repo_path)) report.reviews += this.dropReviews(repo_path);
3333
3428
  for (const { repo_path } of this.distinctRepoPaths("repo_ports")) if (!existsSync(repo_path)) this.db.prepare("DELETE FROM repo_ports WHERE repo_path = ?").run(repo_path);
3334
3429
  const worktrees = this.db.prepare("SELECT worktree_path, repo_path FROM worktrees").all();
3335
3430
  for (const { worktree_path, repo_path } of worktrees) if (!existsSync(repo_path)) this.db.prepare("DELETE FROM worktrees WHERE worktree_path = ?").run(worktree_path);
3336
3431
  const servers = this.db.prepare("SELECT repo_path, pid FROM servers").all();
3337
3432
  for (const { repo_path, pid } of servers) if (!existsSync(repo_path) && !pidAlive$1(pid)) this.db.prepare("DELETE FROM servers WHERE repo_path = ?").run(repo_path);
3338
- this.pruneStaleReviews();
3339
- }
3340
- /**
3341
- * Reviews the reviewer can never return to: a branch that no longer exists, or
3342
- * one untouched for `REVIEW_TTL_DAYS`. Branch existence is asked of git rather
3343
- * than assumed — if git can't answer the row is kept, because guessing here
3344
- * deletes threads.
3345
- */
3346
- pruneStaleReviews() {
3347
- const cutoff = (/* @__PURE__ */ new Date(Date.now() - 5184e6)).toISOString();
3348
- const stale = this.db.prepare("DELETE FROM reviews WHERE updated_at < ?").run(cutoff);
3349
- if (Number(stale.changes) > 0) {
3350
- this.checkpoint();
3351
- return;
3352
- }
3353
3433
  const rows = this.db.prepare("SELECT DISTINCT repo_path, branch FROM reviews").all();
3354
3434
  for (const { repo_path, branch } of rows) {
3355
- if (branch === "" || branchExists(repo_path, branch)) continue;
3356
- this.db.prepare("DELETE FROM reviews WHERE repo_path = ? AND branch = ?").run(repo_path, branch);
3435
+ if (branch === "") continue;
3436
+ const exists = await branchExistsAsync(repo_path, branch);
3437
+ if (this.closed) return report;
3438
+ if (!exists) report.reviews += this.dropReviews(repo_path, branch);
3357
3439
  }
3440
+ if (report.reviews > 0) this.checkpoint();
3441
+ return report;
3442
+ }
3443
+ /** Every review of a repo, or only one branch's. Returns the rows dropped. */
3444
+ dropReviews(repoPath, branch) {
3445
+ const result = branch === void 0 ? this.db.prepare("DELETE FROM reviews WHERE repo_path = ?").run(repoPath) : this.db.prepare("DELETE FROM reviews WHERE repo_path = ? AND branch = ?").run(repoPath, branch);
3446
+ return Number(result.changes);
3358
3447
  }
3359
3448
  /** Fold the write-ahead log back into the database file and truncate it. WAL
3360
3449
  * only shrinks at a checkpoint, which a long-lived server never reaches. */
@@ -3452,6 +3541,7 @@ var DiffoDb = class {
3452
3541
  else this.db.prepare("DELETE FROM servers WHERE repo_path = ? AND port = ?").run(repoPath, port);
3453
3542
  }
3454
3543
  close() {
3544
+ this.closed = true;
3455
3545
  this.db.close();
3456
3546
  }
3457
3547
  };
@@ -3517,6 +3607,9 @@ var DeliveryQueue = class DeliveryQueue {
3517
3607
  stalled = false;
3518
3608
  stallTimer = null;
3519
3609
  betweenPolls = false;
3610
+ /** Why the agent is parked between polls: a reply just landed, or its poll
3611
+ * ended on its own and the re-poll is expected. */
3612
+ parked = "replied";
3520
3613
  graceTimer = null;
3521
3614
  lastDetach = null;
3522
3615
  since = Date.now();
@@ -3664,7 +3757,7 @@ var DeliveryQueue = class DeliveryQueue {
3664
3757
  if (this.awaitingReply) return this.stalled ? "stalled" : "delivered";
3665
3758
  if (this.outlining() !== null) return "delivered";
3666
3759
  if (this.waiter) return "polling";
3667
- if (this.betweenPolls) return "replied";
3760
+ if (this.betweenPolls) return this.parked;
3668
3761
  return this.lastDetach ?? "no-agent";
3669
3762
  }
3670
3763
  hasListener() {
@@ -3717,9 +3810,10 @@ var DeliveryQueue = class DeliveryQueue {
3717
3810
  if (this.stallTimer !== null) clearTimeout(this.stallTimer);
3718
3811
  this.stallTimer = null;
3719
3812
  }
3720
- armGrace() {
3813
+ armGrace(why = "replied") {
3721
3814
  this.clearGrace();
3722
3815
  this.betweenPolls = true;
3816
+ this.parked = why;
3723
3817
  const drop = () => {
3724
3818
  this.graceTimer = null;
3725
3819
  if (!this.betweenPolls) return;
@@ -3754,6 +3848,24 @@ var DeliveryQueue = class DeliveryQueue {
3754
3848
  this.graceTimer = null;
3755
3849
  this.betweenPolls = false;
3756
3850
  }
3851
+ /**
3852
+ * A poll ended without `diffo end`: the poll window closed, or the process
3853
+ * died under its harness. Neither means the agent left — the CLI tells the
3854
+ * session to re-run the poll, and it usually does within moments — so the
3855
+ * reviewer keeps an agent instead of being asked to invite one again. The
3856
+ * agent parks in the same grace a reply uses: a named session is watched
3857
+ * until its process is gone (or the cap), an unnamed one gets the fixed
3858
+ * window. Only a session that is already dead reads as gone at once. When
3859
+ * the grace runs out without a re-poll, the reason it fell to waiting is
3860
+ * still the dead poll.
3861
+ */
3862
+ pollDropped() {
3863
+ this.lastDetach = "disconnected";
3864
+ const pid = this.owner;
3865
+ const isAlive = this.liveness.isAlive ?? pidAlive;
3866
+ if (!(pid !== null && !isAlive(pid)) && !this.awaitingReply && this.outlining() === null) this.armGrace("repolling");
3867
+ this.notify();
3868
+ }
3757
3869
  enqueueThreads(threadIds) {
3758
3870
  const bucket = this.bucket();
3759
3871
  for (const id of threadIds) bucket.threads.add(id);
@@ -3841,8 +3953,7 @@ var DeliveryQueue = class DeliveryQueue {
3841
3953
  onAbort?.(() => {
3842
3954
  if (this.waiter === waiter) {
3843
3955
  this.releaseWaiter(null);
3844
- this.lastDetach = "disconnected";
3845
- this.notify();
3956
+ this.pollDropped();
3846
3957
  }
3847
3958
  });
3848
3959
  });
@@ -6489,6 +6600,9 @@ const POLL_HEARTBEAT_MS = 15e3;
6489
6600
  * aborts, and a listening poll blocks the daemon's idle reap.
6490
6601
  */
6491
6602
  const POLL_MAX_MS = 18e5;
6603
+ /** How long after listening the daemon starts the machine-wide database sweep:
6604
+ * past the first page load, which is what the sweep must never delay. */
6605
+ const MAINTENANCE_DELAY_MS = 5e3;
6492
6606
  function createApp(ctx, store, review, queue) {
6493
6607
  const app = new Hono();
6494
6608
  if (review && queue) queue.onBatchClosed((closed) => {
@@ -7271,11 +7385,13 @@ function startServer(options) {
7271
7385
  throw new RepoAlreadyServedError(holder);
7272
7386
  }
7273
7387
  db.setPreferredPort(resolve(options.root), options.port);
7388
+ const log = (message) => console.log(`[${(/* @__PURE__ */ new Date()).toLocaleTimeString("en-GB", { hour12: false })}] ${message}`);
7389
+ const retired = db.pruneRepo(resolve(options.root));
7390
+ if (retired > 0) log(`retired ${retired} ${retired === 1 ? "review" : "reviews"} for branches this repo no longer has`);
7274
7391
  const review = new ReviewStore(options.root, db, options.spec);
7275
7392
  const queue = new DeliveryQueue();
7276
7393
  queue.rescope(store.get().repo.branch);
7277
7394
  rehydrateQueue(review, queue);
7278
- const log = (message) => console.log(`[${(/* @__PURE__ */ new Date()).toLocaleTimeString("en-GB", { hour12: false })}] ${message}`);
7279
7395
  const telemetry = options.telemetry ?? new Telemetry({
7280
7396
  store: {
7281
7397
  get: (key) => db.getUiSetting(key),
@@ -7358,6 +7474,12 @@ function startServer(options) {
7358
7474
  port: options.port,
7359
7475
  hostname: "127.0.0.1"
7360
7476
  });
7477
+ const maintenance = setTimeout(() => {
7478
+ db.maintain().then((report) => {
7479
+ if (report.reviews > 0) log(`retired ${report.reviews} ${report.reviews === 1 ? "review" : "reviews"} whose repo or branch is gone`);
7480
+ }).catch((err) => log(`database sweep failed: ${err.message}`));
7481
+ }, MAINTENANCE_DELAY_MS);
7482
+ maintenance.unref();
7361
7483
  const deregister = () => {
7362
7484
  try {
7363
7485
  db.removeServer(review.repoPath, options.port);
@@ -7381,6 +7503,7 @@ function startServer(options) {
7381
7503
  queue,
7382
7504
  telemetry,
7383
7505
  stopWatching: async () => {
7506
+ clearTimeout(maintenance);
7384
7507
  idle?.stop();
7385
7508
  puller?.stop();
7386
7509
  unsubscribeReconcile();
@@ -7986,6 +8109,7 @@ if (command.kind === "setup") {
7986
8109
  if (command.kind === "clean") {
7987
8110
  const db = new DiffoDb();
7988
8111
  try {
8112
+ await db.maintain();
7989
8113
  const entries = sweepWorktrees(db, void 0, {
7990
8114
  force: command.force,
7991
8115
  all: command.all
@@ -1 +1 @@
1
- import{m as e,t}from"./mermaid-parser.core-CwcOI9nG.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-Bmfs-TFn.js";import"./chunk-O7XYJQB3-BjcjInBL.js";import{n as i,r as a,t as o}from"./chunk-GTNCS2PH-at0ENjhB.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-BabKb2iQ.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-BjLzFSoy.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-DuEx6MBc.js";import"./chunk-O7XYJQB3-DESjnZZT.js";import{n as i,r as a,t as o}from"./chunk-GTNCS2PH-DNq6Ojc7.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-vvUsQbpX.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-Cezvykkn.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-BBmACywa.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};
@@ -0,0 +1 @@
1
+ import"./chunk-FOHPRMQF-DzxwRta7.js";import{M as e}from"./mermaid-parser.core-BjLzFSoy.js";export{e as createArchitectureServices};