@diffohq/diffo 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +162 -32
- package/dist/client/assets/{abnfDiagram-VCTEODGH-DNZRM2Rn.js → abnfDiagram-VCTEODGH-BK74b0Uj.js} +1 -1
- package/dist/client/assets/{arc-s7daVIwl.js → arc-BZJjnFHJ.js} +1 -1
- package/dist/client/assets/architecture-7GRP2DOG-BMofp_0u.js +1 -0
- package/dist/client/assets/{architectureDiagram-5GKGNRK7-DsxTOcye.js → architectureDiagram-5GKGNRK7-BBjd1L77.js} +1 -1
- package/dist/client/assets/{blockDiagram-NRAW4CY4-DqGD_dcu.js → blockDiagram-I7D4REHJ-BWSjZ0YR.js} +2 -2
- package/dist/client/assets/{c4Diagram-UCG6FXSJ-CMuJod-h.js → c4Diagram-7LVT6UL2-z-xUGKCJ.js} +1 -1
- package/dist/client/assets/channel-CmX7fcUa.js +1 -0
- package/dist/client/assets/{chunk-TEH6E4GO-M22Cr-Sd.js → chunk-4HAMMTFA-CAN-T2o-.js} +1 -1
- package/dist/client/assets/{chunk-75Z2AOVW-HRLiZN7c.js → chunk-75Z2AOVW-B_bGdfJP.js} +1 -1
- package/dist/client/assets/{chunk-DU6HZSFF-D6gjp2l1.js → chunk-DU6HZSFF-wyqPpFTy.js} +1 -1
- package/dist/client/assets/{chunk-F27PBJKO-DRqkoKNg.js → chunk-F27PBJKO-C6X74WsU.js} +1 -1
- package/dist/client/assets/{chunk-GMAD6QVW-DG-OmEbV.js → chunk-GMAD6QVW-DBossm8a.js} +1 -1
- package/dist/client/assets/{chunk-OBVCFTLP-DOl2OrIN.js → chunk-GVQU2GXP-3NWb-Kjs.js} +1 -1
- package/dist/client/assets/{chunk-G27WJ6UU-QUFgr4za.js → chunk-IMKFNOWR-BCvjP66C.js} +1 -1
- package/dist/client/assets/{chunk-JQ64N6SF-CPdpoyCu.js → chunk-L3NEJ4N5-DppEbElX.js} +1 -1
- package/dist/client/assets/chunk-OSK3NFVY-BJ8i4cd-.js +10 -0
- package/dist/client/assets/{chunk-P2QGCYS3-CBWu7ViW.js → chunk-P2QGCYS3-fvNVbdI1.js} +1 -1
- package/dist/client/assets/{chunk-POPQ4Y6H-Dw_D6UWF.js → chunk-POPQ4Y6H-DKwUAqbe.js} +1 -1
- package/dist/client/assets/{chunk-PWAF6VOD-BHpo38Be.js → chunk-PWAF6VOD-BRN4CzQ0.js} +1 -1
- package/dist/client/assets/{chunk-RHFEMEQ7-BabrfzF-.js → chunk-SHT3W25Y-BfzjiqOe.js} +2 -2
- package/dist/client/assets/{chunk-SVP7TREG-CSTzyRmo.js → chunk-SVP7TREG-CsO-w42m.js} +1 -1
- package/dist/client/assets/{chunk-LCL6LL3I-DoHJ4n3V.js → chunk-TICWLB2K-DPzmokY4.js} +1 -1
- package/dist/client/assets/{chunk-XXDRQBXY-BHwLEQfa.js → chunk-XXDRQBXY-BikhrMBF.js} +1 -1
- package/dist/client/assets/classDiagram-ZZMXUADV-BSMgXeCj.js +1 -0
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-BSMgXeCj.js +1 -0
- package/dist/client/assets/{core-B9wYK4yO.js → core-BJUznnCg.js} +1 -1
- package/dist/client/assets/{cose-bilkent-JH36ORCC-BL0lTP0k.js → cose-bilkent-JH36ORCC-CBu7-BXr.js} +1 -1
- package/dist/client/assets/{cynefin-OW5HDTMX-1zOzoEu-.js → cynefin-OW5HDTMX-iJEmw--0.js} +1 -1
- package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-DST_IHb1.js → cynefinDiagram-5FMLGOSQ-B4JnaLZu.js} +1 -1
- package/dist/client/assets/{cytoscape.esm-C2x7inlt.js → cytoscape.esm-CGd-uY3x.js} +1 -1
- package/dist/client/assets/{dagre-3AP2YEHR-CoEaLaFu.js → dagre-GXQ25YYZ-bmDafESr.js} +1 -1
- package/dist/client/assets/{diagram-S7CK7UJ4-BwGXFSb-.js → diagram-S7CK7UJ4-C1jP2NX5.js} +1 -1
- package/dist/client/assets/{diagram-UQ7AKVKN-wJMwiRQW.js → diagram-UQ7AKVKN-DssGkq6D.js} +1 -1
- package/dist/client/assets/{diagram-VSXAHHWV-DRQH2hZ-.js → diagram-VSXAHHWV-BMNFierD.js} +1 -1
- package/dist/client/assets/{diagram-VX7I27RA-BWGYUOwn.js → diagram-VX7I27RA-BmHtC5T2.js} +1 -1
- package/dist/client/assets/{diagram-Z3DM3KII-C2ETOHnp.js → diagram-Z3DM3KII-CzCV6KsS.js} +1 -1
- package/dist/client/assets/dist-BT7WB1vp.js +142 -0
- package/dist/client/assets/{dist-C42IZvNn.js → dist-bii_eoxi.js} +1 -1
- package/dist/client/assets/{ebnfDiagram-PWID7BFC-CkcgAzr3.js → ebnfDiagram-PWID7BFC-DuVnjPWa.js} +1 -1
- package/dist/client/assets/{engine-oniguruma-D9HVl69n.js → engine-oniguruma-BlIEwGaN.js} +1 -1
- package/dist/client/assets/{erDiagram-SSCWMZ5O-Do6h2U1E.js → erDiagram-RLTQ6QDP-CtwYHyZu.js} +1 -1
- package/dist/client/assets/eventmodeling-NTZA5JFV-DBQsn9JF.js +1 -0
- package/dist/client/assets/flowDiagram-HODETNUW-C_zt1wER.js +1 -0
- package/dist/client/assets/{ganttDiagram-EL5Y4UJY-cC8gUuqf.js → ganttDiagram-EL5Y4UJY-CR8Sa06t.js} +1 -1
- package/dist/client/assets/{gitGraph-4MIJSDKK-Con-0IRc.js → gitGraph-4MIJSDKK-DoWc_DJ0.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-Oj6POMRs.js → gitGraphDiagram-WWUBYQGX-C36JIyKh.js} +1 -1
- package/dist/client/assets/index-BUq9UmeC.js +91 -0
- package/dist/client/assets/{info-A6RAGUB7-Cl45HDP4.js → info-A6RAGUB7-DULcTga7.js} +1 -1
- package/dist/client/assets/{infoDiagram-RXCK75RN-DIVe-qvk.js → infoDiagram-27XIBGKW-eQbUxJ9T.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-5VMMS53U-BB3HsPau.js → ishikawaDiagram-5VMMS53U-CsPYEqSH.js} +1 -1
- package/dist/client/assets/{journeyDiagram-EYS64GPL-Cj8ezyBN.js → journeyDiagram-3NMN7TZE-DbHeKN0X.js} +2 -2
- package/dist/client/assets/{kanban-definition-3QL26DDD-D3dbth5Z.js → kanban-definition-UXKFOSKX-CbYeTY2r.js} +1 -1
- package/dist/client/assets/{line-tg3RVOrp.js → line-BeOqlVB1.js} +1 -1
- package/dist/client/assets/{linear-CzAWMsuG.js → linear-D5d3UlAm.js} +1 -1
- package/dist/client/assets/{mermaid-parser.core-DKC3l_TU.js → mermaid-parser.core-BLSiQUXp.js} +3 -3
- package/dist/client/assets/{mermaid.core-B0ktnMCY.js → mermaid.core-BoXUi08V.js} +5 -5
- package/dist/client/assets/{mindmap-definition-FBJOCRG2-CSUjR6w9.js → mindmap-definition-YA3MSWOX-o49TTsg4.js} +1 -1
- package/dist/client/assets/{packet-AYTQ26CC-NTsh29Fp.js → packet-AYTQ26CC-Blxpg-nI.js} +1 -1
- package/dist/client/assets/{pegDiagram-XKGWAZYB-BhLsv72R.js → pegDiagram-XKGWAZYB-CZxoewnI.js} +1 -1
- package/dist/client/assets/{pie-WAS4IAKB-DENes_Cx.js → pie-WAS4IAKB-D-fqeiW7.js} +1 -1
- package/dist/client/assets/{pieDiagram-E7YTZNPT-Ci9YzLDy.js → pieDiagram-E7YTZNPT-dAiwtigh.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-AXDQQJYC-D7D5FwMe.js → quadrantDiagram-AXDQQJYC-mefTaSBl.js} +1 -1
- package/dist/client/assets/{radar-RG4KPBEZ-C3OVgpW0.js → radar-RG4KPBEZ-VaODqy4w.js} +1 -1
- package/dist/client/assets/{railroad-74A4TZTK-DHWDkPlt.js → railroad-74A4TZTK-BwoigfOV.js} +1 -1
- package/dist/client/assets/railroad-abnf-HS5TGJTU-BYYKbIBi.js +1 -0
- package/dist/client/assets/railroad-ebnf-LZEXJU2U-BFA23uel.js +1 -0
- package/dist/client/assets/railroad-peg-WCYAUIDC-Cq02Hm_P.js +1 -0
- package/dist/client/assets/{railroadDiagram-O6MQD6OU-ByO5lwcN.js → railroadDiagram-O6MQD6OU-DdhfhlaU.js} +1 -1
- package/dist/client/assets/{requirementDiagram-EFPCY7ZU-UAUf-JbW.js → requirementDiagram-BXWQKSXE-BVrRfVMy.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-P5KCCOFB-D3dgv1AD.js → sankeyDiagram-P5KCCOFB-BalSSH4U.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-DbGvVPa7.js → sequenceDiagram-WJ2MYXX4-B2KsE_Z_.js} +1 -1
- package/dist/client/assets/{src-DQRzrNpT.js → src-CfhDi0bm.js} +1 -1
- package/dist/client/assets/{stateDiagram-HBIQ2CUA-CJznFEjd.js → stateDiagram-D77RDMKH-CoH6bKG5.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-rXsredo-.js +1 -0
- package/dist/client/assets/{swimlanes-XN3QIQJK-Bp4PtrPm.js → swimlanes-42K2YHIH-3IkzoE1X.js} +1 -1
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-BeXrrDxh.js +8 -0
- package/dist/client/assets/{timeline-definition-24CTP7MA-jqaUS70q.js → timeline-definition-24CTP7MA-B2M9pP5h.js} +1 -1
- package/dist/client/assets/{treeView-Q6P3EWNA-4uMQTFyy.js → treeView-Q6P3EWNA-Brp55dHV.js} +1 -1
- package/dist/client/assets/{treemap-WGGIJYW6-BEvgQaxX.js → treemap-WGGIJYW6-zRe9RDJV.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-BzSNLT-7.js → vennDiagram-4TSXK5OY-PNF-rFET.js} +1 -1
- package/dist/client/assets/{wardley-WFR3VGLG-0Vpm3lxj.js → wardley-WFR3VGLG-BSDDZIR6.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-VM6X3IG4-D9KaADBZ.js → wardleyDiagram-VM6X3IG4-CFaIuWQk.js} +1 -1
- package/dist/client/assets/{xychartDiagram-S5SC5T6Z-CnrJ3a0c.js → xychartDiagram-S5SC5T6Z-et5vk4QS.js} +1 -1
- package/dist/client/index.html +1 -1
- package/package.json +2 -1
- package/plugin.json +1 -1
- package/skills/diffo/SKILL.md +52 -124
- package/dist/client/assets/architecture-7GRP2DOG-DzM3CzOq.js +0 -1
- package/dist/client/assets/channel-Cftoq4wT.js +0 -1
- package/dist/client/assets/chunk-R7TYR2AO-DgC6z76h.js +0 -10
- package/dist/client/assets/classDiagram-DTDB5LWJ-uMtyQjAg.js +0 -1
- package/dist/client/assets/classDiagram-v2-JRS7N3AN-uMtyQjAg.js +0 -1
- package/dist/client/assets/eventmodeling-NTZA5JFV-LK0PWCmm.js +0 -1
- package/dist/client/assets/flowDiagram-A5DVABFB-W_CNjdk0.js +0 -1
- package/dist/client/assets/index-BPuQYkRJ.js +0 -90
- package/dist/client/assets/railroad-abnf-HS5TGJTU-XG9NyE2s.js +0 -1
- package/dist/client/assets/railroad-ebnf-LZEXJU2U-BePIURFQ.js +0 -1
- package/dist/client/assets/railroad-peg-WCYAUIDC-THfR3kY_.js +0 -1
- package/dist/client/assets/stateDiagram-v2-4QOOHH4V-o6PmCsJ0.js +0 -1
- package/dist/client/assets/swimlanesDiagram-VK2B7HYN-W1d9PL3X.js +0 -8
- /package/dist/client/assets/{sizeCapture-X5ZJPWSS-B0uUizjq.js → sizeCapture-INFHLROL-B0uUizjq.js} +0 -0
package/dist/cli.mjs
CHANGED
|
@@ -225,6 +225,7 @@ function nextStepFor(kind, actionable) {
|
|
|
225
225
|
}
|
|
226
226
|
const ACK_NEXT_STEP = {
|
|
227
227
|
reply: `When every thread is handled, run \`${CLI_COMMANDS.poll}\` again to keep listening (${POLL_STANCE}).`,
|
|
228
|
+
replyMore: "Interim reply posted — the reviewer still sees you working on this thread. Post the follow-up as a plain reply (no --more) BEFORE your next poll: re-polling closes the batch and counts the promise as never kept.",
|
|
228
229
|
comment: `It's in the review as your comment, labeled as yours — the reviewer replies to take it up, or resolves it. Continue with the review threads, then run \`${CLI_COMMANDS.poll}\`.`,
|
|
229
230
|
end: "Detached. Do not reopen or re-poll this review unless the user asks — deliver anything remaining directly in the conversation."
|
|
230
231
|
};
|
|
@@ -271,6 +272,11 @@ const INTENT_CONTRACT = {
|
|
|
271
272
|
fix: "- `issue` threads want a code change. Address each one, or push back in the thread with your reasoning."
|
|
272
273
|
};
|
|
273
274
|
const UNLABELED_CONTRACT = "- Unlabeled threads: judge from the text — a question wants an answer, not an edit.";
|
|
275
|
+
/** The agent spoke last: the thread is answered until the reviewer says more.
|
|
276
|
+
* A reply that promised a follow-up (`--more`) is not an answer yet. */
|
|
277
|
+
function answeredByAgent(thread) {
|
|
278
|
+
return thread.messages.at(-1)?.author === "agent" && thread.awaitingFollowUp !== true;
|
|
279
|
+
}
|
|
274
280
|
/** The closing note is the reviewer summing up, so it earns an answer even when it
|
|
275
281
|
* asks nothing — a note with no reply is the review's one dead end. */
|
|
276
282
|
const CLOSING_CONTRACT = "- The closing note speaks for the whole review: read it first, and reply to it — briefly if it only sums up, in full if it asks something.";
|
|
@@ -281,9 +287,34 @@ function intentContract(threads) {
|
|
|
281
287
|
if (threads.some((t) => t.closingNote)) lines.push(CLOSING_CONTRACT);
|
|
282
288
|
return lines;
|
|
283
289
|
}
|
|
284
|
-
|
|
290
|
+
/**
|
|
291
|
+
* The short form, for a session that already received the full protocol this
|
|
292
|
+
* attachment (tracked per session pid by the DeliveryQueue). The full text is
|
|
293
|
+
* ~580 tokens and re-shipping it with every delivery was the loop's largest
|
|
294
|
+
* recurring cost; the compact form keeps only the per-batch contract — intent
|
|
295
|
+
* rules, the reply command, the re-poll — plus the pointer that reprints the rest.
|
|
296
|
+
*/
|
|
297
|
+
function compactProtocol(threads) {
|
|
298
|
+
return `## How to respond
|
|
299
|
+
|
|
300
|
+
Same protocol as your earlier deliveries (\`${CLI} help agent\` reprints it in full):
|
|
301
|
+
|
|
302
|
+
1. Act on each thread.
|
|
303
|
+
${intentContract(threads).map((line) => ` ${line}`).join("\n")}
|
|
304
|
+
2. Reply per thread as soon as it is handled — what changed and where (\`file:line\`), verify it the cheapest honest way first:
|
|
305
|
+
|
|
306
|
+
${CLI_COMMANDS.reply}
|
|
307
|
+
|
|
308
|
+
3. When every thread is handled, run \`${CLI_COMMANDS.poll}\` again to keep listening.
|
|
309
|
+
|
|
310
|
+
Change only what these threads ask about — the reviewer is mid-read. Re-read
|
|
311
|
+
the current file before editing; the code may have moved. Resolving a thread
|
|
312
|
+
is the reviewer's call, never yours.`;
|
|
313
|
+
}
|
|
314
|
+
function replyProtocol(threads, mode = "full") {
|
|
315
|
+
if (mode === "compact") return compactProtocol(threads);
|
|
285
316
|
const batchNote = threads.length > 1 ? "\nRead every thread before you start editing — threads can touch the same\ncode, and an edit for one can move what another is anchored to.\n" : "";
|
|
286
|
-
const answeredNote = threads.some((t) => t
|
|
317
|
+
const answeredNote = threads.some((t) => answeredByAgent(t)) ? [" - Some threads end with your own earlier reply — if nothing new was asked since, don't reply to them again."] : [];
|
|
287
318
|
return `## How to respond
|
|
288
319
|
|
|
289
320
|
Diffo is running locally; talk to it through its CLI.
|
|
@@ -303,6 +334,10 @@ ${[...intentContract(threads).map((line) => ` ${line}`), ...answeredNote].join
|
|
|
303
334
|
is fixed, verify it the cheapest honest way (run the relevant test, re-read
|
|
304
335
|
the change) and mention what you checked.
|
|
305
336
|
Reply as soon as a thread is handled; don't save replies for the end.
|
|
337
|
+
A reply that only promises a follow-up ("I'll investigate and report
|
|
338
|
+
back") is not an answer — post it with \`--more\` so the reviewer keeps
|
|
339
|
+
seeing you at work on that thread, then post the real answer as a plain
|
|
340
|
+
reply (no \`--more\`) before your next poll.
|
|
306
341
|
Replies and comment threads render GitHub-flavored markdown, and a
|
|
307
342
|
\`\`\`mermaid fence renders as a diagram — use one when a flow, sequence,
|
|
308
343
|
or state picture explains the change better than prose. Keep it small
|
|
@@ -418,6 +453,7 @@ function snapshotBlock(thread) {
|
|
|
418
453
|
}
|
|
419
454
|
const lines = codeContext.split("\n");
|
|
420
455
|
const where = thread.anchor.kind === "changeset" ? "the file" : `\`${thread.anchor.path}\``;
|
|
456
|
+
if (thread.deliveredThrough) return [`(diff snapshot delivered to you earlier — read the current ${where} instead)`];
|
|
421
457
|
if (!anchored) return [
|
|
422
458
|
"The commented change:",
|
|
423
459
|
"```diff",
|
|
@@ -457,7 +493,7 @@ function buildThreadPrompt(thread, ctx) {
|
|
|
457
493
|
threadBlock(thread, 0),
|
|
458
494
|
"",
|
|
459
495
|
...siblings ? [siblings, ""] : [],
|
|
460
|
-
replyProtocol([thread]),
|
|
496
|
+
replyProtocol([thread], ctx.protocol),
|
|
461
497
|
""
|
|
462
498
|
].join("\n");
|
|
463
499
|
}
|
|
@@ -469,7 +505,7 @@ function buildCoalescedPrompt(threads, ctx) {
|
|
|
469
505
|
...ctx.changeset ? [specLine(ctx.changeset), ""] : [],
|
|
470
506
|
...threads.map((t, i) => `${threadBlock(t, i)}\n`),
|
|
471
507
|
...siblings ? [siblings, ""] : [],
|
|
472
|
-
replyProtocol(threads),
|
|
508
|
+
replyProtocol(threads, ctx.protocol),
|
|
473
509
|
""
|
|
474
510
|
].join("\n");
|
|
475
511
|
}
|
|
@@ -494,7 +530,9 @@ function buildFinishPrompt(threads, ctx, coverage) {
|
|
|
494
530
|
const repo = ctx.repo;
|
|
495
531
|
const sent = threads.filter((t) => t.state === "sent");
|
|
496
532
|
const closing = sent.find((t) => t.closingNote);
|
|
497
|
-
const
|
|
533
|
+
const ordered = closing ? [closing, ...sent.filter((t) => t !== closing)] : sent;
|
|
534
|
+
const answered = ordered.filter((t) => t !== closing && answeredByAgent(t));
|
|
535
|
+
const actionable = ordered.filter((t) => !answered.includes(t));
|
|
498
536
|
const changed = coverage.changedFiles ?? [];
|
|
499
537
|
const commented = coverage.commentedUnread ?? [];
|
|
500
538
|
const filtered = coverage.filteredOut ?? [];
|
|
@@ -523,11 +561,12 @@ function buildFinishPrompt(threads, ctx, coverage) {
|
|
|
523
561
|
"",
|
|
524
562
|
...owedLines
|
|
525
563
|
];
|
|
564
|
+
if (answered.length > 0) parts.push(`${answered.length} thread${answered.length === 1 ? "" : "s"} you already answered, with nothing new since — no reply owed, not repeated here:`, ...answered.map((t) => `- ${t.id} — ${describeAnchor(t.anchor)}`), "");
|
|
526
565
|
if (coverage.skippedFiles.length > 0) parts.push("The reviewer left the not-marked-read files unread. If any of them hide", "a risky or subtle change you made, say so in a comment thread", `(\`${CLI_COMMANDS.comment}\`) — the reviewer replies to take it up, or resolves it.`, "");
|
|
527
566
|
if (actionable.length === 0) {
|
|
528
567
|
const fullRead = coverage.totalHunks > 0 && coverage.viewedHunks >= coverage.totalHunks && changed.length === 0 && commented.length === 0 && filtered.length === 0 && coverage.skippedFiles.length === 0;
|
|
529
568
|
parts.push(fullRead && coverage.note === void 0 ? "They read everything and left nothing to address — take it as a green light to proceed." : "No open review threads — nothing to act on.", `Run \`${CLI_COMMANDS.poll}\` again to keep listening (${POLL_STANCE});`, "the reviewer may follow up.", "");
|
|
530
|
-
} else parts.push(`${actionable.length} review thread${actionable.length === 1 ? "" : "s"} to act on:`, "", ...actionable.map((t, i) => `${threadBlock(t, i)}\n`), replyProtocol(actionable), "");
|
|
569
|
+
} else parts.push(`${actionable.length} review thread${actionable.length === 1 ? "" : "s"} to act on:`, "", ...actionable.map((t, i) => `${threadBlock(t, i)}\n`), replyProtocol(actionable, ctx.protocol), "");
|
|
531
570
|
return parts.join("\n");
|
|
532
571
|
}
|
|
533
572
|
//#endregion
|
|
@@ -590,11 +629,15 @@ The loop:
|
|
|
590
629
|
away, leaving a background server watching the working tree. Never open a
|
|
591
630
|
browser at the reviewer — end your message with the printed URL instead,
|
|
592
631
|
and keep ending every message with it while you stay attached.
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
${GUIDE.
|
|
597
|
-
|
|
632
|
+
Attached without ever seeing the URL (a takeover, a fresh session)?
|
|
633
|
+
\`diffo status\` prints it.
|
|
634
|
+
2. Guide — post one only when the changeset needs orientation:
|
|
635
|
+
${GUIDE.when}.
|
|
636
|
+
Before sharing the URL, post ONE comment on the whole changeset
|
|
637
|
+
(\`diffo comment -m "…"\`, no file), containing:
|
|
638
|
+
${GUIDE.what}.
|
|
639
|
+
${GUIDE.stance}.
|
|
640
|
+
If the changeset later shifts under the guide, ${GUIDE.update}.
|
|
598
641
|
3. Listen: run \`diffo poll\` — it blocks until the reviewer acts, then prints
|
|
599
642
|
one JSON payload naming the threads to act on. Run it attended:
|
|
600
643
|
${POLL_STANCE}.
|
|
@@ -604,7 +647,10 @@ The loop:
|
|
|
604
647
|
answer in the reply and no edit. Your edits reach the reviewer live.
|
|
605
648
|
5. Reply: \`diffo reply <threadId> --message "<text>"\` (pipe long replies on
|
|
606
649
|
stdin) — concise, addressed to the reviewer. Markdown renders; a
|
|
607
|
-
\`\`\`mermaid fence draws a diagram.
|
|
650
|
+
\`\`\`mermaid fence draws a diagram. A reply that only promises a
|
|
651
|
+
follow-up ("I'll investigate and report back") goes out with \`--more\` —
|
|
652
|
+
the reviewer keeps seeing you at work — and the real answer follows as a
|
|
653
|
+
plain reply before the next poll.
|
|
608
654
|
6. Comment (sparingly): \`diffo comment [<file>] [--line <n>] -m "<text>"\`
|
|
609
655
|
starts a thread in your voice — a concern, or context that helps the read.
|
|
610
656
|
7. Poll again only when the whole batch is handled — a new poll tells the
|
|
@@ -615,7 +661,9 @@ Rules:
|
|
|
615
661
|
- Change only what the threads ask about — the reviewer is mid-read, and an
|
|
616
662
|
unrelated edit moves the diff under them.
|
|
617
663
|
- One attached agent at a time: the newest poll carries the review; don't
|
|
618
|
-
re-poll to take it back from another session — tell the user instead.
|
|
664
|
+
re-poll to take it back from another session — tell the user instead. When
|
|
665
|
+
a poll says it took the review over, or returns status "superseded", say so
|
|
666
|
+
to the user: their feedback moved with it.
|
|
619
667
|
- Resolving a thread is the reviewer's call, never yours.`,
|
|
620
668
|
poll: `diffo poll — wait for the reviewer's feedback
|
|
621
669
|
|
|
@@ -640,6 +688,10 @@ Usage: diffo reply <threadId> --message "<text>"
|
|
|
640
688
|
|
|
641
689
|
Thread ids arrive in poll payloads. Each run posts one message, so don't
|
|
642
690
|
re-run a reply that succeeded.
|
|
691
|
+
--more marks the reply as interim: you are still working, and a follow-up
|
|
692
|
+
reply on this thread is promised. The reviewer keeps seeing the thread as
|
|
693
|
+
"with the agent" until your next plain reply; going quiet instead marks it
|
|
694
|
+
unanswered.
|
|
643
695
|
Messages render GitHub-flavored markdown; a \`\`\`mermaid fence renders as a
|
|
644
696
|
diagram in the review.
|
|
645
697
|
|
|
@@ -878,6 +930,7 @@ function parseVerb(verb, rest) {
|
|
|
878
930
|
short: "m"
|
|
879
931
|
},
|
|
880
932
|
line: { type: "string" },
|
|
933
|
+
more: { type: "boolean" },
|
|
881
934
|
json: { type: "boolean" },
|
|
882
935
|
help: {
|
|
883
936
|
type: "boolean",
|
|
@@ -898,6 +951,10 @@ function parseVerb(verb, rest) {
|
|
|
898
951
|
kind: "error",
|
|
899
952
|
message: `'${verb}' takes no --json`
|
|
900
953
|
};
|
|
954
|
+
if (values.more && verb !== "reply") return {
|
|
955
|
+
kind: "error",
|
|
956
|
+
message: `'${verb}' takes no --more`
|
|
957
|
+
};
|
|
901
958
|
if (verb === "poll" || verb === "end" || verb === "setup" || verb === "status" || verb === "stop") {
|
|
902
959
|
if (positionals.length > 0) return {
|
|
903
960
|
kind: "error",
|
|
@@ -930,7 +987,8 @@ function parseVerb(verb, rest) {
|
|
|
930
987
|
return {
|
|
931
988
|
kind: "reply",
|
|
932
989
|
threadId,
|
|
933
|
-
message: values.message ?? null
|
|
990
|
+
message: values.message ?? null,
|
|
991
|
+
more: values.more === true
|
|
934
992
|
};
|
|
935
993
|
}
|
|
936
994
|
const file = positionals[0] ?? null;
|
|
@@ -1531,7 +1589,8 @@ var DiffoDb = class {
|
|
|
1531
1589
|
const known = /* @__PURE__ */ new Set([
|
|
1532
1590
|
"reviews",
|
|
1533
1591
|
"servers",
|
|
1534
|
-
"repo_ports"
|
|
1592
|
+
"repo_ports",
|
|
1593
|
+
"ui_settings"
|
|
1535
1594
|
]);
|
|
1536
1595
|
const tables = this.db.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'").all();
|
|
1537
1596
|
for (const { name } of tables) if (!known.has(name)) this.db.exec(`DROP TABLE IF EXISTS "${name.replaceAll("\"", "\"\"")}"`);
|
|
@@ -1556,6 +1615,10 @@ var DiffoDb = class {
|
|
|
1556
1615
|
repo_path TEXT PRIMARY KEY,
|
|
1557
1616
|
port INTEGER NOT NULL
|
|
1558
1617
|
);
|
|
1618
|
+
CREATE TABLE IF NOT EXISTS ui_settings (
|
|
1619
|
+
key TEXT PRIMARY KEY,
|
|
1620
|
+
value TEXT NOT NULL
|
|
1621
|
+
);
|
|
1559
1622
|
PRAGMA user_version = ${SCHEMA_VERSION};
|
|
1560
1623
|
`);
|
|
1561
1624
|
this.pruneVanishedRepos();
|
|
@@ -1631,6 +1694,16 @@ var DiffoDb = class {
|
|
|
1631
1694
|
this.db.prepare(`INSERT INTO repo_ports (repo_path, port) VALUES (?, ?)
|
|
1632
1695
|
ON CONFLICT(repo_path) DO UPDATE SET port = excluded.port`).run(repoPath, port);
|
|
1633
1696
|
}
|
|
1697
|
+
/** Reviewer preferences that must outlive one server's origin — every repo is
|
|
1698
|
+
* served from its own port, so localStorage alone can't hold a choice like
|
|
1699
|
+
* the theme. Keyed blobs, no scope: these are per-human, not per-repo. */
|
|
1700
|
+
getUiSetting(key) {
|
|
1701
|
+
return this.db.prepare("SELECT value FROM ui_settings WHERE key = ?").get(key)?.value ?? null;
|
|
1702
|
+
}
|
|
1703
|
+
setUiSetting(key, value) {
|
|
1704
|
+
this.db.prepare(`INSERT INTO ui_settings (key, value) VALUES (?, ?)
|
|
1705
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run(key, value);
|
|
1706
|
+
}
|
|
1634
1707
|
getServer(repoPath) {
|
|
1635
1708
|
const row = this.db.prepare("SELECT port, pid, started_at FROM servers WHERE repo_path = ?").get(repoPath);
|
|
1636
1709
|
return row ? {
|
|
@@ -1710,6 +1783,11 @@ var DeliveryQueue = class DeliveryQueue {
|
|
|
1710
1783
|
reason: "no-agent"
|
|
1711
1784
|
};
|
|
1712
1785
|
owner = null;
|
|
1786
|
+
/** The session pid that last received the full reply protocol. Later
|
|
1787
|
+
* deliveries to the same session carry the compact form — the full text is
|
|
1788
|
+
* the loop's largest recurring token cost. A takeover (new pid) or an
|
|
1789
|
+
* anonymous session (null pid) always gets the full form again. */
|
|
1790
|
+
protocolPid = null;
|
|
1713
1791
|
batch = null;
|
|
1714
1792
|
batchWatch = null;
|
|
1715
1793
|
waiterWatch = null;
|
|
@@ -1770,6 +1848,12 @@ var DeliveryQueue = class DeliveryQueue {
|
|
|
1770
1848
|
ownerPid() {
|
|
1771
1849
|
return this.ownerConnected() ? this.owner : null;
|
|
1772
1850
|
}
|
|
1851
|
+
needsFullProtocol() {
|
|
1852
|
+
return this.owner === null || this.owner !== this.protocolPid;
|
|
1853
|
+
}
|
|
1854
|
+
markProtocolSent() {
|
|
1855
|
+
this.protocolPid = this.owner;
|
|
1856
|
+
}
|
|
1773
1857
|
/**
|
|
1774
1858
|
* A poll attaches for its session; the newest poll always carries the review.
|
|
1775
1859
|
* Returns the pid of a still-live session it took the review from, so both
|
|
@@ -2045,10 +2129,19 @@ var DeliveryQueue = class DeliveryQueue {
|
|
|
2045
2129
|
this.notify();
|
|
2046
2130
|
}
|
|
2047
2131
|
/** The agent replied on a thread. Returns how long since that thread's feedback
|
|
2048
|
-
* was delivered, or null when the reply wasn't an answer to a delivery.
|
|
2049
|
-
|
|
2132
|
+
* was delivered, or null when the reply wasn't an answer to a delivery.
|
|
2133
|
+
* `interim` (a `--more` reply) keeps the thread on the clock: a follow-up is
|
|
2134
|
+
* still owed, so the spinner stays and a batch that closes without the
|
|
2135
|
+
* follow-up counts the thread unanswered. */
|
|
2136
|
+
agentReplied(threadId, interim = false) {
|
|
2050
2137
|
const at = this.deliveredAt.get(threadId);
|
|
2051
|
-
this.deliveredAt.delete(threadId);
|
|
2138
|
+
if (!interim) this.deliveredAt.delete(threadId);
|
|
2139
|
+
else if (at === void 0 && this.batch) {
|
|
2140
|
+
this.deliveredAt.set(threadId, Date.now());
|
|
2141
|
+
if (!this.batch.threadIds.includes(threadId)) this.batch.threadIds.push(threadId);
|
|
2142
|
+
this.awaitingReply = true;
|
|
2143
|
+
this.clearGrace();
|
|
2144
|
+
}
|
|
2052
2145
|
if (this.batch) this.batch.sawReply = true;
|
|
2053
2146
|
if (this.deliveredAt.size > 0) {
|
|
2054
2147
|
if (this.awaitingReply) {
|
|
@@ -2328,7 +2421,7 @@ var ReviewStore = class {
|
|
|
2328
2421
|
* the reviewer raced in since — appended at the end, it would render as an
|
|
2329
2422
|
* answer to a comment it never saw, and the raced comment would stop reading
|
|
2330
2423
|
* as "waiting on the agent" even though it still is. */
|
|
2331
|
-
addMessage(threadId, author, text, withheld = false, seenThroughMs) {
|
|
2424
|
+
addMessage(threadId, author, text, withheld = false, seenThroughMs, followUp = false) {
|
|
2332
2425
|
return this.update(threadId, ({ unanswered: _answered, ...thread }) => {
|
|
2333
2426
|
const message = {
|
|
2334
2427
|
id: randomUUID(),
|
|
@@ -2336,9 +2429,11 @@ var ReviewStore = class {
|
|
|
2336
2429
|
text,
|
|
2337
2430
|
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
2338
2431
|
};
|
|
2339
|
-
const raced = author === "agent" && seenThroughMs !== void 0 ? thread.messages.findIndex((m) => Date.parse(m.at) > seenThroughMs) : -1;
|
|
2432
|
+
const raced = author === "agent" && seenThroughMs !== void 0 ? thread.messages.findIndex((m) => m.author === "reviewer" && Date.parse(m.at) > seenThroughMs) : -1;
|
|
2433
|
+
const { awaitingFollowUp: _promised, ...settled } = thread;
|
|
2340
2434
|
return {
|
|
2341
|
-
...thread,
|
|
2435
|
+
...author === "agent" ? settled : thread,
|
|
2436
|
+
...author === "agent" && followUp ? { awaitingFollowUp: true } : {},
|
|
2342
2437
|
...withheld && author === "reviewer" ? { withheld: true } : {},
|
|
2343
2438
|
messages: raced === -1 ? [...thread.messages, message] : [
|
|
2344
2439
|
...thread.messages.slice(0, raced),
|
|
@@ -2387,7 +2482,7 @@ var ReviewStore = class {
|
|
|
2387
2482
|
const threads = this.state.threads.map((thread) => {
|
|
2388
2483
|
if (!wanted.has(thread.id) || !applies(thread)) return thread;
|
|
2389
2484
|
changed = true;
|
|
2390
|
-
const { unanswered: _was, ...rest } = thread;
|
|
2485
|
+
const { unanswered: _was, awaitingFollowUp: _promised, ...rest } = thread;
|
|
2391
2486
|
return thread.unanswered ? rest : {
|
|
2392
2487
|
...rest,
|
|
2393
2488
|
unanswered: true
|
|
@@ -2401,8 +2496,9 @@ var ReviewStore = class {
|
|
|
2401
2496
|
this.commit();
|
|
2402
2497
|
}
|
|
2403
2498
|
setState(threadId, state) {
|
|
2404
|
-
return this.update(threadId, (thread) => ({
|
|
2499
|
+
return this.update(threadId, ({ awaitingFollowUp: promised, ...thread }) => ({
|
|
2405
2500
|
...thread,
|
|
2501
|
+
...promised && state !== "resolved" ? { awaitingFollowUp: true } : {},
|
|
2406
2502
|
state,
|
|
2407
2503
|
...state === "sent" && !thread.sentAt ? { sentAt: (/* @__PURE__ */ new Date()).toISOString() } : {},
|
|
2408
2504
|
...state === "resolved" ? { codeContext: null } : {}
|
|
@@ -2746,6 +2842,7 @@ function normalizeThread(value, now) {
|
|
|
2746
2842
|
...anchored ? { anchored } : {},
|
|
2747
2843
|
codeChanged: t.codeChanged === true,
|
|
2748
2844
|
...t.unanswered === true ? { unanswered: true } : {},
|
|
2845
|
+
...t.awaitingFollowUp === true && t.unanswered !== true ? { awaitingFollowUp: true } : {},
|
|
2749
2846
|
...t.closingNote === true ? { closingNote: true } : {},
|
|
2750
2847
|
...typeof t.sentAt === "string" ? { sentAt: t.sentAt } : {},
|
|
2751
2848
|
messages,
|
|
@@ -3231,6 +3328,22 @@ function createApp(ctx, store, review, queue) {
|
|
|
3231
3328
|
note: "shutting down"
|
|
3232
3329
|
});
|
|
3233
3330
|
});
|
|
3331
|
+
const THEME_VALUES = /* @__PURE__ */ new Set([
|
|
3332
|
+
"system",
|
|
3333
|
+
"light",
|
|
3334
|
+
"dark"
|
|
3335
|
+
]);
|
|
3336
|
+
app.get("/api/settings", (c) => {
|
|
3337
|
+
const theme = ctx.uiSettings?.get("theme") ?? null;
|
|
3338
|
+
return c.json({ theme: theme !== null && THEME_VALUES.has(theme) ? theme : null });
|
|
3339
|
+
});
|
|
3340
|
+
app.put("/api/settings", async (c) => {
|
|
3341
|
+
if (!ctx.uiSettings) return c.json({ error: "settings unavailable" }, 503);
|
|
3342
|
+
const theme = (await c.req.json().catch(() => null))?.theme;
|
|
3343
|
+
if (typeof theme !== "string" || !THEME_VALUES.has(theme)) return c.json({ error: "need {theme: \"system\" | \"light\" | \"dark\"}" }, 400);
|
|
3344
|
+
ctx.uiSettings.set("theme", theme);
|
|
3345
|
+
return c.json({ ok: true });
|
|
3346
|
+
});
|
|
3234
3347
|
const repoInfo = () => store?.get().repo ?? {
|
|
3235
3348
|
path: resolve(ctx.root),
|
|
3236
3349
|
name: "",
|
|
@@ -3298,9 +3411,10 @@ function createApp(ctx, store, review, queue) {
|
|
|
3298
3411
|
const id = c.req.param("id");
|
|
3299
3412
|
if (!review.get().threads.some((t) => t.id === id)) return c.json({ error: "no such thread" }, 404);
|
|
3300
3413
|
queue?.noteSession(parseSessionPid(c.req.header("x-diffo-session-pid")));
|
|
3301
|
-
const
|
|
3414
|
+
const more = body?.more === true;
|
|
3415
|
+
const waitedMs = queue?.agentReplied(id, more) ?? null;
|
|
3302
3416
|
const seenThroughMs = waitedMs === null ? void 0 : Date.now() - waitedMs;
|
|
3303
|
-
const thread = review.addMessage(id, "agent", text, false, seenThroughMs);
|
|
3417
|
+
const thread = review.addMessage(id, "agent", text, false, seenThroughMs, more);
|
|
3304
3418
|
if (!thread) return c.json({ error: "no such thread" }, 404);
|
|
3305
3419
|
if (waitedMs !== null) review.annotateAgentReplies([thread.id], waitedMs);
|
|
3306
3420
|
return c.json({
|
|
@@ -3479,6 +3593,7 @@ function createApp(ctx, store, review, queue) {
|
|
|
3479
3593
|
});
|
|
3480
3594
|
const pollPayload = (snapshot) => {
|
|
3481
3595
|
const threads = review?.get().threads ?? [];
|
|
3596
|
+
const protocol = queue?.needsFullProtocol() === false ? "compact" : void 0;
|
|
3482
3597
|
if (snapshot.kind === "cleared") return {
|
|
3483
3598
|
status: "feedback",
|
|
3484
3599
|
kind: "cleared",
|
|
@@ -3493,15 +3608,22 @@ function createApp(ctx, store, review, queue) {
|
|
|
3493
3608
|
return {
|
|
3494
3609
|
status: "feedback",
|
|
3495
3610
|
kind: "finish",
|
|
3496
|
-
threadIds: batch.filter((t) => t.state === "sent" && t
|
|
3611
|
+
threadIds: batch.filter((t) => t.state === "sent" && !answeredByAgent(t)).map((t) => t.id),
|
|
3497
3612
|
prompt: buildFinishPrompt(batch, {
|
|
3498
3613
|
repo: repoInfo(),
|
|
3499
|
-
changeset: store?.get() ?? null
|
|
3614
|
+
changeset: store?.get() ?? null,
|
|
3615
|
+
protocol
|
|
3500
3616
|
}, snapshot.coverage)
|
|
3501
3617
|
};
|
|
3502
3618
|
}
|
|
3503
3619
|
const delivered = threads.filter((t) => snapshot.threadIds.includes(t.id));
|
|
3504
|
-
const prompt = delivered.length === 1 ? buildThreadPrompt(delivered[0],
|
|
3620
|
+
const prompt = delivered.length === 1 ? buildThreadPrompt(delivered[0], {
|
|
3621
|
+
...promptCtx(delivered[0].id),
|
|
3622
|
+
protocol
|
|
3623
|
+
}) : buildCoalescedPrompt(delivered, {
|
|
3624
|
+
...promptCtx(...snapshot.threadIds),
|
|
3625
|
+
protocol
|
|
3626
|
+
});
|
|
3505
3627
|
return {
|
|
3506
3628
|
status: "feedback",
|
|
3507
3629
|
kind: "threads",
|
|
@@ -3579,6 +3701,7 @@ function createApp(ctx, store, review, queue) {
|
|
|
3579
3701
|
await s.write(JSON.stringify(payload));
|
|
3580
3702
|
if (aborted) return;
|
|
3581
3703
|
queue.confirm(snapshot, payload.threadIds);
|
|
3704
|
+
if (payload.threadIds.length > 0) queue.markProtocolSent();
|
|
3582
3705
|
review.markDelivered(payload.threadIds);
|
|
3583
3706
|
review.clearUnanswered(payload.threadIds);
|
|
3584
3707
|
if (snapshot.kind === "finish") review.markFinishCollected();
|
|
@@ -3737,6 +3860,8 @@ function markDevIndex(html, isDev) {
|
|
|
3737
3860
|
return html.replace(/<title>[^<]*<\/title>/, "<title>diffo-dev</title>").replace(/<\/head>/, " <meta name=\"diffo-env\" content=\"development\" />\n </head>");
|
|
3738
3861
|
}
|
|
3739
3862
|
function rehydrateQueue(review, queue) {
|
|
3863
|
+
const promised = review.get().threads.filter((t) => t.awaitingFollowUp === true).map((t) => t.id);
|
|
3864
|
+
if (promised.length > 0) review.markUnanswered(promised);
|
|
3740
3865
|
const state = review.get();
|
|
3741
3866
|
queue.enqueueThreads(undeliveredThreadIds(state.threads));
|
|
3742
3867
|
const finish = state.lastFinish;
|
|
@@ -3808,7 +3933,11 @@ function startServer(options) {
|
|
|
3808
3933
|
const app = createApp({
|
|
3809
3934
|
...options,
|
|
3810
3935
|
idle,
|
|
3811
|
-
onShutdownRequest: options.onShutdownRequest ?? (() => process.exit(0))
|
|
3936
|
+
onShutdownRequest: options.onShutdownRequest ?? (() => process.exit(0)),
|
|
3937
|
+
uiSettings: {
|
|
3938
|
+
get: (key) => db.getUiSetting(key),
|
|
3939
|
+
set: (key, value) => db.setUiSetting(key, value)
|
|
3940
|
+
}
|
|
3812
3941
|
}, store, review, queue);
|
|
3813
3942
|
const server = serve({
|
|
3814
3943
|
fetch: app.fetch,
|
|
@@ -4631,7 +4760,7 @@ if (command.kind === "stop") {
|
|
|
4631
4760
|
}
|
|
4632
4761
|
if (command.kind === "poll") {
|
|
4633
4762
|
const port = await requireServer();
|
|
4634
|
-
process.stderr.write("diffo: waiting for the reviewer — keep this process attended: a tracked\nbackground task or the foreground, never detached
|
|
4763
|
+
process.stderr.write("diffo: waiting for the reviewer — keep this process attended: a tracked\nbackground task or the foreground, never detached. If it dies, just\nre-run it — feedback is held in the review and survives.\n");
|
|
4635
4764
|
try {
|
|
4636
4765
|
const res = await fetch(apiUrl(port, "/api/agent/poll"), { headers: sessionHeaders() });
|
|
4637
4766
|
if (!res.ok) fail(`poll failed (${res.status})`);
|
|
@@ -4654,7 +4783,8 @@ if (command.kind === "reply") {
|
|
|
4654
4783
|
if (!message) fail("reply needs a message — pass --message \"<text>\" or pipe it on stdin");
|
|
4655
4784
|
const { status, body } = await postJson(await requireServer(), `/api/review/threads/${encodeURIComponent(command.threadId)}/messages`, {
|
|
4656
4785
|
author: "agent",
|
|
4657
|
-
text: message
|
|
4786
|
+
text: message,
|
|
4787
|
+
...command.more ? { more: true } : {}
|
|
4658
4788
|
});
|
|
4659
4789
|
if (status === 404) fail(`no thread with id '${command.threadId}'`);
|
|
4660
4790
|
if (status !== 200) fail(`reply failed (${status})`);
|
|
@@ -4663,7 +4793,7 @@ if (command.kind === "reply") {
|
|
|
4663
4793
|
ok: true,
|
|
4664
4794
|
threadId: thread.id,
|
|
4665
4795
|
state: thread.state,
|
|
4666
|
-
next_step: ACK_NEXT_STEP.reply
|
|
4796
|
+
next_step: command.more ? ACK_NEXT_STEP.replyMore : ACK_NEXT_STEP.reply
|
|
4667
4797
|
}));
|
|
4668
4798
|
process.exit(0);
|
|
4669
4799
|
}
|
package/dist/client/assets/{abnfDiagram-VCTEODGH-DNZRM2Rn.js → abnfDiagram-VCTEODGH-BK74b0Uj.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{m as e,t}from"./mermaid-parser.core-
|
|
1
|
+
import{m as e,t}from"./mermaid-parser.core-BLSiQUXp.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-CfhDi0bm.js";import"./chunk-DU6HZSFF-wyqPpFTy.js";import{n as i,r as a,t as o}from"./chunk-SVP7TREG-CsO-w42m.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-BoXUi08V.js";var c=e().RailroadAbnf.parser.LangiumParser,l=n(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=n(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=n(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=n(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=n(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=n(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=n(e=>{s(e,o),e.title&&o.setTitle(e.title),e.rules.map(e=>o.addRule(m(e)))},`populateDb`),g={parser:{parse:n(e=>{o.clear(),r.debug(`[ABNF Parser] Starting Langium parse`);let n=c.parse(e);if(n.lexerErrors.length>0||n.parserErrors.length>0)throw new t(n);let i=n.value;r.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),r.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:o}},db:o,renderer:a,styles:i};export{g as diagram};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e,t}from"./path-fybaL0A-.js";import{a as n,c as r,d as i,f as a,i as o,l as s,m as c,n as l,o as u,p as d,r as f,u as p}from"./dist-
|
|
1
|
+
import{n as e,t}from"./path-fybaL0A-.js";import{a as n,c as r,d as i,f as a,i as o,l as s,m as c,n as l,o as u,p as d,r as f,u as p}from"./dist-bii_eoxi.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-DHwB1DNv.js";import{M as e}from"./mermaid-parser.core-BLSiQUXp.js";export{e as createArchitectureServices};
|